X-Git-Url: https://git.friedersdorff.com/?a=blobdiff_plain;f=tmk_core%2Fprotocol%2Fchibios%2Fusb_main.c;h=ee2788e5247711b04242ff31e865081f8f53bd7c;hb=8952d617ea489eed11b454abffc96cb286b1acbc;hp=875f47dc491dfcf488e6ed84a0bcc676135c879f;hpb=27dec2db7bb33cc45b04b89b6855bac6b98de2e5;p=max%2Ftmk_keyboard.git diff --git a/tmk_core/protocol/chibios/usb_main.c b/tmk_core/protocol/chibios/usb_main.c index 875f47dc..ee2788e5 100644 --- a/tmk_core/protocol/chibios/usb_main.c +++ b/tmk_core/protocol/chibios/usb_main.c @@ -20,6 +20,14 @@ #include "usb_main.h" +#include "host.h" +#include "debug.h" +#include "suspend.h" +#ifdef SLEEP_LED_ENABLE +#include "sleep_led.h" +#include "led.h" +#endif + /* --------------------------------------------------------- * Global interface variables and declarations * --------------------------------------------------------- @@ -32,10 +40,16 @@ volatile uint16_t keyboard_idle_count = 0; static virtual_timer_t keyboard_idle_timer; static void keyboard_idle_timer_cb(void *arg); #ifdef NKRO_ENABLE -bool keyboard_nkro = true; +extern bool keyboard_nkro; #endif /* NKRO_ENABLE */ report_keyboard_t keyboard_report_sent = {{0}}; +#ifdef MOUSE_ENABLE +report_mouse_t mouse_report_blank = {0}; +#endif /* MOUSE_ENABLE */ +#ifdef EXTRAKEY_ENABLE +uint8_t extra_report_blank[3] = {0}; +#endif /* EXTRAKEY_ENABLE */ #ifdef CONSOLE_ENABLE /* The emission queue */ @@ -243,7 +257,7 @@ static const uint8_t console_hid_report_desc_data[] = { 0x75, 0x08, // report size = 8 bits 0x15, 0x00, // logical minimum = 0 0x26, 0xFF, 0x00, // logical maximum = 255 - 0x95, CONSOLE_SIZE, // report count + 0x95, CONSOLE_EPSIZE, // report count 0x09, 0x75, // usage 0x81, 0x02, // Input (array) 0xC0 // end collection @@ -343,8 +357,8 @@ static const uint8_t hid_configuration_descriptor_data[] = { NUM_INTERFACES, // bNumInterfaces 1, // bConfigurationValue 0, // iConfiguration - 0xA0, // bmAttributes - 50), // bMaxPower (100mA) + 0xA0, // bmAttributes (RESERVED|REMOTEWAKEUP) + 50), // bMaxPower (50mA) /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */ USB_DESC_INTERFACE(KBD_INTERFACE, // bInterfaceNumber @@ -367,7 +381,7 @@ static const uint8_t hid_configuration_descriptor_data[] = { /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */ USB_DESC_ENDPOINT(KBD_ENDPOINT | 0x80, // bEndpointAddress 0x03, // bmAttributes (Interrupt) - KBD_SIZE, // wMaxPacketSize + KBD_EPSIZE,// wMaxPacketSize 10), // bInterval #ifdef MOUSE_ENABLE @@ -397,7 +411,7 @@ static const uint8_t hid_configuration_descriptor_data[] = { /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */ USB_DESC_ENDPOINT(MOUSE_ENDPOINT | 0x80, // bEndpointAddress 0x03, // bmAttributes (Interrupt) - MOUSE_SIZE, // wMaxPacketSize + MOUSE_EPSIZE, // wMaxPacketSize 1), // bInterval #endif /* MOUSE_ENABLE */ @@ -423,7 +437,7 @@ static const uint8_t hid_configuration_descriptor_data[] = { /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */ USB_DESC_ENDPOINT(CONSOLE_ENDPOINT | 0x80, // bEndpointAddress 0x03, // bmAttributes (Interrupt) - CONSOLE_SIZE, // wMaxPacketSize + CONSOLE_EPSIZE, // wMaxPacketSize 1), // bInterval #endif /* CONSOLE_ENABLE */ @@ -449,7 +463,7 @@ static const uint8_t hid_configuration_descriptor_data[] = { /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */ USB_DESC_ENDPOINT(EXTRA_ENDPOINT | 0x80, // bEndpointAddress 0x03, // bmAttributes (Interrupt) - EXTRA_SIZE, // wMaxPacketSize + EXTRA_EPSIZE, // wMaxPacketSize 10), // bInterval #endif /* EXTRAKEY_ENABLE */ @@ -475,7 +489,7 @@ static const uint8_t hid_configuration_descriptor_data[] = { /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */ USB_DESC_ENDPOINT(NKRO_ENDPOINT | 0x80, // bEndpointAddress 0x03, // bmAttributes (Interrupt) - NKRO_SIZE, // wMaxPacketSize + NKRO_EPSIZE, // wMaxPacketSize 1), // bInterval #endif /* NKRO_ENABLE */ }; @@ -658,7 +672,7 @@ static const USBEndpointConfig kbd_ep_config = { NULL, /* SETUP packet notification callback */ kbd_in_cb, /* IN notification callback */ NULL, /* OUT notification callback */ - KBD_SIZE, /* IN maximum packet size */ + KBD_EPSIZE, /* IN maximum packet size */ 0, /* OUT maximum packet size */ &kbd_ep_state, /* IN Endpoint state */ NULL, /* OUT endpoint state */ @@ -676,7 +690,7 @@ static const USBEndpointConfig mouse_ep_config = { NULL, /* SETUP packet notification callback */ mouse_in_cb, /* IN notification callback */ NULL, /* OUT notification callback */ - MOUSE_SIZE, /* IN maximum packet size */ + MOUSE_EPSIZE, /* IN maximum packet size */ 0, /* OUT maximum packet size */ &mouse_ep_state, /* IN Endpoint state */ NULL, /* OUT endpoint state */ @@ -695,7 +709,7 @@ static const USBEndpointConfig console_ep_config = { NULL, /* SETUP packet notification callback */ console_in_cb, /* IN notification callback */ NULL, /* OUT notification callback */ - CONSOLE_SIZE, /* IN maximum packet size */ + CONSOLE_EPSIZE, /* IN maximum packet size */ 0, /* OUT maximum packet size */ &console_ep_state, /* IN Endpoint state */ NULL, /* OUT endpoint state */ @@ -714,7 +728,7 @@ static const USBEndpointConfig extra_ep_config = { NULL, /* SETUP packet notification callback */ extra_in_cb, /* IN notification callback */ NULL, /* OUT notification callback */ - EXTRA_SIZE, /* IN maximum packet size */ + EXTRA_EPSIZE, /* IN maximum packet size */ 0, /* OUT maximum packet size */ &extra_ep_state, /* IN Endpoint state */ NULL, /* OUT endpoint state */ @@ -733,7 +747,7 @@ static const USBEndpointConfig nkro_ep_config = { NULL, /* SETUP packet notification callback */ nkro_in_cb, /* IN notification callback */ NULL, /* OUT notification callback */ - NKRO_SIZE, /* IN maximum packet size */ + NKRO_EPSIZE, /* IN maximum packet size */ 0, /* OUT maximum packet size */ &nkro_ep_state, /* IN Endpoint state */ NULL, /* OUT endpoint state */ @@ -752,6 +766,7 @@ static const USBEndpointConfig nkro_ep_config = { static void usb_event_cb(USBDriver *usbp, usbevent_t event) { switch(event) { case USB_EVENT_RESET: + //TODO: from ISR! print("[R]"); return; case USB_EVENT_ADDRESS: @@ -778,9 +793,20 @@ static void usb_event_cb(USBDriver *usbp, usbevent_t event) { return; case USB_EVENT_SUSPEND: + //TODO: from ISR! print("[S]"); +#ifdef SLEEP_LED_ENABLE + sleep_led_enable(); +#endif /* SLEEP_LED_ENABLE */ return; case USB_EVENT_WAKEUP: + //TODO: from ISR! print("[W]"); + suspend_wakeup_init(); +#ifdef SLEEP_LED_ENABLE + sleep_led_disable(); + // NOTE: converters may not accept this + led_set(host_keyboard_leds()); +#endif /* SLEEP_LED_ENABLE */ return; case USB_EVENT_STALLED: @@ -838,6 +864,43 @@ static bool usb_request_hook_cb(USBDriver *usbp) { return TRUE; break; +#ifdef MOUSE_ENABLE + case MOUSE_INTERFACE: + usbSetupTransfer(usbp, (uint8_t *)&mouse_report_blank, sizeof(mouse_report_blank), NULL); + return TRUE; + break; +#endif /* MOUSE_ENABLE */ + +#ifdef CONSOLE_ENABLE + case CONSOLE_INTERFACE: + usbSetupTransfer(usbp, console_queue_buffer, CONSOLE_EPSIZE, NULL); + return TRUE; + break; +#endif /* CONSOLE_ENABLE */ + +#ifdef EXTRAKEY_ENABLE + case EXTRA_INTERFACE: + if(usbp->setup[3] == 1) { /* MSB(wValue) [Report Type] == 1 [Input Report] */ + switch(usbp->setup[2]) { /* LSB(wValue) [Report ID] */ + case REPORT_ID_SYSTEM: + extra_report_blank[0] = REPORT_ID_SYSTEM; + usbSetupTransfer(usbp, (uint8_t *)extra_report_blank, sizeof(extra_report_blank), NULL); + return TRUE; + break; + case REPORT_ID_CONSUMER: + extra_report_blank[0] = REPORT_ID_CONSUMER; + usbSetupTransfer(usbp, (uint8_t *)extra_report_blank, sizeof(extra_report_blank), NULL); + return TRUE; + break; + default: + return FALSE; + } + } else { + return FALSE; + } + break; +#endif /* EXTRAKEY_ENABLE */ + default: usbSetupTransfer(usbp, NULL, 0, NULL); return TRUE; @@ -886,7 +949,7 @@ static bool usb_request_hook_cb(USBDriver *usbp) { #endif /* NKRO_ENABLE */ /* arm the idle timer if boot protocol & idle */ osalSysLockFromISR(); - chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, NULL); + chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp); osalSysUnlockFromISR(); } } @@ -903,7 +966,7 @@ static bool usb_request_hook_cb(USBDriver *usbp) { if(keyboard_idle) { #endif /* NKRO_ENABLE */ osalSysLockFromISR(); - chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, NULL); + chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp); osalSysUnlockFromISR(); } usbSetupTransfer(usbp, NULL, 0, NULL); @@ -943,24 +1006,45 @@ static const USBConfig usbcfg = { /* * Initialize the USB driver */ -void init_usb_driver(void) { +void init_usb_driver(USBDriver *usbp) { /* * Activates the USB driver and then the USB bus pull-up on D+. * Note, a delay is inserted in order to not have to disconnect the cable * after a reset. */ - usbDisconnectBus(&USB_DRIVER); + usbDisconnectBus(usbp); chThdSleepMilliseconds(1500); - usbStart(&USB_DRIVER, &usbcfg); - usbConnectBus(&USB_DRIVER); + usbStart(usbp, &usbcfg); + usbConnectBus(usbp); chVTObjectInit(&keyboard_idle_timer); #ifdef CONSOLE_ENABLE - oqObjectInit(&console_queue, console_queue_buffer, sizeof(console_queue_buffer), console_queue_onotify, NULL); + oqObjectInit(&console_queue, console_queue_buffer, sizeof(console_queue_buffer), console_queue_onotify, (void *)usbp); chVTObjectInit(&console_flush_timer); #endif } +/* + * Send remote wakeup packet + * Note: should not be called from ISR + */ +void send_remote_wakeup(USBDriver *usbp) { + (void)usbp; +#if defined(K20x) || defined(KL2x) +#if KINETIS_USB_USE_USB0 + USB0->CTL |= USBx_CTL_RESUME; + chThdSleepMilliseconds(15); + USB0->CTL &= ~USBx_CTL_RESUME; +#endif /* KINETIS_USB_USE_USB0 */ +#elif defined(STM32F0XX) || defined(STM32F1XX) /* K20x || KL2x */ + STM32_USB->CNTR |= CNTR_RESUME; + chThdSleepMilliseconds(15); + STM32_USB->CNTR &= ~CNTR_RESUME; +#else /* STM32F0XX || STM32F1XX */ +#warning Sending remote wakeup packet not implemented for your platform. +#endif /* K20x || KL2x */ +} + /* --------------------------------------------------------- * Keyboard functions * --------------------------------------------------------- @@ -992,12 +1076,12 @@ void kbd_sof_cb(USBDriver *usbp) { /* Idle requests timer code * callback (called from ISR, unlocked state) */ static void keyboard_idle_timer_cb(void *arg) { - (void)arg; + USBDriver *usbp = (USBDriver *)arg; osalSysLockFromISR(); /* check that the states of things are as they're supposed to */ - if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) { + if(usbGetDriverStateI(usbp) != USB_ACTIVE) { /* do not rearm the timer, should be enabled on IDLE request */ osalSysUnlockFromISR(); return; @@ -1010,11 +1094,11 @@ static void keyboard_idle_timer_cb(void *arg) { #endif /* NKRO_ENABLE */ /* TODO: are we sure we want the KBD_ENDPOINT? */ osalSysUnlockFromISR(); - usbPrepareTransmit(&USB_DRIVER, KBD_ENDPOINT, (uint8_t *)&keyboard_report_sent, sizeof(keyboard_report_sent)); + usbPrepareTransmit(usbp, KBD_ENDPOINT, (uint8_t *)&keyboard_report_sent, sizeof(keyboard_report_sent)); osalSysLockFromISR(); - usbStartTransmitI(&USB_DRIVER, KBD_ENDPOINT); + usbStartTransmitI(usbp, KBD_ENDPOINT); /* rearm the timer */ - chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, NULL); + chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp); } /* do not rearm the timer if the condition above fails @@ -1037,19 +1121,26 @@ void send_keyboard(report_keyboard_t *report) { } osalSysUnlock(); + bool ep_not_ready; #ifdef NKRO_ENABLE if(keyboard_nkro) { /* NKRO protocol */ usbPrepareTransmit(&USB_DRIVER, NKRO_ENDPOINT, (uint8_t *)report, sizeof(report_keyboard_t)); - osalSysLock(); - usbStartTransmitI(&USB_DRIVER, NKRO_ENDPOINT); - osalSysUnlock(); + /* need to wait until the previous packet has made it through */ + do { + osalSysLock(); + ep_not_ready = usbStartTransmitI(&USB_DRIVER, NKRO_ENDPOINT); + osalSysUnlock(); + } while (ep_not_ready); } else #endif /* NKRO_ENABLE */ { /* boot protocol */ - usbPrepareTransmit(&USB_DRIVER, KBD_ENDPOINT, (uint8_t *)report, sizeof(report_keyboard_t)); - osalSysLock(); - usbStartTransmitI(&USB_DRIVER, KBD_ENDPOINT); - osalSysUnlock(); + usbPrepareTransmit(&USB_DRIVER, KBD_ENDPOINT, (uint8_t *)report, KBD_EPSIZE); + /* need to wait until the previous packet has made it through */ + do { + osalSysLock(); + ep_not_ready = usbStartTransmitI(&USB_DRIVER, KBD_ENDPOINT); + osalSysUnlock(); + } while (ep_not_ready); } keyboard_report_sent = *report; } @@ -1155,12 +1246,12 @@ void console_in_cb(USBDriver *usbp, usbep_t ep) { osalSysLockFromISR(); /* rearm the timer */ - chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, NULL); + chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, (void *)usbp); /* Check if there is data to send left in the output queue */ - if(chOQGetFullI(&console_queue) >= CONSOLE_SIZE) { + if(chOQGetFullI(&console_queue) >= CONSOLE_EPSIZE) { osalSysUnlockFromISR(); - usbPrepareQueuedTransmit(usbp, CONSOLE_ENDPOINT, &console_queue, CONSOLE_SIZE); + usbPrepareQueuedTransmit(usbp, CONSOLE_ENDPOINT, &console_queue, CONSOLE_EPSIZE); osalSysLockFromISR(); usbStartTransmitI(usbp, CONSOLE_ENDPOINT); } @@ -1171,40 +1262,40 @@ void console_in_cb(USBDriver *usbp, usbep_t ep) { /* Callback when data is inserted into the output queue * Called from a locked state */ void console_queue_onotify(io_queue_t *qp) { - (void)qp; + USBDriver *usbp = qGetLink(qp); - if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) + if(usbGetDriverStateI(usbp) != USB_ACTIVE) return; - if(!usbGetTransmitStatusI(&USB_DRIVER, CONSOLE_ENDPOINT) - && (chOQGetFullI(&console_queue) >= CONSOLE_SIZE)) { + if(!usbGetTransmitStatusI(usbp, CONSOLE_ENDPOINT) + && (chOQGetFullI(&console_queue) >= CONSOLE_EPSIZE)) { osalSysUnlock(); - usbPrepareQueuedTransmit(&USB_DRIVER, CONSOLE_ENDPOINT, &console_queue, CONSOLE_SIZE); + usbPrepareQueuedTransmit(usbp, CONSOLE_ENDPOINT, &console_queue, CONSOLE_EPSIZE); osalSysLock(); - usbStartTransmitI(&USB_DRIVER, CONSOLE_ENDPOINT); + usbStartTransmitI(usbp, CONSOLE_ENDPOINT); } } /* Flush timer code * callback (called from ISR, unlocked state) */ static void console_flush_cb(void *arg) { - (void)arg; + USBDriver *usbp = (USBDriver *)arg; size_t i, n; - uint8_t buf[CONSOLE_SIZE]; /* TODO: a solution without extra buffer? */ + uint8_t buf[CONSOLE_EPSIZE]; /* TODO: a solution without extra buffer? */ osalSysLockFromISR(); /* check that the states of things are as they're supposed to */ - if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) { + if(usbGetDriverStateI(usbp) != USB_ACTIVE) { /* rearm the timer */ - chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, NULL); + chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, (void *)usbp); osalSysUnlockFromISR(); return; } /* don't do anything if the queue is empty or has enough stuff in it */ - if(((n = oqGetFullI(&console_queue)) == 0) || (n >= CONSOLE_SIZE)) { + if(((n = oqGetFullI(&console_queue)) == 0) || (n >= CONSOLE_EPSIZE)) { /* rearm the timer */ - chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, NULL); + chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, (void *)usbp); osalSysUnlockFromISR(); return; } @@ -1212,15 +1303,15 @@ static void console_flush_cb(void *arg) { /* there's stuff hanging in the queue - so dequeue and send */ for(i = 0; i < n; i++) buf[i] = (uint8_t)oqGetI(&console_queue); - for(i = n; i < CONSOLE_SIZE; i++) + for(i = n; i < CONSOLE_EPSIZE; i++) buf[i] = 0; osalSysUnlockFromISR(); - usbPrepareTransmit(&USB_DRIVER, CONSOLE_ENDPOINT, buf, CONSOLE_SIZE); + usbPrepareTransmit(usbp, CONSOLE_ENDPOINT, buf, CONSOLE_EPSIZE); osalSysLockFromISR(); - (void)usbStartTransmitI(&USB_DRIVER, CONSOLE_ENDPOINT); + (void)usbStartTransmitI(usbp, CONSOLE_ENDPOINT); /* rearm the timer */ - chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, NULL); + chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, (void *)usbp); osalSysUnlockFromISR(); } @@ -1232,10 +1323,13 @@ int8_t sendchar(uint8_t c) { return 0; } osalSysUnlock(); - /* should get suspended and wait if the queue is full - * but it's not blocking even if noone is listening, - * because the USB packets are sent anyway */ - return(chOQPut(&console_queue, c)); + /* Timeout after 5us if the queue is full. + * Increase this timeout if too much stuff is getting + * dropped (i.e. the buffer is getting full too fast + * for USB/HIDRAW to dequeue). Another possibility + * for fixing this kind of thing is to increase + * CONSOLE_QUEUE_CAPACITY. */ + return(chOQPutTimeout(&console_queue, c, US2ST(5))); } #else /* CONSOLE_ENABLE */