X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fusb%2Fcore%2Fusb.c;h=de2edfb08582eebf24b8cc94f7e975a693c9e01a;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=0da70f7af71daa426746af4fee463a1b7f7cfd18;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 0da70f7af..de2edfb08 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -93,6 +93,8 @@ int usb_probe_interface(struct device *dev) if (!driver->probe) return error; + if (interface_to_usbdev(intf)->state == USB_STATE_SUSPENDED) + return -EHOSTUNREACH; id = usb_match_id (intf, driver->id_table); if (id) { @@ -198,6 +200,9 @@ void usb_deregister(struct usb_driver *driver) * This routine helps device drivers avoid such mistakes. * However, you should make sure that you do the right thing with any * 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! */ struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum) { @@ -228,6 +233,9 @@ struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum) * it would be incorrect to assume that the first altsetting entry in * the array corresponds to altsetting zero. This routine helps device * 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! */ struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf, unsigned int altnum) @@ -643,7 +651,7 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp, scratch += length; } - envp [i++] = 0; + envp[i++] = NULL; return 0; } @@ -877,6 +885,8 @@ struct usb_device *usb_find_device(u16 vendor_id, u16 product_id) buslist != &usb_bus_list; buslist = buslist->next) { bus = container_of(buslist, struct usb_bus, bus_list); + if (!bus->root_hub) + continue; dev = match_device(bus->root_hub, vendor_id, product_id); if (dev) goto exit; @@ -938,300 +948,6 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, 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); - - dev_dbg (&dev->dev, "unregistering device\n"); - /* Free the device number and remove the /proc/bus/usb entry */ - if (dev->devnum > 0) { - clear_bit(dev->devnum, dev->bus->devmap.devicemap); - 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; - } -} - - -// hub-only!! ... and only exported for reset/reinit path. -// otherwise used internally, for usb_new_device() -int usb_set_address(struct usb_device *dev) -{ - int retval; - - if (dev->devnum == 0) - return -EINVAL; - if (dev->state != USB_STATE_DEFAULT && dev->state != USB_STATE_ADDRESS) - return -EINVAL; - retval = usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS, - 0, dev->devnum, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); - if (retval == 0) - dev->state = USB_STATE_ADDRESS; - return retval; -} - -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); -} - -/* - * By the time we get here, we chose a new device address - * and is in the default state. We need to identify the thing and - * get the ball rolling.. - * - * Returns 0 for success, != 0 for error. - * - * 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. - */ -#define NEW_DEVICE_RETRYS 2 -#define SET_ADDRESS_RETRYS 2 -int usb_new_device(struct usb_device *dev) -{ - int err = -EINVAL; - int i; - int j; - int config; - - /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ... - * it's fixed size except for full speed devices. - */ - switch (dev->speed) { - case USB_SPEED_HIGH: /* fixed at 64 */ - i = 64; - break; - case USB_SPEED_FULL: /* 8, 16, 32, or 64 */ - /* to determine the ep0 maxpacket size, read the first 8 - * bytes from the device descriptor to get bMaxPacketSize0; - * then correct our initial (small) guess. - */ - // FALLTHROUGH - case USB_SPEED_LOW: /* fixed at 8 */ - i = 8; - break; - default: - goto fail; - } - dev->epmaxpacketin [0] = i; - dev->epmaxpacketout[0] = i; - - for (i = 0; i < NEW_DEVICE_RETRYS; ++i) { - - for (j = 0; j < SET_ADDRESS_RETRYS; ++j) { - err = usb_set_address(dev); - if (err >= 0) - break; - wait_ms(200); - } - if (err < 0) { - dev_err(&dev->dev, - "device not accepting address %d, error %d\n", - dev->devnum, err); - goto fail; - } - - wait_ms(10); /* Let the SET_ADDRESS settle */ - - /* high and low speed devices don't need this... */ - err = usb_get_device_descriptor(dev, 8); - if (err >= 8) - break; - wait_ms(100); - } - - if (err < 8) { - dev_err(&dev->dev, "device descriptor read/8, error %d\n", err); - goto fail; - } - if (dev->speed == USB_SPEED_FULL) { - usb_disable_endpoint(dev, 0); - usb_endpoint_running(dev, 0, 1); - usb_endpoint_running(dev, 0, 0); - dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0; - dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0; - } - - /* USB device state == addressed ... still not usable */ - - err = usb_get_device_descriptor(dev, sizeof(dev->descriptor)); - if (err != (signed)sizeof(dev->descriptor)) { - dev_err(&dev->dev, "device descriptor read/all, error %d\n", err); - goto fail; - } - - 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 - - down(&dev->serialize); - - /* 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); - up(&dev->serialize); - goto fail; - } - usb_create_driverfs_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. - */ - config = 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].interface[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; - config = dev->config[i].desc.bConfigurationValue; - break; - } - dev_info(&dev->dev, - "configuration #%d chosen from %d choices\n", - config, - dev->descriptor.bNumConfigurations); - } - err = usb_set_configuration(dev, config); - up(&dev->serialize); - if (err) { - dev_err(&dev->dev, "can't set config #%d, error %d\n", - config, 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_DEFAULT; - clear_bit(dev->devnum, dev->bus->devmap.devicemap); - dev->devnum = -1; - return err; -} - /** * usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_xxx_DMA_MAP * @dev: device the buffer will be used with @@ -1261,7 +977,7 @@ void *usb_buffer_alloc ( ) { 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); } @@ -1313,7 +1029,7 @@ struct urb *usb_buffer_map (struct urb *urb) || !urb->dev || !(bus = urb->dev->bus) || !(controller = bus->controller)) - return 0; + return NULL; if (controller->dma_mask) { urb->transfer_dma = dma_map_single (controller, @@ -1507,13 +1223,15 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, 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; @@ -1525,13 +1243,16 @@ static int usb_device_suspend(struct device *dev, u32 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; @@ -1547,8 +1268,8 @@ struct bus_type usb_bus_type = { .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 @@ -1577,20 +1298,43 @@ int usb_disabled(void) */ static int __init usb_init(void) { + int retval; if (nousb) { pr_info ("%s: USB support disabled\n", usbcore_name); return 0; } - bus_register(&usb_bus_type); - usb_host_init(); - usb_major_init(); - usbfs_init(); - usb_hub_init(); + retval = bus_register(&usb_bus_type); + if (retval) + goto out; + retval = usb_host_init(); + if (retval) + goto host_init_failed; + retval = usb_major_init(); + if (retval) + goto major_init_failed; + retval = usbfs_init(); + if (retval) + goto fs_init_failed; + retval = usb_hub_init(); + if (retval) + goto hub_init_failed; + + retval = driver_register(&usb_generic_driver); + if (!retval) + goto out; - driver_register(&usb_generic_driver); - - return 0; + usb_hub_cleanup(); +hub_init_failed: + usbfs_cleanup(); +fs_init_failed: + usb_major_cleanup(); +major_init_failed: + usb_host_cleanup(); +host_init_failed: + bus_unregister(&usb_bus_type); +out: + return retval; } /*