diff options
author | Vincent Palatin <vpalatin@chromium.org> | 2017-09-12 15:47:31 +0200 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-09-22 10:18:50 -0700 |
commit | 77f011206c87a7a3e8cd93d3635c6c4f0ea3e32d (patch) | |
tree | 75d281c3355aa9c1918e29c31a63037d81768add | |
parent | e3333972d5bcf110fd2c51de92097a546694d0a1 (diff) | |
download | chrome-ec-77f011206c87a7a3e8cd93d3635c6c4f0ea3e32d.tar.gz |
Add WebUSB descriptor support
The WebUSB specification defines a specific Platform Descriptor in the
Binary Object Store:
https://wicg.github.io/webusb/#webusb-platform-capability-descriptor
This descriptor provides a special 'Landing page' URL to the host
browser and associated privileges for it.
Bump the USB version for BOS descriptors to 2.1 to be compatible with
Chrome implementation.
Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
BUG=none
BRANCH=twinkie
TEST=manual: on Twinkie (chip/stm32) and HG proto2 (chip/g), enumerate
WebUSB descriptors with lsusb and connect to a WebUSB page in Chrome
R61+.
Change-Id: I7211ab554f4a6c156c1e8e79a3d9f0d6644217c6
Reviewed-on: https://chromium-review.googlesource.com/664813
Commit-Ready: Vincent Palatin <vpalatin@chromium.org>
Tested-by: Vincent Palatin <vpalatin@chromium.org>
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r-- | chip/g/usb.c | 18 | ||||
-rw-r--r-- | chip/stm32/usb.c | 59 | ||||
-rw-r--r-- | common/build.mk | 1 | ||||
-rw-r--r-- | common/webusb_desc.c | 46 | ||||
-rw-r--r-- | include/config.h | 12 | ||||
-rw-r--r-- | include/usb_descriptor.h | 48 |
6 files changed, 163 insertions, 21 deletions
diff --git a/chip/g/usb.c b/chip/g/usb.c index 532128dc24..37fef3179d 100644 --- a/chip/g/usb.c +++ b/chip/g/usb.c @@ -184,8 +184,8 @@ static void showregs(void) /* Standard USB stuff */ #ifdef CONFIG_USB_BOS -/* v2.01 (vs 2.00) BOS Descriptor provided */ -#define USB_DEV_BCDUSB 0x0201 +/* v2.10 (vs 2.00) BOS Descriptor provided */ +#define USB_DEV_BCDUSB 0x0210 #else #define USB_DEV_BCDUSB 0x0200 #endif @@ -818,6 +818,20 @@ static void handle_setup(enum table_case tc) print_later(" iface returned %d", bytes, 0, 0, 0, 0); } } else { +#ifdef CONFIG_WEBUSB_URL + if (data_phase_in && + ((req->bmRequestType & USB_TYPE_MASK) == USB_TYPE_VENDOR)) { + if (req->bRequest == 0x01 && + req->wIndex == WEBUSB_REQ_GET_URL) { + bytes = *(uint8_t *)webusb_url; + bytes = MIN(req->wLength, bytes); + if (load_in_fifo(webusb_url, bytes) < 0) + bytes = -1; + } else { + report_error(-1); + } + } else +#endif /* Something we need to add support for? */ report_error(-1); } diff --git a/chip/stm32/usb.c b/chip/stm32/usb.c index 26890cadff..c1f39b598d 100644 --- a/chip/stm32/usb.c +++ b/chip/stm32/usb.c @@ -119,6 +119,29 @@ void usb_read_setup_packet(usb_uint *buffer, struct usb_setup_packet *packet) packet->wLength = buffer[3]; } +static void ep0_send_descriptor(const uint8_t *desc, int len, + uint16_t fixup_size) +{ + /* do not send more than what the host asked for */ + len = MIN(ep0_buf_rx[3], len); + /* + * if we cannot transmit everything at once, + * keep the remainder for the next IN packet + */ + if (len >= USB_MAX_PACKET_SIZE) { + desc_left = len - USB_MAX_PACKET_SIZE; + desc_ptr = desc + USB_MAX_PACKET_SIZE; + len = USB_MAX_PACKET_SIZE; + } + memcpy_to_usbram(EP0_BUF_TX_SRAM_ADDR, desc, len); + if (fixup_size) /* set the real descriptor size */ + ep0_buf_tx[1] = fixup_size; + btable_ep[0].tx_count = len; + /* send the null OUT transaction if the transfer is complete */ + STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, + desc_left ? 0 : EP_STATUS_OUT); +} + /* Requests on the control endpoint (aka EP0) */ static void ep0_rx(void) { @@ -142,6 +165,21 @@ static void ep0_rx(void) return; } } + /* vendor specific request */ + if ((req & USB_TYPE_MASK) == USB_TYPE_VENDOR) { +#ifdef CONFIG_WEBUSB_URL + uint8_t b_req = req >> 8; /* bRequest in the transfer */ + uint16_t idx = ep0_buf_rx[2]; /* wIndex in the transfer */ + + if (b_req == 0x01 && idx == WEBUSB_REQ_GET_URL) { + int len = *(uint8_t *)webusb_url; + + ep0_send_descriptor(webusb_url, len, 0); + return; + } +#endif + goto unknown_req; + } /* TODO check setup bit ? */ if (req == (USB_DIR_IN | (USB_REQ_GET_DESCRIPTOR << 8))) { @@ -183,25 +221,8 @@ static void ep0_rx(void) default: /* unhandled descriptor */ goto unknown_req; } - /* do not send more than what the host asked for */ - len = MIN(ep0_buf_rx[3], len); - /* - * if we cannot transmit everything at once, - * keep the remainder for the next IN packet - */ - if (len >= USB_MAX_PACKET_SIZE) { - desc_left = len - USB_MAX_PACKET_SIZE; - desc_ptr = desc + USB_MAX_PACKET_SIZE; - len = USB_MAX_PACKET_SIZE; - } - memcpy_to_usbram(EP0_BUF_TX_SRAM_ADDR, desc, len); - if (type == USB_DT_CONFIGURATION) - /* set the real descriptor size */ - ep0_buf_tx[1] = USB_DESC_SIZE; - btable_ep[0].tx_count = len; - STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, - desc_left ? 0 : EP_STATUS_OUT); - /* send the null OUT transaction if the transfer is complete */ + ep0_send_descriptor(desc, len, type == USB_DT_CONFIGURATION ? + USB_DESC_SIZE : 0); } else if (req == (USB_DIR_IN | (USB_REQ_GET_STATUS << 8))) { uint16_t data = 0; /* Get status */ diff --git a/common/build.mk b/common/build.mk index f775fee0da..7f73c885fa 100644 --- a/common/build.mk +++ b/common/build.mk @@ -120,6 +120,7 @@ common-$(CONFIG_USB_UPDATE)+=usb_update.o update_fw.o common-$(CONFIG_VBOOT_EFS)+=vboot/vboot.o common-$(CONFIG_VBOOT_HASH)+=sha256.o vboot_hash.o common-$(CONFIG_VSTORE)+=vstore.o +common-$(CONFIG_WEBUSB_URL)+=webusb_desc.o common-$(CONFIG_WIRELESS)+=wireless.o common-$(HAS_TASK_CHIPSET)+=chipset.o common-$(HAS_TASK_CONSOLE)+=console.o console_output.o uart_buffering.o diff --git a/common/webusb_desc.c b/common/webusb_desc.c new file mode 100644 index 0000000000..41d39006e0 --- /dev/null +++ b/common/webusb_desc.c @@ -0,0 +1,46 @@ +/* Copyright 2017 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. + */ +/* WebUSB platform descriptor */ + +#include "common.h" +#include "usb_descriptor.h" +#include "util.h" + +#ifndef CONFIG_USB_BOS +#error "CONFIG_USB_BOS must be defined to use WebUSB descriptor" +#endif + +const void *webusb_url = USB_URL_DESC(HTTPS, CONFIG_WEBUSB_URL); + +/* + * Platform Descriptor in the device Binary Object Store + * as defined by USB 3.1 spec chapter 9.6.2. + */ +static struct { + struct usb_bos_hdr_descriptor bos; + struct usb_platform_descriptor platform; +} bos_desc = { + .bos = { + .bLength = USB_DT_BOS_SIZE, + .bDescriptorType = USB_DT_BOS, + .wTotalLength = (USB_DT_BOS_SIZE + USB_DT_PLATFORM_SIZE), + .bNumDeviceCaps = 1, /* platform caps */ + }, + .platform = { + .bLength = USB_DT_PLATFORM_SIZE, + .bDescriptorType = USB_DT_DEVICE_CAPABILITY, + .bDevCapabilityType = USB_DC_DTYPE_PLATFORM, + .bReserved = 0, + .PlatformCapUUID = USB_PLAT_CAP_WEBUSB, + .bcdVersion = 0x0100, + .bVendorCode = 0x01, + .iLandingPage = 1, + }, +}; + +const struct bos_context bos_ctx = { + .descp = (void *)&bos_desc, + .size = sizeof(bos_desc), +}; diff --git a/include/config.h b/include/config.h index 2d44770823..fbcb69604a 100644 --- a/include/config.h +++ b/include/config.h @@ -2888,6 +2888,18 @@ #define CONFIG_AUX_TIMER_PERIOD_MS (CONFIG_WATCHDOG_PERIOD_MS - 500) /*****************************************************************************/ +/* WebUSB config */ + +/* + * Enable the WebUSB support and define its URL. + * Export a WebUSB Platform Descriptor in the Binary Object Store descriptor. + * The WebUSB landing page URL is equal to 'CONFIG_WEBUSB_URL' plus the + * https:// prefix. + * This requires CONFIG_USB_BOS. + */ +#undef CONFIG_WEBUSB_URL + +/*****************************************************************************/ /* * Support controlling power to WiFi, WWAN (3G/LTE), and/or bluetooth modules. diff --git a/include/usb_descriptor.h b/include/usb_descriptor.h index 7f03b1883a..a0e9d843cc 100644 --- a/include/usb_descriptor.h +++ b/include/usb_descriptor.h @@ -86,6 +86,24 @@ struct usb_contid_caps_descriptor { #define USB_DC_DTYPE_BILLBOARD 0x0d /* RESERVED 0x00, 0xOe - 0xff */ +/* Platform descriptor */ +struct usb_platform_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; /* USB_DT_DEVICE_CAPABILITY */ + uint8_t bDevCapabilityType; /* USB_DC_DTYPE_PLATFORM */ + uint8_t bReserved; /* SBZ */ + uint8_t PlatformCapUUID[16]; /* USB_PLAT_CAP_xxx */ + uint16_t bcdVersion; /* 0x0100 */ + uint8_t bVendorCode; + uint8_t iLandingPage; +} __packed; +#define USB_DT_PLATFORM_SIZE 24 + +/* Platform Capability UUIDs */ +#define USB_PLAT_CAP_WEBUSB /*{3408b638-09a9-47a0-8bfd-a0768815b665}*/ \ + {0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, \ + 0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65} + /* Qualifier Descriptor */ struct usb_qualifier_descriptor { uint8_t bLength; @@ -227,6 +245,35 @@ struct usb_endpoint_descriptor { #define USB_REQ_SET_INTERFACE 0x0B #define USB_REQ_SYNCH_FRAME 0x0C +/* WebUSB URL descriptors */ +#define WEBUSB_REQ_GET_URL 0x02 +#define USB_DT_WEBUSB_URL 0x03 + +#define USB_URL_SCHEME_HTTP 0x00 +#define USB_URL_SCHEME_HTTPS 0x01 +#define USB_URL_SCHEME_NONE 0xff + +/* + * URL descriptor helper. + * (similar to string descriptor but UTF-8 instead of UTF-16) + */ +#define USB_URL_DESC(scheme, str) \ + (const void *)&(const struct { \ + uint8_t _len; \ + uint8_t _type; \ + uint8_t _scheme; \ + char _data[sizeof(str)]; \ + }) { \ + /* Total size of the descriptor is : \ + * size of the UTF-8 text plus the len/type fields \ + * minus the string 0-termination \ + */ \ + sizeof(str) + 3 - 1, \ + USB_DT_WEBUSB_URL, \ + USB_URL_SCHEME_##scheme, \ + str \ + } + /* Setup Packet */ struct usb_setup_packet { uint8_t bmRequestType; @@ -294,5 +341,6 @@ extern const uint8_t usb_string_desc[]; /* USB string descriptor with the firmware version */ extern const void * const usb_fw_version; extern const struct bos_context bos_ctx; +extern const void *webusb_url; #endif /* __CROS_EC_USB_DESCRIPTOR_H */ |