Roothub requests are now decoded in one place. Signed-off-by: Jules Maselbas <jmaselbas@xxxxxxxxx> --- drivers/usb/dwc2/dwc2.h | 2 +- drivers/usb/dwc2/host.c | 4 +- drivers/usb/dwc2/rhub.c | 519 +++++++++++++++++++--------------------- 3 files changed, 245 insertions(+), 280 deletions(-) diff --git a/drivers/usb/dwc2/dwc2.h b/drivers/usb/dwc2/dwc2.h index 60cdca520..35ba00660 100644 --- a/drivers/usb/dwc2/dwc2.h +++ b/drivers/usb/dwc2/dwc2.h @@ -36,7 +36,7 @@ int dwc2_submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len, int interval); int dwc2_host_init(struct usb_host *host); -int dwc2_submit_rh_msg(struct dwc2 *dwc2, struct usb_device *dev, +int dwc2_submit_roothub(struct dwc2 *dwc2, struct usb_device *dev, unsigned long pipe, void *buf, int len, struct devrequest *setup); diff --git a/drivers/usb/dwc2/host.c b/drivers/usb/dwc2/host.c index d66c70fbc..61c29910e 100644 --- a/drivers/usb/dwc2/host.c +++ b/drivers/usb/dwc2/host.c @@ -326,9 +326,9 @@ int dwc2_submit_control_msg(struct usb_device *udev, int status_direction; if (devnum == dwc2->root_hub_devnum) { - udev->status = 0; udev->speed = USB_SPEED_HIGH; - return dwc2_submit_rh_msg(dwc2, udev, pipe, buffer, len, setup); + ret = dwc2_submit_roothub(dwc2, udev, pipe, buffer, len, setup); + return ret; } /* SETUP stage */ diff --git a/drivers/usb/dwc2/rhub.c b/drivers/usb/dwc2/rhub.c index 86552da99..cc733f34e 100644 --- a/drivers/usb/dwc2/rhub.c +++ b/drivers/usb/dwc2/rhub.c @@ -7,7 +7,7 @@ static struct descriptor { struct usb_config_descriptor config; struct usb_interface_descriptor interface; struct usb_endpoint_descriptor endpoint; -} __attribute__ ((packed)) descriptor = { +} __packed descriptor = { .hub = { .bLength = USB_DT_HUB_NONVAR_SIZE + ((USB_MAXCHILDREN + 1 + 7) / 8), @@ -22,7 +22,7 @@ static struct descriptor { .device = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = __constant_cpu_to_le16(2), /* v2.0 */ + .bcdUSB = cpu_to_le16(2), /* v2.0 */ .bDeviceClass = USB_CLASS_HUB, .bDeviceSubClass = 0, .bDeviceProtocol = USB_HUB_PR_HS_NO_TT, @@ -38,7 +38,7 @@ static struct descriptor { .config = { .bLength = USB_DT_CONFIG_SIZE, .bDescriptorType = USB_DT_CONFIG, - .wTotalLength = __constant_cpu_to_le16( + .wTotalLength = cpu_to_le16( USB_DT_CONFIG_SIZE + USB_DT_INTERFACE_SIZE + USB_DT_ENDPOINT_SIZE), @@ -64,356 +64,321 @@ static struct descriptor { .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 1 | USB_DIR_IN, /* 0x81 */ .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = __constant_cpu_to_le16( + .wMaxPacketSize = cpu_to_le16( (USB_MAXCHILDREN + 1 + 7) / 8), .bInterval = 255 }, }; -static char *language_string = "\x09\x04"; -static char *vendor_string = "u-boot"; -static char *product_string = "DWC2 root hub"; - -/* - * DWC2 to USB API interface - */ -static int dwc2_submit_rh_msg_in_status(struct dwc2 *dwc2, - struct usb_device *dev, void *buffer, - int txlen, struct devrequest *cmd) +static int dwc2_get_port_status(struct dwc2 *dwc2, struct usb_device *dev, + void *buf, int len) { struct usb_port_status *portsts; - uint32_t hprt0 = 0; - uint32_t port_status = 0; - uint32_t port_change = 0; - int len = 0; + uint32_t hprt0; + uint32_t status = 0; + uint32_t change = 0; int speed; - switch (cmd->requesttype & (USB_TYPE_MASK | USB_RECIP_MASK)) { - case USB_TYPE_STANDARD | USB_RECIP_DEVICE: - *(uint16_t *)buffer = cpu_to_le16(1); - len = 2; - break; - case USB_TYPE_STANDARD | USB_RECIP_INTERFACE: - case USB_TYPE_STANDARD | USB_RECIP_ENDPOINT: - *(uint16_t *)buffer = cpu_to_le16(0); - len = 2; - break; - case USB_RT_HUB: /* USB_TYPE_CLASS | USB_RECIP_DEVICE */ - *(uint32_t *)buffer = cpu_to_le32(0); - len = 4; - break; - case USB_RT_PORT: /* USB_TYPE_CLASS | USB_RECIP_OTHER */ - hprt0 = dwc2_readl(dwc2, HPRT0); + if (!buf || len < sizeof(*portsts)) + return -1; - if (hprt0 & HPRT0_CONNSTS) - port_status |= USB_PORT_STAT_CONNECTION; - if (hprt0 & HPRT0_ENA) - port_status |= USB_PORT_STAT_ENABLE; - if (hprt0 & HPRT0_SUSP) - port_status |= USB_PORT_STAT_SUSPEND; - if (hprt0 & HPRT0_OVRCURRACT) - port_status |= USB_PORT_STAT_OVERCURRENT; - if (hprt0 & HPRT0_RST) - port_status |= USB_PORT_STAT_RESET; - if (hprt0 & HPRT0_PWR) - port_status |= USB_PORT_STAT_POWER; - - speed = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT; - if (speed == HPRT0_SPD_HIGH_SPEED) - port_status |= USB_PORT_STAT_HIGH_SPEED; - else if (speed == HPRT0_SPD_LOW_SPEED) - port_status |= USB_PORT_STAT_LOW_SPEED; - - if (hprt0 & HPRT0_ENACHG) - port_change |= USB_PORT_STAT_C_ENABLE; - if (hprt0 & HPRT0_CONNDET) - port_change |= USB_PORT_STAT_C_CONNECTION; - if (hprt0 & HPRT0_OVRCURRCHG) - port_change |= USB_PORT_STAT_C_OVERCURRENT; - - portsts = buffer; - portsts->wPortStatus = cpu_to_le16(port_status); - portsts->wPortChange = cpu_to_le16(port_change); - len = sizeof(*portsts); + hprt0 = dwc2_readl(dwc2, HPRT0); + + if (hprt0 & HPRT0_CONNSTS) + status |= USB_PORT_STAT_CONNECTION; + if (hprt0 & HPRT0_ENA) + status |= USB_PORT_STAT_ENABLE; + if (hprt0 & HPRT0_SUSP) + status |= USB_PORT_STAT_SUSPEND; + if (hprt0 & HPRT0_OVRCURRACT) + status |= USB_PORT_STAT_OVERCURRENT; + if (hprt0 & HPRT0_RST) + status |= USB_PORT_STAT_RESET; + if (hprt0 & HPRT0_PWR) + status |= USB_PORT_STAT_POWER; + + speed = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT; + if (speed == HPRT0_SPD_HIGH_SPEED) + status |= USB_PORT_STAT_HIGH_SPEED; + else if (speed == HPRT0_SPD_LOW_SPEED) + status |= USB_PORT_STAT_LOW_SPEED; + + if (hprt0 & HPRT0_ENACHG) + change |= USB_PORT_STAT_C_ENABLE; + if (hprt0 & HPRT0_CONNDET) + change |= USB_PORT_STAT_C_CONNECTION; + if (hprt0 & HPRT0_OVRCURRCHG) + change |= USB_PORT_STAT_C_OVERCURRENT; + + portsts = buf; + portsts->wPortStatus = cpu_to_le16(status); + portsts->wPortChange = cpu_to_le16(change); + + dev->act_len = sizeof(*portsts); + dev->status = 0; - break; - default: - goto unknown; - } + return 0; +} - dev->act_len = min(len, txlen); - dev->status = 0; +static int dwc2_get_hub_status(struct dwc2 *dwc2, struct usb_device *dev, + void *buf, int len) +{ + if (!buf || len < 4) + return -1; + + *(uint32_t *)buf = 0; + dev->act_len = 4; + dev->status = 0; return 0; +} -unknown: - dev->act_len = 0; - dev->status = USB_ST_STALLED; +static int dwc2_get_hub_descriptor(struct dwc2 *dwc2, struct usb_device *dev, + void *buf, int len) +{ + if (!buf) + return -1; + + dev->act_len = min_t(int, len, descriptor.hub.bLength); + dev->status = 0; + memcpy(buf, &descriptor.hub, dev->act_len); - return -1; + return 0; } -static void strtodesc(char *dest, char *src, size_t n) +static void strle16(__le16 *dest, char *src, size_t n) { unsigned int i; - dest[0] = n; - dest[1] = 0x3; - for (i = 2; i < n && *src != '\0'; i += 2) { - dest[i] = *(src++); - dest[i + 1] = 0; - } + for (i = 0; i < n && *src != '\0'; i++, src++) + dest[i] = cpu_to_le16(*src); } -/* Direction: In ; Request: Descriptor */ -static int dwc2_submit_rh_msg_in_descriptor(struct usb_device *dev, - void *buffer, int txlen, - struct devrequest *cmd) +static int dwc2_get_string_descriptor(struct dwc2 *dwc2, struct usb_device *dev, + void *buf, int len, int index) { - int len = 0; - char *src; - uint16_t wValue = le16_to_cpu(cmd->value); - uint16_t wLength = le16_to_cpu(cmd->length); - - switch (cmd->requesttype & (USB_TYPE_MASK | USB_RECIP_MASK)) { - case USB_TYPE_STANDARD | USB_RECIP_DEVICE: - switch (wValue >> 8) { - case USB_DT_DEVICE: - debug("USB_DT_DEVICE request\n"); - len = min3(txlen, (int)descriptor.device.bLength, (int)wLength); - memcpy(buffer, &descriptor.device, len); - break; - case USB_DT_CONFIG: - debug("USB_DT_CONFIG config\n"); - len = min3(txlen, (int)descriptor.config.wTotalLength, (int)wLength); - memcpy(buffer, &descriptor.config, len); - break; - case USB_DT_STRING: - debug("USB_DT_STRING: %#x\n", wValue); - switch (wValue & 0xff) { - case 0: /* Language */ - src = language_string; - len = strlen(src) + 2; - ((char *)buffer)[0] = len; - ((char *)buffer)[1] = 0x03; - memcpy(buffer + 2, src, strlen(src)); - break; - case 1: /* Vendor */ - src = vendor_string; - len = 2 * strlen(src) + 2; - strtodesc(buffer, src, len); - break; - case 2: /* Product */ - src = product_string; - len = 2 * strlen(src) + 2; - strtodesc(buffer, src, len); - break; - default: - debug("%s(): unknown string index 0x%x\n", __func__, wValue & 0xff); - goto unknown; - } - len = min3(txlen, len, (int)wLength); - break; - default: - debug("%s(): unknown requesttype: 0x%x\n", __func__, - cmd->requesttype & (USB_TYPE_MASK | USB_RECIP_MASK)); - goto unknown; - } - break; + char *src, *str = buf; + __le16 *le16 = (__le16 *)(str + 2); + int size; + + if (!buf || len < 2) + return -1; - case USB_RT_HUB: /* USB_TYPE_CLASS | USB_RECIP_DEVICE */ - debug("USB_RT_HUB\n"); + switch (index) { + case 0: /* Language */ + src = "\x09\x04"; + size = strlen(src) + 2; + len = min_t(int, len, size); - len = min3(txlen, (int)descriptor.hub.bLength, (int)wLength); - memcpy(buffer, &descriptor.hub, len); + str[0] = size; + str[1] = 0x03; + memcpy(str + 2, src, len - 2); + break; + case 1: /* Vendor */ + src = "u-boot"; + size = 2 * strlen(src) + 2; + len = min_t(int, len, size); + + str[0] = size; + str[1] = 0x03; + strle16(le16, src, (len - 2) / 2); + break; + case 2: /* Product */ + src = "DWC2 root hub"; + size = 2 * strlen(src) + 2; + len = min_t(int, len, size); + + str[0] = size; + str[1] = 0x03; + strle16(le16, src, (len - 2) / 2); break; default: - goto unknown; + dwc2_err(dwc2, "roothub: unknown string descriptor: 0x%x\n", + index); + return -1; } dev->act_len = len; dev->status = 0; return 0; - -unknown: - dev->act_len = 0; - dev->status = USB_ST_STALLED; - - return -1; } -/* Direction: In ; Request: Configuration */ -static int dwc2_submit_rh_msg_in_configuration(struct usb_device *dev, - void *buffer, int txlen, - struct devrequest *cmd) +static int dwc2_get_descriptor(struct dwc2 *dwc2, struct usb_device *dev, + void *buf, int len, int value) { - int len = 0; + int index = value >> 8; + + if (!buf || len < 0) + return -1; - switch (cmd->requesttype & (USB_TYPE_MASK | USB_RECIP_MASK)) { - case USB_TYPE_STANDARD | USB_RECIP_DEVICE: - *(uint8_t *)buffer = 0x01; - len = min(txlen, 1); + switch (index) { + case USB_DT_DEVICE: + len = min(len, (int)descriptor.device.bLength); + memcpy(buf, &descriptor.device, len); break; + case USB_DT_CONFIG: + len = min(len, (int)descriptor.config.wTotalLength); + memcpy(buf, &descriptor.config, len); + break; + case USB_DT_STRING: + value &= 0xff; + return dwc2_get_string_descriptor(dwc2, dev, buf, len, value); default: - goto unknown; + dwc2_err(dwc2, "roothub: unknown descriptor: 0x%x\n", index); + return -1; } dev->act_len = len; dev->status = 0; return 0; - -unknown: - dev->act_len = 0; - dev->status = USB_ST_STALLED; - - return -1; } -/* Direction: In */ -static int dwc2_submit_rh_msg_in(struct dwc2 *dwc2, - struct usb_device *dev, void *buffer, - int txlen, struct devrequest *cmd) +static int dwc2_set_port_feature(struct dwc2 *dwc2, struct usb_device *dev, + int feature) { - switch (cmd->request) { - case USB_REQ_GET_STATUS: - return dwc2_submit_rh_msg_in_status(dwc2, dev, buffer, - txlen, cmd); - case USB_REQ_GET_DESCRIPTOR: - return dwc2_submit_rh_msg_in_descriptor(dev, buffer, - txlen, cmd); - case USB_REQ_GET_CONFIGURATION: - return dwc2_submit_rh_msg_in_configuration(dev, buffer, - txlen, cmd); - default: - dev->act_len = 0; - dev->status = USB_ST_STALLED; + uint32_t hprt0; + + hprt0 = dwc2_readl(dwc2, HPRT0); + hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET | HPRT0_ENACHG | HPRT0_OVRCURRCHG); + + switch (feature) { + case USB_PORT_FEAT_SUSPEND: + break; + case USB_PORT_FEAT_RESET: + hprt0 |= HPRT0_RST; + dwc2_writel(dwc2, hprt0, HPRT0); + + mdelay(60); + hprt0 = dwc2_readl(dwc2, HPRT0); + hprt0 &= ~HPRT0_RST; + dwc2_writel(dwc2, hprt0, HPRT0); + break; + case USB_PORT_FEAT_POWER: + break; + case USB_PORT_FEAT_ENABLE: + /* Set by the core after a reset */ + break; + default: + dwc2_dbg(dwc2, "roothub: unsupported set port feature 0x%x\n", + feature); return -1; } + + dev->act_len = 0; + dev->status = 0; + + return 0; } -/* Direction: Out */ -static int dwc2_submit_rh_msg_out(struct dwc2 *dwc2, - struct usb_device *dev, - void *buffer, int txlen, - struct devrequest *cmd) +static int dwc2_clear_port_feature(struct dwc2 *dwc2, struct usb_device *dev, + int feature) { - uint16_t wValue = le16_to_cpu(cmd->value); uint32_t hprt0; - switch (cmd->requesttype & (USB_TYPE_MASK | USB_RECIP_MASK)) { - case USB_TYPE_STANDARD | USB_RECIP_DEVICE: - switch (cmd->request) { - case USB_REQ_SET_ADDRESS: - dwc2_dbg(dwc2, "set root hub addr %d\n", wValue); - dwc2->root_hub_devnum = wValue; - break; - case USB_REQ_SET_CONFIGURATION: - break; - default: - goto unknown; - } + hprt0 = dwc2_readl(dwc2, HPRT0); + hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET | HPRT0_ENACHG | HPRT0_OVRCURRCHG); + + switch (feature) { + case USB_PORT_FEAT_ENABLE: + hprt0 |= HPRT0_ENA; + break; + case USB_PORT_FEAT_SUSPEND: + break; + case USB_PORT_FEAT_POWER: break; - case USB_TYPE_STANDARD | USB_RECIP_ENDPOINT: - case USB_RT_HUB: /* USB_TYPE_CLASS | USB_RECIP_DEVICE */ - switch (cmd->request) { - case USB_REQ_CLEAR_FEATURE: - break; - } + case USB_PORT_FEAT_C_CONNECTION: + hprt0 |= HPRT0_CONNDET; break; - case USB_RT_PORT: /* USB_TYPE_CLASS | USB_RECIP_OTHER */ - switch (cmd->request) { - case USB_REQ_CLEAR_FEATURE: - hprt0 = dwc2_readl(dwc2, HPRT0); - hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET - | HPRT0_ENACHG | HPRT0_OVRCURRCHG); - switch (wValue) { - case USB_PORT_FEAT_ENABLE: - hprt0 |= HPRT0_ENA; - break; - case USB_PORT_FEAT_SUSPEND: - break; - case USB_PORT_FEAT_POWER: - break; - case USB_PORT_FEAT_C_CONNECTION: - hprt0 |= HPRT0_CONNDET; - break; - case USB_PORT_FEAT_C_ENABLE: - hprt0 |= HPRT0_ENACHG; - break; - case USB_PORT_FEAT_C_OVER_CURRENT: - hprt0 |= HPRT0_OVRCURRCHG; - break; - default: - dwc2_dbg(dwc2, "unknown feature 0x%x\n", wValue); - goto unknown; - } - dwc2_writel(dwc2, hprt0, HPRT0); - break; - case USB_REQ_SET_FEATURE: - hprt0 = dwc2_readl(dwc2, HPRT0); - hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET - | HPRT0_ENACHG | HPRT0_OVRCURRCHG); - switch (wValue) { - case USB_PORT_FEAT_SUSPEND: - break; - case USB_PORT_FEAT_RESET: - hprt0 |= HPRT0_RST; - dwc2_writel(dwc2, hprt0, HPRT0); - - mdelay(60); - - hprt0 = dwc2_readl(dwc2, HPRT0); - hprt0 &= ~HPRT0_RST; - dwc2_writel(dwc2, hprt0, HPRT0); - break; - case USB_PORT_FEAT_POWER: - break; - case USB_PORT_FEAT_ENABLE: - /* Set by the core after a reset */ - break; - default: - dwc2_dbg(dwc2, "unknown feature 0x%x\n", wValue); - goto unknown; - } - break; - default: goto unknown; - } + case USB_PORT_FEAT_C_ENABLE: + hprt0 |= HPRT0_ENACHG; + break; + case USB_PORT_FEAT_C_OVER_CURRENT: + hprt0 |= HPRT0_OVRCURRCHG; break; default: - goto unknown; + dwc2_dbg(dwc2, "roothub: unsupported clear port feature 0x%x\n", + feature); + return -1; } + dwc2_writel(dwc2, hprt0, HPRT0); + dev->act_len = 0; dev->status = 0; return 0; +} + +static int dwc2_set_address(struct dwc2 *dwc2, struct usb_device *dev, int addr) +{ + dwc2_dbg(dwc2, "roothub: set address to %d\n", addr); + dwc2->root_hub_devnum = addr; -unknown: dev->act_len = 0; - dev->status = USB_ST_STALLED; - return -1; + dev->status = 0; + + return 0; } -int -dwc2_submit_rh_msg(struct dwc2 *dwc2, struct usb_device *dev, - unsigned long pipe, void *buffer, int txlen, - struct devrequest *cmd) +int dwc2_submit_roothub(struct dwc2 *dwc2, struct usb_device *dev, + unsigned long pipe, void *buf, int len, + struct devrequest *setup) { - int stat = 0; + unsigned char reqtype = setup->requesttype; + unsigned char request = setup->request; + unsigned short value = le16_to_cpu(setup->value); + unsigned short size = le16_to_cpu(setup->length); + int minlen = min_t(int, len, size); if (usb_pipeint(pipe)) { - dwc2_err(dwc2, "Root-Hub submit IRQ: NOT implemented\n"); + dwc2_err(dwc2, "roothub: submit IRQ NOT implemented\n"); return 0; } - if (cmd->requesttype & USB_DIR_IN) - stat = dwc2_submit_rh_msg_in(dwc2, dev, buffer, txlen, cmd); - else - stat = dwc2_submit_rh_msg_out(dwc2, dev, buffer, txlen, cmd); + dev->act_len = 0; + dev->status = USB_ST_STALLED; + +#define REQ(l, u) ((l) | ((u) << 8)) + + switch (REQ(request, reqtype)) { + case REQ(USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB): + return dwc2_get_hub_descriptor(dwc2, dev, buf, minlen); + + case REQ(USB_REQ_GET_DESCRIPTOR, USB_DIR_IN): + return dwc2_get_descriptor(dwc2, dev, buf, minlen, value); + + case REQ(USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB): + return dwc2_get_hub_status(dwc2, dev, buf, len); + + case REQ(USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT): + return dwc2_get_port_status(dwc2, dev, buf, len); - mdelay(1); - return stat; + case REQ(USB_REQ_SET_FEATURE, USB_DIR_OUT | USB_RT_PORT): + return dwc2_set_port_feature(dwc2, dev, value); + + case REQ(USB_REQ_CLEAR_FEATURE, USB_DIR_OUT | USB_RT_PORT): + return dwc2_clear_port_feature(dwc2, dev, value); + + case REQ(USB_REQ_SET_ADDRESS, USB_DIR_OUT): + return dwc2_set_address(dwc2, dev, value); + + case REQ(USB_REQ_SET_CONFIGURATION, USB_DIR_OUT): + dev->act_len = 0; + dev->status = 0; + return 0; + + case REQ(USB_REQ_GET_CONFIGURATION, USB_DIR_IN): + *(char *)buf = 1; + dev->act_len = 1; + dev->status = 0; + return 0; + } + + dwc2_err(dwc2, "roothub: unsupported request 0x%x requesttype 0x%x\n", + request, reqtype); + + return 0; } -- 2.21.0.196.g041f5ea _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox