diff options
Diffstat (limited to 'drivers/usb/core')
| -rw-r--r-- | drivers/usb/core/Kconfig | 19 | ||||
| -rw-r--r-- | drivers/usb/core/Makefile | 2 | ||||
| -rw-r--r-- | drivers/usb/core/buffer.c | 2 | ||||
| -rw-r--r-- | drivers/usb/core/config.c | 13 | ||||
| -rw-r--r-- | drivers/usb/core/devio.c | 326 | ||||
| -rw-r--r-- | drivers/usb/core/driver.c | 180 | ||||
| -rw-r--r-- | drivers/usb/core/file.c | 24 | ||||
| -rw-r--r-- | drivers/usb/core/generic.c | 1 | ||||
| -rw-r--r-- | drivers/usb/core/hcd-pci.c | 7 | ||||
| -rw-r--r-- | drivers/usb/core/hcd.c | 241 | ||||
| -rw-r--r-- | drivers/usb/core/hub.c | 1366 | ||||
| -rw-r--r-- | drivers/usb/core/hub.h | 47 | ||||
| -rw-r--r-- | drivers/usb/core/message.c | 19 | ||||
| -rw-r--r-- | drivers/usb/core/port.c | 354 | ||||
| -rw-r--r-- | drivers/usb/core/quirks.c | 44 | ||||
| -rw-r--r-- | drivers/usb/core/sysfs.c | 66 | ||||
| -rw-r--r-- | drivers/usb/core/urb.c | 71 | ||||
| -rw-r--r-- | drivers/usb/core/usb-acpi.c | 140 | ||||
| -rw-r--r-- | drivers/usb/core/usb.c | 2 | ||||
| -rw-r--r-- | drivers/usb/core/usb.h | 26 |
20 files changed, 1909 insertions, 1041 deletions
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index db535b0aa17..1060657ca1b 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -1,16 +1,8 @@ # # USB Core configuration # -config USB_DEBUG - bool "USB verbose debug messages" - help - Say Y here if you want the USB core & hub drivers to produce a bunch - of debug messages to the system log. Select this if you are having a - problem with USB support and want to see more of what is going on. - config USB_ANNOUNCE_NEW_DEVICES bool "USB announce new devices" - default N help Say Y here if you want the USB core to always announce the idVendor, idProduct, Manufacturer, Product, and SerialNumber @@ -28,7 +20,7 @@ config USB_DEFAULT_PERSIST bool "Enable USB persist by default" default y help - Say N here if you don't want USB power session persistance + Say N here if you don't want USB power session persistence enabled by default. If you say N it will make suspended USB devices that lose power get reenumerated as if they had been unplugged, causing any mounted filesystems to be lost. The @@ -89,3 +81,12 @@ config USB_OTG_BLACKLIST_HUB and software costs by not supporting external hubs. So are "Embedded Hosts" that don't offer OTG support. +config USB_OTG_FSM + tristate "USB 2.0 OTG FSM implementation" + depends on USB + select USB_OTG + select USB_PHY + help + Implements OTG Finite State Machine as specified in On-The-Go + and Embedded Host Supplement to the USB Revision 2.0 Specification. + diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile index 5e847ad2f58..2f6f9322004 100644 --- a/drivers/usb/core/Makefile +++ b/drivers/usb/core/Makefile @@ -2,8 +2,6 @@ # Makefile for USB Core files and filesystem # -ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG - usbcore-y := usb.o hub.o hcd.o urb.o message.o driver.o usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o usbcore-y += devio.o notify.o generic.o quirks.o devices.o diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index 23559746be9..684ef70dc09 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -2,7 +2,7 @@ * DMA memory management for framework level HCD code (hc_driver) * * This implementation plugs in through generic "usb_bus" level methods, - * and should work with all USB controllers, regardles of bus type. + * and should work with all USB controllers, regardless of bus type. */ #include <linux/module.h> diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index a6b2cabe793..1ab4df1de2d 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -3,7 +3,6 @@ #include <linux/usb/hcd.h> #include <linux/usb/quirks.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/device.h> #include <asm/byteorder.h> @@ -11,7 +10,6 @@ #define USB_MAXALTSETTING 128 /* Hard limit */ -#define USB_MAXENDPOINTS 30 /* Hard limit */ #define USB_MAXCONFIG 8 /* Arbitrary limit */ @@ -651,10 +649,6 @@ void usb_destroy_configuration(struct usb_device *dev) * * hub-only!! ... and only in reset path, or usb_new_device() * (used by real hubs and virtual root hubs) - * - * NOTE: if this is a WUSB device and is not authorized, we skip the - * whole thing. A non-authorized USB device has no - * configurations. */ int usb_get_configuration(struct usb_device *dev) { @@ -666,8 +660,6 @@ int usb_get_configuration(struct usb_device *dev) struct usb_config_descriptor *desc; cfgno = 0; - if (dev->authorized == 0) /* Not really an error */ - goto out_not_authorized; result = -ENOMEM; if (ncfg > USB_MAXCONFIG) { dev_warn(ddev, "too many configurations: %d, " @@ -724,6 +716,10 @@ int usb_get_configuration(struct usb_device *dev) result = -ENOMEM; goto err; } + + if (dev->quirks & USB_QUIRK_DELAY_INIT) + msleep(100); + result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, length); if (result < 0) { @@ -751,7 +747,6 @@ int usb_get_configuration(struct usb_device *dev) err: kfree(desc); -out_not_authorized: dev->descriptor.bNumConfigurations = cfgno; err2: if (result == -ENOMEM) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 71dc5d768fa..257876ea03a 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -62,7 +62,7 @@ /* Mutual exclusion for removal, open, and release */ DEFINE_MUTEX(usbfs_mutex); -struct dev_state { +struct usb_dev_state { struct list_head list; /* state list */ struct usb_device *dev; struct file *file; @@ -81,7 +81,7 @@ struct dev_state { struct async { struct list_head asynclist; - struct dev_state *ps; + struct usb_dev_state *ps; struct pid *pid; const struct cred *cred; unsigned int signr; @@ -118,7 +118,7 @@ module_param(usbfs_memory_mb, uint, 0644); MODULE_PARM_DESC(usbfs_memory_mb, "maximum MB allowed for usbfs buffers (0 = no limit)"); -/* Hard limit, necessary to avoid aithmetic overflow */ +/* Hard limit, necessary to avoid arithmetic overflow */ #define USBFS_XFER_MAX (UINT_MAX / 2 - 1000000) static atomic_t usbfs_memory_usage; /* Total memory currently allocated */ @@ -151,7 +151,7 @@ static void usbfs_decrease_memory_usage(unsigned amount) atomic_sub(amount, &usbfs_memory_usage); } -static int connected(struct dev_state *ps) +static int connected(struct usb_dev_state *ps) { return (!list_empty(&ps->list) && ps->dev->state != USB_STATE_NOTATTACHED); @@ -184,7 +184,7 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig) static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) { - struct dev_state *ps = file->private_data; + struct usb_dev_state *ps = file->private_data; struct usb_device *dev = ps->dev; ssize_t ret = 0; unsigned len; @@ -307,7 +307,7 @@ static void free_async(struct async *as) static void async_newpending(struct async *as) { - struct dev_state *ps = as->ps; + struct usb_dev_state *ps = as->ps; unsigned long flags; spin_lock_irqsave(&ps->lock, flags); @@ -317,7 +317,7 @@ static void async_newpending(struct async *as) static void async_removepending(struct async *as) { - struct dev_state *ps = as->ps; + struct usb_dev_state *ps = as->ps; unsigned long flags; spin_lock_irqsave(&ps->lock, flags); @@ -325,7 +325,7 @@ static void async_removepending(struct async *as) spin_unlock_irqrestore(&ps->lock, flags); } -static struct async *async_getcompleted(struct dev_state *ps) +static struct async *async_getcompleted(struct usb_dev_state *ps) { unsigned long flags; struct async *as = NULL; @@ -340,7 +340,7 @@ static struct async *async_getcompleted(struct dev_state *ps) return as; } -static struct async *async_getpending(struct dev_state *ps, +static struct async *async_getpending(struct usb_dev_state *ps, void __user *userurb) { struct async *as; @@ -448,7 +448,7 @@ static int copy_urb_data_to_user(u8 __user *userbuffer, struct urb *urb) #define AS_CONTINUATION 1 #define AS_UNLINK 2 -static void cancel_bulk_urbs(struct dev_state *ps, unsigned bulk_addr) +static void cancel_bulk_urbs(struct usb_dev_state *ps, unsigned bulk_addr) __releases(ps->lock) __acquires(ps->lock) { @@ -489,7 +489,7 @@ __acquires(ps->lock) static void async_completed(struct urb *urb) { struct async *as = urb->context; - struct dev_state *ps = as->ps; + struct usb_dev_state *ps = as->ps; struct siginfo sinfo; struct pid *pid = NULL; u32 secid = 0; @@ -529,7 +529,7 @@ static void async_completed(struct urb *urb) wake_up(&ps->wait); } -static void destroy_async(struct dev_state *ps, struct list_head *list) +static void destroy_async(struct usb_dev_state *ps, struct list_head *list) { struct urb *urb; struct async *as; @@ -551,7 +551,7 @@ static void destroy_async(struct dev_state *ps, struct list_head *list) spin_unlock_irqrestore(&ps->lock, flags); } -static void destroy_async_on_interface(struct dev_state *ps, +static void destroy_async_on_interface(struct usb_dev_state *ps, unsigned int ifnum) { struct list_head *p, *q, hitlist; @@ -566,7 +566,7 @@ static void destroy_async_on_interface(struct dev_state *ps, destroy_async(ps, &hitlist); } -static void destroy_all_async(struct dev_state *ps) +static void destroy_all_async(struct usb_dev_state *ps) { destroy_async(ps, &ps->async_pending); } @@ -585,7 +585,7 @@ static int driver_probe(struct usb_interface *intf, static void driver_disconnect(struct usb_interface *intf) { - struct dev_state *ps = usb_get_intfdata(intf); + struct usb_dev_state *ps = usb_get_intfdata(intf); unsigned int ifnum = intf->altsetting->desc.bInterfaceNumber; if (!ps) @@ -628,7 +628,7 @@ struct usb_driver usbfs_driver = { .resume = driver_resume, }; -static int claimintf(struct dev_state *ps, unsigned int ifnum) +static int claimintf(struct usb_dev_state *ps, unsigned int ifnum) { struct usb_device *dev = ps->dev; struct usb_interface *intf; @@ -650,7 +650,7 @@ static int claimintf(struct dev_state *ps, unsigned int ifnum) return err; } -static int releaseintf(struct dev_state *ps, unsigned int ifnum) +static int releaseintf(struct usb_dev_state *ps, unsigned int ifnum) { struct usb_device *dev; struct usb_interface *intf; @@ -670,7 +670,7 @@ static int releaseintf(struct dev_state *ps, unsigned int ifnum) return err; } -static int checkintf(struct dev_state *ps, unsigned int ifnum) +static int checkintf(struct usb_dev_state *ps, unsigned int ifnum) { if (ps->dev->state != USB_STATE_CONFIGURED) return -EHOSTUNREACH; @@ -710,7 +710,7 @@ static int findintfep(struct usb_device *dev, unsigned int ep) return -ENOENT; } -static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, +static int check_ctrlrecip(struct usb_dev_state *ps, unsigned int requesttype, unsigned int request, unsigned int index) { int ret = 0; @@ -769,6 +769,88 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, return ret; } +static struct usb_host_endpoint *ep_to_host_endpoint(struct usb_device *dev, + unsigned char ep) +{ + if (ep & USB_ENDPOINT_DIR_MASK) + return dev->ep_in[ep & USB_ENDPOINT_NUMBER_MASK]; + else + return dev->ep_out[ep & USB_ENDPOINT_NUMBER_MASK]; +} + +static int parse_usbdevfs_streams(struct usb_dev_state *ps, + struct usbdevfs_streams __user *streams, + unsigned int *num_streams_ret, + unsigned int *num_eps_ret, + struct usb_host_endpoint ***eps_ret, + struct usb_interface **intf_ret) +{ + unsigned int i, num_streams, num_eps; + struct usb_host_endpoint **eps; + struct usb_interface *intf = NULL; + unsigned char ep; + int ifnum, ret; + + if (get_user(num_streams, &streams->num_streams) || + get_user(num_eps, &streams->num_eps)) + return -EFAULT; + + if (num_eps < 1 || num_eps > USB_MAXENDPOINTS) + return -EINVAL; + + /* The XHCI controller allows max 2 ^ 16 streams */ + if (num_streams_ret && (num_streams < 2 || num_streams > 65536)) + return -EINVAL; + + eps = kmalloc(num_eps * sizeof(*eps), GFP_KERNEL); + if (!eps) + return -ENOMEM; + + for (i = 0; i < num_eps; i++) { + if (get_user(ep, &streams->eps[i])) { + ret = -EFAULT; + goto error; + } + eps[i] = ep_to_host_endpoint(ps->dev, ep); + if (!eps[i]) { + ret = -EINVAL; + goto error; + } + + /* usb_alloc/free_streams operate on an usb_interface */ + ifnum = findintfep(ps->dev, ep); + if (ifnum < 0) { + ret = ifnum; + goto error; + } + + if (i == 0) { + ret = checkintf(ps, ifnum); + if (ret < 0) + goto error; + intf = usb_ifnum_to_if(ps->dev, ifnum); + } else { + /* Verify all eps belong to the same interface */ + if (ifnum != intf->altsetting->desc.bInterfaceNumber) { + ret = -EINVAL; + goto error; + } + } + } + + if (num_streams_ret) + *num_streams_ret = num_streams; + *num_eps_ret = num_eps; + *eps_ret = eps; + *intf_ret = intf; + + return 0; + +error: + kfree(eps); + return ret; +} + static int match_devt(struct device *dev, void *data) { return dev->devt == (dev_t) (unsigned long) data; @@ -791,11 +873,11 @@ static struct usb_device *usbdev_lookup_by_devt(dev_t devt) static int usbdev_open(struct inode *inode, struct file *file) { struct usb_device *dev = NULL; - struct dev_state *ps; + struct usb_dev_state *ps; int ret; ret = -ENOMEM; - ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL); + ps = kmalloc(sizeof(struct usb_dev_state), GFP_KERNEL); if (!ps) goto out_free_ps; @@ -852,7 +934,7 @@ static int usbdev_open(struct inode *inode, struct file *file) static int usbdev_release(struct inode *inode, struct file *file) { - struct dev_state *ps = file->private_data; + struct usb_dev_state *ps = file->private_data; struct usb_device *dev = ps->dev; unsigned int ifnum; struct async *as; @@ -883,7 +965,7 @@ static int usbdev_release(struct inode *inode, struct file *file) return 0; } -static int proc_control(struct dev_state *ps, void __user *arg) +static int proc_control(struct usb_dev_state *ps, void __user *arg) { struct usb_device *dev = ps->dev; struct usbdevfs_ctrltransfer ctrl; @@ -914,10 +996,8 @@ static int proc_control(struct dev_state *ps, void __user *arg) snoop(&dev->dev, "control urb: bRequestType=%02x " "bRequest=%02x wValue=%04x " "wIndex=%04x wLength=%04x\n", - ctrl.bRequestType, ctrl.bRequest, - __le16_to_cpup(&ctrl.wValue), - __le16_to_cpup(&ctrl.wIndex), - __le16_to_cpup(&ctrl.wLength)); + ctrl.bRequestType, ctrl.bRequest, ctrl.wValue, + ctrl.wIndex, ctrl.wLength); if (ctrl.bRequestType & 0x80) { if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.wLength)) { @@ -972,7 +1052,7 @@ static int proc_control(struct dev_state *ps, void __user *arg) return ret; } -static int proc_bulk(struct dev_state *ps, void __user *arg) +static int proc_bulk(struct usb_dev_state *ps, void __user *arg) { struct usb_device *dev = ps->dev; struct usbdevfs_bulktransfer bulk; @@ -1045,7 +1125,21 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) return ret; } -static int proc_resetep(struct dev_state *ps, void __user *arg) +static void check_reset_of_active_ep(struct usb_device *udev, + unsigned int epnum, char *ioctl_name) +{ + struct usb_host_endpoint **eps; + struct usb_host_endpoint *ep; + + eps = (epnum & USB_DIR_IN) ? udev->ep_in : udev->ep_out; + ep = eps[epnum & 0x0f]; + if (ep && !list_empty(&ep->urb_list)) + dev_warn(&udev->dev, "Process %d (%s) called USBDEVFS_%s for active endpoint 0x%02x\n", + task_pid_nr(current), current->comm, + ioctl_name, epnum); +} + +static int proc_resetep(struct usb_dev_state *ps, void __user *arg) { unsigned int ep; int ret; @@ -1058,11 +1152,12 @@ static int proc_resetep(struct dev_state *ps, void __user *arg) ret = checkintf(ps, ret); if (ret) return ret; + check_reset_of_active_ep(ps->dev, ep, "RESETEP"); usb_reset_endpoint(ps->dev, ep); return 0; } -static int proc_clearhalt(struct dev_state *ps, void __user *arg) +static int proc_clearhalt(struct usb_dev_state *ps, void __user *arg) { unsigned int ep; int pipe; @@ -1076,6 +1171,7 @@ static int proc_clearhalt(struct dev_state *ps, void __user *arg) ret = checkintf(ps, ret); if (ret) return ret; + check_reset_of_active_ep(ps->dev, ep, "CLEAR_HALT"); if (ep & USB_DIR_IN) pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f); else @@ -1084,7 +1180,7 @@ static int proc_clearhalt(struct dev_state *ps, void __user *arg) return usb_clear_halt(ps->dev, pipe); } -static int proc_getdriver(struct dev_state *ps, void __user *arg) +static int proc_getdriver(struct usb_dev_state *ps, void __user *arg) { struct usbdevfs_getdriver gd; struct usb_interface *intf; @@ -1103,7 +1199,7 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg) return ret; } -static int proc_connectinfo(struct dev_state *ps, void __user *arg) +static int proc_connectinfo(struct usb_dev_state *ps, void __user *arg) { struct usbdevfs_connectinfo ci = { .devnum = ps->dev->devnum, @@ -1115,12 +1211,12 @@ static int proc_connectinfo(struct dev_state *ps, void __user *arg) return 0; } -static int proc_resetdevice(struct dev_state *ps) +static int proc_resetdevice(struct usb_dev_state *ps) { return usb_reset_device(ps->dev); } -static int proc_setintf(struct dev_state *ps, void __user *arg) +static int proc_setintf(struct usb_dev_state *ps, void __user *arg) { struct usbdevfs_setinterface setintf; int ret; @@ -1129,11 +1225,14 @@ static int proc_setintf(struct dev_state *ps, void __user *arg) return -EFAULT; if ((ret = checkintf(ps, setintf.interface))) return ret; + + destroy_async_on_interface(ps, setintf.interface); + return usb_set_interface(ps->dev, setintf.interface, setintf.altsetting); } -static int proc_setconfig(struct dev_state *ps, void __user *arg) +static int proc_setconfig(struct usb_dev_state *ps, void __user *arg) { int u; int status = 0; @@ -1181,7 +1280,7 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg) return status; } -static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, +static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb, struct usbdevfs_iso_packet_desc __user *iso_frame_desc, void __user *arg) { @@ -1191,6 +1290,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, struct usb_ctrlrequest *dr = NULL; unsigned int u, totlen, isofrmlen; int i, ret, is_in, num_sgs = 0, ifnum = -1; + int number_of_packets = 0; + unsigned int stream_id = 0; void *buf; if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP | @@ -1211,15 +1312,10 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, if (ret) return ret; } - if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) { - is_in = 1; - ep = ps->dev->ep_in[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; - } else { - is_in = 0; - ep = ps->dev->ep_out[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; - } + ep = ep_to_host_endpoint(ps->dev, uurb->endpoint); if (!ep) return -ENOENT; + is_in = (uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0; u = 0; switch(uurb->type) { @@ -1244,7 +1340,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, le16_to_cpup(&dr->wIndex)); if (ret) goto error; - uurb->number_of_packets = 0; uurb->buffer_length = le16_to_cpup(&dr->wLength); uurb->buffer += 8; if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) { @@ -1274,17 +1369,17 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, uurb->type = USBDEVFS_URB_TYPE_INTERRUPT; goto interrupt_urb; } - uurb->number_of_packets = 0; num_sgs = DIV_ROUND_UP(uurb->buffer_length, USB_SG_SIZE); if (num_sgs == 1 || num_sgs > ps->dev->bus->sg_tablesize) num_sgs = 0; + if (ep->streams) + stream_id = uurb->stream_id; break; case USBDEVFS_URB_TYPE_INTERRUPT: if (!usb_endpoint_xfer_int(&ep->desc)) return -EINVAL; interrupt_urb: - uurb->number_of_packets = 0; break; case USBDEVFS_URB_TYPE_ISO: @@ -1294,15 +1389,16 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return -EINVAL; if (!usb_endpoint_xfer_isoc(&ep->desc)) return -EINVAL; + number_of_packets = uurb->number_of_packets; isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * - uurb->number_of_packets; + number_of_packets; if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL))) return -ENOMEM; if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) { ret = -EFAULT; goto error; } - for (totlen = u = 0; u < uurb->number_of_packets; u++) { + for (totlen = u = 0; u < number_of_packets; u++) { /* * arbitrary limit need for USB 3.0 * bMaxBurst (0~15 allowed, 1~16 packets) @@ -1333,7 +1429,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, ret = -EFAULT; goto error; } - as = alloc_async(uurb->number_of_packets); + as = alloc_async(number_of_packets); if (!as) { ret = -ENOMEM; goto error; @@ -1427,7 +1523,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, as->urb->setup_packet = (unsigned char *)dr; dr = NULL; as->urb->start_frame = uurb->start_frame; - as->urb->number_of_packets = uurb->number_of_packets; + as->urb->number_of_packets = number_of_packets; + as->urb->stream_id = stream_id; if (uurb->type == USBDEVFS_URB_TYPE_ISO || ps->dev->speed == USB_SPEED_HIGH) as->urb->interval = 1 << min(15, ep->desc.bInterval - 1); @@ -1435,7 +1532,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, as->urb->interval = ep->desc.bInterval; as->urb->context = as; as->urb->complete = async_completed; - for (totlen = u = 0; u < uurb->number_of_packets; u++) { + for (totlen = u = 0; u < number_of_packets; u++) { as->urb->iso_frame_desc[u].offset = totlen; as->urb->iso_frame_desc[u].length = isopkt[u].length; totlen += isopkt[u].length; @@ -1510,7 +1607,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return ret; } -static int proc_submiturb(struct dev_state *ps, void __user *arg) +static int proc_submiturb(struct usb_dev_state *ps, void __user *arg) { struct usbdevfs_urb uurb; @@ -1522,7 +1619,7 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg) arg); } -static int proc_unlinkurb(struct dev_state *ps, void __user *arg) +static int proc_unlinkurb(struct usb_dev_state *ps, void __user *arg) { struct urb *urb; struct async *as; @@ -1582,7 +1679,7 @@ err_out: return -EFAULT; } -static struct async *reap_as(struct dev_state *ps) +static struct async *reap_as(struct usb_dev_state *ps) { DECLARE_WAITQUEUE(wait, current); struct async *as = NULL; @@ -1605,7 +1702,7 @@ static struct async *reap_as(struct dev_state *ps) return as; } -static int proc_reapurb(struct dev_state *ps, void __user *arg) +static int proc_reapurb(struct usb_dev_state *ps, void __user *arg) { struct async *as = reap_as(ps); if (as) { @@ -1618,7 +1715,7 @@ static int proc_reapurb(struct dev_state *ps, void __user *arg) return -EIO; } -static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg) +static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg) { int retval; struct async *as; @@ -1633,37 +1730,37 @@ static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg) } #ifdef CONFIG_COMPAT -static int proc_control_compat(struct dev_state *ps, +static int proc_control_compat(struct usb_dev_state *ps, struct usbdevfs_ctrltransfer32 __user *p32) { - struct usbdevfs_ctrltransfer __user *p; - __u32 udata; - p = compat_alloc_user_space(sizeof(*p)); - if (copy_in_user(p, p32, (sizeof(*p32) - sizeof(compat_caddr_t))) || - get_user(udata, &p32->data) || + struct usbdevfs_ctrltransfer __user *p; + __u32 udata; + p = compat_alloc_user_space(sizeof(*p)); + if (copy_in_user(p, p32, (sizeof(*p32) - sizeof(compat_caddr_t))) || + get_user(udata, &p32->data) || put_user(compat_ptr(udata), &p->data)) return -EFAULT; - return proc_control(ps, p); + return proc_control(ps, p); } -static int proc_bulk_compat(struct dev_state *ps, +static int proc_bulk_compat(struct usb_dev_state *ps, struct usbdevfs_bulktransfer32 __user *p32) { - struct usbdevfs_bulktransfer __user *p; - compat_uint_t n; - compat_caddr_t addr; + struct usbdevfs_bulktransfer __user *p; + compat_uint_t n; + compat_caddr_t addr; - p = compat_alloc_user_space(sizeof(*p)); + p = compat_alloc_user_space(sizeof(*p)); - if (get_user(n, &p32->ep) || put_user(n, &p->ep) || - get_user(n, &p32->len) || put_user(n, &p->len) || - get_user(n, &p32->timeout) || put_user(n, &p->timeout) || - get_user(addr, &p32->data) || put_user(compat_ptr(addr), &p->data)) - return -EFAULT; + if (get_user(n, &p32->ep) || put_user(n, &p->ep) || + get_user(n, &p32->len) || put_user(n, &p->len) || + get_user(n, &p32->timeout) || put_user(n, &p->timeout) || + get_user(addr, &p32->data) || put_user(compat_ptr(addr), &p->data)) + return -EFAULT; - return proc_bulk(ps, p); + return proc_bulk(ps, p); } -static int proc_disconnectsignal_compat(struct dev_state *ps, void __user *arg) +static int proc_disconnectsignal_compat(struct usb_dev_state *ps, void __user *arg) { struct usbdevfs_disconnectsignal32 ds; @@ -1701,7 +1798,7 @@ static int get_urb32(struct usbdevfs_urb *kurb, return 0; } -static int proc_submiturb_compat(struct dev_state *ps, void __user *arg) +static int proc_submiturb_compat(struct usb_dev_state *ps, void __user *arg) { struct usbdevfs_urb uurb; @@ -1747,7 +1844,7 @@ static int processcompl_compat(struct async *as, void __user * __user *arg) return 0; } -static int proc_reapurb_compat(struct dev_state *ps, void __user *arg) +static int proc_reapurb_compat(struct usb_dev_state *ps, void __user *arg) { struct async *as = reap_as(ps); if (as) { @@ -1760,7 +1857,7 @@ static int proc_reapurb_compat(struct dev_state *ps, void __user *arg) return -EIO; } -static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg) +static int proc_reapurbnonblock_compat(struct usb_dev_state *ps, void __user *arg) { int retval; struct async *as; @@ -1777,7 +1874,7 @@ static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg) #endif -static int proc_disconnectsignal(struct dev_state *ps, void __user *arg) +static int proc_disconnectsignal(struct usb_dev_state *ps, void __user *arg) { struct usbdevfs_disconnectsignal ds; @@ -1788,7 +1885,7 @@ static int proc_disconnectsignal(struct dev_state *ps, void __user *arg) return 0; } -static int proc_claiminterface(struct dev_state *ps, void __user *arg) +static int proc_claiminterface(struct usb_dev_state *ps, void __user *arg) { unsigned int ifnum; @@ -1797,7 +1894,7 @@ static int proc_claiminterface(struct dev_state *ps, void __user *arg) return claimintf(ps, ifnum); } -static int proc_releaseinterface(struct dev_state *ps, void __user *arg) +static int proc_releaseinterface(struct usb_dev_state *ps, void __user *arg) { unsigned int ifnum; int ret; @@ -1810,7 +1907,7 @@ static int proc_releaseinterface(struct dev_state *ps, void __user *arg) return 0; } -static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) +static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl) { int size; void *buf = NULL; @@ -1886,7 +1983,7 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) return retval; } -static int proc_ioctl_default(struct dev_state *ps, void __user *arg) +static int proc_ioctl_default(struct usb_dev_state *ps, void __user *arg) { struct usbdevfs_ioctl ctrl; @@ -1896,7 +1993,7 @@ static int proc_ioctl_default(struct dev_state *ps, void __user *arg) } #ifdef CONFIG_COMPAT -static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg) +static int proc_ioctl_compat(struct usb_dev_state *ps, compat_uptr_t arg) { struct usbdevfs_ioctl32 __user *uioc; struct usbdevfs_ioctl ctrl; @@ -1914,7 +2011,7 @@ static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg) } #endif -static int proc_claim_port(struct dev_state *ps, void __user *arg) +static int proc_claim_port(struct usb_dev_state *ps, void __user *arg) { unsigned portnum; int rc; @@ -1928,7 +2025,7 @@ static int proc_claim_port(struct dev_state *ps, void __user *arg) return rc; } -static int proc_release_port(struct dev_state *ps, void __user *arg) +static int proc_release_port(struct usb_dev_state *ps, void __user *arg) { unsigned portnum; @@ -1937,7 +2034,7 @@ static int proc_release_port(struct dev_state *ps, void __user *arg) return usb_hub_release_port(ps->dev, portnum, ps); } -static int proc_get_capabilities(struct dev_state *ps, void __user *arg) +static int proc_get_capabilities(struct usb_dev_state *ps, void __user *arg) { __u32 caps; @@ -1953,7 +2050,7 @@ static int proc_get_capabilities(struct dev_state *ps, void __user *arg) return 0; } -static int proc_disconnect_claim(struct dev_state *ps, void __user *arg) +static int proc_disconnect_claim(struct usb_dev_state *ps, void __user *arg) { struct usbdevfs_disconnect_claim dc; struct usb_interface *intf; @@ -1985,6 +2082,45 @@ static int proc_disconnect_claim(struct dev_state *ps, void __user *arg) return claimintf(ps, dc.interface); } +static int proc_alloc_streams(struct usb_dev_state *ps, void __user *arg) +{ + unsigned num_streams, num_eps; + struct usb_host_endpoint **eps; + struct usb_interface *intf; + int r; + + r = parse_usbdevfs_streams(ps, arg, &num_streams, &num_eps, + &eps, &intf); + if (r) + return r; + + destroy_async_on_interface(ps, + intf->altsetting[0].desc.bInterfaceNumber); + + r = usb_alloc_streams(intf, eps, num_eps, num_streams, GFP_KERNEL); + kfree(eps); + return r; +} + +static int proc_free_streams(struct usb_dev_state *ps, void __user *arg) +{ + unsigned num_eps; + struct usb_host_endpoint **eps; + struct usb_interface *intf; + int r; + + r = parse_usbdevfs_streams(ps, arg, NULL, &num_eps, &eps, &intf); + if (r) + return r; + + destroy_async_on_interface(ps, + intf->altsetting[0].desc.bInterfaceNumber); + + r = usb_free_streams(intf, eps, num_eps, GFP_KERNEL); + kfree(eps); + return r; +} + /* * NOTE: All requests here that have interface numbers as parameters * are assuming that somehow the configuration has been prevented from @@ -1993,7 +2129,7 @@ static int proc_disconnect_claim(struct dev_state *ps, void __user *arg) static long usbdev_do_ioctl(struct file *file, unsigned int cmd, void __user *p) { - struct dev_state *ps = file->private_data; + struct usb_dev_state *ps = file->private_data; struct inode *inode = file_inode(file); struct usb_device *dev = ps->dev; int ret = -ENOTTY; @@ -2161,6 +2297,12 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd, case USBDEVFS_DISCONNECT_CLAIM: ret = proc_disconnect_claim(ps, p); break; + case USBDEVFS_ALLOC_STREAMS: + ret = proc_alloc_streams(ps, p); + break; + case USBDEVFS_FREE_STREAMS: + ret = proc_free_streams(ps, p); + break; } usb_unlock_device(dev); if (ret >= 0) @@ -2194,7 +2336,7 @@ static long usbdev_compat_ioctl(struct file *file, unsigned int cmd, static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wait) { - struct dev_state *ps = file->private_data; + struct usb_dev_state *ps = file->private_data; unsigned int mask = 0; poll_wait(file, &ps->wait, wait); @@ -2220,11 +2362,11 @@ const struct file_operations usbdev_file_operations = { static void usbdev_remove(struct usb_device *udev) { - struct dev_state *ps; + struct usb_dev_state *ps; struct siginfo sinfo; while (!list_empty(&udev->filelist)) { - ps = list_entry(udev->filelist.next, struct dev_state, list); + ps = list_entry(udev->filelist.next, struct usb_dev_state, list); destroy_all_async(ps); wake_up_all(&ps->wait); list_del_init(&ps->list); diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index f7841d44fed..4aeb10034de 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -37,6 +37,7 @@ * and cause the driver to probe for all devices again. */ ssize_t usb_store_new_id(struct usb_dynids *dynids, + const struct usb_device_id *id_table, struct device_driver *driver, const char *buf, size_t count) { @@ -44,11 +45,12 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids, u32 idVendor = 0; u32 idProduct = 0; unsigned int bInterfaceClass = 0; + u32 refVendor, refProduct; int fields = 0; int retval = 0; - fields = sscanf(buf, "%x %x %x", &idVendor, &idProduct, - &bInterfaceClass); + fields = sscanf(buf, "%x %x %x %x %x", &idVendor, &idProduct, + &bInterfaceClass, &refVendor, &refProduct); if (fields < 2) return -EINVAL; @@ -60,11 +62,36 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids, dynid->id.idVendor = idVendor; dynid->id.idProduct = idProduct; dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE; - if (fields == 3) { + if (fields > 2 && bInterfaceClass) { + if (bInterfaceClass > 255) { + retval = -EINVAL; + goto fail; + } + dynid->id.bInterfaceClass = (u8)bInterfaceClass; dynid->id.match_flags |= USB_DEVICE_ID_MATCH_INT_CLASS; } + if (fields > 4) { + const struct usb_device_id *id = id_table; + + if (!id) { + retval = -ENODEV; + goto fail; + } + + for (; id->match_flags; id++) + if (id->idVendor == refVendor && id->idProduct == refProduct) + break; + + if (id->match_flags) { + dynid->id.driver_info = id->driver_info; + } else { + retval = -ENODEV; + goto fail; + } + } + spin_lock(&dynids->lock); list_add_tail(&dynid->node, &dynids->list); spin_unlock(&dynids->lock); @@ -74,6 +101,10 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids, if (retval) return retval; return count; + +fail: + kfree(dynid); + return retval; } EXPORT_SYMBOL_GPL(usb_store_new_id); @@ -106,7 +137,7 @@ static ssize_t new_id_store(struct device_driver *driver, { struct usb_driver *usb_drv = to_usb_driver(driver); - return usb_store_new_id(&usb_drv->dynids, driver, buf, count); + return usb_store_new_id(&usb_drv->dynids, usb_drv->id_table, driver, buf, count); } static DRIVER_ATTR_RW(new_id); @@ -281,9 +312,9 @@ static int usb_probe_interface(struct device *dev) return error; } - id = usb_match_id(intf, driver->id_table); + id = usb_match_dynamic_id(intf, driver); if (!id) - id = usb_match_dynamic_id(intf, driver); + id = usb_match_id(intf, driver->id_table); if (!id) return error; @@ -369,8 +400,9 @@ static int usb_unbind_interface(struct device *dev) { struct usb_driver *driver = to_usb_driver(dev->driver); struct usb_interface *intf = to_usb_interface(dev); + struct usb_host_endpoint *ep, **eps = NULL; struct usb_device *udev; - int error, r, lpm_disable_error; + int i, j, error, r, lpm_disable_error; intf->condition = USB_INTERFACE_UNBINDING; @@ -394,6 +426,26 @@ static int usb_unbind_interface(struct device *dev) driver->disconnect(intf); usb_cancel_queued_reset(intf); + /* Free streams */ + for (i = 0, j = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) { + ep = &intf->cur_altsetting->endpoint[i]; + if (ep->streams == 0) + continue; + if (j == 0) { + eps = kmalloc(USB_MAXENDPOINTS * sizeof(void *), + GFP_KERNEL); + if (!eps) { + dev_warn(dev, "oom, leaking streams\n"); + break; + } + } + eps[j++] = ep; + } + if (j) { + usb_free_streams(intf, eps, j, GFP_KERNEL); + kfree(eps); + } + /* Reset other interface state. * We cannot do a Set-Interface if the device is suspended or * if it is prepared for a system sleep (since installing a new @@ -839,7 +891,7 @@ int usb_register_device_driver(struct usb_device_driver *new_udriver, return -ENODEV; new_udriver->drvwrap.for_devices = 1; - new_udriver->drvwrap.driver.name = (char *) new_udriver->name; + new_udriver->drvwrap.driver.name = new_udriver->name; new_udriver->drvwrap.driver.bus = &usb_bus_type; new_udriver->drvwrap.driver.probe = usb_probe_device; new_udriver->drvwrap.driver.remove = usb_unbind_device; @@ -900,7 +952,7 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner, return -ENODEV; new_driver->drvwrap.for_devices = 0; - new_driver->drvwrap.driver.name = (char *) new_driver->name; + new_driver->drvwrap.driver.name = new_driver->name; new_driver->drvwrap.driver.bus = &usb_bus_type; new_driver->drvwrap.driver.probe = usb_probe_interface; new_driver->drvwrap.driver.remove = usb_unbind_interface; @@ -959,8 +1011,7 @@ EXPORT_SYMBOL_GPL(usb_deregister); * it doesn't support pre_reset/post_reset/reset_resume or * because it doesn't support suspend/resume. * - * The caller must hold @intf's device's lock, but not its pm_mutex - * and not @intf->dev.sem. + * The caller must hold @intf's device's lock, but not @intf's lock. */ void usb_forced_unbind_intf(struct usb_interface *intf) { @@ -973,16 +1024,37 @@ void usb_forced_unbind_intf(struct usb_interface *intf) intf->needs_binding = 1; } +/* + * Unbind drivers for @udev's marked interfaces. These interfaces have + * the needs_binding flag set, for example by usb_resume_interface(). + * + * The caller must hold @udev's device lock. + */ +static void unbind_marked_interfaces(struct usb_device *udev) +{ + struct usb_host_config *config; + int i; + struct usb_interface *intf; + + config = udev->actconfig; + if (config) { + for (i = 0; i < config->desc.bNumInterfaces; ++i) { + intf = config->interface[i]; + if (intf->dev.driver && intf->needs_binding) + usb_forced_unbind_intf(intf); + } + } +} + /* Delayed forced unbinding of a USB interface driver and scan * for rebinding. * - * The caller must hold @intf's device's lock, but not its pm_mutex - * and not @intf->dev.sem. + * The caller must hold @intf's device's lock, but not @intf's lock. * * Note: Rebinds will be skipped if a system sleep transition is in * progress and the PM "complete" callback hasn't occurred yet. */ -void usb_rebind_intf(struct usb_interface *intf) +static void usb_rebind_intf(struct usb_interface *intf) { int rc; @@ -999,68 +1071,66 @@ void usb_rebind_intf(struct usb_interface *intf) } } -#ifdef CONFIG_PM - -/* Unbind drivers for @udev's interfaces that don't support suspend/resume - * There is no check for reset_resume here because it can be determined - * only during resume whether reset_resume is needed. +/* + * Rebind drivers to @udev's marked interfaces. These interfaces have + * the needs_binding flag set. * * The caller must hold @udev's device lock. */ -static void unbind_no_pm_drivers_interfaces(struct usb_device *udev) +static void rebind_marked_interfaces(struct usb_device *udev) { struct usb_host_config *config; int i; struct usb_interface *intf; - struct usb_driver *drv; config = udev->actconfig; if (config) { for (i = 0; i < config->desc.bNumInterfaces; ++i) { intf = config->interface[i]; - - if (intf->dev.driver) { - drv = to_usb_driver(intf->dev.driver); - if (!drv->suspend || !drv->resume) - usb_forced_unbind_intf(intf); - } + if (intf->needs_binding) + usb_rebind_intf(intf); } } } -/* Unbind drivers for @udev's interfaces that failed to support reset-resume. - * These interfaces have the needs_binding flag set by usb_resume_interface(). +/* + * Unbind all of @udev's marked interfaces and then rebind all of them. + * This ordering is necessary because some drivers claim several interfaces + * when they are first probed. * * The caller must hold @udev's device lock. */ -static void unbind_no_reset_resume_drivers_interfaces(struct usb_device *udev) +void usb_unbind_and_rebind_marked_interfaces(struct usb_device *udev) { - struct usb_host_config *config; - int i; - struct usb_interface *intf; - - config = udev->actconfig; - if (config) { - for (i = 0; i < config->desc.bNumInterfaces; ++i) { - intf = config->interface[i]; - if (intf->dev.driver && intf->needs_binding) - usb_forced_unbind_intf(intf); - } - } + unbind_marked_interfaces(udev); + rebind_marked_interfaces(udev); } -static void do_rebind_interfaces(struct usb_device *udev) +#ifdef CONFIG_PM + +/* Unbind drivers for @udev's interfaces that don't support suspend/resume + * There is no check for reset_resume here because it can be determined + * only during resume whether reset_resume is needed. + * + * The caller must hold @udev's device lock. + */ +static void unbind_no_pm_drivers_interfaces(struct usb_device *udev) { struct usb_host_config *config; int i; struct usb_interface *intf; + struct usb_driver *drv; config = udev->actconfig; if (config) { for (i = 0; i < config->desc.bNumInterfaces; ++i) { intf = config->interface[i]; - if (intf->needs_binding) - usb_rebind_intf(intf); + + if (intf->dev.driver) { + drv = to_usb_driver(intf->dev.driver); + if (!drv->suspend || !drv->resume) + usb_forced_unbind_intf(intf); + } } } } @@ -1179,8 +1249,8 @@ static int usb_resume_interface(struct usb_device *udev, "reset_resume", status); } else { intf->needs_binding = 1; - dev_warn(&intf->dev, "no %s for driver %s?\n", - "reset_resume", driver->name); + dev_dbg(&intf->dev, "no reset_resume for driver %s?\n", + driver->name); } } else { status = driver->resume(intf); @@ -1389,7 +1459,7 @@ int usb_resume_complete(struct device *dev) * whose needs_binding flag is set */ if (udev->state != USB_STATE_NOTATTACHED) - do_rebind_interfaces(udev); + rebind_marked_interfaces(udev); return 0; } @@ -1411,7 +1481,7 @@ int usb_resume(struct device *dev, pm_message_t msg) pm_runtime_disable(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); - unbind_no_reset_resume_drivers_interfaces(udev); + unbind_marked_interfaces(udev); } /* Avoid PM error messages for devices disconnected while suspended @@ -1752,10 +1822,13 @@ int usb_runtime_suspend(struct device *dev) if (status == -EAGAIN || status == -EBUSY) usb_mark_last_busy(udev); - /* The PM core reacts badly unless the return code is 0, - * -EAGAIN, or -EBUSY, so always return -EBUSY on an error. + /* + * The PM core reacts badly unless the return code is 0, + * -EAGAIN, or -EBUSY, so always return -EBUSY on an error + * (except for root hubs, because they don't suspend through + * an upstream port like other USB devices). */ - if (status != 0) + if (status != 0 && udev->parent) return -EBUSY; return status; } @@ -1790,6 +1863,9 @@ int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) struct usb_hcd *hcd = bus_to_hcd(udev->bus); int ret = -EPERM; + if (enable && !udev->usb2_hw_lpm_allowed) + return 0; + if (hcd->driver->set_usb2_hw_lpm) { ret = hcd->driver->set_usb2_hw_lpm(hcd, udev, enable); if (!ret) diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index 7421888087a..ea337a718cc 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -8,7 +8,7 @@ * (C) Copyright Deti Fliegl 1999 (new USB architecture) * (C) Copyright Randy Dunlap 2000 * (C) Copyright David Brownell 2000-2001 (kernel hotplug, usb_device_id, - more docs, etc) + * more docs, etc) * (C) Copyright Yggdrasil Computing, Inc. 2000 * (usb_device_id matching changes by Adam J. Richter) * (C) Copyright Greg Kroah-Hartman 2002-2003 @@ -27,29 +27,21 @@ static const struct file_operations *usb_minors[MAX_USB_MINORS]; static DECLARE_RWSEM(minor_rwsem); -static int usb_open(struct inode * inode, struct file * file) +static int usb_open(struct inode *inode, struct file *file) { - int minor = iminor(inode); - const struct file_operations *c; int err = -ENODEV; - const struct file_operations *old_fops, *new_fops = NULL; + const struct file_operations *new_fops; down_read(&minor_rwsem); - c = usb_minors[minor]; + new_fops = fops_get(usb_minors[iminor(inode)]); - if (!c || !(new_fops = fops_get(c))) + if (!new_fops) goto done; - old_fops = file->f_op; - file->f_op = new_fops; + replace_fops(file, new_fops); /* Curiouser and curiouser... NULL ->open() as "no device" ? */ if (file->f_op->open) - err = file->f_op->open(inode,file); - if (err) { - fops_put(file->f_op); - file->f_op = fops_get(old_fops); - } - fops_put(old_fops); + err = file->f_op->open(inode, file); done: up_read(&minor_rwsem); return err; @@ -166,7 +158,7 @@ int usb_register_dev(struct usb_interface *intf, char *temp; #ifdef CONFIG_USB_DYNAMIC_MINORS - /* + /* * We don't care what the device tries to start at, we want to start * at zero to pack the devices into the smallest available space with * no holes in the minor range. diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index acbfeb0a011..358ca8dd784 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -155,6 +155,7 @@ int usb_choose_configuration(struct usb_device *udev) } return i; } +EXPORT_SYMBOL_GPL(usb_choose_configuration); static int generic_probe(struct usb_device *udev) { diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index b9d3c43e385..82044b5d611 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -75,7 +75,7 @@ static void for_each_companion(struct pci_dev *pdev, struct usb_hcd *hcd, PCI_SLOT(companion->devfn) != slot) continue; companion_hcd = pci_get_drvdata(companion); - if (!companion_hcd) + if (!companion_hcd || !companion_hcd->self.root_hub) continue; fn(pdev, hcd, companion, companion_hcd); } @@ -192,7 +192,6 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) if (pci_enable_device(dev) < 0) return -ENODEV; - dev->current_state = PCI_D0; /* * The xHCI driver has its own irq management @@ -215,6 +214,9 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) goto disable_pci; } + hcd->amd_resume_bug = (usb_hcd_amd_remote_wakeup_quirk(dev) && + driver->flags & (HCD_USB11 | HCD_USB3)) ? 1 : 0; + if (driver->flags & HCD_MEMORY) { /* EHCI, OHCI */ hcd->rsrc_start = pci_resource_start(dev, 0); @@ -279,6 +281,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) if (retval != 0) goto unmap_registers; + device_wakeup_enable(hcd->self.controller); if (pci_dev_run_wake(dev)) pm_runtime_put_noidle(&dev->dev); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index d6a8d23f047..bec31e2efb8 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -6,7 +6,7 @@ * (C) Copyright Deti Fliegl 1999 * (C) Copyright Randy Dunlap 2000 * (C) Copyright David Brownell 2000-2002 - * + * * 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 @@ -40,9 +40,11 @@ #include <linux/platform_device.h> #include <linux/workqueue.h> #include <linux/pm_runtime.h> +#include <linux/types.h> #include <linux/usb.h> #include <linux/usb/hcd.h> +#include <linux/usb/phy.h> #include "usb.h" @@ -92,10 +94,7 @@ EXPORT_SYMBOL_GPL (usb_bus_list); /* used when allocating bus numbers */ #define USB_MAXBUS 64 -struct usb_busmap { - unsigned long busmap [USB_MAXBUS / (8*sizeof (unsigned long))]; -}; -static struct usb_busmap busmap; +static DECLARE_BITMAP(busmap, USB_MAXBUS); /* used when updating list of hcds */ DEFINE_MUTEX(usb_bus_list_lock); /* exported only for usbfs */ @@ -171,7 +170,7 @@ static const u8 usb25_rh_dev_descriptor[18] = { }; /* usb 2.0 root hub device descriptor */ -static const u8 usb2_rh_dev_descriptor [18] = { +static const u8 usb2_rh_dev_descriptor[18] = { 0x12, /* __u8 bLength; */ 0x01, /* __u8 bDescriptorType; Device */ 0x00, 0x02, /* __le16 bcdUSB; v2.0 */ @@ -194,7 +193,7 @@ static const u8 usb2_rh_dev_descriptor [18] = { /* no usb 2.0 root hub "device qualifier" descriptor: one speed only */ /* usb 1.1 root hub device descriptor */ -static const u8 usb11_rh_dev_descriptor [18] = { +static const u8 usb11_rh_dev_descriptor[18] = { 0x12, /* __u8 bLength; */ 0x01, /* __u8 bDescriptorType; Device */ 0x10, 0x01, /* __le16 bcdUSB; v1.1 */ @@ -219,7 +218,7 @@ static const u8 usb11_rh_dev_descriptor [18] = { /* Configuration descriptors for our root hubs */ -static const u8 fs_rh_config_descriptor [] = { +static const u8 fs_rh_config_descriptor[] = { /* one configuration */ 0x09, /* __u8 bLength; */ @@ -228,13 +227,13 @@ static const u8 fs_rh_config_descriptor [] = { 0x01, /* __u8 bNumInterfaces; (1) */ 0x01, /* __u8 bConfigurationValue; */ 0x00, /* __u8 iConfiguration; */ - 0xc0, /* __u8 bmAttributes; + 0xc0, /* __u8 bmAttributes; Bit 7: must be set, 6: Self-powered, 5: Remote wakeup, 4..0: resvd */ 0x00, /* __u8 MaxPower; */ - + /* USB 1.1: * USB 2.0, single TT organization (mandatory): * one interface, protocol 0 @@ -256,17 +255,17 @@ static const u8 fs_rh_config_descriptor [] = { 0x00, /* __u8 if_bInterfaceSubClass; */ 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ 0x00, /* __u8 if_iInterface; */ - + /* one endpoint (status change endpoint) */ 0x07, /* __u8 ep_bLength; */ 0x05, /* __u8 ep_bDescriptorType; Endpoint */ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* __u8 ep_bmAttributes; Interrupt */ - 0x02, 0x00, /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ + 0x03, /* __u8 ep_bmAttributes; Interrupt */ + 0x02, 0x00, /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ 0xff /* __u8 ep_bInterval; (255ms -- usb 2.0 spec) */ }; -static const u8 hs_rh_config_descriptor [] = { +static const u8 hs_rh_config_descriptor[] = { /* one configuration */ 0x09, /* __u8 bLength; */ @@ -275,13 +274,13 @@ static const u8 hs_rh_config_descriptor [] = { 0x01, /* __u8 bNumInterfaces; (1) */ 0x01, /* __u8 bConfigurationValue; */ 0x00, /* __u8 iConfiguration; */ - 0xc0, /* __u8 bmAttributes; + 0xc0, /* __u8 bmAttributes; Bit 7: must be set, 6: Self-powered, 5: Remote wakeup, 4..0: resvd */ 0x00, /* __u8 MaxPower; */ - + /* USB 1.1: * USB 2.0, single TT organization (mandatory): * one interface, protocol 0 @@ -303,12 +302,12 @@ static const u8 hs_rh_config_descriptor [] = { 0x00, /* __u8 if_bInterfaceSubClass; */ 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ 0x00, /* __u8 if_iInterface; */ - + /* one endpoint (status change endpoint) */ 0x07, /* __u8 ep_bLength; */ 0x05, /* __u8 ep_bDescriptorType; Endpoint */ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* __u8 ep_bmAttributes; Interrupt */ + 0x03, /* __u8 ep_bmAttributes; Interrupt */ /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) * see hub.c:hub_configure() for details. */ (USB_MAXCHILDREN + 1 + 7) / 8, 0x00, @@ -428,7 +427,7 @@ rh_string(int id, struct usb_hcd const *hcd, u8 *data, unsigned len) char const *s; static char const langids[4] = {4, USB_DT_STRING, 0x09, 0x04}; - // language ids + /* language ids */ switch (id) { case 0: /* Array of LANGID codes (0x0409 is MSFT-speak for "en-us") */ @@ -464,7 +463,7 @@ rh_string(int id, struct usb_hcd const *hcd, u8 *data, unsigned len) static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) { struct usb_ctrlrequest *cmd; - u16 typeReq, wValue, wIndex, wLength; + u16 typeReq, wValue, wIndex, wLength; u8 *ubuf = urb->transfer_buffer; unsigned len = 0; int status; @@ -526,10 +525,10 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) */ case DeviceRequest | USB_REQ_GET_STATUS: - tbuf [0] = (device_may_wakeup(&hcd->self.root_hub->dev) + tbuf[0] = (device_may_wakeup(&hcd->self.root_hub->dev) << USB_DEVICE_REMOTE_WAKEUP) | (1 << USB_DEVICE_SELF_POWERED); - tbuf [1] = 0; + tbuf[1] = 0; len = 2; break; case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: @@ -546,7 +545,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) goto error; break; case DeviceRequest | USB_REQ_GET_CONFIGURATION: - tbuf [0] = 1; + tbuf[0] = 1; len = 1; /* FALLTHROUGH */ case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: @@ -609,13 +608,13 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) } break; case DeviceRequest | USB_REQ_GET_INTERFACE: - tbuf [0] = 0; + tbuf[0] = 0; len = 1; /* FALLTHROUGH */ case DeviceOutRequest | USB_REQ_SET_INTERFACE: break; case DeviceOutRequest | USB_REQ_SET_ADDRESS: - // wValue == urb->dev->devaddr + /* wValue == urb->dev->devaddr */ dev_dbg (hcd->self.controller, "root hub device address %d\n", wValue); break; @@ -625,9 +624,9 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) /* ENDPOINT REQUESTS */ case EndpointRequest | USB_REQ_GET_STATUS: - // ENDPOINT_HALT flag - tbuf [0] = 0; - tbuf [1] = 0; + /* ENDPOINT_HALT flag */ + tbuf[0] = 0; + tbuf[1] = 0; len = 2; /* FALLTHROUGH */ case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: @@ -683,7 +682,7 @@ error: if (urb->transfer_buffer_length < len) len = urb->transfer_buffer_length; urb->actual_length = len; - // always USB_DIR_IN, toward host + /* always USB_DIR_IN, toward host */ memcpy (ubuf, bufp, len); /* report whether RH hardware supports remote wakeup */ @@ -877,11 +876,11 @@ static ssize_t authorized_default_store(struct device *dev, usb_hcd = bus_to_hcd(usb_bus); result = sscanf(buf, "%u\n", &val); if (result == 1) { - usb_hcd->authorized_default = val? 1 : 0; + usb_hcd->authorized_default = val ? 1 : 0; result = size; - } - else + } else { result = -EINVAL; + } return result; } static DEVICE_ATTR_RW(authorized_default); @@ -919,6 +918,7 @@ static void usb_bus_init (struct usb_bus *bus) bus->bandwidth_allocated = 0; bus->bandwidth_int_reqs = 0; bus->bandwidth_isoc_reqs = 0; + mutex_init(&bus->usb_address0_mutex); INIT_LIST_HEAD (&bus->bus_list); } @@ -941,12 +941,12 @@ static int usb_register_bus(struct usb_bus *bus) int busnum; mutex_lock(&usb_bus_list_lock); - busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1); + busnum = find_next_zero_bit(busmap, USB_MAXBUS, 1); if (busnum >= USB_MAXBUS) { printk (KERN_ERR "%s: too many buses\n", usbcore_name); goto error_find_busnum; } - set_bit (busnum, busmap.busmap); + set_bit(busnum, busmap); bus->busnum = busnum; /* Add it to the local list of buses */ @@ -987,7 +987,7 @@ static void usb_deregister_bus (struct usb_bus *bus) usb_notify_remove_bus(bus); - clear_bit (bus->busnum, busmap.busmap); + clear_bit(bus->busnum, busmap); } /** @@ -1120,21 +1120,21 @@ long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount) case USB_SPEED_LOW: /* INTR only */ if (is_input) { tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L; - return (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); + return 64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp; } else { tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L; - return (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); + return 64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp; } case USB_SPEED_FULL: /* ISOC or INTR */ if (isoc) { tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; - return (((is_input) ? 7268L : 6265L) + BW_HOST_DELAY + tmp); + return ((is_input) ? 7268L : 6265L) + BW_HOST_DELAY + tmp; } else { tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; - return (9107L + BW_HOST_DELAY + tmp); + return 9107L + BW_HOST_DELAY + tmp; } case USB_SPEED_HIGH: /* ISOC or INTR */ - // FIXME adjust for input vs output + /* FIXME adjust for input vs output */ if (isoc) tmp = HS_NSECS_ISO (bytecount); else @@ -1298,7 +1298,7 @@ EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep); * DMA framework is dma_declare_coherent_memory() * * - So we use that, even though the primary requirement - * is that the memory be "local" (hence addressible + * is that the memory be "local" (hence addressable * by that device), not "coherent". * */ @@ -1503,6 +1503,9 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, ret = -EAGAIN; else urb->transfer_flags |= URB_DMA_MAP_PAGE; + } else if (is_vmalloc_addr(urb->transfer_buffer)) { + WARN_ONCE(1, "transfer buffer not dma capable\n"); + ret = -EAGAIN; } else { urb->transfer_dma = dma_map_single( hcd->self.controller, @@ -1651,6 +1654,7 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) static void __usb_hcd_giveback_urb(struct urb *urb) { struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); + struct usb_anchor *anchor = urb->anchor; int status = urb->unlinked; unsigned long flags; @@ -1662,6 +1666,7 @@ static void __usb_hcd_giveback_urb(struct urb *urb) unmap_urb_for_dma(hcd, urb); usbmon_urb_complete(&hcd->self, urb, status); + usb_anchor_suspend_wakeups(anchor); usb_unanchor_urb(urb); /* pass ownership to the completion handler */ @@ -1681,6 +1686,7 @@ static void __usb_hcd_giveback_urb(struct urb *urb) urb->complete(urb); local_irq_restore(flags); + usb_anchor_resume_wakeups(anchor); atomic_dec(&urb->use_count); if (unlikely(atomic_read(&urb->reject))) wake_up(&usb_kill_urb_queue); @@ -1703,7 +1709,9 @@ static void usb_giveback_urb_bh(unsigned long param) urb = list_entry(local_list.next, struct urb, urb_list); list_del_init(&urb->urb_list); + bh->completing_ep = urb->ep; __usb_hcd_giveback_urb(urb); + bh->completing_ep = NULL; } /* check if there are new URBs to giveback */ @@ -1812,7 +1820,7 @@ rescan: case USB_ENDPOINT_XFER_INT: s = "-intr"; break; default: - s = "-iso"; break; + s = "-iso"; break; }; s; })); @@ -2045,7 +2053,7 @@ int usb_alloc_streams(struct usb_interface *interface, { struct usb_hcd *hcd; struct usb_device *dev; - int i; + int i, ret; dev = interface_to_usbdev(interface); hcd = bus_to_hcd(dev->bus); @@ -2054,13 +2062,24 @@ int usb_alloc_streams(struct usb_interface *interface, if (dev->speed != USB_SPEED_SUPER) return -EINVAL; - /* Streams only apply to bulk endpoints. */ - for (i = 0; i < num_eps; i++) + for (i = 0; i < num_eps; i++) { + /* Streams only apply to bulk endpoints. */ if (!usb_endpoint_xfer_bulk(&eps[i]->desc)) return -EINVAL; + /* Re-alloc is not allowed */ + if (eps[i]->streams) + return -EINVAL; + } - return hcd->driver->alloc_streams(hcd, dev, eps, num_eps, + ret = hcd->driver->alloc_streams(hcd, dev, eps, num_eps, num_streams, mem_flags); + if (ret < 0) + return ret; + + for (i = 0; i < num_eps; i++) + eps[i]->streams = ret; + + return ret; } EXPORT_SYMBOL_GPL(usb_alloc_streams); @@ -2073,26 +2092,35 @@ EXPORT_SYMBOL_GPL(usb_alloc_streams); * * Reverts a group of bulk endpoints back to not using stream IDs. * Can fail if we are given bad arguments, or HCD is broken. + * + * Return: 0 on success. On failure, a negative error code. */ -void usb_free_streams(struct usb_interface *interface, +int usb_free_streams(struct usb_interface *interface, struct usb_host_endpoint **eps, unsigned int num_eps, gfp_t mem_flags) { struct usb_hcd *hcd; struct usb_device *dev; - int i; + int i, ret; dev = interface_to_usbdev(interface); hcd = bus_to_hcd(dev->bus); if (dev->speed != USB_SPEED_SUPER) - return; + return -EINVAL; - /* Streams only apply to bulk endpoints. */ + /* Double-free is not allowed */ for (i = 0; i < num_eps; i++) - if (!eps[i] || !usb_endpoint_xfer_bulk(&eps[i]->desc)) - return; + if (!eps[i] || !eps[i]->streams) + return -EINVAL; + + ret = hcd->driver->free_streams(hcd, dev, eps, num_eps, mem_flags); + if (ret < 0) + return ret; - hcd->driver->free_streams(hcd, dev, eps, num_eps, mem_flags); + for (i = 0; i < num_eps; i++) + eps[i]->streams = 0; + + return ret; } EXPORT_SYMBOL_GPL(usb_free_streams); @@ -2239,13 +2267,11 @@ static void hcd_resume_work(struct work_struct *work) struct usb_hcd *hcd = container_of(work, struct usb_hcd, wakeup_work); struct usb_device *udev = hcd->self.root_hub; - usb_lock_device(udev); usb_remote_wakeup(udev); - usb_unlock_device(udev); } /** - * usb_hcd_resume_root_hub - called by HCD to resume its root hub + * usb_hcd_resume_root_hub - called by HCD to resume its root hub * @hcd: host controller for this root hub * * The USB host controller calls this function when its root hub is @@ -2324,15 +2350,8 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum); irqreturn_t usb_hcd_irq (int irq, void *__hcd) { struct usb_hcd *hcd = __hcd; - unsigned long flags; irqreturn_t rc; - /* IRQF_DISABLED doesn't work correctly with shared IRQs - * when the first handler doesn't use it. So let's just - * assume it's never used. - */ - local_irq_save(flags); - if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd))) rc = IRQ_NONE; else if (hcd->driver->irq(hcd) == IRQ_NONE) @@ -2340,7 +2359,6 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd) else rc = IRQ_HANDLED; - local_irq_restore(flags); return rc; } EXPORT_SYMBOL_GPL(usb_hcd_irq); @@ -2438,11 +2456,13 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver, mutex_init(hcd->bandwidth_mutex); dev_set_drvdata(dev, hcd); } else { + mutex_lock(&usb_port_peer_mutex); hcd->bandwidth_mutex = primary_hcd->bandwidth_mutex; hcd->primary_hcd = primary_hcd; primary_hcd->primary_hcd = primary_hcd; hcd->shared_hcd = primary_hcd; primary_hcd->shared_hcd = hcd; + mutex_unlock(&usb_port_peer_mutex); } kref_init(&hcd->kref); @@ -2494,18 +2514,25 @@ EXPORT_SYMBOL_GPL(usb_create_hcd); * deallocated. * * Make sure to only deallocate the bandwidth_mutex when the primary HCD is - * freed. When hcd_release() is called for the non-primary HCD, set the - * primary_hcd's shared_hcd pointer to null (since the non-primary HCD will be - * freed shortly). + * freed. When hcd_release() is called for either hcd in a peer set + * invalidate the peer's ->shared_hcd and ->primary_hcd pointers to + * block new peering attempts */ -static void hcd_release (struct kref *kref) +static void hcd_release(struct kref *kref) { struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref); + mutex_lock(&usb_port_peer_mutex); if (usb_hcd_is_primary_hcd(hcd)) kfree(hcd->bandwidth_mutex); - else - hcd->shared_hcd->shared_hcd = NULL; + if (hcd->shared_hcd) { + struct usb_hcd *peer = hcd->shared_hcd; + + peer->shared_hcd = NULL; + if (peer->primary_hcd == hcd) + peer->primary_hcd = NULL; + } + mutex_unlock(&usb_port_peer_mutex); kfree(hcd); } @@ -2547,13 +2574,6 @@ static int usb_hcd_request_irqs(struct usb_hcd *hcd, if (hcd->driver->irq) { - /* IRQF_DISABLED doesn't work as advertised when used together - * with IRQF_SHARED. As usb_hcd_irq() will always disable - * interrupts we can remove it here. - */ - if (irqflags & IRQF_SHARED) - irqflags &= ~IRQF_DISABLED; - snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d", hcd->driver->description, hcd->self.busnum); retval = request_irq(irqnum, &usb_hcd_irq, irqflags, @@ -2580,6 +2600,21 @@ static int usb_hcd_request_irqs(struct usb_hcd *hcd, return 0; } +/* + * Before we free this root hub, flush in-flight peering attempts + * and disable peer lookups + */ +static void usb_put_invalidate_rhdev(struct usb_hcd *hcd) +{ + struct usb_device *rhdev; + + mutex_lock(&usb_port_peer_mutex); + rhdev = hcd->self.root_hub; + hcd->self.root_hub = NULL; + mutex_unlock(&usb_port_peer_mutex); + usb_put_dev(rhdev); +} + /** * usb_add_hcd - finish generic HCD structure initialization and register * @hcd: the usb_hcd structure to initialize @@ -2596,11 +2631,29 @@ int usb_add_hcd(struct usb_hcd *hcd, int retval; struct usb_device *rhdev; + if (IS_ENABLED(CONFIG_USB_PHY) && !hcd->phy) { + struct usb_phy *phy = usb_get_phy_dev(hcd->self.controller, 0); + + if (IS_ERR(phy)) { + retval = PTR_ERR(phy); + if (retval == -EPROBE_DEFER) + return retval; + } else { + retval = usb_phy_init(phy); + if (retval) { + usb_put_phy(phy); + return retval; + } + hcd->phy = phy; + hcd->remove_phy = 1; + } + } + dev_info(hcd->self.controller, "%s\n", hcd->product_desc); /* Keep old behaviour if authorized_default is not in [0, 1]. */ if (authorized_default < 0 || authorized_default > 1) - hcd->authorized_default = hcd->wireless? 0 : 1; + hcd->authorized_default = hcd->wireless ? 0 : 1; else hcd->authorized_default = authorized_default; set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); @@ -2611,7 +2664,7 @@ int usb_add_hcd(struct usb_hcd *hcd, */ if ((retval = hcd_buffer_create(hcd)) != 0) { dev_dbg(hcd->self.controller, "pool alloc failed\n"); - return retval; + goto err_remove_phy; } if ((retval = usb_register_bus(&hcd->self)) < 0) @@ -2622,7 +2675,9 @@ int usb_add_hcd(struct usb_hcd *hcd, retval = -ENOMEM; goto err_allocate_root_hub; } + mutex_lock(&usb_port_peer_mutex); hcd->self.root_hub = rhdev; + mutex_unlock(&usb_port_peer_mutex); switch (hcd->speed) { case HCD_USB11: @@ -2701,12 +2756,6 @@ int usb_add_hcd(struct usb_hcd *hcd, if (hcd->uses_new_polling && HCD_POLL_RH(hcd)) usb_hcd_poll_rh_status(hcd); - /* - * Host controllers don't generate their own wakeup requests; - * they only forward requests from the root hub. Therefore - * controllers should always be enabled for remote wakeup. - */ - device_wakeup_enable(hcd->self.controller); return retval; error_create_attr_group: @@ -2737,13 +2786,19 @@ err_hcd_driver_start: err_request_irq: err_hcd_driver_setup: err_set_rh_speed: - usb_put_dev(hcd->self.root_hub); + usb_put_invalidate_rhdev(hcd); err_allocate_root_hub: usb_deregister_bus(&hcd->self); err_register_bus: hcd_buffer_destroy(hcd); +err_remove_phy: + if (hcd->remove_phy && hcd->phy) { + usb_phy_shutdown(hcd->phy); + usb_put_phy(hcd->phy); + hcd->phy = NULL; + } return retval; -} +} EXPORT_SYMBOL_GPL(usb_add_hcd); /** @@ -2811,14 +2866,20 @@ void usb_remove_hcd(struct usb_hcd *hcd) free_irq(hcd->irq, hcd); } - usb_put_dev(hcd->self.root_hub); usb_deregister_bus(&hcd->self); hcd_buffer_destroy(hcd); + if (hcd->remove_phy && hcd->phy) { + usb_phy_shutdown(hcd->phy); + usb_put_phy(hcd->phy); + hcd->phy = NULL; + } + + usb_put_invalidate_rhdev(hcd); } EXPORT_SYMBOL_GPL(usb_remove_hcd); void -usb_hcd_platform_shutdown(struct platform_device* dev) +usb_hcd_platform_shutdown(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); @@ -2840,7 +2901,7 @@ struct usb_mon_operations *mon_ops; * Notice that the code is minimally error-proof. Because usbmon needs * symbols from usbcore, usbcore gets referenced and cannot be unloaded first. */ - + int usb_mon_register (struct usb_mon_operations *ops) { diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index e6b682c6c23..0e950ad8cb2 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -33,21 +33,9 @@ #include "hub.h" -/* if we are in debug mode, always announce new devices */ -#ifdef DEBUG -#ifndef CONFIG_USB_ANNOUNCE_NEW_DEVICES -#define CONFIG_USB_ANNOUNCE_NEW_DEVICES -#endif -#endif - #define USB_VENDOR_GENESYS_LOGIC 0x05e3 #define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND 0x01 -static inline int hub_is_superspeed(struct usb_device *hdev) -{ - return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS); -} - /* Protect struct usb_device->state and ->children members * Note: Both are also protected by ->dev.sem, except that ->state can * change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */ @@ -62,6 +50,9 @@ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait); static struct task_struct *khubd_task; +/* synchronize hub-port add/remove and peering operations */ +DEFINE_MUTEX(usb_port_peer_mutex); + /* cycle leds on hubs that aren't blinking for attention */ static bool blinkenlights = 0; module_param (blinkenlights, bool, S_IRUGO); @@ -120,7 +111,7 @@ static inline char *portspeed(struct usb_hub *hub, int portstatus) if (hub_is_superspeed(hub->hdev)) return "5.0 Gb/s"; if (portstatus & USB_PORT_STAT_HIGH_SPEED) - return "480 Mb/s"; + return "480 Mb/s"; else if (portstatus & USB_PORT_STAT_LOW_SPEED) return "1.5 Mb/s"; else @@ -148,19 +139,27 @@ static int usb_device_supports_lpm(struct usb_device *udev) return 0; } - /* All USB 3.0 must support LPM, but we need their max exit latency - * information from the SuperSpeed Extended Capabilities BOS descriptor. + /* + * According to the USB 3.0 spec, all USB 3.0 devices must support LPM. + * However, there are some that don't, and they set the U1/U2 exit + * latencies to zero. */ if (!udev->bos->ss_cap) { - dev_warn(&udev->dev, "No LPM exit latency info found. " - "Power management will be impacted.\n"); + dev_info(&udev->dev, "No LPM exit latency info found, disabling LPM.\n"); return 0; } - if (udev->parent->lpm_capable) - return 1; - dev_warn(&udev->dev, "Parent hub missing LPM exit latency info. " - "Power management will be impacted.\n"); + if (udev->bos->ss_cap->bU1devExitLat == 0 && + udev->bos->ss_cap->bU2DevExitLat == 0) { + if (udev->parent) + dev_info(&udev->dev, "LPM exit latency is zeroed, disabling LPM.\n"); + else + dev_info(&udev->dev, "We don't know the algorithms for LPM for this host, disabling LPM.\n"); + return 0; + } + + if (!udev->parent || udev->parent->lpm_capable) + return 1; return 0; } @@ -310,9 +309,9 @@ static void usb_set_lpm_parameters(struct usb_device *udev) return; udev_u1_del = udev->bos->ss_cap->bU1devExitLat; - udev_u2_del = udev->bos->ss_cap->bU2DevExitLat; + udev_u2_del = le16_to_cpu(udev->bos->ss_cap->bU2DevExitLat); hub_u1_del = udev->parent->bos->ss_cap->bU1devExitLat; - hub_u2_del = udev->parent->bos->ss_cap->bU2DevExitLat; + hub_u2_del = le16_to_cpu(udev->parent->bos->ss_cap->bU2DevExitLat); usb_set_lpm_mel(udev, &udev->u1_params, udev_u1_del, hub, &udev->parent->u1_params, hub_u1_del); @@ -411,30 +410,35 @@ static int set_port_feature(struct usb_device *hdev, int port1, int feature) NULL, 0, 1000); } +static char *to_led_name(int selector) +{ + switch (selector) { + case HUB_LED_AMBER: + return "amber"; + case HUB_LED_GREEN: + return "green"; + case HUB_LED_OFF: + return "off"; + case HUB_LED_AUTO: + return "auto"; + default: + return "??"; + } +} + /* * USB 2.0 spec Section 11.24.2.7.1.10 and table 11-7 * for info about using port indicators */ -static void set_port_led( - struct usb_hub *hub, - int port1, - int selector -) +static void set_port_led(struct usb_hub *hub, int port1, int selector) { - int status = set_port_feature(hub->hdev, (selector << 8) | port1, + struct usb_port *port_dev = hub->ports[port1 - 1]; + int status; + + status = set_port_feature(hub->hdev, (selector << 8) | port1, USB_PORT_FEAT_INDICATOR); - if (status < 0) - dev_dbg (hub->intfdev, - "port %d indicator %s status %d\n", - port1, - ({ char *s; switch (selector) { - case HUB_LED_AMBER: s = "amber"; break; - case HUB_LED_GREEN: s = "green"; break; - case HUB_LED_OFF: s = "off"; break; - case HUB_LED_AUTO: s = "auto"; break; - default: s = "??"; break; - }; s; }), - status); + dev_dbg(&port_dev->dev, "indicator %s status %d\n", + to_led_name(selector), status); } #define LED_CYCLE_PERIOD ((2*HZ)/3) @@ -506,7 +510,8 @@ static void led_work (struct work_struct *work) changed++; } if (changed) - schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD); + queue_delayed_work(system_power_efficient_wq, + &hub->leds, LED_CYCLE_PERIOD); } /* use a short timeout for hub/port status fetches */ @@ -741,16 +746,20 @@ int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub, int port1, bool set) { int ret; - struct usb_port *port_dev = hub->ports[port1 - 1]; if (set) ret = set_port_feature(hdev, port1, USB_PORT_FEAT_POWER); else ret = usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_POWER); - if (!ret) - port_dev->power_is_on = set; - return ret; + if (ret) + return ret; + + if (set) + set_bit(port1, hub->power_bits); + else + clear_bit(port1, hub->power_bits); + return 0; } /** @@ -808,16 +817,9 @@ int usb_hub_clear_tt_buffer(struct urb *urb) } EXPORT_SYMBOL_GPL(usb_hub_clear_tt_buffer); -/* If do_delay is false, return the number of milliseconds the caller - * needs to delay. - */ -static unsigned hub_power_on(struct usb_hub *hub, bool do_delay) +static void hub_power_on(struct usb_hub *hub, bool do_delay) { int port1; - unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2; - unsigned delay; - u16 wHubCharacteristics = - le16_to_cpu(hub->descriptor->wHubCharacteristics); /* Enable power on each port. Some hubs have reserved values * of LPSM (> 2) in their descriptors, even though they are @@ -825,23 +827,19 @@ static unsigned hub_power_on(struct usb_hub *hub, bool do_delay) * but only emulate it. In all cases, the ports won't work * unless we send these messages to the hub. */ - if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2) + if (hub_is_port_power_switchable(hub)) dev_dbg(hub->intfdev, "enabling power on all ports\n"); else dev_dbg(hub->intfdev, "trying to enable port power on " "non-switchable hub\n"); for (port1 = 1; port1 <= hub->hdev->maxchild; port1++) - if (hub->ports[port1 - 1]->power_is_on) + if (test_bit(port1, hub->power_bits)) set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER); else usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER); - - /* Wait at least 100 msec for power to become stable */ - delay = max(pgood_delay, (unsigned) 100); if (do_delay) - msleep(delay); - return delay; + msleep(hub_power_on_good_delay(hub)); } static int hub_hub_status(struct usb_hub *hub, @@ -857,7 +855,7 @@ static int hub_hub_status(struct usb_hub *hub, "%s failed (err = %d)\n", __func__, ret); } else { *status = le16_to_cpu(hub->status->hub.wHubStatus); - *change = le16_to_cpu(hub->status->hub.wHubChange); + *change = le16_to_cpu(hub->status->hub.wHubChange); ret = 0; } mutex_unlock(&hub->status_mutex); @@ -891,6 +889,25 @@ static int hub_usb3_port_disable(struct usb_hub *hub, int port1) if (!hub_is_superspeed(hub->hdev)) return -EINVAL; + ret = hub_port_status(hub, port1, &portstatus, &portchange); + if (ret < 0) + return ret; + + /* + * USB controller Advanced Micro Devices, Inc. [AMD] FCH USB XHCI + * Controller [1022:7814] will have spurious result making the following + * usb 3.0 device hotplugging route to the 2.0 root hub and recognized + * as high-speed device if we set the usb 3.0 port link state to + * Disabled. Since it's already in USB_SS_PORT_LS_RX_DETECT state, we + * check the state here to avoid the bug. + */ + if ((portstatus & USB_PORT_STAT_LINK_STATE) == + USB_SS_PORT_LS_RX_DETECT) { + dev_dbg(&hub->ports[port1 - 1]->dev, + "Not disabling port; link state is RxDetect\n"); + return ret; + } + ret = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_SS_DISABLED); if (ret) return ret; @@ -909,20 +926,20 @@ static int hub_usb3_port_disable(struct usb_hub *hub, int port1) msleep(HUB_DEBOUNCE_STEP); } if (total_time >= HUB_DEBOUNCE_TIMEOUT) - dev_warn(hub->intfdev, "Could not disable port %d after %d ms\n", - port1, total_time); + dev_warn(&hub->ports[port1 - 1]->dev, + "Could not disable after %d ms\n", total_time); return hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_RX_DETECT); } static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) { + struct usb_port *port_dev = hub->ports[port1 - 1]; struct usb_device *hdev = hub->hdev; int ret = 0; - if (hub->ports[port1 - 1]->child && set_state) - usb_set_device_state(hub->ports[port1 - 1]->child, - USB_STATE_NOTATTACHED); + if (port_dev->child && set_state) + usb_set_device_state(port_dev->child, USB_STATE_NOTATTACHED); if (!hub->error) { if (hub_is_superspeed(hub->hdev)) ret = hub_usb3_port_disable(hub, port1); @@ -931,8 +948,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) USB_PORT_FEAT_ENABLE); } if (ret && ret != -ENODEV) - dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n", - port1, ret); + dev_err(&port_dev->dev, "cannot disable (err = %d)\n", ret); return ret; } @@ -943,7 +959,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) */ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1) { - dev_dbg(hub->intfdev, "logical disconnect on port %d\n", port1); + dev_dbg(&hub->ports[port1 - 1]->dev, "logical disconnect\n"); hub_port_disable(hub, port1, 1); /* FIXME let caller ask to power down the port: @@ -956,7 +972,7 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1) */ set_bit(port1, hub->change_bits); - kick_khubd(hub); + kick_khubd(hub); } /** @@ -1046,9 +1062,12 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) * for HUB_POST_RESET, but it's easier not to. */ if (type == HUB_INIT) { - delay = hub_power_on(hub, false); - PREPARE_DELAYED_WORK(&hub->init_work, hub_init_func2); - schedule_delayed_work(&hub->init_work, + unsigned delay = hub_power_on_good_delay(hub); + + hub_power_on(hub, false); + INIT_DELAYED_WORK(&hub->init_work, hub_init_func2); + queue_delayed_work(system_power_efficient_wq, + &hub->init_work, msecs_to_jiffies(delay)); /* Suppress autosuspend until init is done */ @@ -1080,21 +1099,23 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) } init2: - /* Check each port and set hub->change_bits to let khubd know + /* + * Check each port and set hub->change_bits to let khubd know * which ports need attention. */ for (port1 = 1; port1 <= hdev->maxchild; ++port1) { - struct usb_device *udev = hub->ports[port1 - 1]->child; + struct usb_port *port_dev = hub->ports[port1 - 1]; + struct usb_device *udev = port_dev->child; u16 portstatus, portchange; portstatus = portchange = 0; status = hub_port_status(hub, port1, &portstatus, &portchange); if (udev || (portstatus & USB_PORT_STAT_CONNECTION)) - dev_dbg(hub->intfdev, - "port %d: status %04x change %04x\n", - port1, portstatus, portchange); + dev_dbg(&port_dev->dev, "status %04x change %04x\n", + portstatus, portchange); - /* After anything other than HUB_RESUME (i.e., initialization + /* + * After anything other than HUB_RESUME (i.e., initialization * or any sort of reset), every port should be disabled. * Unconnected ports should likewise be disabled (paranoia), * and so should ports for which we have no usb_device. @@ -1107,16 +1128,13 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) /* * USB3 protocol ports will automatically transition * to Enabled state when detect an USB3.0 device attach. - * Do not disable USB3 protocol ports. + * Do not disable USB3 protocol ports, just pretend + * power was lost */ - if (!hub_is_superspeed(hdev)) { + portstatus &= ~USB_PORT_STAT_ENABLE; + if (!hub_is_superspeed(hdev)) usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE); - portstatus &= ~USB_PORT_STAT_ENABLE; - } else { - /* Pretend that power was lost for USB3 devs */ - portstatus &= ~USB_PORT_STAT_ENABLE; - } } /* Clear status-change flags; we'll debounce later */ @@ -1130,6 +1148,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_ENABLE); } + if (portchange & USB_PORT_STAT_C_RESET) { + need_debounce_delay = true; + usb_clear_port_feature(hub->hdev, port1, + USB_PORT_FEAT_C_RESET); + } if ((portchange & USB_PORT_STAT_C_BH_RESET) && hub_is_superspeed(hub->hdev)) { need_debounce_delay = true; @@ -1147,7 +1170,8 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) /* Tell khubd to disconnect the device or * check for a new connection */ - if (udev || (portstatus & USB_PORT_STAT_CONNECTION)) + if (udev || (portstatus & USB_PORT_STAT_CONNECTION) || + (portstatus & USB_PORT_STAT_OVERCURRENT)) set_bit(port1, hub->change_bits); } else if (portstatus & USB_PORT_STAT_ENABLE) { @@ -1167,15 +1191,13 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) set_bit(port1, hub->change_bits); } else if (udev->persist_enabled) { - struct usb_port *port_dev = hub->ports[port1 - 1]; - #ifdef CONFIG_PM udev->reset_resume = 1; #endif /* Don't set the change_bits when the device * was powered off. */ - if (port_dev->power_is_on) + if (test_bit(port1, hub->power_bits)) set_bit(port1, hub->change_bits); } else { @@ -1198,8 +1220,9 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) /* Don't do a long sleep inside a workqueue routine */ if (type == HUB_INIT2) { - PREPARE_DELAYED_WORK(&hub->init_work, hub_init_func3); - schedule_delayed_work(&hub->init_work, + INIT_DELAYED_WORK(&hub->init_work, hub_init_func3); + queue_delayed_work(system_power_efficient_wq, + &hub->init_work, msecs_to_jiffies(delay)); return; /* Continues at init3: below */ } else { @@ -1213,7 +1236,8 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) if (status < 0) dev_err(hub->intfdev, "activate --> %d\n", status); if (hub->has_indicators && blinkenlights) - schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD); + queue_delayed_work(system_power_efficient_wq, + &hub->leds, LED_CYCLE_PERIOD); /* Scan all ports that need attention */ kick_khubd(hub); @@ -1268,12 +1292,22 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type) flush_work(&hub->tt.clear_work); } +static void hub_pm_barrier_for_all_ports(struct usb_hub *hub) +{ + int i; + + for (i = 0; i < hub->hdev->maxchild; ++i) + pm_runtime_barrier(&hub->ports[i]->dev); +} + /* caller has locked the hub device */ static int hub_pre_reset(struct usb_interface *intf) { struct usb_hub *hub = usb_get_intfdata(intf); hub_quiesce(hub, HUB_PRE_RESET); + hub->in_reset = 1; + hub_pm_barrier_for_all_ports(hub); return 0; } @@ -1282,6 +1316,8 @@ static int hub_post_reset(struct usb_interface *intf) { struct usb_hub *hub = usb_get_intfdata(intf); + hub->in_reset = 0; + hub_pm_barrier_for_all_ports(hub); hub_activate(hub, HUB_POST_RESET); return 0; } @@ -1299,6 +1335,7 @@ static int hub_configure(struct usb_hub *hub, char *message = "out of memory"; unsigned unit_load; unsigned full_load; + unsigned maxchild; hub->buffer = kmalloc(sizeof(*hub->buffer), GFP_KERNEL); if (!hub->buffer) { @@ -1337,12 +1374,11 @@ static int hub_configure(struct usb_hub *hub, goto fail; } - hdev->maxchild = hub->descriptor->bNbrPorts; - dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild, - (hdev->maxchild == 1) ? "" : "s"); + maxchild = hub->descriptor->bNbrPorts; + dev_info(hub_dev, "%d port%s detected\n", maxchild, + (maxchild == 1) ? "" : "s"); - hub->ports = kzalloc(hdev->maxchild * sizeof(struct usb_port *), - GFP_KERNEL); + hub->ports = kzalloc(maxchild * sizeof(struct usb_port *), GFP_KERNEL); if (!hub->ports) { ret = -ENOMEM; goto fail; @@ -1361,13 +1397,13 @@ static int hub_configure(struct usb_hub *hub, if ((wHubCharacteristics & HUB_CHAR_COMPOUND) && !(hub_is_superspeed(hdev))) { int i; - char portstr [USB_MAXCHILDREN + 1]; + char portstr[USB_MAXCHILDREN + 1]; - for (i = 0; i < hdev->maxchild; i++) + for (i = 0; i < maxchild; i++) portstr[i] = hub->descriptor->u.hs.DeviceRemovable [((i + 1) / 8)] & (1 << ((i + 1) % 8)) ? 'F' : 'R'; - portstr[hdev->maxchild] = 0; + portstr[maxchild] = 0; dev_dbg(hub_dev, "compound device; port removable status: %s\n", portstr); } else dev_dbg(hub_dev, "standalone hub\n"); @@ -1429,32 +1465,32 @@ static int hub_configure(struct usb_hub *hub, /* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */ switch (wHubCharacteristics & HUB_CHAR_TTTT) { - case HUB_TTTT_8_BITS: - if (hdev->descriptor.bDeviceProtocol != 0) { - hub->tt.think_time = 666; - dev_dbg(hub_dev, "TT requires at most %d " - "FS bit times (%d ns)\n", - 8, hub->tt.think_time); - } - break; - case HUB_TTTT_16_BITS: - hub->tt.think_time = 666 * 2; - dev_dbg(hub_dev, "TT requires at most %d " - "FS bit times (%d ns)\n", - 16, hub->tt.think_time); - break; - case HUB_TTTT_24_BITS: - hub->tt.think_time = 666 * 3; - dev_dbg(hub_dev, "TT requires at most %d " - "FS bit times (%d ns)\n", - 24, hub->tt.think_time); - break; - case HUB_TTTT_32_BITS: - hub->tt.think_time = 666 * 4; + case HUB_TTTT_8_BITS: + if (hdev->descriptor.bDeviceProtocol != 0) { + hub->tt.think_time = 666; dev_dbg(hub_dev, "TT requires at most %d " "FS bit times (%d ns)\n", - 32, hub->tt.think_time); - break; + 8, hub->tt.think_time); + } + break; + case HUB_TTTT_16_BITS: + hub->tt.think_time = 666 * 2; + dev_dbg(hub_dev, "TT requires at most %d " + "FS bit times (%d ns)\n", + 16, hub->tt.think_time); + break; + case HUB_TTTT_24_BITS: + hub->tt.think_time = 666 * 3; + dev_dbg(hub_dev, "TT requires at most %d " + "FS bit times (%d ns)\n", + 24, hub->tt.think_time); + break; + case HUB_TTTT_32_BITS: + hub->tt.think_time = 666 * 4; + dev_dbg(hub_dev, "TT requires at most %d " + "FS bit times (%d ns)\n", + 32, hub->tt.think_time); + break; } /* probe() zeroes hub->indicator[] */ @@ -1479,7 +1515,7 @@ static int hub_configure(struct usb_hub *hub, if (hcd->power_budget > 0) hdev->bus_mA = hcd->power_budget; else - hdev->bus_mA = full_load * hdev->maxchild; + hdev->bus_mA = full_load * maxchild; if (hdev->bus_mA >= full_load) hub->mA_per_port = full_load; else { @@ -1494,7 +1530,7 @@ static int hub_configure(struct usb_hub *hub, hub->descriptor->bHubContrCurrent); hub->limited_power = 1; - if (remaining < hdev->maxchild * unit_load) + if (remaining < maxchild * unit_load) dev_warn(hub_dev, "insufficient power available " "to use all downstream ports\n"); @@ -1509,18 +1545,6 @@ static int hub_configure(struct usb_hub *hub, dev_dbg(hub_dev, "%umA bus power budget for each child\n", hub->mA_per_port); - /* Update the HCD's internal representation of this hub before khubd - * starts getting port status changes for devices under the hub. - */ - if (hcd->driver->update_hub_device) { - ret = hcd->driver->update_hub_device(hcd, hdev, - &hub->tt, GFP_KERNEL); - if (ret < 0) { - message = "can't update HCD hub info"; - goto fail; - } - } - ret = hub_hub_status(hub, &hubstatus, &hubchange); if (ret < 0) { message = "can't get hub status"; @@ -1560,15 +1584,37 @@ static int hub_configure(struct usb_hub *hub, /* maybe cycle the hub leds */ if (hub->has_indicators && blinkenlights) - hub->indicator [0] = INDICATOR_CYCLE; + hub->indicator[0] = INDICATOR_CYCLE; - for (i = 0; i < hdev->maxchild; i++) { + mutex_lock(&usb_port_peer_mutex); + for (i = 0; i < maxchild; i++) { ret = usb_hub_create_port_device(hub, i + 1); if (ret < 0) { dev_err(hub->intfdev, "couldn't create port%d device.\n", i + 1); - hdev->maxchild = i; - goto fail_keep_maxchild; + break; + } + } + hdev->maxchild = i; + for (i = 0; i < hdev->maxchild; i++) { + struct usb_port *port_dev = hub->ports[i]; + + pm_runtime_put(&port_dev->dev); + } + + mutex_unlock(&usb_port_peer_mutex); + if (ret < 0) + goto fail; + + /* Update the HCD's internal representation of this hub before khubd + * starts getting port status changes for devices under the hub. + */ + if (hcd->driver->update_hub_device) { + ret = hcd->driver->update_hub_device(hcd, hdev, + &hub->tt, GFP_KERNEL); + if (ret < 0) { + message = "can't update HCD hub info"; + goto fail; } } @@ -1578,8 +1624,6 @@ static int hub_configure(struct usb_hub *hub, return 0; fail: - hdev->maxchild = 0; -fail_keep_maxchild: dev_err (hub_dev, "config failed, %s (err %d)\n", message, ret); /* hub_disconnect() frees urb and descriptor */ @@ -1600,7 +1644,7 @@ static void hub_disconnect(struct usb_interface *intf) { struct usb_hub *hub = usb_get_intfdata(intf); struct usb_device *hdev = interface_to_usbdev(intf); - int i; + int port1; /* Take the hub off the event list and don't let it be added again */ spin_lock_irq(&hub_event_lock); @@ -1615,11 +1659,19 @@ static void hub_disconnect(struct usb_interface *intf) hub->error = 0; hub_quiesce(hub, HUB_DISCONNECT); - usb_set_intfdata (intf, NULL); + mutex_lock(&usb_port_peer_mutex); - for (i = 0; i < hdev->maxchild; i++) - usb_hub_remove_port_device(hub, i + 1); - hub->hdev->maxchild = 0; + /* Avoid races with recursively_mark_NOTATTACHED() */ + spin_lock_irq(&device_state_lock); + port1 = hdev->maxchild; + hdev->maxchild = 0; + usb_set_intfdata(intf, NULL); + spin_unlock_irq(&device_state_lock); + + for (; port1 > 0; --port1) + usb_hub_remove_port_device(hub, port1); + + mutex_unlock(&usb_port_peer_mutex); if (hub->hdev->speed == USB_SPEED_HIGH) highspeed_hubs--; @@ -1679,8 +1731,19 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) */ pm_runtime_set_autosuspend_delay(&hdev->dev, 0); - /* Hubs have proper suspend/resume support. */ - usb_enable_autosuspend(hdev); + /* + * Hubs have proper suspend/resume support, except for root hubs + * where the controller driver doesn't have bus_suspend and + * bus_resume methods. + */ + if (hdev->parent) { /* normal device */ + usb_enable_autosuspend(hdev); + } else { /* root hub */ + const struct hc_driver *drv = bus_to_hcd(hdev->bus)->driver; + + if (drv->bus_suspend && drv->bus_resume) + usb_enable_autosuspend(hdev); + } if (hdev->level == MAX_TOPO_LEVEL) { dev_err(&intf->dev, @@ -1788,7 +1851,7 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data) * to one of these "claimed" ports, the program will "own" the device. */ static int find_port_owner(struct usb_device *hdev, unsigned port1, - struct dev_state ***ppowner) + struct usb_dev_state ***ppowner) { struct usb_hub *hub = usb_hub_to_struct_hub(hdev); @@ -1806,10 +1869,10 @@ static int find_port_owner(struct usb_device *hdev, unsigned port1, /* In the following three functions, the caller must hold hdev's lock */ int usb_hub_claim_port(struct usb_device *hdev, unsigned port1, - struct dev_state *owner) + struct usb_dev_state *owner) { int rc; - struct dev_state **powner; + struct usb_dev_state **powner; rc = find_port_owner(hdev, port1, &powner); if (rc) @@ -1819,12 +1882,13 @@ int usb_hub_claim_port(struct usb_device *hdev, unsigned port1, *powner = owner; return rc; } +EXPORT_SYMBOL_GPL(usb_hub_claim_port); int usb_hub_release_port(struct usb_device *hdev, unsigned port1, - struct dev_state *owner) + struct usb_dev_state *owner) { int rc; - struct dev_state **powner; + struct usb_dev_state **powner; rc = find_port_owner(hdev, port1, &powner); if (rc) @@ -1834,8 +1898,9 @@ int usb_hub_release_port(struct usb_device *hdev, unsigned port1, *powner = NULL; return rc; } +EXPORT_SYMBOL_GPL(usb_hub_release_port); -void usb_hub_release_all_ports(struct usb_device *hdev, struct dev_state *owner) +void usb_hub_release_all_ports(struct usb_device *hdev, struct usb_dev_state *owner) { struct usb_hub *hub = usb_hub_to_struct_hub(hdev); int n; @@ -1978,7 +2043,7 @@ static void choose_devnum(struct usb_device *udev) if (devnum >= 128) devnum = find_next_zero_bit(bus->devmap.devicemap, 128, 1); - bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1); + bus->devnum_next = (devnum >= 127 ? 1 : devnum + 1); } if (devnum < 128) { set_bit(devnum, bus->devmap.devicemap); @@ -2010,6 +2075,18 @@ static void hub_free_dev(struct usb_device *udev) hcd->driver->free_dev(hcd, udev); } +static void hub_disconnect_children(struct usb_device *udev) +{ + struct usb_hub *hub = usb_hub_to_struct_hub(udev); + int i; + + /* Free up all the children before we remove this device */ + for (i = 0; i < udev->maxchild; i++) { + if (hub->ports[i]->child) + usb_disconnect(&hub->ports[i]->child); + } +} + /** * usb_disconnect - disconnect a device (usbcore-internal) * @pdev: pointer to device being disconnected @@ -2018,8 +2095,8 @@ static void hub_free_dev(struct usb_device *udev) * Something got disconnected. Get rid of it and all of its children. * * If *pdev is a normal device then the parent hub must already be locked. - * If *pdev is a root hub then this routine will acquire the - * usb_bus_list_lock on behalf of the caller. + * If *pdev is a root hub then the caller must hold the usb_bus_list_lock, + * which protects the set of root hubs as well as the list of buses. * * Only hub drivers (including virtual root hub drivers for host * controllers) should ever call this. @@ -2028,9 +2105,10 @@ static void hub_free_dev(struct usb_device *udev) */ void usb_disconnect(struct usb_device **pdev) { - struct usb_device *udev = *pdev; - struct usb_hub *hub = usb_hub_to_struct_hub(udev); - int i; + struct usb_port *port_dev = NULL; + struct usb_device *udev = *pdev; + struct usb_hub *hub; + int port1; /* mark the device as inactive, so any further urb submissions for * this device (and any of its children) will fail immediately. @@ -2042,11 +2120,7 @@ void usb_disconnect(struct usb_device **pdev) usb_lock_device(udev); - /* Free up all the children before we remove this device */ - for (i = 0; i < udev->maxchild; i++) { - if (hub->ports[i]->child) - usb_disconnect(&hub->ports[i]->child); - } + hub_disconnect_children(udev); /* deallocate hcd/hardware state ... nuking all pending urbs and * cleaning up all state associated with the current configuration @@ -2057,16 +2131,19 @@ void usb_disconnect(struct usb_device **pdev) usb_hcd_synchronize_unlinks(udev); if (udev->parent) { - struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); - struct usb_port *port_dev = hub->ports[udev->portnum - 1]; + port1 = udev->portnum; + hub = usb_hub_to_struct_hub(udev->parent); + port_dev = hub->ports[port1 - 1]; sysfs_remove_link(&udev->dev.kobj, "port"); sysfs_remove_link(&port_dev->dev.kobj, "device"); - if (!port_dev->did_runtime_put) - pm_runtime_put(&port_dev->dev); - else - port_dev->did_runtime_put = false; + /* + * As usb_port_runtime_resume() de-references udev, make + * sure no resumes occur during removal + */ + if (!test_and_set_bit(port1, hub->child_usage_bits)) + pm_runtime_get_sync(&port_dev->dev); } usb_remove_ep_devs(&udev->ep0); @@ -2088,6 +2165,9 @@ void usb_disconnect(struct usb_device **pdev) *pdev = NULL; spin_unlock_irq(&device_state_lock); + if (port_dev && test_and_clear_bit(port1, hub->child_usage_bits)) + pm_runtime_put(&port_dev->dev); + hub_free_dev(udev); put_device(&udev->dev); @@ -2228,18 +2308,13 @@ static int usb_enumerate_device(struct usb_device *udev) return err; } } - if (udev->wusb == 1 && udev->authorized == 0) { - udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); - udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); - udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); - } - else { - /* read the standard strings and cache them if present */ - udev->product = usb_cache_string(udev, udev->descriptor.iProduct); - udev->manufacturer = usb_cache_string(udev, - udev->descriptor.iManufacturer); - udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); - } + + /* read the standard strings and cache them if present */ + udev->product = usb_cache_string(udev, udev->descriptor.iProduct); + udev->manufacturer = usb_cache_string(udev, + udev->descriptor.iManufacturer); + udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); + err = usb_enumerate_device_otg(udev); if (err < 0) return err; @@ -2280,6 +2355,22 @@ static void set_usb_port_removable(struct usb_device *udev) udev->removable = USB_DEVICE_REMOVABLE; else udev->removable = USB_DEVICE_FIXED; + + /* + * Platform firmware may have populated an alternative value for + * removable. If the parent port has a known connect_type use + * that instead. + */ + switch (hub->ports[udev->portnum - 1]->connect_type) { + case USB_PORT_CONNECT_TYPE_HOT_PLUG: + udev->removable = USB_DEVICE_REMOVABLE; + break; + case USB_PORT_CONNECT_TYPE_HARD_WIRED: + udev->removable = USB_DEVICE_FIXED; + break; + default: /* use what was set above */ + break; + } } /** @@ -2349,11 +2440,7 @@ int usb_new_device(struct usb_device *udev) device_enable_async_suspend(&udev->dev); - /* - * check whether the hub marks this port as non-removable. Do it - * now so that platform-specific data can override it in - * device_add() - */ + /* check whether the hub or firmware marks this port as non-removable */ if (udev->parent) set_usb_port_removable(udev); @@ -2370,7 +2457,8 @@ int usb_new_device(struct usb_device *udev) /* Create link files between child device and usb port device. */ if (udev->parent) { struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); - struct usb_port *port_dev = hub->ports[udev->portnum - 1]; + int port1 = udev->portnum; + struct usb_port *port_dev = hub->ports[port1 - 1]; err = sysfs_create_link(&udev->dev.kobj, &port_dev->dev.kobj, "port"); @@ -2384,7 +2472,8 @@ int usb_new_device(struct usb_device *udev) goto fail; } - pm_runtime_get_sync(&port_dev->dev); + if (!test_and_set_bit(port1, hub->child_usage_bits)) + pm_runtime_get_sync(&port_dev->dev); } (void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev); @@ -2421,16 +2510,6 @@ int usb_deauthorize_device(struct usb_device *usb_dev) usb_dev->authorized = 0; usb_set_configuration(usb_dev, -1); - kfree(usb_dev->product); - usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); - kfree(usb_dev->manufacturer); - usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); - kfree(usb_dev->serial); - usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); - - usb_destroy_configuration(usb_dev); - usb_dev->descriptor.bNumConfigurations = 0; - out_unauthorized: usb_unlock_device(usb_dev); return 0; @@ -2458,17 +2537,7 @@ int usb_authorize_device(struct usb_device *usb_dev) goto error_device_descriptor; } - kfree(usb_dev->product); - usb_dev->product = NULL; - kfree(usb_dev->manufacturer); - usb_dev->manufacturer = NULL; - kfree(usb_dev->serial); - usb_dev->serial = NULL; - usb_dev->authorized = 1; - result = usb_enumerate_device(usb_dev); - if (result < 0) - goto error_enumerate; /* Choose and set the configuration. This registers the interfaces * with the driver core and lets interface drivers bind to them. */ @@ -2484,12 +2553,11 @@ int usb_authorize_device(struct usb_device *usb_dev) } dev_info(&usb_dev->dev, "authorized to connect\n"); -error_enumerate: error_device_descriptor: usb_autosuspend_device(usb_dev); error_autoresume: out_authorized: - usb_unlock_device(usb_dev); // complements locktree + usb_unlock_device(usb_dev); /* complements locktree */ return result; } @@ -2517,10 +2585,25 @@ static unsigned hub_is_wusb(struct usb_hub *hub) #define HUB_LONG_RESET_TIME 200 #define HUB_RESET_TIMEOUT 800 +/* + * "New scheme" enumeration causes an extra state transition to be + * exposed to an xhci host and causes USB3 devices to receive control + * commands in the default state. This has been seen to cause + * enumeration failures, so disable this enumeration scheme for USB3 + * devices. + */ +static bool use_new_scheme(struct usb_device *udev, int retry) +{ + if (udev->speed == USB_SPEED_SUPER) + return false; + + return USE_NEW_SCHEME(retry); +} + static int hub_port_reset(struct usb_hub *hub, int port1, struct usb_device *udev, unsigned int delay, bool warm); -/* Is a USB 3.0 port in the Inactive or Complinance Mode state? +/* Is a USB 3.0 port in the Inactive or Compliance Mode state? * Port worm reset is required to recover */ static bool hub_port_warm_reset_required(struct usb_hub *hub, u16 portstatus) @@ -2558,9 +2641,9 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, if (delay_time >= 2 * HUB_SHORT_RESET_TIME) delay = HUB_LONG_RESET_TIME; - dev_dbg (hub->intfdev, - "port %d not %sreset yet, waiting %dms\n", - port1, warm ? "warm " : "", delay); + dev_dbg(&hub->ports[port1 - 1]->dev, + "not %sreset yet, waiting %dms\n", + warm ? "warm " : "", delay); } if ((portstatus & USB_PORT_STAT_RESET)) @@ -2644,6 +2727,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1, { int i, status; u16 portchange, portstatus; + struct usb_port *port_dev = hub->ports[port1 - 1]; if (!hub_is_superspeed(hub->hdev)) { if (warm) { @@ -2677,9 +2761,9 @@ static int hub_port_reset(struct usb_hub *hub, int port1, if (status == -ENODEV) { ; /* The hub is gone */ } else if (status) { - dev_err(hub->intfdev, - "cannot %sreset port %d (err = %d)\n", - warm ? "warm " : "", port1, status); + dev_err(&port_dev->dev, + "cannot %sreset (err = %d)\n", + warm ? "warm " : "", status); } else { status = hub_port_wait_reset(hub, port1, udev, delay, warm); @@ -2712,21 +2796,19 @@ static int hub_port_reset(struct usb_hub *hub, int port1, * hot or warm reset failed. Try another warm reset. */ if (!warm) { - dev_dbg(hub->intfdev, "hot reset failed, warm reset port %d\n", - port1); + dev_dbg(&port_dev->dev, + "hot reset failed, warm reset\n"); warm = true; } } - dev_dbg (hub->intfdev, - "port %d not enabled, trying %sreset again...\n", - port1, warm ? "warm " : ""); + dev_dbg(&port_dev->dev, + "not enabled, trying %sreset again...\n", + warm ? "warm " : ""); delay = HUB_LONG_RESET_TIME; } - dev_err (hub->intfdev, - "Cannot enable port %i. Maybe the USB cable is bad?\n", - port1); + dev_err(&port_dev->dev, "Cannot enable. Maybe the USB cable is bad?\n"); done: if (!hub_is_superspeed(hub->hdev)) @@ -2751,6 +2833,20 @@ static int port_is_power_on(struct usb_hub *hub, unsigned portstatus) return ret; } +static void usb_lock_port(struct usb_port *port_dev) + __acquires(&port_dev->status_lock) +{ + mutex_lock(&port_dev->status_lock); + __acquire(&port_dev->status_lock); +} + +static void usb_unlock_port(struct usb_port *port_dev) + __releases(&port_dev->status_lock) +{ + mutex_unlock(&port_dev->status_lock); + __release(&port_dev->status_lock); +} + #ifdef CONFIG_PM /* Check if a port is suspended(USB2.0 port) or in U3 state(USB3.0 port) */ @@ -2777,6 +2873,8 @@ static int check_port_resume_type(struct usb_device *udev, struct usb_hub *hub, int port1, int status, unsigned portchange, unsigned portstatus) { + struct usb_port *port_dev = hub->ports[port1 - 1]; + /* Is the device still present? */ if (status || port_is_suspended(hub, portstatus) || !port_is_power_on(hub, portstatus) || @@ -2796,9 +2894,8 @@ static int check_port_resume_type(struct usb_device *udev, } if (status) { - dev_dbg(hub->intfdev, - "port %d status %04x.%04x after resume, %d\n", - port1, portchange, portstatus, status); + dev_dbg(&port_dev->dev, "status %04x.%04x after resume, %d\n", + portchange, portstatus, status); } else if (udev->reset_resume) { /* Late port handoff can set status-change bits */ @@ -2972,6 +3069,8 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) int status; bool really_suspend = true; + usb_lock_port(port_dev); + /* enable remote wakeup when appropriate; this lets the device * wake up the upstream hub (including maybe the root hub). * @@ -3029,8 +3128,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) status = 0; } if (status) { - dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n", - port1, status); + dev_dbg(&port_dev->dev, "can't suspend, status %d\n", status); /* Try to enable USB3 LPM and LTM again */ usb_unlocked_enable_lpm(udev); @@ -3061,12 +3159,13 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) usb_set_device_state(udev, USB_STATE_SUSPENDED); } - if (status == 0 && !udev->do_remote_wakeup && udev->persist_enabled) { + if (status == 0 && !udev->do_remote_wakeup && udev->persist_enabled + && test_and_clear_bit(port1, hub->child_usage_bits)) pm_runtime_put_sync(&port_dev->dev); - port_dev->did_runtime_put = true; - } usb_mark_last_busy(hub->hdev); + + usb_unlock_port(port_dev); return status; } @@ -3104,12 +3203,22 @@ static int finish_port_resume(struct usb_device *udev) * operation is carried out here, after the port has been * resumed. */ - if (udev->reset_resume) + if (udev->reset_resume) { + /* + * If the device morphs or switches modes when it is reset, + * we don't want to perform a reset-resume. We'll fail the + * resume, which will cause a logical disconnect, and then + * the device will be rediscovered. + */ retry_reset_resume: - status = usb_reset_and_verify_device(udev); + if (udev->quirks & USB_QUIRK_RESET) + status = -ENODEV; + else + status = usb_reset_and_verify_device(udev); + } - /* 10.5.4.5 says be sure devices in the tree are still there. - * For now let's assume the device didn't go crazy on resume, + /* 10.5.4.5 says be sure devices in the tree are still there. + * For now let's assume the device didn't go crazy on resume, * and device drivers will know about any resume quirks. */ if (status == 0) { @@ -3196,9 +3305,8 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) int status; u16 portchange, portstatus; - if (port_dev->did_runtime_put) { + if (!test_and_set_bit(port1, hub->child_usage_bits)) { status = pm_runtime_get_sync(&port_dev->dev); - port_dev->did_runtime_put = false; if (status < 0) { dev_dbg(&udev->dev, "can't resume usb port, status %d\n", status); @@ -3206,15 +3314,13 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) } } + usb_lock_port(port_dev); + /* Skip the initial Clear-Suspend step for a remote wakeup */ status = hub_port_status(hub, port1, &portstatus, &portchange); if (status == 0 && !port_is_suspended(hub, portstatus)) goto SuspendCleared; - // dev_dbg(hub->intfdev, "resume port %d\n", port1); - - set_bit(port1, hub->busy_bits); - /* see 7.1.7.7; affects power usage, but not budgeting */ if (hub_is_superspeed(hub->hdev)) status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U0); @@ -3222,8 +3328,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) status = usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_SUSPEND); if (status) { - dev_dbg(hub->intfdev, "can't resume port %d, status %d\n", - port1, status); + dev_dbg(&port_dev->dev, "can't resume, status %d\n", status); } else { /* drive resume for at least 20 msec */ dev_dbg(&udev->dev, "usb %sresume\n", @@ -3254,8 +3359,6 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) } } - clear_bit(port1, hub->busy_bits); - status = check_port_resume_type(udev, hub, port1, status, portchange, portstatus); if (status == 0) @@ -3273,16 +3376,18 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) usb_unlocked_enable_lpm(udev); } + usb_unlock_port(port_dev); + return status; } #ifdef CONFIG_PM_RUNTIME -/* caller has locked udev */ int usb_remote_wakeup(struct usb_device *udev) { int status = 0; + usb_lock_device(udev); if (udev->state == USB_STATE_SUSPENDED) { dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-"); status = usb_autoresume_device(udev); @@ -3291,9 +3396,59 @@ int usb_remote_wakeup(struct usb_device *udev) usb_autosuspend_device(udev); } } + usb_unlock_device(udev); return status; } +/* Returns 1 if there was a remote wakeup and a connect status change. */ +static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, + u16 portstatus, u16 portchange) + __must_hold(&port_dev->status_lock) +{ + struct usb_port *port_dev = hub->ports[port - 1]; + struct usb_device *hdev; + struct usb_device *udev; + int connect_change = 0; + int ret; + + hdev = hub->hdev; + udev = port_dev->child; + if (!hub_is_superspeed(hdev)) { + if (!(portchange & USB_PORT_STAT_C_SUSPEND)) + return 0; + usb_clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND); + } else { + if (!udev || udev->state != USB_STATE_SUSPENDED || + (portstatus & USB_PORT_STAT_LINK_STATE) != + USB_SS_PORT_LS_U0) + return 0; + } + + if (udev) { + /* TRSMRCY = 10 msec */ + msleep(10); + + usb_unlock_port(port_dev); + ret = usb_remote_wakeup(udev); + usb_lock_port(port_dev); + if (ret < 0) + connect_change = 1; + } else { + ret = -ENODEV; + hub_port_disable(hub, port, 1); + } + dev_dbg(&port_dev->dev, "resume, status %d\n", ret); + return connect_change; +} + +#else + +static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, + u16 portstatus, u16 portchange) +{ + return 0; +} + #endif static int check_ports_changed(struct usb_hub *hub) @@ -3324,11 +3479,12 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) */ hub->wakeup_enabled_descendants = 0; for (port1 = 1; port1 <= hdev->maxchild; port1++) { - struct usb_device *udev; + struct usb_port *port_dev = hub->ports[port1 - 1]; + struct usb_device *udev = port_dev->child; - udev = hub->ports[port1 - 1]->child; if (udev && udev->can_submit) { - dev_warn(&intf->dev, "port %d nyet suspended\n", port1); + dev_warn(&port_dev->dev, "device %s not suspended yet\n", + dev_name(&udev->dev)); if (PMSG_IS_AUTO(msg)) return -EBUSY; } @@ -3847,6 +4003,12 @@ EXPORT_SYMBOL_GPL(usb_disable_ltm); void usb_enable_ltm(struct usb_device *udev) { } EXPORT_SYMBOL_GPL(usb_enable_ltm); +static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, + u16 portstatus, u16 portchange) +{ + return 0; +} + #endif /* CONFIG_PM */ @@ -3855,7 +4017,7 @@ EXPORT_SYMBOL_GPL(usb_enable_ltm); * Between connect detection and reset signaling there must be a delay * of 100ms at least for debounce and power-settling. The corresponding * timer shall restart whenever the downstream port detects a disconnect. - * + * * Apparently there are some bluetooth and irda-dongles and a number of * low-speed devices for which this debounce period may last over a second. * Not covered by the spec - but easy to deal with. @@ -3868,9 +4030,10 @@ EXPORT_SYMBOL_GPL(usb_enable_ltm); int hub_port_debounce(struct usb_hub *hub, int port1, bool must_be_connected) { int ret; - int total_time, stable_time = 0; u16 portchange, portstatus; unsigned connection = 0xffff; + int total_time, stable_time = 0; + struct usb_port *port_dev = hub->ports[port1 - 1]; for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) { ret = hub_port_status(hub, port1, &portstatus, &portchange); @@ -3899,9 +4062,8 @@ int hub_port_debounce(struct usb_hub *hub, int port1, bool must_be_connected) msleep(HUB_DEBOUNCE_STEP); } - dev_dbg (hub->intfdev, - "debounce: port %d: total %dms stable %dms status 0x%x\n", - port1, total_time, stable_time, portstatus); + dev_dbg(&port_dev->dev, "debounce total %dms stable %dms status 0x%x\n", + total_time, stable_time, portstatus); if (stable_time < HUB_DEBOUNCE_STABLE) return -ETIMEDOUT; @@ -3949,21 +4111,61 @@ static int hub_set_address(struct usb_device *udev, int devnum) return retval; } +/* + * There are reports of USB 3.0 devices that say they support USB 2.0 Link PM + * when they're plugged into a USB 2.0 port, but they don't work when LPM is + * enabled. + * + * Only enable USB 2.0 Link PM if the port is internal (hardwired), or the + * device says it supports the new USB 2.0 Link PM errata by setting the BESL + * support bit in the BOS descriptor. + */ +static void hub_set_initial_usb2_lpm_policy(struct usb_device *udev) +{ + struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); + int connect_type = USB_PORT_CONNECT_TYPE_UNKNOWN; + + if (!udev->usb2_hw_lpm_capable) + return; + + if (hub) + connect_type = hub->ports[udev->portnum - 1]->connect_type; + + if ((udev->bos->ext_cap->bmAttributes & cpu_to_le32(USB_BESL_SUPPORT)) || + connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) { + udev->usb2_hw_lpm_allowed = 1; + usb_set_usb2_hardware_lpm(udev, 1); + } +} + +static int hub_enable_device(struct usb_device *udev) +{ + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + + if (!hcd->driver->enable_device) + return 0; + if (udev->state == USB_STATE_ADDRESS) + return 0; + if (udev->state != USB_STATE_DEFAULT) + return -EINVAL; + + return hcd->driver->enable_device(hcd, udev); +} + /* Reset device, (re)assign address, get device descriptor. * Device connection must be stable, no more debouncing needed. * Returns device in USB_STATE_ADDRESS, except on error. * * If this is called for an already-existing device (as part of - * usb_reset_and_verify_device), the caller must own the device lock. For a - * newly detected device that is not accessible through any global - * pointers, it's not necessary to lock the device. + * usb_reset_and_verify_device), the caller must own the device lock and + * the port lock. For a newly detected device that is not accessible + * through any global pointers, it's not necessary to lock the device, + * but it is still necessary to lock the port. */ static int hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, int retry_counter) { - static DEFINE_MUTEX(usb_address0_mutex); - struct usb_device *hdev = hub->hdev; struct usb_hcd *hcd = bus_to_hcd(hdev->bus); int i, j, retval; @@ -3986,7 +4188,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, if (oldspeed == USB_SPEED_LOW) delay = HUB_LONG_RESET_TIME; - mutex_lock(&usb_address0_mutex); + mutex_lock(&hdev->bus->usb_address0_mutex); /* Reset the device; full speed may morph to high speed */ /* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */ @@ -4055,13 +4257,13 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, udev->tt = &hub->tt; udev->ttport = port1; } - + /* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way? * Because device hardware and firmware is sometimes buggy in * this area, and this is how Linux has done it for ages. * Change it cautiously. * - * NOTE: If USE_NEW_SCHEME() is true we will start by issuing + * NOTE: If use_new_scheme() is true we will start by issuing * a 64-byte GET_DESCRIPTOR request. This is what Windows does, * so it may help with some non-standards-compliant devices. * Otherwise we start with SET_ADDRESS and then try to read the @@ -4069,10 +4271,21 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, * value. */ for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) { - if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) { + bool did_new_scheme = false; + + if (use_new_scheme(udev, retry_counter)) { struct usb_device_descriptor *buf; int r = 0; + did_new_scheme = true; + retval = hub_enable_device(udev); + if (retval < 0) { + dev_err(&udev->dev, + "hub failed to enable device, error %d\n", + retval); + goto fail; + } + #define GET_DESCRIPTOR_BUFSIZE 64 buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO); if (!buf) { @@ -4130,11 +4343,11 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, #undef GET_DESCRIPTOR_BUFSIZE } - /* - * If device is WUSB, we already assigned an - * unauthorized address in the Connect Ack sequence; - * authorization will assign the final address. - */ + /* + * If device is WUSB, we already assigned an + * unauthorized address in the Connect Ack sequence; + * authorization will assign the final address. + */ if (udev->wusb == 0) { for (j = 0; j < SET_ADDRESS_TRIES; ++j) { retval = hub_set_address(udev, devnum); @@ -4161,9 +4374,13 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, * - read ep0 maxpacket even for high and low speed, */ msleep(10); - if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) + /* use_new_scheme() checks the speed which may have + * changed since the initial look so we cache the result + * in did_new_scheme + */ + if (did_new_scheme) break; - } + } retval = usb_get_device_descriptor(udev, 8); if (retval < 8) { @@ -4219,7 +4436,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i); usb_ep0_reinit(udev); } - + retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE); if (retval < (signed)sizeof(udev->descriptor)) { if (retval != -ENODEV) @@ -4242,12 +4459,13 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, /* notify HCD that we have a device connected and addressed */ if (hcd->driver->update_device) hcd->driver->update_device(hcd, udev); + hub_set_initial_usb2_lpm_policy(udev); fail: if (retval) { hub_port_disable(hub, port1, 0); update_devnum(udev, devnum); /* for disconnect processing */ } - mutex_unlock(&usb_address0_mutex); + mutex_unlock(&hdev->bus->usb_address0_mutex); return retval; } @@ -4269,7 +4487,8 @@ check_highspeed (struct usb_hub *hub, struct usb_device *udev, int port1) /* hub LEDs are probably harder to miss than syslog */ if (hub->has_indicators) { hub->indicator[port1-1] = INDICATOR_GREEN_BLINK; - schedule_delayed_work (&hub->leds, 0); + queue_delayed_work(system_power_efficient_wq, + &hub->leds, 0); } } kfree(qual); @@ -4287,9 +4506,10 @@ hub_power_remaining (struct usb_hub *hub) remaining = hdev->bus_mA - hub->descriptor->bHubContrCurrent; for (port1 = 1; port1 <= hdev->maxchild; ++port1) { - struct usb_device *udev = hub->ports[port1 - 1]->child; - int delta; - unsigned unit_load; + struct usb_port *port_dev = hub->ports[port1 - 1]; + struct usb_device *udev = port_dev->child; + unsigned unit_load; + int delta; if (!udev) continue; @@ -4309,91 +4529,35 @@ hub_power_remaining (struct usb_hub *hub) else delta = 8; if (delta > hub->mA_per_port) - dev_warn(&udev->dev, - "%dmA is over %umA budget for port %d!\n", - delta, hub->mA_per_port, port1); + dev_warn(&port_dev->dev, "%dmA is over %umA budget!\n", + delta, hub->mA_per_port); remaining -= delta; } if (remaining < 0) { dev_warn(hub->intfdev, "%dmA over power budget!\n", - - remaining); + -remaining); remaining = 0; } return remaining; } -/* Handle physical or logical connection change events. - * This routine is called when: - * a port connection-change occurs; - * a port enable-change occurs (often caused by EMI); - * usb_reset_and_verify_device() encounters changed descriptors (as from - * a firmware download) - * caller already locked the hub - */ -static void hub_port_connect_change(struct usb_hub *hub, int port1, - u16 portstatus, u16 portchange) +static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, + u16 portchange) { - struct usb_device *hdev = hub->hdev; - struct device *hub_dev = hub->intfdev; - struct usb_hcd *hcd = bus_to_hcd(hdev->bus); - unsigned wHubCharacteristics = - le16_to_cpu(hub->descriptor->wHubCharacteristics); - struct usb_device *udev; int status, i; unsigned unit_load; - - dev_dbg (hub_dev, - "port %d, status %04x, change %04x, %s\n", - port1, portstatus, portchange, portspeed(hub, portstatus)); - - if (hub->has_indicators) { - set_port_led(hub, port1, HUB_LED_AUTO); - hub->indicator[port1-1] = INDICATOR_AUTO; - } - -#ifdef CONFIG_USB_OTG - /* during HNP, don't repeat the debounce */ - if (hdev->bus->is_b_host) - portchange &= ~(USB_PORT_STAT_C_CONNECTION | - USB_PORT_STAT_C_ENABLE); -#endif - - /* Try to resuscitate an existing device */ - udev = hub->ports[port1 - 1]->child; - if ((portstatus & USB_PORT_STAT_CONNECTION) && udev && - udev->state != USB_STATE_NOTATTACHED) { - usb_lock_device(udev); - if (portstatus & USB_PORT_STAT_ENABLE) { - status = 0; /* Nothing to do */ - -#ifdef CONFIG_PM_RUNTIME - } else if (udev->state == USB_STATE_SUSPENDED && - udev->persist_enabled) { - /* For a suspended device, treat this as a - * remote wakeup event. - */ - status = usb_remote_wakeup(udev); -#endif - - } else { - status = -ENODEV; /* Don't resuscitate */ - } - usb_unlock_device(udev); - - if (status == 0) { - clear_bit(port1, hub->change_bits); - return; - } - } + struct usb_device *hdev = hub->hdev; + struct usb_hcd *hcd = bus_to_hcd(hdev->bus); + struct usb_port *port_dev = hub->ports[port1 - 1]; + struct usb_device *udev = port_dev->child; /* Disconnect any existing devices under this port */ if (udev) { if (hcd->phy && !hdev->parent && !(portstatus & USB_PORT_STAT_CONNECTION)) usb_phy_notify_disconnect(hcd->phy, udev->speed); - usb_disconnect(&hub->ports[port1 - 1]->child); + usb_disconnect(&port_dev->child); } - clear_bit(port1, hub->change_bits); /* We can forget about a "removed" device when there's a physical * disconnect or the connect status changes. @@ -4407,8 +4571,8 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, status = hub_port_debounce_be_stable(hub, port1); if (status < 0) { if (status != -ENODEV && printk_ratelimit()) - dev_err(hub_dev, "connect-debounce failed, " - "port %d disabled\n", port1); + dev_err(&port_dev->dev, + "connect-debounce failed\n"); portstatus &= ~USB_PORT_STAT_CONNECTION; } else { portstatus = status; @@ -4422,12 +4586,12 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, test_bit(port1, hub->removed_bits)) { /* maybe switch power back on (e.g. root hub was reset) */ - if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2 + if (hub_is_port_power_switchable(hub) && !port_is_power_on(hub, portstatus)) set_port_feature(hdev, port1, USB_PORT_FEAT_POWER); if (portstatus & USB_PORT_STAT_ENABLE) - goto done; + goto done; return; } if (hub_is_superspeed(hub->hdev)) @@ -4443,14 +4607,13 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, */ udev = usb_alloc_dev(hdev, hdev->bus, port1); if (!udev) { - dev_err (hub_dev, - "couldn't allocate port %d usb_device\n", - port1); + dev_err(&port_dev->dev, + "couldn't allocate usb_device\n"); goto done; } usb_set_device_state(udev, USB_STATE_POWERED); - udev->bus_mA = hub->mA_per_port; + udev->bus_mA = hub->mA_per_port; udev->level = hdev->level + 1; udev->wusb = hub_is_wusb(hub); @@ -4467,7 +4630,9 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, } /* reset (non-USB 3.0 devices) and get descriptor */ + usb_lock_port(port_dev); status = hub_port_init(hub, udev, port1, i); + usb_unlock_port(port_dev); if (status < 0) goto loop; @@ -4498,13 +4663,15 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, if (hub->has_indicators) { hub->indicator[port1-1] = INDICATOR_AMBER_BLINK; - schedule_delayed_work (&hub->leds, 0); + queue_delayed_work( + system_power_efficient_wq, + &hub->leds, 0); } status = -ENOTCONN; /* Don't retry */ goto loop_disable; } } - + /* check for devices running slower than they could */ if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200 && udev->speed == USB_SPEED_FULL @@ -4517,6 +4684,8 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, */ status = 0; + mutex_lock(&usb_port_peer_mutex); + /* We mustn't add new devices if the parent hub has * been disconnected; we would race with the * recursively_mark_NOTATTACHED() routine. @@ -4525,16 +4694,19 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, if (hdev->state == USB_STATE_NOTATTACHED) status = -ENOTCONN; else - hub->ports[port1 - 1]->child = udev; + port_dev->child = udev; spin_unlock_irq(&device_state_lock); + mutex_unlock(&usb_port_peer_mutex); /* Run it through the hoops (find a driver, etc) */ if (!status) { status = usb_new_device(udev); if (status) { + mutex_lock(&usb_port_peer_mutex); spin_lock_irq(&device_state_lock); - hub->ports[port1 - 1]->child = NULL; + port_dev->child = NULL; spin_unlock_irq(&device_state_lock); + mutex_unlock(&usb_port_peer_mutex); } } @@ -4543,7 +4715,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, status = hub_power_remaining(hub); if (status) - dev_dbg(hub_dev, "%dmA power budget left\n", status); + dev_dbg(hub->intfdev, "%dmA power budget left\n", status); return; @@ -4561,56 +4733,200 @@ loop: !hcd->driver->port_handed_over || !(hcd->driver->port_handed_over)(hcd, port1)) { if (status != -ENOTCONN && status != -ENODEV) - dev_err(hub_dev, "unable to enumerate USB device on port %d\n", - port1); + dev_err(&port_dev->dev, + "unable to enumerate USB device\n"); } - + done: hub_port_disable(hub, port1, 1); if (hcd->driver->relinquish_port && !hub->hdev->parent) hcd->driver->relinquish_port(hcd, port1); + } -/* Returns 1 if there was a remote wakeup and a connect status change. */ -static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, - u16 portstatus, u16 portchange) +/* Handle physical or logical connection change events. + * This routine is called when: + * a port connection-change occurs; + * a port enable-change occurs (often caused by EMI); + * usb_reset_and_verify_device() encounters changed descriptors (as from + * a firmware download) + * caller already locked the hub + */ +static void hub_port_connect_change(struct usb_hub *hub, int port1, + u16 portstatus, u16 portchange) + __must_hold(&port_dev->status_lock) { - struct usb_device *hdev; - struct usb_device *udev; - int connect_change = 0; - int ret; + struct usb_port *port_dev = hub->ports[port1 - 1]; + struct usb_device *udev = port_dev->child; + int status = -ENODEV; - hdev = hub->hdev; - udev = hub->ports[port - 1]->child; - if (!hub_is_superspeed(hdev)) { - if (!(portchange & USB_PORT_STAT_C_SUSPEND)) - return 0; - usb_clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND); - } else { - if (!udev || udev->state != USB_STATE_SUSPENDED || - (portstatus & USB_PORT_STAT_LINK_STATE) != - USB_SS_PORT_LS_U0) - return 0; + dev_dbg(&port_dev->dev, "status %04x, change %04x, %s\n", portstatus, + portchange, portspeed(hub, portstatus)); + + if (hub->has_indicators) { + set_port_led(hub, port1, HUB_LED_AUTO); + hub->indicator[port1-1] = INDICATOR_AUTO; } - if (udev) { - /* TRSMRCY = 10 msec */ - msleep(10); +#ifdef CONFIG_USB_OTG + /* during HNP, don't repeat the debounce */ + if (hub->hdev->bus->is_b_host) + portchange &= ~(USB_PORT_STAT_C_CONNECTION | + USB_PORT_STAT_C_ENABLE); +#endif + /* Try to resuscitate an existing device */ + if ((portstatus & USB_PORT_STAT_CONNECTION) && udev && + udev->state != USB_STATE_NOTATTACHED) { + if (portstatus & USB_PORT_STAT_ENABLE) { + status = 0; /* Nothing to do */ +#ifdef CONFIG_PM_RUNTIME + } else if (udev->state == USB_STATE_SUSPENDED && + udev->persist_enabled) { + /* For a suspended device, treat this as a + * remote wakeup event. + */ + usb_unlock_port(port_dev); + status = usb_remote_wakeup(udev); + usb_lock_port(port_dev); +#endif + } else { + /* Don't resuscitate */; + } + } + clear_bit(port1, hub->change_bits); + + /* successfully revalidated the connection */ + if (status == 0) + return; + + usb_unlock_port(port_dev); + hub_port_connect(hub, port1, portstatus, portchange); + usb_lock_port(port_dev); +} + +static void port_event(struct usb_hub *hub, int port1) + __must_hold(&port_dev->status_lock) +{ + int connect_change, reset_device = 0; + struct usb_port *port_dev = hub->ports[port1 - 1]; + struct usb_device *udev = port_dev->child; + struct usb_device *hdev = hub->hdev; + u16 portstatus, portchange; + + connect_change = test_bit(port1, hub->change_bits); + clear_bit(port1, hub->event_bits); + clear_bit(port1, hub->wakeup_bits); + + if (hub_port_status(hub, port1, &portstatus, &portchange) < 0) + return; + + if (portchange & USB_PORT_STAT_C_CONNECTION) { + usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION); + connect_change = 1; + } + + if (portchange & USB_PORT_STAT_C_ENABLE) { + if (!connect_change) + dev_dbg(&port_dev->dev, "enable change, status %08x\n", + portstatus); + usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE); + + /* + * EM interference sometimes causes badly shielded USB devices + * to be shutdown by the hub, this hack enables them again. + * Works at least with mouse driver. + */ + if (!(portstatus & USB_PORT_STAT_ENABLE) + && !connect_change && udev) { + dev_err(&port_dev->dev, "disabled by hub (EMI?), re-enabling...\n"); + connect_change = 1; + } + } + + if (portchange & USB_PORT_STAT_C_OVERCURRENT) { + u16 status = 0, unused; + + dev_dbg(&port_dev->dev, "over-current change\n"); + usb_clear_port_feature(hdev, port1, + USB_PORT_FEAT_C_OVER_CURRENT); + msleep(100); /* Cool down */ + hub_power_on(hub, true); + hub_port_status(hub, port1, &status, &unused); + if (status & USB_PORT_STAT_OVERCURRENT) + dev_err(&port_dev->dev, "over-current condition\n"); + } + + if (portchange & USB_PORT_STAT_C_RESET) { + dev_dbg(&port_dev->dev, "reset change\n"); + usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_RESET); + } + if ((portchange & USB_PORT_STAT_C_BH_RESET) + && hub_is_superspeed(hdev)) { + dev_dbg(&port_dev->dev, "warm reset change\n"); + usb_clear_port_feature(hdev, port1, + USB_PORT_FEAT_C_BH_PORT_RESET); + } + if (portchange & USB_PORT_STAT_C_LINK_STATE) { + dev_dbg(&port_dev->dev, "link state change\n"); + usb_clear_port_feature(hdev, port1, + USB_PORT_FEAT_C_PORT_LINK_STATE); + } + if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) { + dev_warn(&port_dev->dev, "config error\n"); + usb_clear_port_feature(hdev, port1, + USB_PORT_FEAT_C_PORT_CONFIG_ERROR); + } + + /* skip port actions that require the port to be powered on */ + if (!pm_runtime_active(&port_dev->dev)) + return; + + if (hub_handle_remote_wakeup(hub, port1, portstatus, portchange)) + connect_change = 1; + + /* + * Warm reset a USB3 protocol port if it's in + * SS.Inactive state. + */ + if (hub_port_warm_reset_required(hub, portstatus)) { + dev_dbg(&port_dev->dev, "do warm reset\n"); + if (!udev || !(portstatus & USB_PORT_STAT_CONNECTION) + || udev->state == USB_STATE_NOTATTACHED) { + if (hub_port_reset(hub, port1, NULL, + HUB_BH_RESET_TIME, true) < 0) + hub_port_disable(hub, port1, 1); + } else + reset_device = 1; + } + + /* + * On disconnect USB3 protocol ports transit from U0 to + * SS.Inactive to Rx.Detect. If this happens a warm- + * reset is not needed, but a (re)connect may happen + * before khubd runs and sees the disconnect, and the + * device may be an unknown state. + * + * If the port went through SS.Inactive without khubd + * seeing it the C_LINK_STATE change flag will be set, + * and we reset the dev to put it in a known state. + */ + if (reset_device || (udev && hub_is_superspeed(hub->hdev) + && (portchange & USB_PORT_STAT_C_LINK_STATE) + && (portstatus & USB_PORT_STAT_CONNECTION))) { + usb_unlock_port(port_dev); usb_lock_device(udev); - ret = usb_remote_wakeup(udev); + usb_reset_device(udev); usb_unlock_device(udev); - if (ret < 0) - connect_change = 1; - } else { - ret = -ENODEV; - hub_port_disable(hub, port, 1); + usb_lock_port(port_dev); + connect_change = 0; } - dev_dbg(hub->intfdev, "resume on port %d, status %d\n", - port, ret); - return connect_change; + + if (connect_change) + hub_port_connect_change(hub, port1, portstatus, portchange); } + static void hub_events(void) { struct list_head *tmp; @@ -4620,10 +4936,7 @@ static void hub_events(void) struct device *hub_dev; u16 hubstatus; u16 hubchange; - u16 portstatus; - u16 portchange; int i, ret; - int connect_change, wakeup_change; /* * We restart the list every time to avoid a deadlock with @@ -4697,127 +5010,28 @@ static void hub_events(void) /* deal with port status changes */ for (i = 1; i <= hdev->maxchild; i++) { - if (test_bit(i, hub->busy_bits)) - continue; - connect_change = test_bit(i, hub->change_bits); - wakeup_change = test_and_clear_bit(i, hub->wakeup_bits); - if (!test_and_clear_bit(i, hub->event_bits) && - !connect_change && !wakeup_change) - continue; - - ret = hub_port_status(hub, i, - &portstatus, &portchange); - if (ret < 0) - continue; - - if (portchange & USB_PORT_STAT_C_CONNECTION) { - usb_clear_port_feature(hdev, i, - USB_PORT_FEAT_C_CONNECTION); - connect_change = 1; - } - - if (portchange & USB_PORT_STAT_C_ENABLE) { - if (!connect_change) - dev_dbg (hub_dev, - "port %d enable change, " - "status %08x\n", - i, portstatus); - usb_clear_port_feature(hdev, i, - USB_PORT_FEAT_C_ENABLE); + struct usb_port *port_dev = hub->ports[i - 1]; + if (test_bit(i, hub->event_bits) + || test_bit(i, hub->change_bits) + || test_bit(i, hub->wakeup_bits)) { /* - * EM interference sometimes causes badly - * shielded USB devices to be shutdown by - * the hub, this hack enables them again. - * Works at least with mouse driver. + * The get_noresume and barrier ensure that if + * the port was in the process of resuming, we + * flush that work and keep the port active for + * the duration of the port_event(). However, + * if the port is runtime pm suspended + * (powered-off), we leave it in that state, run + * an abbreviated port_event(), and move on. */ - if (!(portstatus & USB_PORT_STAT_ENABLE) - && !connect_change - && hub->ports[i - 1]->child) { - dev_err (hub_dev, - "port %i " - "disabled by hub (EMI?), " - "re-enabling...\n", - i); - connect_change = 1; - } - } - - if (hub_handle_remote_wakeup(hub, i, - portstatus, portchange)) - connect_change = 1; - - if (portchange & USB_PORT_STAT_C_OVERCURRENT) { - u16 status = 0; - u16 unused; - - dev_dbg(hub_dev, "over-current change on port " - "%d\n", i); - usb_clear_port_feature(hdev, i, - USB_PORT_FEAT_C_OVER_CURRENT); - msleep(100); /* Cool down */ - hub_power_on(hub, true); - hub_port_status(hub, i, &status, &unused); - if (status & USB_PORT_STAT_OVERCURRENT) - dev_err(hub_dev, "over-current " - "condition on port %d\n", i); - } - - if (portchange & USB_PORT_STAT_C_RESET) { - dev_dbg (hub_dev, - "reset change on port %d\n", - i); - usb_clear_port_feature(hdev, i, - USB_PORT_FEAT_C_RESET); - } - if ((portchange & USB_PORT_STAT_C_BH_RESET) && - hub_is_superspeed(hub->hdev)) { - dev_dbg(hub_dev, - "warm reset change on port %d\n", - i); - usb_clear_port_feature(hdev, i, - USB_PORT_FEAT_C_BH_PORT_RESET); + pm_runtime_get_noresume(&port_dev->dev); + pm_runtime_barrier(&port_dev->dev); + usb_lock_port(port_dev); + port_event(hub, i); + usb_unlock_port(port_dev); + pm_runtime_put_sync(&port_dev->dev); } - if (portchange & USB_PORT_STAT_C_LINK_STATE) { - usb_clear_port_feature(hub->hdev, i, - USB_PORT_FEAT_C_PORT_LINK_STATE); - } - if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) { - dev_warn(hub_dev, - "config error on port %d\n", - i); - usb_clear_port_feature(hub->hdev, i, - USB_PORT_FEAT_C_PORT_CONFIG_ERROR); - } - - /* Warm reset a USB3 protocol port if it's in - * SS.Inactive state. - */ - if (hub_port_warm_reset_required(hub, portstatus)) { - int status; - struct usb_device *udev = - hub->ports[i - 1]->child; - - dev_dbg(hub_dev, "warm reset port %d\n", i); - if (!udev || !(portstatus & - USB_PORT_STAT_CONNECTION)) { - status = hub_port_reset(hub, i, - NULL, HUB_BH_RESET_TIME, - true); - if (status < 0) - hub_port_disable(hub, i, 1); - } else { - usb_lock_device(udev); - status = usb_reset_device(udev); - usb_unlock_device(udev); - connect_change = 0; - } - } - - if (connect_change) - hub_port_connect_change(hub, i, - portstatus, portchange); - } /* end for i */ + } /* deal with hub status changes */ if (test_and_clear_bit(0, hub->event_bits) == 0) @@ -4841,7 +5055,7 @@ static void hub_events(void) dev_dbg(hub_dev, "over-current change\n"); clear_hub_feature(hdev, C_HUB_OVER_CURRENT); msleep(500); /* Cool down */ - hub_power_on(hub, true); + hub_power_on(hub, true); hub_hub_status(hub, &status, &unused); if (status & HUB_STATUS_OVERCURRENT) dev_err(hub_dev, "over-current " @@ -4861,12 +5075,12 @@ static void hub_events(void) usb_unlock_device(hdev); kref_put(&hub->kref, hub_release); - } /* end while (1) */ + } /* end while (1) */ } static int hub_thread(void *__unused) { - /* khubd needs to be freezable to avoid intefering with USB-PERSIST + /* khubd needs to be freezable to avoid interfering with USB-PERSIST * port handover. Otherwise it might see that a full-speed device * was gone before the EHCI controller had handed its port over to * the companion full-speed controller. @@ -4886,7 +5100,7 @@ static int hub_thread(void *__unused) static const struct usb_device_id hub_id_table[] = { { .match_flags = USB_DEVICE_ID_MATCH_VENDOR - | USB_DEVICE_ID_MATCH_INT_CLASS, + | USB_DEVICE_ID_MATCH_INT_CLASS, .idVendor = USB_VENDOR_GENESYS_LOGIC, .bInterfaceClass = USB_CLASS_HUB, .driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND}, @@ -5052,15 +5266,18 @@ static int descriptors_changed(struct usb_device *udev, * if the reset wasn't even attempted. * * Note: - * The caller must own the device lock. For example, it's safe to use - * this from a driver probe() routine after downloading new firmware. - * For calls that might not occur during probe(), drivers should lock - * the device using usb_lock_device_for_reset(). + * The caller must own the device lock and the port lock, the latter is + * taken by usb_reset_device(). For example, it's safe to use + * usb_reset_device() from a driver probe() routine after downloading + * new firmware. For calls that might not occur during probe(), drivers + * should lock the device using usb_lock_device_for_reset(). * * Locking exception: This routine may also be called from within an * autoresume handler. Such usage won't conflict with other tasks * holding the device lock because these tasks should always call - * usb_autopm_resume_device(), thereby preventing any unwanted autoresume. + * usb_autopm_resume_device(), thereby preventing any unwanted + * autoresume. The autoresume handler is expected to have already + * acquired the port lock before calling this routine. */ static int usb_reset_and_verify_device(struct usb_device *udev) { @@ -5069,7 +5286,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) struct usb_hcd *hcd = bus_to_hcd(udev->bus); struct usb_device_descriptor descriptor = udev->descriptor; struct usb_host_bos *bos; - int i, ret = 0; + int i, j, ret = 0; int port1 = udev->portnum; if (udev->state == USB_STATE_NOTATTACHED || @@ -5079,13 +5296,17 @@ static int usb_reset_and_verify_device(struct usb_device *udev) return -EINVAL; } - if (!parent_hdev) { - /* this requires hcd-specific logic; see ohci_restart() */ - dev_dbg(&udev->dev, "%s for root hub!\n", __func__); + if (!parent_hdev) return -EISDIR; - } + parent_hub = usb_hub_to_struct_hub(parent_hdev); + /* Disable USB2 hardware LPM. + * It will be re-enabled by the enumeration process. + */ + if (udev->usb2_hw_lpm_enabled == 1) + usb_set_usb2_hardware_lpm(udev, 0); + bos = udev->bos; udev->bos = NULL; @@ -5106,7 +5327,6 @@ static int usb_reset_and_verify_device(struct usb_device *udev) goto re_enumerate; } - set_bit(port1, parent_hub->busy_bits); for (i = 0; i < SET_CONFIG_TRIES; ++i) { /* ep0 maxpacket size may change; let the HCD know about it. @@ -5116,17 +5336,16 @@ static int usb_reset_and_verify_device(struct usb_device *udev) if (ret >= 0 || ret == -ENOTCONN || ret == -ENODEV) break; } - clear_bit(port1, parent_hub->busy_bits); if (ret < 0) goto re_enumerate; - + /* Device might have changed firmware (DFU or similar) */ if (descriptors_changed(udev, &descriptor, bos)) { dev_info(&udev->dev, "device firmware changed\n"); udev->descriptor = descriptor; /* for disconnect() calls */ goto re_enumerate; - } + } /* Restore the device's previous configuration */ if (!udev->actconfig) @@ -5151,7 +5370,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) udev->actconfig->desc.bConfigurationValue, ret); mutex_unlock(hcd->bandwidth_mutex); goto re_enumerate; - } + } mutex_unlock(hcd->bandwidth_mutex); usb_set_device_state(udev, USB_STATE_CONFIGURED); @@ -5189,16 +5408,20 @@ static int usb_reset_and_verify_device(struct usb_device *udev) ret); goto re_enumerate; } + /* Resetting also frees any allocated streams */ + for (j = 0; j < intf->cur_altsetting->desc.bNumEndpoints; j++) + intf->cur_altsetting->endpoint[j].streams = 0; } done: /* Now that the alt settings are re-installed, enable LTM and LPM. */ + usb_set_usb2_hardware_lpm(udev, 1); usb_unlocked_enable_lpm(udev); usb_enable_ltm(udev); usb_release_bos_descriptor(udev); udev->bos = bos; return 0; - + re_enumerate: /* LPM state doesn't matter when we're about to destroy the device. */ hub_port_logical_disconnect(parent_hub, port1); @@ -5233,7 +5456,9 @@ int usb_reset_device(struct usb_device *udev) int ret; int i; unsigned int noio_flag; + struct usb_port *port_dev; struct usb_host_config *config = udev->actconfig; + struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); if (udev->state == USB_STATE_NOTATTACHED || udev->state == USB_STATE_SUSPENDED) { @@ -5242,6 +5467,14 @@ int usb_reset_device(struct usb_device *udev) return -EINVAL; } + if (!udev->parent) { + /* this requires hcd-specific logic; see ohci_restart() */ + dev_dbg(&udev->dev, "%s for root hub!\n", __func__); + return -EISDIR; + } + + port_dev = hub->ports[udev->portnum - 1]; + /* * Don't allocate memory with GFP_KERNEL in current * context to avoid possible deadlock if usb mass @@ -5275,7 +5508,9 @@ int usb_reset_device(struct usb_device *udev) } } + usb_lock_port(port_dev); ret = usb_reset_and_verify_device(udev); + usb_unlock_port(port_dev); if (config) { for (i = config->desc.bNumInterfaces - 1; i >= 0; --i) { @@ -5290,10 +5525,11 @@ int usb_reset_device(struct usb_device *udev) else if (cintf->condition == USB_INTERFACE_BOUND) rebind = 1; + if (rebind) + cintf->needs_binding = 1; } - if (ret == 0 && rebind) - usb_rebind_intf(cintf); } + usb_unbind_and_rebind_marked_interfaces(udev); } usb_autosuspend_device(udev); @@ -5369,56 +5605,26 @@ struct usb_device *usb_hub_find_child(struct usb_device *hdev, } EXPORT_SYMBOL_GPL(usb_hub_find_child); -/** - * usb_set_hub_port_connect_type - set hub port connect type. - * @hdev: USB device belonging to the usb hub - * @port1: port num of the port - * @type: connect type of the port - */ -void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1, - enum usb_port_connect_type type) -{ - struct usb_hub *hub = usb_hub_to_struct_hub(hdev); - - if (hub) - hub->ports[port1 - 1]->connect_type = type; -} - -/** - * usb_get_hub_port_connect_type - Get the port's connect type - * @hdev: USB device belonging to the usb hub - * @port1: port num of the port - * - * Return: The connect type of the port if successful. Or - * USB_PORT_CONNECT_TYPE_UNKNOWN if input params are invalid. - */ -enum usb_port_connect_type -usb_get_hub_port_connect_type(struct usb_device *hdev, int port1) -{ - struct usb_hub *hub = usb_hub_to_struct_hub(hdev); - - if (!hub) - return USB_PORT_CONNECT_TYPE_UNKNOWN; - - return hub->ports[port1 - 1]->connect_type; -} - void usb_hub_adjust_deviceremovable(struct usb_device *hdev, struct usb_hub_descriptor *desc) { + struct usb_hub *hub = usb_hub_to_struct_hub(hdev); enum usb_port_connect_type connect_type; int i; + if (!hub) + return; + if (!hub_is_superspeed(hdev)) { for (i = 1; i <= hdev->maxchild; i++) { - connect_type = usb_get_hub_port_connect_type(hdev, i); + struct usb_port *port_dev = hub->ports[i - 1]; + connect_type = port_dev->connect_type; if (connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) { u8 mask = 1 << (i%8); if (!(desc->u.hs.DeviceRemovable[i/8] & mask)) { - dev_dbg(&hdev->dev, "usb port%d's DeviceRemovable is changed to 1 according to platform information.\n", - i); + dev_dbg(&port_dev->dev, "DeviceRemovable is changed to 1 according to platform information.\n"); desc->u.hs.DeviceRemovable[i/8] |= mask; } } @@ -5427,14 +5633,14 @@ void usb_hub_adjust_deviceremovable(struct usb_device *hdev, u16 port_removable = le16_to_cpu(desc->u.ss.DeviceRemovable); for (i = 1; i <= hdev->maxchild; i++) { - connect_type = usb_get_hub_port_connect_type(hdev, i); + struct usb_port *port_dev = hub->ports[i - 1]; + connect_type = port_dev->connect_type; if (connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) { u16 mask = 1 << i; if (!(port_removable & mask)) { - dev_dbg(&hdev->dev, "usb port%d's DeviceRemovable is changed to 1 according to platform information.\n", - i); + dev_dbg(&port_dev->dev, "DeviceRemovable is changed to 1 according to platform information.\n"); port_removable |= mask; } } @@ -5461,6 +5667,6 @@ acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev, if (!hub) return NULL; - return DEVICE_ACPI_HANDLE(&hub->ports[port1 - 1]->dev); + return ACPI_HANDLE(&hub->ports[port1 - 1]->dev); } #endif diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 4e4790dea34..326308e5396 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -45,12 +45,13 @@ struct usb_hub { unsigned long event_bits[1]; /* status change bitmask */ unsigned long change_bits[1]; /* ports with logical connect status change */ - unsigned long busy_bits[1]; /* ports being reset or - resumed */ unsigned long removed_bits[1]; /* ports with a "removed" device present */ unsigned long wakeup_bits[1]; /* ports that have signaled remote wakeup */ + unsigned long power_bits[1]; /* ports that are powered */ + unsigned long child_usage_bits[1]; /* ports powered on for + children */ #if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */ #error event_bits[] is too short! #endif @@ -66,6 +67,7 @@ struct usb_hub { unsigned limited_power:1; unsigned quiescing:1; unsigned disconnected:1; + unsigned in_reset:1; unsigned quirk_check_port_auto_suspend:1; @@ -78,22 +80,28 @@ struct usb_hub { /** * struct usb port - kernel's representation of a usb port - * @child: usb device attatched to the port + * @child: usb device attached to the port * @dev: generic device interface * @port_owner: port's owner + * @peer: related usb2 and usb3 ports (share the same connector) + * @req: default pm qos request for hubs without port power control * @connect_type: port's connect type + * @location: opaque representation of platform connector location + * @status_lock: synchronize port_event() vs usb_port_{suspend|resume} * @portnum: port index num based one - * @power_is_on: port's power state - * @did_runtime_put: port has done pm_runtime_put(). + * @is_superspeed cache super-speed status */ struct usb_port { struct usb_device *child; struct device dev; - struct dev_state *port_owner; + struct usb_dev_state *port_owner; + struct usb_port *peer; + struct dev_pm_qos_request *req; enum usb_port_connect_type connect_type; + usb_port_location_t location; + struct mutex status_lock; u8 portnum; - unsigned power_is_on:1; - unsigned did_runtime_put:1; + unsigned int is_superspeed:1; }; #define to_usb_port(_dev) \ @@ -111,6 +119,29 @@ extern int hub_port_debounce(struct usb_hub *hub, int port1, extern int usb_clear_port_feature(struct usb_device *hdev, int port1, int feature); +static inline bool hub_is_port_power_switchable(struct usb_hub *hub) +{ + __le16 hcs; + + if (!hub) + return false; + hcs = hub->descriptor->wHubCharacteristics; + return (le16_to_cpu(hcs) & HUB_CHAR_LPSM) < HUB_CHAR_NO_LPSM; +} + +static inline int hub_is_superspeed(struct usb_device *hdev) +{ + return hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS; +} + +static inline unsigned hub_power_on_good_delay(struct usb_hub *hub) +{ + unsigned delay = hub->descriptor->bPwrOn2PwrGood * 2; + + /* Wait at least 100 msec for power to become stable */ + return max(delay, 100U); +} + static inline int hub_port_debounce_be_connected(struct usb_hub *hub, int port1) { diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 82927e1ed27..0c8a7fc4dad 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -6,7 +6,6 @@ #include <linux/usb.h> #include <linux/module.h> #include <linux/slab.h> -#include <linux/init.h> #include <linux/mm.h> #include <linux/timer.h> #include <linux/ctype.h> @@ -179,7 +178,7 @@ EXPORT_SYMBOL_GPL(usb_control_msg); * * Return: * If successful, 0. Otherwise a negative error number. The number of actual - * bytes transferred will be stored in the @actual_length paramater. + * bytes transferred will be stored in the @actual_length parameter. */ int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout) @@ -218,7 +217,7 @@ EXPORT_SYMBOL_GPL(usb_interrupt_msg); * * Return: * If successful, 0. Otherwise a negative error number. The number of actual - * bytes transferred will be stored in the @actual_length paramater. + * bytes transferred will be stored in the @actual_length parameter. * */ int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, @@ -518,7 +517,7 @@ void usb_sg_wait(struct usb_sg_request *io) io->urbs[i]->dev = io->dev; retval = usb_submit_urb(io->urbs[i], GFP_ATOMIC); - /* after we submit, let completions or cancelations fire; + /* after we submit, let completions or cancellations fire; * we handshake using io->status. */ spin_unlock_irq(&io->lock); @@ -1182,8 +1181,12 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) put_device(&dev->actconfig->interface[i]->dev); dev->actconfig->interface[i] = NULL; } + + if (dev->usb2_hw_lpm_enabled == 1) + usb_set_usb2_hardware_lpm(dev, 0); usb_unlocked_disable_lpm(dev); usb_disable_ltm(dev); + dev->actconfig = NULL; if (dev->state == USB_STATE_CONFIGURED) usb_set_device_state(dev, USB_STATE_ADDRESS); @@ -1290,8 +1293,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) struct usb_interface *iface; struct usb_host_interface *alt; struct usb_hcd *hcd = bus_to_hcd(dev->bus); - int ret; - int manual = 0; + int i, ret, manual = 0; unsigned int epaddr; unsigned int pipe; @@ -1326,6 +1328,10 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) mutex_unlock(hcd->bandwidth_mutex); return -ENOMEM; } + /* Changing alt-setting also frees any allocated streams */ + for (i = 0; i < iface->cur_altsetting->desc.bNumEndpoints; i++) + iface->cur_altsetting->endpoint[i].streams = 0; + ret = usb_hcd_alloc_bandwidth(dev, NULL, iface->cur_altsetting, alt); if (ret < 0) { dev_info(&dev->dev, "Not enough bandwidth for altsetting %d\n", @@ -1917,6 +1923,7 @@ free_interfaces: usb_autosuspend_device(dev); return 0; } +EXPORT_SYMBOL_GPL(usb_set_configuration); static LIST_HEAD(set_config_list); static DEFINE_SPINLOCK(set_config_lock); diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 51542f85239..fe1b6d0967e 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -21,6 +21,8 @@ #include "hub.h" +static int usb_port_block_power_off; + static const struct attribute_group *port_dev_group[]; static ssize_t connect_type_show(struct device *dev, @@ -66,6 +68,7 @@ static void usb_port_device_release(struct device *dev) { struct usb_port *port_dev = to_usb_port(dev); + kfree(port_dev->req); kfree(port_dev); } @@ -76,17 +79,29 @@ static int usb_port_runtime_resume(struct device *dev) struct usb_device *hdev = to_usb_device(dev->parent->parent); struct usb_interface *intf = to_usb_interface(dev->parent); struct usb_hub *hub = usb_hub_to_struct_hub(hdev); + struct usb_device *udev = port_dev->child; + struct usb_port *peer = port_dev->peer; int port1 = port_dev->portnum; int retval; if (!hub) return -EINVAL; + if (hub->in_reset) { + set_bit(port1, hub->power_bits); + return 0; + } - usb_autopm_get_interface(intf); - set_bit(port1, hub->busy_bits); + /* + * Power on our usb3 peer before this usb2 port to prevent a usb3 + * device from degrading to its usb2 connection + */ + if (!port_dev->is_superspeed && peer) + pm_runtime_get_sync(&peer->dev); + usb_autopm_get_interface(intf); retval = usb_hub_set_port_power(hdev, hub, port1, true); - if (port_dev->child && !retval) { + msleep(hub_power_on_good_delay(hub)); + if (udev && !retval) { /* * Attempt to wait for usb hub port to be reconnected in order * to make the resume procedure successful. The device may have @@ -97,12 +112,17 @@ static int usb_port_runtime_resume(struct device *dev) if (retval < 0) dev_dbg(&port_dev->dev, "can't get reconnection after setting port power on, status %d\n", retval); - usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE); retval = 0; + + /* Force the child awake to revalidate after the power loss. */ + if (!test_and_set_bit(port1, hub->child_usage_bits)) { + pm_runtime_get_noresume(&port_dev->dev); + pm_request_resume(&udev->dev); + } } - clear_bit(port1, hub->busy_bits); usb_autopm_put_interface(intf); + return retval; } @@ -112,23 +132,37 @@ static int usb_port_runtime_suspend(struct device *dev) struct usb_device *hdev = to_usb_device(dev->parent->parent); struct usb_interface *intf = to_usb_interface(dev->parent); struct usb_hub *hub = usb_hub_to_struct_hub(hdev); + struct usb_port *peer = port_dev->peer; int port1 = port_dev->portnum; int retval; if (!hub) return -EINVAL; + if (hub->in_reset) + return -EBUSY; if (dev_pm_qos_flags(&port_dev->dev, PM_QOS_FLAG_NO_POWER_OFF) == PM_QOS_FLAGS_ALL) return -EAGAIN; + if (usb_port_block_power_off) + return -EBUSY; + usb_autopm_get_interface(intf); - set_bit(port1, hub->busy_bits); retval = usb_hub_set_port_power(hdev, hub, port1, false); usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION); - usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE); - clear_bit(port1, hub->busy_bits); + if (!port_dev->is_superspeed) + usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE); usb_autopm_put_interface(intf); + + /* + * Our peer usb3 port may now be able to suspend, so + * asynchronously queue a suspend request to observe that this + * usb2 port is now off. + */ + if (!port_dev->is_superspeed && peer) + pm_runtime_put(&peer->dev); + return retval; } #endif @@ -146,51 +180,305 @@ struct device_type usb_port_device_type = { .pm = &usb_port_pm_ops, }; +static struct device_driver usb_port_driver = { + .name = "usb", + .owner = THIS_MODULE, +}; + +static int link_peers(struct usb_port *left, struct usb_port *right) +{ + struct usb_port *ss_port, *hs_port; + int rc; + + if (left->peer == right && right->peer == left) + return 0; + + if (left->peer || right->peer) { + struct usb_port *lpeer = left->peer; + struct usb_port *rpeer = right->peer; + char *method; + + if (left->location && left->location == right->location) + method = "location"; + else + method = "default"; + + pr_warn("usb: failed to peer %s and %s by %s (%s:%s) (%s:%s)\n", + dev_name(&left->dev), dev_name(&right->dev), method, + dev_name(&left->dev), + lpeer ? dev_name(&lpeer->dev) : "none", + dev_name(&right->dev), + rpeer ? dev_name(&rpeer->dev) : "none"); + return -EBUSY; + } + + rc = sysfs_create_link(&left->dev.kobj, &right->dev.kobj, "peer"); + if (rc) + return rc; + rc = sysfs_create_link(&right->dev.kobj, &left->dev.kobj, "peer"); + if (rc) { + sysfs_remove_link(&left->dev.kobj, "peer"); + return rc; + } + + /* + * We need to wake the HiSpeed port to make sure we don't race + * setting ->peer with usb_port_runtime_suspend(). Otherwise we + * may miss a suspend event for the SuperSpeed port. + */ + if (left->is_superspeed) { + ss_port = left; + WARN_ON(right->is_superspeed); + hs_port = right; + } else { + ss_port = right; + WARN_ON(!right->is_superspeed); + hs_port = left; + } + pm_runtime_get_sync(&hs_port->dev); + + left->peer = right; + right->peer = left; + + /* + * The SuperSpeed reference is dropped when the HiSpeed port in + * this relationship suspends, i.e. when it is safe to allow a + * SuperSpeed connection to drop since there is no risk of a + * device degrading to its powered-off HiSpeed connection. + * + * Also, drop the HiSpeed ref taken above. + */ + pm_runtime_get_sync(&ss_port->dev); + pm_runtime_put(&hs_port->dev); + + return 0; +} + +static void link_peers_report(struct usb_port *left, struct usb_port *right) +{ + int rc; + + rc = link_peers(left, right); + if (rc == 0) { + dev_dbg(&left->dev, "peered to %s\n", dev_name(&right->dev)); + } else { + dev_warn(&left->dev, "failed to peer to %s (%d)\n", + dev_name(&right->dev), rc); + pr_warn_once("usb: port power management may be unreliable\n"); + usb_port_block_power_off = 1; + } +} + +static void unlink_peers(struct usb_port *left, struct usb_port *right) +{ + struct usb_port *ss_port, *hs_port; + + WARN(right->peer != left || left->peer != right, + "%s and %s are not peers?\n", + dev_name(&left->dev), dev_name(&right->dev)); + + /* + * We wake the HiSpeed port to make sure we don't race its + * usb_port_runtime_resume() event which takes a SuperSpeed ref + * when ->peer is !NULL. + */ + if (left->is_superspeed) { + ss_port = left; + hs_port = right; + } else { + ss_port = right; + hs_port = left; + } + + pm_runtime_get_sync(&hs_port->dev); + + sysfs_remove_link(&left->dev.kobj, "peer"); + right->peer = NULL; + sysfs_remove_link(&right->dev.kobj, "peer"); + left->peer = NULL; + + /* Drop the SuperSpeed ref held on behalf of the active HiSpeed port */ + pm_runtime_put(&ss_port->dev); + + /* Drop the ref taken above */ + pm_runtime_put(&hs_port->dev); +} + +/* + * For each usb hub device in the system check to see if it is in the + * peer domain of the given port_dev, and if it is check to see if it + * has a port that matches the given port by location + */ +static int match_location(struct usb_device *peer_hdev, void *p) +{ + int port1; + struct usb_hcd *hcd, *peer_hcd; + struct usb_port *port_dev = p, *peer; + struct usb_hub *peer_hub = usb_hub_to_struct_hub(peer_hdev); + struct usb_device *hdev = to_usb_device(port_dev->dev.parent->parent); + + if (!peer_hub) + return 0; + + hcd = bus_to_hcd(hdev->bus); + peer_hcd = bus_to_hcd(peer_hdev->bus); + /* peer_hcd is provisional until we verify it against the known peer */ + if (peer_hcd != hcd->shared_hcd) + return 0; + + for (port1 = 1; port1 <= peer_hdev->maxchild; port1++) { + peer = peer_hub->ports[port1 - 1]; + if (peer && peer->location == port_dev->location) { + link_peers_report(port_dev, peer); + return 1; /* done */ + } + } + + return 0; +} + +/* + * Find the peer port either via explicit platform firmware "location" + * data, the peer hcd for root hubs, or the upstream peer relationship + * for all other hubs. + */ +static void find_and_link_peer(struct usb_hub *hub, int port1) +{ + struct usb_port *port_dev = hub->ports[port1 - 1], *peer; + struct usb_device *hdev = hub->hdev; + struct usb_device *peer_hdev; + struct usb_hub *peer_hub; + + /* + * If location data is available then we can only peer this port + * by a location match, not the default peer (lest we create a + * situation where we need to go back and undo a default peering + * when the port is later peered by location data) + */ + if (port_dev->location) { + /* we link the peer in match_location() if found */ + usb_for_each_dev(port_dev, match_location); + return; + } else if (!hdev->parent) { + struct usb_hcd *hcd = bus_to_hcd(hdev->bus); + struct usb_hcd *peer_hcd = hcd->shared_hcd; + + if (!peer_hcd) + return; + + peer_hdev = peer_hcd->self.root_hub; + } else { + struct usb_port *upstream; + struct usb_device *parent = hdev->parent; + struct usb_hub *parent_hub = usb_hub_to_struct_hub(parent); + + if (!parent_hub) + return; + + upstream = parent_hub->ports[hdev->portnum - 1]; + if (!upstream || !upstream->peer) + return; + + peer_hdev = upstream->peer->child; + } + + peer_hub = usb_hub_to_struct_hub(peer_hdev); + if (!peer_hub || port1 > peer_hdev->maxchild) + return; + + /* + * we found a valid default peer, last check is to make sure it + * does not have location data + */ + peer = peer_hub->ports[port1 - 1]; + if (peer && peer->location == 0) + link_peers_report(port_dev, peer); +} + int usb_hub_create_port_device(struct usb_hub *hub, int port1) { - struct usb_port *port_dev = NULL; + struct usb_port *port_dev; int retval; port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL); - if (!port_dev) { - retval = -ENOMEM; - goto exit; + if (!port_dev) + return -ENOMEM; + + port_dev->req = kzalloc(sizeof(*(port_dev->req)), GFP_KERNEL); + if (!port_dev->req) { + kfree(port_dev); + return -ENOMEM; } hub->ports[port1 - 1] = port_dev; port_dev->portnum = port1; - port_dev->power_is_on = true; + set_bit(port1, hub->power_bits); port_dev->dev.parent = hub->intfdev; port_dev->dev.groups = port_dev_group; port_dev->dev.type = &usb_port_device_type; - dev_set_name(&port_dev->dev, "port%d", port1); - + port_dev->dev.driver = &usb_port_driver; + if (hub_is_superspeed(hub->hdev)) + port_dev->is_superspeed = 1; + dev_set_name(&port_dev->dev, "%s-port%d", dev_name(&hub->hdev->dev), + port1); + mutex_init(&port_dev->status_lock); retval = device_register(&port_dev->dev); - if (retval) - goto error_register; + if (retval) { + put_device(&port_dev->dev); + return retval; + } + + /* Set default policy of port-poweroff disabled. */ + retval = dev_pm_qos_add_request(&port_dev->dev, port_dev->req, + DEV_PM_QOS_FLAGS, PM_QOS_FLAG_NO_POWER_OFF); + if (retval < 0) { + device_unregister(&port_dev->dev); + return retval; + } + + find_and_link_peer(hub, port1); + /* + * Enable runtime pm and hold a refernce that hub_configure() + * will drop once the PM_QOS_NO_POWER_OFF flag state has been set + * and the hub has been fully registered (hdev->maxchild set). + */ pm_runtime_set_active(&port_dev->dev); + pm_runtime_get_noresume(&port_dev->dev); + pm_runtime_enable(&port_dev->dev); + device_enable_async_suspend(&port_dev->dev); - /* It would be dangerous if user space couldn't - * prevent usb device from being powered off. So don't - * enable port runtime pm if failed to expose port's pm qos. + /* + * Keep hidden the ability to enable port-poweroff if the hub + * does not support power switching. */ - if (!dev_pm_qos_expose_flags(&port_dev->dev, - PM_QOS_FLAG_NO_POWER_OFF)) - pm_runtime_enable(&port_dev->dev); + if (!hub_is_port_power_switchable(hub)) + return 0; + + /* Attempt to let userspace take over the policy. */ + retval = dev_pm_qos_expose_flags(&port_dev->dev, + PM_QOS_FLAG_NO_POWER_OFF); + if (retval < 0) { + dev_warn(&port_dev->dev, "failed to expose pm_qos_no_poweroff\n"); + return 0; + } - device_enable_async_suspend(&port_dev->dev); + /* Userspace owns the policy, drop the kernel 'no_poweroff' request. */ + retval = dev_pm_qos_remove_request(port_dev->req); + if (retval >= 0) { + kfree(port_dev->req); + port_dev->req = NULL; + } return 0; - -error_register: - put_device(&port_dev->dev); -exit: - return retval; } -void usb_hub_remove_port_device(struct usb_hub *hub, - int port1) +void usb_hub_remove_port_device(struct usb_hub *hub, int port1) { - device_unregister(&hub->ports[port1 - 1]->dev); -} + struct usb_port *port_dev = hub->ports[port1 - 1]; + struct usb_port *peer; + peer = port_dev->peer; + if (peer) + unlink_peers(port_dev, peer); + device_unregister(&port_dev->dev); +} diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 5b44cd47da5..739ee8e8bdf 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -13,6 +13,7 @@ #include <linux/usb.h> #include <linux/usb/quirks.h> +#include <linux/usb/hcd.h> #include "usb.h" /* Lists of quirky USB devices, split in device quirks and interface quirks. @@ -46,6 +47,10 @@ static const struct usb_device_id usb_quirk_list[] = { /* Microsoft LifeCam-VX700 v2.0 */ { USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Logitech HD Pro Webcams C920 and C930e */ + { USB_DEVICE(0x046d, 0x082d), .driver_info = USB_QUIRK_DELAY_INIT }, + { USB_DEVICE(0x046d, 0x0843), .driver_info = USB_QUIRK_DELAY_INIT }, + /* Logitech Quickcam Fusion */ { USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME }, @@ -130,6 +135,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* Broadcom BCM92035DGROM BT dongle */ { USB_DEVICE(0x0a5c, 0x2021), .driver_info = USB_QUIRK_RESET_RESUME }, + /* MAYA44USB sound device */ + { USB_DEVICE(0x0a92, 0x0091), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Action Semiconductor flash disk */ { USB_DEVICE(0x10d6, 0x2200), .driver_info = USB_QUIRK_STRING_FETCH_255 }, @@ -155,6 +163,21 @@ static const struct usb_device_id usb_interface_quirk_list[] = { { } /* terminating entry must be last */ }; +static const struct usb_device_id usb_amd_resume_quirk_list[] = { + /* Lenovo Mouse with Pixart controller */ + { USB_DEVICE(0x17ef, 0x602e), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Pixart Mouse */ + { USB_DEVICE(0x093a, 0x2500), .driver_info = USB_QUIRK_RESET_RESUME }, + { USB_DEVICE(0x093a, 0x2510), .driver_info = USB_QUIRK_RESET_RESUME }, + { USB_DEVICE(0x093a, 0x2521), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Optical Mouse M90/M100 */ + { USB_DEVICE(0x046d, 0xc05a), .driver_info = USB_QUIRK_RESET_RESUME }, + + { } /* terminating entry must be last */ +}; + static bool usb_match_any_interface(struct usb_device *udev, const struct usb_device_id *id) { @@ -181,6 +204,18 @@ static bool usb_match_any_interface(struct usb_device *udev, return false; } +static int usb_amd_resume_quirk(struct usb_device *udev) +{ + struct usb_hcd *hcd; + + hcd = bus_to_hcd(udev->bus); + /* The device should be attached directly to root hub */ + if (udev->level == 1 && hcd->amd_resume_bug == 1) + return 1; + + return 0; +} + static u32 __usb_detect_quirks(struct usb_device *udev, const struct usb_device_id *id) { @@ -206,6 +241,15 @@ static u32 __usb_detect_quirks(struct usb_device *udev, void usb_detect_quirks(struct usb_device *udev) { udev->quirks = __usb_detect_quirks(udev, usb_quirk_list); + + /* + * Pixart-based mice would trigger remote wakeup issue on AMD + * Yangtze chipset, so set them as RESET_RESUME flag. + */ + if (usb_amd_resume_quirk(udev)) + udev->quirks |= __usb_detect_quirks(udev, + usb_amd_resume_quirk_list); + if (udev->quirks) dev_dbg(&udev->dev, "USB quirks for this device: %x\n", udev->quirks); diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 6d2c8edb1ff..1236c6011c7 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -23,14 +23,16 @@ static ssize_t field##_show(struct device *dev, \ { \ struct usb_device *udev; \ struct usb_host_config *actconfig; \ + ssize_t rc = 0; \ \ udev = to_usb_device(dev); \ + usb_lock_device(udev); \ actconfig = udev->actconfig; \ if (actconfig) \ - return sprintf(buf, format_string, \ + rc = sprintf(buf, format_string, \ actconfig->desc.field); \ - else \ - return 0; \ + usb_unlock_device(udev); \ + return rc; \ } \ #define usb_actconfig_attr(field, format_string) \ @@ -45,12 +47,15 @@ static ssize_t bMaxPower_show(struct device *dev, { struct usb_device *udev; struct usb_host_config *actconfig; + ssize_t rc = 0; udev = to_usb_device(dev); + usb_lock_device(udev); actconfig = udev->actconfig; - if (!actconfig) - return 0; - return sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig)); + if (actconfig) + rc = sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig)); + usb_unlock_device(udev); + return rc; } static DEVICE_ATTR_RO(bMaxPower); @@ -59,12 +64,15 @@ static ssize_t configuration_show(struct device *dev, { struct usb_device *udev; struct usb_host_config *actconfig; + ssize_t rc = 0; udev = to_usb_device(dev); + usb_lock_device(udev); actconfig = udev->actconfig; - if ((!actconfig) || (!actconfig->string)) - return 0; - return sprintf(buf, "%s\n", actconfig->string); + if (actconfig && actconfig->string) + rc = sprintf(buf, "%s\n", actconfig->string); + usb_unlock_device(udev); + return rc; } static DEVICE_ATTR_RO(configuration); @@ -390,7 +398,8 @@ static DEVICE_ATTR_RW(autosuspend); static const char on_string[] = "on"; static const char auto_string[] = "auto"; -static void warn_level(void) { +static void warn_level(void) +{ static int level_warned; if (!level_warned) { @@ -449,7 +458,7 @@ static ssize_t usb2_hardware_lpm_show(struct device *dev, struct usb_device *udev = to_usb_device(dev); const char *p; - if (udev->usb2_hw_lpm_enabled == 1) + if (udev->usb2_hw_lpm_allowed == 1) p = "enabled"; else p = "disabled"; @@ -469,8 +478,10 @@ static ssize_t usb2_hardware_lpm_store(struct device *dev, ret = strtobool(buf, &value); - if (!ret) + if (!ret) { + udev->usb2_hw_lpm_allowed = value; ret = usb_set_usb2_hardware_lpm(udev, value); + } usb_unlock_device(udev); @@ -644,7 +655,7 @@ static ssize_t authorized_store(struct device *dev, result = usb_deauthorize_device(usb_dev); else result = usb_authorize_device(usb_dev); - return result < 0? result : size; + return result < 0 ? result : size; } static DEVICE_ATTR_IGNORE_LOCKDEP(authorized, S_IRUGO | S_IWUSR, authorized_show, authorized_store); @@ -764,6 +775,7 @@ read_descriptors(struct file *filp, struct kobject *kobj, * Following that are the raw descriptor entries for all the * configurations (config plus subsidiary descriptors). */ + usb_lock_device(udev); for (cfgno = -1; cfgno < udev->descriptor.bNumConfigurations && nleft > 0; ++cfgno) { if (cfgno < 0) { @@ -784,6 +796,7 @@ read_descriptors(struct file *filp, struct kobject *kobj, off -= srclen; } } + usb_unlock_device(udev); return count - nleft; } @@ -824,7 +837,7 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev) device_remove_bin_file(dev, &dev_bin_attr_descriptors); } -/* Interface Accociation Descriptor fields */ +/* Interface Association Descriptor fields */ #define usb_intf_assoc_attr(field, format_string) \ static ssize_t \ iad_##field##_show(struct device *dev, struct device_attribute *attr, \ @@ -870,9 +883,7 @@ static ssize_t interface_show(struct device *dev, struct device_attribute *attr, char *string; intf = to_usb_interface(dev); - string = intf->cur_altsetting->string; - barrier(); /* The altsetting might change! */ - + string = ACCESS_ONCE(intf->cur_altsetting->string); if (!string) return 0; return sprintf(buf, "%s\n", string); @@ -888,7 +899,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, intf = to_usb_interface(dev); udev = interface_to_usbdev(intf); - alt = intf->cur_altsetting; + alt = ACCESS_ONCE(intf->cur_altsetting); return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X" "ic%02Xisc%02Xip%02Xin%02X\n", @@ -909,23 +920,14 @@ static ssize_t supports_autosuspend_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct usb_interface *intf; - struct usb_device *udev; - int ret; + int s; - intf = to_usb_interface(dev); - udev = interface_to_usbdev(intf); - - usb_lock_device(udev); + device_lock(dev); /* Devices will be autosuspended even when an interface isn't claimed */ - if (!intf->dev.driver || - to_usb_driver(intf->dev.driver)->supports_autosuspend) - ret = sprintf(buf, "%u\n", 1); - else - ret = sprintf(buf, "%u\n", 0); - usb_unlock_device(udev); + s = (!dev->driver || to_usb_driver(dev->driver)->supports_autosuspend); + device_unlock(dev); - return ret; + return sprintf(buf, "%u\n", s); } static DEVICE_ATTR_RO(supports_autosuspend); diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index c12bc790a6a..991386ceb4e 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -2,7 +2,6 @@ #include <linux/string.h> #include <linux/bitops.h> #include <linux/slab.h> -#include <linux/init.h> #include <linux/log2.h> #include <linux/usb.h> #include <linux/wait.h> @@ -53,7 +52,7 @@ EXPORT_SYMBOL_GPL(usb_init_urb); * valid options for this. * * Creates an urb for the USB driver to use, initializes a few internal - * structures, incrementes the usage counter, and returns a pointer to it. + * structures, increments the usage counter, and returns a pointer to it. * * If the driver want to use this urb for interrupt, control, or bulk * endpoints, pass '0' as the number of iso packets. @@ -138,13 +137,19 @@ void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor) } EXPORT_SYMBOL_GPL(usb_anchor_urb); +static int usb_anchor_check_wakeup(struct usb_anchor *anchor) +{ + return atomic_read(&anchor->suspend_wakeups) == 0 && + list_empty(&anchor->urb_list); +} + /* Callers must hold anchor->lock */ static void __usb_unanchor_urb(struct urb *urb, struct usb_anchor *anchor) { urb->anchor = NULL; list_del(&urb->anchor_list); usb_put_urb(urb); - if (list_empty(&anchor->urb_list)) + if (usb_anchor_check_wakeup(anchor)) wake_up(&anchor->wait); } @@ -275,7 +280,7 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); * * Device drivers must explicitly request that repetition, by ensuring that * some URB is always on the endpoint's queue (except possibly for short - * periods during completion callacks). When there is no longer an urb + * periods during completion callbacks). When there is no longer an urb * queued, the endpoint's bandwidth reservation is canceled. This means * drivers can use their completion handlers to ensure they keep bandwidth * they need, by reinitializing and resubmitting the just-completed urb @@ -319,10 +324,14 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); */ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) { + static int pipetypes[4] = { + PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT + }; int xfertype, max; struct usb_device *dev; struct usb_host_endpoint *ep; int is_out; + unsigned int allowed; if (!urb || !urb->complete) return -EINVAL; @@ -430,15 +439,10 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) if (urb->transfer_buffer_length > INT_MAX) return -EMSGSIZE; -#ifdef DEBUG - /* stuff that drivers shouldn't do, but which shouldn't + /* + * stuff that drivers shouldn't do, but which shouldn't * cause problems in HCDs if they get it wrong. */ - { - unsigned int allowed; - static int pipetypes[4] = { - PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT - }; /* Check that the pipe's type matches the endpoint's type */ if (usb_pipetype(urb->pipe) != pipetypes[xfertype]) @@ -470,8 +474,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) if (allowed != urb->transfer_flags) dev_WARN(&dev->dev, "BOGUS urb flags, %x --> %x\n", urb->transfer_flags, allowed); - } -#endif + /* * Force periodic transfer intervals to be legal values that are * a power of two (so HCDs don't need to). @@ -486,9 +489,9 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) /* too small? */ switch (dev->speed) { case USB_SPEED_WIRELESS: - if (urb->interval < 6) + if ((urb->interval < 6) + && (xfertype == USB_ENDPOINT_XFER_INT)) return -EINVAL; - break; default: if (urb->interval <= 0) return -EINVAL; @@ -828,7 +831,7 @@ EXPORT_SYMBOL_GPL(usb_unpoison_anchored_urbs); * * this allows all outstanding URBs to be unlinked starting * from the back of the queue. This function is asynchronous. - * The unlinking is just tiggered. It may happen after this + * The unlinking is just triggered. It may happen after this * function has returned. * * This routine should not be called by a driver after its disconnect @@ -846,6 +849,39 @@ void usb_unlink_anchored_urbs(struct usb_anchor *anchor) EXPORT_SYMBOL_GPL(usb_unlink_anchored_urbs); /** + * usb_anchor_suspend_wakeups + * @anchor: the anchor you want to suspend wakeups on + * + * Call this to stop the last urb being unanchored from waking up any + * usb_wait_anchor_empty_timeout waiters. This is used in the hcd urb give- + * back path to delay waking up until after the completion handler has run. + */ +void usb_anchor_suspend_wakeups(struct usb_anchor *anchor) +{ + if (anchor) + atomic_inc(&anchor->suspend_wakeups); +} +EXPORT_SYMBOL_GPL(usb_anchor_suspend_wakeups); + +/** + * usb_anchor_resume_wakeups + * @anchor: the anchor you want to resume wakeups on + * + * Allow usb_wait_anchor_empty_timeout waiters to be woken up again, and + * wake up any current waiters if the anchor is empty. + */ +void usb_anchor_resume_wakeups(struct usb_anchor *anchor) +{ + if (!anchor) + return; + + atomic_dec(&anchor->suspend_wakeups); + if (usb_anchor_check_wakeup(anchor)) + wake_up(&anchor->wait); +} +EXPORT_SYMBOL_GPL(usb_anchor_resume_wakeups); + +/** * usb_wait_anchor_empty_timeout - wait for an anchor to be unused * @anchor: the anchor you want to become unused * @timeout: how long you are willing to wait in milliseconds @@ -858,7 +894,8 @@ EXPORT_SYMBOL_GPL(usb_unlink_anchored_urbs); int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor, unsigned int timeout) { - return wait_event_timeout(anchor->wait, list_empty(&anchor->urb_list), + return wait_event_timeout(anchor->wait, + usb_anchor_check_wakeup(anchor), msecs_to_jiffies(timeout)); } EXPORT_SYMBOL_GPL(usb_wait_anchor_empty_timeout); diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index 255c14464bf..2776cfe64c0 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -16,9 +16,8 @@ #include <linux/acpi.h> #include <linux/pci.h> #include <linux/usb/hcd.h> -#include <acpi/acpi_bus.h> -#include "usb.h" +#include "hub.h" /** * usb_acpi_power_manageable - check whether usb port has @@ -56,13 +55,18 @@ EXPORT_SYMBOL_GPL(usb_acpi_power_manageable); */ int usb_acpi_set_power_state(struct usb_device *hdev, int index, bool enable) { + struct usb_hub *hub = usb_hub_to_struct_hub(hdev); + struct usb_port *port_dev; acpi_handle port_handle; unsigned char state; int port1 = index + 1; int error = -EINVAL; - port_handle = (acpi_handle)usb_get_hub_port_acpi_handle(hdev, - port1); + if (!hub) + return -ENODEV; + port_dev = hub->ports[port1 - 1]; + + port_handle = (acpi_handle) usb_get_hub_port_acpi_handle(hdev, port1); if (!port_handle) return error; @@ -73,65 +77,61 @@ int usb_acpi_set_power_state(struct usb_device *hdev, int index, bool enable) error = acpi_bus_set_power(port_handle, state); if (!error) - dev_dbg(&hdev->dev, "The power of hub port %d was set to %d\n", - port1, enable); + dev_dbg(&port_dev->dev, "acpi: power was set to %d\n", enable); else - dev_dbg(&hdev->dev, "The power of hub port failed to be set\n"); + dev_dbg(&port_dev->dev, "acpi: power failed to be set\n"); return error; } EXPORT_SYMBOL_GPL(usb_acpi_set_power_state); -static int usb_acpi_check_port_connect_type(struct usb_device *hdev, - acpi_handle handle, int port1) +static enum usb_port_connect_type usb_acpi_get_connect_type(acpi_handle handle, + struct acpi_pld_info *pld) { - acpi_status status; + enum usb_port_connect_type connect_type = USB_PORT_CONNECT_TYPE_UNKNOWN; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *upc; - struct acpi_pld_info *pld; - int ret = 0; + acpi_status status; /* - * Accoding to ACPI Spec 9.13. PLD indicates whether usb port is + * According to ACPI Spec 9.13. PLD indicates whether usb port is * user visible and _UPC indicates whether it is connectable. If * the port was visible and connectable, it could be freely connected * and disconnected with USB devices. If no visible and connectable, * a usb device is directly hard-wired to the port. If no visible and * no connectable, the port would be not used. */ - status = acpi_get_physical_device_location(handle, &pld); - if (ACPI_FAILURE(status)) - return -ENODEV; - status = acpi_evaluate_object(handle, "_UPC", NULL, &buffer); upc = buffer.pointer; if (!upc || (upc->type != ACPI_TYPE_PACKAGE) || upc->package.count != 4) { - ret = -EINVAL; goto out; } if (upc->package.elements[0].integer.value) if (pld->user_visible) - usb_set_hub_port_connect_type(hdev, port1, - USB_PORT_CONNECT_TYPE_HOT_PLUG); + connect_type = USB_PORT_CONNECT_TYPE_HOT_PLUG; else - usb_set_hub_port_connect_type(hdev, port1, - USB_PORT_CONNECT_TYPE_HARD_WIRED); + connect_type = USB_PORT_CONNECT_TYPE_HARD_WIRED; else if (!pld->user_visible) - usb_set_hub_port_connect_type(hdev, port1, USB_PORT_NOT_USED); - + connect_type = USB_PORT_NOT_USED; out: - ACPI_FREE(pld); kfree(upc); - return ret; + return connect_type; } -static int usb_acpi_find_device(struct device *dev, acpi_handle *handle) + +/* + * Private to usb-acpi, all the core needs to know is that + * port_dev->location is non-zero when it has been set by the firmware. + */ +#define USB_ACPI_LOCATION_VALID (1 << 31) + +static struct acpi_device *usb_acpi_find_companion(struct device *dev) { struct usb_device *udev; + struct acpi_device *adev; acpi_handle *parent_handle; - int port_num; /* * In the ACPI DSDT table, only usb root hub and usb ports are @@ -148,38 +148,19 @@ static int usb_acpi_find_device(struct device *dev, acpi_handle *handle) */ if (is_usb_device(dev)) { udev = to_usb_device(dev); - if (udev->parent) { - enum usb_port_connect_type type; - - /* - * According usb port's connect type to set usb device's - * removability. - */ - type = usb_get_hub_port_connect_type(udev->parent, - udev->portnum); - switch (type) { - case USB_PORT_CONNECT_TYPE_HOT_PLUG: - udev->removable = USB_DEVICE_REMOVABLE; - break; - case USB_PORT_CONNECT_TYPE_HARD_WIRED: - udev->removable = USB_DEVICE_FIXED; - break; - default: - udev->removable = USB_DEVICE_REMOVABLE_UNKNOWN; - break; - } - - return -ENODEV; - } + if (udev->parent) + return NULL; - /* root hub's parent is the usb hcd. */ - parent_handle = DEVICE_ACPI_HANDLE(dev->parent); - *handle = acpi_get_child(parent_handle, udev->portnum); - if (!*handle) - return -ENODEV; - return 0; + /* root hub is only child (_ADR=0) under its parent, the HC */ + adev = ACPI_COMPANION(dev->parent); + return acpi_find_child_device(adev, 0, false); } else if (is_usb_port(dev)) { - sscanf(dev_name(dev), "port%d", &port_num); + struct usb_port *port_dev = to_usb_port(dev); + int port1 = port_dev->portnum; + struct acpi_pld_info *pld; + acpi_handle *handle; + acpi_status status; + /* Get the struct usb_device point of port's hub */ udev = to_usb_device(dev->parent->parent); @@ -190,30 +171,39 @@ static int usb_acpi_find_device(struct device *dev, acpi_handle *handle) */ if (!udev->parent) { struct usb_hcd *hcd = bus_to_hcd(udev->bus); - int raw_port_num; - - raw_port_num = usb_hcd_find_raw_port_number(hcd, - port_num); - *handle = acpi_get_child(DEVICE_ACPI_HANDLE(&udev->dev), - raw_port_num); - if (!*handle) - return -ENODEV; + int raw; + + raw = usb_hcd_find_raw_port_number(hcd, port1); + adev = acpi_find_child_device(ACPI_COMPANION(&udev->dev), + raw, false); + if (!adev) + return NULL; } else { parent_handle = usb_get_hub_port_acpi_handle(udev->parent, udev->portnum); if (!parent_handle) - return -ENODEV; + return NULL; - *handle = acpi_get_child(parent_handle, port_num); - if (!*handle) - return -ENODEV; + acpi_bus_get_device(parent_handle, &adev); + adev = acpi_find_child_device(adev, port1, false); + if (!adev) + return NULL; } - usb_acpi_check_port_connect_type(udev, *handle, port_num); - } else - return -ENODEV; + handle = adev->handle; + status = acpi_get_physical_device_location(handle, &pld); + if (ACPI_FAILURE(status) || !pld) + return adev; + + port_dev->location = USB_ACPI_LOCATION_VALID + | pld->group_token << 8 | pld->group_position; + port_dev->connect_type = usb_acpi_get_connect_type(handle, pld); + ACPI_FREE(pld); + + return adev; + } - return 0; + return NULL; } static bool usb_acpi_bus_match(struct device *dev) @@ -224,7 +214,7 @@ static bool usb_acpi_bus_match(struct device *dev) static struct acpi_bus_type usb_acpi_bus = { .name = "USB", .match = usb_acpi_bus_match, - .find_device = usb_acpi_find_device, + .find_companion = usb_acpi_find_companion, }; int usb_acpi_register(void) diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 0a6ee2e70b2..4d1144990d4 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -497,7 +497,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, dev->authorized = 1; else { dev->authorized = usb_hcd->authorized_default; - dev->wusb = usb_bus_is_wusb(bus)? 1 : 0; + dev->wusb = usb_bus_is_wusb(bus) ? 1 : 0; } return dev; } diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 823857767a1..d9d08720c38 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -2,7 +2,7 @@ #include <linux/acpi.h> struct usb_hub_descriptor; -struct dev_state; +struct usb_dev_state; /* Functions local to drivers/usb/core/ */ @@ -55,14 +55,10 @@ extern int usb_match_one_id_intf(struct usb_device *dev, extern int usb_match_device(struct usb_device *dev, const struct usb_device_id *id); extern void usb_forced_unbind_intf(struct usb_interface *intf); -extern void usb_rebind_intf(struct usb_interface *intf); +extern void usb_unbind_and_rebind_marked_interfaces(struct usb_device *udev); -extern int usb_hub_claim_port(struct usb_device *hdev, unsigned port, - struct dev_state *owner); -extern int usb_hub_release_port(struct usb_device *hdev, unsigned port, - struct dev_state *owner); extern void usb_hub_release_all_ports(struct usb_device *hdev, - struct dev_state *owner); + struct usb_dev_state *owner); extern bool usb_device_is_owned(struct usb_device *udev); extern int usb_hub_init(void); @@ -111,11 +107,6 @@ static inline int usb_autoresume_device(struct usb_device *udev) return 0; } -static inline int usb_remote_wakeup(struct usb_device *udev) -{ - return 0; -} - static inline int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) { return 0; @@ -123,6 +114,7 @@ static inline int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) #endif extern struct bus_type usb_bus_type; +extern struct mutex usb_port_peer_mutex; extern struct device_type usb_device_type; extern struct device_type usb_if_device_type; extern struct device_type usb_ep_device_type; @@ -174,15 +166,17 @@ extern void usbfs_conn_disc_event(void); extern int usb_devio_init(void); extern void usb_devio_cleanup(void); +/* + * Firmware specific cookie identifying a port's location. '0' == no location + * data available + */ +typedef u32 usb_port_location_t; + /* internal notify stuff */ extern void usb_notify_add_device(struct usb_device *udev); extern void usb_notify_remove_device(struct usb_device *udev); extern void usb_notify_add_bus(struct usb_bus *ubus); extern void usb_notify_remove_bus(struct usb_bus *ubus); -extern enum usb_port_connect_type - usb_get_hub_port_connect_type(struct usb_device *hdev, int port1); -extern void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1, - enum usb_port_connect_type type); extern void usb_hub_adjust_deviceremovable(struct usb_device *hdev, struct usb_hub_descriptor *desc); |
