diff options
author | Vincent Palatin <vpalatin@chromium.org> | 2014-06-16 13:44:11 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-06-19 03:28:43 +0000 |
commit | 17696e1470d152308ad39ac0ec1e61f82f4ff260 (patch) | |
tree | 0658d2d0e2832a8b9cb4a9519fd6dcf44f0150d8 | |
parent | 94acd01e0c4e9cb9c31c6b6d332d24bb352d669c (diff) | |
download | chrome-ec-17696e1470d152308ad39ac0ec1e61f82f4ff260.tar.gz |
usb: add USB HID driver
Add a USB HID endpoint providing a keyboard interface.
Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
BRANCH=none
BUG=none
TEST=build for the Reston keyboard and press keys on the matrix.
Change-Id: I3f4cc55acdd33286f0638dabaa9050c37698404f
Reviewed-on: https://chromium-review.googlesource.com/204166
Reviewed-by: Vic Yang <victoryang@chromium.org>
Tested-by: Vincent Palatin <vpalatin@chromium.org>
Commit-Queue: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r-- | chip/stm32/build.mk | 1 | ||||
-rw-r--r-- | chip/stm32/usb_hid.c | 162 | ||||
-rw-r--r-- | include/usb_hid.h | 45 |
3 files changed, 208 insertions, 0 deletions
diff --git a/chip/stm32/build.mk b/chip/stm32/build.mk index f420fed742..7278785f53 100644 --- a/chip/stm32/build.mk +++ b/chip/stm32/build.mk @@ -38,4 +38,5 @@ chip-$(CONFIG_FLASH)+=flash-$(FLASH_FAMILY).o chip-$(CONFIG_ADC)+=adc-$(CHIP_FAMILY).o chip-$(CONFIG_PWM)+=pwm.o chip-$(CONFIG_USB)+=usb.o usb_endpoints.o +chip-$(CONFIG_USB_HID)+=usb_hid.o chip-$(CONFIG_USB_POWER_DELIVERY)+=usb_pd_phy.o diff --git a/chip/stm32/usb_hid.c b/chip/stm32/usb_hid.c new file mode 100644 index 0000000000..347140f9ac --- /dev/null +++ b/chip/stm32/usb_hid.c @@ -0,0 +1,162 @@ +/* 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.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_usbram(hid_ep_buf, (const uint8_t *)&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 void 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_usbram(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]); + } else { + STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_RX_VALID | EP_TX_STALL, 0); + } +} +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", + NULL); diff --git a/include/usb_hid.h b/include/usb_hid.h new file mode 100644 index 0000000000..89ec887342 --- /dev/null +++ b/include/usb_hid.h @@ -0,0 +1,45 @@ +/* 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. + * + * USB HID definitions. + */ + +#ifndef USB_HID_H +#define USB_HID_H + +#define USB_HID_SUBCLASS_BOOT 1 +#define USB_HID_PROTOCOL_KEYBOARD 1 +#define USB_HID_PROTOCOL_MOUSE 2 + +/* USB HID Class requests */ +#define USB_HID_REQ_GET_REPORT 0x01 +#define USB_HID_REQ_GET_IDLE 0x02 +#define USB_HID_REQ_GET_PROTOCOL 0x03 +#define USB_HID_REQ_SET_REPORT 0x09 +#define USB_HID_REQ_SET_IDLE 0x0A +#define USB_HID_REQ_SET_PROTOCOL 0x0B + +/* USB HID class descriptor types */ +#define USB_HID_DT_HID (USB_TYPE_CLASS | 0x01) +#define USB_HID_DT_REPORT (USB_TYPE_CLASS | 0x02) +#define USB_HID_DT_PHYSICAL (USB_TYPE_CLASS | 0x03) + +struct usb_hid_class_descriptor { + uint8_t bDescriptorType; + uint16_t wDescriptorLength; +} __packed; + +struct usb_hid_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdHID; + uint8_t bCountryCode; + uint8_t bNumDescriptors; + struct usb_hid_class_descriptor desc[1]; +} __packed; + +/* class implementation interfaces */ +void set_keyboard_report(uint64_t rpt); + +#endif /* USB_H */ |