summaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/core/usb.c')
-rw-r--r--drivers/usb/core/usb.c350
1 files changed, 214 insertions, 136 deletions
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 1c3dcb79a8..1f6f1d7c41 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
*
* Most of this source has been derived from the Linux USB
@@ -14,21 +15,6 @@
*
* Adapted for barebox:
* (C) Copyright 2001 Denis Peter, MPL AG Switzerland
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- *
*/
/*
@@ -40,7 +26,6 @@
*
* For each transfer (except "Interrupt") we wait for completion.
*/
-
#define pr_fmt(fmt) "usb: " fmt
#include <common.h>
@@ -53,11 +38,10 @@
#include <init.h>
#include <dma.h>
-#include <usb/usb.h>
-#include <usb/ch9.h>
+#include <linux/usb/usb.h>
+#include <linux/usb/ch9.h>
#include "usb.h"
-#include "hub.h"
#define USB_BUFSIZ 512
@@ -69,7 +53,7 @@ LIST_HEAD(usb_device_list);
static void print_usb_device(struct usb_device *dev)
{
- pr_info("Bus %03d Device %03d: ID %04x:%04x %s\n",
+ dev_info(&dev->dev, "Bus %03d Device %03d: ID %04x:%04x %s\n",
dev->host->busnum, dev->devnum,
dev->descriptor->idVendor,
dev->descriptor->idProduct,
@@ -80,28 +64,44 @@ static int host_busnum = 1;
static inline int usb_host_acquire(struct usb_host *host)
{
- if (host->sem)
+ if (slice_acquired(&host->slice))
return -EAGAIN;
- host->sem++;
+
+ slice_acquire(&host->slice);
+
return 0;
}
static inline void usb_host_release(struct usb_host *host)
{
- if (host->sem > 0)
- host->sem--;
+ slice_release(&host->slice);
+}
+
+static int usb_hw_detect(struct device *dev)
+{
+ struct usb_host *host;
+
+ list_for_each_entry(host, &host_list, list) {
+ if (dev == host->hw_dev)
+ return usb_host_detect(host);
+ }
+
+ return -ENODEV;
}
int usb_register_host(struct usb_host *host)
{
list_add_tail(&host->list, &host_list);
host->busnum = host_busnum++;
- host->sem = 0;
+ slice_init(&host->slice, dev_name(host->hw_dev));
+ if (!host->hw_dev->detect)
+ host->hw_dev->detect = usb_hw_detect;
return 0;
}
void usb_unregister_host(struct usb_host *host)
{
+ slice_exit(&host->slice);
list_del(&host->list);
}
@@ -112,7 +112,7 @@ static int usb_set_configuration(struct usb_device *dev, int configuration)
{
int res;
- pr_debug("set configuration %d\n", configuration);
+ dev_dbg(&dev->dev, "set configuration %d\n", configuration);
/* set setup command */
res = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
@@ -147,21 +147,21 @@ usb_set_maxpacket_ep(struct usb_device *dev, struct usb_endpoint_descriptor *ep)
/* Control => bidirectional */
dev->epmaxpacketout[b] = ep->wMaxPacketSize;
dev->epmaxpacketin[b] = ep->wMaxPacketSize;
- pr_debug("##Control EP epmaxpacketout/in[%d] = %d\n",
+ dev_dbg(&dev->dev, "##Control EP epmaxpacketout/in[%d] = %d\n",
b, dev->epmaxpacketin[b]);
} else {
if ((ep->bEndpointAddress & 0x80) == 0) {
/* OUT Endpoint */
if (ep->wMaxPacketSize > dev->epmaxpacketout[b]) {
dev->epmaxpacketout[b] = ep->wMaxPacketSize;
- pr_debug("##EP epmaxpacketout[%d] = %d\n",
+ dev_dbg(&dev->dev, "##EP epmaxpacketout[%d] = %d\n",
b, dev->epmaxpacketout[b]);
}
} else {
/* IN Endpoint */
if (ep->wMaxPacketSize > dev->epmaxpacketin[b]) {
dev->epmaxpacketin[b] = ep->wMaxPacketSize;
- pr_debug("##EP epmaxpacketin[%d] = %d\n",
+ dev_dbg(&dev->dev, "##EP epmaxpacketin[%d] = %d\n",
b, dev->epmaxpacketin[b]);
}
} /* if out */
@@ -193,6 +193,7 @@ static int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int c
int index, ifno, epno, curr_if_num;
int i;
unsigned char *ch;
+ struct usb_interface *if_desc;
ifno = -1;
epno = -1;
@@ -201,7 +202,7 @@ static int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int c
dev->configno = cfgno;
head = (struct usb_descriptor_header *) &buffer[0];
if (head->bDescriptorType != USB_DT_CONFIG) {
- printf(" ERROR: NOT USB_CONFIG_DESC %x\n",
+ dev_err(&dev->dev, " ERROR: NOT USB_CONFIG_DESC %x\n",
head->bDescriptorType);
return -1;
}
@@ -224,7 +225,7 @@ static int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int c
* next memcpy() will corrupt dev->config
*/
if (ifno > USB_MAXINTERFACES) {
- printf("ifno = %d > "
+ dev_err(&dev->dev, "ifno = %d > "
"USB_MAXINTERFACES = %d !\n",
ifno,
USB_MAXINTERFACES);
@@ -250,13 +251,18 @@ static int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int c
&buffer[index], buffer[index]);
le16_to_cpus(&(dev->config.interface[ifno].ep_desc[epno].\
wMaxPacketSize));
- pr_debug("if %d, ep %d\n", ifno, epno);
+ dev_dbg(&dev->dev, "if %d, ep %d\n", ifno, epno);
+ break;
+ case USB_DT_SS_ENDPOINT_COMP:
+ if_desc = &dev->config.interface[ifno];
+ memcpy(&if_desc->ss_ep_comp_desc[epno],
+ &buffer[index], buffer[index]);
break;
default:
if (head->bLength == 0)
return 1;
- pr_debug("unknown Description Type : %x\n",
+ dev_dbg(&dev->dev, "unknown Description Type : %x\n",
head->bDescriptorType);
{
@@ -273,23 +279,6 @@ static int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int c
return 1;
}
-/**
- * set address of a device to the value in dev->devnum.
- * This can only be done by addressing the device via the default address (0)
- */
-static int usb_set_address(struct usb_device *dev)
-{
- int res;
-
- pr_debug("set address %d\n", dev->devnum);
-
- res = usb_control_msg(dev, usb_snddefctrl(dev),
- USB_REQ_SET_ADDRESS, 0,
- (dev->devnum), 0,
- NULL, 0, USB_CNTL_TIMEOUT);
- return res;
-}
-
static int usb_get_descriptor(struct usb_device *dev, unsigned char type,
unsigned char index, void *buf, int size)
{
@@ -301,29 +290,30 @@ static int usb_get_descriptor(struct usb_device *dev, unsigned char type,
return res;
}
-/*
- * By the time we get here, the device has gotten a new device ID
- * and is in the default state. We need to identify the thing and
- * get the ball rolling..
- *
- * Returns 0 for success, != 0 for error.
- */
-int usb_new_device(struct usb_device *dev)
+static int get_descriptor_len(struct usb_device *dev, int len, int expect_len)
{
- int addr, err;
- int tmp;
- void *buf;
- struct usb_device_descriptor *desc;
- struct usb_device *parent = dev->parent;
- char str[16];
+ int err;
- buf = dma_alloc(USB_BUFSIZ);
+ err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, dev->descriptor, len);
+ if (err < expect_len) {
+ if (err < 0) {
+ dev_err(&dev->dev, "unable to get device descriptor (error=%d)\n",
+ err);
+ return err;
+ } else {
+ dev_err(&dev->dev, "USB device descriptor short read (expected %i, got %i)\n",
+ expect_len, err);
+ return -EIO;
+ }
+ }
- /* We still haven't set the Address yet */
- addr = dev->devnum;
- dev->devnum = 0;
+ return 0;
+}
- /* This is a Windows scheme of initialization sequence, with double
+static int usb_setup_descriptor(struct usb_device *dev, bool do_read)
+{
+ /*
+ * This is a Windows scheme of initialization sequence, with double
* reset of the device (Linux uses the same sequence)
* Some equipment is said to work only with such init sequence; this
* patch is based on the work by Alan Stern:
@@ -331,38 +321,50 @@ int usb_new_device(struct usb_device *dev)
* thread_id=5729457&forum_id=5398
*/
- /* send 64-byte GET-DEVICE-DESCRIPTOR request. Since the descriptor is
+ /*
+ * send 64-byte GET-DEVICE-DESCRIPTOR request. Since the descriptor is
* only 18 bytes long, this will terminate with a short packet. But if
* the maxpacket size is 8 or 16 the device may be waiting to transmit
- * some more, or keeps on retransmitting the 8 byte header. */
-
- desc = buf;
- dev->descriptor->bMaxPacketSize0 = 64; /* Start off at 64 bytes */
- /* Default to 64 byte max packet size */
- dev->maxpacketsize = PACKET_SIZE_64;
- dev->epmaxpacketin[0] = 64;
- dev->epmaxpacketout[0] = 64;
+ * some more, or keeps on retransmitting the 8 byte header.
+ */
- err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, 64);
- if (err < 0) {
- pr_debug("%s: usb_get_descriptor() failed with %d\n", __func__, err);
- goto err_out;
+ if (dev->speed == USB_SPEED_LOW) {
+ dev->descriptor->bMaxPacketSize0 = 8;
+ dev->maxpacketsize = PACKET_SIZE_8;
+ } else {
+ dev->descriptor->bMaxPacketSize0 = 64;
+ dev->maxpacketsize = PACKET_SIZE_64;
}
+ dev->epmaxpacketin[0] = dev->descriptor->bMaxPacketSize0;
+ dev->epmaxpacketout[0] = dev->descriptor->bMaxPacketSize0;
- dev->descriptor->bMaxPacketSize0 = desc->bMaxPacketSize0;
-
- /* find the port number we're at */
- if (parent) {
- /* reset the port for the second time */
- err = hub_port_reset(dev->parent, dev->portnr - 1, dev);
- if (err < 0) {
- printf("\n Couldn't reset port %i\n", dev->portnr);
- goto err_out;
- }
+ if (do_read && dev->speed == USB_SPEED_FULL) {
+ int err;
+
+ /*
+ * Validate we've received only at least 8 bytes, not that
+ * we've received the entire descriptor. The reasoning is:
+ * - The code only uses fields in the first 8 bytes, so
+ * that's all we need to have fetched at this stage.
+ * - The smallest maxpacket size is 8 bytes. Before we know
+ * the actual maxpacket the device uses, the USB controller
+ * may only accept a single packet. Consequently we are only
+ * guaranteed to receive 1 packet (at least 8 bytes) even in
+ * a non-error case.
+ *
+ * At least the DWC2 controller needs to be programmed with
+ * the number of packets in addition to the number of bytes.
+ * A request for 64 bytes of data with the maxpacket guessed
+ * as 64 (above) yields a request for 1 packet.
+ */
+ err = get_descriptor_len(dev, 64, 8);
+ if (err)
+ return err;
+
+ dev->epmaxpacketin[0] = dev->descriptor->bMaxPacketSize0;
+ dev->epmaxpacketout[0] = dev->descriptor->bMaxPacketSize0;
}
- dev->epmaxpacketin[0] = dev->descriptor->bMaxPacketSize0;
- dev->epmaxpacketout[0] = dev->descriptor->bMaxPacketSize0;
switch (dev->descriptor->bMaxPacketSize0) {
case 8:
dev->maxpacketsize = PACKET_SIZE_8;
@@ -377,29 +379,90 @@ int usb_new_device(struct usb_device *dev)
dev->maxpacketsize = PACKET_SIZE_64;
break;
}
- dev->devnum = addr;
+
+ return 0;
+}
+
+/**
+ * set address of a device to the value in dev->devnum.
+ * This can only be done by addressing the device via the default address (0)
+ */
+static int usb_set_address(struct usb_device *dev)
+{
+ int res;
+
+ dev_dbg(&dev->dev, "set address %d\n", dev->devnum);
+
+ res = usb_control_msg(dev, usb_snddefctrl(dev),
+ USB_REQ_SET_ADDRESS, 0,
+ (dev->devnum), 0,
+ NULL, 0, USB_CNTL_TIMEOUT);
+ return res;
+}
+
+/*
+ * By the time we get here, the device is in the default state. We need to
+ * identify the thing and get the ball rolling..
+ *
+ * Returns 0 for success, != 0 for error.
+ */
+int usb_new_device(struct usb_device *dev)
+{
+ int err;
+ void *buf;
+ struct usb_host *host = dev->host;
+ struct usb_device *parent = dev->parent;
+ char str[16];
+
+ if (parent)
+ dev_set_name(&dev->dev, "%s-%d", parent->dev.name,
+ dev->portnr - 1);
+ else
+ dev_set_name(&dev->dev, "usb%d", dev->host->busnum);
+
+ dev->dev.id = DEVICE_ID_SINGLE;
+
+ buf = dma_alloc(USB_BUFSIZ);
+
+ if (parent)
+ dev->level = parent->level + 1;
+
+ if (host->alloc_device) {
+ err = host->alloc_device(dev);
+ if (err)
+ goto err_out;
+ }
+
+ usb_setup_descriptor(dev, !host->no_desc_before_addr);
+
+ dev->devnum = ++dev_index;
err = usb_set_address(dev); /* set address */
if (err < 0) {
- printf("\n USB device not accepting new address " \
+ dev_err(&dev->dev, "USB device not accepting new address " \
"(error=%lX)\n", dev->status);
goto err_out;
}
mdelay(10); /* Let the SET_ADDRESS settle */
- tmp = sizeof(*dev->descriptor);
+ if (host->no_desc_before_addr) {
+ err = usb_setup_descriptor(dev, true);
+ if (err)
+ goto err_out;
+ }
err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
dev->descriptor, sizeof(*dev->descriptor));
- if (err < tmp) {
+ if (err < sizeof(*dev->descriptor)) {
if (err < 0)
- printf("unable to get device descriptor (error=%d)\n",
+ dev_err(&dev->dev, "unable to get device descriptor (error=%d)\n",
err);
else
- printf("USB device descriptor short read " \
- "(expected %i, got %i)\n", tmp, err);
+ dev_err(&dev->dev, "USB device descriptor short read " \
+ "(expected %zu, got %i)\n",
+ sizeof(*dev->descriptor), err);
goto err_out;
}
/* correct le values */
@@ -414,12 +477,12 @@ int usb_new_device(struct usb_device *dev)
/* we set the default configuration here */
err = usb_set_configuration(dev, dev->config.desc.bConfigurationValue);
if (err) {
- printf("Setting default configuration failed with: %s\n" \
- "len %d, status %lX\n", strerror(-err),
+ dev_err(&dev->dev, "Setting default configuration failed with: %pe\n" \
+ "len %d, status %lX\n", ERR_PTR(err),
dev->act_len, dev->status);
goto err_out;
}
- pr_debug("new device: Mfr=%d, Product=%d, SerialNumber=%d\n",
+ dev_dbg(&dev->dev, "new device: Mfr=%d, Product=%d, SerialNumber=%d\n",
dev->descriptor->iManufacturer, dev->descriptor->iProduct,
dev->descriptor->iSerialNumber);
memset(dev->mf, 0, sizeof(dev->mf));
@@ -435,20 +498,11 @@ int usb_new_device(struct usb_device *dev)
usb_string(dev, dev->descriptor->iSerialNumber,
dev->serial, sizeof(dev->serial));
- if (parent) {
- dev_set_name(&dev->dev, "%s-%d", parent->dev.name,
- dev->portnr - 1);
- } else {
- dev_set_name(&dev->dev, "usb%d", dev->host->busnum);
- }
-
- dev->dev.id = DEVICE_ID_SINGLE;
-
print_usb_device(dev);
err = register_device(&dev->dev);
if (err) {
- printf("Failed to register device: %s\n", strerror(-err));
+ dev_err(&dev->dev, "Failed to register device: %pe\n", ERR_PTR(err));
goto err_out;
}
@@ -480,6 +534,7 @@ void usb_free_device(struct usb_device *usbdev)
{
dma_free(usbdev->descriptor);
dma_free(usbdev->setup_packet);
+ free_device_res(&usbdev->dev);
free(usbdev);
}
@@ -509,7 +564,6 @@ struct usb_device *usb_alloc_new_device(void)
{
struct usb_device *usbdev = xzalloc(sizeof (*usbdev));
- usbdev->devnum = ++dev_index;
usbdev->maxchild = 0;
usbdev->dev.bus = &usb_bus_type;
usbdev->setup_packet = dma_alloc(sizeof(*usbdev->setup_packet));
@@ -522,10 +576,14 @@ int usb_host_detect(struct usb_host *host)
{
int ret;
+ of_usb_host_probe_hubs(host);
+
if (!host->root_dev) {
- ret = host->init(host);
- if (ret)
- return ret;
+ if (host->init) {
+ ret = host->init(host);
+ if (ret)
+ return ret;
+ }
host->root_dev = usb_alloc_new_device();
host->root_dev->dev.parent = host->hw_dev;
@@ -543,7 +601,7 @@ int usb_host_detect(struct usb_host *host)
return 0;
}
-void usb_rescan(void)
+int usb_rescan(void)
{
struct usb_host *host;
int ret;
@@ -557,6 +615,22 @@ void usb_rescan(void)
}
pr_info("%d USB Device(s) found\n", dev_count);
+
+ if (IS_ENABLED(CONFIG_USB_OTGDEV)) {
+ unsigned int skipped_otg = 0;
+ struct device *dev;
+
+ bus_for_each_device(&otg_bus_type, dev) {
+ if (otg_device_get_mode(dev) == USB_DR_MODE_OTG)
+ skipped_otg++;
+ }
+
+ if (skipped_otg)
+ pr_notice("%u unconfigured OTG controller(s) were not scanned\n",
+ skipped_otg);
+ }
+
+ return dev_count;
}
/*-------------------------------------------------------------------
@@ -611,7 +685,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe,
setup_packet->value = cpu_to_le16(value);
setup_packet->index = cpu_to_le16(index);
setup_packet->length = cpu_to_le16(size);
- pr_debug("usb_control_msg: request: 0x%X, requesttype: 0x%X, " \
+ dev_dbg(&dev->dev, "usb_control_msg: request: 0x%X, requesttype: 0x%X, " \
"value 0x%X index 0x%X length 0x%X\n",
request, requesttype, value, index, size);
dev->status = USB_ST_NOT_PROC; /*not yet processed */
@@ -721,23 +795,23 @@ int usb_get_configuration_no(struct usb_device *dev,
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 9);
if (result < 9) {
if (result < 0)
- printf("unable to get descriptor, error %lX\n",
+ dev_err(&dev->dev, "unable to get descriptor, error %lX\n",
dev->status);
else
- printf("config descriptor too short " \
+ dev_err(&dev->dev, "config descriptor too short " \
"(expected %i, got %i)\n", 9, result);
return -1;
}
tmp = le16_to_cpu(config->wTotalLength);
if (tmp > USB_BUFSIZ) {
- pr_debug("usb_get_configuration_no: failed to get " \
+ dev_dbg(&dev->dev, "usb_get_configuration_no: failed to get " \
"descriptor - too long: %u\n", tmp);
return -1;
}
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, tmp);
- pr_debug("get_conf_no %d Result %d, wLength %u\n",
+ dev_dbg(&dev->dev, "get_conf_no %d Result %d, wLength %u\n",
cfgno, result, tmp);
return result;
}
@@ -757,7 +831,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
}
}
if (!if_face) {
- printf("selecting invalid interface %d", interface);
+ dev_err(&dev->dev, "selecting invalid interface %d", interface);
return -1;
}
/*
@@ -904,31 +978,33 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid,
*/
int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
{
- unsigned char mybuf[USB_BUFSIZ];
unsigned char *tbuf;
- int err;
+ int err = 0;
unsigned int u, idx;
if (size <= 0 || !buf || !index)
return -1;
+
+ tbuf = dma_alloc(USB_BUFSIZ);
buf[0] = 0;
- tbuf = &mybuf[0];
/* get langid for strings if it's not yet known */
if (!dev->have_langid) {
err = usb_string_sub(dev, 0, 0, tbuf);
if (err < 0) {
- pr_debug("error getting string descriptor 0 " \
+ dev_dbg(&dev->dev, "error getting string descriptor 0 " \
"(error=%lx)\n", dev->status);
- return -1;
+ err = -1;
+ goto fail;
} else if (tbuf[0] < 4) {
pr_debug("string descriptor 0 too short\n");
- return -1;
+ err = -1;
+ goto fail;
} else {
dev->have_langid = -1;
dev->string_langid = tbuf[2] | (tbuf[3] << 8);
/* always use the first langid listed */
- pr_debug("USB device number %d default " \
+ dev_dbg(&dev->dev, "USB device number %d default " \
"language ID 0x%x\n",
dev->devnum, dev->string_langid);
}
@@ -936,7 +1012,7 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
err = usb_string_sub(dev, dev->string_langid, index, tbuf);
if (err < 0)
- return err;
+ goto fail;
size--; /* leave room for trailing NULL char in output buffer */
for (idx = 0, u = 2; u < err; u += 2) {
@@ -949,6 +1025,8 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
}
buf[idx] = 0;
err = idx;
+fail:
+ dma_free(tbuf);
return err;
}
@@ -1044,7 +1122,7 @@ static const struct usb_device_id *usb_match_id(struct usb_device *usbdev,
}
EXPORT_SYMBOL(usb_match_id);
-static int usb_match(struct device_d *dev, struct driver_d *drv)
+static int usb_match(struct device *dev, struct driver *drv)
{
struct usb_device *usbdev = container_of(dev, struct usb_device, dev);
struct usb_driver *usbdrv = container_of(dev->driver, struct usb_driver, driver);
@@ -1061,7 +1139,7 @@ static int usb_match(struct device_d *dev, struct driver_d *drv)
return 1;
}
-static int usb_probe(struct device_d *dev)
+static int usb_probe(struct device *dev)
{
struct usb_device *usbdev = container_of(dev, struct usb_device, dev);
struct usb_driver *usbdrv = container_of(dev->driver, struct usb_driver, driver);
@@ -1072,7 +1150,7 @@ static int usb_probe(struct device_d *dev)
return usbdrv->probe(usbdev, id);
}
-static void usb_remove(struct device_d *dev)
+static void usb_remove(struct device *dev)
{
struct usb_device *usbdev = container_of(dev, struct usb_device, dev);
struct usb_driver *usbdrv = container_of(dev->driver, struct usb_driver, driver);