summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Boichat <drinkcat@google.com>2017-05-17 18:15:15 +0800
committerchrome-bot <chrome-bot@chromium.org>2017-05-18 06:03:52 -0700
commit11237d5e911d769cac995e2e1ab9d16598542bc8 (patch)
tree1e679437f36debf7a67e74891bb7bd937049234b
parent0b077ad67173f11f8816b01213bc09f622326799 (diff)
downloadchrome-ec-11237d5e911d769cac995e2e1ab9d16598542bc8.tar.gz
hammer: Make keyboard work at firmware screen
First, libpayload expects the keyboard interface index to be 0. Then, hid_iface_request needs to reply to USB_HID_DT_HID request with the content of struct usb_hid_descriptor. With current code, the variable name is generated (and therefore hard to guess), so we create a new set of macros so that we can use a specific variable name. Also, add support for HID Get_Protocol and Set_Protocol, as they are compulsory for devices supporting boot protocol, even though those are mostly no-op for now. Finally, add a note regarding USB HID keyboard boot protocol, to make sure that we do not accidentally change the report format. BRANCH=none BUG=b:36538963 TEST=Keyboard works in FW screen, both trackpad and keyboard still work when AP has booted. TEST=hammer/staff can still be updated (both RO from RW, and RW from RO) Change-Id: Ibea4888385909c9ce3b430464e5805c039d4b9ed Reviewed-on: https://chromium-review.googlesource.com/505796 Commit-Ready: Nicolas Boichat <drinkcat@chromium.org> Tested-by: Nicolas Boichat <drinkcat@chromium.org> Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--board/hammer/board.h5
-rw-r--r--chip/stm32/usb_hid.c49
-rw-r--r--chip/stm32/usb_hid_hw.h3
-rw-r--r--chip/stm32/usb_hid_keyboard.c52
-rw-r--r--chip/stm32/usb_hid_touchpad.c6
-rw-r--r--include/usb_descriptor.h5
6 files changed, 92 insertions, 28 deletions
diff --git a/board/hammer/board.h b/board/hammer/board.h
index b7d2b57f89..5f094e03f7 100644
--- a/board/hammer/board.h
+++ b/board/hammer/board.h
@@ -101,13 +101,14 @@
#define DEFAULT_SERIALNO "Uninitialized"
/* USB interface indexes (use define rather than enum to expand them) */
-#define USB_IFACE_UPDATE 0
#ifdef SECTION_IS_RW
-#define USB_IFACE_HID_KEYBOARD 1
+#define USB_IFACE_HID_KEYBOARD 0
+#define USB_IFACE_UPDATE 1
#define USB_IFACE_HID_TOUCHPAD 2
#define USB_IFACE_I2C 3
#define USB_IFACE_COUNT 4
#else
+#define USB_IFACE_UPDATE 0
#define USB_IFACE_COUNT 1
#endif
diff --git a/chip/stm32/usb_hid.c b/chip/stm32/usb_hid.c
index 5561c8afad..4a89d9573c 100644
--- a/chip/stm32/usb_hid.c
+++ b/chip/stm32/usb_hid.c
@@ -17,6 +17,7 @@
#include "usb_descriptor.h"
#include "usb_hw.h"
#include "usb_hid.h"
+#include "usb_hid_hw.h"
/* Console output macro */
#define CPRINTF(format, args...) cprintf(CC_USB, format, ## args)
@@ -49,7 +50,8 @@ static int report_left;
static const uint8_t *report_ptr;
int hid_iface_request(usb_uint *ep0_buf_rx, usb_uint *ep0_buf_tx,
- const uint8_t *report_desc, int report_size)
+ const uint8_t *report_desc, int report_size,
+ const struct usb_hid_descriptor *hid_desc)
{
if (!ep0_buf_rx) {
/*
@@ -68,26 +70,35 @@ int hid_iface_request(usb_uint *ep0_buf_rx, usb_uint *ep0_buf_tx,
STM32_TOGGLE_EP(0, EP_TX_MASK, EP_TX_VALID,
report_left ? 0 : EP_STATUS_OUT);
return report_left ? 1 : 0;
- } else 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 */
- report_size = MIN(ep0_buf_rx[3], report_size);
+ } else if (ep0_buf_rx[0] == (USB_DIR_IN | USB_RECIP_INTERFACE |
+ (USB_REQ_GET_DESCRIPTOR << 8))) {
+ if (ep0_buf_rx[1] == (USB_HID_DT_REPORT << 8)) {
+ /* Setup : HID specific : Get Report descriptor */
+ report_size = MIN(ep0_buf_rx[3], report_size);
- if (report_size > USB_MAX_PACKET_SIZE) {
- /* Report descriptor does not fit in one packet. */
- report_left = report_size - USB_MAX_PACKET_SIZE;
- report_ptr = report_desc + USB_MAX_PACKET_SIZE;
- report_size = USB_MAX_PACKET_SIZE;
- } else {
- report_left = 0;
+ if (report_size > USB_MAX_PACKET_SIZE) {
+ /* Report descriptor doesn't fit in 1 packet. */
+ report_left = report_size - USB_MAX_PACKET_SIZE;
+ report_ptr = report_desc + USB_MAX_PACKET_SIZE;
+ report_size = USB_MAX_PACKET_SIZE;
+ } else {
+ report_left = 0;
+ }
+ memcpy_to_usbram((void *) usb_sram_addr(ep0_buf_tx),
+ report_desc, report_size);
+ btable_ep[0].tx_count = report_size;
+ STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID,
+ report_left ? 0 : EP_STATUS_OUT);
+ return report_left ? 1 : 0;
+ } else if (ep0_buf_rx[1] == (USB_HID_DT_HID << 8)) {
+ /* Setup : HID specific : Get HID descriptor */
+ memcpy_to_usbram((void *) usb_sram_addr(ep0_buf_tx),
+ hid_desc, sizeof(*hid_desc));
+ btable_ep[0].tx_count = sizeof(*hid_desc);
+ STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID,
+ EP_STATUS_OUT);
+ return 0;
}
- memcpy_to_usbram((void *) usb_sram_addr(ep0_buf_tx),
- report_desc, report_size);
- btable_ep[0].tx_count = report_size;
- STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID,
- report_left ? 0 : EP_STATUS_OUT);
- return report_left ? 1 : 0;
}
return -1;
diff --git a/chip/stm32/usb_hid_hw.h b/chip/stm32/usb_hid_hw.h
index 083bfbfeaa..6e53559bd0 100644
--- a/chip/stm32/usb_hid_hw.h
+++ b/chip/stm32/usb_hid_hw.h
@@ -12,6 +12,7 @@
void hid_tx(int ep);
void hid_reset(int ep, usb_uint *hid_ep_buf, int len);
int hid_iface_request(usb_uint *ep0_buf_rx, usb_uint *ep0_buf_tx,
- const uint8_t *report_desc, int report_size);
+ const uint8_t *report_desc, int report_size,
+ const struct usb_hid_descriptor *hid_desc);
#endif
diff --git a/chip/stm32/usb_hid_keyboard.c b/chip/stm32/usb_hid_keyboard.c
index da3c215050..4147fcad1c 100644
--- a/chip/stm32/usb_hid_keyboard.c
+++ b/chip/stm32/usb_hid_keyboard.c
@@ -26,6 +26,22 @@
/* Console output macro */
#define CPRINTF(format, args...) cprintf(CC_USB, format, ## args)
+enum hid_protocol {
+ HID_BOOT_PROTOCOL = 0,
+ HID_REPORT_PROTOCOL = 1,
+ HID_PROTOCOL_COUNT = 2,
+};
+
+/* Current protocol, behaviour is identical in both modes. */
+static enum hid_protocol protocol = HID_REPORT_PROTOCOL;
+
+/*
+ * Note: This report format cannot be changed without breaking HID Boot protocol
+ * compatibility (see HID 1.11 "Appendix B: Boot Interface Descriptors").
+ *
+ * If this needs to be extended, we need to use this report in boot protocol
+ * mode, and an alternate one in report protocol mode.
+ */
struct __attribute__((__packed__)) usb_hid_keyboard_report {
uint8_t modifiers; /* bitmap of modifiers 224-231 */
uint8_t reserved; /* 0x0 */
@@ -115,7 +131,9 @@ static const uint8_t report_desc[] = {
0xC0 /* End Collection */
};
-const struct usb_hid_descriptor USB_CUSTOM_DESC(USB_IFACE_HID_KEYBOARD, hid) = {
+/* HID: HID Descriptor */
+const struct usb_hid_descriptor USB_CUSTOM_DESC_VAR(USB_IFACE_HID_KEYBOARD,
+ hid, hid_desc_kb) = {
.bLength = 9,
.bDescriptorType = USB_HID_DT_HID,
.bcdHID = 0x0100,
@@ -199,8 +217,36 @@ USB_DECLARE_EP(USB_EP_HID_KEYBOARD, hid_keyboard_tx, hid_keyboard_tx,
static int hid_keyboard_iface_request(usb_uint *ep0_buf_rx,
usb_uint *ep0_buf_tx)
{
- return hid_iface_request(ep0_buf_rx, ep0_buf_tx,
- report_desc, sizeof(report_desc));
+ int ret = hid_iface_request(ep0_buf_rx, ep0_buf_tx,
+ report_desc, sizeof(report_desc),
+ &hid_desc_kb);
+ if (ret >= 0)
+ return ret;
+
+ if (ep0_buf_rx[0] == (USB_DIR_OUT | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE | (USB_HID_REQ_SET_PROTOCOL << 8))) {
+ uint16_t value = ep0_buf_rx[1];
+
+ if (value >= HID_PROTOCOL_COUNT)
+ return -1;
+
+ protocol = value;
+
+ btable_ep[0].tx_count = 0;
+ STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, 0);
+ return 0;
+ } else if (ep0_buf_rx[0] == (USB_DIR_IN | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE | (USB_HID_REQ_GET_PROTOCOL << 8))) {
+ uint8_t value = protocol;
+
+ memcpy_to_usbram((void *) usb_sram_addr(ep0_buf_tx),
+ &value, sizeof(value));
+ btable_ep[0].tx_count = 1;
+ STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, 0);
+ return 0;
+ }
+
+ return -1;
}
USB_DECLARE_IFACE(USB_IFACE_HID_KEYBOARD, hid_keyboard_iface_request)
diff --git a/chip/stm32/usb_hid_touchpad.c b/chip/stm32/usb_hid_touchpad.c
index 8f2d2c4dad..686abdcda3 100644
--- a/chip/stm32/usb_hid_touchpad.c
+++ b/chip/stm32/usb_hid_touchpad.c
@@ -250,7 +250,8 @@ static const uint8_t report_desc[] = {
0xC0, /* End Collection */
};
-const struct usb_hid_descriptor USB_CUSTOM_DESC(USB_IFACE_HID_TOUCHPAD, hid) = {
+const struct usb_hid_descriptor USB_CUSTOM_DESC_VAR(USB_IFACE_HID_TOUCHPAD,
+ hid, hid_desc_tp) = {
.bLength = 9,
.bDescriptorType = USB_HID_DT_HID,
.bcdHID = 0x0100,
@@ -309,6 +310,7 @@ static int hid_touchpad_iface_request(usb_uint *ep0_buf_rx,
usb_uint *ep0_buf_tx)
{
return hid_iface_request(ep0_buf_rx, ep0_buf_tx,
- report_desc, sizeof(report_desc));
+ report_desc, sizeof(report_desc),
+ &hid_desc_tp);
}
USB_DECLARE_IFACE(USB_IFACE_HID_TOUCHPAD, hid_touchpad_iface_request)
diff --git a/include/usb_descriptor.h b/include/usb_descriptor.h
index 1343e0d777..c6e877aac6 100644
--- a/include/usb_descriptor.h
+++ b/include/usb_descriptor.h
@@ -275,9 +275,12 @@ extern struct usb_string_desc *usb_serialno_desc;
#endif
/* Use these macros for declaring descriptors, to order them properly */
-#define USB_CONF_DESC(name) CONCAT2(usb_desc_, name) \
+#define USB_CONF_DESC_VAR(name, varname) varname \
__attribute__((section(".rodata.usb_desc_" STRINGIFY(name))))
+#define USB_CONF_DESC(name) USB_CONF_DESC_VAR(name, CONCAT2(usb_desc_, name))
#define USB_IFACE_DESC(num) USB_CONF_DESC(CONCAT3(iface, num, _0iface))
+#define USB_CUSTOM_DESC_VAR(i, name, varname) \
+ USB_CONF_DESC_VAR(CONCAT4(iface, i, _1, name), varname)
#define USB_CUSTOM_DESC(i, name) USB_CONF_DESC(CONCAT4(iface, i, _1, name))
#define USB_EP_DESC(i, num) USB_CONF_DESC(CONCAT4(iface, i, _2ep, num))