#include "usbdrv.h" #include "usbconfig.h" #include "keyboard.h" #include "print.h" #include "host.h" #include "host_vusb.h" #define KBUF_SIZE 8 static report_keyboard_t kbuf[KBUF_SIZE]; static uint8_t kbuf_head = 0; static uint8_t kbuf_tail = 0; void host_vusb_keyboard_send() { if (kbuf_head != kbuf_tail) { if (usbInterruptIsReady()) { usbSetInterrupt((void *)&kbuf[kbuf_tail], sizeof(report_keyboard_t)); kbuf_tail = (kbuf_tail + 1) % KBUF_SIZE; } } } void host_keyboard_send(report_keyboard_t *report) { uint8_t next = (kbuf_head + 1) % KBUF_SIZE; if (next != kbuf_tail) { kbuf[kbuf_head] = *report; kbuf_head = next; } } void host_mouse_send(report_mouse_t *report) { // dirty hack to send twice a loop :( //while (!usbInterruptIsReady3()) usbPoll(); if (usbInterruptIsReady3()) { usbSetInterrupt3((void *)report, sizeof(*report)); } else { print("Int3 not ready\n"); } } static uchar idleRate; /* repeat rate for keyboards, never used for mice */ usbMsgLen_t usbFunctionSetup(uchar data[8]) { usbRequest_t *rq = (void *)data; print("Setup: "); if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* class request type */ print("CLASS: "); phex(rq->bRequest); if(rq->bRequest == USBRQ_HID_GET_REPORT){ print("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){ print("GET_IDLE: "); phex(idleRate); usbMsgPtr = &idleRate; return 1; }else if(rq->bRequest == USBRQ_HID_SET_IDLE){ idleRate = rq->wValue.bytes[1]; print("SET_IDLE: "); phex(idleRate); } print("\n"); }else{ print("VENDOR\n"); /* no vendor specific requests implemented */ } return 0; /* default for not implemented requests: return no data back to host */ } 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 }; // 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, 0x01, // Usage (Pointer), 0xA1, 0x00, // Collection (Physical), 0x05, 0x09, // Usage Page (Buttons), 0x19, 0x01, // Usage Minimum (01), 0x29, 0x03, // Usage Maximun (03), 0x15, 0x00, // Logical Minimum (0), 0x25, 0x01, // Logical Maximum (1), 0x95, 0x03, // Report Count (3), 0x75, 0x01, // Report Size (1), 0x81, 0x02, // Input (Data, Variable, Absolute), ;3 button bits 0x95, 0x01, // Report Count (1), 0x75, 0x05, // Report Size (5), 0x81, 0x01, // Input (Constant), ;5 bit padding 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, Variable, Relative), ;2 position bytes (X & Y) 0xC0, // End Collection, 0xC0, // End Collection /* 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 */ #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; print("usbFunctionDescriptor: "); phex(rq->bmRequestType); print(" "); phex(rq->bRequest); print(" "); phex16(rq->wValue.word); print(" "); phex16(rq->wIndex.word); print(" "); phex16(rq->wLength.word); print("\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; } print("desc len: "); phex(len); print("\n"); return len; }