#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/smp_lock.h>
+#include <linux/rwsem.h>
#include <linux/usb.h>
#include <asm/io.h>
int nousb; /* Disable USB when built into kernel image */
/* Not honored on modular build */
+static DECLARE_RWSEM(usb_all_devices_rwsem);
+
static int generic_probe (struct device *dev)
{
}
static struct device_driver usb_generic_driver = {
+ .owner = THIS_MODULE,
.name = "usb",
.bus = &usb_bus_type,
.probe = generic_probe,
if (!driver->probe)
return error;
+ /* FIXME we'd much prefer to just resume it ... */
+ if (interface_to_usbdev(intf)->state == USB_STATE_SUSPENDED)
+ return -EHOSTUNREACH;
id = usb_match_id (intf, driver->id_table);
if (id) {
dev_dbg (dev, "%s - got id\n", __FUNCTION__);
+ intf->condition = USB_INTERFACE_BINDING;
error = driver->probe (intf, id);
+ intf->condition = error ? USB_INTERFACE_UNBOUND :
+ USB_INTERFACE_BOUND;
}
return error;
struct usb_interface *intf = to_usb_interface(dev);
struct usb_driver *driver = to_usb_driver(intf->dev.driver);
+ intf->condition = USB_INTERFACE_UNBINDING;
+
/* release all urbs for this interface */
usb_disable_interface(interface_to_usbdev(intf), intf);
intf->altsetting[0].desc.bInterfaceNumber,
0);
usb_set_intfdata(intf, NULL);
+ intf->condition = USB_INTERFACE_UNBOUND;
return 0;
}
new_driver->driver.bus = &usb_bus_type;
new_driver->driver.probe = usb_probe_interface;
new_driver->driver.remove = usb_unbind_interface;
+ new_driver->driver.owner = new_driver->owner;
+ usb_lock_all_devices();
retval = driver_register(&new_driver->driver);
+ usb_unlock_all_devices();
if (!retval) {
pr_info("%s: registered new driver %s\n",
{
pr_info("%s: deregistering driver %s\n", usbcore_name, driver->name);
+ usb_lock_all_devices();
driver_unregister (&driver->driver);
+ usb_unlock_all_devices();
usbfs_update_special();
}
* alternate settings available for this interfaces.
*
* Don't call this function unless you are bound to one of the interfaces
- * on this device or you own the dev->serialize semaphore!
+ * on this device or you have locked the device!
*/
struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
{
* drivers avoid such mistakes.
*
* Don't call this function unless you are bound to the intf interface
- * or you own the device's ->serialize semaphore!
+ * or you have locked the device!
*/
struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf,
unsigned int altnum)
return NULL;
}
-/**
- * usb_epnum_to_ep_desc - get the endpoint object with a given endpoint number
- * @dev: the device whose current configuration+altsettings is considered
- * @epnum: the desired endpoint, masked with USB_DIR_IN as appropriate.
- *
- * This walks the device descriptor for the currently active configuration,
- * and returns a pointer to the endpoint with that particular endpoint
- * number, or null.
- *
- * Note that interface descriptors are not required to list endpoint
- * numbers in any standardized order, so that it would be wrong to
- * assume that ep2in precedes either ep5in, ep2out, or even ep1out.
- * This routine helps device drivers avoid such mistakes.
- */
-struct usb_endpoint_descriptor *
-usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum)
-{
- struct usb_host_config *config = dev->actconfig;
- int i, k;
-
- if (!config)
- return NULL;
- for (i = 0; i < config->desc.bNumInterfaces; i++) {
- struct usb_interface *intf;
- struct usb_host_interface *alt;
-
- /* only endpoints in current altsetting are active */
- intf = config->interface[i];
- alt = intf->cur_altsetting;
-
- for (k = 0; k < alt->desc.bNumEndpoints; k++)
- if (epnum == alt->endpoint[k].desc.bEndpointAddress)
- return &alt->endpoint[k].desc;
- }
-
- return NULL;
-}
-
/**
* usb_driver_claim_interface - bind a driver to an interface
* @driver: the driver to be bound
* way to bind to an interface is to return the private data from
* the driver's probe() method.
*
- * Callers must own the driver model's usb bus writelock. So driver
- * probe() entries don't need extra locking, but other call contexts
- * may need to explicitly claim that lock.
+ * Callers must own the device lock and the driver model's usb_bus_type.subsys
+ * writelock. So driver probe() entries don't need extra locking,
+ * but other call contexts may need to explicitly claim those locks.
*/
-int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv)
+int usb_driver_claim_interface(struct usb_driver *driver,
+ struct usb_interface *iface, void* priv)
{
struct device *dev = &iface->dev;
dev->driver = &driver->driver;
usb_set_intfdata(iface, priv);
+ iface->condition = USB_INTERFACE_BOUND;
/* if interface was already added, bind now; else let
* the future device_add() bind it, bypassing probe()
* also causes the driver disconnect() method to be called.
*
* This call is synchronous, and may not be used in an interrupt context.
- * Callers must own the usb_device serialize semaphore and the driver model's
- * usb bus writelock. So driver disconnect() entries don't need extra locking,
+ * Callers must own the device lock and the driver model's usb_bus_type.subsys
+ * writelock. So driver disconnect() entries don't need extra locking,
* but other call contexts may need to explicitly claim those locks.
*/
void usb_driver_release_interface(struct usb_driver *driver,
dev->driver = NULL;
usb_set_intfdata(iface, NULL);
+ iface->condition = USB_INTERFACE_UNBOUND;
}
/**
id->driver_info; id++) {
if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
- id->idVendor != dev->descriptor.idVendor)
+ id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
continue;
if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
- id->idProduct != dev->descriptor.idProduct)
+ id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
continue;
/* No need to test id->bcdDevice_lo != 0, since 0 is never
greater than any unsigned number. */
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
- (id->bcdDevice_lo > dev->descriptor.bcdDevice))
+ (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
continue;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
- (id->bcdDevice_hi < dev->descriptor.bcdDevice))
+ (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
continue;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
return 0;
intf = to_usb_interface(dev);
-
usb_drv = to_usb_driver(drv);
- id = usb_drv->id_table;
id = usb_match_id (intf, usb_drv->id_table);
if (id)
{
struct usb_interface *intf;
struct usb_device *usb_dev;
- char *scratch;
int i = 0;
int length = 0;
return -ENODEV;
}
- scratch = buffer;
-
#ifdef CONFIG_USB_DEVICEFS
/* If this is available, userspace programs can directly read
* all the device descriptors we don't tell them about. Or
*
* FIXME reduce hardwired intelligence here
*/
- envp [i++] = scratch;
- length += snprintf (scratch, buffer_size - length,
- "DEVICE=/proc/bus/usb/%03d/%03d",
- usb_dev->bus->busnum, usb_dev->devnum);
- if ((buffer_size - length <= 0) || (i >= num_envp))
+ if (add_hotplug_env_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "DEVICE=/proc/bus/usb/%03d/%03d",
+ usb_dev->bus->busnum, usb_dev->devnum))
return -ENOMEM;
- ++length;
- scratch += length;
#endif
/* per-device configurations are common */
- envp [i++] = scratch;
- length += snprintf (scratch, buffer_size - length, "PRODUCT=%x/%x/%x",
- usb_dev->descriptor.idVendor,
- usb_dev->descriptor.idProduct,
- usb_dev->descriptor.bcdDevice);
- if ((buffer_size - length <= 0) || (i >= num_envp))
+ if (add_hotplug_env_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "PRODUCT=%x/%x/%x",
+ le16_to_cpu(usb_dev->descriptor.idVendor),
+ le16_to_cpu(usb_dev->descriptor.idProduct),
+ le16_to_cpu(usb_dev->descriptor.bcdDevice)))
return -ENOMEM;
- ++length;
- scratch += length;
/* class-based driver binding models */
- envp [i++] = scratch;
- length += snprintf (scratch, buffer_size - length, "TYPE=%d/%d/%d",
- usb_dev->descriptor.bDeviceClass,
- usb_dev->descriptor.bDeviceSubClass,
- usb_dev->descriptor.bDeviceProtocol);
- if ((buffer_size - length <= 0) || (i >= num_envp))
+ if (add_hotplug_env_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "TYPE=%d/%d/%d",
+ usb_dev->descriptor.bDeviceClass,
+ usb_dev->descriptor.bDeviceSubClass,
+ usb_dev->descriptor.bDeviceProtocol))
return -ENOMEM;
- ++length;
- scratch += length;
if (usb_dev->descriptor.bDeviceClass == 0) {
struct usb_host_interface *alt = intf->cur_altsetting;
* agents are called for all interfaces, and can use
* $DEVPATH/bInterfaceNumber if necessary.
*/
- envp [i++] = scratch;
- length += snprintf (scratch, buffer_size - length,
- "INTERFACE=%d/%d/%d",
- alt->desc.bInterfaceClass,
- alt->desc.bInterfaceSubClass,
- alt->desc.bInterfaceProtocol);
- if ((buffer_size - length <= 0) || (i >= num_envp))
+ if (add_hotplug_env_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "INTERFACE=%d/%d/%d",
+ alt->desc.bInterfaceClass,
+ alt->desc.bInterfaceSubClass,
+ alt->desc.bInterfaceProtocol))
return -ENOMEM;
- ++length;
- scratch += length;
-
}
- envp [i++] = 0;
+
+ envp[i] = NULL;
return 0;
}
udev = to_usb_device(dev);
- if (udev->bus && udev->bus->op && udev->bus->op->deallocate)
- udev->bus->op->deallocate(udev);
usb_destroy_configuration(udev);
usb_bus_put(udev->bus);
kfree (udev);
* usb_alloc_dev - usb device constructor (usbcore-internal)
* @parent: hub to which device is connected; null to allocate a root hub
* @bus: bus used to access the device
- * @port: zero based index of port; ignored for root hubs
+ * @port1: one-based index of port; ignored for root hubs
* Context: !in_interrupt ()
*
* Only hub drivers (including virtual root hub drivers for host
* This call may not be used in a non-sleeping context.
*/
struct usb_device *
-usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port)
+usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
{
struct usb_device *dev;
dev->dev.release = usb_release_dev;
dev->state = USB_STATE_ATTACHED;
+ INIT_LIST_HEAD(&dev->ep0.urb_list);
+ dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
+ dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
+ /* ep0 maxpacket comes later, from device descriptor */
+ dev->ep_in[0] = dev->ep_out[0] = &dev->ep0;
+
/* Save readable and stable topology id, distinguishing devices
* by location for diagnostics, tools, driver model, etc. The
* string is a path along hub ports, from the root. Each device's
/* match any labeling on the hubs; it's one-based */
if (parent->devpath [0] == '0')
snprintf (dev->devpath, sizeof dev->devpath,
- "%d", port + 1);
+ "%d", port1);
else
snprintf (dev->devpath, sizeof dev->devpath,
- "%s.%d", parent->devpath, port + 1);
+ "%s.%d", parent->devpath, port1);
dev->dev.parent = &parent->dev;
sprintf (&dev->dev.bus_id[0], "%d-%s",
init_MUTEX(&dev->serialize);
- if (dev->bus->op->allocate)
- dev->bus->op->allocate(dev);
-
return dev;
}
put_device(&intf->dev);
}
+
+/* USB device locking
+ *
+ * Although locking USB devices should be straightforward, it is
+ * complicated by the way the driver-model core works. When a new USB
+ * driver is registered or unregistered, the core will automatically
+ * probe or disconnect all matching interfaces on all USB devices while
+ * holding the USB subsystem writelock. There's no good way for us to
+ * tell which devices will be used or to lock them beforehand; our only
+ * option is to effectively lock all the USB devices.
+ *
+ * We do that by using a private rw-semaphore, usb_all_devices_rwsem.
+ * When locking an individual device you must first acquire the rwsem's
+ * readlock. When a driver is registered or unregistered the writelock
+ * must be held. These actions are encapsulated in the subroutines
+ * below, so all a driver needs to do is call usb_lock_device() and
+ * usb_unlock_device().
+ *
+ * Complications arise when several devices are to be locked at the same
+ * time. Only hub-aware drivers that are part of usbcore ever have to
+ * do this; nobody else needs to worry about it. The problem is that
+ * usb_lock_device() must not be called to lock a second device since it
+ * would acquire the rwsem's readlock reentrantly, leading to deadlock if
+ * another thread was waiting for the writelock. The solution is simple:
+ *
+ * When locking more than one device, call usb_lock_device()
+ * to lock the first one. Lock the others by calling
+ * down(&udev->serialize) directly.
+ *
+ * When unlocking multiple devices, use up(&udev->serialize)
+ * to unlock all but the last one. Unlock the last one by
+ * calling usb_unlock_device().
+ *
+ * When locking both a device and its parent, always lock the
+ * the parent first.
+ */
+
+/**
+ * usb_lock_device - acquire the lock for a usb device structure
+ * @udev: device that's being locked
+ *
+ * Use this routine when you don't hold any other device locks;
+ * to acquire nested inner locks call down(&udev->serialize) directly.
+ * This is necessary for proper interaction with usb_lock_all_devices().
+ */
+void usb_lock_device(struct usb_device *udev)
+{
+ down_read(&usb_all_devices_rwsem);
+ down(&udev->serialize);
+}
+
+/**
+ * usb_trylock_device - attempt to acquire the lock for a usb device structure
+ * @udev: device that's being locked
+ *
+ * Don't use this routine if you already hold a device lock;
+ * use down_trylock(&udev->serialize) instead.
+ * This is necessary for proper interaction with usb_lock_all_devices().
+ *
+ * Returns 1 if successful, 0 if contention.
+ */
+int usb_trylock_device(struct usb_device *udev)
+{
+ if (!down_read_trylock(&usb_all_devices_rwsem))
+ return 0;
+ if (down_trylock(&udev->serialize)) {
+ up_read(&usb_all_devices_rwsem);
+ return 0;
+ }
+ return 1;
+}
+
+/**
+ * usb_lock_device_for_reset - cautiously acquire the lock for a
+ * usb device structure
+ * @udev: device that's being locked
+ * @iface: interface bound to the driver making the request (optional)
+ *
+ * Attempts to acquire the device lock, but fails if the device is
+ * NOTATTACHED or SUSPENDED, or if iface is specified and the interface
+ * is neither BINDING nor BOUND. Rather than sleeping to wait for the
+ * lock, the routine polls repeatedly. This is to prevent deadlock with
+ * disconnect; in some drivers (such as usb-storage) the disconnect()
+ * callback will block waiting for a device reset to complete.
+ *
+ * Returns a negative error code for failure, otherwise 1 or 0 to indicate
+ * that the device will or will not have to be unlocked. (0 can be
+ * returned when an interface is given and is BINDING, because in that
+ * case the driver already owns the device lock.)
+ */
+int usb_lock_device_for_reset(struct usb_device *udev,
+ struct usb_interface *iface)
+{
+ if (udev->state == USB_STATE_NOTATTACHED)
+ return -ENODEV;
+ if (udev->state == USB_STATE_SUSPENDED)
+ return -EHOSTUNREACH;
+ if (iface) {
+ switch (iface->condition) {
+ case USB_INTERFACE_BINDING:
+ return 0;
+ case USB_INTERFACE_BOUND:
+ break;
+ default:
+ return -EINTR;
+ }
+ }
+
+ while (!usb_trylock_device(udev)) {
+ msleep(15);
+ if (udev->state == USB_STATE_NOTATTACHED)
+ return -ENODEV;
+ if (udev->state == USB_STATE_SUSPENDED)
+ return -EHOSTUNREACH;
+ if (iface && iface->condition != USB_INTERFACE_BOUND)
+ return -EINTR;
+ }
+ return 1;
+}
+
+/**
+ * usb_unlock_device - release the lock for a usb device structure
+ * @udev: device that's being unlocked
+ *
+ * Use this routine when releasing the only device lock you hold;
+ * to release inner nested locks call up(&udev->serialize) directly.
+ * This is necessary for proper interaction with usb_lock_all_devices().
+ */
+void usb_unlock_device(struct usb_device *udev)
+{
+ up(&udev->serialize);
+ up_read(&usb_all_devices_rwsem);
+}
+
+/**
+ * usb_lock_all_devices - acquire the lock for all usb device structures
+ *
+ * This is necessary when registering a new driver or probing a bus,
+ * since the driver-model core may try to use any usb_device.
+ */
+void usb_lock_all_devices(void)
+{
+ down_write(&usb_all_devices_rwsem);
+}
+
+/**
+ * usb_unlock_all_devices - release the lock for all usb device structures
+ */
+void usb_unlock_all_devices(void)
+{
+ up_write(&usb_all_devices_rwsem);
+}
+
+
static struct usb_device *match_device(struct usb_device *dev,
u16 vendor_id, u16 product_id)
{
int child;
dev_dbg(&dev->dev, "check for vendor %04x, product %04x ...\n",
- dev->descriptor.idVendor,
- dev->descriptor.idProduct);
+ le16_to_cpu(dev->descriptor.idVendor),
+ le16_to_cpu(dev->descriptor.idProduct));
/* see if this device matches */
- if ((dev->descriptor.idVendor == vendor_id) &&
- (dev->descriptor.idProduct == product_id)) {
+ if ((vendor_id == le16_to_cpu(dev->descriptor.idVendor)) &&
+ (product_id == le16_to_cpu(dev->descriptor.idProduct))) {
dev_dbg (&dev->dev, "matched this device!\n");
ret_dev = usb_get_dev(dev);
goto exit;
/* look through all of the children of this device */
for (child = 0; child < dev->maxchild; ++child) {
if (dev->children[child]) {
+ down(&dev->children[child]->serialize);
ret_dev = match_device(dev->children[child],
vendor_id, product_id);
+ up(&dev->children[child]->serialize);
if (ret_dev)
goto exit;
}
buslist != &usb_bus_list;
buslist = buslist->next) {
bus = container_of(buslist, struct usb_bus, bus_list);
+ if (!bus->root_hub)
+ continue;
+ usb_lock_device(bus->root_hub);
dev = match_device(bus->root_hub, vendor_id, product_id);
+ usb_unlock_device(bus->root_hub);
if (dev)
goto exit;
}
return -1;
}
-/**
- * usb_disconnect - disconnect a device (usbcore-internal)
- * @pdev: pointer to device being disconnected
- * Context: !in_interrupt ()
- *
- * Something got disconnected. Get rid of it, and all of its children.
- *
- * Only hub drivers (including virtual root hub drivers for host
- * controllers) should ever call this.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- */
-void usb_disconnect(struct usb_device **pdev)
-{
- struct usb_device *dev = *pdev;
- struct usb_bus *bus;
- struct usb_operations *ops;
- int i;
-
- might_sleep ();
-
- if (!dev) {
- pr_debug ("%s nodev\n", __FUNCTION__);
- return;
- }
- bus = dev->bus;
- if (!bus) {
- pr_debug ("%s nobus\n", __FUNCTION__);
- return;
- }
- ops = bus->op;
-
- *pdev = NULL;
-
- /* mark the device as inactive, so any further urb submissions for
- * this device will fail.
- */
- dev->state = USB_STATE_NOTATTACHED;
- down(&dev->serialize);
-
- dev_info (&dev->dev, "USB disconnect, address %d\n", dev->devnum);
-
- /* Free up all the children before we remove this device */
- for (i = 0; i < USB_MAXCHILDREN; i++) {
- struct usb_device **child = dev->children + i;
- if (*child)
- usb_disconnect(child);
- }
-
- /* deallocate hcd/hardware state ... nuking all pending urbs and
- * cleaning up all state associated with the current configuration
- */
- usb_disable_device(dev, 0);
-
- /* Free the device number and remove the /proc/bus/usb entry */
- dev_dbg (&dev->dev, "unregistering device\n");
- usb_release_address(dev);
- usbfs_remove_device(dev);
- up(&dev->serialize);
- device_unregister(&dev->dev);
-}
-
-/**
- * usb_choose_address - pick device address (usbcore-internal)
- * @dev: newly detected device (in DEFAULT state)
- *
- * Picks a device address. It's up to the hub (or root hub) driver
- * to handle and manage enumeration, starting from the DEFAULT state.
- * Only hub drivers (but not virtual root hub drivers for host
- * controllers) should ever call this.
- */
-void usb_choose_address(struct usb_device *dev)
-{
- int devnum;
- // FIXME needs locking for SMP!!
- /* why? this is called only from the hub thread,
- * which hopefully doesn't run on multiple CPU's simultaneously 8-)
- */
-
- /* Try to allocate the next devnum beginning at bus->devnum_next. */
- devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, dev->bus->devnum_next);
- if (devnum >= 128)
- devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1);
-
- dev->bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1);
-
- if (devnum < 128) {
- set_bit(devnum, dev->bus->devmap.devicemap);
- dev->devnum = devnum;
- }
-}
-
-/**
- * usb_release_address - deallocate device address (usbcore-internal)
- * @dev: newly removed device
- *
- * Removes and deallocates the address assigned to a device.
- * Only hub drivers (but not virtual root hub drivers for host
- * controllers) should ever call this.
- */
-void usb_release_address(struct usb_device *dev)
-{
- if (dev->devnum > 0) {
- clear_bit(dev->devnum, dev->bus->devmap.devicemap);
- dev->devnum = -1;
- }
-}
-
-
-static inline void usb_show_string(struct usb_device *dev, char *id, int index)
-{
- char *buf;
-
- if (!index)
- return;
- if (!(buf = kmalloc(256, GFP_KERNEL)))
- return;
- if (usb_string(dev, index, buf, 256) > 0)
- dev_printk(KERN_INFO, &dev->dev, "%s: %s\n", id, buf);
- kfree(buf);
-}
-
-static int usb_choose_configuration(struct usb_device *dev)
-{
- int c, i;
-
- c = dev->config[0].desc.bConfigurationValue;
- if (dev->descriptor.bNumConfigurations != 1) {
- for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
- struct usb_interface_descriptor *desc;
-
- /* heuristic: Linux is more likely to have class
- * drivers, so avoid vendor-specific interfaces.
- */
- desc = &dev->config[i].intf_cache[0]
- ->altsetting->desc;
- if (desc->bInterfaceClass == USB_CLASS_VENDOR_SPEC)
- continue;
- /* COMM/2/all is CDC ACM, except 0xff is MSFT RNDIS */
- if (desc->bInterfaceClass == USB_CLASS_COMM
- && desc->bInterfaceSubClass == 2
- && desc->bInterfaceProtocol == 0xff)
- continue;
- c = dev->config[i].desc.bConfigurationValue;
- break;
- }
- dev_info(&dev->dev,
- "configuration #%d chosen from %d choices\n",
- c, dev->descriptor.bNumConfigurations);
- }
- return c;
-}
-
-/*
- * usb_new_device - perform initial device setup (usbcore-internal)
- * @dev: newly addressed device (in ADDRESS state)
- *
- * This is called with devices which have been enumerated, but not yet
- * configured. The device descriptor is available, but not descriptors
- * for any device configuration. The caller owns dev->serialize, and
- * the device is not visible through sysfs or other filesystem code.
- *
- * Returns 0 for success (device is configured and listed, with its
- * interfaces, in sysfs); else a negative errno value. On error, one
- * reference count to the device has been dropped.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- *
- * Only the hub driver should ever call this; root hub registration
- * uses it only indirectly.
- */
-int usb_new_device(struct usb_device *dev)
-{
- int err;
- int c;
-
- err = usb_get_configuration(dev);
- if (err < 0) {
- dev_err(&dev->dev, "can't read configurations, error %d\n",
- err);
- goto fail;
- }
-
- /* Tell the world! */
- dev_dbg(&dev->dev, "new device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",
- dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber);
-
-#ifdef DEBUG
- if (dev->descriptor.iProduct)
- usb_show_string(dev, "Product", dev->descriptor.iProduct);
- if (dev->descriptor.iManufacturer)
- usb_show_string(dev, "Manufacturer", dev->descriptor.iManufacturer);
- if (dev->descriptor.iSerialNumber)
- usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
-#endif
-
- /* put device-specific files into sysfs */
- err = device_add (&dev->dev);
- if (err) {
- dev_err(&dev->dev, "can't device_add, error %d\n", err);
- goto fail;
- }
- usb_create_sysfs_dev_files (dev);
-
- /* choose and set the configuration. that registers the interfaces
- * with the driver core, and lets usb device drivers bind to them.
- * NOTE: should interact with hub power budgeting.
- */
- c = usb_choose_configuration(dev);
- err = usb_set_configuration(dev, c);
- if (err) {
- dev_err(&dev->dev, "can't set config #%d, error %d\n", c, err);
- device_del(&dev->dev);
- goto fail;
- }
-
- /* USB device state == configured ... usable */
-
- /* add a /proc/bus/usb entry */
- usbfs_add_device(dev);
-
- return 0;
-fail:
- dev->state = USB_STATE_NOTATTACHED;
- usb_release_address(dev);
- usb_put_dev(dev);
- return err;
-}
-
/**
* usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_xxx_DMA_MAP
* @dev: device the buffer will be used with
)
{
if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_alloc)
- return 0;
+ return NULL;
return dev->bus->op->buffer_alloc (dev->bus, size, mem_flags, dma);
}
|| !urb->dev
|| !(bus = urb->dev->bus)
|| !(controller = bus->controller))
- return 0;
+ return NULL;
if (controller->dma_mask) {
urb->transfer_dma = dma_map_single (controller,
usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
-static int usb_device_suspend(struct device *dev, u32 state)
+static int usb_generic_suspend(struct device *dev, u32 state)
{
struct usb_interface *intf;
struct usb_driver *driver;
+ if (dev->driver == &usb_generic_driver)
+ return usb_suspend_device (to_usb_device(dev), state);
+
if ((dev->driver == NULL) ||
- (dev->driver == &usb_generic_driver) ||
(dev->driver_data == &usb_generic_driver_data))
return 0;
intf = to_usb_interface(dev);
driver = to_usb_driver(dev->driver);
+ /* there's only one USB suspend state */
+ if (intf->dev.power.power_state)
+ return 0;
+
if (driver->suspend)
return driver->suspend(intf, state);
return 0;
}
-static int usb_device_resume(struct device *dev)
+static int usb_generic_resume(struct device *dev)
{
struct usb_interface *intf;
struct usb_driver *driver;
+ /* devices resume through their hub */
+ if (dev->driver == &usb_generic_driver)
+ return usb_resume_device (to_usb_device(dev));
+
if ((dev->driver == NULL) ||
- (dev->driver == &usb_generic_driver) ||
(dev->driver_data == &usb_generic_driver_data))
return 0;
.name = "usb",
.match = usb_device_match,
.hotplug = usb_hotplug,
- .suspend = usb_device_suspend,
- .resume = usb_device_resume,
+ .suspend = usb_generic_suspend,
+ .resume = usb_generic_resume,
};
#ifndef MODULE
retval = bus_register(&usb_bus_type);
if (retval)
goto out;
- usb_host_init();
+ retval = usb_host_init();
+ if (retval)
+ goto host_init_failed;
retval = usb_major_init();
if (retval)
goto major_init_failed;
usb_major_cleanup();
major_init_failed:
usb_host_cleanup();
+host_init_failed:
bus_unregister(&usb_bus_type);
out:
return retval;
* These symbols are exported for device (or host controller)
* driver modules to use.
*/
-EXPORT_SYMBOL(usb_epnum_to_ep_desc);
EXPORT_SYMBOL(usb_register);
EXPORT_SYMBOL(usb_deregister);
EXPORT_SYMBOL(usb_get_dev);
EXPORT_SYMBOL(usb_hub_tt_clear_buffer);
+EXPORT_SYMBOL(usb_lock_device);
+EXPORT_SYMBOL(usb_trylock_device);
+EXPORT_SYMBOL(usb_lock_device_for_reset);
+EXPORT_SYMBOL(usb_unlock_device);
+
EXPORT_SYMBOL(usb_driver_claim_interface);
EXPORT_SYMBOL(usb_driver_release_interface);
EXPORT_SYMBOL(usb_match_id);