X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fusb%2Fcore%2Fhcd.c;h=9e82afc3389c9078b4aad89bd293cfd22d8c15d8;hb=987b0145d94eecf292d8b301228356f44611ab7c;hp=e2e00ba4e1e6dd5b20aff7dda22316cd02a39e97;hpb=f7ed79d23a47594e7834d66a8f14449796d4f3e6;p=linux-2.6.git diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index e2e00ba4e..9e82afc33 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include @@ -94,7 +93,7 @@ struct usb_busmap { static struct usb_busmap busmap; /* used when updating list of hcds */ -DEFINE_MUTEX(usb_bus_list_lock); /* exported only for usbfs */ +DECLARE_MUTEX (usb_bus_list_lock); /* exported only for usbfs */ EXPORT_SYMBOL_GPL (usb_bus_list_lock); /* used for controlling access to virtual root hubs */ @@ -345,7 +344,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) struct usb_ctrlrequest *cmd; u16 typeReq, wValue, wIndex, wLength; u8 *ubuf = urb->transfer_buffer; - u8 tbuf [sizeof (struct usb_hub_descriptor)]; + u8 tbuf [sizeof (struct usb_hub_descriptor)] + __attribute__((aligned(4))); const u8 *bufp = tbuf; int len = 0; int patch_wakeup = 0; @@ -367,39 +367,21 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) /* DEVICE REQUESTS */ - /* The root hub's remote wakeup enable bit is implemented using - * driver model wakeup flags. If this system supports wakeup - * through USB, userspace may change the default "allow wakeup" - * policy through sysfs or these calls. - * - * Most root hubs support wakeup from downstream devices, for - * runtime power management (disabling USB clocks and reducing - * VBUS power usage). However, not all of them do so; silicon, - * board, and BIOS bugs here are not uncommon, so these can't - * be treated quite like external hubs. - * - * Likewise, not all root hubs will pass wakeup events upstream, - * to wake up the whole system. So don't assume root hub and - * controller capabilities are identical. - */ - case DeviceRequest | USB_REQ_GET_STATUS: - tbuf [0] = (device_may_wakeup(&hcd->self.root_hub->dev) - << USB_DEVICE_REMOTE_WAKEUP) + tbuf [0] = (hcd->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP) | (1 << USB_DEVICE_SELF_POWERED); tbuf [1] = 0; len = 2; break; case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: if (wValue == USB_DEVICE_REMOTE_WAKEUP) - device_set_wakeup_enable(&hcd->self.root_hub->dev, 0); + hcd->remote_wakeup = 0; else goto error; break; case DeviceOutRequest | USB_REQ_SET_FEATURE: - if (device_can_wakeup(&hcd->self.root_hub->dev) - && wValue == USB_DEVICE_REMOTE_WAKEUP) - device_set_wakeup_enable(&hcd->self.root_hub->dev, 1); + if (hcd->can_wakeup && wValue == USB_DEVICE_REMOTE_WAKEUP) + hcd->remote_wakeup = 1; else goto error; break; @@ -428,7 +410,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) bufp = fs_rh_config_descriptor; len = sizeof fs_rh_config_descriptor; } - if (device_can_wakeup(&hcd->self.root_hub->dev)) + if (hcd->can_wakeup) patch_wakeup = 1; break; case USB_DT_STRING << 8: @@ -780,14 +762,14 @@ static int usb_register_bus(struct usb_bus *bus) { int busnum; - mutex_lock(&usb_bus_list_lock); + down (&usb_bus_list_lock); busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1); if (busnum < USB_MAXBUS) { set_bit (busnum, busmap.busmap); bus->busnum = busnum; } else { printk (KERN_ERR "%s: too many buses\n", usbcore_name); - mutex_unlock(&usb_bus_list_lock); + up(&usb_bus_list_lock); return -E2BIG; } @@ -795,7 +777,7 @@ static int usb_register_bus(struct usb_bus *bus) bus->controller, "usb_host%d", busnum); if (IS_ERR(bus->class_dev)) { clear_bit(busnum, busmap.busmap); - mutex_unlock(&usb_bus_list_lock); + up(&usb_bus_list_lock); return PTR_ERR(bus->class_dev); } @@ -803,7 +785,7 @@ static int usb_register_bus(struct usb_bus *bus) /* Add it to the local list of buses */ list_add (&bus->bus_list, &usb_bus_list); - mutex_unlock(&usb_bus_list_lock); + up (&usb_bus_list_lock); usb_notify_add_bus(bus); @@ -828,9 +810,9 @@ static void usb_deregister_bus (struct usb_bus *bus) * controller code, as well as having it call this when cleaning * itself up */ - mutex_lock(&usb_bus_list_lock); + down (&usb_bus_list_lock); list_del (&bus->bus_list); - mutex_unlock(&usb_bus_list_lock); + up (&usb_bus_list_lock); usb_notify_remove_bus(bus); @@ -841,17 +823,18 @@ static void usb_deregister_bus (struct usb_bus *bus) /** * register_root_hub - called by usb_add_hcd() to register a root hub + * @usb_dev: the usb root hub device to be registered. * @hcd: host controller for this root hub * * This function registers the root hub with the USB subsystem. It sets up - * the device properly in the device tree and then calls usb_new_device() - * to register the usb device. It also assigns the root hub's USB address - * (always 1). + * the device properly in the device tree and stores the root_hub pointer + * in the bus structure, then calls usb_new_device() to register the usb + * device. It also assigns the root hub's USB address (always 1). */ -static int register_root_hub(struct usb_hcd *hcd) +static int register_root_hub (struct usb_device *usb_dev, + struct usb_hcd *hcd) { struct device *parent_dev = hcd->self.controller; - struct usb_device *usb_dev = hcd->self.root_hub; const int devnum = 1; int retval; @@ -862,12 +845,14 @@ static int register_root_hub(struct usb_hcd *hcd) set_bit (devnum, usb_dev->bus->devmap.devicemap); usb_set_device_state(usb_dev, USB_STATE_ADDRESS); - mutex_lock(&usb_bus_list_lock); + down (&usb_bus_list_lock); + usb_dev->bus->root_hub = usb_dev; usb_dev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64); retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE); if (retval != sizeof usb_dev->descriptor) { - mutex_unlock(&usb_bus_list_lock); + usb_dev->bus->root_hub = NULL; + up (&usb_bus_list_lock); dev_dbg (parent_dev, "can't read %s device descriptor %d\n", usb_dev->dev.bus_id, retval); return (retval < 0) ? retval : -EMSGSIZE; @@ -875,10 +860,11 @@ static int register_root_hub(struct usb_hcd *hcd) retval = usb_new_device (usb_dev); if (retval) { + usb_dev->bus->root_hub = NULL; dev_err (parent_dev, "can't register root hub for %s, %d\n", usb_dev->dev.bus_id, retval); } - mutex_unlock(&usb_bus_list_lock); + up (&usb_bus_list_lock); if (retval == 0) { spin_lock_irq (&hcd_root_hub_lock); @@ -1105,6 +1091,7 @@ static void urb_unlink (struct urb *urb) spin_lock_irqsave (&hcd_data_lock, flags); list_del_init (&urb->urb_list); spin_unlock_irqrestore (&hcd_data_lock, flags); + usb_put_dev (urb->dev); } @@ -1144,6 +1131,7 @@ static int hcd_submit_urb (struct urb *urb, gfp_t mem_flags) case HC_STATE_RUNNING: case HC_STATE_RESUMING: doit: + usb_get_dev (urb->dev); list_add_tail (&urb->urb_list, &ep->urb_list); status = 0; break; @@ -1784,10 +1772,12 @@ int usb_add_hcd(struct usb_hcd *hcd, set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - /* HC is in reset state, but accessible. Now do the one-time init, - * bottom up so that hcds can customize the root hubs before khubd - * starts talking to them. (Note, bus id is assigned early too.) - */ + /* till now HC has been in an indeterminate state ... */ + if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) { + dev_err(hcd->self.controller, "can't reset\n"); + return retval; + } + if ((retval = hcd_buffer_create(hcd)) != 0) { dev_dbg(hcd->self.controller, "pool alloc failed\n"); return retval; @@ -1796,35 +1786,6 @@ int usb_add_hcd(struct usb_hcd *hcd, if ((retval = usb_register_bus(&hcd->self)) < 0) goto err_register_bus; - if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) { - dev_err(hcd->self.controller, "unable to allocate root hub\n"); - retval = -ENOMEM; - goto err_allocate_root_hub; - } - rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH : - USB_SPEED_FULL; - hcd->self.root_hub = rhdev; - - /* wakeup flag init defaults to "everything works" for root hubs, - * but drivers can override it in reset() if needed, along with - * recording the overall controller's system wakeup capability. - */ - device_init_wakeup(&rhdev->dev, 1); - - /* "reset" is misnamed; its role is now one-time init. the controller - * should already have been reset (and boot firmware kicked off etc). - */ - if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) { - dev_err(hcd->self.controller, "can't setup\n"); - goto err_hcd_driver_setup; - } - - /* NOTE: root hub and controller capabilities may not be the same */ - if (device_can_wakeup(hcd->self.controller) - && device_can_wakeup(&hcd->self.root_hub->dev)) - dev_dbg(hcd->self.controller, "supports USB remote wakeup\n"); - - /* enable irqs just before we start the controller */ if (hcd->driver->irq) { char buf[8], *bufp = buf; @@ -1856,32 +1817,56 @@ int usb_add_hcd(struct usb_hcd *hcd, (unsigned long long)hcd->rsrc_start); } + /* Allocate the root hub before calling hcd->driver->start(), + * but don't register it until afterward so that the hardware + * is running. + */ + if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) { + dev_err(hcd->self.controller, "unable to allocate root hub\n"); + retval = -ENOMEM; + goto err_allocate_root_hub; + } + + /* Although in principle hcd->driver->start() might need to use rhdev, + * none of the current drivers do. + */ if ((retval = hcd->driver->start(hcd)) < 0) { dev_err(hcd->self.controller, "startup error %d\n", retval); goto err_hcd_driver_start; } - /* starting here, usbcore will pay attention to this root hub */ + /* hcd->driver->start() reported can_wakeup, probably with + * assistance from board's boot firmware. + * NOTE: normal devices won't enable wakeup by default. + */ + if (hcd->can_wakeup) + dev_dbg(hcd->self.controller, "supports USB remote wakeup\n"); + hcd->remote_wakeup = hcd->can_wakeup; + + rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH : + USB_SPEED_FULL; rhdev->bus_mA = min(500u, hcd->power_budget); - if ((retval = register_root_hub(hcd)) != 0) + if ((retval = register_root_hub(rhdev, hcd)) != 0) goto err_register_root_hub; if (hcd->uses_new_polling && hcd->poll_rh) usb_hcd_poll_rh_status(hcd); return retval; -err_register_root_hub: + err_register_root_hub: hcd->driver->stop(hcd); -err_hcd_driver_start: + + err_hcd_driver_start: + usb_put_dev(rhdev); + + err_allocate_root_hub: if (hcd->irq >= 0) free_irq(irqnum, hcd); -err_request_irq: -err_hcd_driver_setup: - hcd->self.root_hub = NULL; - usb_put_dev(rhdev); -err_allocate_root_hub: + + err_request_irq: usb_deregister_bus(&hcd->self); -err_register_bus: + + err_register_bus: hcd_buffer_destroy(hcd); return retval; } @@ -1907,9 +1892,9 @@ void usb_remove_hcd(struct usb_hcd *hcd) hcd->rh_registered = 0; spin_unlock_irq (&hcd_root_hub_lock); - mutex_lock(&usb_bus_list_lock); + down(&usb_bus_list_lock); usb_disconnect(&hcd->self.root_hub); - mutex_unlock(&usb_bus_list_lock); + up(&usb_bus_list_lock); hcd->poll_rh = 0; del_timer_sync(&hcd->rh_timer);