/* 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, "[]", "test USB HID driver");