2 * (c) 2015 flabberast <s3+flabbergast@sdfeu.org>
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
14 * Since some GPL'd code is used, this work is licensed under
26 #ifdef SLEEP_LED_ENABLE
27 #include "sleep_led.h"
31 #include "usb_descriptor.h"
32 #include "usb_driver.h"
35 #include "keycode_config.h"
37 extern keymap_config_t keymap_config;
40 /* ---------------------------------------------------------
41 * Global interface variables and declarations
42 * ---------------------------------------------------------
45 #ifndef usb_lld_connect_bus
46 #define usb_lld_connect_bus(usbp)
49 #ifndef usb_lld_disconnect_bus
50 #define usb_lld_disconnect_bus(usbp)
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);
60 report_keyboard_t keyboard_report_sent = {{0}};
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 */
68 /* ---------------------------------------------------------
69 * Descriptors and USB driver objects
70 * ---------------------------------------------------------
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
82 * Handles the GET_DESCRIPTOR callback
84 * Returns the proper descriptor
86 static const USBDescriptor *usb_get_descriptor_cb(USBDriver *usbp, uint8_t dtype, uint8_t dindex, uint16_t wIndex) {
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)
98 /* keyboard endpoint state structure */
99 static USBInEndpointState kbd_ep_state;
100 /* keyboard endpoint initialization structure (IN) */
101 static const USBEndpointConfig kbd_ep_config = {
102 USB_EP_MODE_TYPE_INTR, /* Interrupt EP */
103 NULL, /* SETUP packet notification callback */
104 kbd_in_cb, /* IN notification callback */
105 NULL, /* OUT notification callback */
106 KEYBOARD_EPSIZE, /* IN maximum packet size */
107 0, /* OUT maximum packet size */
108 &kbd_ep_state, /* IN Endpoint state */
109 NULL, /* OUT endpoint state */
110 2, /* IN multiplier */
111 NULL /* SETUP buffer (not a SETUP endpoint) */
115 /* mouse endpoint state structure */
116 static USBInEndpointState mouse_ep_state;
118 /* mouse endpoint initialization structure (IN) */
119 static const USBEndpointConfig mouse_ep_config = {
120 USB_EP_MODE_TYPE_INTR, /* Interrupt EP */
121 NULL, /* SETUP packet notification callback */
122 mouse_in_cb, /* IN notification callback */
123 NULL, /* OUT notification callback */
124 MOUSE_EPSIZE, /* IN maximum packet size */
125 0, /* OUT maximum packet size */
126 &mouse_ep_state, /* IN Endpoint state */
127 NULL, /* OUT endpoint state */
128 2, /* IN multiplier */
129 NULL /* SETUP buffer (not a SETUP endpoint) */
131 #endif /* MOUSE_ENABLE */
133 #ifdef EXTRAKEY_ENABLE
134 /* extrakey endpoint state structure */
135 static USBInEndpointState extra_ep_state;
137 /* extrakey endpoint initialization structure (IN) */
138 static const USBEndpointConfig extra_ep_config = {
139 USB_EP_MODE_TYPE_INTR, /* Interrupt EP */
140 NULL, /* SETUP packet notification callback */
141 extra_in_cb, /* IN notification callback */
142 NULL, /* OUT notification callback */
143 EXTRAKEY_EPSIZE, /* IN maximum packet size */
144 0, /* OUT maximum packet size */
145 &extra_ep_state, /* IN Endpoint state */
146 NULL, /* OUT endpoint state */
147 2, /* IN multiplier */
148 NULL /* SETUP buffer (not a SETUP endpoint) */
150 #endif /* EXTRAKEY_ENABLE */
153 /* nkro endpoint state structure */
154 static USBInEndpointState nkro_ep_state;
156 /* nkro endpoint initialization structure (IN) */
157 static const USBEndpointConfig nkro_ep_config = {
158 USB_EP_MODE_TYPE_INTR, /* Interrupt EP */
159 NULL, /* SETUP packet notification callback */
160 nkro_in_cb, /* IN notification callback */
161 NULL, /* OUT notification callback */
162 NKRO_EPSIZE, /* IN maximum packet size */
163 0, /* OUT maximum packet size */
164 &nkro_ep_state, /* IN Endpoint state */
165 NULL, /* OUT endpoint state */
166 2, /* IN multiplier */
167 NULL /* SETUP buffer (not a SETUP endpoint) */
169 #endif /* NKRO_ENABLE */
172 size_t queue_capacity_in;
173 size_t queue_capacity_out;
174 USBInEndpointState in_ep_state;
175 USBOutEndpointState out_ep_state;
176 USBInEndpointState int_ep_state;
177 USBEndpointConfig in_ep_config;
178 USBEndpointConfig out_ep_config;
179 USBEndpointConfig int_ep_config;
180 const QMKUSBConfig config;
182 } usb_driver_config_t;
184 #define QMK_USB_DRIVER_CONFIG(stream, notification, fixedsize) { \
185 .queue_capacity_in = stream##_IN_CAPACITY, \
186 .queue_capacity_out = stream##_OUT_CAPACITY, \
188 .ep_mode = stream##_IN_MODE, \
190 .in_cb = qmkusbDataTransmitted, \
192 .in_maxsize = stream##_EPSIZE, \
194 /* The pointer to the states will be filled during initialization */ \
201 .ep_mode = stream##_OUT_MODE, \
204 .out_cb = qmkusbDataReceived, \
206 .out_maxsize = stream##_EPSIZE, \
207 /* The pointer to the states will be filled during initialization */ \
214 .ep_mode = USB_EP_MODE_TYPE_INTR, \
216 .in_cb = qmkusbInterruptTransmitted, \
218 .in_maxsize = CDC_NOTIFICATION_EPSIZE, \
220 /* The pointer to the states will be filled during initialization */ \
227 .usbp = &USB_DRIVER, \
228 .bulk_in = stream##_IN_EPNUM, \
229 .bulk_out = stream##_OUT_EPNUM, \
230 .int_in = notification, \
231 .in_buffers = stream##_IN_CAPACITY, \
232 .out_buffers = stream##_OUT_CAPACITY, \
233 .in_size = stream##_EPSIZE, \
234 .out_size = stream##_EPSIZE, \
235 .fixed_size = fixedsize, \
236 .ib = (uint8_t[BQ_BUFFER_SIZE(stream##_IN_CAPACITY, stream##_EPSIZE)]) {}, \
237 .ob = (uint8_t[BQ_BUFFER_SIZE(stream##_OUT_CAPACITY,stream##_EPSIZE)]) {}, \
244 #ifdef CONSOLE_ENABLE
245 usb_driver_config_t console_driver;
248 usb_driver_config_t raw_driver;
251 usb_driver_config_t midi_driver;
253 #ifdef VIRTSER_ENABLE
254 usb_driver_config_t serial_driver;
257 usb_driver_config_t array[0];
259 } usb_driver_configs_t;
261 static usb_driver_configs_t drivers = {
262 #ifdef CONSOLE_ENABLE
263 #define CONSOLE_IN_CAPACITY 4
264 #define CONSOLE_OUT_CAPACITY 4
265 #define CONSOLE_IN_MODE USB_EP_MODE_TYPE_INTR
266 #define CONSOLE_OUT_MODE USB_EP_MODE_TYPE_INTR
267 .console_driver = QMK_USB_DRIVER_CONFIG(CONSOLE, 0, true),
270 #define RAW_IN_CAPACITY 4
271 #define RAW_OUT_CAPACITY 4
272 #define RAW_IN_MODE USB_EP_MODE_TYPE_INTR
273 #define RAW_OUT_MODE USB_EP_MODE_TYPE_INTR
274 .raw_driver = QMK_USB_DRIVER_CONFIG(RAW, 0, false),
278 #define MIDI_STREAM_IN_CAPACITY 4
279 #define MIDI_STREAM_OUT_CAPACITY 4
280 #define MIDI_STREAM_IN_MODE USB_EP_MODE_TYPE_BULK
281 #define MIDI_STREAM_OUT_MODE USB_EP_MODE_TYPE_BULK
282 .midi_driver = QMK_USB_DRIVER_CONFIG(MIDI_STREAM, 0, false),
285 #ifdef VIRTSER_ENABLE
286 #define CDC_IN_CAPACITY 4
287 #define CDC_OUT_CAPACITY 4
288 #define CDC_IN_MODE USB_EP_MODE_TYPE_BULK
289 #define CDC_OUT_MODE USB_EP_MODE_TYPE_BULK
290 .serial_driver = QMK_USB_DRIVER_CONFIG(CDC, CDC_NOTIFICATION_EPNUM, false),
294 #define NUM_USB_DRIVERS (sizeof(drivers) / sizeof(usb_driver_config_t))
297 /* ---------------------------------------------------------
298 * USB driver functions
299 * ---------------------------------------------------------
302 /* Handles the USB driver global events
303 * TODO: maybe disable some things when connection is lost? */
304 static void usb_event_cb(USBDriver *usbp, usbevent_t event) {
306 case USB_EVENT_ADDRESS:
309 case USB_EVENT_CONFIGURED:
310 osalSysLockFromISR();
311 /* Enable the endpoints specified into the configuration. */
312 usbInitEndpointI(usbp, KEYBOARD_IN_EPNUM, &kbd_ep_config);
314 usbInitEndpointI(usbp, MOUSE_IN_EPNUM, &mouse_ep_config);
315 #endif /* MOUSE_ENABLE */
316 #ifdef EXTRAKEY_ENABLE
317 usbInitEndpointI(usbp, EXTRAKEY_IN_EPNUM, &extra_ep_config);
318 #endif /* EXTRAKEY_ENABLE */
320 usbInitEndpointI(usbp, NKRO_IN_EPNUM, &nkro_ep_config);
321 #endif /* NKRO_ENABLE */
322 for (int i=0;i<NUM_USB_DRIVERS;i++) {
323 usbInitEndpointI(usbp, drivers.array[i].config.bulk_in, &drivers.array[i].in_ep_config);
324 usbInitEndpointI(usbp, drivers.array[i].config.bulk_out, &drivers.array[i].out_ep_config);
325 if (drivers.array[i].config.int_in) {
326 usbInitEndpointI(usbp, drivers.array[i].config.int_in, &drivers.array[i].int_ep_config);
328 qmkusbConfigureHookI(&drivers.array[i].driver);
330 osalSysUnlockFromISR();
332 case USB_EVENT_SUSPEND:
333 #ifdef SLEEP_LED_ENABLE
335 #endif /* SLEEP_LED_ENABLE */
337 case USB_EVENT_UNCONFIGURED:
339 case USB_EVENT_RESET:
340 for (int i=0;i<NUM_USB_DRIVERS;i++) {
342 /* Disconnection event on suspend.*/
343 qmkusbSuspendHookI(&drivers.array[i].driver);
344 chSysUnlockFromISR();
348 case USB_EVENT_WAKEUP:
349 //TODO: from ISR! print("[W]");
350 for (int i=0;i<NUM_USB_DRIVERS;i++) {
352 /* Disconnection event on suspend.*/
353 qmkusbWakeupHookI(&drivers.array[i].driver);
354 chSysUnlockFromISR();
356 suspend_wakeup_init();
357 #ifdef SLEEP_LED_ENABLE
359 // NOTE: converters may not accept this
360 led_set(host_keyboard_leds());
361 #endif /* SLEEP_LED_ENABLE */
364 case USB_EVENT_STALLED:
369 /* Function used locally in os/hal/src/usb.c for getting descriptors
370 * need it here for HID descriptor */
371 static uint16_t get_hword(uint8_t *p) {
375 hw |= (uint16_t)*p << 8U;
380 * Appendix G: HID Request Support Requirements
382 * The following table enumerates the requests that need to be supported by various types of HID class devices.
383 * Device type GetReport SetReport GetIdle SetIdle GetProtocol SetProtocol
384 * ------------------------------------------------------------------------------------------
385 * Boot Mouse Required Optional Optional Optional Required Required
386 * Non-Boot Mouse Required Optional Optional Optional Optional Optional
387 * Boot Keyboard Required Optional Required Required Required Required
388 * Non-Boot Keybrd Required Optional Required Required Optional Optional
389 * Other Device Required Optional Optional Optional Optional Optional
392 /* Callback for SETUP request on the endpoint 0 (control) */
393 static bool usb_request_hook_cb(USBDriver *usbp) {
394 const USBDescriptor *dp;
396 /* usbp->setup fields:
397 * 0: bmRequestType (bitmask)
399 * 2,3: (LSB,MSB) wValue
400 * 4,5: (LSB,MSB) wIndex
401 * 6,7: (LSB,MSB) wLength (number of bytes to transfer if there is a data phase) */
403 /* Handle HID class specific requests */
404 if(((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) &&
405 ((usbp->setup[0] & USB_RTYPE_RECIPIENT_MASK) == USB_RTYPE_RECIPIENT_INTERFACE)) {
406 switch(usbp->setup[0] & USB_RTYPE_DIR_MASK) {
407 case USB_RTYPE_DIR_DEV2HOST:
408 switch(usbp->setup[1]) { /* bRequest */
410 switch(usbp->setup[4]) { /* LSB(wIndex) (check MSB==0?) */
411 case KEYBOARD_INTERFACE:
414 #endif /* NKRO_ENABLE */
415 usbSetupTransfer(usbp, (uint8_t *)&keyboard_report_sent, sizeof(keyboard_report_sent), NULL);
420 case MOUSE_INTERFACE:
421 usbSetupTransfer(usbp, (uint8_t *)&mouse_report_blank, sizeof(mouse_report_blank), NULL);
424 #endif /* MOUSE_ENABLE */
426 #ifdef EXTRAKEY_ENABLE
427 case EXTRAKEY_INTERFACE:
428 if(usbp->setup[3] == 1) { /* MSB(wValue) [Report Type] == 1 [Input Report] */
429 switch(usbp->setup[2]) { /* LSB(wValue) [Report ID] */
430 case REPORT_ID_SYSTEM:
431 extra_report_blank[0] = REPORT_ID_SYSTEM;
432 usbSetupTransfer(usbp, (uint8_t *)extra_report_blank, sizeof(extra_report_blank), NULL);
435 case REPORT_ID_CONSUMER:
436 extra_report_blank[0] = REPORT_ID_CONSUMER;
437 usbSetupTransfer(usbp, (uint8_t *)extra_report_blank, sizeof(extra_report_blank), NULL);
447 #endif /* EXTRAKEY_ENABLE */
450 usbSetupTransfer(usbp, NULL, 0, NULL);
456 case HID_GET_PROTOCOL:
457 if((usbp->setup[4] == KEYBOARD_INTERFACE) && (usbp->setup[5] == 0)) { /* wIndex */
458 usbSetupTransfer(usbp, &keyboard_protocol, 1, NULL);
464 usbSetupTransfer(usbp, &keyboard_idle, 1, NULL);
470 case USB_RTYPE_DIR_HOST2DEV:
471 switch(usbp->setup[1]) { /* bRequest */
473 switch(usbp->setup[4]) { /* LSB(wIndex) (check MSB==0 and wLength==1?) */
474 case KEYBOARD_INTERFACE:
477 #endif /* NKRO_ENABLE */
478 /* keyboard_led_stats = <read byte from next OUT report>
479 * keyboard_led_stats needs be word (or dword), otherwise we get an exception on F0 */
480 usbSetupTransfer(usbp, (uint8_t *)&keyboard_led_stats, 1, NULL);
486 case HID_SET_PROTOCOL:
487 if((usbp->setup[4] == KEYBOARD_INTERFACE) && (usbp->setup[5] == 0)) { /* wIndex */
488 keyboard_protocol = ((usbp->setup[2]) != 0x00); /* LSB(wValue) */
490 keymap_config.nkro = !!keyboard_protocol;
491 if(!keymap_config.nkro && keyboard_idle) {
492 #else /* NKRO_ENABLE */
494 #endif /* NKRO_ENABLE */
495 /* arm the idle timer if boot protocol & idle */
496 osalSysLockFromISR();
497 chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp);
498 osalSysUnlockFromISR();
501 usbSetupTransfer(usbp, NULL, 0, NULL);
506 keyboard_idle = usbp->setup[3]; /* MSB(wValue) */
509 if(!keymap_config.nkro && keyboard_idle) {
510 #else /* NKRO_ENABLE */
512 #endif /* NKRO_ENABLE */
513 osalSysLockFromISR();
514 chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp);
515 osalSysUnlockFromISR();
517 usbSetupTransfer(usbp, NULL, 0, NULL);
525 /* Handle the Get_Descriptor Request for HID class (not handled by the default hook) */
526 if((usbp->setup[0] == 0x81) && (usbp->setup[1] == USB_REQ_GET_DESCRIPTOR)) {
527 dp = usbp->config->get_descriptor_cb(usbp, usbp->setup[3], usbp->setup[2], get_hword(&usbp->setup[4]));
530 usbSetupTransfer(usbp, (uint8_t *)dp->ud_string, dp->ud_size, NULL);
534 for (int i=0;i<NUM_USB_DRIVERS;i++) {
535 if (drivers.array[i].config.int_in) {
536 // NOTE: Assumes that we only have one serial driver
537 return qmkusbRequestsHook(usbp);
544 /* Start-of-frame callback */
545 static void usb_sof_cb(USBDriver *usbp) {
547 osalSysLockFromISR();
548 for (int i=0; i<NUM_USB_DRIVERS;i++) {
549 qmkusbSOFHookI(&drivers.array[i].driver);
551 osalSysUnlockFromISR();
555 /* USB driver configuration */
556 static const USBConfig usbcfg = {
557 usb_event_cb, /* USB events callback */
558 usb_get_descriptor_cb, /* Device GET_DESCRIPTOR request callback */
559 usb_request_hook_cb, /* Requests hook callback */
560 usb_sof_cb /* Start Of Frame callback */
564 * Initialize the USB driver
566 void init_usb_driver(USBDriver *usbp) {
567 for (int i=0; i<NUM_USB_DRIVERS;i++) {
568 QMKUSBDriver* driver = &drivers.array[i].driver;
569 drivers.array[i].in_ep_config.in_state = &drivers.array[i].in_ep_state;
570 drivers.array[i].out_ep_config.out_state = &drivers.array[i].out_ep_state;
571 drivers.array[i].int_ep_config.in_state = &drivers.array[i].int_ep_state;
572 qmkusbObjectInit(driver, &drivers.array[i].config);
573 qmkusbStart(driver, &drivers.array[i].config);
577 * Activates the USB driver and then the USB bus pull-up on D+.
578 * Note, a delay is inserted in order to not have to disconnect the cable
581 usbDisconnectBus(usbp);
583 usbStart(usbp, &usbcfg);
586 chVTObjectInit(&keyboard_idle_timer);
589 /* ---------------------------------------------------------
591 * ---------------------------------------------------------
593 /* keyboard IN callback hander (a kbd report has made it IN) */
594 void kbd_in_cb(USBDriver *usbp, usbep_t ep) {
601 /* nkro IN callback hander (a nkro report has made it IN) */
602 void nkro_in_cb(USBDriver *usbp, usbep_t ep) {
607 #endif /* NKRO_ENABLE */
609 /* start-of-frame handler
610 * TODO: i guess it would be better to re-implement using timers,
611 * so that this is not going to have to be checked every 1ms */
612 void kbd_sof_cb(USBDriver *usbp) {
616 /* Idle requests timer code
617 * callback (called from ISR, unlocked state) */
618 static void keyboard_idle_timer_cb(void *arg) {
619 USBDriver *usbp = (USBDriver *)arg;
621 osalSysLockFromISR();
623 /* check that the states of things are as they're supposed to */
624 if(usbGetDriverStateI(usbp) != USB_ACTIVE) {
625 /* do not rearm the timer, should be enabled on IDLE request */
626 osalSysUnlockFromISR();
631 if(!keymap_config.nkro && keyboard_idle) {
632 #else /* NKRO_ENABLE */
634 #endif /* NKRO_ENABLE */
635 /* TODO: are we sure we want the KBD_ENDPOINT? */
636 if(!usbGetTransmitStatusI(usbp, KEYBOARD_IN_EPNUM)) {
637 usbStartTransmitI(usbp, KEYBOARD_IN_EPNUM, (uint8_t *)&keyboard_report_sent, KEYBOARD_EPSIZE);
639 /* rearm the timer */
640 chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp);
643 /* do not rearm the timer if the condition above fails
644 * it should be enabled again on either IDLE or SET_PROTOCOL requests */
645 osalSysUnlockFromISR();
649 uint8_t keyboard_leds(void) {
650 return (uint8_t)(keyboard_led_stats & 0xFF);
653 /* prepare and start sending a report IN
654 * not callable from ISR or locked state */
655 void send_keyboard(report_keyboard_t *report) {
657 if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
664 if(keymap_config.nkro) { /* NKRO protocol */
665 /* need to wait until the previous packet has made it through */
666 /* can rewrite this using the synchronous API, then would wait
667 * until *after* the packet has been transmitted. I think
668 * this is more efficient */
669 /* busy wait, should be short and not very common */
671 if(usbGetTransmitStatusI(&USB_DRIVER, NKRO_IN_EPNUM)) {
672 /* Need to either suspend, or loop and call unlock/lock during
673 * every iteration - otherwise the system will remain locked,
674 * no interrupts served, so USB not going through as well.
675 * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */
676 osalThreadSuspendS(&(&USB_DRIVER)->epc[NKRO_IN_EPNUM]->in_state->thread);
678 usbStartTransmitI(&USB_DRIVER, NKRO_IN_EPNUM, (uint8_t *)report, sizeof(report_keyboard_t));
681 #endif /* NKRO_ENABLE */
682 { /* boot protocol */
683 /* need to wait until the previous packet has made it through */
684 /* busy wait, should be short and not very common */
686 if(usbGetTransmitStatusI(&USB_DRIVER, KEYBOARD_IN_EPNUM)) {
687 /* Need to either suspend, or loop and call unlock/lock during
688 * every iteration - otherwise the system will remain locked,
689 * no interrupts served, so USB not going through as well.
690 * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */
691 osalThreadSuspendS(&(&USB_DRIVER)->epc[KEYBOARD_IN_EPNUM]->in_state->thread);
693 usbStartTransmitI(&USB_DRIVER, KEYBOARD_IN_EPNUM, (uint8_t *)report, KEYBOARD_EPSIZE);
696 keyboard_report_sent = *report;
699 /* ---------------------------------------------------------
701 * ---------------------------------------------------------
706 /* mouse IN callback hander (a mouse report has made it IN) */
707 void mouse_in_cb(USBDriver *usbp, usbep_t ep) {
712 void send_mouse(report_mouse_t *report) {
714 if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
720 /* TODO: LUFA manually waits for the endpoint to become ready
721 * for about 10ms for mouse, kbd, system; 1ms for nkro
722 * is this really needed?
726 usbStartTransmitI(&USB_DRIVER, MOUSE_IN_EPNUM, (uint8_t *)report, sizeof(report_mouse_t));
730 #else /* MOUSE_ENABLE */
731 void send_mouse(report_mouse_t *report) {
734 #endif /* MOUSE_ENABLE */
736 /* ---------------------------------------------------------
738 * ---------------------------------------------------------
741 #ifdef EXTRAKEY_ENABLE
743 /* extrakey IN callback hander */
744 void extra_in_cb(USBDriver *usbp, usbep_t ep) {
750 static void send_extra_report(uint8_t report_id, uint16_t data) {
752 if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
757 report_extra_t report = {
758 .report_id = report_id,
762 usbStartTransmitI(&USB_DRIVER, EXTRAKEY_IN_EPNUM, (uint8_t *)&report, sizeof(report_extra_t));
766 void send_system(uint16_t data) {
767 send_extra_report(REPORT_ID_SYSTEM, data);
770 void send_consumer(uint16_t data) {
771 send_extra_report(REPORT_ID_CONSUMER, data);
774 #else /* EXTRAKEY_ENABLE */
775 void send_system(uint16_t data) {
778 void send_consumer(uint16_t data) {
781 #endif /* EXTRAKEY_ENABLE */
783 /* ---------------------------------------------------------
785 * ---------------------------------------------------------
788 #ifdef CONSOLE_ENABLE
790 int8_t sendchar(uint8_t c) {
791 // The previous implmentation had timeouts, but I think it's better to just slow down
792 // and make sure that everything is transferred, rather than dropping stuff
793 return chnWrite(&drivers.console_driver.driver, &c, 1);
796 // Just a dummy function for now, this could be exposed as a weak function
797 // Or connected to the actual QMK console
798 static void console_receive( uint8_t *data, uint8_t length ) {
803 void console_task(void) {
804 uint8_t buffer[CONSOLE_EPSIZE];
807 size_t size = chnReadTimeout(&drivers.console_driver.driver, buffer, sizeof(buffer), TIME_IMMEDIATE);
809 console_receive(buffer, size);
814 #else /* CONSOLE_ENABLE */
815 int8_t sendchar(uint8_t c) {
819 #endif /* CONSOLE_ENABLE */
821 void sendchar_pf(void *p, char c) {
823 sendchar((uint8_t)c);
827 void raw_hid_send( uint8_t *data, uint8_t length ) {
828 // TODO: implement variable size packet
829 if ( length != RAW_EPSIZE )
834 chnWrite(&drivers.raw_driver.driver, data, length);
837 __attribute__ ((weak))
838 void raw_hid_receive( uint8_t *data, uint8_t length ) {
839 // Users should #include "raw_hid.h" in their own code
840 // and implement this function there. Leave this as weak linkage
841 // so users can opt to not handle data coming in.
844 void raw_hid_task(void) {
845 uint8_t buffer[RAW_EPSIZE];
848 size_t size = chnReadTimeout(&drivers.raw_driver.driver, buffer, sizeof(buffer), TIME_IMMEDIATE);
850 raw_hid_receive(buffer, size);
859 void send_midi_packet(MIDI_EventPacket_t* event) {
860 chnWrite(&drivers.midi_driver.driver, (uint8_t*)event, sizeof(MIDI_EventPacket_t));
863 bool recv_midi_packet(MIDI_EventPacket_t* const event) {
864 size_t size = chnReadTimeout(&drivers.midi_driver.driver, (uint8_t*)event, sizeof(MIDI_EventPacket_t), TIME_IMMEDIATE);
865 return size == sizeof(MIDI_EventPacket_t);
870 #ifdef VIRTSER_ENABLE
872 void virtser_send(const uint8_t byte) {
873 chnWrite(&drivers.serial_driver.driver, &byte, 1);
876 __attribute__ ((weak))
877 void virtser_recv(uint8_t c)
882 void virtser_task(void) {
883 uint8_t numBytesReceived = 0;
886 numBytesReceived = chnReadTimeout(&drivers.serial_driver.driver, buffer, sizeof(buffer), TIME_IMMEDIATE);
887 for (int i=0;i<numBytesReceived;i++) {
888 virtser_recv(buffer[i]);
890 } while (numBytesReceived > 0);