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