]> git.donarmstrong.com Git - qmk_firmware.git/blob - tmk_core/protocol/chibios/usb_main.c
[Keyboard] Add QMK configurator JSON for Alice PCB (#6397)
[qmk_firmware.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 #include "suspend.h"
26 #ifdef SLEEP_LED_ENABLE
27 #include "sleep_led.h"
28 #include "led.h"
29 #endif
30 #include "wait.h"
31 #include "usb_descriptor.h"
32 #include "usb_driver.h"
33
34 #ifdef NKRO_ENABLE
35   #include "keycode_config.h"
36
37   extern keymap_config_t keymap_config;
38 #endif
39
40 /* ---------------------------------------------------------
41  *       Global interface variables and declarations
42  * ---------------------------------------------------------
43  */
44
45 #ifndef usb_lld_connect_bus
46   #define usb_lld_connect_bus(usbp)
47 #endif
48
49 #ifndef usb_lld_disconnect_bus
50   #define usb_lld_disconnect_bus(usbp)
51 #endif
52
53 uint8_t keyboard_idle __attribute__((aligned(2))) = 0;
54 uint8_t keyboard_protocol __attribute__((aligned(2))) = 1;
55 uint16_t keyboard_led_stats __attribute__((aligned(2))) = 0;
56 volatile uint16_t keyboard_idle_count = 0;
57 static virtual_timer_t keyboard_idle_timer;
58 static void keyboard_idle_timer_cb(void *arg);
59
60 report_keyboard_t keyboard_report_sent = {{0}};
61 #ifdef MOUSE_ENABLE
62 report_mouse_t mouse_report_blank = {0};
63 #endif /* MOUSE_ENABLE */
64 #ifdef EXTRAKEY_ENABLE
65 uint8_t extra_report_blank[3] = {0};
66 #endif /* EXTRAKEY_ENABLE */
67
68 /* ---------------------------------------------------------
69  *            Descriptors and USB driver objects
70  * ---------------------------------------------------------
71  */
72
73 /* HID specific constants */
74 #define HID_GET_REPORT 0x01
75 #define HID_GET_IDLE 0x02
76 #define HID_GET_PROTOCOL 0x03
77 #define HID_SET_REPORT 0x09
78 #define HID_SET_IDLE 0x0A
79 #define HID_SET_PROTOCOL 0x0B
80
81 /*
82  * Handles the GET_DESCRIPTOR callback
83  *
84  * Returns the proper descriptor
85  */
86 static const USBDescriptor *usb_get_descriptor_cb(USBDriver *usbp, uint8_t dtype, uint8_t dindex, uint16_t wIndex) {
87   (void)usbp;
88   static USBDescriptor desc;
89   uint16_t wValue = ((uint16_t)dtype << 8) | dindex;
90   desc.ud_string = NULL;
91   desc.ud_size = get_usb_descriptor(wValue, wIndex, (const void** const)&desc.ud_string);
92   if (desc.ud_string == NULL)
93     return NULL;
94   else
95     return &desc;
96 }
97
98 #ifndef KEYBOARD_SHARED_EP
99 /* keyboard endpoint state structure */
100 static USBInEndpointState kbd_ep_state;
101 /* keyboard endpoint initialization structure (IN) */
102 static const USBEndpointConfig kbd_ep_config = {
103   USB_EP_MODE_TYPE_INTR,        /* Interrupt EP */
104   NULL,                         /* SETUP packet notification callback */
105   kbd_in_cb,                    /* IN notification callback */
106   NULL,                         /* OUT notification callback */
107   KEYBOARD_EPSIZE,              /* IN maximum packet size */
108   0,                            /* OUT maximum packet size */
109   &kbd_ep_state,                /* IN Endpoint state */
110   NULL,                         /* OUT endpoint state */
111   2,                            /* IN multiplier */
112   NULL                          /* SETUP buffer (not a SETUP endpoint) */
113 };
114 #endif
115
116 #if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
117 /* mouse endpoint state structure */
118 static USBInEndpointState mouse_ep_state;
119
120 /* mouse endpoint initialization structure (IN) */
121 static const USBEndpointConfig mouse_ep_config = {
122   USB_EP_MODE_TYPE_INTR,        /* Interrupt EP */
123   NULL,                         /* SETUP packet notification callback */
124   mouse_in_cb,                  /* IN notification callback */
125   NULL,                         /* OUT notification callback */
126   MOUSE_EPSIZE,                 /* IN maximum packet size */
127   0,                            /* OUT maximum packet size */
128   &mouse_ep_state,              /* IN Endpoint state */
129   NULL,                         /* OUT endpoint state */
130   2,                            /* IN multiplier */
131   NULL                          /* SETUP buffer (not a SETUP endpoint) */
132 };
133 #endif
134
135 #ifdef SHARED_EP_ENABLE
136 /* shared endpoint state structure */
137 static USBInEndpointState shared_ep_state;
138
139 /* shared endpoint initialization structure (IN) */
140 static const USBEndpointConfig shared_ep_config = {
141   USB_EP_MODE_TYPE_INTR,        /* Interrupt EP */
142   NULL,                         /* SETUP packet notification callback */
143   shared_in_cb,                 /* IN notification callback */
144   NULL,                         /* OUT notification callback */
145   SHARED_EPSIZE,                /* IN maximum packet size */
146   0,                            /* OUT maximum packet size */
147   &shared_ep_state,             /* IN Endpoint state */
148   NULL,                         /* OUT endpoint state */
149   2,                            /* IN multiplier */
150   NULL                          /* SETUP buffer (not a SETUP endpoint) */
151 };
152 #endif
153
154 typedef struct {
155   size_t queue_capacity_in;
156   size_t queue_capacity_out;
157   USBInEndpointState in_ep_state;
158   USBOutEndpointState out_ep_state;
159   USBInEndpointState int_ep_state;
160   USBEndpointConfig in_ep_config;
161   USBEndpointConfig out_ep_config;
162   USBEndpointConfig int_ep_config;
163   const QMKUSBConfig config;
164   QMKUSBDriver driver;
165 } usb_driver_config_t;
166
167 #define QMK_USB_DRIVER_CONFIG(stream, notification, fixedsize) { \
168   .queue_capacity_in = stream##_IN_CAPACITY, \
169   .queue_capacity_out = stream##_OUT_CAPACITY, \
170   .in_ep_config = { \
171     .ep_mode = stream##_IN_MODE, \
172     .setup_cb = NULL, \
173     .in_cb = qmkusbDataTransmitted, \
174     .out_cb = NULL, \
175     .in_maxsize = stream##_EPSIZE, \
176     .out_maxsize = 0, \
177     /* The pointer to the states will be filled during initialization */ \
178     .in_state = NULL, \
179     .out_state = NULL, \
180     .ep_buffers = 2, \
181     .setup_buf = NULL \
182   }, \
183   .out_ep_config = { \
184     .ep_mode = stream##_OUT_MODE, \
185     .setup_cb = NULL, \
186     .in_cb = NULL, \
187     .out_cb = qmkusbDataReceived, \
188     .in_maxsize = 0, \
189     .out_maxsize = stream##_EPSIZE, \
190     /* The pointer to the states will be filled during initialization */ \
191     .in_state = NULL, \
192     .out_state = NULL, \
193     .ep_buffers = 2, \
194     .setup_buf = NULL, \
195   }, \
196   .int_ep_config = { \
197     .ep_mode = USB_EP_MODE_TYPE_INTR, \
198     .setup_cb = NULL, \
199     .in_cb = qmkusbInterruptTransmitted, \
200     .out_cb = NULL, \
201     .in_maxsize = CDC_NOTIFICATION_EPSIZE, \
202     .out_maxsize = 0, \
203     /* The pointer to the states will be filled during initialization */ \
204     .in_state = NULL, \
205     .out_state = NULL, \
206     .ep_buffers = 2, \
207     .setup_buf = NULL, \
208   }, \
209   .config = { \
210     .usbp = &USB_DRIVER, \
211     .bulk_in = stream##_IN_EPNUM, \
212     .bulk_out = stream##_OUT_EPNUM, \
213     .int_in = notification, \
214     .in_buffers = stream##_IN_CAPACITY, \
215     .out_buffers = stream##_OUT_CAPACITY, \
216     .in_size = stream##_EPSIZE, \
217     .out_size = stream##_EPSIZE, \
218     .fixed_size = fixedsize, \
219     .ib = (uint8_t[BQ_BUFFER_SIZE(stream##_IN_CAPACITY, stream##_EPSIZE)]) {}, \
220     .ob = (uint8_t[BQ_BUFFER_SIZE(stream##_OUT_CAPACITY,stream##_EPSIZE)]) {}, \
221   } \
222 }
223
224 typedef struct {
225   union {
226     struct {
227 #ifdef CONSOLE_ENABLE
228       usb_driver_config_t console_driver;
229 #endif
230 #ifdef RAW_ENABLE
231       usb_driver_config_t raw_driver;
232 #endif
233 #ifdef MIDI_ENABLE
234       usb_driver_config_t midi_driver;
235 #endif
236 #ifdef VIRTSER_ENABLE
237       usb_driver_config_t serial_driver;
238 #endif
239     };
240     usb_driver_config_t array[0];
241   };
242 } usb_driver_configs_t;
243
244 static usb_driver_configs_t drivers = {
245 #ifdef CONSOLE_ENABLE
246   #define CONSOLE_IN_CAPACITY 4
247   #define CONSOLE_OUT_CAPACITY 4
248   #define CONSOLE_IN_MODE USB_EP_MODE_TYPE_INTR
249   #define CONSOLE_OUT_MODE USB_EP_MODE_TYPE_INTR
250   .console_driver = QMK_USB_DRIVER_CONFIG(CONSOLE, 0, true),
251 #endif
252 #ifdef RAW_ENABLE
253   #define RAW_IN_CAPACITY 4
254   #define RAW_OUT_CAPACITY 4
255   #define RAW_IN_MODE USB_EP_MODE_TYPE_INTR
256   #define RAW_OUT_MODE USB_EP_MODE_TYPE_INTR
257   .raw_driver = QMK_USB_DRIVER_CONFIG(RAW, 0, false),
258 #endif
259
260 #ifdef MIDI_ENABLE
261   #define MIDI_STREAM_IN_CAPACITY 4
262   #define MIDI_STREAM_OUT_CAPACITY 4
263   #define MIDI_STREAM_IN_MODE USB_EP_MODE_TYPE_BULK
264   #define MIDI_STREAM_OUT_MODE USB_EP_MODE_TYPE_BULK
265   .midi_driver = QMK_USB_DRIVER_CONFIG(MIDI_STREAM, 0, false),
266 #endif
267
268 #ifdef VIRTSER_ENABLE
269   #define CDC_IN_CAPACITY 4
270   #define CDC_OUT_CAPACITY 4
271   #define CDC_IN_MODE USB_EP_MODE_TYPE_BULK
272   #define CDC_OUT_MODE USB_EP_MODE_TYPE_BULK
273   .serial_driver = QMK_USB_DRIVER_CONFIG(CDC, CDC_NOTIFICATION_EPNUM, false),
274 #endif
275 };
276
277 #define NUM_USB_DRIVERS (sizeof(drivers) / sizeof(usb_driver_config_t))
278
279
280 /* ---------------------------------------------------------
281  *                  USB driver functions
282  * ---------------------------------------------------------
283  */
284
285 /* Handles the USB driver global events
286  * TODO: maybe disable some things when connection is lost? */
287 static void usb_event_cb(USBDriver *usbp, usbevent_t event) {
288   switch(event) {
289   case USB_EVENT_ADDRESS:
290     return;
291
292   case USB_EVENT_CONFIGURED:
293     osalSysLockFromISR();
294     /* Enable the endpoints specified into the configuration. */
295 #ifndef KEYBOARD_SHARED_EP
296     usbInitEndpointI(usbp, KEYBOARD_IN_EPNUM, &kbd_ep_config);
297 #endif
298 #if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
299     usbInitEndpointI(usbp, MOUSE_IN_EPNUM, &mouse_ep_config);
300 #endif
301 #ifdef SHARED_EP_ENABLE
302     usbInitEndpointI(usbp, SHARED_IN_EPNUM, &shared_ep_config);
303 #endif
304     for (int i=0;i<NUM_USB_DRIVERS;i++) {
305       usbInitEndpointI(usbp, drivers.array[i].config.bulk_in, &drivers.array[i].in_ep_config);
306       usbInitEndpointI(usbp, drivers.array[i].config.bulk_out, &drivers.array[i].out_ep_config);
307       if (drivers.array[i].config.int_in) {
308         usbInitEndpointI(usbp, drivers.array[i].config.int_in, &drivers.array[i].int_ep_config);
309       }
310       qmkusbConfigureHookI(&drivers.array[i].driver);
311     }
312     osalSysUnlockFromISR();
313     return;
314   case USB_EVENT_SUSPEND:
315 #ifdef SLEEP_LED_ENABLE
316     sleep_led_enable();
317 #endif /* SLEEP_LED_ENABLE */
318     /* Falls into.*/
319   case USB_EVENT_UNCONFIGURED:
320     /* Falls into.*/
321   case USB_EVENT_RESET:
322       for (int i=0;i<NUM_USB_DRIVERS;i++) {
323         chSysLockFromISR();
324         /* Disconnection event on suspend.*/
325         qmkusbSuspendHookI(&drivers.array[i].driver);
326         chSysUnlockFromISR();
327       }
328     return;
329
330   case USB_EVENT_WAKEUP:
331     //TODO: from ISR! print("[W]");
332       for (int i=0;i<NUM_USB_DRIVERS;i++) {
333         chSysLockFromISR();
334         /* Disconnection event on suspend.*/
335         qmkusbWakeupHookI(&drivers.array[i].driver);
336         chSysUnlockFromISR();
337       }
338     suspend_wakeup_init();
339 #ifdef SLEEP_LED_ENABLE
340     sleep_led_disable();
341     // NOTE: converters may not accept this
342     led_set(host_keyboard_leds());
343 #endif /* SLEEP_LED_ENABLE */
344     return;
345
346   case USB_EVENT_STALLED:
347     return;
348   }
349 }
350
351 /* Function used locally in os/hal/src/usb.c for getting descriptors
352  * need it here for HID descriptor */
353 static uint16_t get_hword(uint8_t *p) {
354   uint16_t hw;
355
356   hw = (uint16_t)*p++;
357   hw |= (uint16_t)*p << 8U;
358   return hw;
359 }
360
361 /*
362  * Appendix G: HID Request Support Requirements
363  *
364  * The following table enumerates the requests that need to be supported by various types of HID class devices.
365  * Device type     GetReport   SetReport   GetIdle     SetIdle     GetProtocol SetProtocol
366  * ------------------------------------------------------------------------------------------
367  * Boot Mouse      Required    Optional    Optional    Optional    Required    Required
368  * Non-Boot Mouse  Required    Optional    Optional    Optional    Optional    Optional
369  * Boot Keyboard   Required    Optional    Required    Required    Required    Required
370  * Non-Boot Keybrd Required    Optional    Required    Required    Optional    Optional
371  * Other Device    Required    Optional    Optional    Optional    Optional    Optional
372  */
373
374 #ifdef SHARED_EP_ENABLE
375 static uint8_t set_report_buf[2] __attribute__((aligned(2)));
376 static void set_led_transfer_cb(USBDriver *usbp) {
377   if ((set_report_buf[0] == REPORT_ID_KEYBOARD) ||
378       (set_report_buf[0] == REPORT_ID_NKRO)) {
379     keyboard_led_stats = set_report_buf[1];
380   }
381 }
382 #endif
383
384 /* Callback for SETUP request on the endpoint 0 (control) */
385 static bool usb_request_hook_cb(USBDriver *usbp) {
386   const USBDescriptor *dp;
387   int has_report_id;
388
389   /* usbp->setup fields:
390    *  0:   bmRequestType (bitmask)
391    *  1:   bRequest
392    *  2,3: (LSB,MSB) wValue
393    *  4,5: (LSB,MSB) wIndex
394    *  6,7: (LSB,MSB) wLength (number of bytes to transfer if there is a data phase) */
395
396   /* Handle HID class specific requests */
397   if(((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) &&
398      ((usbp->setup[0] & USB_RTYPE_RECIPIENT_MASK) == USB_RTYPE_RECIPIENT_INTERFACE)) {
399     switch(usbp->setup[0] & USB_RTYPE_DIR_MASK) {
400     case USB_RTYPE_DIR_DEV2HOST:
401       switch(usbp->setup[1]) {   /* bRequest */
402       case HID_GET_REPORT:
403         switch(usbp->setup[4]) {     /* LSB(wIndex) (check MSB==0?) */
404         case KEYBOARD_INTERFACE:
405           usbSetupTransfer(usbp, (uint8_t *)&keyboard_report_sent, sizeof(keyboard_report_sent), NULL);
406           return TRUE;
407           break;
408
409 #if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
410         case MOUSE_INTERFACE:
411           usbSetupTransfer(usbp, (uint8_t *)&mouse_report_blank, sizeof(mouse_report_blank), NULL);
412           return TRUE;
413           break;
414 #endif
415
416         default:
417           usbSetupTransfer(usbp, NULL, 0, NULL);
418           return TRUE;
419           break;
420         }
421         break;
422
423       case HID_GET_PROTOCOL:
424         if((usbp->setup[4] == KEYBOARD_INTERFACE) && (usbp->setup[5] == 0)) {   /* wIndex */
425           usbSetupTransfer(usbp, &keyboard_protocol, 1, NULL);
426           return TRUE;
427         }
428         break;
429
430       case HID_GET_IDLE:
431         usbSetupTransfer(usbp, &keyboard_idle, 1, NULL);
432         return TRUE;
433         break;
434       }
435       break;
436
437     case USB_RTYPE_DIR_HOST2DEV:
438       switch(usbp->setup[1]) {   /* bRequest */
439       case HID_SET_REPORT:
440         switch(usbp->setup[4]) {       /* LSB(wIndex) (check MSB==0 and wLength==1?) */
441         case KEYBOARD_INTERFACE:
442 #if defined(SHARED_EP_ENABLE) && !defined(KEYBOARD_SHARED_EP)
443         case SHARED_INTERFACE:
444 #endif
445         /* keyboard_led_stats = <read byte from next OUT report>
446          * keyboard_led_stats needs be word (or dword), otherwise we get an exception on F0 */
447           has_report_id = 0;
448 #if defined(SHARED_EP_ENABLE)
449           if (usbp->setup[4] == SHARED_INTERFACE) {
450             has_report_id = 1;
451           }
452 #endif
453           if (usbp->setup[4] == KEYBOARD_INTERFACE && !keyboard_protocol) {
454             has_report_id = 0;
455           }
456           if (has_report_id) {
457             usbSetupTransfer(usbp, set_report_buf, sizeof(set_report_buf), set_led_transfer_cb);
458           } else {
459             usbSetupTransfer(usbp, (uint8_t *)&keyboard_led_stats, 1, NULL);
460           }
461           return TRUE;
462           break;
463         }
464         break;
465
466       case HID_SET_PROTOCOL:
467         if((usbp->setup[4] == KEYBOARD_INTERFACE) && (usbp->setup[5] == 0)) {   /* wIndex */
468           keyboard_protocol = ((usbp->setup[2]) != 0x00);   /* LSB(wValue) */
469 #ifdef NKRO_ENABLE
470           keymap_config.nkro = !!keyboard_protocol;
471           if(!keymap_config.nkro && keyboard_idle) {
472 #else /* NKRO_ENABLE */
473           if(keyboard_idle) {
474 #endif /* NKRO_ENABLE */
475           /* arm the idle timer if boot protocol & idle */
476             osalSysLockFromISR();
477             chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp);
478             osalSysUnlockFromISR();
479           }
480         }
481         usbSetupTransfer(usbp, NULL, 0, NULL);
482         return TRUE;
483         break;
484
485       case HID_SET_IDLE:
486         keyboard_idle = usbp->setup[3];     /* MSB(wValue) */
487         /* arm the timer */
488 #ifdef NKRO_ENABLE
489         if(!keymap_config.nkro && keyboard_idle) {
490 #else /* NKRO_ENABLE */
491         if(keyboard_idle) {
492 #endif /* NKRO_ENABLE */
493           osalSysLockFromISR();
494           chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp);
495           osalSysUnlockFromISR();
496         }
497         usbSetupTransfer(usbp, NULL, 0, NULL);
498         return TRUE;
499         break;
500       }
501       break;
502     }
503   }
504
505   /* Handle the Get_Descriptor Request for HID class (not handled by the default hook) */
506   if((usbp->setup[0] == 0x81) && (usbp->setup[1] == USB_REQ_GET_DESCRIPTOR)) {
507     dp = usbp->config->get_descriptor_cb(usbp, usbp->setup[3], usbp->setup[2], get_hword(&usbp->setup[4]));
508     if(dp == NULL)
509       return FALSE;
510     usbSetupTransfer(usbp, (uint8_t *)dp->ud_string, dp->ud_size, NULL);
511     return TRUE;
512   }
513
514   for (int i=0;i<NUM_USB_DRIVERS;i++) {
515     if (drivers.array[i].config.int_in) {
516       // NOTE: Assumes that we only have one serial driver
517       return qmkusbRequestsHook(usbp);
518     }
519   }
520
521   return FALSE;
522 }
523
524 /* Start-of-frame callback */
525 static void usb_sof_cb(USBDriver *usbp) {
526   kbd_sof_cb(usbp);
527   osalSysLockFromISR();
528   for (int i=0; i<NUM_USB_DRIVERS;i++) {
529     qmkusbSOFHookI(&drivers.array[i].driver);
530   }
531   osalSysUnlockFromISR();
532 }
533
534
535 /* USB driver configuration */
536 static const USBConfig usbcfg = {
537   usb_event_cb,                 /* USB events callback */
538   usb_get_descriptor_cb,        /* Device GET_DESCRIPTOR request callback */
539   usb_request_hook_cb,          /* Requests hook callback */
540   usb_sof_cb                    /* Start Of Frame callback */
541 };
542
543 /*
544  * Initialize the USB driver
545  */
546 void init_usb_driver(USBDriver *usbp) {
547   for (int i=0; i<NUM_USB_DRIVERS;i++) {
548     QMKUSBDriver* driver = &drivers.array[i].driver;
549     drivers.array[i].in_ep_config.in_state = &drivers.array[i].in_ep_state;
550     drivers.array[i].out_ep_config.out_state = &drivers.array[i].out_ep_state;
551     drivers.array[i].int_ep_config.in_state = &drivers.array[i].int_ep_state;
552     qmkusbObjectInit(driver, &drivers.array[i].config);
553     qmkusbStart(driver, &drivers.array[i].config);
554   }
555
556   /*
557    * Activates the USB driver and then the USB bus pull-up on D+.
558    * Note, a delay is inserted in order to not have to disconnect the cable
559    * after a reset.
560    */
561   usbDisconnectBus(usbp);
562   wait_ms(1500);
563   usbStart(usbp, &usbcfg);
564   usbConnectBus(usbp);
565
566   chVTObjectInit(&keyboard_idle_timer);
567 }
568
569 /* ---------------------------------------------------------
570  *                  Keyboard functions
571  * ---------------------------------------------------------
572  */
573 /* keyboard IN callback hander (a kbd report has made it IN) */
574 #ifndef KEYBOARD_SHARED_EP
575 void kbd_in_cb(USBDriver *usbp, usbep_t ep) {
576   /* STUB */
577   (void)usbp;
578   (void)ep;
579 }
580 #endif
581
582 /* start-of-frame handler
583  * TODO: i guess it would be better to re-implement using timers,
584  *  so that this is not going to have to be checked every 1ms */
585 void kbd_sof_cb(USBDriver *usbp) {
586   (void)usbp;
587 }
588
589 /* Idle requests timer code
590  * callback (called from ISR, unlocked state) */
591 static void keyboard_idle_timer_cb(void *arg) {
592   USBDriver *usbp = (USBDriver *)arg;
593
594   osalSysLockFromISR();
595
596   /* check that the states of things are as they're supposed to */
597   if(usbGetDriverStateI(usbp) != USB_ACTIVE) {
598     /* do not rearm the timer, should be enabled on IDLE request */
599     osalSysUnlockFromISR();
600     return;
601   }
602
603 #ifdef NKRO_ENABLE
604   if(!keymap_config.nkro && keyboard_idle && keyboard_protocol) {
605 #else /* NKRO_ENABLE */
606   if(keyboard_idle && keyboard_protocol) {
607 #endif /* NKRO_ENABLE */
608     /* TODO: are we sure we want the KBD_ENDPOINT? */
609     if(!usbGetTransmitStatusI(usbp, KEYBOARD_IN_EPNUM)) {
610       usbStartTransmitI(usbp, KEYBOARD_IN_EPNUM, (uint8_t *)&keyboard_report_sent, KEYBOARD_EPSIZE);
611     }
612     /* rearm the timer */
613     chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp);
614   }
615
616   /* do not rearm the timer if the condition above fails
617    * it should be enabled again on either IDLE or SET_PROTOCOL requests */
618   osalSysUnlockFromISR();
619 }
620
621 /* LED status */
622 uint8_t keyboard_leds(void) {
623   return (uint8_t)(keyboard_led_stats & 0xFF);
624 }
625
626 /* prepare and start sending a report IN
627  * not callable from ISR or locked state */
628 void send_keyboard(report_keyboard_t *report) {
629   osalSysLock();
630   if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
631     osalSysUnlock();
632     return;
633   }
634   osalSysUnlock();
635
636 #ifdef NKRO_ENABLE
637   if(keymap_config.nkro && keyboard_protocol) {  /* NKRO protocol */
638     /* need to wait until the previous packet has made it through */
639     /* can rewrite this using the synchronous API, then would wait
640      * until *after* the packet has been transmitted. I think
641      * this is more efficient */
642     /* busy wait, should be short and not very common */
643     osalSysLock();
644     if(usbGetTransmitStatusI(&USB_DRIVER, SHARED_IN_EPNUM)) {
645       /* Need to either suspend, or loop and call unlock/lock during
646        * every iteration - otherwise the system will remain locked,
647        * no interrupts served, so USB not going through as well.
648        * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */
649       osalThreadSuspendS(&(&USB_DRIVER)->epc[SHARED_IN_EPNUM]->in_state->thread);
650     }
651     usbStartTransmitI(&USB_DRIVER, SHARED_IN_EPNUM, (uint8_t *)report, sizeof(struct nkro_report));
652     osalSysUnlock();
653   } else
654 #endif /* NKRO_ENABLE */
655   { /* regular protocol */
656     /* need to wait until the previous packet has made it through */
657     /* busy wait, should be short and not very common */
658     osalSysLock();
659     if(usbGetTransmitStatusI(&USB_DRIVER, KEYBOARD_IN_EPNUM)) {
660       /* Need to either suspend, or loop and call unlock/lock during
661        * every iteration - otherwise the system will remain locked,
662        * no interrupts served, so USB not going through as well.
663        * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */
664       osalThreadSuspendS(&(&USB_DRIVER)->epc[KEYBOARD_IN_EPNUM]->in_state->thread);
665     }
666     uint8_t *data, size;
667     if (keyboard_protocol) {
668       data = (uint8_t*)report;
669       size = KEYBOARD_REPORT_SIZE;
670     } else {    /* boot protocol */
671       data = &report->mods;
672       size = 8;
673     }
674     usbStartTransmitI(&USB_DRIVER, KEYBOARD_IN_EPNUM, data, size);
675     osalSysUnlock();
676   }
677   keyboard_report_sent = *report;
678 }
679
680 /* ---------------------------------------------------------
681  *                     Mouse functions
682  * ---------------------------------------------------------
683  */
684
685 #ifdef MOUSE_ENABLE
686
687 #ifndef MOUSE_SHARED_EP
688 /* mouse IN callback hander (a mouse report has made it IN) */
689 void mouse_in_cb(USBDriver *usbp, usbep_t ep) {
690   (void)usbp;
691   (void)ep;
692 }
693 #endif
694
695 void send_mouse(report_mouse_t *report) {
696   osalSysLock();
697   if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
698     osalSysUnlock();
699     return;
700   }
701
702   if(usbGetTransmitStatusI(&USB_DRIVER, MOUSE_IN_EPNUM)) {
703     /* Need to either suspend, or loop and call unlock/lock during
704      * every iteration - otherwise the system will remain locked,
705      * no interrupts served, so USB not going through as well.
706      * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */
707     if (osalThreadSuspendTimeoutS(&(&USB_DRIVER)->epc[MOUSE_IN_EPNUM]->in_state->thread, MS2ST(10))==MSG_TIMEOUT) {
708       osalSysUnlock();
709       return;
710     }
711   }
712   usbStartTransmitI(&USB_DRIVER, MOUSE_IN_EPNUM, (uint8_t *)report, sizeof(report_mouse_t));
713   osalSysUnlock();
714 }
715
716 #else /* MOUSE_ENABLE */
717 void send_mouse(report_mouse_t *report) {
718   (void)report;
719 }
720 #endif /* MOUSE_ENABLE */
721
722 /* ---------------------------------------------------------
723  *                   Shared EP functions
724  * ---------------------------------------------------------
725  */
726 #ifdef SHARED_EP_ENABLE
727 /* shared IN callback hander */
728 void shared_in_cb(USBDriver *usbp, usbep_t ep) {
729   /* STUB */
730   (void)usbp;
731   (void)ep;
732 }
733 #endif
734
735 /* ---------------------------------------------------------
736  *                   Extrakey functions
737  * ---------------------------------------------------------
738  */
739
740 #ifdef EXTRAKEY_ENABLE
741 static void send_extra_report(uint8_t report_id, uint16_t data) {
742   osalSysLock();
743   if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
744     osalSysUnlock();
745     return;
746   }
747
748   report_extra_t report = {
749     .report_id = report_id,
750     .usage = data
751   };
752
753   usbStartTransmitI(&USB_DRIVER, SHARED_IN_EPNUM, (uint8_t *)&report, sizeof(report_extra_t));
754   osalSysUnlock();
755 }
756
757 void send_system(uint16_t data) {
758   send_extra_report(REPORT_ID_SYSTEM, data);
759 }
760
761 void send_consumer(uint16_t data) {
762   send_extra_report(REPORT_ID_CONSUMER, data);
763 }
764
765 #else /* EXTRAKEY_ENABLE */
766 void send_system(uint16_t data) {
767   (void)data;
768 }
769 void send_consumer(uint16_t data) {
770   (void)data;
771 }
772 #endif /* EXTRAKEY_ENABLE */
773
774 /* ---------------------------------------------------------
775  *                   Console functions
776  * ---------------------------------------------------------
777  */
778
779 #ifdef CONSOLE_ENABLE
780
781 int8_t sendchar(uint8_t c) {
782   // The previous implmentation had timeouts, but I think it's better to just slow down
783   // and make sure that everything is transferred, rather than dropping stuff
784   return chnWrite(&drivers.console_driver.driver, &c, 1);
785 }
786
787 // Just a dummy function for now, this could be exposed as a weak function
788 // Or connected to the actual QMK console
789 static void console_receive( uint8_t *data, uint8_t length ) {
790   (void)data;
791   (void)length;
792 }
793
794 void console_task(void) {
795   uint8_t buffer[CONSOLE_EPSIZE];
796   size_t size = 0;
797   do {
798     size_t size = chnReadTimeout(&drivers.console_driver.driver, buffer, sizeof(buffer), TIME_IMMEDIATE);
799     if (size > 0) {
800         console_receive(buffer, size);
801     }
802   } while(size > 0);
803 }
804
805 #else /* CONSOLE_ENABLE */
806 int8_t sendchar(uint8_t c) {
807   (void)c;
808   return 0;
809 }
810 #endif /* CONSOLE_ENABLE */
811
812 void sendchar_pf(void *p, char c) {
813   (void)p;
814   sendchar((uint8_t)c);
815 }
816
817 #ifdef RAW_ENABLE
818 void raw_hid_send( uint8_t *data, uint8_t length ) {
819         // TODO: implement variable size packet
820         if ( length != RAW_EPSIZE )
821         {
822                 return;
823
824         }
825   chnWrite(&drivers.raw_driver.driver, data, length);
826 }
827
828 __attribute__ ((weak))
829 void raw_hid_receive( uint8_t *data, uint8_t length ) {
830         // Users should #include "raw_hid.h" in their own code
831         // and implement this function there. Leave this as weak linkage
832         // so users can opt to not handle data coming in.
833 }
834
835 void raw_hid_task(void) {
836   uint8_t buffer[RAW_EPSIZE];
837   size_t size = 0;
838   do {
839     size_t size = chnReadTimeout(&drivers.raw_driver.driver, buffer, sizeof(buffer), TIME_IMMEDIATE);
840     if (size > 0) {
841         raw_hid_receive(buffer, size);
842     }
843   } while(size > 0);
844 }
845
846 #endif
847
848 #ifdef MIDI_ENABLE
849
850 void send_midi_packet(MIDI_EventPacket_t* event) {
851   chnWrite(&drivers.midi_driver.driver, (uint8_t*)event, sizeof(MIDI_EventPacket_t));
852 }
853
854 bool recv_midi_packet(MIDI_EventPacket_t* const event) {
855   size_t size = chnReadTimeout(&drivers.midi_driver.driver, (uint8_t*)event, sizeof(MIDI_EventPacket_t), TIME_IMMEDIATE);
856   return size == sizeof(MIDI_EventPacket_t);
857 }
858
859 #endif
860
861 #ifdef VIRTSER_ENABLE
862
863 void virtser_send(const uint8_t byte) {
864   chnWrite(&drivers.serial_driver.driver, &byte, 1);
865 }
866
867 __attribute__ ((weak))
868 void virtser_recv(uint8_t c)
869 {
870   // Ignore by default
871 }
872
873 void virtser_task(void) {
874   uint8_t numBytesReceived = 0;
875   uint8_t buffer[16];
876   do {
877     numBytesReceived = chnReadTimeout(&drivers.serial_driver.driver, buffer, sizeof(buffer), TIME_IMMEDIATE);
878     for (int i=0;i<numBytesReceived;i++) {
879       virtser_recv(buffer[i]);
880     }
881   } while (numBytesReceived > 0);
882 }
883
884 #endif