X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fusb%2Fcore%2Fusb.c;h=3c2ddb5d021e2853fb5b527de39c4748f0cf2ae6;hb=4e4f43fe003969bdaa246374b90e16708a22ef79;hp=0da70f7af71daa426746af4fee463a1b7f7cfd18;hpb=86090fcac5e27b630656fe3d963a6b80e26dac44;p=linux-2.6.git diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 0da70f7af..3c2ddb5d0 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -198,6 +198,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 +231,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) @@ -992,12 +998,10 @@ void usb_disconnect(struct usb_device **pdev) */ 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); - } + dev_dbg (&dev->dev, "unregistering device\n"); + usb_release_address(dev); + usbfs_remove_device(dev); up(&dev->serialize); device_unregister(&dev->dev); } @@ -1032,24 +1036,23 @@ void usb_choose_address(struct usb_device *dev) } } - -// hub-only!! ... and only exported for reset/reinit path. -// otherwise used internally, for usb_new_device() -int usb_set_address(struct usb_device *dev) +/** + * 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) { - 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; + 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; @@ -1063,92 +1066,59 @@ static inline void usb_show_string(struct usb_device *dev, char *id, int index) 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; +} + /* - * 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.. + * usb_new_device - perform initial device setup (usbcore-internal) + * @dev: newly addressed device (in ADDRESS state) * - * Returns 0 for success, != 0 for error. + * 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. */ -#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; - } + int err; + int c; err = usb_get_configuration(dev); if (err < 0) { @@ -1170,51 +1140,22 @@ int usb_new_device(struct usb_device *dev) 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); + 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. */ - 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); + 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", - config, err); + dev_err(&dev->dev, "can't set config #%d, error %d\n", c, err); device_del(&dev->dev); goto fail; } @@ -1226,9 +1167,9 @@ int usb_new_device(struct usb_device *dev) return 0; fail: - dev->state = USB_STATE_DEFAULT; - clear_bit(dev->devnum, dev->bus->devmap.devicemap); - dev->devnum = -1; + dev->state = USB_STATE_NOTATTACHED; + usb_release_address(dev); + usb_put_dev(dev); return err; } @@ -1577,20 +1518,40 @@ 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); + retval = bus_register(&usb_bus_type); + if (retval) + goto out; usb_host_init(); - usb_major_init(); - usbfs_init(); - usb_hub_init(); - - driver_register(&usb_generic_driver); + 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; - return 0; + usb_hub_cleanup(); +hub_init_failed: + usbfs_cleanup(); +fs_init_failed: + usb_major_cleanup(); +major_init_failed: + usb_host_cleanup(); + bus_unregister(&usb_bus_type); +out: + return retval; } /*