| /* Copyright (c) 2014 The Chromium OS Authors. All rights reserved. |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "clock.h" |
| #include "common.h" |
| #include "config.h" |
| #include "console.h" |
| #include "gpio.h" |
| #include "hooks.h" |
| #include "link_defs.h" |
| #include "registers.h" |
| #include "task.h" |
| #include "timer.h" |
| #include "util.h" |
| #include "usb_descriptor.h" |
| #include "usb_hid.h" |
| |
| /* Console output macro */ |
| #define CPRINTF(format, args...) cprintf(CC_USB, format, ## args) |
| |
| #define HID_REPORT_SIZE 8 |
| |
| /* HID descriptors */ |
| const struct usb_interface_descriptor USB_IFACE_DESC(USB_IFACE_HID) = { |
| .bLength = USB_DT_INTERFACE_SIZE, |
| .bDescriptorType = USB_DT_INTERFACE, |
| .bInterfaceNumber = USB_IFACE_HID, |
| .bAlternateSetting = 0, |
| .bNumEndpoints = 1, |
| .bInterfaceClass = USB_CLASS_HID, |
| .bInterfaceSubClass = USB_HID_SUBCLASS_BOOT, |
| .bInterfaceProtocol = USB_HID_PROTOCOL_KEYBOARD, |
| .iInterface = 0, |
| }; |
| const struct usb_endpoint_descriptor USB_EP_DESC(USB_IFACE_HID, 81) = { |
| .bLength = USB_DT_ENDPOINT_SIZE, |
| .bDescriptorType = USB_DT_ENDPOINT, |
| .bEndpointAddress = 0x80 | USB_EP_HID, |
| .bmAttributes = 0x03 /* Interrupt endpoint */, |
| .wMaxPacketSize = HID_REPORT_SIZE, |
| .bInterval = 40 /* ms polling interval */ |
| }; |
| const struct usb_hid_descriptor USB_CUSTOM_DESC(USB_IFACE_HID, hid) = { |
| .bLength = 9, |
| .bDescriptorType = USB_HID_DT_HID, |
| .bcdHID = 0x0100, |
| .bCountryCode = 0x00, /* Hardware target country */ |
| .bNumDescriptors = 1, |
| .desc = {{ |
| .bDescriptorType = USB_HID_DT_REPORT, |
| .wDescriptorLength = 45 |
| }} |
| }; |
| |
| /* HID : Report Descriptor */ |
| static const uint8_t report_desc[] = { |
| 0x05, 0x01, /* Usage Page (Generic Desktop) */ |
| 0x09, 0x06, /* Usage (Keyboard) */ |
| 0xA1, 0x01, /* Collection (Application) */ |
| 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) */ |
| 0x75, 0x01, /* Report Size (1) */ |
| 0x95, 0x08, /* Report Count (8) */ |
| 0x81, 0x02, /* Input (Data, Variable, Absolute), ;Modifier byte */ |
| |
| 0x95, 0x01, /* Report Count (1) */ |
| 0x75, 0x08, /* Report Size (8) */ |
| 0x81, 0x01, /* Input (Constant), ;Reserved byte */ |
| |
| 0x95, 0x06, /* Report Count (6) */ |
| 0x75, 0x08, /* Report Size (8) */ |
| 0x15, 0x00, /* Logical Minimum (0) */ |
| 0x25, 0x65, /* Logical Maximum(101) */ |
| 0x05, 0x07, /* Usage Page (Key Codes) */ |
| 0x19, 0x00, /* Usage Minimum (0) */ |
| 0x29, 0x65, /* Usage Maximum (101) */ |
| 0x81, 0x00, /* Input (Data, Array), ;Key arrays (6 bytes) */ |
| 0xC0, /* End Collection */ |
| 0x00 /* Padding */ |
| }; |
| |
| static usb_uint hid_ep_buf[HID_REPORT_SIZE / 2] __usb_ram; |
| |
| void set_keyboard_report(uint64_t rpt) |
| { |
| memcpy_to_usbram((void *) usb_sram_addr(hid_ep_buf), &rpt, sizeof(rpt)); |
| /* enable TX */ |
| STM32_TOGGLE_EP(USB_EP_HID, EP_TX_MASK, EP_TX_VALID, 0); |
| } |
| |
| static void hid_tx(void) |
| { |
| uint16_t ep = STM32_USB_EP(USB_EP_HID); |
| /* clear IT */ |
| STM32_USB_EP(USB_EP_HID) = (ep & EP_MASK); |
| return; |
| } |
| |
| static void hid_reset(void) |
| { |
| /* HID interrupt endpoint 1 */ |
| btable_ep[USB_EP_HID].tx_addr = usb_sram_addr(hid_ep_buf); |
| btable_ep[USB_EP_HID].tx_count = 8; |
| hid_ep_buf[0] = 0; |
| hid_ep_buf[1] = 0; |
| hid_ep_buf[2] = 0; |
| hid_ep_buf[3] = 0; |
| STM32_USB_EP(USB_EP_HID) = (USB_EP_HID << 0) /*Endpoint Address*/ | |
| (3 << 4) /* TX Valid */ | |
| (3 << 9) /* interrupt EP */ | |
| (0 << 12) /* RX Disabled */; |
| } |
| |
| USB_DECLARE_EP(USB_EP_HID, hid_tx, hid_tx, hid_reset); |
| |
| static int hid_iface_request(usb_uint *ep0_buf_rx, usb_uint *ep0_buf_tx) |
| { |
| if ((ep0_buf_rx[0] == (USB_DIR_IN | USB_RECIP_INTERFACE | |
| (USB_REQ_GET_DESCRIPTOR << 8))) && |
| (ep0_buf_rx[1] == (USB_HID_DT_REPORT << 8))) { |
| /* Setup : HID specific : Get Report descriptor */ |
| memcpy_to_usbram((void *) usb_sram_addr(ep0_buf_tx), |
| report_desc, |
| sizeof(report_desc)); |
| btable_ep[0].tx_count = MIN(ep0_buf_rx[3], |
| sizeof(report_desc)); |
| STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, |
| EP_STATUS_OUT); |
| CPRINTF("RPT %04x[l %04x]\n", STM32_USB_EP(0), |
| ep0_buf_rx[3]); |
| return 0; |
| } |
| |
| return 1; |
| } |
| USB_DECLARE_IFACE(USB_IFACE_HID, hid_iface_request) |
| |
| static int command_hid(int argc, char **argv) |
| { |
| uint8_t keycode = 0x0a; /* 'G' key */ |
| |
| if (argc >= 2) { |
| char *e; |
| keycode = strtoi(argv[1], &e, 16); |
| if (*e) |
| return EC_ERROR_PARAM1; |
| } |
| |
| /* press then release the key */ |
| set_keyboard_report((uint32_t)keycode << 16); |
| udelay(50000); |
| set_keyboard_report(0x000000); |
| |
| return EC_SUCCESS; |
| } |
| DECLARE_CONSOLE_COMMAND(hid, command_hid, |
| "[<HID keycode>]", |
| "test USB HID driver"); |