]> git.friedersdorff.com Git - max/tmk_keyboard.git/blob - tmk_core/protocol/chibios/usb_main.c
Small updates.
[max/tmk_keyboard.git] / tmk_core / protocol / chibios / usb_main.c
1 /*
2  * (c) 2015 flabberast <s3+flabbergast@sdfeu.org>
3  *
4  * Based on the following work:
5  *  - Guillaume Duc's raw hid example (MIT License)
6  *    https://github.com/guiduc/usb-hid-chibios-example
7  *  - PJRC Teensy examples (MIT License)
8  *    https://www.pjrc.com/teensy/usb_keyboard.html
9  *  - hasu's TMK keyboard code (GPL v2 and some code Modified BSD)
10  *    https://github.com/tmk/tmk_keyboard/
11  *  - ChibiOS demo code (Apache 2.0 License)
12  *    http://www.chibios.org
13  *
14  * Since some GPL'd code is used, this work is licensed under
15  * GPL v2 or later.
16  */
17
18 #include "ch.h"
19 #include "hal.h"
20
21 #include "usb_main.h"
22
23 #include "debug.h"
24 #ifdef SLEEP_LED_ENABLE
25 #include "sleep_led.h"
26 #endif
27
28 /* ---------------------------------------------------------
29  *       Global interface variables and declarations
30  * ---------------------------------------------------------
31  */
32
33 uint8_t keyboard_idle = 0;
34 uint8_t keyboard_protocol = 1;
35 uint16_t keyboard_led_stats = 0;
36 volatile uint16_t keyboard_idle_count = 0;
37 static virtual_timer_t keyboard_idle_timer;
38 static void keyboard_idle_timer_cb(void *arg);
39 #ifdef NKRO_ENABLE
40 bool keyboard_nkro = true;
41 #endif /* NKRO_ENABLE */
42
43 report_keyboard_t keyboard_report_sent = {{0}};
44
45 #ifdef CONSOLE_ENABLE
46 /* The emission queue */
47 output_queue_t console_queue;
48 static uint8_t console_queue_buffer[CONSOLE_QUEUE_BUFFER_SIZE];
49 static virtual_timer_t console_flush_timer;
50 void console_queue_onotify(io_queue_t *qp);
51 static void console_flush_cb(void *arg);
52 #endif /* CONSOLE_ENABLE */
53
54 /* ---------------------------------------------------------
55  *            Descriptors and USB driver objects
56  * ---------------------------------------------------------
57  */
58
59 /* HID specific constants */
60 #define USB_DESCRIPTOR_HID 0x21
61 #define USB_DESCRIPTOR_HID_REPORT 0x22
62 #define HID_GET_REPORT 0x01
63 #define HID_GET_IDLE 0x02
64 #define HID_GET_PROTOCOL 0x03
65 #define HID_SET_REPORT 0x09
66 #define HID_SET_IDLE 0x0A
67 #define HID_SET_PROTOCOL 0x0B
68
69 /* USB Device Descriptor */
70 static const uint8_t usb_device_descriptor_data[] = {
71   USB_DESC_DEVICE(0x0200,      // bcdUSB (1.1)
72                   0,           // bDeviceClass (defined in later in interface)
73                   0,           // bDeviceSubClass
74                   0,           // bDeviceProtocol
75                   64,          // bMaxPacketSize (64 bytes) (the driver didn't work with 32)
76                   VENDOR_ID,   // idVendor
77                   PRODUCT_ID,  // idProduct
78                   DEVICE_VER,      // bcdDevice
79                   1,           // iManufacturer
80                   2,           // iProduct
81                   3,           // iSerialNumber
82                   1)           // bNumConfigurations
83 };
84
85 /* Device Descriptor wrapper */
86 static const USBDescriptor usb_device_descriptor = {
87   sizeof usb_device_descriptor_data,
88   usb_device_descriptor_data
89 };
90
91 /*
92  * HID Report Descriptor
93  *
94  * See "Device Class Definition for Human Interface Devices (HID)"
95  * (http://www.usb.org/developers/hidpage/HID1_11.pdf) for the
96  * detailed descrition of all the fields
97  */
98
99 /* Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60 */
100 static const uint8_t keyboard_hid_report_desc_data[] = {
101   0x05, 0x01,                // Usage Page (Generic Desktop),
102   0x09, 0x06,                // Usage (Keyboard),
103   0xA1, 0x01,                // Collection (Application),
104   0x75, 0x01,                //   Report Size (1),
105   0x95, 0x08,                //   Report Count (8),
106   0x05, 0x07,                //   Usage Page (Key Codes),
107   0x19, 0xE0,                //   Usage Minimum (224),
108   0x29, 0xE7,                //   Usage Maximum (231),
109   0x15, 0x00,                //   Logical Minimum (0),
110   0x25, 0x01,                //   Logical Maximum (1),
111   0x81, 0x02,                //   Input (Data, Variable, Absolute), ;Modifier byte
112   0x95, 0x01,                //   Report Count (1),
113   0x75, 0x08,                //   Report Size (8),
114   0x81, 0x03,                //   Input (Constant),                 ;Reserved byte
115   0x95, 0x05,                //   Report Count (5),
116   0x75, 0x01,                //   Report Size (1),
117   0x05, 0x08,                //   Usage Page (LEDs),
118   0x19, 0x01,                //   Usage Minimum (1),
119   0x29, 0x05,                //   Usage Maximum (5),
120   0x91, 0x02,                //   Output (Data, Variable, Absolute), ;LED report
121   0x95, 0x01,                //   Report Count (1),
122   0x75, 0x03,                //   Report Size (3),
123   0x91, 0x03,                //   Output (Constant),                 ;LED report padding
124   0x95, KBD_REPORT_KEYS,          //   Report Count (),
125   0x75, 0x08,                //   Report Size (8),
126   0x15, 0x00,                //   Logical Minimum (0),
127   0x25, 0xFF,                //   Logical Maximum(255),
128   0x05, 0x07,                //   Usage Page (Key Codes),
129   0x19, 0x00,                //   Usage Minimum (0),
130   0x29, 0xFF,                //   Usage Maximum (255),
131   0x81, 0x00,                //   Input (Data, Array),
132   0xc0                       // End Collection
133 };
134 /* wrapper */
135 static const USBDescriptor keyboard_hid_report_descriptor = {
136   sizeof keyboard_hid_report_desc_data,
137   keyboard_hid_report_desc_data
138 };
139
140 #ifdef NKRO_ENABLE
141 static const uint8_t nkro_hid_report_desc_data[] = {
142   0x05, 0x01,                           // Usage Page (Generic Desktop),
143   0x09, 0x06,                           // Usage (Keyboard),
144   0xA1, 0x01,                           // Collection (Application),
145   // bitmap of modifiers
146   0x75, 0x01,                           //   Report Size (1),
147   0x95, 0x08,                           //   Report Count (8),
148   0x05, 0x07,                           //   Usage Page (Key Codes),
149   0x19, 0xE0,                           //   Usage Minimum (224),
150   0x29, 0xE7,                           //   Usage Maximum (231),
151   0x15, 0x00,                           //   Logical Minimum (0),
152   0x25, 0x01,                           //   Logical Maximum (1),
153   0x81, 0x02,                           //   Input (Data, Variable, Absolute), ;Modifier byte
154   // LED output report
155   0x95, 0x05,                           //   Report Count (5),
156   0x75, 0x01,                           //   Report Size (1),
157   0x05, 0x08,                           //   Usage Page (LEDs),
158   0x19, 0x01,                           //   Usage Minimum (1),
159   0x29, 0x05,                           //   Usage Maximum (5),
160   0x91, 0x02,                           //   Output (Data, Variable, Absolute),
161   0x95, 0x01,                           //   Report Count (1),
162   0x75, 0x03,                           //   Report Size (3),
163   0x91, 0x03,                           //   Output (Constant),
164   // bitmap of keys
165   0x95, NKRO_REPORT_KEYS * 8,           //   Report Count (),
166   0x75, 0x01,                           //   Report Size (1),
167   0x15, 0x00,                           //   Logical Minimum (0),
168   0x25, 0x01,                           //   Logical Maximum(1),
169   0x05, 0x07,                           //   Usage Page (Key Codes),
170   0x19, 0x00,                           //   Usage Minimum (0),
171   0x29, NKRO_REPORT_KEYS * 8 - 1,       //   Usage Maximum (),
172   0x81, 0x02,                           //   Input (Data, Variable, Absolute),
173   0xc0                                  // End Collection
174 };
175 /* wrapper */
176 static const USBDescriptor nkro_hid_report_descriptor = {
177   sizeof nkro_hid_report_desc_data,
178   nkro_hid_report_desc_data
179 };
180 #endif /* NKRO_ENABLE */
181
182 #ifdef MOUSE_ENABLE
183 /* Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension
184  * http://www.microchip.com/forums/tm.aspx?high=&m=391435&mpage=1#391521
185  * http://www.keil.com/forum/15671/
186  * http://www.microsoft.com/whdc/device/input/wheel.mspx */
187 static const uint8_t mouse_hid_report_desc_data[] = {
188   /* mouse */
189   0x05, 0x01,                      // USAGE_PAGE (Generic Desktop)
190   0x09, 0x02,                      // USAGE (Mouse)
191   0xa1, 0x01,                      // COLLECTION (Application)
192   //0x85, REPORT_ID_MOUSE,         //   REPORT_ID (1)
193   0x09, 0x01,                      //   USAGE (Pointer)
194   0xa1, 0x00,                      //   COLLECTION (Physical)
195                                    // ----------------------------  Buttons
196   0x05, 0x09,                      //     USAGE_PAGE (Button)
197   0x19, 0x01,                      //     USAGE_MINIMUM (Button 1)
198   0x29, 0x05,                      //     USAGE_MAXIMUM (Button 5)
199   0x15, 0x00,                      //     LOGICAL_MINIMUM (0)
200   0x25, 0x01,                      //     LOGICAL_MAXIMUM (1)
201   0x75, 0x01,                      //     REPORT_SIZE (1)
202   0x95, 0x05,                      //     REPORT_COUNT (5)
203   0x81, 0x02,                      //     INPUT (Data,Var,Abs)
204   0x75, 0x03,                      //     REPORT_SIZE (3)
205   0x95, 0x01,                      //     REPORT_COUNT (1)
206   0x81, 0x03,                      //     INPUT (Cnst,Var,Abs)
207                                    // ----------------------------  X,Y position
208   0x05, 0x01,                      //     USAGE_PAGE (Generic Desktop)
209   0x09, 0x30,                      //     USAGE (X)
210   0x09, 0x31,                      //     USAGE (Y)
211   0x15, 0x81,                      //     LOGICAL_MINIMUM (-127)
212   0x25, 0x7f,                      //     LOGICAL_MAXIMUM (127)
213   0x75, 0x08,                      //     REPORT_SIZE (8)
214   0x95, 0x02,                      //     REPORT_COUNT (2)
215   0x81, 0x06,                      //     INPUT (Data,Var,Rel)
216                                    // ----------------------------  Vertical wheel
217   0x09, 0x38,                      //     USAGE (Wheel)
218   0x15, 0x81,                      //     LOGICAL_MINIMUM (-127)
219   0x25, 0x7f,                      //     LOGICAL_MAXIMUM (127)
220   0x35, 0x00,                      //     PHYSICAL_MINIMUM (0)        - reset physical
221   0x45, 0x00,                      //     PHYSICAL_MAXIMUM (0)
222   0x75, 0x08,                      //     REPORT_SIZE (8)
223   0x95, 0x01,                      //     REPORT_COUNT (1)
224   0x81, 0x06,                      //     INPUT (Data,Var,Rel)
225                                    // ----------------------------  Horizontal wheel
226   0x05, 0x0c,                      //     USAGE_PAGE (Consumer Devices)
227   0x0a, 0x38, 0x02,                //     USAGE (AC Pan)
228   0x15, 0x81,                      //     LOGICAL_MINIMUM (-127)
229   0x25, 0x7f,                      //     LOGICAL_MAXIMUM (127)
230   0x75, 0x08,                      //     REPORT_SIZE (8)
231   0x95, 0x01,                      //     REPORT_COUNT (1)
232   0x81, 0x06,                      //     INPUT (Data,Var,Rel)
233   0xc0,                            //   END_COLLECTION
234   0xc0,                            // END_COLLECTION
235 };
236 /* wrapper */
237 static const USBDescriptor mouse_hid_report_descriptor = {
238   sizeof mouse_hid_report_desc_data,
239   mouse_hid_report_desc_data
240 };
241 #endif /* MOUSE_ENABLE */
242
243 #ifdef CONSOLE_ENABLE
244 static const uint8_t console_hid_report_desc_data[] = {
245   0x06, 0x31, 0xFF, // Usage Page 0xFF31 (vendor defined)
246   0x09, 0x74,       // Usage 0x74
247   0xA1, 0x53,       // Collection 0x53
248   0x75, 0x08,       // report size = 8 bits
249   0x15, 0x00,       // logical minimum = 0
250   0x26, 0xFF, 0x00, // logical maximum = 255
251   0x95, CONSOLE_SIZE, // report count
252   0x09, 0x75,       // usage
253   0x81, 0x02,       // Input (array)
254   0xC0              // end collection
255 };
256 /* wrapper */
257 static const USBDescriptor console_hid_report_descriptor = {
258   sizeof console_hid_report_desc_data,
259   console_hid_report_desc_data
260 };
261 #endif /* CONSOLE_ENABLE */
262
263 #ifdef EXTRAKEY_ENABLE
264 /* audio controls & system controls
265  * http://www.microsoft.com/whdc/archive/w2kbd.mspx */
266 static const uint8_t extra_hid_report_desc_data[] = {
267   /* system control */
268   0x05, 0x01,                      // USAGE_PAGE (Generic Desktop)
269   0x09, 0x80,                      // USAGE (System Control)
270   0xa1, 0x01,                      // COLLECTION (Application)
271   0x85, REPORT_ID_SYSTEM,          //   REPORT_ID (2)
272   0x15, 0x01,                      //   LOGICAL_MINIMUM (0x1)
273   0x25, 0xb7,                      //   LOGICAL_MAXIMUM (0xb7)
274   0x19, 0x01,                      //   USAGE_MINIMUM (0x1)
275   0x29, 0xb7,                      //   USAGE_MAXIMUM (0xb7)
276   0x75, 0x10,                      //   REPORT_SIZE (16)
277   0x95, 0x01,                      //   REPORT_COUNT (1)
278   0x81, 0x00,                      //   INPUT (Data,Array,Abs)
279   0xc0,                            // END_COLLECTION
280   /* consumer */
281   0x05, 0x0c,                      // USAGE_PAGE (Consumer Devices)
282   0x09, 0x01,                      // USAGE (Consumer Control)
283   0xa1, 0x01,                      // COLLECTION (Application)
284   0x85, REPORT_ID_CONSUMER,        //   REPORT_ID (3)
285   0x15, 0x01,                      //   LOGICAL_MINIMUM (0x1)
286   0x26, 0x9c, 0x02,                //   LOGICAL_MAXIMUM (0x29c)
287   0x19, 0x01,                      //   USAGE_MINIMUM (0x1)
288   0x2a, 0x9c, 0x02,                //   USAGE_MAXIMUM (0x29c)
289   0x75, 0x10,                      //   REPORT_SIZE (16)
290   0x95, 0x01,                      //   REPORT_COUNT (1)
291   0x81, 0x00,                      //   INPUT (Data,Array,Abs)
292   0xc0,                            // END_COLLECTION
293 };
294 /* wrapper */
295 static const USBDescriptor extra_hid_report_descriptor = {
296   sizeof extra_hid_report_desc_data,
297   extra_hid_report_desc_data
298 };
299 #endif /* EXTRAKEY_ENABLE */
300
301
302 /*
303  * Configuration Descriptor tree for a HID device
304  *
305  * The HID Specifications version 1.11 require the following order:
306  * - Configuration Descriptor
307  * - Interface Descriptor
308  * - HID Descriptor
309  * - Endpoints Descriptors
310  */
311 #define KBD_HID_DESC_NUM                0
312 #define KBD_HID_DESC_OFFSET             (9 + (9 + 9 + 7) * KBD_HID_DESC_NUM + 9)
313
314 #ifdef MOUSE_ENABLE
315 #   define MOUSE_HID_DESC_NUM           (KBD_HID_DESC_NUM + 1)
316 #   define MOUSE_HID_DESC_OFFSET        (9 + (9 + 9 + 7) * MOUSE_HID_DESC_NUM + 9)
317 #else /* MOUSE_ENABLE */
318 #   define MOUSE_HID_DESC_NUM           (KBD_HID_DESC_NUM + 0)
319 #endif /* MOUSE_ENABLE */
320
321 #ifdef CONSOLE_ENABLE
322 #define CONSOLE_HID_DESC_NUM            (MOUSE_HID_DESC_NUM + 1)
323 #define CONSOLE_HID_DESC_OFFSET         (9 + (9 + 9 + 7) * CONSOLE_HID_DESC_NUM + 9)
324 #else /* CONSOLE_ENABLE */
325 #   define CONSOLE_HID_DESC_NUM         (MOUSE_HID_DESC_NUM + 0)
326 #endif /* CONSOLE_ENABLE */
327
328 #ifdef EXTRAKEY_ENABLE
329 #   define EXTRA_HID_DESC_NUM           (CONSOLE_HID_DESC_NUM + 1)
330 #   define EXTRA_HID_DESC_OFFSET        (9 + (9 + 9 + 7) * EXTRA_HID_DESC_NUM + 9)
331 #else /* EXTRAKEY_ENABLE */
332 #   define EXTRA_HID_DESC_NUM           (CONSOLE_HID_DESC_NUM + 0)
333 #endif /* EXTRAKEY_ENABLE */
334
335 #ifdef NKRO_ENABLE
336 #   define NKRO_HID_DESC_NUM            (EXTRA_HID_DESC_NUM + 1)
337 #   define NKRO_HID_DESC_OFFSET         (9 + (9 + 9 + 7) * EXTRA_HID_DESC_NUM + 9)
338 #else /* NKRO_ENABLE */
339 #   define NKRO_HID_DESC_NUM            (EXTRA_HID_DESC_NUM + 0)
340 #endif /* NKRO_ENABLE */
341
342 #define NUM_INTERFACES                  (NKRO_HID_DESC_NUM + 1)
343 #define CONFIG1_DESC_SIZE               (9 + (9 + 9 + 7) * NUM_INTERFACES)
344
345 static const uint8_t hid_configuration_descriptor_data[] = {
346   /* Configuration Descriptor (9 bytes) USB spec 9.6.3, page 264-266, Table 9-10 */
347   USB_DESC_CONFIGURATION(CONFIG1_DESC_SIZE, // wTotalLength
348                          NUM_INTERFACES,    // bNumInterfaces
349                          1,    // bConfigurationValue
350                          0,    // iConfiguration
351                          0xA0, // bmAttributes
352                          50),  // bMaxPower (100mA)
353
354   /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
355   USB_DESC_INTERFACE(KBD_INTERFACE,        // bInterfaceNumber
356                      0,        // bAlternateSetting
357                      1,        // bNumEndpoints
358                      0x03,     // bInterfaceClass: HID
359                      0x01,     // bInterfaceSubClass: Boot
360                      0x01,     // bInterfaceProtocol: Keyboard
361                      0),       // iInterface
362
363   /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
364   USB_DESC_BYTE(9),            // bLength
365   USB_DESC_BYTE(0x21),         // bDescriptorType (HID class)
366   USB_DESC_BCD(0x0111),        // bcdHID: HID version 1.11
367   USB_DESC_BYTE(0),            // bCountryCode
368   USB_DESC_BYTE(1),            // bNumDescriptors
369   USB_DESC_BYTE(0x22),         // bDescriptorType (report desc)
370   USB_DESC_WORD(sizeof(keyboard_hid_report_desc_data)), // wDescriptorLength
371
372   /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
373   USB_DESC_ENDPOINT(KBD_ENDPOINT | 0x80,  // bEndpointAddress
374                     0x03,      // bmAttributes (Interrupt)
375                     KBD_SIZE,  // wMaxPacketSize
376                     10),       // bInterval
377
378   #ifdef MOUSE_ENABLE
379   /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
380   USB_DESC_INTERFACE(MOUSE_INTERFACE,   // bInterfaceNumber
381                      0,        // bAlternateSetting
382                      1,        // bNumEndpoints
383                      0x03,     // bInterfaceClass (0x03 = HID)
384                      // ThinkPad T23 BIOS doesn't work with boot mouse.
385                      0x00,     // bInterfaceSubClass (0x01 = Boot)
386                      0x00,     // bInterfaceProtocol (0x02 = Mouse)
387                      /*
388                         0x01,      // bInterfaceSubClass (0x01 = Boot)
389                         0x02,      // bInterfaceProtocol (0x02 = Mouse)
390                       */
391                      0),        // iInterface
392
393   /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
394   USB_DESC_BYTE(9),            // bLength
395   USB_DESC_BYTE(0x21),         // bDescriptorType (HID class)
396   USB_DESC_BCD(0x0111),        // bcdHID: HID version 1.11
397   USB_DESC_BYTE(0),            // bCountryCode
398   USB_DESC_BYTE(1),            // bNumDescriptors
399   USB_DESC_BYTE(0x22),         // bDescriptorType (report desc)
400   USB_DESC_WORD(sizeof(mouse_hid_report_desc_data)), // wDescriptorLength
401
402   /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
403   USB_DESC_ENDPOINT(MOUSE_ENDPOINT | 0x80,  // bEndpointAddress
404                     0x03,      // bmAttributes (Interrupt)
405                     MOUSE_SIZE,  // wMaxPacketSize
406                     1),        // bInterval
407   #endif /* MOUSE_ENABLE */
408
409   #ifdef CONSOLE_ENABLE
410   /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
411   USB_DESC_INTERFACE(CONSOLE_INTERFACE, // bInterfaceNumber
412                      0,        // bAlternateSetting
413                      1,        // bNumEndpoints
414                      0x03,     // bInterfaceClass: HID
415                      0x00,     // bInterfaceSubClass: None
416                      0x00,     // bInterfaceProtocol: None
417                      0),       // iInterface
418
419   /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
420   USB_DESC_BYTE(9),            // bLength
421   USB_DESC_BYTE(0x21),         // bDescriptorType (HID class)
422   USB_DESC_BCD(0x0111),        // bcdHID: HID version 1.11
423   USB_DESC_BYTE(0),            // bCountryCode
424   USB_DESC_BYTE(1),            // bNumDescriptors
425   USB_DESC_BYTE(0x22),         // bDescriptorType (report desc)
426   USB_DESC_WORD(sizeof(console_hid_report_desc_data)), // wDescriptorLength
427
428   /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
429   USB_DESC_ENDPOINT(CONSOLE_ENDPOINT | 0x80,  // bEndpointAddress
430                     0x03,      // bmAttributes (Interrupt)
431                     CONSOLE_SIZE, // wMaxPacketSize
432                     1),        // bInterval
433   #endif /* CONSOLE_ENABLE */
434
435   #ifdef EXTRAKEY_ENABLE
436   /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
437   USB_DESC_INTERFACE(EXTRA_INTERFACE, // bInterfaceNumber
438                      0,        // bAlternateSetting
439                      1,        // bNumEndpoints
440                      0x03,     // bInterfaceClass: HID
441                      0x00,     // bInterfaceSubClass: None
442                      0x00,     // bInterfaceProtocol: None
443                      0),       // iInterface
444
445   /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
446   USB_DESC_BYTE(9),            // bLength
447   USB_DESC_BYTE(0x21),         // bDescriptorType (HID class)
448   USB_DESC_BCD(0x0111),        // bcdHID: HID version 1.11
449   USB_DESC_BYTE(0),            // bCountryCode
450   USB_DESC_BYTE(1),            // bNumDescriptors
451   USB_DESC_BYTE(0x22),         // bDescriptorType (report desc)
452   USB_DESC_WORD(sizeof(extra_hid_report_desc_data)), // wDescriptorLength
453
454   /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
455   USB_DESC_ENDPOINT(EXTRA_ENDPOINT | 0x80,  // bEndpointAddress
456                     0x03,      // bmAttributes (Interrupt)
457                     EXTRA_SIZE, // wMaxPacketSize
458                     10),       // bInterval
459   #endif /* EXTRAKEY_ENABLE */
460
461   #ifdef NKRO_ENABLE
462   /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
463   USB_DESC_INTERFACE(NKRO_INTERFACE, // bInterfaceNumber
464                      0,        // bAlternateSetting
465                      1,        // bNumEndpoints
466                      0x03,     // bInterfaceClass: HID
467                      0x00,     // bInterfaceSubClass: None
468                      0x00,     // bInterfaceProtocol: None
469                      0),       // iInterface
470
471   /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
472   USB_DESC_BYTE(9),            // bLength
473   USB_DESC_BYTE(0x21),         // bDescriptorType (HID class)
474   USB_DESC_BCD(0x0111),        // bcdHID: HID version 1.11
475   USB_DESC_BYTE(0),            // bCountryCode
476   USB_DESC_BYTE(1),            // bNumDescriptors
477   USB_DESC_BYTE(0x22),         // bDescriptorType (report desc)
478   USB_DESC_WORD(sizeof(nkro_hid_report_desc_data)), // wDescriptorLength
479
480   /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
481   USB_DESC_ENDPOINT(NKRO_ENDPOINT | 0x80,  // bEndpointAddress
482                     0x03,      // bmAttributes (Interrupt)
483                     NKRO_SIZE, // wMaxPacketSize
484                     1),       // bInterval
485   #endif /* NKRO_ENABLE */
486 };
487
488 /* Configuration Descriptor wrapper */
489 static const USBDescriptor hid_configuration_descriptor = {
490   sizeof hid_configuration_descriptor_data,
491   hid_configuration_descriptor_data
492 };
493
494 /* wrappers */
495 #define HID_DESCRIPTOR_SIZE 9
496 static const USBDescriptor keyboard_hid_descriptor = {
497   HID_DESCRIPTOR_SIZE,
498   &hid_configuration_descriptor_data[KBD_HID_DESC_OFFSET]
499 };
500 #ifdef MOUSE_ENABLE
501 static const USBDescriptor mouse_hid_descriptor = {
502   HID_DESCRIPTOR_SIZE,
503   &hid_configuration_descriptor_data[MOUSE_HID_DESC_OFFSET]
504 };
505 #endif /* MOUSE_ENABLE */
506 #ifdef CONSOLE_ENABLE
507 static const USBDescriptor console_hid_descriptor = {
508   HID_DESCRIPTOR_SIZE,
509   &hid_configuration_descriptor_data[CONSOLE_HID_DESC_OFFSET]
510 };
511 #endif /* CONSOLE_ENABLE */
512 #ifdef EXTRAKEY_ENABLE
513 static const USBDescriptor extra_hid_descriptor = {
514   HID_DESCRIPTOR_SIZE,
515   &hid_configuration_descriptor_data[EXTRA_HID_DESC_OFFSET]
516 };
517 #endif /* EXTRAKEY_ENABLE */
518 #ifdef NKRO_ENABLE
519 static const USBDescriptor nkro_hid_descriptor = {
520   HID_DESCRIPTOR_SIZE,
521   &hid_configuration_descriptor_data[NKRO_HID_DESC_OFFSET]
522 };
523 #endif /* NKRO_ENABLE */
524
525
526 /* U.S. English language identifier */
527 static const uint8_t usb_string_langid[] = {
528   USB_DESC_BYTE(4),                        // bLength
529   USB_DESC_BYTE(USB_DESCRIPTOR_STRING),    // bDescriptorType
530   USB_DESC_WORD(0x0409)                    // wLANGID (U.S. English)
531 };
532
533 /* ugly ugly hack */
534 #define PP_NARG(...) \
535          PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
536 #define PP_NARG_(...) \
537          PP_ARG_N(__VA_ARGS__)
538 #define PP_ARG_N( \
539           _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
540          _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
541          _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
542          _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
543          _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
544          _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
545          _61,_62,_63,N,...) N
546 #define PP_RSEQ_N() \
547          63,62,61,60,                   \
548          59,58,57,56,55,54,53,52,51,50, \
549          49,48,47,46,45,44,43,42,41,40, \
550          39,38,37,36,35,34,33,32,31,30, \
551          29,28,27,26,25,24,23,22,21,20, \
552          19,18,17,16,15,14,13,12,11,10, \
553          9,8,7,6,5,4,3,2,1,0
554
555 /* Vendor string = manufacturer */
556 static const uint8_t usb_string_vendor[] = {
557   USB_DESC_BYTE(PP_NARG(USBSTR_MANUFACTURER)+2),                       // bLength
558   USB_DESC_BYTE(USB_DESCRIPTOR_STRING),    // bDescriptorType
559   USBSTR_MANUFACTURER
560 };
561
562 /* Device Description string = product */
563 static const uint8_t usb_string_description[] = {
564   USB_DESC_BYTE(PP_NARG(USBSTR_PRODUCT)+2),           // bLength
565   USB_DESC_BYTE(USB_DESCRIPTOR_STRING),    // bDescriptorType
566   USBSTR_PRODUCT
567 };
568
569 /* Serial Number string (will be filled by the function init_usb_serial_string) */
570 static uint8_t usb_string_serial[] = {
571   USB_DESC_BYTE(22),                       // bLength
572   USB_DESC_BYTE(USB_DESCRIPTOR_STRING),    // bDescriptorType
573   '0', 0, 'x', 0, 'D', 0, 'E', 0, 'A', 0, 'D', 0, 'B', 0, 'E', 0, 'E', 0, 'F', 0
574 };
575
576 /* Strings wrappers array */
577 static const USBDescriptor usb_strings[] = {
578   { sizeof usb_string_langid, usb_string_langid }
579   ,
580   { sizeof usb_string_vendor, usb_string_vendor }
581   ,
582   { sizeof usb_string_description, usb_string_description }
583   ,
584   { sizeof usb_string_serial, usb_string_serial }
585 };
586
587 /*
588  * Handles the GET_DESCRIPTOR callback
589  *
590  * Returns the proper descriptor
591  */
592 static const USBDescriptor *usb_get_descriptor_cb(USBDriver *usbp, uint8_t dtype, uint8_t dindex, uint16_t lang) {
593   (void)usbp;
594   (void)lang;
595   switch(dtype) {
596   /* Generic descriptors */
597   case USB_DESCRIPTOR_DEVICE:   /* Device Descriptor */
598     return &usb_device_descriptor;
599
600   case USB_DESCRIPTOR_CONFIGURATION:    /* Configuration Descriptor */
601     return &hid_configuration_descriptor;
602
603   case USB_DESCRIPTOR_STRING:   /* Strings */
604     if(dindex < 4)
605       return &usb_strings[dindex];
606     break;
607
608   /* HID specific descriptors */
609   case USB_DESCRIPTOR_HID:      /* HID Descriptors */
610     switch(lang) {    /* yea, poor label, it's actually wIndex from the setup packet */
611     case KBD_INTERFACE:
612       return &keyboard_hid_descriptor;
613
614 #ifdef MOUSE_ENABLE
615     case MOUSE_INTERFACE:
616       return &mouse_hid_descriptor;
617 #endif /* MOUSE_ENABLE */
618 #ifdef CONSOLE_ENABLE
619     case CONSOLE_INTERFACE:
620       return &console_hid_descriptor;
621 #endif /* CONSOLE_ENABLE */
622 #ifdef EXTRAKEY_ENABLE
623     case EXTRA_INTERFACE:
624       return &extra_hid_descriptor;
625 #endif /* EXTRAKEY_ENABLE */
626 #ifdef NKRO_ENABLE
627     case NKRO_INTERFACE:
628       return &nkro_hid_descriptor;
629 #endif /* NKRO_ENABLE */
630     }
631
632   case USB_DESCRIPTOR_HID_REPORT:       /* HID Report Descriptor */
633     switch(lang) {
634     case KBD_INTERFACE:
635       return &keyboard_hid_report_descriptor;
636
637 #ifdef MOUSE_ENABLE
638     case MOUSE_INTERFACE:
639       return &mouse_hid_report_descriptor;
640 #endif /* MOUSE_ENABLE */
641 #ifdef CONSOLE_ENABLE
642     case CONSOLE_INTERFACE:
643       return &console_hid_report_descriptor;
644 #endif /* CONSOLE_ENABLE */
645 #ifdef EXTRAKEY_ENABLE
646     case EXTRA_INTERFACE:
647       return &extra_hid_report_descriptor;
648 #endif /* EXTRAKEY_ENABLE */
649 #ifdef NKRO_ENABLE
650     case NKRO_INTERFACE:
651       return &nkro_hid_report_descriptor;
652 #endif /* NKRO_ENABLE */
653     }
654   }
655   return NULL;
656 }
657
658 /* keyboard endpoint state structure */
659 static USBInEndpointState kbd_ep_state;
660 /* keyboard endpoint initialization structure (IN) */
661 static const USBEndpointConfig kbd_ep_config = {
662   USB_EP_MODE_TYPE_INTR,        /* Interrupt EP */
663   NULL,                         /* SETUP packet notification callback */
664   kbd_in_cb,                    /* IN notification callback */
665   NULL,                         /* OUT notification callback */
666   KBD_SIZE,                     /* IN maximum packet size */
667   0,                            /* OUT maximum packet size */
668   &kbd_ep_state,                /* IN Endpoint state */
669   NULL,                         /* OUT endpoint state */
670   2,                            /* IN multiplier */
671   NULL                          /* SETUP buffer (not a SETUP endpoint) */
672 };
673
674 #ifdef MOUSE_ENABLE
675 /* mouse endpoint state structure */
676 static USBInEndpointState mouse_ep_state;
677
678 /* mouse endpoint initialization structure (IN) */
679 static const USBEndpointConfig mouse_ep_config = {
680   USB_EP_MODE_TYPE_INTR,        /* Interrupt EP */
681   NULL,                         /* SETUP packet notification callback */
682   mouse_in_cb,                  /* IN notification callback */
683   NULL,                         /* OUT notification callback */
684   MOUSE_SIZE,                   /* IN maximum packet size */
685   0,                            /* OUT maximum packet size */
686   &mouse_ep_state,              /* IN Endpoint state */
687   NULL,                         /* OUT endpoint state */
688   2,                            /* IN multiplier */
689   NULL                          /* SETUP buffer (not a SETUP endpoint) */
690 };
691 #endif /* MOUSE_ENABLE */
692
693 #ifdef CONSOLE_ENABLE
694 /* console endpoint state structure */
695 static USBInEndpointState console_ep_state;
696
697 /* console endpoint initialization structure (IN) */
698 static const USBEndpointConfig console_ep_config = {
699   USB_EP_MODE_TYPE_INTR,        /* Interrupt EP */
700   NULL,                         /* SETUP packet notification callback */
701   console_in_cb,                /* IN notification callback */
702   NULL,                         /* OUT notification callback */
703   CONSOLE_SIZE,                 /* IN maximum packet size */
704   0,                            /* OUT maximum packet size */
705   &console_ep_state,            /* IN Endpoint state */
706   NULL,                         /* OUT endpoint state */
707   2,                            /* IN multiplier */
708   NULL                          /* SETUP buffer (not a SETUP endpoint) */
709 };
710 #endif /* CONSOLE_ENABLE */
711
712 #ifdef EXTRAKEY_ENABLE
713 /* extrakey endpoint state structure */
714 static USBInEndpointState extra_ep_state;
715
716 /* extrakey endpoint initialization structure (IN) */
717 static const USBEndpointConfig extra_ep_config = {
718   USB_EP_MODE_TYPE_INTR,        /* Interrupt EP */
719   NULL,                         /* SETUP packet notification callback */
720   extra_in_cb,                  /* IN notification callback */
721   NULL,                         /* OUT notification callback */
722   EXTRA_SIZE,                   /* IN maximum packet size */
723   0,                            /* OUT maximum packet size */
724   &extra_ep_state,              /* IN Endpoint state */
725   NULL,                         /* OUT endpoint state */
726   2,                            /* IN multiplier */
727   NULL                          /* SETUP buffer (not a SETUP endpoint) */
728 };
729 #endif /* EXTRAKEY_ENABLE */
730
731 #ifdef NKRO_ENABLE
732 /* nkro endpoint state structure */
733 static USBInEndpointState nkro_ep_state;
734
735 /* nkro endpoint initialization structure (IN) */
736 static const USBEndpointConfig nkro_ep_config = {
737   USB_EP_MODE_TYPE_INTR,        /* Interrupt EP */
738   NULL,                         /* SETUP packet notification callback */
739   nkro_in_cb,                   /* IN notification callback */
740   NULL,                         /* OUT notification callback */
741   NKRO_SIZE,                    /* IN maximum packet size */
742   0,                            /* OUT maximum packet size */
743   &nkro_ep_state,               /* IN Endpoint state */
744   NULL,                         /* OUT endpoint state */
745   2,                            /* IN multiplier */
746   NULL                          /* SETUP buffer (not a SETUP endpoint) */
747 };
748 #endif /* NKRO_ENABLE */
749
750 /* ---------------------------------------------------------
751  *                  USB driver functions
752  * ---------------------------------------------------------
753  */
754
755 /* Handles the USB driver global events
756  * TODO: maybe disable some things when connection is lost? */
757 static void usb_event_cb(USBDriver *usbp, usbevent_t event) {
758   switch(event) {
759   case USB_EVENT_RESET:
760     //TODO: from ISR! print("[R]");
761     return;
762
763   case USB_EVENT_ADDRESS:
764     return;
765
766   case USB_EVENT_CONFIGURED:
767     osalSysLockFromISR();
768     /* Enable the endpoints specified into the configuration. */
769     usbInitEndpointI(usbp, KBD_ENDPOINT, &kbd_ep_config);
770 #ifdef MOUSE_ENABLE
771     usbInitEndpointI(usbp, MOUSE_ENDPOINT, &mouse_ep_config);
772 #endif /* MOUSE_ENABLE */
773 #ifdef CONSOLE_ENABLE
774     usbInitEndpointI(usbp, CONSOLE_ENDPOINT, &console_ep_config);
775     /* don't need to start the flush timer, it starts from console_in_cb automatically */
776 #endif /* CONSOLE_ENABLE */
777 #ifdef EXTRAKEY_ENABLE
778     usbInitEndpointI(usbp, EXTRA_ENDPOINT, &extra_ep_config);
779 #endif /* EXTRAKEY_ENABLE */
780 #ifdef NKRO_ENABLE
781     usbInitEndpointI(usbp, NKRO_ENDPOINT, &nkro_ep_config);
782 #endif /* NKRO_ENABLE */
783     osalSysUnlockFromISR();
784     return;
785
786   case USB_EVENT_SUSPEND:
787     //TODO: from ISR! print("[S]");
788     //TODO: signal suspend?
789 #ifdef SLEEP_LED_ENABLE
790     sleep_led_enable();
791 #endif /* SLEEP_LED_ENABLE */
792     return;
793
794   case USB_EVENT_WAKEUP:
795     //TODO: from ISR! print("[W]");
796     //TODO: suspend_wakeup_init();
797 #ifdef SLEEP_LED_ENABLE
798     sleep_led_disable();
799     // NOTE: converters may not accept this
800     led_set(host_keyboard_leds());
801 #endif /* SLEEP_LED_ENABLE */
802     return;
803
804   case USB_EVENT_STALLED:
805     return;
806   }
807 }
808
809 /* Function used locally in os/hal/src/usb.c for getting descriptors
810  * need it here for HID descriptor */
811 static uint16_t get_hword(uint8_t *p) {
812   uint16_t hw;
813
814   hw = (uint16_t)*p++;
815   hw |= (uint16_t)*p << 8U;
816   return hw;
817 }
818
819 /*
820  * Appendix G: HID Request Support Requirements
821  *
822  * The following table enumerates the requests that need to be supported by various types of HID class devices.
823  * Device type     GetReport   SetReport   GetIdle     SetIdle     GetProtocol SetProtocol
824  * ------------------------------------------------------------------------------------------
825  * Boot Mouse      Required    Optional    Optional    Optional    Required    Required
826  * Non-Boot Mouse  Required    Optional    Optional    Optional    Optional    Optional
827  * Boot Keyboard   Required    Optional    Required    Required    Required    Required
828  * Non-Boot Keybrd Required    Optional    Required    Required    Optional    Optional
829  * Other Device    Required    Optional    Optional    Optional    Optional    Optional
830  */
831
832 /* Callback for SETUP request on the endpoint 0 (control) */
833 static bool usb_request_hook_cb(USBDriver *usbp) {
834   const USBDescriptor *dp;
835
836   /* usbp->setup fields:
837    *  0:   bmRequestType (bitmask)
838    *  1:   bRequest
839    *  2,3: (LSB,MSB) wValue
840    *  4,5: (LSB,MSB) wIndex
841    *  6,7: (LSB,MSB) wLength (number of bytes to transfer if there is a data phase) */
842
843   /* Handle HID class specific requests */
844   if(((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) &&
845      ((usbp->setup[0] & USB_RTYPE_RECIPIENT_MASK) == USB_RTYPE_RECIPIENT_INTERFACE)) {
846     switch(usbp->setup[0] & USB_RTYPE_DIR_MASK) {
847     case USB_RTYPE_DIR_DEV2HOST:
848       switch(usbp->setup[1]) {   /* bRequest */
849       case HID_GET_REPORT:
850         switch(usbp->setup[4]) {     /* LSB(wIndex) (check MSB==0?) */
851         case KBD_INTERFACE:
852 #ifdef NKRO_ENABLE
853         case NKRO_INTERFACE:
854 #endif /* NKRO_ENABLE */
855           usbSetupTransfer(usbp, (uint8_t *)&keyboard_report_sent, sizeof(keyboard_report_sent), NULL);
856           return TRUE;
857           break;
858
859         default:
860           usbSetupTransfer(usbp, NULL, 0, NULL);
861           return TRUE;
862           break;
863         }
864         break;
865
866       case HID_GET_PROTOCOL:
867         if((usbp->setup[4] == KBD_INTERFACE) && (usbp->setup[5] == 0)) {   /* wIndex */
868           usbSetupTransfer(usbp, &keyboard_protocol, 1, NULL);
869           return TRUE;
870         }
871         break;
872
873       case HID_GET_IDLE:
874         usbSetupTransfer(usbp, &keyboard_idle, 1, NULL);
875         return TRUE;
876         break;
877       }
878       break;
879
880     case USB_RTYPE_DIR_HOST2DEV:
881       switch(usbp->setup[1]) {   /* bRequest */
882       case HID_SET_REPORT:
883         switch(usbp->setup[4]) {       /* LSB(wIndex) (check MSB==0 and wLength==1?) */
884         case KBD_INTERFACE:
885 #ifdef NKRO_ENABLE
886         case NKRO_INTERFACE:
887 #endif  /* NKRO_ENABLE */
888         /* keyboard_led_stats = <read byte from next OUT report>
889          * keyboard_led_stats needs be word (or dword), otherwise we get an exception on F0 */
890           usbSetupTransfer(usbp, (uint8_t *)&keyboard_led_stats, 1, NULL);
891           return TRUE;
892           break;
893         }
894         break;
895
896       case HID_SET_PROTOCOL:
897         if((usbp->setup[4] == KBD_INTERFACE) && (usbp->setup[5] == 0)) {   /* wIndex */
898           keyboard_protocol = ((usbp->setup[2]) != 0x00);   /* LSB(wValue) */
899 #ifdef NKRO_ENABLE
900           keyboard_nkro = !!keyboard_protocol;
901           if(!keyboard_nkro && keyboard_idle) {
902 #else /* NKRO_ENABLE */
903           if(keyboard_idle) {
904 #endif /* NKRO_ENABLE */
905           /* arm the idle timer if boot protocol & idle */
906             osalSysLockFromISR();
907             chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp);
908             osalSysUnlockFromISR();
909           }
910         }
911         usbSetupTransfer(usbp, NULL, 0, NULL);
912         return TRUE;
913         break;
914
915       case HID_SET_IDLE:
916         keyboard_idle = usbp->setup[3];     /* MSB(wValue) */
917         /* arm the timer */
918 #ifdef NKRO_ENABLE
919         if(!keyboard_nkro && keyboard_idle) {
920 #else /* NKRO_ENABLE */
921         if(keyboard_idle) {
922 #endif /* NKRO_ENABLE */
923           osalSysLockFromISR();
924           chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp);
925           osalSysUnlockFromISR();
926         }
927         usbSetupTransfer(usbp, NULL, 0, NULL);
928         return TRUE;
929         break;
930       }
931       break;
932     }
933   }
934
935   /* Handle the Get_Descriptor Request for HID class (not handled by the default hook) */
936   if((usbp->setup[0] == 0x81) && (usbp->setup[1] == USB_REQ_GET_DESCRIPTOR)) {
937     dp = usbp->config->get_descriptor_cb(usbp, usbp->setup[3], usbp->setup[2], get_hword(&usbp->setup[4]));
938     if(dp == NULL)
939       return FALSE;
940     usbSetupTransfer(usbp, (uint8_t *)dp->ud_string, dp->ud_size, NULL);
941     return TRUE;
942   }
943
944   return FALSE;
945 }
946
947 /* Start-of-frame callback */
948 static void usb_sof_cb(USBDriver *usbp) {
949   kbd_sof_cb(usbp);
950 }
951
952
953 /* USB driver configuration */
954 static const USBConfig usbcfg = {
955   usb_event_cb,                 /* USB events callback */
956   usb_get_descriptor_cb,        /* Device GET_DESCRIPTOR request callback */
957   usb_request_hook_cb,          /* Requests hook callback */
958   usb_sof_cb                    /* Start Of Frame callback */
959 };
960
961 /*
962  * Initialize the USB driver
963  */
964 void init_usb_driver(USBDriver *usbp) {
965   /*
966    * Activates the USB driver and then the USB bus pull-up on D+.
967    * Note, a delay is inserted in order to not have to disconnect the cable
968    * after a reset.
969    */
970   usbDisconnectBus(usbp);
971   chThdSleepMilliseconds(1500);
972   usbStart(usbp, &usbcfg);
973   usbConnectBus(usbp);
974
975   chVTObjectInit(&keyboard_idle_timer);
976 #ifdef CONSOLE_ENABLE
977   oqObjectInit(&console_queue, console_queue_buffer, sizeof(console_queue_buffer), console_queue_onotify, (void *)usbp);
978   chVTObjectInit(&console_flush_timer);
979 #endif
980 }
981
982 /* ---------------------------------------------------------
983  *                  Keyboard functions
984  * ---------------------------------------------------------
985  */
986
987 /* keyboard IN callback hander (a kbd report has made it IN) */
988 void kbd_in_cb(USBDriver *usbp, usbep_t ep) {
989   /* STUB */
990   (void)usbp;
991   (void)ep;
992 }
993
994 #ifdef NKRO_ENABLE
995 /* nkro IN callback hander (a nkro report has made it IN) */
996 void nkro_in_cb(USBDriver *usbp, usbep_t ep) {
997   /* STUB */
998   (void)usbp;
999   (void)ep;
1000 }
1001 #endif /* NKRO_ENABLE */
1002
1003 /* start-of-frame handler
1004  * TODO: i guess it would be better to re-implement using timers,
1005  *  so that this is not going to have to be checked every 1ms */
1006 void kbd_sof_cb(USBDriver *usbp) {
1007   (void)usbp;
1008 }
1009
1010 /* Idle requests timer code
1011  * callback (called from ISR, unlocked state) */
1012 static void keyboard_idle_timer_cb(void *arg) {
1013   USBDriver *usbp = (USBDriver *)arg;
1014
1015   osalSysLockFromISR();
1016
1017   /* check that the states of things are as they're supposed to */
1018   if(usbGetDriverStateI(usbp) != USB_ACTIVE) {
1019     /* do not rearm the timer, should be enabled on IDLE request */
1020     osalSysUnlockFromISR();
1021     return;
1022   }
1023
1024 #ifdef NKRO_ENABLE
1025   if(!keyboard_nkro && keyboard_idle) {
1026 #else /* NKRO_ENABLE */
1027   if(keyboard_idle) {
1028 #endif /* NKRO_ENABLE */
1029     /* TODO: are we sure we want the KBD_ENDPOINT? */
1030     osalSysUnlockFromISR();
1031     usbPrepareTransmit(usbp, KBD_ENDPOINT, (uint8_t *)&keyboard_report_sent, sizeof(keyboard_report_sent));
1032     osalSysLockFromISR();
1033     usbStartTransmitI(usbp, KBD_ENDPOINT);
1034     /* rearm the timer */
1035     chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp);
1036   }
1037
1038   /* do not rearm the timer if the condition above fails
1039    * it should be enabled again on either IDLE or SET_PROTOCOL requests */
1040   osalSysUnlockFromISR();
1041 }
1042
1043 /* LED status */
1044 uint8_t keyboard_leds(void) {
1045   return (uint8_t)(keyboard_led_stats & 0xFF);
1046 }
1047
1048 /* prepare and start sending a report IN
1049  * not callable from ISR or locked state */
1050 void send_keyboard(report_keyboard_t *report) {
1051   osalSysLock();
1052   if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
1053     osalSysUnlock();
1054     return;
1055   }
1056   osalSysUnlock();
1057
1058 #ifdef NKRO_ENABLE
1059   if(keyboard_nkro) {  /* NKRO protocol */
1060     usbPrepareTransmit(&USB_DRIVER, NKRO_ENDPOINT, (uint8_t *)report, sizeof(report_keyboard_t));
1061     osalSysLock();
1062     usbStartTransmitI(&USB_DRIVER, NKRO_ENDPOINT);
1063     osalSysUnlock();
1064   } else
1065 #endif /* NKRO_ENABLE */
1066   { /* boot protocol */
1067     usbPrepareTransmit(&USB_DRIVER, KBD_ENDPOINT, (uint8_t *)report, sizeof(report_keyboard_t));
1068     osalSysLock();
1069     usbStartTransmitI(&USB_DRIVER, KBD_ENDPOINT);
1070     osalSysUnlock();
1071   }
1072   keyboard_report_sent = *report;
1073 }
1074
1075 /* ---------------------------------------------------------
1076  *                     Mouse functions
1077  * ---------------------------------------------------------
1078  */
1079
1080 #ifdef MOUSE_ENABLE
1081
1082 /* mouse IN callback hander (a mouse report has made it IN) */
1083 void mouse_in_cb(USBDriver *usbp, usbep_t ep) {
1084   (void)usbp;
1085   (void)ep;
1086 }
1087
1088 void send_mouse(report_mouse_t *report) {
1089   osalSysLock();
1090   if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
1091     osalSysUnlock();
1092     return;
1093   }
1094   osalSysUnlock();
1095
1096   /* TODO: LUFA manually waits for the endpoint to become ready
1097    * for about 10ms for mouse, kbd, system; 1ms for nkro
1098    * is this really needed?
1099    */
1100
1101   usbPrepareTransmit(&USB_DRIVER, MOUSE_ENDPOINT, (uint8_t *)report, sizeof(report_mouse_t));
1102   osalSysLock();
1103   usbStartTransmitI(&USB_DRIVER, MOUSE_ENDPOINT);
1104   osalSysUnlock();
1105 }
1106
1107 #else /* MOUSE_ENABLE */
1108 void send_mouse(report_mouse_t *report) {
1109   (void)report;
1110 }
1111 #endif /* MOUSE_ENABLE */
1112
1113 /* ---------------------------------------------------------
1114  *                   Extrakey functions
1115  * ---------------------------------------------------------
1116  */
1117
1118 #ifdef EXTRAKEY_ENABLE
1119
1120 /* extrakey IN callback hander */
1121 void extra_in_cb(USBDriver *usbp, usbep_t ep) {
1122   /* STUB */
1123   (void)usbp;
1124   (void)ep;
1125 }
1126
1127 static void send_extra_report(uint8_t report_id, uint16_t data) {
1128   osalSysLock();
1129   if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
1130     osalSysUnlock();
1131     return;
1132   }
1133
1134   report_extra_t report = {
1135     .report_id = report_id,
1136     .usage = data
1137   };
1138
1139   osalSysUnlock();
1140   usbPrepareTransmit(&USB_DRIVER, EXTRA_ENDPOINT, (uint8_t *)&report, sizeof(report_extra_t));
1141   osalSysLock();
1142   usbStartTransmitI(&USB_DRIVER, EXTRA_ENDPOINT);
1143   osalSysUnlock();
1144 }
1145
1146 void send_system(uint16_t data) {
1147   send_extra_report(REPORT_ID_SYSTEM, data);
1148 }
1149
1150 void send_consumer(uint16_t data) {
1151   send_extra_report(REPORT_ID_CONSUMER, data);
1152 }
1153
1154 #else /* EXTRAKEY_ENABLE */
1155 void send_system(uint16_t data) {
1156   (void)data;
1157 }
1158 void send_consumer(uint16_t data) {
1159   (void)data;
1160 }
1161 #endif /* EXTRAKEY_ENABLE */
1162
1163 /* ---------------------------------------------------------
1164  *                   Console functions
1165  * ---------------------------------------------------------
1166  */
1167
1168 #ifdef CONSOLE_ENABLE
1169
1170 /* debug IN callback hander */
1171 void console_in_cb(USBDriver *usbp, usbep_t ep) {
1172   (void)ep;
1173   osalSysLockFromISR();
1174
1175   /* rearm the timer */
1176   chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, (void *)usbp);
1177
1178   /* Check if there is data to send left in the output queue */
1179   if(chOQGetFullI(&console_queue) >= CONSOLE_SIZE) {
1180     osalSysUnlockFromISR();
1181     usbPrepareQueuedTransmit(usbp, CONSOLE_ENDPOINT, &console_queue, CONSOLE_SIZE);
1182     osalSysLockFromISR();
1183     usbStartTransmitI(usbp, CONSOLE_ENDPOINT);
1184   }
1185
1186   osalSysUnlockFromISR();
1187 }
1188
1189 /* Callback when data is inserted into the output queue
1190  * Called from a locked state */
1191 void console_queue_onotify(io_queue_t *qp) {
1192   USBDriver *usbp = qGetLink(qp);
1193
1194   if(usbGetDriverStateI(usbp) != USB_ACTIVE)
1195     return;
1196
1197   if(!usbGetTransmitStatusI(usbp, CONSOLE_ENDPOINT)
1198      && (chOQGetFullI(&console_queue) >= CONSOLE_SIZE)) {
1199     osalSysUnlock();
1200     usbPrepareQueuedTransmit(usbp, CONSOLE_ENDPOINT, &console_queue, CONSOLE_SIZE);
1201     osalSysLock();
1202     usbStartTransmitI(usbp, CONSOLE_ENDPOINT);
1203   }
1204 }
1205
1206 /* Flush timer code
1207  * callback (called from ISR, unlocked state) */
1208 static void console_flush_cb(void *arg) {
1209   USBDriver *usbp = (USBDriver *)arg;
1210   size_t i, n;
1211   uint8_t buf[CONSOLE_SIZE]; /* TODO: a solution without extra buffer? */
1212   osalSysLockFromISR();
1213
1214   /* check that the states of things are as they're supposed to */
1215   if(usbGetDriverStateI(usbp) != USB_ACTIVE) {
1216     /* rearm the timer */
1217     chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, (void *)usbp);
1218     osalSysUnlockFromISR();
1219     return;
1220   }
1221
1222   /* don't do anything if the queue is empty or has enough stuff in it */
1223   if(((n = oqGetFullI(&console_queue)) == 0) || (n >= CONSOLE_SIZE)) {
1224     /* rearm the timer */
1225     chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, (void *)usbp);
1226     osalSysUnlockFromISR();
1227     return;
1228   }
1229
1230   /* there's stuff hanging in the queue - so dequeue and send */
1231   for(i = 0; i < n; i++)
1232     buf[i] = (uint8_t)oqGetI(&console_queue);
1233   for(i = n; i < CONSOLE_SIZE; i++)
1234     buf[i] = 0;
1235   osalSysUnlockFromISR();
1236   usbPrepareTransmit(usbp, CONSOLE_ENDPOINT, buf, CONSOLE_SIZE);
1237   osalSysLockFromISR();
1238   (void)usbStartTransmitI(usbp, CONSOLE_ENDPOINT);
1239
1240   /* rearm the timer */
1241   chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, (void *)usbp);
1242   osalSysUnlockFromISR();
1243 }
1244
1245
1246 int8_t sendchar(uint8_t c) {
1247   osalSysLock();
1248   if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
1249     osalSysUnlock();
1250     return 0;
1251   }
1252   osalSysUnlock();
1253   /* should get suspended and wait if the queue is full
1254    * but it's not blocking even if noone is listening,
1255    *  because the USB packets are sent anyway */
1256   return(chOQPut(&console_queue, c));
1257 }
1258
1259 #else /* CONSOLE_ENABLE */
1260 int8_t sendchar(uint8_t c) {
1261   (void)c;
1262   return 0;
1263 }
1264 #endif /* CONSOLE_ENABLE */
1265
1266 void sendchar_pf(void *p, char c) {
1267   (void)p;
1268   sendchar((uint8_t)c);
1269 }