Merge tag 'usb-3.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB patches from Greg KH: "Here's the big USB pull request for 3.15-rc1. The normal set of patches, lots of controller driver updates, and a smattering of individual USB driver updates as well. All have been in linux-next for a while" * tag 'usb-3.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (249 commits) xhci: Transition maintainership to Mathias Nyman. USB: disable reset-resume when USB_QUIRK_RESET is set USB: unbind all interfaces before rebinding any usb: phy: Add ulpi IDs for SMSC USB3320 and TI TUSB1210 usb: gadget: tcm_usb_gadget: stop format strings usb: gadget: f_fs: add missing spinlock and mutex unlock usb: gadget: composite: switch over to ERR_CAST() usb: gadget: inode: switch over to memdup_user() usb: gadget: f_subset: switch over to PTR_RET usb: gadget: lpc32xx_udc: fix wrong clk_put() sequence USB: keyspan: remove dead debugging code USB: serial: add missing newlines to dev_<level> messages. USB: serial: add missing braces USB: serial: continue to write on errors USB: serial: continue to read on errors USB: serial: make bulk_out_size a lower limit USB: cypress_m8: fix potential scheduling while atomic devicetree: bindings: document lsi,zevio-usb usb: chipidea: add support for USB OTG controller on LSI Zevio SoCs usb: chipidea: imx: Use dev_name() for ci_hdrc name to distinguish USBs ...
This commit is contained in:
@@ -10,7 +10,6 @@
|
||||
|
||||
|
||||
#define USB_MAXALTSETTING 128 /* Hard limit */
|
||||
#define USB_MAXENDPOINTS 30 /* Hard limit */
|
||||
|
||||
#define USB_MAXCONFIG 8 /* Arbitrary limit */
|
||||
|
||||
|
@@ -769,6 +769,88 @@ static int check_ctrlrecip(struct usb_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;
|
||||
@@ -1043,6 +1125,20 @@ static int proc_bulk(struct usb_dev_state *ps, void __user *arg)
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -1056,6 +1152,7 @@ static int proc_resetep(struct usb_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;
|
||||
}
|
||||
@@ -1074,6 +1171,7 @@ static int proc_clearhalt(struct usb_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
|
||||
@@ -1127,6 +1225,9 @@ static int proc_setintf(struct usb_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);
|
||||
}
|
||||
@@ -1189,6 +1290,8 @@ static int proc_do_submiturb(struct usb_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 |
|
||||
@@ -1209,15 +1312,10 @@ static int proc_do_submiturb(struct usb_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) {
|
||||
@@ -1242,7 +1340,6 @@ static int proc_do_submiturb(struct usb_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) {
|
||||
@@ -1272,17 +1369,17 @@ static int proc_do_submiturb(struct usb_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:
|
||||
@@ -1292,15 +1389,16 @@ static int proc_do_submiturb(struct usb_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)
|
||||
@@ -1331,7 +1429,7 @@ static int proc_do_submiturb(struct usb_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;
|
||||
@@ -1425,7 +1523,8 @@ static int proc_do_submiturb(struct usb_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);
|
||||
@@ -1433,7 +1532,7 @@ static int proc_do_submiturb(struct usb_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;
|
||||
@@ -1983,6 +2082,45 @@ static int proc_disconnect_claim(struct usb_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
|
||||
@@ -2159,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)
|
||||
|
@@ -312,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;
|
||||
|
||||
@@ -400,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;
|
||||
|
||||
@@ -425,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
|
||||
@@ -990,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)
|
||||
{
|
||||
@@ -1004,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;
|
||||
|
||||
@@ -1030,6 +1071,41 @@ void usb_rebind_intf(struct usb_interface *intf)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 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->needs_binding)
|
||||
usb_rebind_intf(intf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
void usb_unbind_and_rebind_marked_interfaces(struct usb_device *udev)
|
||||
{
|
||||
unbind_marked_interfaces(udev);
|
||||
rebind_marked_interfaces(udev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
/* Unbind drivers for @udev's interfaces that don't support suspend/resume
|
||||
@@ -1059,43 +1135,6 @@ static void unbind_no_pm_drivers_interfaces(struct usb_device *udev)
|
||||
}
|
||||
}
|
||||
|
||||
/* Unbind drivers for @udev's interfaces that failed to support reset-resume.
|
||||
* These interfaces have the needs_binding flag set by usb_resume_interface().
|
||||
*
|
||||
* The caller must hold @udev's device lock.
|
||||
*/
|
||||
static void unbind_no_reset_resume_drivers_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void do_rebind_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->needs_binding)
|
||||
usb_rebind_intf(intf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
|
||||
{
|
||||
struct usb_device_driver *udriver;
|
||||
@@ -1420,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;
|
||||
}
|
||||
|
||||
@@ -1442,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
|
||||
|
@@ -2049,7 +2049,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);
|
||||
@@ -2058,13 +2058,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);
|
||||
|
||||
@@ -2078,8 +2089,7 @@ 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: On success, the number of allocated streams. On failure, a negative
|
||||
* error code.
|
||||
* Return: 0 on success. On failure, a negative error code.
|
||||
*/
|
||||
int usb_free_streams(struct usb_interface *interface,
|
||||
struct usb_host_endpoint **eps, unsigned int num_eps,
|
||||
@@ -2087,19 +2097,26 @@ int usb_free_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);
|
||||
if (dev->speed != USB_SPEED_SUPER)
|
||||
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))
|
||||
if (!eps[i] || !eps[i]->streams)
|
||||
return -EINVAL;
|
||||
|
||||
return hcd->driver->free_streams(hcd, dev, eps, num_eps, mem_flags);
|
||||
ret = hcd->driver->free_streams(hcd, dev, eps, num_eps, mem_flags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < num_eps; i++)
|
||||
eps[i]->streams = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_free_streams);
|
||||
|
||||
|
@@ -141,19 +141,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;
|
||||
}
|
||||
|
||||
@@ -499,7 +507,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 */
|
||||
@@ -1041,7 +1050,8 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
|
||||
if (type == HUB_INIT) {
|
||||
delay = hub_power_on(hub, false);
|
||||
INIT_DELAYED_WORK(&hub->init_work, hub_init_func2);
|
||||
schedule_delayed_work(&hub->init_work,
|
||||
queue_delayed_work(system_power_efficient_wq,
|
||||
&hub->init_work,
|
||||
msecs_to_jiffies(delay));
|
||||
|
||||
/* Suppress autosuspend until init is done */
|
||||
@@ -1195,7 +1205,8 @@ 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) {
|
||||
INIT_DELAYED_WORK(&hub->init_work, hub_init_func3);
|
||||
schedule_delayed_work(&hub->init_work,
|
||||
queue_delayed_work(system_power_efficient_wq,
|
||||
&hub->init_work,
|
||||
msecs_to_jiffies(delay));
|
||||
return; /* Continues at init3: below */
|
||||
} else {
|
||||
@@ -1209,7 +1220,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);
|
||||
@@ -3095,9 +3107,19 @@ 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,
|
||||
@@ -3960,7 +3982,7 @@ static void hub_set_initial_usb2_lpm_policy(struct usb_device *udev)
|
||||
connect_type = usb_get_hub_port_connect_type(udev->parent,
|
||||
udev->portnum);
|
||||
|
||||
if ((udev->bos->ext_cap->bmAttributes & USB_BESL_SUPPORT) ||
|
||||
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);
|
||||
@@ -4109,8 +4131,12 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
|
||||
did_new_scheme = true;
|
||||
retval = hub_enable_device(udev);
|
||||
if (retval < 0)
|
||||
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);
|
||||
@@ -4313,7 +4339,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);
|
||||
@@ -4542,7 +4569,9 @@ 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;
|
||||
@@ -4741,6 +4770,8 @@ static void hub_events(void)
|
||||
|
||||
/* deal with port status changes */
|
||||
for (i = 1; i <= hdev->maxchild; i++) {
|
||||
struct usb_device *udev = hub->ports[i - 1]->child;
|
||||
|
||||
if (test_bit(i, hub->busy_bits))
|
||||
continue;
|
||||
connect_change = test_bit(i, hub->change_bits);
|
||||
@@ -4839,8 +4870,6 @@ static void hub_events(void)
|
||||
*/
|
||||
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 ||
|
||||
@@ -4857,6 +4886,24 @@ static void hub_events(void)
|
||||
usb_unlock_device(udev);
|
||||
connect_change = 0;
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
} else if (udev && hub_is_superspeed(hub->hdev) &&
|
||||
(portchange & USB_PORT_STAT_C_LINK_STATE) &&
|
||||
(portstatus & USB_PORT_STAT_CONNECTION)) {
|
||||
usb_lock_device(udev);
|
||||
usb_reset_device(udev);
|
||||
usb_unlock_device(udev);
|
||||
connect_change = 0;
|
||||
}
|
||||
|
||||
if (connect_change)
|
||||
@@ -5114,7 +5161,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 ||
|
||||
@@ -5240,6 +5287,9 @@ 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:
|
||||
@@ -5342,10 +5392,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);
|
||||
|
@@ -1293,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;
|
||||
|
||||
@@ -1329,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",
|
||||
|
@@ -55,7 +55,7 @@ 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 void usb_hub_release_all_ports(struct usb_device *hdev,
|
||||
struct usb_dev_state *owner);
|
||||
|
Reference in New Issue
Block a user