X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fusb%2Fcore%2Fusb.c;h=99268c2e51647af25a6a74308d602e15e9d459be;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=de2edfb08582eebf24b8cc94f7e975a693c9e01a;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index de2edfb08..99268c2e5 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -62,6 +63,8 @@ const char *usbcore_name = "usbcore"; 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) { @@ -73,6 +76,7 @@ static int generic_remove (struct device *dev) } static struct device_driver usb_generic_driver = { + .owner = THIS_MODULE, .name = "usb", .bus = &usb_bus_type, .probe = generic_probe, @@ -93,13 +97,17 @@ int usb_probe_interface(struct device *dev) 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; @@ -111,6 +119,8 @@ int usb_unbind_interface(struct device *dev) 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); @@ -122,6 +132,7 @@ int usb_unbind_interface(struct device *dev) intf->altsetting[0].desc.bInterfaceNumber, 0); usb_set_intfdata(intf, NULL); + intf->condition = USB_INTERFACE_UNBOUND; return 0; } @@ -150,8 +161,11 @@ int usb_register(struct usb_driver *new_driver) 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", @@ -180,7 +194,9 @@ void usb_deregister(struct usb_driver *driver) { 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(); } @@ -202,7 +218,7 @@ void usb_deregister(struct usb_driver *driver) * 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) { @@ -235,7 +251,7 @@ 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) @@ -249,44 +265,6 @@ struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf, 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 @@ -303,11 +281,12 @@ usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum) * 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; @@ -316,6 +295,7 @@ int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface * 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() @@ -336,8 +316,8 @@ int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface * * 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, @@ -355,6 +335,7 @@ void usb_driver_release_interface(struct usb_driver *driver, dev->driver = NULL; usb_set_intfdata(iface, NULL); + iface->condition = USB_INTERFACE_UNBOUND; } /** @@ -441,21 +422,21 @@ usb_match_id(struct usb_interface *interface, const struct usb_device_id *id) 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) && @@ -532,9 +513,7 @@ static int usb_device_match (struct device *dev, struct device_driver *drv) 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) @@ -564,7 +543,6 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp, { struct usb_interface *intf; struct usb_device *usb_dev; - char *scratch; int i = 0; int length = 0; @@ -591,8 +569,6 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp, 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 @@ -600,37 +576,30 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp, * * 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; @@ -639,19 +608,16 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp, * 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++] = NULL; + + envp[i] = NULL; return 0; } @@ -679,8 +645,6 @@ static void usb_release_dev(struct device *dev) 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); @@ -690,7 +654,7 @@ static void usb_release_dev(struct device *dev) * 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 @@ -699,7 +663,7 @@ static void usb_release_dev(struct device *dev) * 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; @@ -723,6 +687,12 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port) 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 @@ -740,10 +710,10 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port) /* 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", @@ -758,9 +728,6 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port) init_MUTEX(&dev->serialize); - if (dev->bus->op->allocate) - dev->bus->op->allocate(dev); - return dev; } @@ -830,6 +797,160 @@ void usb_put_intf(struct usb_interface *intf) 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) { @@ -837,12 +958,12 @@ static struct usb_device *match_device(struct usb_device *dev, 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; @@ -851,8 +972,10 @@ static struct usb_device *match_device(struct usb_device *dev, /* 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; } @@ -887,7 +1010,9 @@ struct usb_device *usb_find_device(u16 vendor_id, u16 product_id) 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; } @@ -1238,6 +1363,10 @@ static int usb_generic_suspend(struct device *dev, u32 state) 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; @@ -1362,7 +1491,6 @@ module_exit(usb_exit); * 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); @@ -1373,6 +1501,11 @@ EXPORT_SYMBOL(usb_put_dev); 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);