summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Palatin <vpalatin@chromium.org>2014-06-16 13:44:11 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-06-19 03:28:43 +0000
commit17696e1470d152308ad39ac0ec1e61f82f4ff260 (patch)
tree0658d2d0e2832a8b9cb4a9519fd6dcf44f0150d8
parent94acd01e0c4e9cb9c31c6b6d332d24bb352d669c (diff)
downloadchrome-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.mk1
-rw-r--r--chip/stm32/usb_hid.c162
-rw-r--r--include/usb_hid.h45
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 */