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