diff options
author | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-01 16:41:58 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-01 16:41:58 -0800 |
commit | 9641219825a54249d77d7aa1afa7d874a05c7f90 (patch) | |
tree | 94dae67a8804a070e2597b931d1e3335f08389fc /drivers/usb | |
parent | 72a73a69f6a79266b8b4b18f796907b73a5c01e3 (diff) | |
parent | 94fcda1f8ab5e0cacc381c5ca1cc9aa6ad523576 (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6: (103 commits)
usbcore: remove unused argument in autosuspend
USB: keep count of unsuspended children
USB hub: simplify remote-wakeup handling
USB: struct usb_device: change flag to bitflag
OHCI: make autostop conditional on CONFIG_PM
USB: Add autosuspend support to the hub driver
EHCI: Fix root-hub and port suspend/resume problems
USB: create a new thread for every USB device found during the probe sequence
USB: add driver for the USB debug devices
USB: added dynamic major number for USB endpoints
USB: pegasus error path not resetting task's state
USB: endianness fix for asix.c
USB: build the appledisplay driver
USB serial: replace kmalloc+memset with kzalloc
USB: hid-core: canonical defines for Apple USB device IDs
USB: idmouse cleanup
USB: make drivers/usb/core/driver.c:usb_device_match() static
USB: lh7a40x_udc remove double declaration
USB: pxa2xx_udc recognizes ixp425 rev b0 chip
usbtouchscreen: add support for DMC TSC-10/25 devices
...
Diffstat (limited to 'drivers/usb')
81 files changed, 1068 insertions, 782 deletions
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index c870c804470..a823486495c 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -834,8 +834,8 @@ static int speedtch_bind(struct usbatm_data *usbatm, const struct usb_endpoint_descriptor *endpoint_desc = &desc->endpoint[i].desc; if ((endpoint_desc->bEndpointAddress == target_address)) { - use_isoc = (endpoint_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_ISOC; + use_isoc = + usb_endpoint_xfer_isoc(endpoint_desc); break; } } diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index f6b9f7e1f71..c137c041f7a 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -401,9 +401,8 @@ static int uea_send_modem_cmd(struct usb_device *usb, int ret = -ENOMEM; u8 *xfer_buff; - xfer_buff = kmalloc(size, GFP_KERNEL); + xfer_buff = kmemdup(buff, size, GFP_KERNEL); if (xfer_buff) { - memcpy(xfer_buff, buff, size); ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), LOAD_INTERNAL, @@ -595,14 +594,12 @@ static int uea_idma_write(struct uea_softc *sc, void *data, u32 size) u8 *xfer_buff; int bytes_read; - xfer_buff = kmalloc(size, GFP_KERNEL); + xfer_buff = kmemdup(data, size, GFP_KERNEL); if (!xfer_buff) { uea_err(INS_TO_USBDEV(sc), "can't allocate xfer_buff\n"); return ret; } - memcpy(xfer_buff, data, size); - ret = usb_bulk_msg(sc->usb_dev, usb_sndbulkpipe(sc->usb_dev, UEA_IDMA_PIPE), xfer_buff, size, &bytes_read, BULK_TIMEOUT); @@ -765,12 +762,11 @@ static int uea_request(struct uea_softc *sc, u8 *xfer_buff; int ret = -ENOMEM; - xfer_buff = kmalloc(size, GFP_KERNEL); + xfer_buff = kmemdup(data, size, GFP_KERNEL); if (!xfer_buff) { uea_err(INS_TO_USBDEV(sc), "can't allocate xfer_buff\n"); return ret; } - memcpy(xfer_buff, data, size); ret = usb_control_msg(sc->usb_dev, usb_sndctrlpipe(sc->usb_dev, 0), UCDC_SEND_ENCAPSULATED_COMMAND, diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 9a9012fd284..ec3438dc8ee 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -892,7 +892,7 @@ skip_normal_probe: /* workaround for switched endpoints */ - if ((epread->bEndpointAddress & USB_DIR_IN) != USB_DIR_IN) { + if (!usb_endpoint_dir_in(epread)) { /* descriptors are swapped */ struct usb_endpoint_descriptor *t; dev_dbg(&intf->dev,"The data interface has switched endpoints"); diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 6e3b5358a76..f8324d8d06a 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -72,6 +72,21 @@ config USB_SUSPEND If you are unsure about this, say N here. +config USB_MULTITHREAD_PROBE + bool "USB Multi-threaded probe (EXPERIMENTAL)" + depends on USB && EXPERIMENTAL + default n + help + Say Y here if you want the USB core to spawn a new thread for + every USB device that is probed. This can cause a small speedup + in boot times on systems with a lot of different USB devices. + + This option should be safe to enable, but if any odd probing + problems are found, please disable it, or dynamically turn it + off in the /sys/module/usbcore/parameters/multithread_probe + file + + When in doubt, say N. config USB_OTG bool diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index 3538c2fdadf..ea398e5d50a 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -175,12 +175,13 @@ static char *usb_dump_endpoint_descriptor ( ) { char dir, unit, *type; - unsigned interval, in, bandwidth = 1; + unsigned interval, bandwidth = 1; if (start > end) return start; - in = (desc->bEndpointAddress & USB_DIR_IN); - dir = in ? 'I' : 'O'; + + dir = usb_endpoint_dir_in(desc) ? 'I' : 'O'; + if (speed == USB_SPEED_HIGH) { switch (le16_to_cpu(desc->wMaxPacketSize) & (0x03 << 11)) { case 1 << 11: bandwidth = 2; break; @@ -204,7 +205,7 @@ static char *usb_dump_endpoint_descriptor ( break; case USB_ENDPOINT_XFER_BULK: type = "Bulk"; - if (speed == USB_SPEED_HIGH && !in) /* uframes per NAK */ + if (speed == USB_SPEED_HIGH && dir == 'O') /* uframes per NAK */ interval = desc->bInterval; else interval = 0; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index fed92be63b5..3ed4cb2d56d 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -561,7 +561,7 @@ static int usbdev_open(struct inode *inode, struct file *file) dev = inode->i_private; if (!dev) goto out; - ret = usb_autoresume_device(dev, 1); + ret = usb_autoresume_device(dev); if (ret) goto out; @@ -609,7 +609,7 @@ static int usbdev_release(struct inode *inode, struct file *file) releaseintf(ps, ifnum); } destroy_all_async(ps); - usb_autosuspend_device(dev, 1); + usb_autosuspend_device(dev); usb_unlock_device(dev); usb_put_dev(dev); put_pid(ps->disc_pid); diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 113e484c763..d6eb5ce1dd1 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -205,7 +205,7 @@ static int usb_probe_interface(struct device *dev) if (id) { dev_dbg(dev, "%s - got id\n", __FUNCTION__); - error = usb_autoresume_device(udev, 1); + error = usb_autoresume_device(udev); if (error) return error; @@ -229,7 +229,7 @@ static int usb_probe_interface(struct device *dev) } else intf->condition = USB_INTERFACE_BOUND; - usb_autosuspend_device(udev, 1); + usb_autosuspend_device(udev); } return error; @@ -247,7 +247,7 @@ static int usb_unbind_interface(struct device *dev) /* Autoresume for set_interface call below */ udev = interface_to_usbdev(intf); - error = usb_autoresume_device(udev, 1); + error = usb_autoresume_device(udev); /* release all urbs for this interface */ usb_disable_interface(interface_to_usbdev(intf), intf); @@ -265,7 +265,7 @@ static int usb_unbind_interface(struct device *dev) intf->needs_remote_wakeup = 0; if (!error) - usb_autosuspend_device(udev, 1); + usb_autosuspend_device(udev); return 0; } @@ -408,6 +408,16 @@ static int usb_match_one_id(struct usb_interface *interface, (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol)) return 0; + /* The interface class, subclass, and protocol should never be + * checked for a match if the device class is Vendor Specific, + * unless the match record specifies the Vendor ID. */ + if (dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC && + !(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && + (id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS | + USB_DEVICE_ID_MATCH_INT_PROTOCOL))) + return 0; + if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) && (id->bInterfaceClass != intf->desc.bInterfaceClass)) return 0; @@ -476,7 +486,17 @@ static int usb_match_one_id(struct usb_interface *interface, * most general; they let drivers bind to any interface on a * multiple-function device. Use the USB_INTERFACE_INFO * macro, or its siblings, to match class-per-interface style - * devices (as recorded in bDeviceClass). + * devices (as recorded in bInterfaceClass). + * + * Note that an entry created by USB_INTERFACE_INFO won't match + * any interface if the device class is set to Vendor-Specific. + * This is deliberate; according to the USB spec the meanings of + * the interface class/subclass/protocol for these devices are also + * vendor-specific, and hence matching against a standard product + * class wouldn't work anyway. If you really want to use an + * interface-based match for such a device, create a match record + * that also specifies the vendor ID. (Unforunately there isn't a + * standard macro for creating records like this.) * * Within those groups, remember that not all combinations are * meaningful. For example, don't give a product version range @@ -505,7 +525,7 @@ const struct usb_device_id *usb_match_id(struct usb_interface *interface, } EXPORT_SYMBOL_GPL_FUTURE(usb_match_id); -int usb_device_match(struct device *dev, struct device_driver *drv) +static int usb_device_match(struct device *dev, struct device_driver *drv) { /* devices and interfaces are handled separately */ if (is_usb_device(dev)) { @@ -790,7 +810,7 @@ EXPORT_SYMBOL_GPL_FUTURE(usb_deregister); #ifdef CONFIG_PM /* Caller has locked udev's pm_mutex */ -static int suspend_device(struct usb_device *udev, pm_message_t msg) +static int usb_suspend_device(struct usb_device *udev, pm_message_t msg) { struct usb_device_driver *udriver; int status = 0; @@ -817,7 +837,7 @@ done: } /* Caller has locked udev's pm_mutex */ -static int resume_device(struct usb_device *udev) +static int usb_resume_device(struct usb_device *udev) { struct usb_device_driver *udriver; int status = 0; @@ -843,7 +863,7 @@ done: } /* Caller has locked intf's usb_device's pm mutex */ -static int suspend_interface(struct usb_interface *intf, pm_message_t msg) +static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg) { struct usb_driver *driver; int status = 0; @@ -880,7 +900,7 @@ done: } /* Caller has locked intf's usb_device's pm_mutex */ -static int resume_interface(struct usb_interface *intf) +static int usb_resume_interface(struct usb_interface *intf) { struct usb_driver *driver; int status = 0; @@ -920,6 +940,44 @@ done: return status; } +#ifdef CONFIG_USB_SUSPEND + +/* Internal routine to check whether we may autosuspend a device. */ +static int autosuspend_check(struct usb_device *udev) +{ + int i; + struct usb_interface *intf; + + /* For autosuspend, fail fast if anything is in use. + * Also fail if any interfaces require remote wakeup but it + * isn't available. */ + udev->do_remote_wakeup = device_may_wakeup(&udev->dev); + if (udev->pm_usage_cnt > 0) + return -EBUSY; + if (udev->actconfig) { + for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { + intf = udev->actconfig->interface[i]; + if (!is_active(intf)) + continue; + if (intf->pm_usage_cnt > 0) + return -EBUSY; + if (intf->needs_remote_wakeup && + !udev->do_remote_wakeup) { + dev_dbg(&udev->dev, "remote wakeup needed " + "for autosuspend\n"); + return -EOPNOTSUPP; + } + } + } + return 0; +} + +#else + +#define autosuspend_check(udev) 0 + +#endif + /** * usb_suspend_both - suspend a USB device and its interfaces * @udev: the usb_device to suspend @@ -971,52 +1029,34 @@ int usb_suspend_both(struct usb_device *udev, pm_message_t msg) udev->do_remote_wakeup = device_may_wakeup(&udev->dev); - /* For autosuspend, fail fast if anything is in use. - * Also fail if any interfaces require remote wakeup but it - * isn't available. */ if (udev->auto_pm) { - if (udev->pm_usage_cnt > 0) - return -EBUSY; - if (udev->actconfig) { - for (; i < udev->actconfig->desc.bNumInterfaces; i++) { - intf = udev->actconfig->interface[i]; - if (!is_active(intf)) - continue; - if (intf->pm_usage_cnt > 0) - return -EBUSY; - if (intf->needs_remote_wakeup && - !udev->do_remote_wakeup) { - dev_dbg(&udev->dev, - "remote wakeup needed for autosuspend\n"); - return -EOPNOTSUPP; - } - } - i = 0; - } + status = autosuspend_check(udev); + if (status < 0) + return status; } /* Suspend all the interfaces and then udev itself */ if (udev->actconfig) { for (; i < udev->actconfig->desc.bNumInterfaces; i++) { intf = udev->actconfig->interface[i]; - status = suspend_interface(intf, msg); + status = usb_suspend_interface(intf, msg); if (status != 0) break; } } if (status == 0) - status = suspend_device(udev, msg); + status = usb_suspend_device(udev, msg); /* If the suspend failed, resume interfaces that did get suspended */ if (status != 0) { while (--i >= 0) { intf = udev->actconfig->interface[i]; - resume_interface(intf); + usb_resume_interface(intf); } /* If the suspend succeeded, propagate it up the tree */ } else if (parent) - usb_autosuspend_device(parent, 0); + usb_autosuspend_device(parent); // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); return status; @@ -1064,9 +1104,25 @@ int usb_resume_both(struct usb_device *udev) /* Propagate the resume up the tree, if necessary */ if (udev->state == USB_STATE_SUSPENDED) { if (parent) { - usb_pm_lock(parent); - parent->auto_pm = 1; - status = usb_resume_both(parent); + status = usb_autoresume_device(parent); + if (status == 0) { + status = usb_resume_device(udev); + if (status) { + usb_autosuspend_device(parent); + + /* It's possible usb_resume_device() + * failed after the port was + * unsuspended, causing udev to be + * logically disconnected. We don't + * want usb_disconnect() to autosuspend + * the parent again, so tell it that + * udev disconnected while still + * suspended. */ + if (udev->state == + USB_STATE_NOTATTACHED) + udev->discon_suspended = 1; + }< |