summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Palatin <vpalatin@chromium.org>2014-10-09 16:57:13 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-11-11 22:58:39 +0000
commit3df9de1e945b2ce6f6539fbd945c2e99a49e1bd8 (patch)
tree604349348b8728d178e591bb03a491f0e0406c7d
parent30bb3a8b028e8033c5d80264a7e075f064e6ae8a (diff)
downloadchrome-ec-3df9de1e945b2ce6f6539fbd945c2e99a49e1bd8.tar.gz
CHERRY-PICK: usb: allow reading descriptors larger than 64 bytes
When a control transfer requests a descriptor larger than 64 bytes, we need to do several IN transfers to get the proper packet sequence : SETUP IN IN IN .. IN OUT(null) Signed-off-by: Vincent Palatin <vpalatin@chromium.org> BRANCH=samus BUG=chrome-os-partner:32652 TEST=set USB_STR_VERSION to "012345678901234567890123456789ABCDEF", then do "lsusb -v" on the host and check the USB transfers with the protocol analyzer. Change-Id: I5ddeede41bd39acf3619a620c7046c9fcad5bc7a Original-Change-Id: I6940095008cb2a34c6896b337c5eda4fa267adc1 Reviewed-on: https://chromium-review.googlesource.com/222700 Tested-by: Vincent Palatin <vpalatin@chromium.org> Reviewed-by: Todd Broch <tbroch@chromium.org> Commit-Queue: Vincent Palatin <vpalatin@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/229151 Reviewed-by: Mohammed Habibulla <moch@chromium.org> Commit-Queue: Mohammed Habibulla <moch@chromium.org> Tested-by: Mohammed Habibulla <moch@chromium.org>
-rw-r--r--chip/stm32/usb.c79
1 files changed, 50 insertions, 29 deletions
diff --git a/chip/stm32/usb.c b/chip/stm32/usb.c
index 1dfb24e0ff..d4ad8e48ea 100644
--- a/chip/stm32/usb.c
+++ b/chip/stm32/usb.c
@@ -74,12 +74,19 @@ static usb_uint ep0_buf_tx[USB_MAX_PACKET_SIZE / 2] __usb_ram;
static usb_uint ep0_buf_rx[USB_MAX_PACKET_SIZE / 2] __usb_ram;
static int set_addr;
+/* remaining size of descriptor data to transfer */
+static int desc_left;
+/* pointer to descriptor data if any */
+static const uint8_t *desc_ptr;
/* Requests on the control endpoint (aka EP0) */
static void ep0_rx(void)
{
uint16_t req = ep0_buf_rx[0]; /* bRequestType | bRequest */
+ /* reset any incomplete descriptor transfer */
+ desc_ptr = NULL;
+
/* interface specific requests */
if ((req & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {
uint8_t iface = ep0_buf_rx[2] & 0xff;
@@ -92,26 +99,17 @@ static void ep0_rx(void)
if (req == (USB_DIR_IN | (USB_REQ_GET_DESCRIPTOR << 8))) {
uint8_t type = ep0_buf_rx[1] >> 8;
uint8_t idx = ep0_buf_rx[1] & 0xff;
- const uint8_t *str_desc;
+ const uint8_t *desc;
+ int len;
switch (type) {
case USB_DT_DEVICE: /* Setup : Get device descriptor */
- memcpy_usbram(ep0_buf_tx, (void *)&dev_desc,
- sizeof(dev_desc));
- btable_ep[0].tx_count = MIN(ep0_buf_rx[3],
- sizeof(dev_desc));
- STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID,
- EP_STATUS_OUT /*null OUT transaction */);
+ desc = (void *)&dev_desc;
+ len = sizeof(dev_desc);
break;
case USB_DT_CONFIGURATION: /* Setup : Get configuration desc */
- memcpy_usbram(ep0_buf_tx, __usb_desc,
- USB_DESC_SIZE);
- /* set the real descriptor size */
- ep0_buf_tx[1] = USB_DESC_SIZE;
- btable_ep[0].tx_count = MIN(ep0_buf_rx[3],
- USB_DESC_SIZE);
- STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID,
- EP_STATUS_OUT /*null OUT transaction */);
+ desc = __usb_desc;
+ len = USB_DESC_SIZE;
break;
#ifdef CONFIG_USB_BOS
case USB_DT_BOS: /* Setup : Get BOS descriptor */
@@ -120,26 +118,38 @@ static void ep0_rx(void)
break;
#endif
case USB_DT_STRING: /* Setup : Get string descriptor */
- if (idx >= USB_STR_COUNT) {
+ if (idx >= USB_STR_COUNT)
/* The string does not exist : STALL */
- STM32_TOGGLE_EP(0, EP_TX_RX_MASK,
- EP_RX_VALID | EP_TX_STALL, 0);
- return; /* don't remove the STALL */
- }
- str_desc = usb_strings[idx];
- memcpy_usbram(ep0_buf_tx, str_desc, str_desc[0]);
- btable_ep[0].tx_count = MIN(ep0_buf_rx[3], str_desc[0]);
- STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID,
- EP_STATUS_OUT /*null OUT transaction */);
+ goto unknown_req;
+
+ desc = usb_strings[idx];
+ len = desc[0];
break;
case USB_DT_DEVICE_QUALIFIER: /* Get device qualifier desc */
/* Not high speed : STALL next IN used as handshake */
- STM32_TOGGLE_EP(0, EP_TX_RX_MASK,
- EP_RX_VALID | EP_TX_STALL, 0);
- break;
+ goto unknown_req;
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_usbram(ep0_buf_tx, 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 */
} else if (req == (USB_DIR_IN | (USB_REQ_GET_STATUS << 8))) {
uint16_t zero = 0;
/* Get status */
@@ -182,7 +192,18 @@ static void ep0_tx(void)
set_addr = 0;
CPRINTF("SETAD %02x\n", STM32_USB_DADDR);
}
-
+ if (desc_ptr) {
+ /* we have an on-going descriptor transfer */
+ int len = MIN(desc_left, USB_MAX_PACKET_SIZE);
+ memcpy_usbram(ep0_buf_tx, desc_ptr, len);
+ btable_ep[0].tx_count = len;
+ desc_left -= len;
+ desc_ptr += len;
+ STM32_TOGGLE_EP(0, EP_TX_MASK, EP_TX_VALID,
+ desc_left ? 0 : EP_STATUS_OUT);
+ /* send the null OUT transaction if the transfer is complete */
+ return;
+ }
STM32_TOGGLE_EP(0, EP_TX_MASK, EP_TX_VALID, 0);
}