#include "usbdrv.h" #include "usbconfig.h" #include "print.h" #include "usb_keycodes.h" #include "host.h" #include "host_vusb.h" #include "debug.h" static report_keyboard_t report0; static report_keyboard_t report1; report_keyboard_t *keyboard_report = &report0; report_keyboard_t *keyboard_report_prev = &report1; static uint8_t keyboard_leds = 0; static uchar idleRate = 0; uint8_t host_keyboard_leds(void) { return keyboard_leds; } /*------------------------------------------------------------------* * Keyboard report operations *------------------------------------------------------------------*/ void host_add_key(uint8_t code) { int8_t i = 0; int8_t empty = -1; for (; i < REPORT_KEYS; i++) { if (keyboard_report_prev->keys[i] == code) { keyboard_report->keys[i] = code; break; } if (empty == -1 && keyboard_report_prev->keys[i] == KB_NO && keyboard_report->keys[i] == KB_NO) { empty = i; } } if (i == REPORT_KEYS && empty != -1) { keyboard_report->keys[empty] = code; } } void host_add_mod_bit(uint8_t mod) { keyboard_report->mods |= mod; } void host_set_mods(uint8_t mods) { keyboard_report->mods = mods; } void host_add_code(uint8_t code) { if (IS_MOD(code)) { host_add_mod_bit(MOD_BIT(code)); } else { host_add_key(code); } } void host_swap_keyboard_report(void) { report_keyboard_t *tmp = keyboard_report_prev; keyboard_report_prev = keyboard_report; keyboard_report = tmp; } void host_clear_keyboard_report(void) { keyboard_report->mods = 0; for (int8_t i = 0; i < REPORT_KEYS; i++) { keyboard_report->keys[i] = 0; } } uint8_t host_has_anykey(void) { uint8_t cnt = 0; for (int i = 0; i < REPORT_KEYS; i++) { if (keyboard_report->keys[i]) cnt++; } return cnt; } uint8_t *host_get_keys(void) { return keyboard_report->keys; } uint8_t host_get_mods(void) { return keyboard_report->mods; } /*------------------------------------------------------------------* * Keyboard report send buffer *------------------------------------------------------------------*/ #define KBUF_SIZE 16 static report_keyboard_t kbuf[KBUF_SIZE]; static uint8_t kbuf_head = 0; static uint8_t kbuf_tail = 0; void host_vusb_keyboard_send(void) { while (usbInterruptIsReady() && kbuf_head != kbuf_tail) { usbSetInterrupt((void *)&kbuf[kbuf_tail], sizeof(report_keyboard_t)); kbuf_tail = (kbuf_tail + 1) % KBUF_SIZE; } } void host_send_keyboard_report(void) { uint8_t next = (kbuf_head + 1) % KBUF_SIZE; if (next != kbuf_tail) { kbuf[kbuf_head] = *keyboard_report; kbuf_head = next; } else { debug("kbuf: full\n"); } } void host_mouse_send(report_mouse_t *report) { if (usbInterruptIsReady3()) { usbSetInterrupt3((void *)report, sizeof(*report)); } else { debug("Int3 not ready\n"); } } /*------------------------------------------------------------------* * Request from host * *------------------------------------------------------------------*/ static struct { uint16_t len; enum { NONE, SET_LED } kind; } last_req; usbMsgLen_t usbFunctionSetup(uchar data[8]) { usbRequest_t *rq = (void *)data; if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* class request type */ if(rq->bRequest == USBRQ_HID_GET_REPORT){ debug(" GET_REPORT"); /* we only have one report type, so don't look at wValue */ usbMsgPtr = (void *)keyboard_report; return sizeof(*keyboard_report); }else if(rq->bRequest == USBRQ_HID_GET_IDLE){ debug(" GET_IDLE: "); debug_hex(idleRate); usbMsgPtr = &idleRate; return 1; }else if(rq->bRequest == USBRQ_HID_SET_IDLE){ idleRate = rq->wValue.bytes[1]; debug(" SET_IDLE: "); debug_hex(idleRate); }else if(rq->bRequest == USBRQ_HID_SET_REPORT){ //debug(" SET_REPORT: "); if (rq->wValue.word == 0x0200 && rq->wIndex.word == 0) { last_req.kind = SET_LED; last_req.len = rq->wLength.word; } return USB_NO_MSG; // to get data in usbFunctionWrite } debug("\n"); }else{ debug("VENDOR\n"); /* no vendor specific requests implemented */ } return 0; /* default for not implemented requests: return no data back to host */ } uchar usbFunctionWrite(uchar *data, uchar len) { if (last_req.len == 0) { return -1; } switch (last_req.kind) { case SET_LED: //debug("SET_LED\n"); keyboard_leds = data[0]; last_req.len = 0; return 1; break; case NONE: default: return -1; break; } return 1; } /*------------------------------------------------------------------* * Descriptors * *------------------------------------------------------------------*/ /* * Report Descriptor for keyboard * * from an example in HID spec appendix */ PROGMEM uchar keyboard_hid_report[] = { 0x05, 0x01, // Usage Page (Generic Desktop), 0x09, 0x06, // Usage (Keyboard), 0xA1, 0x01, // Collection (Application), 0x75, 0x01, // Report Size (1), 0x95, 0x08, // Report Count (8), 0x05, 0x07, // Usage Page (Key Codes), 0x19, 0xE0, // Usage Minimum (224), 0x29, 0xE7, // Usage Maximum (231), 0x15, 0x00, // Logical Minimum (0), 0x25, 0x01, // Logical Maximum (1), 0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte 0x95, 0x01, // Report Count (1), 0x75, 0x08, // Report Size (8), 0x81, 0x03, // Input (Constant), ;Reserved byte 0x95, 0x05, // Report Count (5), 0x75, 0x01, // Report Size (1), 0x05, 0x08, // Usage Page (LEDs), 0x19, 0x01, // Usage Minimum (1), 0x29, 0x05, // Usage Maximum (5), 0x91, 0x02, // Output (Data, Variable, Absolute), ;LED report 0x95, 0x01, // Report Count (1), 0x75, 0x03, // Report Size (3), 0x91, 0x03, // Output (Constant), ;LED report padding 0x95, 0x06, // Report Count (6), 0x75, 0x08, // Report Size (8), 0x15, 0x00, // Logical Minimum (0), 0x25, 0xFF, // Logical Maximum(255), 0x05, 0x07, // Usage Page (Key Codes), 0x19, 0x00, // Usage Minimum (0), 0x29, 0xFF, // Usage Maximum (255), 0x81, 0x00, // Input (Data, Array), 0xc0 // End Collection }; /* * Report Descriptor for mouse * * Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension * http://www.microchip.com/forums/tm.aspx?high=&m=391435&mpage=1#391521 * http://www.keil.com/forum/15671/ * http://www.microsoft.com/whdc/device/input/wheel.mspx */ PROGMEM uchar mouse_hid_report[] = { /* from HID 1.11 spec example */ 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x02, // USAGE (Mouse) 0xa1, 0x01, // COLLECTION (Application) 0x09, 0x02, // USAGE (Mouse) 0xa1, 0x02, // COLLECTION (Logical) 0x09, 0x01, // USAGE (Pointer) 0xa1, 0x00, // COLLECTION (Physical) // ------------------------------ Buttons 0x05, 0x09, // USAGE_PAGE (Button) 0x19, 0x01, // USAGE_MINIMUM (Button 1) 0x29, 0x05, // USAGE_MAXIMUM (Button 5) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x75, 0x01, // REPORT_SIZE (1) 0x95, 0x05, // REPORT_COUNT (5) 0x81, 0x02, // INPUT (Data,Var,Abs) // ------------------------------ Padding 0x75, 0x03, // REPORT_SIZE (3) 0x95, 0x01, // REPORT_COUNT (1) 0x81, 0x03, // INPUT (Cnst,Var,Abs) // ------------------------------ X,Y position 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x30, // USAGE (X) 0x09, 0x31, // USAGE (Y) 0x15, 0x81, // LOGICAL_MINIMUM (-127) 0x25, 0x7f, // LOGICAL_MAXIMUM (127) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x02, // REPORT_COUNT (2) 0x81, 0x06, // INPUT (Data,Var,Rel) 0xa1, 0x02, // COLLECTION (Logical) // ------------------------------ Vertical wheel res multiplier 0x09, 0x48, // USAGE (Resolution Multiplier) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x35, 0x01, // PHYSICAL_MINIMUM (1) 0x45, 0x04, // PHYSICAL_MAXIMUM (4) 0x75, 0x02, // REPORT_SIZE (2) 0x95, 0x01, // REPORT_COUNT (1) 0xa4, // PUSH 0xb1, 0x02, // FEATURE (Data,Var,Abs) // ------------------------------ Vertical wheel 0x09, 0x38, // USAGE (Wheel) 0x15, 0x81, // LOGICAL_MINIMUM (-127) 0x25, 0x7f, // LOGICAL_MAXIMUM (127) 0x35, 0x00, // PHYSICAL_MINIMUM (0) - reset physical 0x45, 0x00, // PHYSICAL_MAXIMUM (0) 0x75, 0x08, // REPORT_SIZE (8) 0x81, 0x06, // INPUT (Data,Var,Rel) 0xc0, // END_COLLECTION 0xa1, 0x02, // COLLECTION (Logical) // ------------------------------ Horizontal wheel res multiplier 0x09, 0x48, // USAGE (Resolution Multiplier) 0xb4, // POP 0xb1, 0x02, // FEATURE (Data,Var,Abs) // ------------------------------ Padding for Feature report 0x35, 0x00, // PHYSICAL_MINIMUM (0) - reset physical 0x45, 0x00, // PHYSICAL_MAXIMUM (0) 0x75, 0x04, // REPORT_SIZE (4) 0xb1, 0x03, // FEATURE (Cnst,Var,Abs) // ------------------------------ Horizontal wheel 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) 0x0a, 0x38, 0x02, // USAGE (AC Pan) 0x15, 0x81, // LOGICAL_MINIMUM (-127) 0x25, 0x7f, // LOGICAL_MAXIMUM (127) 0x75, 0x08, // REPORT_SIZE (8) 0x81, 0x06, // INPUT (Data,Var,Rel) 0xc0, // END_COLLECTION 0xc0, // END_COLLECTION 0xc0, // END_COLLECTION 0xc0 // END_COLLECTION }; /* * Descriptor for compite device: Keyboard + Mouse * * contains: device, interface, HID and endpoint descriptors */ #if USB_CFG_DESCR_PROPS_CONFIGURATION PROGMEM char usbDescriptorConfiguration[] = { /* USB configuration descriptor */ 9, /* sizeof(usbDescriptorConfiguration): length of descriptor in bytes */ USBDESCR_CONFIG, /* descriptor type */ 9 + (9 + 9 + 7) + (9 + 9 + 7), 0, //18 + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT3 + 9, 0, /* total length of data returned (including inlined descriptors) */ 2, /* number of interfaces in this configuration */ 1, /* index of this configuration */ 0, /* configuration name string index */ #if USB_CFG_IS_SELF_POWERED (1 << 7) | USBATTR_SELFPOWER, /* attributes */ #else (1 << 7), /* attributes */ #endif USB_CFG_MAX_BUS_POWER/2, /* max USB current in 2mA units */ /* * Keyboard interface */ /* Interface descriptor */ 9, /* sizeof(usbDescrInterface): length of descriptor in bytes */ USBDESCR_INTERFACE, /* descriptor type */ 0, /* index of this interface */ 0, /* alternate setting for this interface */ USB_CFG_HAVE_INTRIN_ENDPOINT, /* endpoints excl 0: number of endpoint descriptors to follow */ USB_CFG_INTERFACE_CLASS, USB_CFG_INTERFACE_SUBCLASS, USB_CFG_INTERFACE_PROTOCOL, 0, /* string index for interface */ /* HID descriptor */ 9, /* sizeof(usbDescrHID): length of descriptor in bytes */ USBDESCR_HID, /* descriptor type: HID */ 0x01, 0x01, /* BCD representation of HID version */ 0x00, /* target country code */ 0x01, /* number of HID Report (or other HID class) Descriptor infos to follow */ 0x22, /* descriptor type: report */ sizeof(keyboard_hid_report), 0, /* total length of report descriptor */ /* Endpoint descriptor */ #if USB_CFG_HAVE_INTRIN_ENDPOINT /* endpoint descriptor for endpoint 1 */ 7, /* sizeof(usbDescrEndpoint) */ USBDESCR_ENDPOINT, /* descriptor type = endpoint */ (char)0x81, /* IN endpoint number 1 */ 0x03, /* attrib: Interrupt endpoint */ 8, 0, /* maximum packet size */ USB_CFG_INTR_POLL_INTERVAL, /* in ms */ #endif /* * Mouse interface */ /* Interface descriptor */ 9, /* sizeof(usbDescrInterface): length of descriptor in bytes */ USBDESCR_INTERFACE, /* descriptor type */ 1, /* index of this interface */ 0, /* alternate setting for this interface */ USB_CFG_HAVE_INTRIN_ENDPOINT3, /* endpoints excl 0: number of endpoint descriptors to follow */ 0x03, /* CLASS: HID */ 0, /* SUBCLASS: none */ 0, /* PROTOCOL: none */ 0, /* string index for interface */ /* HID descriptor */ 9, /* sizeof(usbDescrHID): length of descriptor in bytes */ USBDESCR_HID, /* descriptor type: HID */ 0x01, 0x01, /* BCD representation of HID version */ 0x00, /* target country code */ 0x01, /* number of HID Report (or other HID class) Descriptor infos to follow */ 0x22, /* descriptor type: report */ sizeof(mouse_hid_report), 0, /* total length of report descriptor */ #if USB_CFG_HAVE_INTRIN_ENDPOINT3 /* endpoint descriptor for endpoint 3 */ /* Endpoint descriptor */ 7, /* sizeof(usbDescrEndpoint) */ USBDESCR_ENDPOINT, /* descriptor type = endpoint */ (char)(0x80 | USB_CFG_EP3_NUMBER), /* IN endpoint number 3 */ 0x03, /* attrib: Interrupt endpoint */ 8, 0, /* maximum packet size */ USB_CFG_INTR_POLL_INTERVAL, /* in ms */ #endif }; #endif USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq) { usbMsgLen_t len = 0; debug("usbFunctionDescriptor: "); debug_hex(rq->bmRequestType); debug(" "); debug_hex(rq->bRequest); debug(" "); debug_hex16(rq->wValue.word); debug(" "); debug_hex16(rq->wIndex.word); debug(" "); debug_hex16(rq->wLength.word); debug("\n"); switch (rq->wValue.bytes[1]) { #if USB_CFG_DESCR_PROPS_CONFIGURATION case USBDESCR_CONFIG: usbMsgPtr = (unsigned char *)usbDescriptorConfiguration; len = sizeof(usbDescriptorConfiguration); break; #endif case USBDESCR_HID: usbMsgPtr = (unsigned char *)(usbDescriptorConfiguration + 18); len = 9; break; case USBDESCR_HID_REPORT: /* interface index */ switch (rq->wIndex.word) { case 0: usbMsgPtr = keyboard_hid_report; len = sizeof(keyboard_hid_report); break; case 1: usbMsgPtr = mouse_hid_report; len = sizeof(mouse_hid_report); break; } break; } debug("desc len: "); debug_hex(len); debug("\n"); return len; }