diff options
Diffstat (limited to 'vusb')
-rw-r--r-- | vusb/host.c | 487 | ||||
-rw-r--r-- | vusb/host_vusb.h | 6 |
2 files changed, 493 insertions, 0 deletions
diff --git a/vusb/host.c b/vusb/host.c new file mode 100644 index 000000000..a32a1b17e --- /dev/null +++ b/vusb/host.c @@ -0,0 +1,487 @@ +#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, 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 + * + * 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; +} diff --git a/vusb/host_vusb.h b/vusb/host_vusb.h new file mode 100644 index 000000000..f09ad5822 --- /dev/null +++ b/vusb/host_vusb.h @@ -0,0 +1,6 @@ +#ifndef HOST_VUSB_H +#define HOST_VUSB_H + +void host_vusb_keyboard_send(void); + +#endif |