@ -28,6 +28,7 @@
# include "led.h"
# include "led.h"
# endif
# endif
# include "wait.h"
# include "wait.h"
# include "usb_descriptor.h"
# ifdef NKRO_ENABLE
# ifdef NKRO_ENABLE
# include "keycode_config.h"
# include "keycode_config.h"
@ -63,24 +64,12 @@ report_mouse_t mouse_report_blank = {0};
uint8_t extra_report_blank [ 3 ] = { 0 } ;
uint8_t extra_report_blank [ 3 ] = { 0 } ;
# endif /* EXTRAKEY_ENABLE */
# endif /* EXTRAKEY_ENABLE */
# ifdef CONSOLE_ENABLE
/* The emission buffers queue */
output_buffers_queue_t console_buf_queue ;
static uint8_t console_queue_buffer [ BQ_BUFFER_SIZE ( CONSOLE_QUEUE_CAPACITY , CONSOLE_EPSIZE ) ] ;
static virtual_timer_t console_flush_timer ;
void console_queue_onotify ( io_buffers_queue_t * bqp ) ;
static void console_flush_cb ( void * arg ) ;
# endif /* CONSOLE_ENABLE */
/* ---------------------------------------------------------
/* ---------------------------------------------------------
* Descriptors and USB driver objects
* Descriptors and USB driver objects
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
*/
/* HID specific constants */
/* HID specific constants */
# define USB_DESCRIPTOR_HID 0x21
# define USB_DESCRIPTOR_HID_REPORT 0x22
# define HID_GET_REPORT 0x01
# define HID_GET_REPORT 0x01
# define HID_GET_IDLE 0x02
# define HID_GET_IDLE 0x02
# define HID_GET_PROTOCOL 0x03
# define HID_GET_PROTOCOL 0x03
@ -88,593 +77,21 @@ static void console_flush_cb(void *arg);
# define HID_SET_IDLE 0x0A
# define HID_SET_IDLE 0x0A
# define HID_SET_PROTOCOL 0x0B
# define HID_SET_PROTOCOL 0x0B
/* USB Device Descriptor */
static const uint8_t usb_device_descriptor_data [ ] = {
USB_DESC_DEVICE ( 0x0200 , // bcdUSB (1.1)
0 , // bDeviceClass (defined in later in interface)
0 , // bDeviceSubClass
0 , // bDeviceProtocol
64 , // bMaxPacketSize (64 bytes) (the driver didn't work with 32)
VENDOR_ID , // idVendor
PRODUCT_ID , // idProduct
DEVICE_VER , // bcdDevice
1 , // iManufacturer
2 , // iProduct
3 , // iSerialNumber
1 ) // bNumConfigurations
} ;
/* Device Descriptor wrapper */
static const USBDescriptor usb_device_descriptor = {
sizeof usb_device_descriptor_data ,
usb_device_descriptor_data
} ;
/*
* HID Report Descriptor
*
* See " Device Class Definition for Human Interface Devices (HID) "
* ( http : //www.usb.org/developers/hidpage/HID1_11.pdf) for the
* detailed descrition of all the fields
*/
/* Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60 */
static const uint8_t keyboard_hid_report_desc_data [ ] = {
0x05 , 0x01 , // Usage Page (Generic Desktop),
0x09 , 0x06 , // Usage (Keyboard),
0xA1 , 0x01 , // Collection (Application),
0x75 , 0x01 , // Report Size (1),
0x95 , 0x08 , // Report Count (8),
0x05 , 0x07 , // Usage Page (Key Codes),
0x19 , 0xE0 , // Usage Minimum (224),
0x29 , 0xE7 , // Usage Maximum (231),
0x15 , 0x00 , // Logical Minimum (0),
0x25 , 0x01 , // Logical Maximum (1),
0x81 , 0x02 , // Input (Data, Variable, Absolute), ;Modifier byte
0x95 , 0x01 , // Report Count (1),
0x75 , 0x08 , // Report Size (8),
0x81 , 0x03 , // Input (Constant), ;Reserved byte
0x95 , 0x05 , // Report Count (5),
0x75 , 0x01 , // Report Size (1),
0x05 , 0x08 , // Usage Page (LEDs),
0x19 , 0x01 , // Usage Minimum (1),
0x29 , 0x05 , // Usage Maximum (5),
0x91 , 0x02 , // Output (Data, Variable, Absolute), ;LED report
0x95 , 0x01 , // Report Count (1),
0x75 , 0x03 , // Report Size (3),
0x91 , 0x03 , // Output (Constant), ;LED report padding
0x95 , KBD_REPORT_KEYS , // Report Count (),
0x75 , 0x08 , // Report Size (8),
0x15 , 0x00 , // Logical Minimum (0),
0x26 , 0xFF , 0x00 , // Logical Maximum(255),
0x05 , 0x07 , // Usage Page (Key Codes),
0x19 , 0x00 , // Usage Minimum (0),
0x29 , 0xFF , // Usage Maximum (255),
0x81 , 0x00 , // Input (Data, Array),
0xc0 // End Collection
} ;
/* wrapper */
static const USBDescriptor keyboard_hid_report_descriptor = {
sizeof keyboard_hid_report_desc_data ,
keyboard_hid_report_desc_data
} ;
# ifdef NKRO_ENABLE
static const uint8_t nkro_hid_report_desc_data [ ] = {
0x05 , 0x01 , // Usage Page (Generic Desktop),
0x09 , 0x06 , // Usage (Keyboard),
0xA1 , 0x01 , // Collection (Application),
// bitmap of modifiers
0x75 , 0x01 , // Report Size (1),
0x95 , 0x08 , // Report Count (8),
0x05 , 0x07 , // Usage Page (Key Codes),
0x19 , 0xE0 , // Usage Minimum (224),
0x29 , 0xE7 , // Usage Maximum (231),
0x15 , 0x00 , // Logical Minimum (0),
0x25 , 0x01 , // Logical Maximum (1),
0x81 , 0x02 , // Input (Data, Variable, Absolute), ;Modifier byte
// LED output report
0x95 , 0x05 , // Report Count (5),
0x75 , 0x01 , // Report Size (1),
0x05 , 0x08 , // Usage Page (LEDs),
0x19 , 0x01 , // Usage Minimum (1),
0x29 , 0x05 , // Usage Maximum (5),
0x91 , 0x02 , // Output (Data, Variable, Absolute),
0x95 , 0x01 , // Report Count (1),
0x75 , 0x03 , // Report Size (3),
0x91 , 0x03 , // Output (Constant),
// bitmap of keys
0x95 , NKRO_REPORT_KEYS * 8 , // Report Count (),
0x75 , 0x01 , // Report Size (1),
0x15 , 0x00 , // Logical Minimum (0),
0x25 , 0x01 , // Logical Maximum(1),
0x05 , 0x07 , // Usage Page (Key Codes),
0x19 , 0x00 , // Usage Minimum (0),
0x29 , NKRO_REPORT_KEYS * 8 - 1 , // Usage Maximum (),
0x81 , 0x02 , // Input (Data, Variable, Absolute),
0xc0 // End Collection
} ;
/* wrapper */
static const USBDescriptor nkro_hid_report_descriptor = {
sizeof nkro_hid_report_desc_data ,
nkro_hid_report_desc_data
} ;
# endif /* NKRO_ENABLE */
# ifdef MOUSE_ENABLE
/* Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension
* http : //www.microchip.com/forums/tm.aspx?high=&m=391435&mpage=1#391521
* http : //www.keil.com/forum/15671/
* http : //www.microsoft.com/whdc/device/input/wheel.mspx */
static const uint8_t mouse_hid_report_desc_data [ ] = {
/* mouse */
0x05 , 0x01 , // USAGE_PAGE (Generic Desktop)
0x09 , 0x02 , // USAGE (Mouse)
0xa1 , 0x01 , // COLLECTION (Application)
//0x85, REPORT_ID_MOUSE, // REPORT_ID (1)
0x09 , 0x01 , // USAGE (Pointer)
0xa1 , 0x00 , // COLLECTION (Physical)
// ---------------------------- Buttons
0x05 , 0x09 , // USAGE_PAGE (Button)
0x19 , 0x01 , // USAGE_MINIMUM (Button 1)
0x29 , 0x05 , // USAGE_MAXIMUM (Button 5)
0x15 , 0x00 , // LOGICAL_MINIMUM (0)
0x25 , 0x01 , // LOGICAL_MAXIMUM (1)
0x75 , 0x01 , // REPORT_SIZE (1)
0x95 , 0x05 , // REPORT_COUNT (5)
0x81 , 0x02 , // INPUT (Data,Var,Abs)
0x75 , 0x03 , // REPORT_SIZE (3)
0x95 , 0x01 , // REPORT_COUNT (1)
0x81 , 0x03 , // INPUT (Cnst,Var,Abs)
// ---------------------------- X,Y position
0x05 , 0x01 , // USAGE_PAGE (Generic Desktop)
0x09 , 0x30 , // USAGE (X)
0x09 , 0x31 , // USAGE (Y)
0x15 , 0x81 , // LOGICAL_MINIMUM (-127)
0x25 , 0x7f , // LOGICAL_MAXIMUM (127)
0x75 , 0x08 , // REPORT_SIZE (8)
0x95 , 0x02 , // REPORT_COUNT (2)
0x81 , 0x06 , // INPUT (Data,Var,Rel)
// ---------------------------- Vertical wheel
0x09 , 0x38 , // USAGE (Wheel)
0x15 , 0x81 , // LOGICAL_MINIMUM (-127)
0x25 , 0x7f , // LOGICAL_MAXIMUM (127)
0x35 , 0x00 , // PHYSICAL_MINIMUM (0) - reset physical
0x45 , 0x00 , // PHYSICAL_MAXIMUM (0)
0x75 , 0x08 , // REPORT_SIZE (8)
0x95 , 0x01 , // REPORT_COUNT (1)
0x81 , 0x06 , // INPUT (Data,Var,Rel)
// ---------------------------- Horizontal wheel
0x05 , 0x0c , // USAGE_PAGE (Consumer Devices)
0x0a , 0x38 , 0x02 , // USAGE (AC Pan)
0x15 , 0x81 , // LOGICAL_MINIMUM (-127)
0x25 , 0x7f , // LOGICAL_MAXIMUM (127)
0x75 , 0x08 , // REPORT_SIZE (8)
0x95 , 0x01 , // REPORT_COUNT (1)
0x81 , 0x06 , // INPUT (Data,Var,Rel)
0xc0 , // END_COLLECTION
0xc0 , // END_COLLECTION
} ;
/* wrapper */
static const USBDescriptor mouse_hid_report_descriptor = {
sizeof mouse_hid_report_desc_data ,
mouse_hid_report_desc_data
} ;
# endif /* MOUSE_ENABLE */
# ifdef CONSOLE_ENABLE
static const uint8_t console_hid_report_desc_data [ ] = {
0x06 , 0x31 , 0xFF , // Usage Page 0xFF31 (vendor defined)
0x09 , 0x74 , // Usage 0x74
0xA1 , 0x53 , // Collection 0x53
0x75 , 0x08 , // report size = 8 bits
0x15 , 0x00 , // logical minimum = 0
0x26 , 0xFF , 0x00 , // logical maximum = 255
0x95 , CONSOLE_EPSIZE , // report count
0x09 , 0x75 , // usage
0x81 , 0x02 , // Input (array)
0xC0 // end collection
} ;
/* wrapper */
static const USBDescriptor console_hid_report_descriptor = {
sizeof console_hid_report_desc_data ,
console_hid_report_desc_data
} ;
# endif /* CONSOLE_ENABLE */
# ifdef EXTRAKEY_ENABLE
/* audio controls & system controls
* http : //www.microsoft.com/whdc/archive/w2kbd.mspx */
static const uint8_t extra_hid_report_desc_data [ ] = {
/* system control */
0x05 , 0x01 , // USAGE_PAGE (Generic Desktop)
0x09 , 0x80 , // USAGE (System Control)
0xa1 , 0x01 , // COLLECTION (Application)
0x85 , REPORT_ID_SYSTEM , // REPORT_ID (2)
0x15 , 0x01 , // LOGICAL_MINIMUM (0x1)
0x25 , 0xb7 , // LOGICAL_MAXIMUM (0xb7)
0x19 , 0x01 , // USAGE_MINIMUM (0x1)
0x29 , 0xb7 , // USAGE_MAXIMUM (0xb7)
0x75 , 0x10 , // REPORT_SIZE (16)
0x95 , 0x01 , // REPORT_COUNT (1)
0x81 , 0x00 , // INPUT (Data,Array,Abs)
0xc0 , // END_COLLECTION
/* consumer */
0x05 , 0x0c , // USAGE_PAGE (Consumer Devices)
0x09 , 0x01 , // USAGE (Consumer Control)
0xa1 , 0x01 , // COLLECTION (Application)
0x85 , REPORT_ID_CONSUMER , // REPORT_ID (3)
0x15 , 0x01 , // LOGICAL_MINIMUM (0x1)
0x26 , 0x9c , 0x02 , // LOGICAL_MAXIMUM (0x29c)
0x19 , 0x01 , // USAGE_MINIMUM (0x1)
0x2a , 0x9c , 0x02 , // USAGE_MAXIMUM (0x29c)
0x75 , 0x10 , // REPORT_SIZE (16)
0x95 , 0x01 , // REPORT_COUNT (1)
0x81 , 0x00 , // INPUT (Data,Array,Abs)
0xc0 , // END_COLLECTION
} ;
/* wrapper */
static const USBDescriptor extra_hid_report_descriptor = {
sizeof extra_hid_report_desc_data ,
extra_hid_report_desc_data
} ;
# endif /* EXTRAKEY_ENABLE */
/*
* Configuration Descriptor tree for a HID device
*
* The HID Specifications version 1.11 require the following order :
* - Configuration Descriptor
* - Interface Descriptor
* - HID Descriptor
* - Endpoints Descriptors
*/
# define KBD_HID_DESC_NUM 0
# define KBD_HID_DESC_OFFSET (9 + (9 + 9 + 7) * KBD_HID_DESC_NUM + 9)
# ifdef MOUSE_ENABLE
# define MOUSE_HID_DESC_NUM (KBD_HID_DESC_NUM + 1)
# define MOUSE_HID_DESC_OFFSET (9 + (9 + 9 + 7) * MOUSE_HID_DESC_NUM + 9)
# else /* MOUSE_ENABLE */
# define MOUSE_HID_DESC_NUM (KBD_HID_DESC_NUM + 0)
# endif /* MOUSE_ENABLE */
# ifdef CONSOLE_ENABLE
# define CONSOLE_HID_DESC_NUM (MOUSE_HID_DESC_NUM + 1)
# define CONSOLE_HID_DESC_OFFSET (9 + (9 + 9 + 7) * CONSOLE_HID_DESC_NUM + 9)
# else /* CONSOLE_ENABLE */
# define CONSOLE_HID_DESC_NUM (MOUSE_HID_DESC_NUM + 0)
# endif /* CONSOLE_ENABLE */
# ifdef EXTRAKEY_ENABLE
# define EXTRA_HID_DESC_NUM (CONSOLE_HID_DESC_NUM + 1)
# define EXTRA_HID_DESC_OFFSET (9 + (9 + 9 + 7) * EXTRA_HID_DESC_NUM + 9)
# else /* EXTRAKEY_ENABLE */
# define EXTRA_HID_DESC_NUM (CONSOLE_HID_DESC_NUM + 0)
# endif /* EXTRAKEY_ENABLE */
# ifdef NKRO_ENABLE
# define NKRO_HID_DESC_NUM (EXTRA_HID_DESC_NUM + 1)
# define NKRO_HID_DESC_OFFSET (9 + (9 + 9 + 7) * EXTRA_HID_DESC_NUM + 9)
# else /* NKRO_ENABLE */
# define NKRO_HID_DESC_NUM (EXTRA_HID_DESC_NUM + 0)
# endif /* NKRO_ENABLE */
# define NUM_INTERFACES (NKRO_HID_DESC_NUM + 1)
# define CONFIG1_DESC_SIZE (9 + (9 + 9 + 7) * NUM_INTERFACES)
static const uint8_t hid_configuration_descriptor_data [ ] = {
/* Configuration Descriptor (9 bytes) USB spec 9.6.3, page 264-266, Table 9-10 */
USB_DESC_CONFIGURATION ( CONFIG1_DESC_SIZE , // wTotalLength
NUM_INTERFACES , // bNumInterfaces
1 , // bConfigurationValue
0 , // iConfiguration
0xA0 , // bmAttributes (RESERVED|REMOTEWAKEUP)
50 ) , // bMaxPower (50mA)
/* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
USB_DESC_INTERFACE ( KBD_INTERFACE , // bInterfaceNumber
0 , // bAlternateSetting
1 , // bNumEndpoints
0x03 , // bInterfaceClass: HID
0x01 , // bInterfaceSubClass: Boot
0x01 , // bInterfaceProtocol: Keyboard
0 ) , // iInterface
/* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
USB_DESC_BYTE ( 9 ) , // bLength
USB_DESC_BYTE ( 0x21 ) , // bDescriptorType (HID class)
USB_DESC_BCD ( 0x0111 ) , // bcdHID: HID version 1.11
USB_DESC_BYTE ( 0 ) , // bCountryCode
USB_DESC_BYTE ( 1 ) , // bNumDescriptors
USB_DESC_BYTE ( 0x22 ) , // bDescriptorType (report desc)
USB_DESC_WORD ( sizeof ( keyboard_hid_report_desc_data ) ) , // wDescriptorLength
/* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
USB_DESC_ENDPOINT ( KBD_ENDPOINT | 0x80 , // bEndpointAddress
0x03 , // bmAttributes (Interrupt)
KBD_EPSIZE , // wMaxPacketSize
10 ) , // bInterval
# ifdef MOUSE_ENABLE
/* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
USB_DESC_INTERFACE ( MOUSE_INTERFACE , // bInterfaceNumber
0 , // bAlternateSetting
1 , // bNumEndpoints
0x03 , // bInterfaceClass (0x03 = HID)
// ThinkPad T23 BIOS doesn't work with boot mouse.
0x00 , // bInterfaceSubClass (0x01 = Boot)
0x00 , // bInterfaceProtocol (0x02 = Mouse)
/*
0x01 , // bInterfaceSubClass (0x01 = Boot)
0x02 , // bInterfaceProtocol (0x02 = Mouse)
*/
0 ) , // iInterface
/* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
USB_DESC_BYTE ( 9 ) , // bLength
USB_DESC_BYTE ( 0x21 ) , // bDescriptorType (HID class)
USB_DESC_BCD ( 0x0111 ) , // bcdHID: HID version 1.11
USB_DESC_BYTE ( 0 ) , // bCountryCode
USB_DESC_BYTE ( 1 ) , // bNumDescriptors
USB_DESC_BYTE ( 0x22 ) , // bDescriptorType (report desc)
USB_DESC_WORD ( sizeof ( mouse_hid_report_desc_data ) ) , // wDescriptorLength
/* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
USB_DESC_ENDPOINT ( MOUSE_ENDPOINT | 0x80 , // bEndpointAddress
0x03 , // bmAttributes (Interrupt)
MOUSE_EPSIZE , // wMaxPacketSize
1 ) , // bInterval
# endif /* MOUSE_ENABLE */
# ifdef CONSOLE_ENABLE
/* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
USB_DESC_INTERFACE ( CONSOLE_INTERFACE , // bInterfaceNumber
0 , // bAlternateSetting
1 , // bNumEndpoints
0x03 , // bInterfaceClass: HID
0x00 , // bInterfaceSubClass: None
0x00 , // bInterfaceProtocol: None
0 ) , // iInterface
/* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
USB_DESC_BYTE ( 9 ) , // bLength
USB_DESC_BYTE ( 0x21 ) , // bDescriptorType (HID class)
USB_DESC_BCD ( 0x0111 ) , // bcdHID: HID version 1.11
USB_DESC_BYTE ( 0 ) , // bCountryCode
USB_DESC_BYTE ( 1 ) , // bNumDescriptors
USB_DESC_BYTE ( 0x22 ) , // bDescriptorType (report desc)
USB_DESC_WORD ( sizeof ( console_hid_report_desc_data ) ) , // wDescriptorLength
/* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
USB_DESC_ENDPOINT ( CONSOLE_ENDPOINT | 0x80 , // bEndpointAddress
0x03 , // bmAttributes (Interrupt)
CONSOLE_EPSIZE , // wMaxPacketSize
1 ) , // bInterval
# endif /* CONSOLE_ENABLE */
# ifdef EXTRAKEY_ENABLE
/* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
USB_DESC_INTERFACE ( EXTRA_INTERFACE , // bInterfaceNumber
0 , // bAlternateSetting
1 , // bNumEndpoints
0x03 , // bInterfaceClass: HID
0x00 , // bInterfaceSubClass: None
0x00 , // bInterfaceProtocol: None
0 ) , // iInterface
/* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
USB_DESC_BYTE ( 9 ) , // bLength
USB_DESC_BYTE ( 0x21 ) , // bDescriptorType (HID class)
USB_DESC_BCD ( 0x0111 ) , // bcdHID: HID version 1.11
USB_DESC_BYTE ( 0 ) , // bCountryCode
USB_DESC_BYTE ( 1 ) , // bNumDescriptors
USB_DESC_BYTE ( 0x22 ) , // bDescriptorType (report desc)
USB_DESC_WORD ( sizeof ( extra_hid_report_desc_data ) ) , // wDescriptorLength
/* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
USB_DESC_ENDPOINT ( EXTRA_ENDPOINT | 0x80 , // bEndpointAddress
0x03 , // bmAttributes (Interrupt)
EXTRA_EPSIZE , // wMaxPacketSize
10 ) , // bInterval
# endif /* EXTRAKEY_ENABLE */
# ifdef NKRO_ENABLE
/* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
USB_DESC_INTERFACE ( NKRO_INTERFACE , // bInterfaceNumber
0 , // bAlternateSetting
1 , // bNumEndpoints
0x03 , // bInterfaceClass: HID
0x00 , // bInterfaceSubClass: None
0x00 , // bInterfaceProtocol: None
0 ) , // iInterface
/* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
USB_DESC_BYTE ( 9 ) , // bLength
USB_DESC_BYTE ( 0x21 ) , // bDescriptorType (HID class)
USB_DESC_BCD ( 0x0111 ) , // bcdHID: HID version 1.11
USB_DESC_BYTE ( 0 ) , // bCountryCode
USB_DESC_BYTE ( 1 ) , // bNumDescriptors
USB_DESC_BYTE ( 0x22 ) , // bDescriptorType (report desc)
USB_DESC_WORD ( sizeof ( nkro_hid_report_desc_data ) ) , // wDescriptorLength
/* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
USB_DESC_ENDPOINT ( NKRO_ENDPOINT | 0x80 , // bEndpointAddress
0x03 , // bmAttributes (Interrupt)
NKRO_EPSIZE , // wMaxPacketSize
1 ) , // bInterval
# endif /* NKRO_ENABLE */
} ;
/* Configuration Descriptor wrapper */
static const USBDescriptor hid_configuration_descriptor = {
sizeof hid_configuration_descriptor_data ,
hid_configuration_descriptor_data
} ;
/* wrappers */
# define HID_DESCRIPTOR_SIZE 9
static const USBDescriptor keyboard_hid_descriptor = {
HID_DESCRIPTOR_SIZE ,
& hid_configuration_descriptor_data [ KBD_HID_DESC_OFFSET ]
} ;
# ifdef MOUSE_ENABLE
static const USBDescriptor mouse_hid_descriptor = {
HID_DESCRIPTOR_SIZE ,
& hid_configuration_descriptor_data [ MOUSE_HID_DESC_OFFSET ]
} ;
# endif /* MOUSE_ENABLE */
# ifdef CONSOLE_ENABLE
static const USBDescriptor console_hid_descriptor = {
HID_DESCRIPTOR_SIZE ,
& hid_configuration_descriptor_data [ CONSOLE_HID_DESC_OFFSET ]
} ;
# endif /* CONSOLE_ENABLE */
# ifdef EXTRAKEY_ENABLE
static const USBDescriptor extra_hid_descriptor = {
HID_DESCRIPTOR_SIZE ,
& hid_configuration_descriptor_data [ EXTRA_HID_DESC_OFFSET ]
} ;
# endif /* EXTRAKEY_ENABLE */
# ifdef NKRO_ENABLE
static const USBDescriptor nkro_hid_descriptor = {
HID_DESCRIPTOR_SIZE ,
& hid_configuration_descriptor_data [ NKRO_HID_DESC_OFFSET ]
} ;
# endif /* NKRO_ENABLE */
/* U.S. English language identifier */
static const uint8_t usb_string_langid [ ] = {
USB_DESC_BYTE ( 4 ) , // bLength
USB_DESC_BYTE ( USB_DESCRIPTOR_STRING ) , // bDescriptorType
USB_DESC_WORD ( 0x0409 ) // wLANGID (U.S. English)
} ;
/* ugly ugly hack */
# define PP_NARG(...) \
PP_NARG_ ( __VA_ARGS__ , PP_RSEQ_N ( ) )
# define PP_NARG_(...) \
PP_ARG_N ( __VA_ARGS__ )
# define PP_ARG_N( \
_1 , _2 , _3 , _4 , _5 , _6 , _7 , _8 , _9 , _10 , \
_11 , _12 , _13 , _14 , _15 , _16 , _17 , _18 , _19 , _20 , \
_21 , _22 , _23 , _24 , _25 , _26 , _27 , _28 , _29 , _30 , \
_31 , _32 , _33 , _34 , _35 , _36 , _37 , _38 , _39 , _40 , \
_41 , _42 , _43 , _44 , _45 , _46 , _47 , _48 , _49 , _50 , \
_51 , _52 , _53 , _54 , _55 , _56 , _57 , _58 , _59 , _60 , \
_61 , _62 , _63 , N , . . . ) N
# define PP_RSEQ_N() \
63 , 62 , 61 , 60 , \
59 , 58 , 57 , 56 , 55 , 54 , 53 , 52 , 51 , 50 , \
49 , 48 , 47 , 46 , 45 , 44 , 43 , 42 , 41 , 40 , \
39 , 38 , 37 , 36 , 35 , 34 , 33 , 32 , 31 , 30 , \
29 , 28 , 27 , 26 , 25 , 24 , 23 , 22 , 21 , 20 , \
19 , 18 , 17 , 16 , 15 , 14 , 13 , 12 , 11 , 10 , \
9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 , 0
/* Vendor string = manufacturer */
static const uint8_t usb_string_vendor [ ] = {
USB_DESC_BYTE ( PP_NARG ( USBSTR_MANUFACTURER ) + 2 ) , // bLength
USB_DESC_BYTE ( USB_DESCRIPTOR_STRING ) , // bDescriptorType
USBSTR_MANUFACTURER
} ;
/* Device Description string = product */
static const uint8_t usb_string_description [ ] = {
USB_DESC_BYTE ( PP_NARG ( USBSTR_PRODUCT ) + 2 ) , // bLength
USB_DESC_BYTE ( USB_DESCRIPTOR_STRING ) , // bDescriptorType
USBSTR_PRODUCT
} ;
/* Serial Number string (will be filled by the function init_usb_serial_string) */
static uint8_t usb_string_serial [ ] = {
USB_DESC_BYTE ( 22 ) , // bLength
USB_DESC_BYTE ( USB_DESCRIPTOR_STRING ) , // bDescriptorType
' 0 ' , 0 , ' x ' , 0 , ' D ' , 0 , ' E ' , 0 , ' A ' , 0 , ' D ' , 0 , ' B ' , 0 , ' E ' , 0 , ' E ' , 0 , ' F ' , 0
} ;
/* Strings wrappers array */
static const USBDescriptor usb_strings [ ] = {
{ sizeof usb_string_langid , usb_string_langid }
,
{ sizeof usb_string_vendor , usb_string_vendor }
,
{ sizeof usb_string_description , usb_string_description }
,
{ sizeof usb_string_serial , usb_string_serial }
} ;
/*
/*
* Handles the GET_DESCRIPTOR callback
* Handles the GET_DESCRIPTOR callback
*
*
* Returns the proper descriptor
* Returns the proper descriptor
*/
*/
static const USBDescriptor * usb_get_descriptor_cb ( USBDriver * usbp , uint8_t dtype , uint8_t dindex , uint16_t lang ) {
static const USBDescriptor * usb_get_descriptor_cb ( USBDriver * usbp , uint8_t dtype , uint8_t dindex , uint16_t wIndex ) {
( void ) usbp ;
( void ) usbp ;
( void ) lang ;
static USBDescriptor desc ;
switch ( dtype ) {
uint16_t wValue = ( ( uint16_t ) dtype < < 8 ) | dindex ;
/* Generic descriptors */
desc . ud_string = NULL ;
case USB_DESCRIPTOR_DEVICE : /* Device Descriptor */
desc . ud_size = get_usb_descriptor ( wValue , wIndex , ( const void * * const ) & desc . ud_string ) ;
return & usb_device_descriptor ;
if ( desc . ud_string = = NULL )
case USB_DESCRIPTOR_CONFIGURATION : /* Configuration Descriptor */
return & hid_configuration_descriptor ;
case USB_DESCRIPTOR_STRING : /* Strings */
if ( dindex < 4 )
return & usb_strings [ dindex ] ;
break ;
/* HID specific descriptors */
case USB_DESCRIPTOR_HID : /* HID Descriptors */
switch ( lang ) { /* yea, poor label, it's actually wIndex from the setup packet */
case KBD_INTERFACE :
return & keyboard_hid_descriptor ;
# ifdef MOUSE_ENABLE
case MOUSE_INTERFACE :
return & mouse_hid_descriptor ;
# endif /* MOUSE_ENABLE */
# ifdef CONSOLE_ENABLE
case CONSOLE_INTERFACE :
return & console_hid_descriptor ;
# endif /* CONSOLE_ENABLE */
# ifdef EXTRAKEY_ENABLE
case EXTRA_INTERFACE :
return & extra_hid_descriptor ;
# endif /* EXTRAKEY_ENABLE */
# ifdef NKRO_ENABLE
case NKRO_INTERFACE :
return & nkro_hid_descriptor ;
# endif /* NKRO_ENABLE */
}
case USB_DESCRIPTOR_HID_REPORT : /* HID Report Descriptor */
switch ( lang ) {
case KBD_INTERFACE :
return & keyboard_hid_report_descriptor ;
# ifdef MOUSE_ENABLE
case MOUSE_INTERFACE :
return & mouse_hid_report_descriptor ;
# endif /* MOUSE_ENABLE */
# ifdef CONSOLE_ENABLE
case CONSOLE_INTERFACE :
return & console_hid_report_descriptor ;
# endif /* CONSOLE_ENABLE */
# ifdef EXTRAKEY_ENABLE
case EXTRA_INTERFACE :
return & extra_hid_report_descriptor ;
# endif /* EXTRAKEY_ENABLE */
# ifdef NKRO_ENABLE
case NKRO_INTERFACE :
return & nkro_hid_report_descriptor ;
# endif /* NKRO_ENABLE */
}
}
return NULL ;
return NULL ;
else
return & desc ;
}
}
/* keyboard endpoint state structure */
/* keyboard endpoint state structure */
@ -685,7 +102,7 @@ static const USBEndpointConfig kbd_ep_config = {
NULL , /* SETUP packet notification callback */
NULL , /* SETUP packet notification callback */
kbd_in_cb , /* IN notification callback */
kbd_in_cb , /* IN notification callback */
NULL , /* OUT notification callback */
NULL , /* OUT notification callback */
K BD_EPSIZE, /* IN maximum packet size */
K EY BOAR D_EPSIZE, /* IN maximum packet size */
0 , /* OUT maximum packet size */
0 , /* OUT maximum packet size */
& kbd_ep_state , /* IN Endpoint state */
& kbd_ep_state , /* IN Endpoint state */
NULL , /* OUT endpoint state */
NULL , /* OUT endpoint state */
@ -712,25 +129,6 @@ static const USBEndpointConfig mouse_ep_config = {
} ;
} ;
# endif /* MOUSE_ENABLE */
# endif /* MOUSE_ENABLE */
# ifdef CONSOLE_ENABLE
/* console endpoint state structure */
static USBInEndpointState console_ep_state ;
/* console endpoint initialization structure (IN) */
static const USBEndpointConfig console_ep_config = {
USB_EP_MODE_TYPE_INTR , /* Interrupt EP */
NULL , /* SETUP packet notification callback */
console_in_cb , /* IN notification callback */
NULL , /* OUT notification callback */
CONSOLE_EPSIZE , /* IN maximum packet size */
0 , /* OUT maximum packet size */
& console_ep_state , /* IN Endpoint state */
NULL , /* OUT endpoint state */
2 , /* IN multiplier */
NULL /* SETUP buffer (not a SETUP endpoint) */
} ;
# endif /* CONSOLE_ENABLE */
# ifdef EXTRAKEY_ENABLE
# ifdef EXTRAKEY_ENABLE
/* extrakey endpoint state structure */
/* extrakey endpoint state structure */
static USBInEndpointState extra_ep_state ;
static USBInEndpointState extra_ep_state ;
@ -741,7 +139,7 @@ static const USBEndpointConfig extra_ep_config = {
NULL , /* SETUP packet notification callback */
NULL , /* SETUP packet notification callback */
extra_in_cb , /* IN notification callback */
extra_in_cb , /* IN notification callback */
NULL , /* OUT notification callback */
NULL , /* OUT notification callback */
EXTRA _EPSIZE, /* IN maximum packet size */
EXTRA KEY _EPSIZE, /* IN maximum packet size */
0 , /* OUT maximum packet size */
0 , /* OUT maximum packet size */
& extra_ep_state , /* IN Endpoint state */
& extra_ep_state , /* IN Endpoint state */
NULL , /* OUT endpoint state */
NULL , /* OUT endpoint state */
@ -769,6 +167,129 @@ static const USBEndpointConfig nkro_ep_config = {
} ;
} ;
# endif /* NKRO_ENABLE */
# endif /* NKRO_ENABLE */
typedef struct {
size_t queue_capacity_in ;
size_t queue_capacity_out ;
uint8_t * queue_buffer_in ;
uint8_t * queue_buffer_out ;
USBInEndpointState in_ep_state ;
USBOutEndpointState out_ep_state ;
USBInEndpointState int_ep_state ;
USBEndpointConfig in_ep_config ;
USBEndpointConfig out_ep_config ;
USBEndpointConfig int_ep_config ;
const SerialUSBConfig config ;
SerialUSBDriver driver ;
} stream_driver_t ;
# define STREAM_DRIVER(stream, notification) { \
. queue_capacity_in = stream # # _IN_CAPACITY , \
. queue_capacity_out = stream # # _OUT_CAPACITY , \
. queue_buffer_in = ( uint8_t [ BQ_BUFFER_SIZE ( stream # # _IN_CAPACITY , stream # # _EPSIZE ) ] ) { } , \
. queue_buffer_out = ( uint8_t [ BQ_BUFFER_SIZE ( stream # # _OUT_CAPACITY , stream # # _EPSIZE ) ] ) { } , \
. in_ep_config = { \
. ep_mode = stream # # _IN_MODE , \
. setup_cb = NULL , \
. in_cb = sduDataTransmitted , \
. out_cb = NULL , \
. in_maxsize = stream # # _EPSIZE , \
. out_maxsize = 0 , \
/* The pointer to the states will be filled during initialization */ \
. in_state = NULL , \
. out_state = NULL , \
. ep_buffers = 2 , \
. setup_buf = NULL \
} , \
. out_ep_config = { \
. ep_mode = stream # # _OUT_MODE , \
. setup_cb = NULL , \
. in_cb = NULL , \
. out_cb = sduDataReceived , \
. in_maxsize = 0 , \
. out_maxsize = stream # # _EPSIZE , \
/* The pointer to the states will be filled during initialization */ \
. in_state = NULL , \
. out_state = NULL , \
. ep_buffers = 2 , \
. setup_buf = NULL , \
} , \
. int_ep_config = { \
. ep_mode = USB_EP_MODE_TYPE_INTR , \
. setup_cb = NULL , \
. in_cb = sduInterruptTransmitted , \
. out_cb = NULL , \
. in_maxsize = CDC_NOTIFICATION_EPSIZE , \
. out_maxsize = 0 , \
/* The pointer to the states will be filled during initialization */ \
. in_state = NULL , \
. out_state = NULL , \
. ep_buffers = 2 , \
. setup_buf = NULL , \
} , \
. config = { \
. usbp = & USB_DRIVER , \
. bulk_in = stream # # _IN_EPNUM , \
. bulk_out = stream # # _OUT_EPNUM , \
. int_in = notification \
} \
}
typedef struct {
union {
struct {
# ifdef CONSOLE_ENABLE
stream_driver_t console_driver ;
# endif
# ifdef RAW_ENABLE
stream_driver_t raw_driver ;
# endif
# ifdef MIDI_ENABLE
stream_driver_t midi_driver ;
# endif
# ifdef VIRTSER_ENABLE
stream_driver_t serial_driver ;
# endif
} ;
stream_driver_t array [ 0 ] ;
} ;
} stream_drivers_t ;
static stream_drivers_t drivers = {
# ifdef CONSOLE_ENABLE
# define CONSOLE_IN_CAPACITY 4
# define CONSOLE_OUT_CAPACITY 4
# define CONSOLE_IN_MODE USB_EP_MODE_TYPE_INTR
# define CONSOLE_OUT_MODE USB_EP_MODE_TYPE_INTR
. console_driver = STREAM_DRIVER ( CONSOLE , 0 ) ,
# endif
# ifdef RAW_ENABLE
# define RAW_IN_CAPACITY 4
# define RAW_OUT_CAPACITY 4
# define RAW_IN_MODE USB_EP_MODE_TYPE_INTR
# define RAW_OUT_MODE USB_EP_MODE_TYPE_INTR
. raw_driver = STREAM_DRIVER ( RAW , 0 ) ,
# endif
# ifdef MIDI_ENABLE
# define MIDI_STREAM_IN_CAPACITY 4
# define MIDI_STREAM_OUT_CAPACITY 4
# define MIDI_STREAM_IN_MODE USB_EP_MODE_TYPE_BULK
# define MIDI_STREAM_OUT_MODE USB_EP_MODE_TYPE_BULK
. midi_driver = STREAM_DRIVER ( MIDI_STREAM , 0 ) ,
# endif
# ifdef VIRTSER_ENABLE
# define CDC_IN_CAPACITY 4
# define CDC_OUT_CAPACITY 4
# define CDC_IN_MODE USB_EP_MODE_TYPE_BULK
# define CDC_OUT_MODE USB_EP_MODE_TYPE_BULK
. serial_driver = STREAM_DRIVER ( CDC , CDC_NOTIFICATION_EPNUM ) ,
# endif
} ;
# define NUM_STREAM_DRIVERS (sizeof(drivers) / sizeof(stream_driver_t))
/* ---------------------------------------------------------
/* ---------------------------------------------------------
* USB driver functions
* USB driver functions
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -784,24 +305,27 @@ static void usb_event_cb(USBDriver *usbp, usbevent_t event) {
case USB_EVENT_CONFIGURED :
case USB_EVENT_CONFIGURED :
osalSysLockFromISR ( ) ;
osalSysLockFromISR ( ) ;
/* Enable the endpoints specified into the configuration. */
/* Enable the endpoints specified into the configuration. */
usbInitEndpointI ( usbp , K BD_ENDPOINT , & kbd_ep_config ) ;
usbInitEndpointI ( usbp , K EYBOARD_IN_EPNUM , & kbd_ep_config ) ;
# ifdef MOUSE_ENABLE
# ifdef MOUSE_ENABLE
usbInitEndpointI ( usbp , MOUSE_ ENDPOINT , & mouse_ep_config ) ;
usbInitEndpointI ( usbp , MOUSE_ IN_EPNUM , & mouse_ep_config ) ;
# endif /* MOUSE_ENABLE */
# endif /* MOUSE_ENABLE */
# ifdef CONSOLE_ENABLE
usbInitEndpointI ( usbp , CONSOLE_ENDPOINT , & console_ep_config ) ;
/* don't need to start the flush timer, it starts from console_in_cb automatically */
# endif /* CONSOLE_ENABLE */
# ifdef EXTRAKEY_ENABLE
# ifdef EXTRAKEY_ENABLE
usbInitEndpointI ( usbp , EXTRA _ENDPOINT , & extra_ep_config ) ;
usbInitEndpointI ( usbp , EXTRAKEY_IN_EPNUM , & extra_ep_config ) ;
# endif /* EXTRAKEY_ENABLE */
# endif /* EXTRAKEY_ENABLE */
# ifdef NKRO_ENABLE
# ifdef NKRO_ENABLE
usbInitEndpointI ( usbp , NKRO_ ENDPOINT , & nkro_ep_config ) ;
usbInitEndpointI ( usbp , NKRO_ IN_EPNUM , & nkro_ep_config ) ;
# endif /* NKRO_ENABLE */
# endif /* NKRO_ENABLE */
for ( int i = 0 ; i < NUM_STREAM_DRIVERS ; i + + ) {
usbInitEndpointI ( usbp , drivers . array [ i ] . config . bulk_in , & drivers . array [ i ] . in_ep_config ) ;
usbInitEndpointI ( usbp , drivers . array [ i ] . config . bulk_out , & drivers . array [ i ] . out_ep_config ) ;
if ( drivers . array [ i ] . config . int_in ) {
usbInitEndpointI ( usbp , drivers . array [ i ] . config . int_in , & drivers . array [ i ] . int_ep_config ) ;
}
sduConfigureHookI ( & drivers . array [ i ] . driver ) ;
}
osalSysUnlockFromISR ( ) ;
osalSysUnlockFromISR ( ) ;
return ;
return ;
case USB_EVENT_SUSPEND :
case USB_EVENT_SUSPEND :
//TODO: from ISR! print("[S]");
# ifdef SLEEP_LED_ENABLE
# ifdef SLEEP_LED_ENABLE
sleep_led_enable ( ) ;
sleep_led_enable ( ) ;
# endif /* SLEEP_LED_ENABLE */
# endif /* SLEEP_LED_ENABLE */
@ -809,10 +333,22 @@ static void usb_event_cb(USBDriver *usbp, usbevent_t event) {
case USB_EVENT_UNCONFIGURED :
case USB_EVENT_UNCONFIGURED :
/* Falls into.*/
/* Falls into.*/
case USB_EVENT_RESET :
case USB_EVENT_RESET :
for ( int i = 0 ; i < NUM_STREAM_DRIVERS ; i + + ) {
chSysLockFromISR ( ) ;
/* Disconnection event on suspend.*/
sduSuspendHookI ( & drivers . array [ i ] . driver ) ;
chSysUnlockFromISR ( ) ;
}
return ;
return ;
case USB_EVENT_WAKEUP :
case USB_EVENT_WAKEUP :
//TODO: from ISR! print("[W]");
//TODO: from ISR! print("[W]");
for ( int i = 0 ; i < NUM_STREAM_DRIVERS ; i + + ) {
chSysLockFromISR ( ) ;
/* Disconnection event on suspend.*/
sduWakeupHookI ( & drivers . array [ i ] . driver ) ;
chSysUnlockFromISR ( ) ;
}
suspend_wakeup_init ( ) ;
suspend_wakeup_init ( ) ;
# ifdef SLEEP_LED_ENABLE
# ifdef SLEEP_LED_ENABLE
sleep_led_disable ( ) ;
sleep_led_disable ( ) ;
@ -868,7 +404,7 @@ static bool usb_request_hook_cb(USBDriver *usbp) {
switch ( usbp - > setup [ 1 ] ) { /* bRequest */
switch ( usbp - > setup [ 1 ] ) { /* bRequest */
case HID_GET_REPORT :
case HID_GET_REPORT :
switch ( usbp - > setup [ 4 ] ) { /* LSB(wIndex) (check MSB==0?) */
switch ( usbp - > setup [ 4 ] ) { /* LSB(wIndex) (check MSB==0?) */
case K BD_INTERFACE:
case K EY BOAR D_INTERFACE:
# ifdef NKRO_ENABLE
# ifdef NKRO_ENABLE
case NKRO_INTERFACE :
case NKRO_INTERFACE :
# endif /* NKRO_ENABLE */
# endif /* NKRO_ENABLE */
@ -883,15 +419,8 @@ static bool usb_request_hook_cb(USBDriver *usbp) {
break ;
break ;
# endif /* MOUSE_ENABLE */
# endif /* MOUSE_ENABLE */
# ifdef CONSOLE_ENABLE
case CONSOLE_INTERFACE :
usbSetupTransfer ( usbp , console_queue_buffer , CONSOLE_EPSIZE , NULL ) ;
return TRUE ;
break ;
# endif /* CONSOLE_ENABLE */
# ifdef EXTRAKEY_ENABLE
# ifdef EXTRAKEY_ENABLE
case EXTRA _INTERFACE:
case EXTRAKEY_INTERFACE :
if ( usbp - > setup [ 3 ] = = 1 ) { /* MSB(wValue) [Report Type] == 1 [Input Report] */
if ( usbp - > setup [ 3 ] = = 1 ) { /* MSB(wValue) [Report Type] == 1 [Input Report] */
switch ( usbp - > setup [ 2 ] ) { /* LSB(wValue) [Report ID] */
switch ( usbp - > setup [ 2 ] ) { /* LSB(wValue) [Report ID] */
case REPORT_ID_SYSTEM :
case REPORT_ID_SYSTEM :
@ -921,7 +450,7 @@ static bool usb_request_hook_cb(USBDriver *usbp) {
break ;
break ;
case HID_GET_PROTOCOL :
case HID_GET_PROTOCOL :
if ( ( usbp - > setup [ 4 ] = = K BD_INTERFACE) & & ( usbp - > setup [ 5 ] = = 0 ) ) { /* wIndex */
if ( ( usbp - > setup [ 4 ] = = K EY BOAR D_INTERFACE) & & ( usbp - > setup [ 5 ] = = 0 ) ) { /* wIndex */
usbSetupTransfer ( usbp , & keyboard_protocol , 1 , NULL ) ;
usbSetupTransfer ( usbp , & keyboard_protocol , 1 , NULL ) ;
return TRUE ;
return TRUE ;
}
}
@ -938,7 +467,7 @@ static bool usb_request_hook_cb(USBDriver *usbp) {
switch ( usbp - > setup [ 1 ] ) { /* bRequest */
switch ( usbp - > setup [ 1 ] ) { /* bRequest */
case HID_SET_REPORT :
case HID_SET_REPORT :
switch ( usbp - > setup [ 4 ] ) { /* LSB(wIndex) (check MSB==0 and wLength==1?) */
switch ( usbp - > setup [ 4 ] ) { /* LSB(wIndex) (check MSB==0 and wLength==1?) */
case K BD_INTERFACE:
case K EY BOAR D_INTERFACE:
# ifdef NKRO_ENABLE
# ifdef NKRO_ENABLE
case NKRO_INTERFACE :
case NKRO_INTERFACE :
# endif /* NKRO_ENABLE */
# endif /* NKRO_ENABLE */
@ -951,7 +480,7 @@ static bool usb_request_hook_cb(USBDriver *usbp) {
break ;
break ;
case HID_SET_PROTOCOL :
case HID_SET_PROTOCOL :
if ( ( usbp - > setup [ 4 ] = = K BD_INTERFACE) & & ( usbp - > setup [ 5 ] = = 0 ) ) { /* wIndex */
if ( ( usbp - > setup [ 4 ] = = K EY BOAR D_INTERFACE) & & ( usbp - > setup [ 5 ] = = 0 ) ) { /* wIndex */
keyboard_protocol = ( ( usbp - > setup [ 2 ] ) ! = 0x00 ) ; /* LSB(wValue) */
keyboard_protocol = ( ( usbp - > setup [ 2 ] ) ! = 0x00 ) ; /* LSB(wValue) */
# ifdef NKRO_ENABLE
# ifdef NKRO_ENABLE
keymap_config . nkro = ! ! keyboard_protocol ;
keymap_config . nkro = ! ! keyboard_protocol ;
@ -998,12 +527,24 @@ static bool usb_request_hook_cb(USBDriver *usbp) {
return TRUE ;
return TRUE ;
}
}
for ( int i = 0 ; i < NUM_STREAM_DRIVERS ; i + + ) {
if ( drivers . array [ i ] . config . int_in ) {
// NOTE: Assumes that we only have one serial driver
return sduRequestsHook ( usbp ) ;
}
}
return FALSE ;
return FALSE ;
}
}
/* Start-of-frame callback */
/* Start-of-frame callback */
static void usb_sof_cb ( USBDriver * usbp ) {
static void usb_sof_cb ( USBDriver * usbp ) {
kbd_sof_cb ( usbp ) ;
kbd_sof_cb ( usbp ) ;
osalSysLockFromISR ( ) ;
for ( int i = 0 ; i < NUM_STREAM_DRIVERS ; i + + ) {
sduSOFHookI ( & drivers . array [ i ] . driver ) ;
}
osalSysUnlockFromISR ( ) ;
}
}
@ -1019,6 +560,19 @@ static const USBConfig usbcfg = {
* Initialize the USB driver
* Initialize the USB driver
*/
*/
void init_usb_driver ( USBDriver * usbp ) {
void init_usb_driver ( USBDriver * usbp ) {
for ( int i = 0 ; i < NUM_STREAM_DRIVERS ; i + + ) {
SerialUSBDriver * driver = & drivers . array [ i ] . driver ;
drivers . array [ i ] . in_ep_config . in_state = & drivers . array [ i ] . in_ep_state ;
drivers . array [ i ] . out_ep_config . out_state = & drivers . array [ i ] . out_ep_state ;
drivers . array [ i ] . int_ep_config . in_state = & drivers . array [ i ] . int_ep_state ;
sduObjectInit ( driver ) ;
bqnotify_t notify = driver - > ibqueue . notify ;
ibqObjectInit ( & driver - > ibqueue , false , drivers . array [ i ] . queue_buffer_in , drivers . array [ i ] . in_ep_config . in_maxsize , drivers . array [ i ] . queue_capacity_in , notify , driver ) ;
notify = driver - > obqueue . notify ;
ibqObjectInit ( & driver - > ibqueue , false , drivers . array [ i ] . queue_buffer_out , drivers . array [ i ] . out_ep_config . out_maxsize , drivers . array [ i ] . queue_capacity_out , notify , driver ) ;
sduStart ( driver , & drivers . array [ i ] . config ) ;
}
/*
/*
* Activates the USB driver and then the USB bus pull - up on D + .
* Activates the USB driver and then the USB bus pull - up on D + .
* Note , a delay is inserted in order to not have to disconnect the cable
* Note , a delay is inserted in order to not have to disconnect the cable
@ -1030,17 +584,12 @@ void init_usb_driver(USBDriver *usbp) {
usbConnectBus ( usbp ) ;
usbConnectBus ( usbp ) ;
chVTObjectInit ( & keyboard_idle_timer ) ;
chVTObjectInit ( & keyboard_idle_timer ) ;
# ifdef CONSOLE_ENABLE
obqObjectInit ( & console_buf_queue , false , console_queue_buffer , CONSOLE_EPSIZE , CONSOLE_QUEUE_CAPACITY , console_queue_onotify , ( void * ) usbp ) ;
chVTObjectInit ( & console_flush_timer ) ;
# endif
}
}
/* ---------------------------------------------------------
/* ---------------------------------------------------------
* Keyboard functions
* Keyboard functions
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
*/
/* keyboard IN callback hander (a kbd report has made it IN) */
/* keyboard IN callback hander (a kbd report has made it IN) */
void kbd_in_cb ( USBDriver * usbp , usbep_t ep ) {
void kbd_in_cb ( USBDriver * usbp , usbep_t ep ) {
/* STUB */
/* STUB */
@ -1084,8 +633,8 @@ static void keyboard_idle_timer_cb(void *arg) {
if ( keyboard_idle ) {
if ( keyboard_idle ) {
# endif /* NKRO_ENABLE */
# endif /* NKRO_ENABLE */
/* TODO: are we sure we want the KBD_ENDPOINT? */
/* TODO: are we sure we want the KBD_ENDPOINT? */
if ( ! usbGetTransmitStatusI ( usbp , K BD_ENDPOINT ) ) {
if ( ! usbGetTransmitStatusI ( usbp , K EYBOARD_IN_EPNUM ) ) {
usbStartTransmitI ( usbp , K BD_ENDPOINT , ( uint8_t * ) & keyboard_report_sent , K BD_EPSIZE) ;
usbStartTransmitI ( usbp , K EYBOARD_IN_EPNUM , ( uint8_t * ) & keyboard_report_sent , K EY BOAR D_EPSIZE) ;
}
}
/* rearm the timer */
/* rearm the timer */
chVTSetI ( & keyboard_idle_timer , 4 * MS2ST ( keyboard_idle ) , keyboard_idle_timer_cb , ( void * ) usbp ) ;
chVTSetI ( & keyboard_idle_timer , 4 * MS2ST ( keyboard_idle ) , keyboard_idle_timer_cb , ( void * ) usbp ) ;
@ -1119,14 +668,14 @@ void send_keyboard(report_keyboard_t *report) {
* this is more efficient */
* this is more efficient */
/* busy wait, should be short and not very common */
/* busy wait, should be short and not very common */
osalSysLock ( ) ;
osalSysLock ( ) ;
if ( usbGetTransmitStatusI ( & USB_DRIVER , NKRO_ ENDPOINT ) ) {
if ( usbGetTransmitStatusI ( & USB_DRIVER , NKRO_ IN_EPNUM ) ) {
/* Need to either suspend, or loop and call unlock/lock during
/* Need to either suspend, or loop and call unlock/lock during
* every iteration - otherwise the system will remain locked ,
* every iteration - otherwise the system will remain locked ,
* no interrupts served , so USB not going through as well .
* no interrupts served , so USB not going through as well .
* Note : for suspend , need USB_USE_WAIT = = TRUE in halconf . h */
* Note : for suspend , need USB_USE_WAIT = = TRUE in halconf . h */
osalThreadSuspendS ( & ( & USB_DRIVER ) - > epc [ NKRO_ ENDPOINT ] - > in_state - > thread ) ;
osalThreadSuspendS ( & ( & USB_DRIVER ) - > epc [ NKRO_ IN_EPNUM ] - > in_state - > thread ) ;
}
}
usbStartTransmitI ( & USB_DRIVER , NKRO_ ENDPOINT , ( uint8_t * ) report , sizeof ( report_keyboard_t ) ) ;
usbStartTransmitI ( & USB_DRIVER , NKRO_ IN_EPNUM , ( uint8_t * ) report , sizeof ( report_keyboard_t ) ) ;
osalSysUnlock ( ) ;
osalSysUnlock ( ) ;
} else
} else
# endif /* NKRO_ENABLE */
# endif /* NKRO_ENABLE */
@ -1134,14 +683,14 @@ void send_keyboard(report_keyboard_t *report) {
/* need to wait until the previous packet has made it through */
/* need to wait until the previous packet has made it through */
/* busy wait, should be short and not very common */
/* busy wait, should be short and not very common */
osalSysLock ( ) ;
osalSysLock ( ) ;
if ( usbGetTransmitStatusI ( & USB_DRIVER , K BD_ENDPOINT ) ) {
if ( usbGetTransmitStatusI ( & USB_DRIVER , K EYBOARD_IN_EPNUM ) ) {
/* Need to either suspend, or loop and call unlock/lock during
/* Need to either suspend, or loop and call unlock/lock during
* every iteration - otherwise the system will remain locked ,
* every iteration - otherwise the system will remain locked ,
* no interrupts served , so USB not going through as well .
* no interrupts served , so USB not going through as well .
* Note : for suspend , need USB_USE_WAIT = = TRUE in halconf . h */
* Note : for suspend , need USB_USE_WAIT = = TRUE in halconf . h */
osalThreadSuspendS ( & ( & USB_DRIVER ) - > epc [ K BD_ENDPOINT ] - > in_state - > thread ) ;
osalThreadSuspendS ( & ( & USB_DRIVER ) - > epc [ K EYBOARD_IN_EPNUM ] - > in_state - > thread ) ;
}
}
usbStartTransmitI ( & USB_DRIVER , K BD_ENDPOINT , ( uint8_t * ) report , K BD_EPSIZE) ;
usbStartTransmitI ( & USB_DRIVER , K EYBOARD_IN_EPNUM , ( uint8_t * ) report , K EY BOAR D_EPSIZE) ;
osalSysUnlock ( ) ;
osalSysUnlock ( ) ;
}
}
keyboard_report_sent = * report ;
keyboard_report_sent = * report ;
@ -1174,7 +723,7 @@ void send_mouse(report_mouse_t *report) {
*/
*/
osalSysLock ( ) ;
osalSysLock ( ) ;
usbStartTransmitI ( & USB_DRIVER , MOUSE_ ENDPOINT , ( uint8_t * ) report , sizeof ( report_mouse_t ) ) ;
usbStartTransmitI ( & USB_DRIVER , MOUSE_ IN_EPNUM , ( uint8_t * ) report , sizeof ( report_mouse_t ) ) ;
osalSysUnlock ( ) ;
osalSysUnlock ( ) ;
}
}
@ -1210,7 +759,7 @@ static void send_extra_report(uint8_t report_id, uint16_t data) {
. usage = data
. usage = data
} ;
} ;
usbStartTransmitI ( & USB_DRIVER , EXTRA _ENDPOINT , ( uint8_t * ) & report , sizeof ( report_extra_t ) ) ;
usbStartTransmitI ( & USB_DRIVER , EXTRA KEY_IN_EPNUM , ( uint8_t * ) & report , sizeof ( report_extra_t ) ) ;
osalSysUnlock ( ) ;
osalSysUnlock ( ) ;
}
}
@ -1238,125 +787,107 @@ void send_consumer(uint16_t data) {
# ifdef CONSOLE_ENABLE
# ifdef CONSOLE_ENABLE
/* console IN callback hander */
int8_t sendchar ( uint8_t c ) {
void console_in_cb ( USBDriver * usbp , usbep_t ep ) {
// The previous implmentation had timeouts, but I think it's better to just slow down
( void ) ep ; /* should have ep == CONSOLE_ENDPOINT, so use that to save time/space */
// and make sure that everything is transferred, rather than dropping stuff
uint8_t * buf ;
return chnWrite ( & drivers . console_driver . driver , & c , 1 ) ;
size_t n ;
osalSysLockFromISR ( ) ;
/* rearm the timer */
chVTSetI ( & console_flush_timer , MS2ST ( CONSOLE_FLUSH_MS ) , console_flush_cb , ( void * ) usbp ) ;
/* Freeing the buffer just transmitted, if it was not a zero size packet.*/
if ( usbp - > epc [ CONSOLE_ENDPOINT ] - > in_state - > txsize > 0U ) {
obqReleaseEmptyBufferI ( & console_buf_queue ) ;
}
}
/* Checking if there is a buffer ready for transmission.*/
// Just a dummy function for now, this could be exposed as a weak function
buf = obqGetFullBufferI ( & console_buf_queue , & n ) ;
// Or connected to the actual QMK console
static void console_receive ( uint8_t * data , uint8_t length ) {
( void ) data ;
( void ) length ;
}
if ( buf ! = NULL ) {
void console_task ( void ) {
/* The endpoint cannot be busy, we are in the context of the callback,
uint8_t buffer [ CONSOLE_EPSIZE ] ;
so it is safe to transmit without a check . */
size_t size = 0 ;
/* Should have n == CONSOLE_EPSIZE; check it? */
do {
usbStartTransmitI ( usbp , CONSOLE_ENDPOINT , buf , CONSOLE_EPSIZE ) ;
size_t size = chnReadTimeout ( & drivers . console_driver . driver , buffer , sizeof ( buffer ) , TIME_IMMEDIATE ) ;
} else {
if ( size > 0 ) {
/* Nothing to transmit.*/
console_receive ( buffer , size ) ;
}
} while ( size > 0 ) ;
}
}
osalSysUnlockFromISR ( ) ;
# else /* CONSOLE_ENABLE */
int8_t sendchar ( uint8_t c ) {
( void ) c ;
return 0 ;
}
}
# endif /* CONSOLE_ENABLE */
/* Callback when data is inserted into the output queue
void sendchar_pf ( void * p , char c ) {
* Called from a locked state */
( void ) p ;
void console_queue_onotify ( io_buffers_queue_t * bqp ) {
sendchar ( ( uint8_t ) c ) ;
size_t n ;
}
USBDriver * usbp = bqGetLinkX ( bqp ) ;
if ( usbGetDriverStateI ( usbp ) ! = USB_ACTIVE )
# ifdef RAW_ENABLE
void raw_hid_send ( uint8_t * data , uint8_t length ) {
// TODO: implement variable size packet
if ( length ! = RAW_EPSIZE )
{
return ;
return ;
/* Checking if there is already a transaction ongoing on the endpoint.*/
if ( ! usbGetTransmitStatusI ( usbp , CONSOLE_ENDPOINT ) ) {
/* Trying to get a full buffer.*/
uint8_t * buf = obqGetFullBufferI ( & console_buf_queue , & n ) ;
if ( buf ! = NULL ) {
/* Buffer found, starting a new transaction.*/
/* Should have n == CONSOLE_EPSIZE; check this? */
usbStartTransmitI ( usbp , CONSOLE_ENDPOINT , buf , CONSOLE_EPSIZE ) ;
}
}
}
chnWrite ( & drivers . raw_driver . driver , data , length ) ;
}
}
/* Flush timer code
__attribute__ ( ( weak ) )
* callback ( called from ISR , unlocked state ) */
void raw_hid_receive ( uint8_t * data , uint8_t length ) {
static void console_flush_cb ( void * arg ) {
// Users should #include "raw_hid.h" in their own code
USBDriver * usbp = ( USBDriver * ) arg ;
// and implement this function there. Leave this as weak linkage
osalSysLockFromISR ( ) ;
// so users can opt to not handle data coming in.
/* check that the states of things are as they're supposed to */
if ( usbGetDriverStateI ( usbp ) ! = USB_ACTIVE ) {
/* rearm the timer */
chVTSetI ( & console_flush_timer , MS2ST ( CONSOLE_FLUSH_MS ) , console_flush_cb , ( void * ) usbp ) ;
osalSysUnlockFromISR ( ) ;
return ;
}
}
/* If there is already a transaction ongoing then another one cannot be
void raw_hid_task ( void ) {
started . */
uint8_t buffer [ RAW_EPSIZE ] ;
if ( usbGetTransmitStatusI ( usbp , CONSOLE_ENDPOINT ) ) {
size_t size = 0 ;
/* rearm the timer */
do {
chVTSetI ( & console_flush_timer , MS2ST ( CONSOLE_FLUSH_MS ) , console_flush_cb , ( void * ) usbp ) ;
size_t size = chnReadTimeout ( & drivers . raw_driver . driver , buffer , sizeof ( buffer ) , TIME_IMMEDIATE ) ;
osalSysUnlockFromISR ( ) ;
if ( size > 0 ) {
return ;
raw_hid_receive ( buffer , size ) ;
}
} while ( size > 0 ) ;
}
}
/* Checking if there only a buffer partially filled, if so then it is
# endif
enforced in the queue and transmitted . */
if ( obqTryFlushI ( & console_buf_queue ) ) {
size_t n , i ;
uint8_t * buf = obqGetFullBufferI ( & console_buf_queue , & n ) ;
osalDbgAssert ( buf ! = NULL , " queue is empty " ) ;
# ifdef MIDI_ENABLE
/* zero the rest of the buffer (buf should point to allocated space) */
void send_midi_packet ( MIDI_EventPacket_t * event ) {
for ( i = n ; i < CONSOLE_EPSIZE ; i + + )
chnWrite ( & drivers . midi_driver . driver , ( uint8_t * ) event , sizeof ( MIDI_EventPacket_t ) ) ;
buf [ i ] = 0 ;
usbStartTransmitI ( usbp , CONSOLE_ENDPOINT , buf , CONSOLE_EPSIZE ) ;
}
}
/* rearm the timer */
bool recv_midi_packet ( MIDI_EventPacket_t * const event ) {
chVTSetI ( & console_flush_timer , MS2ST ( CONSOLE_FLUSH_MS ) , console_flush_cb , ( void * ) usbp ) ;
size_t size = chnReadTimeout ( & drivers . midi_driver . driver , ( uint8_t * ) event , sizeof ( MIDI_EventPacket_t ) , TIME_IMMEDIATE ) ;
osalSysUnlockFromISR ( ) ;
return size = = sizeof ( MIDI_EventPacket_t ) ;
}
}
# endif
int8_t sendchar ( uint8_t c ) {
# ifdef VIRTSER_ENABLE
osalSysLock ( ) ;
if ( usbGetDriverStateI ( & USB_DRIVER ) ! = USB_ACTIVE ) {
void virtser_send ( const uint8_t byte ) {
osalSysUnlock ( ) ;
chnWrite ( & drivers . serial_driver . driver , & byte , 1 ) ;
return 0 ;
}
osalSysUnlock ( ) ;
/* Timeout after 100us if the queue is full.
* Increase this timeout if too much stuff is getting
* dropped ( i . e . the buffer is getting full too fast
* for USB / HIDRAW to dequeue ) . Another possibility
* for fixing this kind of thing is to increase
* CONSOLE_QUEUE_CAPACITY . */
return ( obqPutTimeout ( & console_buf_queue , c , US2ST ( 100 ) ) ) ;
}
}
# else /* CONSOLE_ENABLE */
__attribute__ ( ( weak ) )
int8_t sendchar ( uint8_t c ) {
void virtser_recv ( uint8_t c )
( void ) c ;
{
return 0 ;
// Ignore by default
}
}
# endif /* CONSOLE_ENABLE */
void sendchar_pf ( void * p , char c ) {
void virtser_task ( void ) {
( void ) p ;
uint8_t numBytesReceived = 0 ;
sendchar ( ( uint8_t ) c ) ;
uint8_t buffer [ 16 ] ;
do {
numBytesReceived = chnReadTimeout ( & drivers . serial_driver . driver , buffer , sizeof ( buffer ) , TIME_IMMEDIATE ) ;
for ( int i = 0 ; i < numBytesReceived ; i + + ) {
virtser_recv ( buffer [ i ] ) ;
}
}
} while ( numBytesReceived > 0 ) ;
}
# endif