#include "usb_main.h"
+#include "host.h"
#include "debug.h"
+#include "suspend.h"
#ifdef SLEEP_LED_ENABLE
#include "sleep_led.h"
#include "led.h"
-#include "host.h"
#endif
/* ---------------------------------------------------------
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 */
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
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
/* 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
/* 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 */
/* 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 */
/* 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 */
/* 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 */
};
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 */
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 */
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 */
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 */
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 */
case USB_EVENT_SUSPEND:
//TODO: from ISR! print("[S]");
- //TODO: signal suspend?
#ifdef SLEEP_LED_ENABLE
sleep_led_enable();
#endif /* SLEEP_LED_ENABLE */
case USB_EVENT_WAKEUP:
//TODO: from ISR! print("[W]");
- //TODO: suspend_wakeup_init();
+ suspend_wakeup_init();
#ifdef SLEEP_LED_ENABLE
sleep_led_disable();
// NOTE: converters may not accept this
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;
#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) /* K20x || KL2x */
+ STM32_USB->CNTR |= CNTR_RESUME;
+ chThdSleepMilliseconds(15);
+ STM32_USB->CNTR &= ~CNTR_RESUME;
+#else /* STM32F0XX */
+#warning Sending remote wakeup packet not implemented for your platform.
+#endif /* K20x || KL2x */
+}
+
/* ---------------------------------------------------------
* Keyboard functions
* ---------------------------------------------------------
}
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;
}
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);
}
return;
if(!usbGetTransmitStatusI(usbp, CONSOLE_ENDPOINT)
- && (chOQGetFullI(&console_queue) >= CONSOLE_SIZE)) {
+ && (chOQGetFullI(&console_queue) >= CONSOLE_EPSIZE)) {
osalSysUnlock();
- usbPrepareQueuedTransmit(usbp, CONSOLE_ENDPOINT, &console_queue, CONSOLE_SIZE);
+ usbPrepareQueuedTransmit(usbp, CONSOLE_ENDPOINT, &console_queue, CONSOLE_EPSIZE);
osalSysLock();
usbStartTransmitI(usbp, CONSOLE_ENDPOINT);
}
static void console_flush_cb(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 */
}
/* 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, (void *)usbp);
osalSysUnlockFromISR();
/* 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(usbp, CONSOLE_ENDPOINT, buf, CONSOLE_SIZE);
+ usbPrepareTransmit(usbp, CONSOLE_ENDPOINT, buf, CONSOLE_EPSIZE);
osalSysLockFromISR();
(void)usbStartTransmitI(usbp, CONSOLE_ENDPOINT);