diff options
| author | David Woodhouse <dwmw2@shinybook.infradead.org> | 2005-07-02 13:39:09 +0100 |
|---|---|---|
| committer | David Woodhouse <dwmw2@shinybook.infradead.org> | 2005-07-02 13:39:09 +0100 |
| commit | d2f6409584e2c62ffad81690562330ff3bf4a458 (patch) | |
| tree | 3bdfb97d0b51be2f7f414f2107e97603c1206abb /drivers/usb/core | |
| parent | e1b09eba2686eca94a3a188042b518df6044a3c1 (diff) | |
| parent | 4a89a04f1ee21a7c1f4413f1ad7dcfac50ff9b63 (diff) | |
Merge with master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
Diffstat (limited to 'drivers/usb/core')
| -rw-r--r-- | drivers/usb/core/devices.c | 2 | ||||
| -rw-r--r-- | drivers/usb/core/devio.c | 6 | ||||
| -rw-r--r-- | drivers/usb/core/file.c | 13 | ||||
| -rw-r--r-- | drivers/usb/core/hcd.c | 342 | ||||
| -rw-r--r-- | drivers/usb/core/hcd.h | 21 | ||||
| -rw-r--r-- | drivers/usb/core/hub.c | 21 | ||||
| -rw-r--r-- | drivers/usb/core/hub.h | 11 | ||||
| -rw-r--r-- | drivers/usb/core/inode.c | 13 | ||||
| -rw-r--r-- | drivers/usb/core/sysfs.c | 26 | ||||
| -rw-r--r-- | drivers/usb/core/usb.c | 53 |
10 files changed, 287 insertions, 221 deletions
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index ef0b35731ff0..83e815d3cd52 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -239,7 +239,7 @@ static char *usb_dump_interface_descriptor(char *start, char *end, int setno) { const struct usb_interface_descriptor *desc = &intfc->altsetting[setno].desc; - char *driver_name = ""; + const char *driver_name = ""; if (start > end) return start; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 6bfab4bcaa9e..787c27a63c51 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -784,16 +784,16 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg) for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) { if (usb_interface_claimed(actconfig->interface[i])) { dev_warn (&ps->dev->dev, - "usbfs: interface %d claimed " + "usbfs: interface %d claimed by %s " "while '%s' sets config #%d\n", actconfig->interface[i] ->cur_altsetting ->desc.bInterfaceNumber, + actconfig->interface[i] + ->dev.driver->name, current->comm, u); -#if 0 /* FIXME: enable in 2.6.10 or so */ status = -EBUSY; break; -#endif } } } diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index 38ed2220c9fc..65ca131cc44c 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -68,7 +68,7 @@ static struct file_operations usb_fops = { .open = usb_open, }; -static struct class_simple *usb_class; +static struct class *usb_class; int usb_major_init(void) { @@ -80,9 +80,10 @@ int usb_major_init(void) goto out; } - usb_class = class_simple_create(THIS_MODULE, "usb"); + usb_class = class_create(THIS_MODULE, "usb"); if (IS_ERR(usb_class)) { - err("class_simple_create failed for usb devices"); + error = PTR_ERR(usb_class); + err("class_create failed for usb devices"); unregister_chrdev(USB_MAJOR, "usb"); goto out; } @@ -95,7 +96,7 @@ out: void usb_major_cleanup(void) { - class_simple_destroy(usb_class); + class_destroy(usb_class); devfs_remove("usb"); unregister_chrdev(USB_MAJOR, "usb"); } @@ -171,7 +172,7 @@ int usb_register_dev(struct usb_interface *intf, ++temp; else temp = name; - intf->class_dev = class_simple_device_add(usb_class, MKDEV(USB_MAJOR, minor), &intf->dev, "%s", temp); + intf->class_dev = class_device_create(usb_class, MKDEV(USB_MAJOR, minor), &intf->dev, "%s", temp); if (IS_ERR(intf->class_dev)) { spin_lock (&minor_lock); usb_minors[intf->minor] = NULL; @@ -220,7 +221,7 @@ void usb_deregister_dev(struct usb_interface *intf, snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base); devfs_remove (name); - class_simple_device_remove(MKDEV(USB_MAJOR, intf->minor)); + class_device_destroy(usb_class, MKDEV(USB_MAJOR, intf->minor)); intf->class_dev = NULL; intf->minor = -1; } diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 266e9e06a9f5..83e732a0d64a 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -519,119 +519,120 @@ error: /*-------------------------------------------------------------------------*/ /* - * Root Hub interrupt transfers are synthesized with a timer. - * Completions are called in_interrupt() but not in_irq(). + * Root Hub interrupt transfers are polled using a timer if the + * driver requests it; otherwise the driver is responsible for + * calling usb_hcd_poll_rh_status() when an event occurs. * - * Note: some root hubs (including common UHCI based designs) can't - * correctly issue port change IRQs. They're the ones that _need_ a - * timer; most other root hubs don't. Some systems could save a - * lot of battery power by eliminating these root hub timer IRQs. + * Completions are called in_interrupt(), but they may or may not + * be in_irq(). */ +void usb_hcd_poll_rh_status(struct usb_hcd *hcd) +{ + struct urb *urb; + int length; + unsigned long flags; + char buffer[4]; /* Any root hubs with > 31 ports? */ -static void rh_report_status (unsigned long ptr); + if (!hcd->uses_new_polling && !hcd->status_urb) + return; -static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb) -{ - int len = 1 + (urb->dev->maxchild / 8); + length = hcd->driver->hub_status_data(hcd, buffer); + if (length > 0) { - /* rh_timer protected by hcd_data_lock */ - if (hcd->rh_timer.data || urb->transfer_buffer_length < len) { - dev_dbg (hcd->self.controller, - "not queuing rh status urb, stat %d\n", - urb->status); - return -EINVAL; + /* try to complete the status urb */ + local_irq_save (flags); + spin_lock(&hcd_root_hub_lock); + urb = hcd->status_urb; + if (urb) { + spin_lock(&urb->lock); + if (urb->status == -EINPROGRESS) { + hcd->poll_pending = 0; + hcd->status_urb = NULL; + urb->status = 0; + urb->hcpriv = NULL; + urb->actual_length = length; + memcpy(urb->transfer_buffer, buffer, length); + } else /* urb has been unlinked */ + length = 0; + spin_unlock(&urb->lock); + } else + length = 0; + spin_unlock(&hcd_root_hub_lock); + + /* local irqs are always blocked in completions */ + if (length > 0) + usb_hcd_giveback_urb (hcd, urb, NULL); + else + hcd->poll_pending = 1; + local_irq_restore (flags); } - init_timer (&hcd->rh_timer); - hcd->rh_timer.function = rh_report_status; - hcd->rh_timer.data = (unsigned long) urb; - /* USB 2.0 spec says 256msec; this is close enough */ - hcd->rh_timer.expires = jiffies + HZ/4; - add_timer (&hcd->rh_timer); - urb->hcpriv = hcd; /* nonzero to indicate it's queued */ - return 0; + /* The USB 2.0 spec says 256 ms. This is close enough and won't + * exceed that limit if HZ is 100. */ + if (hcd->uses_new_polling ? hcd->poll_rh : + (length == 0 && hcd->status_urb != NULL)) + mod_timer (&hcd->rh_timer, jiffies + msecs_to_jiffies(250)); } +EXPORT_SYMBOL_GPL(usb_hcd_poll_rh_status); /* timer callback */ +static void rh_timer_func (unsigned long _hcd) +{ + usb_hcd_poll_rh_status((struct usb_hcd *) _hcd); +} -static void rh_report_status (unsigned long ptr) +/*-------------------------------------------------------------------------*/ + +static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb) { - struct urb *urb; - struct usb_hcd *hcd; - int length = 0; + int retval; unsigned long flags; + int len = 1 + (urb->dev->maxchild / 8); - urb = (struct urb *) ptr; - local_irq_save (flags); - spin_lock (&urb->lock); + spin_lock_irqsave (&hcd_root_hub_lock, flags); + if (urb->status != -EINPROGRESS) /* already unlinked */ + retval = urb->status; + else if (hcd->status_urb || urb->transfer_buffer_length < len) { + dev_dbg (hcd->self.controller, "not queuing rh status urb\n"); + retval = -EINVAL; + } else { + hcd->status_urb = urb; + urb->hcpriv = hcd; /* indicate it's queued */ - /* do nothing if the urb's been unlinked */ - if (!urb->dev - || urb->status != -EINPROGRESS - || (hcd = urb->dev->bus->hcpriv) == NULL) { - spin_unlock (&urb->lock); - local_irq_restore (flags); - return; - } + if (!hcd->uses_new_polling) + mod_timer (&hcd->rh_timer, jiffies + + msecs_to_jiffies(250)); - /* complete the status urb, or retrigger the timer */ - spin_lock (&hcd_data_lock); - if (urb->dev->state == USB_STATE_CONFIGURED) { - length = hcd->driver->hub_status_data ( - hcd, urb->transfer_buffer); - if (length > 0) { - hcd->rh_timer.data = 0; - urb->actual_length = length; - urb->status = 0; - urb->hcpriv = NULL; - } else - mod_timer (&hcd->rh_timer, jiffies + HZ/4); + /* If a status change has already occurred, report it ASAP */ + else if (hcd->poll_pending) + mod_timer (&hcd->rh_timer, jiffies); + retval = 0; } - spin_unlock (&hcd_data_lock); - spin_unlock (&urb->lock); - - /* local irqs are always blocked in completions */ - if (length > 0) - usb_hcd_giveback_urb (hcd, urb, NULL); - local_irq_restore (flags); + spin_unlock_irqrestore (&hcd_root_hub_lock, flags); + return retval; } -/*-------------------------------------------------------------------------*/ - static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) { - if (usb_pipeint (urb->pipe)) { - int retval; - unsigned long flags; - - spin_lock_irqsave (&hcd_data_lock, flags); - retval = rh_status_urb (hcd, urb); - spin_unlock_irqrestore (&hcd_data_lock, flags); - return retval; - } + if (usb_pipeint (urb->pipe)) + return rh_queue_status (hcd, urb); if (usb_pipecontrol (urb->pipe)) return rh_call_control (hcd, urb); - else - return -EINVAL; + return -EINVAL; } /*-------------------------------------------------------------------------*/ +/* Asynchronous unlinks of root-hub control URBs are legal, but they + * don't do anything. Status URB unlinks must be made in process context + * with interrupts enabled. + */ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) { - unsigned long flags; - - /* note: always a synchronous unlink */ - if ((unsigned long) urb == hcd->rh_timer.data) { - del_timer_sync (&hcd->rh_timer); - hcd->rh_timer.data = 0; + if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */ + if (in_interrupt()) + return 0; /* nothing to do */ - local_irq_save (flags); - urb->hcpriv = NULL; - usb_hcd_giveback_urb (hcd, urb, NULL); - local_irq_restore (flags); - - } else if (usb_pipeendpoint(urb->pipe) == 0) { spin_lock_irq(&urb->lock); /* from usb_kill_urb */ ++urb->reject; spin_unlock_irq(&urb->lock); @@ -642,8 +643,22 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) spin_lock_irq(&urb->lock); --urb->reject; spin_unlock_irq(&urb->lock); - } else - return -EINVAL; + + } else { /* Status URB */ + if (!hcd->uses_new_polling) + del_timer_sync (&hcd->rh_timer); + local_irq_disable (); + spin_lock (&hcd_root_hub_lock); + if (urb == hcd->status_urb) { + hcd->status_urb = NULL; + urb->hcpriv = NULL; + } else + urb = NULL; /* wasn't fully queued */ + spin_unlock (&hcd_root_hub_lock); + if (urb) + usb_hcd_giveback_urb (hcd, urb, NULL); + local_irq_enable (); + } return 0; } @@ -651,50 +666,45 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) /*-------------------------------------------------------------------------*/ /* exported only within usbcore */ -struct usb_bus *usb_bus_get (struct usb_bus *bus) +struct usb_bus *usb_bus_get(struct usb_bus *bus) { - struct class_device *tmp; + if (bus) + kref_get(&bus->kref); + return bus; +} - if (!bus) - return NULL; +static void usb_host_release(struct kref *kref) +{ + struct usb_bus *bus = container_of(kref, struct usb_bus, kref); - tmp = class_device_get(&bus->class_dev); - if (tmp) - return to_usb_bus(tmp); - else - return NULL; + if (bus->release) + bus->release(bus); } /* exported only within usbcore */ -void usb_bus_put (struct usb_bus *bus) +void usb_bus_put(struct usb_bus *bus) { if (bus) - class_device_put(&bus->class_dev); + kref_put(&bus->kref, usb_host_release); } /*-------------------------------------------------------------------------*/ -static void usb_host_release(struct class_device *class_dev) -{ - struct usb_bus *bus = to_usb_bus(class_dev); - - if (bus->release) - bus->release(bus); -} - -static struct class usb_host_class = { - .name = "usb_host", - .release = &usb_host_release, -}; +static struct class *usb_host_class; int usb_host_init(void) { - return class_register(&usb_host_class); + int retval = 0; + + usb_host_class = class_create(THIS_MODULE, "usb_host"); + if (IS_ERR(usb_host_class)) + retval = PTR_ERR(usb_host_class); + return retval; } void usb_host_cleanup(void) { - class_unregister(&usb_host_class); + class_destroy(usb_host_class); } /** @@ -719,8 +729,7 @@ static void usb_bus_init (struct usb_bus *bus) INIT_LIST_HEAD (&bus->bus_list); - class_device_initialize(&bus->class_dev); - bus->class_dev.class = &usb_host_class; + kref_init(&bus->kref); } /** @@ -761,7 +770,6 @@ struct usb_bus *usb_alloc_bus (struct usb_operations *op) static int usb_register_bus(struct usb_bus *bus) { int busnum; - int retval; down (&usb_bus_list_lock); busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1); @@ -774,15 +782,15 @@ static int usb_register_bus(struct usb_bus *bus) return -E2BIG; } - snprintf(bus->class_dev.class_id, BUS_ID_SIZE, "usb%d", busnum); - bus->class_dev.dev = bus->controller; - retval = class_device_add(&bus->class_dev); - if (retval) { + bus->class_dev = class_device_create(usb_host_class, MKDEV(0,0), bus->controller, "usb%d", busnum); + if (IS_ERR(bus->class_dev)) { clear_bit(busnum, busmap.busmap); up(&usb_bus_list_lock); - return retval; + return PTR_ERR(bus->class_dev); } + class_set_devdata(bus->class_dev, bus); + /* Add it to the local list of buses */ list_add (&bus->bus_list, &usb_bus_list); up (&usb_bus_list_lock); @@ -820,34 +828,26 @@ static void usb_deregister_bus (struct usb_bus *bus) clear_bit (bus->busnum, busmap.busmap); - class_device_del(&bus->class_dev); + class_device_unregister(bus->class_dev); } /** - * usb_hcd_register_root_hub - called by HCD to register its root hub + * 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 * - * The USB host controller calls this function to register the root hub - * properly with the USB subsystem. It sets up 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). + * This function registers the root hub with the USB subsystem. It sets up + * 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). */ -int usb_hcd_register_root_hub (struct usb_device *usb_dev, 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; const int devnum = 1; int retval; - /* 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 (parent_dev, "supports USB remote wakeup\n"); - hcd->remote_wakeup = hcd->can_wakeup; - usb_dev->devnum = devnum; usb_dev->bus->devnum_next = devnum + 1; memset (&usb_dev->bus->devmap.devicemap, 0, @@ -890,7 +890,16 @@ int usb_hcd_register_root_hub (struct usb_device *usb_dev, struct usb_hcd *hcd) return retval; } -EXPORT_SYMBOL_GPL(usb_hcd_register_root_hub); + +void usb_enable_root_hub_irq (struct usb_bus *bus) +{ + struct usb_hcd *hcd; + + hcd = container_of (bus, struct usb_hcd, self); + if (hcd->driver->hub_irq_enable && !hcd->poll_rh && + hcd->state != HC_STATE_HALT) + hcd->driver->hub_irq_enable (hcd); +} /*-------------------------------------------------------------------------*/ @@ -1355,7 +1364,8 @@ hcd_endpoint_disable (struct usb_device *udev, struct usb_host_endpoint *ep) hcd = udev->bus->hcpriv; - WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT); + WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT && + udev->state != USB_STATE_NOTATTACHED); local_irq_disable (); @@ -1619,6 +1629,8 @@ void usb_hc_died (struct usb_hcd *hcd) spin_lock_irqsave (&hcd_root_hub_lock, flags); if (hcd->rh_registered) { + hcd->poll_rh = 0; + del_timer(&hcd->rh_timer); /* make khubd clean up old urbs and devices */ usb_set_device_state (hcd->self.root_hub, @@ -1672,6 +1684,8 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, hcd->self.bus_name = bus_name; init_timer(&hcd->rh_timer); + hcd->rh_timer.function = rh_timer_func; + hcd->rh_timer.data = (unsigned long) hcd; hcd->driver = driver; hcd->product_desc = (driver->product_desc) ? driver->product_desc : @@ -1701,7 +1715,8 @@ EXPORT_SYMBOL (usb_put_hcd); int usb_add_hcd(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags) { - int retval; + int retval; + struct usb_device *rhdev; dev_info(hcd->self.controller, "%s\n", hcd->product_desc); @@ -1717,7 +1732,7 @@ int usb_add_hcd(struct usb_hcd *hcd, } if ((retval = usb_register_bus(&hcd->self)) < 0) - goto err1; + goto err_register_bus; if (hcd->driver->irq) { char buf[8], *bufp = buf; @@ -1734,7 +1749,7 @@ int usb_add_hcd(struct usb_hcd *hcd, hcd->irq_descr, hcd)) != 0) { dev_err(hcd->self.controller, "request interrupt %s failed\n", bufp); - goto err2; + goto err_request_irq; } hcd->irq = irqnum; dev_info(hcd->self.controller, "irq %s, %s 0x%08llx\n", bufp, @@ -1750,19 +1765,55 @@ 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; + } + rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH : + USB_SPEED_FULL; + + /* 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 err3; + goto err_hcd_driver_start; } + /* 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; + + 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; - err3: + err_register_root_hub: + hcd->driver->stop(hcd); + + err_hcd_driver_start: + usb_put_dev(rhdev); + + err_allocate_root_hub: if (hcd->irq >= 0) free_irq(irqnum, hcd); - err2: + + err_request_irq: usb_deregister_bus(&hcd->self); - err1: + + err_register_bus: hcd_buffer_destroy(hcd); return retval; } @@ -1789,6 +1840,9 @@ void usb_remove_hcd(struct usb_hcd *hcd) spin_unlock_irq (&hcd_root_hub_lock); usb_disconnect(&hcd->self.root_hub); + hcd->poll_rh = 0; + del_timer_sync(&hcd->rh_timer); + hcd->driver->stop(hcd); hcd->state = HC_STATE_HALT; @@ -1801,7 +1855,7 @@ EXPORT_SYMBOL (usb_remove_hcd); /*-------------------------------------------------------------------------*/ -#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE) +#if defined(CONFIG_USB_MON) struct usb_mon_operations *mon_ops; diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index f67cf1e634fc..8dc13cde2f73 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -65,7 +65,8 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */ const char *product_desc; /* product/vendor string */ char irq_descr[24]; /* driver + bus # */ - struct timer_list rh_timer; /* drives root hub */ + struct timer_list rh_timer; /* drives root-hub polling */ + struct urb *status_urb; /* the current status urb */ /* * hardware info/state @@ -76,10 +77,17 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */ unsigned remote_wakeup:1;/* sw should use wakeup? */ unsigned rh_registered:1;/* is root hub registered? */ + /* The next flag is a stopgap, to be removed when all the HCDs + * support the new root-hub polling mechanism. */ + unsigned uses_new_polling:1; + unsigned poll_rh:1; /* poll for rh status? */ + unsigned poll_pending:1; /* status has changed? */ + int irq; /* irq allocated */ void __iomem *regs; /* device memory/io */ u64 rsrc_start; /* memory/io resource start */ u64 rsrc_len; /* memory/io resource length */ + unsigned power_budget; /* in mA, 0 = no limit */ #define HCD_BUFFER_POOLS 4 struct dma_pool *pool [HCD_BUFFER_POOLS]; @@ -207,6 +215,8 @@ struct hc_driver { int (*hub_suspend)(struct usb_hcd *); int (*hub_resume)(struct usb_hcd *); int (*start_port_reset)(struct usb_hcd *, unsigned port_num); + void (*hub_irq_enable)(struct usb_hcd *); + /* Needed only if port-change IRQs are level-triggered */ }; extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs); @@ -243,7 +253,9 @@ void hcd_buffer_free (struct usb_bus *bus, size_t size, /* generic bus glue, needed for host controllers that don't use PCI */ extern irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs *r); + extern void usb_hc_died (struct usb_hcd *hcd); +extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd); /* -------------------------------------------------------------------------- */ @@ -341,9 +353,6 @@ extern long usb_calc_bus_time (int speed, int is_input, extern struct usb_bus *usb_alloc_bus (struct usb_operations *); -extern int usb_hcd_register_root_hub (struct usb_device *usb_dev, - struct usb_hcd *hcd); - extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd); extern void usb_set_device_state(struct usb_device *udev, @@ -360,6 +369,8 @@ extern wait_queue_head_t usb_kill_urb_queue; extern struct usb_bus *usb_bus_get (struct usb_bus *bus); extern void usb_bus_put (struct usb_bus *bus); +extern void usb_enable_root_hub_irq (struct usb_bus *bus); + extern int usb_find_interface_driver (struct usb_device *dev, struct usb_interface *interface); @@ -399,7 +410,7 @@ static inline void usbfs_cleanup(void) { } /*-------------------------------------------------------------------------*/ -#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE) +#if defined(CONFIG_USB_MON) struct usb_mon_operations { void (*urb_submit)(struct usb_bus *bus, struct urb *urb); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index d2d648ee8640..32ff32181852 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -643,15 +643,21 @@ static int hub_configure(struct usb_hub *hub, message = "can't get hub status"; goto fail; } - cpu_to_le16s(&hubstatus); - if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) { + le16_to_cpus(&hubstatus); + if (hdev == hdev->bus->root_hub) { + struct usb_hcd *hcd = + container_of(hdev->bus, struct usb_hcd, self); + + hub->power_budget = min(500u, hcd->power_budget) / 2; + } else if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) { dev_dbg(hub_dev, "hub controller current requirement: %dmA\n", hub->descriptor->bHubContrCurrent); hub->power_budget = (501 - hub->descriptor->bHubContrCurrent) / 2; + } + if (hub->power_budget) dev_dbg(hub_dev, "%dmA bus power budget for children\n", hub->power_budget * 2); - } ret = hub_hub_status(hub, &hubstatus, &hubchange); @@ -1727,7 +1733,7 @@ static int finish_port_resume(struct usb_device *udev) struct usb_driver *driver; intf = udev->actconfig->interface[i]; - if (intf->dev.power.power_state == PMSG_SUSPEND) + if (intf->dev.power.power_state == PMSG_ON) continue; if (!intf->dev.driver) { /* FIXME maybe force to alt 0 */ @@ -2787,6 +2793,11 @@ static void hub_events(void) hub->activating = 0; + /* If this is a root hub, tell the HCD it's okay to + * re-enable port-change interrupts now. */ + if (!hdev->parent) + usb_enable_root_hub_irq(hdev->bus); + loop: usb_unlock_device(hdev); usb_put_intf(intf); @@ -2808,7 +2819,7 @@ static int hub_thread(void *__unused) do { hub_events(); wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list)); - try_to_freeze(PF_FREEZE); + try_to_freeze(); } while (!signal_pending(current)); pr_debug ("%s: khubd exiting\n", usbcore_name); diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index d114b847d56f..53bf5649621e 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -224,15 +224,4 @@ struct usb_hub { struct work_struct leds; }; -/* use this for low-powered root hubs */ -static inline void -hub_set_power_budget (struct usb_device *hubdev, unsigned mA) -{ - struct usb_hub *hub; - - hub = (struct usb_hub *) - usb_get_intfdata (hubdev->actconfig->interface[0]); - hub->power_budget = min(mA,(unsigned)500)/2; -} - #endif /* __LINUX_HUB_H */ diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index f9f9561c6bad..c3e3a95d3804 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -453,17 +453,6 @@ static int usbfs_fill_super(struct super_block *sb, void *data, int silent) return 0; } -static struct dentry * get_dentry(struct dentry *parent, const char *name) -{ - struct qstr qstr; - - qstr.name = name; - qstr.len = strlen(name); - qstr.hash = full_name_hash(name,qstr.len); - return lookup_hash(&qstr,parent); -} - - /* * fs_create_by_name - create a file, given a name * @name: name of file @@ -496,7 +485,7 @@ static int fs_create_by_name (const char *name, mode_t mode, *dentry = NULL; down(&parent->d_inode->i_sem); - *dentry = get_dentry (parent, name); + *dentry = lookup_one_len(name, parent, strlen(name)); if (!IS_ERR(dentry)) { if ((mode & S_IFMT) == S_IFDIR) error = usbfs_mkdir (parent->d_inode, *dentry, mode); diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 4d0c9e65cd03..740cb4c668df 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -24,7 +24,7 @@ /* Active configuration fields */ #define usb_actconfig_show(field, multiplier, format_string) \ -static ssize_t show_##field (struct device *dev, char *buf) \ +static ssize_t show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct usb_device *udev; \ struct usb_host_config *actconfig; \ @@ -46,7 +46,7 @@ usb_actconfig_attr (bNumInterfaces, 1, "%2d\n") usb_actconfig_attr (bmAttributes, 1, "%2x\n") usb_actconfig_attr (bMaxPower, 2, "%3dmA\n") -static ssize_t show_configuration_string(struct device *dev, char *buf) +static ssize_t show_configuration_string(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; struct usb_host_config *actconfig; @@ -69,7 +69,7 @@ static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL); usb_actconfig_show(bConfigurationValue, 1, "%u\n"); static ssize_t -set_bConfigurationValue (struct device *dev, const char *buf, size_t count) +set_bConfigurationValue (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct usb_device *udev = udev = to_usb_device (dev); int config, value; @@ -87,7 +87,7 @@ static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR, /* String fields */ #define usb_string_attr(name) \ -static ssize_t show_##name(struct device *dev, char *buf) \ +static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct usb_device *udev; \ int len; \ @@ -107,7 +107,7 @@ usb_string_attr(manufacturer); usb_string_attr(serial); static ssize_t -show_speed (struct device *dev, char *buf) +show_speed (struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; char *speed; @@ -133,7 +133,7 @@ show_speed (struct device *dev, char *buf) static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL); static ssize_t -show_devnum (struct device *dev, char *buf) +show_devnum (struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; @@ -143,7 +143,7 @@ show_devnum (struct device *dev, char *buf) static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL); static ssize_t -show_version (struct device *dev, char *buf) +show_version (struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; u16 bcdUSB; @@ -155,7 +155,7 @@ show_version (struct device *dev, char *buf) static DEVICE_ATTR(version, S_IRUGO, show_version, NULL); static ssize_t -show_maxchild (struct device *dev, char *buf) +show_maxchild (struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; @@ -167,7 +167,7 @@ static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL); /* Descriptor fields */ #define usb_descriptor_attr_le16(field, format_string) \ static ssize_t \ -show_##field (struct device *dev, char *buf) \ +show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct usb_device *udev; \ \ @@ -183,7 +183,7 @@ usb_descriptor_attr_le16(bcdDevice, "%04x\n") #define usb_descriptor_attr(field, format_string) \ static ssize_t \ -show_##field (struct device *dev, char *buf) \ +show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct usb_device *udev; \ \ @@ -254,7 +254,7 @@ void usb_remove_sysfs_dev_files (struct usb_device *udev) /* Interface fields */ #define usb_intf_attr(field, format_string) \ static ssize_t \ -show_##field (struct device *dev, char *buf) \ +show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct usb_interface *intf = to_usb_interface (dev); \ \ @@ -269,7 +269,7 @@ usb_intf_attr (bInterfaceClass, "%02x\n") usb_intf_attr (bInterfaceSubClass, "%02x\n") usb_intf_attr (bInterfaceProtocol, "%02x\n") -static ssize_t show_interface_string(struct device *dev, char *buf) +static ssize_t show_interface_string(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_interface *intf; struct usb_device *udev; @@ -286,7 +286,7 @@ static ssize_t show_interface_string(struct device *dev, char *buf) } static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL); -static ssize_t show_modalias(struct device *dev, char *buf) +static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_interface *intf; struct usb_device *udev; diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 25cf7e9eccfa..a3c42203213a 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -293,7 +293,7 @@ int usb_driver_claim_interface(struct usb_driver *driver, /* if interface was already added, bind now; else let * the future device_add() bind it, bypassing probe() */ - if (!list_empty (&dev->bus_list)) + if (klist_node_attached(&dev->knode_bus)) device_bind_driver(dev); return 0; @@ -322,9 +322,15 @@ void usb_driver_release_interface(struct usb_driver *driver, if (!dev->driver || dev->driver != &driver->driver) return; - /* don't disconnect from disconnect(), or before dev_add() */ - if (!list_empty (&dev->driver_list) && !list_empty (&dev->bus_list)) + /* don't release from within disconnect() */ + if (iface->condition != USB_INTERFACE_BOUND) + return; + + /* release only after device_add() */ + if (klist_node_attached(&dev->knode_bus)) { + iface->condition = USB_INTERFACE_UNBINDING; device_release_driver(dev); + } dev->driver = NULL; usb_set_intfdata(iface, NULL); @@ -462,6 +468,25 @@ usb_match_id(struct usb_interface *interface, const struct usb_device_id *id) return NULL; } + +static int __find_interface(struct device * dev, void * data) +{ + struct usb_interface ** ret = (struct usb_interface **)data; + struct usb_interface * intf = *ret; + int *minor = (int *)data; + + /* can't look at usb devices, only interfaces */ + if (dev->driver == &usb_generic_driver) + return 0; + + intf = to_usb_interface(dev); + if (intf->minor != -1 && intf->minor == *minor) { + *ret = intf; + return 1; + } + return 0; +} + /** * usb_find_interface - find usb_interface pointer for driver and device * @drv: the driver whose current configuration is considered @@ -473,26 +498,12 @@ usb_match_id(struct usb_interface *interface, const struct usb_device_id *id) */ struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor) { - struct list_head *entry; - struct device *dev; - struct usb_interface *intf; + struct usb_interface *intf = (struct usb_interface *)(long)minor; + int ret; - list_for_each(entry, &drv->driver.devices) { - dev = container_of(entry, struct device, driver_list); - - /* can't look at usb devices, only interfaces */ - if (dev->driver == &usb_generic_driver) - continue; - - intf = to_usb_interface(dev); - if (intf->minor == -1) - continue; - if (intf->minor == minor) - return intf; - } + ret = driver_for_each_device(&drv->driver, NULL, &intf, __find_interface); - /* no device found that matches */ - return NULL; + return ret ? intf : NULL; } static int usb_device_match (struct device *dev, struct device_driver *drv) |
