X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fusb%2Fcore%2Fhub.c;fp=drivers%2Fusb%2Fcore%2Fhub.c;h=650d5ee5871b2f1e6c3f8d7f628c11cd91bed2b1;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=26c8cb5f3e6722467379204762fb5d8a89b938a0;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c;p=linux-2.6.git diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 26c8cb5f3..650d5ee58 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -8,6 +8,7 @@ * */ +#include #include #include #include @@ -21,7 +22,6 @@ #include #include #include -#include #include #include @@ -431,22 +431,15 @@ static void hub_power_on(struct usb_hub *hub) { int port1; unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2; - u16 wHubCharacteristics = - le16_to_cpu(hub->descriptor->wHubCharacteristics); - - /* Enable power on each port. Some hubs have reserved values - * of LPSM (> 2) in their descriptors, even though they are - * USB 2.0 hubs. Some hubs do not implement port-power switching - * but only emulate it. In all cases, the ports won't work - * unless we send these messages to the hub. - */ - if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2) + u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); + + /* if hub supports power switching, enable power on each port */ + if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2) { dev_dbg(hub->intfdev, "enabling power on all ports\n"); - else - dev_dbg(hub->intfdev, "trying to enable port power on " - "non-switchable hub\n"); - for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++) - set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER); + for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++) + set_port_feature(hub->hdev, port1, + USB_PORT_FEAT_POWER); + } /* Wait at least 100 msec for power to become stable */ msleep(max(pgood_delay, (unsigned) 100)); @@ -524,16 +517,15 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) /* caller has locked the hub device */ -static void hub_pre_reset(struct usb_interface *intf) +static void hub_pre_reset(struct usb_hub *hub, int disable_ports) { - struct usb_hub *hub = usb_get_intfdata(intf); struct usb_device *hdev = hub->hdev; int port1; for (port1 = 1; port1 <= hdev->maxchild; ++port1) { if (hdev->children[port1 - 1]) { usb_disconnect(&hdev->children[port1 - 1]); - if (hub->error == 0) + if (disable_ports) hub_port_disable(hub, port1, 0); } } @@ -541,10 +533,8 @@ static void hub_pre_reset(struct usb_interface *intf) } /* caller has locked the hub device */ -static void hub_post_reset(struct usb_interface *intf) +static void hub_post_reset(struct usb_hub *hub) { - struct usb_hub *hub = usb_get_intfdata(intf); - hub_activate(hub); hub_power_on(hub); } @@ -804,16 +794,15 @@ static void hub_disconnect(struct usb_interface *intf) struct usb_hub *hub = usb_get_intfdata (intf); struct usb_device *hdev; - /* Disconnect all children and quiesce the hub */ - hub->error = 0; - hub_pre_reset(intf); - usb_set_intfdata (intf, NULL); hdev = hub->hdev; if (hdev->speed == USB_SPEED_HIGH) highspeed_hubs--; + /* Disconnect all children and quiesce the hub */ + hub_pre_reset(hub, 1); + usb_free_urb(hub->urb); hub->urb = NULL; @@ -846,13 +835,6 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) desc = intf->cur_altsetting; hdev = interface_to_usbdev(intf); -#ifdef CONFIG_USB_OTG_BLACKLIST_HUB - if (hdev->parent) { - dev_warn(&intf->dev, "ignoring external hub\n"); - return -ENODEV; - } -#endif - /* Some hubs have a subclass of 1, which AFAICT according to the */ /* specs is not defined, but it works */ if ((desc->desc.bInterfaceSubClass != 0) && @@ -1023,22 +1005,17 @@ void usb_set_device_state(struct usb_device *udev, ; /* do nothing */ else if (new_state != USB_STATE_NOTATTACHED) { udev->state = new_state; - - /* root hub wakeup capabilities are managed out-of-band - * and may involve silicon errata ... ignore them here. - */ - if (udev->parent) { - if (new_state == USB_STATE_CONFIGURED) - device_init_wakeup(&udev->dev, - (udev->actconfig->desc.bmAttributes - & USB_CONFIG_ATT_WAKEUP)); - else if (new_state != USB_STATE_SUSPENDED) - device_init_wakeup(&udev->dev, 0); - } + if (new_state == USB_STATE_CONFIGURED) + device_init_wakeup(&udev->dev, + (udev->actconfig->desc.bmAttributes + & USB_CONFIG_ATT_WAKEUP)); + else if (new_state != USB_STATE_SUSPENDED) + device_init_wakeup(&udev->dev, 0); } else recursively_mark_NOTATTACHED(udev); spin_unlock_irqrestore(&device_state_lock, flags); } +EXPORT_SYMBOL(usb_set_device_state); #ifdef CONFIG_PM @@ -1178,19 +1155,25 @@ static inline const char *plural(int n) static int choose_configuration(struct usb_device *udev) { int i; + u16 devstatus; + int bus_powered; int num_configs; - int insufficient_power = 0; struct usb_host_config *c, *best; + /* If this fails, assume the device is bus-powered */ + devstatus = 0; + usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus); + le16_to_cpus(&devstatus); + bus_powered = ((devstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0); + dev_dbg(&udev->dev, "device is %s-powered\n", + bus_powered ? "bus" : "self"); + best = NULL; c = udev->config; num_configs = udev->descriptor.bNumConfigurations; for (i = 0; i < num_configs; (i++, c++)) { - struct usb_interface_descriptor *desc = NULL; - - /* It's possible that a config has no interfaces! */ - if (c->desc.bNumInterfaces > 0) - desc = &c->intf_cache[0]->altsetting->desc; + struct usb_interface_descriptor *desc = + &c->intf_cache[0]->altsetting->desc; /* * HP's USB bus-powered keyboard has only one configuration @@ -1198,19 +1181,6 @@ static int choose_configuration(struct usb_device *udev) * similar errors in their descriptors. If the next test * were allowed to execute, such configurations would always * be rejected and the devices would not work as expected. - * In the meantime, we run the risk of selecting a config - * that requires external power at a time when that power - * isn't available. It seems to be the lesser of two evils. - * - * Bugzilla #6448 reports a device that appears to crash - * when it receives a GET_DEVICE_STATUS request! We don't - * have any other way to tell whether a device is self-powered, - * but since we don't use that information anywhere but here, - * the call has been removed. - * - * Maybe the GET_DEVICE_STATUS call and the test below can - * be reinstated when device firmwares become more reliable. - * Don't hold your breath. */ #if 0 /* Rule out self-powered configs for a bus-powered device */ @@ -1232,19 +1202,16 @@ static int choose_configuration(struct usb_device *udev) */ /* Rule out configs that draw too much bus current */ - if (c->desc.bMaxPower * 2 > udev->bus_mA) { - insufficient_power++; + if (c->desc.bMaxPower * 2 > udev->bus_mA) continue; - } /* If the first config's first interface is COMM/2/0xff * (MSFT RNDIS), rule it out unless Linux has host-side * RNDIS support. */ - if (i == 0 && desc - && desc->bInterfaceClass == USB_CLASS_COMM + if (i == 0 && desc->bInterfaceClass == USB_CLASS_COMM && desc->bInterfaceSubClass == 2 && desc->bInterfaceProtocol == 0xff) { -#ifndef CONFIG_USB_NET_RNDIS_HOST +#ifndef CONFIG_USB_NET_RNDIS continue; #else best = c; @@ -1257,8 +1224,8 @@ static int choose_configuration(struct usb_device *udev) * than a vendor-specific driver. */ else if (udev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC && - (!desc || desc->bInterfaceClass != - USB_CLASS_VENDOR_SPEC)) { + desc->bInterfaceClass != + USB_CLASS_VENDOR_SPEC) { best = c; break; } @@ -1269,11 +1236,6 @@ static int choose_configuration(struct usb_device *udev) best = c; } - if (insufficient_power > 0) - dev_info(&udev->dev, "rejected %d configuration%s " - "due to insufficient available bus power\n", - insufficient_power, plural(insufficient_power)); - if (best) { i = best->desc.bConfigurationValue; dev_info(&udev->dev, @@ -1790,10 +1752,7 @@ static int finish_device_resume(struct usb_device *udev) * and device drivers will know about any resume quirks. */ status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus); - if (status >= 0) - status = (status == 2 ? 0 : -ENODEV); - - if (status) + if (status < 2) dev_dbg(&udev->dev, "gone after usb resume? status %d\n", status); @@ -1882,12 +1841,7 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) dev_dbg(hub->intfdev, "port %d status %04x.%04x after resume, %d\n", port1, portchange, devstatus, status); - if (status >= 0) - status = -ENODEV; } else { - if (portchange & USB_PORT_STAT_C_SUSPEND) - clear_port_feature(hub->hdev, port1, - USB_PORT_FEAT_C_SUSPEND); /* TRSMRCY = 10 msec */ msleep(10); if (udev) @@ -1922,18 +1876,18 @@ int usb_resume_device(struct usb_device *udev) if (udev->state == USB_STATE_NOTATTACHED) return -ENODEV; +#ifdef CONFIG_USB_SUSPEND /* selective resume of one downstream hub-to-device port */ if (udev->parent) { -#ifdef CONFIG_USB_SUSPEND if (udev->state == USB_STATE_SUSPENDED) { // NOTE swsusp may bork us, device state being wrong... // NOTE this fails if parent is also suspended... status = hub_port_resume(hdev_to_hub(udev->parent), udev->portnum, udev); } else -#endif status = 0; } else +#endif status = finish_device_resume(udev); if (status < 0) dev_dbg(&udev->dev, "can't resume, status %d\n", @@ -2208,7 +2162,7 @@ static int hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, int retry_counter) { - static DEFINE_MUTEX(usb_address0_mutex); + static DECLARE_MUTEX(usb_address0_sem); struct usb_device *hdev = hub->hdev; int i, j, retval; @@ -2229,7 +2183,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, if (oldspeed == USB_SPEED_LOW) delay = HUB_LONG_RESET_TIME; - mutex_lock(&usb_address0_mutex); + down(&usb_address0_sem); /* Reset the device; full speed may morph to high speed */ retval = hub_port_reset(hub, port1, udev, delay); @@ -2427,7 +2381,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, fail: if (retval) hub_port_disable(hub, port1, 0); - mutex_unlock(&usb_address0_mutex); + up(&usb_address0_sem); return retval; } @@ -2758,8 +2712,7 @@ static void hub_events(void) /* If the hub has died, clean up after it */ if (hdev->state == USB_STATE_NOTATTACHED) { - hub->error = -ENODEV; - hub_pre_reset(intf); + hub_pre_reset(hub, 0); goto loop; } @@ -2771,7 +2724,7 @@ static void hub_events(void) dev_dbg (hub_dev, "resetting for error %d\n", hub->error); - ret = usb_reset_composite_device(hdev, intf); + ret = usb_reset_device(hdev); if (ret) { dev_dbg (hub_dev, "error resetting hub: %d\n", ret); @@ -2940,8 +2893,6 @@ static struct usb_driver hub_driver = { .disconnect = hub_disconnect, .suspend = hub_suspend, .resume = hub_resume, - .pre_reset = hub_pre_reset, - .post_reset = hub_post_reset, .ioctl = hub_ioctl, .id_table = hub_id_table, }; @@ -3021,9 +2972,9 @@ static int config_descriptors_changed(struct usb_device *udev) * usb_reset_device - perform a USB port reset to reinitialize a device * @udev: device to reset (not in SUSPENDED or NOTATTACHED state) * - * WARNING - don't use this routine to reset a composite device - * (one with multiple interfaces owned by separate drivers)! - * Use usb_reset_composite_device() instead. + * WARNING - don't reset any device unless drivers for all of its + * interfaces are expecting that reset! Maybe some driver->reset() + * method should eventually help ensure sufficient cooperation. * * Do a port reset, reassign the device's address, and establish its * former operating configuration. If the reset fails, or the device's @@ -3047,6 +2998,7 @@ int usb_reset_device(struct usb_device *udev) struct usb_device *parent_hdev = udev->parent; struct usb_hub *parent_hub; struct usb_device_descriptor descriptor = udev->descriptor; + struct usb_hub *hub = NULL; int i, ret = 0; int port1 = udev->portnum; @@ -3064,6 +3016,14 @@ int usb_reset_device(struct usb_device *udev) } parent_hub = hdev_to_hub(parent_hdev); + /* If we're resetting an active hub, take some special actions */ + if (udev->actconfig && + udev->actconfig->interface[0]->dev.driver == + &hub_driver.driver && + (hub = hdev_to_hub(udev)) != NULL) { + hub_pre_reset(hub, 0); + } + set_bit(port1, parent_hub->busy_bits); for (i = 0; i < SET_CONFIG_TRIES; ++i) { @@ -3122,87 +3082,11 @@ int usb_reset_device(struct usb_device *udev) } done: + if (hub) + hub_post_reset(hub); return 0; re_enumerate: hub_port_logical_disconnect(parent_hub, port1); return -ENODEV; } - -/** - * usb_reset_composite_device - warn interface drivers and perform a USB port reset - * @udev: device to reset (not in SUSPENDED or NOTATTACHED state) - * @iface: interface bound to the driver making the request (optional) - * - * Warns all drivers bound to registered interfaces (using their pre_reset - * method), performs the port reset, and then lets the drivers know that - * the reset is over (using their post_reset method). - * - * Return value is the same as for usb_reset_device(). - * - * The caller must own the device lock. For example, it's safe to use - * this from a driver probe() routine after downloading new firmware. - * For calls that might not occur during probe(), drivers should lock - * the device using usb_lock_device_for_reset(). - * - * The interface locks are acquired during the pre_reset stage and released - * during the post_reset stage. However if iface is not NULL and is - * currently being probed, we assume that the caller already owns its - * lock. - */ -int usb_reset_composite_device(struct usb_device *udev, - struct usb_interface *iface) -{ - int ret; - struct usb_host_config *config = udev->actconfig; - - if (udev->state == USB_STATE_NOTATTACHED || - udev->state == USB_STATE_SUSPENDED) { - dev_dbg(&udev->dev, "device reset not allowed in state %d\n", - udev->state); - return -EINVAL; - } - - if (iface && iface->condition != USB_INTERFACE_BINDING) - iface = NULL; - - if (config) { - int i; - struct usb_interface *cintf; - struct usb_driver *drv; - - for (i = 0; i < config->desc.bNumInterfaces; ++i) { - cintf = config->interface[i]; - if (cintf != iface) - down(&cintf->dev.sem); - if (device_is_registered(&cintf->dev) && - cintf->dev.driver) { - drv = to_usb_driver(cintf->dev.driver); - if (drv->pre_reset) - (drv->pre_reset)(cintf); - } - } - } - - ret = usb_reset_device(udev); - - if (config) { - int i; - struct usb_interface *cintf; - struct usb_driver *drv; - - for (i = config->desc.bNumInterfaces - 1; i >= 0; --i) { - cintf = config->interface[i]; - if (device_is_registered(&cintf->dev) && - cintf->dev.driver) { - drv = to_usb_driver(cintf->dev.driver); - if (drv->post_reset) - (drv->post_reset)(cintf); - } - if (cintf != iface) - up(&cintf->dev.sem); - } - } - - return ret; -}