diff options
Diffstat (limited to 'drivers/usb/core')
-rw-r--r-- | drivers/usb/core/Makefile | 2 | ||||
-rw-r--r-- | drivers/usb/core/buffer.c | 4 | ||||
-rw-r--r-- | drivers/usb/core/config.c | 4 | ||||
-rw-r--r-- | drivers/usb/core/devices.c | 6 | ||||
-rw-r--r-- | drivers/usb/core/devio.c | 68 | ||||
-rw-r--r-- | drivers/usb/core/driver.c | 1011 | ||||
-rw-r--r-- | drivers/usb/core/endpoint.c | 30 | ||||
-rw-r--r-- | drivers/usb/core/file.c | 2 | ||||
-rw-r--r-- | drivers/usb/core/generic.c | 208 | ||||
-rw-r--r-- | drivers/usb/core/hcd-pci.c | 18 | ||||
-rw-r--r-- | drivers/usb/core/hcd.c | 244 | ||||
-rw-r--r-- | drivers/usb/core/hcd.h | 60 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 555 | ||||
-rw-r--r-- | drivers/usb/core/hub.h | 3 | ||||
-rw-r--r-- | drivers/usb/core/inode.c | 13 | ||||
-rw-r--r-- | drivers/usb/core/message.c | 148 | ||||
-rw-r--r-- | drivers/usb/core/notify.c | 3 | ||||
-rw-r--r-- | drivers/usb/core/sysfs.c | 60 | ||||
-rw-r--r-- | drivers/usb/core/urb.c | 15 | ||||
-rw-r--r-- | drivers/usb/core/usb.c | 533 | ||||
-rw-r--r-- | drivers/usb/core/usb.h | 76 |
21 files changed, 1948 insertions, 1115 deletions
diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile index ec510922af6..34e9bac319b 100644 --- a/drivers/usb/core/Makefile +++ b/drivers/usb/core/Makefile @@ -4,7 +4,7 @@ usbcore-objs := usb.o hub.o hcd.o urb.o message.o driver.o \ config.o file.o buffer.o sysfs.o endpoint.o \ - devio.o notify.o + devio.o notify.o generic.o ifeq ($(CONFIG_PCI),y) usbcore-objs += hcd-pci.o diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index f4f4ef0f377..840442a25b6 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -104,7 +104,7 @@ void *hcd_buffer_alloc ( dma_addr_t *dma ) { - struct usb_hcd *hcd = bus->hcpriv; + struct usb_hcd *hcd = bus_to_hcd(bus); int i; /* some USB hosts just use PIO */ @@ -127,7 +127,7 @@ void hcd_buffer_free ( dma_addr_t dma ) { - struct usb_hcd *hcd = bus->hcpriv; + struct usb_hcd *hcd = bus_to_hcd(bus); int i; if (!addr) diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 4c9e63e665b..bfb3731d42d 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -475,7 +475,9 @@ int usb_get_configuration(struct usb_device *dev) if (result < 0) { dev_err(ddev, "unable to read config index %d " "descriptor/%s\n", cfgno, "start"); - goto err; + dev_err(ddev, "chopping to %d config(s)\n", cfgno); + dev->descriptor.bNumConfigurations = cfgno; + break; } else if (result < 4) { dev_err(ddev, "config index %d descriptor too short " "(expected %i, got %i)\n", cfgno, diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index c0f37343a27..3538c2fdadf 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -593,7 +593,7 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte /* Kernel lock for "lastev" protection */ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct *wait) { - struct usb_device_status *st = (struct usb_device_status *)file->private_data; + struct usb_device_status *st = file->private_data; unsigned int mask = 0; lock_kernel(); @@ -603,7 +603,7 @@ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct unlock_kernel(); return POLLIN; } - + /* we may have dropped BKL - need to check for having lost the race */ if (file->private_data) { kfree(st); @@ -667,7 +667,7 @@ static loff_t usb_device_lseek(struct file * file, loff_t offset, int orig) return ret; } -struct file_operations usbfs_devices_fops = { +const struct file_operations usbfs_devices_fops = { .llseek = usb_device_lseek, .read = usb_device_read, .poll = usb_device_poll, diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 218621b9958..a94c63bef63 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -59,6 +59,9 @@ #define USB_DEVICE_MAX USB_MAXBUS * 128 static struct class *usb_device_class; +/* Mutual exclusion for removal, open, and release */ +DEFINE_MUTEX(usbfs_mutex); + struct async { struct list_head asynclist; struct dev_state *ps; @@ -87,9 +90,10 @@ MODULE_PARM_DESC (usbfs_snoop, "true to log all usbfs traffic"); #define MAX_USBFS_BUFFER_SIZE 16384 -static inline int connected (struct usb_device *dev) +static inline int connected (struct dev_state *ps) { - return dev->state != USB_STATE_NOTATTACHED; + return (!list_empty(&ps->list) && + ps->dev->state != USB_STATE_NOTATTACHED); } static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig) @@ -118,7 +122,7 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig) static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) { - struct dev_state *ps = (struct dev_state *)file->private_data; + struct dev_state *ps = file->private_data; struct usb_device *dev = ps->dev; ssize_t ret = 0; unsigned len; @@ -127,7 +131,7 @@ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, l pos = *ppos; usb_lock_device(dev); - if (!connected(dev)) { + if (!connected(ps)) { ret = -ENODEV; goto err; } else if (pos < 0) { @@ -301,7 +305,7 @@ static void snoop_urb(struct urb *urb, void __user *userurb) static void async_completed(struct urb *urb, struct pt_regs *regs) { - struct async *as = (struct async *)urb->context; + struct async *as = urb->context; struct dev_state *ps = as->ps; struct siginfo sinfo; @@ -541,25 +545,25 @@ static int usbdev_open(struct inode *inode, struct file *file) struct dev_state *ps; int ret; - /* - * no locking necessary here, as chrdev_open has the kernel lock - * (still acquire the kernel lock for safety) - */ + /* Protect against simultaneous removal or release */ + mutex_lock(&usbfs_mutex); + ret = -ENOMEM; if (!(ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL))) - goto out_nolock; + goto out; - lock_kernel(); ret = -ENOENT; /* check if we are called from a real node or usbfs */ if (imajor(inode) == USB_DEVICE_MAJOR) dev = usbdev_lookup_minor(iminor(inode)); if (!dev) - dev = inode->u.generic_ip; - if (!dev) { - kfree(ps); + dev = inode->i_private; + if (!dev) goto out; - } + ret = usb_autoresume_device(dev, 1); + if (ret) + goto out; + usb_get_dev(dev); ret = 0; ps->dev = dev; @@ -579,30 +583,36 @@ static int usbdev_open(struct inode *inode, struct file *file) list_add_tail(&ps->list, &dev->filelist); file->private_data = ps; out: - unlock_kernel(); - out_nolock: - return ret; + if (ret) + kfree(ps); + mutex_unlock(&usbfs_mutex); + return ret; } static int usbdev_release(struct inode *inode, struct file *file) { - struct dev_state *ps = (struct dev_state *)file->private_data; + struct dev_state *ps = file->private_data; struct usb_device *dev = ps->dev; unsigned int ifnum; usb_lock_device(dev); + + /* Protect against simultaneous open */ + mutex_lock(&usbfs_mutex); list_del_init(&ps->list); + mutex_unlock(&usbfs_mutex); + for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed); ifnum++) { if (test_bit(ifnum, &ps->ifclaimed)) releaseintf(ps, ifnum); } destroy_all_async(ps); + usb_autosuspend_device(dev, 1); usb_unlock_device(dev); usb_put_dev(dev); - ps->dev = NULL; kfree(ps); - return 0; + return 0; } static int proc_control(struct dev_state *ps, void __user *arg) @@ -1322,7 +1332,7 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) } } - if (!connected(ps->dev)) { + if (!connected(ps)) { kfree(buf); return -ENODEV; } @@ -1349,7 +1359,7 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) /* let kernel drivers try to (re)bind to the interface */ case USBDEVFS_CONNECT: usb_unlock_device(ps->dev); - bus_rescan_devices(intf->dev.bus); + retval = bus_rescan_devices(intf->dev.bus); usb_lock_device(ps->dev); break; @@ -1413,7 +1423,7 @@ static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg) */ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct dev_state *ps = (struct dev_state *)file->private_data; + struct dev_state *ps = file->private_data; struct usb_device *dev = ps->dev; void __user *p = (void __user *)arg; int ret = -ENOTTY; @@ -1421,7 +1431,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd if (!(file->f_mode & FMODE_WRITE)) return -EPERM; usb_lock_device(dev); - if (!connected(dev)) { + if (!connected(ps)) { usb_unlock_device(dev); return -ENODEV; } @@ -1556,18 +1566,18 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd /* No kernel lock - fine */ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wait) { - struct dev_state *ps = (struct dev_state *)file->private_data; - unsigned int mask = 0; + struct dev_state *ps = file->private_data; + unsigned int mask = 0; poll_wait(file, &ps->wait, wait); if (file->f_mode & FMODE_WRITE && !list_empty(&ps->async_completed)) mask |= POLLOUT | POLLWRNORM; - if (!connected(ps->dev)) + if (!connected(ps)) mask |= POLLERR | POLLHUP; return mask; } -struct file_operations usbfs_device_file_operations = { +const struct file_operations usbfs_device_file_operations = { .llseek = usbdev_lseek, .read = usbdev_read, .poll = usbdev_poll, diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index ec890650141..b1046324441 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -17,7 +17,8 @@ * * NOTE! This is not actually a driver at all, rather this is * just a collection of helper routines that implement the - * generic USB things that the real drivers can use.. + * matching, probing, releasing, suspending and resuming for + * real drivers. * */ @@ -34,38 +35,6 @@ struct usb_dynid { struct usb_device_id id; }; - -static int generic_probe(struct device *dev) -{ - return 0; -} -static int generic_remove(struct device *dev) -{ - struct usb_device *udev = to_usb_device(dev); - - /* if this is only an unbind, not a physical disconnect, then - * unconfigure the device */ - if (udev->state == USB_STATE_CONFIGURED) - usb_set_configuration(udev, 0); - - /* in case the call failed or the device was suspended */ - if (udev->state >= USB_STATE_CONFIGURED) - usb_disable_device(udev, 0); - return 0; -} - -struct device_driver usb_generic_driver = { - .owner = THIS_MODULE, - .name = "usb", - .bus = &usb_bus_type, - .probe = generic_probe, - .remove = generic_remove, -}; - -/* Fun hack to determine if the struct device is a - * usb device or a usb interface. */ -int usb_generic_driver_data; - #ifdef CONFIG_HOTPLUG /* @@ -80,6 +49,7 @@ static ssize_t store_new_id(struct device_driver *driver, u32 idVendor = 0; u32 idProduct = 0; int fields = 0; + int retval = 0; fields = sscanf(buf, "%x %x", &idVendor, &idProduct); if (fields < 2) @@ -99,10 +69,12 @@ static ssize_t store_new_id(struct device_driver *driver, spin_unlock(&usb_drv->dynids.lock); if (get_driver(driver)) { - driver_attach(driver); + retval = driver_attach(driver); put_driver(driver); } + if (retval) + return retval; return count; } static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); @@ -115,7 +87,7 @@ static int usb_create_newid_file(struct usb_driver *usb_drv) goto exit; if (usb_drv->probe != NULL) - error = sysfs_create_file(&usb_drv->driver.kobj, + error = sysfs_create_file(&usb_drv->drvwrap.driver.kobj, &driver_attr_new_id.attr); exit: return error; @@ -127,7 +99,7 @@ static void usb_remove_newid_file(struct usb_driver *usb_drv) return; if (usb_drv->probe != NULL) - sysfs_remove_file(&usb_drv->driver.kobj, + sysfs_remove_file(&usb_drv->drvwrap.driver.kobj, &driver_attr_new_id.attr); } @@ -174,21 +146,57 @@ static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *in } -/* called from driver core with usb_bus_type.subsys writelock */ +/* called from driver core with dev locked */ +static int usb_probe_device(struct device *dev) +{ + struct usb_device_driver *udriver = to_usb_device_driver(dev->driver); + struct usb_device *udev; + int error = -ENODEV; + + dev_dbg(dev, "%s\n", __FUNCTION__); + + if (!is_usb_device(dev)) /* Sanity check */ + return error; + + udev = to_usb_device(dev); + + /* TODO: Add real matching code */ + + /* The device should always appear to be in use + * unless the driver suports autosuspend. + */ + udev->pm_usage_cnt = !(udriver->supports_autosuspend); + + error = udriver->probe(udev); + return error; +} + +/* called from driver core with dev locked */ +static int usb_unbind_device(struct device *dev) +{ + struct usb_device_driver *udriver = to_usb_device_driver(dev->driver); + + udriver->disconnect(to_usb_device(dev)); + return 0; +} + + +/* called from driver core with dev locked */ static int usb_probe_interface(struct device *dev) { - struct usb_interface * intf = to_usb_interface(dev); - struct usb_driver * driver = to_usb_driver(dev->driver); + struct usb_driver *driver = to_usb_driver(dev->driver); + struct usb_interface *intf; + struct usb_device *udev; const struct usb_device_id *id; int error = -ENODEV; dev_dbg(dev, "%s\n", __FUNCTION__); - if (!driver->probe) + if (is_usb_device(dev)) /* Sanity check */ return error; - /* FIXME we'd much prefer to just resume it ... */ - if (interface_to_usbdev(intf)->state == USB_STATE_SUSPENDED) - return -EHOSTUNREACH; + + intf = to_usb_interface(dev); + udev = interface_to_usbdev(intf); id = usb_match_id(intf, driver->id_table); if (!id) @@ -196,48 +204,165 @@ static int usb_probe_interface(struct device *dev) if (id) { dev_dbg(dev, "%s - got id\n", __FUNCTION__); + error = usb_autoresume_device(udev, 1); + if (error) + return error; + /* Interface "power state" doesn't correspond to any hardware * state whatsoever. We use it to record when it's bound to * a driver that may start I/0: it's not frozen/quiesced. */ mark_active(intf); intf->condition = USB_INTERFACE_BINDING; + + /* The interface should always appear to be in use + * unless the driver suports autosuspend. + */ + intf->pm_usage_cnt = !(driver->supports_autosuspend); + error = driver->probe(intf, id); if (error) { mark_quiesced(intf); + intf->needs_remote_wakeup = 0; intf->condition = USB_INTERFACE_UNBOUND; } else intf->condition = USB_INTERFACE_BOUND; + + usb_autosuspend_device(udev, 1); } return error; } -/* called from driver core with usb_bus_type.subsys writelock */ +/* called from driver core with dev locked */ static int usb_unbind_interface(struct device *dev) { + struct usb_driver *driver = to_usb_driver(dev->driver); struct usb_interface *intf = to_usb_interface(dev); - struct usb_driver *driver = to_usb_driver(intf->dev.driver); + struct usb_device *udev; + int error; intf->condition = USB_INTERFACE_UNBINDING; + /* Autoresume for set_interface call below */ + udev = interface_to_usbdev(intf); + error = usb_autoresume_device(udev, 1); + /* release all urbs for this interface */ usb_disable_interface(interface_to_usbdev(intf), intf); - if (driver && driver->disconnect) - driver->disconnect(intf); + driver->disconnect(intf); /* reset other interface state */ usb_set_interface(interface_to_usbdev(intf), intf->altsetting[0].desc.bInterfaceNumber, 0); usb_set_intfdata(intf, NULL); + intf->condition = USB_INTERFACE_UNBOUND; mark_quiesced(intf); + intf->needs_remote_wakeup = 0; + + if (!error) + usb_autosuspend_device(udev, 1); return 0; } +/** + * usb_driver_claim_interface - bind a driver to an interface + * @driver: the driver to be bound + * @iface: the interface to which it will be bound; must be in the + * usb device's active configuration + * @priv: driver data associated with that interface + * + * This is used by usb device drivers that need to claim more than one + * interface on a device when probing (audio and acm are current examples). + * No device driver should directly modify internal usb_interface or + * usb_device structure members. + * + * Few drivers should need to use this routine, since the most natural + * way to bind to an interface is to return the private data from + * the driver's probe() method. + * + * Callers must own the device lock and the driver model's usb_bus_type.subsys + * writelock. So driver probe() entries don't need extra locking, + * but other call contexts may need to explicitly claim those locks. + */ +int usb_driver_claim_interface(struct usb_driver *driver, + struct usb_interface *iface, void* priv) +{ + struct device *dev = &iface->dev; + struct usb_device *udev = interface_to_usbdev(iface); + int retval = 0; + + if (dev->driver) + return -EBUSY; + + dev->driver = &driver->drvwrap.driver; + usb_set_intfdata(iface, priv); + + mutex_lock_nested(&udev->pm_mutex, udev->level); + iface->condition = USB_INTERFACE_BOUND; + mark_active(iface); + iface->pm_usage_cnt = !(driver->supports_autosuspend); + mutex_unlock(&udev->pm_mutex); + + /* if interface was already added, bind now; else let + * the future device_add() bind it, bypassing probe() + */ + if (device_is_registered(dev)) + retval = device_bind_driver(dev); + + return retval; +} +EXPORT_SYMBOL(usb_driver_claim_interface); + +/** + * usb_driver_release_interface - unbind a driver from an interface + * @driver: the driver to be unbound + * @iface: the interface from which it will be unbound + * + * This can be used by drivers to release an interface without waiting + * for their disconnect() methods to be called. In typical cases this + * also causes the driver disconnect() method to be called. + * + * This call is synchronous, and may not be used in an interrupt context. + * Callers must own the device lock and the driver model's usb_bus_type.subsys + * writelock. So driver disconnect() entries don't need extra locking, + * but other call contexts may need to explicitly claim those locks. + */ +void usb_driver_release_interface(struct usb_driver *driver, + struct usb_interface *iface) +{ + struct device *dev = &iface->dev; + struct usb_device *udev = interface_to_usbdev(iface); + + /* this should never happen, don't release something that's not ours */ + if (!dev->driver || dev->driver != &driver->drvwrap.driver) + return; + + /* don't release from within disconnect() */ + if (iface->condition != USB_INTERFACE_BOUND) + return; + + /* don't release if the interface hasn't been added yet */ + if (device_is_registered(dev)) { + iface->condition = USB_INTERFACE_UNBINDING; + device_release_driver(dev); + } + + dev->driver = NULL; + usb_set_intfdata(iface, NULL); + + mutex_lock_nested(&udev->pm_mutex, udev->level); + iface->condition = USB_INTERFACE_UNBOUND; + mark_quiesced(iface); + iface->needs_remote_wakeup = 0; + mutex_unlock(&udev->pm_mutex); +} +EXPORT_SYMBOL(usb_driver_release_interface); + /* returns 0 if no match, 1 if match */ static int usb_match_one_id(struct usb_interface *interface, const struct usb_device_id *id) @@ -381,35 +506,223 @@ EXPORT_SYMBOL_GPL_FUTURE(usb_match_id); int usb_device_match(struct device *dev, struct device_driver *drv) { + /* devices and interfaces are handled separately */ + if (is_usb_device(dev)) { + + /* interface drivers never match devices */ + if (!is_usb_device_driver(drv)) + return 0; + + /* TODO: Add real matching code */ + return 1; + + } else { + struct usb_interface *intf; + struct usb_driver *usb_drv; + const struct usb_device_id *id; + + /* device drivers never match interfaces */ + if (is_usb_device_driver(drv)) + return 0; + + intf = to_usb_interface(dev); + usb_drv = to_usb_driver(drv); + + id = usb_match_id(intf, usb_drv->id_table); + if (id) + return 1; + + id = usb_match_dynamic_id(intf, usb_drv); + if (id) + return 1; + } + + return 0; +} + +#ifdef CONFIG_HOTPLUG + +/* + * This sends an uevent to userspace, typically helping to load driver + * or other modules, configure the device, and more. Drivers can provide + * a MODULE_DEVICE_TABLE to help with module loading subtasks. + * + * We're called either from khubd (the typical case) or from root hub + * (init, kapmd, modprobe, rmmod, etc), but the agents need to handle + * delays in event delivery. Use sysfs (and DEVPATH) to make sure the + * device (and this configuration!) are still present. + */ +static int usb_uevent(struct device *dev, char **envp, int num_envp, + char *buffer, int buffer_size) +{ struct usb_interface *intf; - struct usb_driver *usb_drv; - const struct usb_device_id *id; + struct usb_device *usb_dev; + struct usb_host_interface *alt; + int i = 0; + int length = 0; - /* check for generic driver, which we don't match any device with */ - if (drv == &usb_generic_driver) - return 0; + if (!dev) + return -ENODEV; - intf = to_usb_interface(dev); - usb_drv = to_usb_driver(drv); + /* driver is often null here; dev_dbg() would oops */ + pr_debug ("usb %s: uevent\n", dev->bus_id); - id = usb_match_id(intf, usb_drv->id_table); - if (id) - return 1; + if (is_usb_device(dev)) { + usb_dev = to_usb_device(dev); + alt = NULL; + } else { + intf = to_usb_interface(dev); + usb_dev = interface_to_usbdev(intf); + alt = intf->cur_altsetting; + } + + if (usb_dev->devnum < 0) { + pr_debug ("usb %s: already deleted?\n", dev->bus_id); + return -ENODEV; + } + if (!usb_dev->bus) { + pr_debug ("usb %s: bus removed?\n", dev->bus_id); + return -ENODEV; + } + +#ifdef CONFIG_USB_DEVICEFS + /* If this is available, userspace programs can directly read + * all the device descriptors we don't tell them about. Or + * even act as usermode drivers. + * + * FIXME reduce hardwired intelligence here + */ + if (add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "DEVICE=/proc/bus/usb/%03d/%03d", + usb_dev->bus->busnum, usb_dev->devnum)) + return -ENOMEM; +#endif + + /* per-device configurations are common */ + if (add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "PRODUCT=%x/%x/%x", + le16_to_cpu(usb_dev->descriptor.idVendor), + le16_to_cpu(usb_dev->descriptor.idProduct), + le16_to_cpu(usb_dev->descriptor.bcdDevice))) + return -ENOMEM; + + /* class-based driver binding models */ + if (add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "TYPE=%d/%d/%d", + usb_dev->descriptor.bDeviceClass, + usb_dev->descriptor.bDeviceSubClass, + usb_dev->descriptor.bDeviceProtocol)) + return -ENOMEM; + + if (!is_usb_device(dev)) { + + if (add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "INTERFACE=%d/%d/%d", + alt->desc.bInterfaceClass, + alt->desc.bInterfaceSubClass, + alt->desc.bInterfaceProtocol)) + return -ENOMEM; + + if (add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", + le16_to_cpu(usb_dev->descriptor.idVendor), + le16_to_cpu(usb_dev->descriptor.idProduct), + le16_to_cpu(usb_dev->descriptor.bcdDevice), + usb_dev->descriptor.bDeviceClass, + usb_dev->descriptor.bDeviceSubClass, + usb_dev->descriptor.bDeviceProtocol, + alt->desc.bInterfaceClass, + alt->desc.bInterfaceSubClass, + alt->desc.bInterfaceProtocol)) + return -ENOMEM; + } + + envp[i] = NULL; - id = usb_match_dynamic_id(intf, usb_drv); - if (id) - return 1; return 0; } +#else + +static int usb_uevent(struct device *dev, char **envp, + int num_envp, char *buffer, int buffer_size) +{ + return -ENODEV; +} + +#endif /* CONFIG_HOTPLUG */ + +/** + * usb_register_device_driver - register a USB device (not interface) driver + * @new_udriver: USB operations for the device driver + * @owner: module owner of this driver. + * + * Registers a USB device driver with the USB core. The list of + * unattached devices will be rescanned whenever a new driver is + * added, allowing the new driver to attach to any recognized devices. + * Returns a negative error code on failure and 0 on success. + */ +int usb_register_device_driver(struct usb_device_driver *new_udriver, + struct module *owner) +{ + int retval = 0; + + if (usb_disabled()) + return -ENODEV; + + new_udriver->drvwrap.for_devices = 1; + new_udriver->drvwrap.driver.name = (char *) new_udriver->name; + new_udriver->drvwrap.driver.bus = &usb_bus_type; + new_udriver->drvwrap.driver.probe = usb_probe_device; + new_udriver->drvwrap.driver.remove = usb_unbind_device; + new_udriver->drvwrap.driver.owner = owner; + + retval = driver_register(&new_udriver->drvwrap.driver); + + if (!retval) { + pr_info("%s: registered new device driver %s\n", + usbcore_name, new_udriver->name); + usbfs_update_special(); + } else { + printk(KERN_ERR "%s: error %d registering device " + " driver %s\n", + usbcore_name, retval, new_udriver->name); + } + + return retval; +} +EXPORT_SYMBOL_GPL(usb_register_device_driver); + +/** + * usb_deregister_device_driver - unregister a USB device (not interface) driver + * @udriver: USB operations of the device driver to unregister + * Context: must be able to sleep + * + * Unlinks the specified driver from the internal USB driver list. + */ +void usb_deregister_device_driver(struct usb_device_driver *udriver) +{ + pr_info("%s: deregistering device driver %s\n", + usbcore_name, udriver->name); + + driver_unregister(&udriver->drvwrap.driver); + usbfs_update_special(); +} +EXPORT_SYMBOL_GPL(usb_deregister_device_driver); + /** - * usb_register_driver - register a USB driver - * @new_driver: USB operations for the driver + * usb_register_driver - register a USB interface driver + * @new_driver: USB operations for the interface driver * @owner: module owner of this driver. * - * Registers a USB driver with the USB core. The list of unattached - * interfaces will be rescanned whenever a new driver is added, allowing - * the new driver to attach to any recognized devices. + * Registers a USB interface driver with the USB core. The list of + * unattached interfaces will be rescanned whenever a new driver is + * added, allowing the new driver to attach to any recognized interfaces. * Returns a negative error code on failure and 0 on success. * * NOTE: if you want your driver to use the USB major number, you must call @@ -423,23 +736,25 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner) if (usb_disabled()) return -ENODEV; - new_driver->driver.name = (char *)new_driver->name; - new_driver->driver.bus = &usb_bus_type; - new_driver->driver.probe = usb_probe_interface; - new_driver->driver.remove = usb_unbind_interface; - new_driver->driver.owner = owner; + new_driver->drvwrap.for_devices = 0; + new_driver->drvwrap.driver.name = (char *) new_driver->name; + new_driver->drvwrap.driver.bus = &usb_bus_type; + new_driver->drvwrap.driver.probe = usb_probe_interface; + new_driver->drvwrap.driver.remove = usb_unbind_interface; + new_driver->drvwrap.driver.owner = owner; spin_lock_init(&new_driver->dynids.lock); INIT_LIST_HEAD(&new_driver->dynids.list); - retval = driver_register(&new_driver->driver); + retval = driver_register(&new_driver->drvwrap.driver); if (!retval) { - pr_info("%s: registered new driver %s\n", + pr_info("%s: registered new interface driver %s\n", usbcore_name, new_driver->name); usbfs_update_special(); usb_create_newid_file(new_driver); } else { - printk(KERN_ERR "%s: error %d registering driver %s\n", + printk(KERN_ERR "%s: error %d registering interface " + " driver %s\n", usbcore_name, retval, new_driver->name); } @@ -448,8 +763,8 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner) EXPORT_SYMBOL_GPL_FUTURE(usb_register_driver); /** - * usb_deregister - unregister a USB driver - * @driver: USB operations of the driver to unregister + * usb_deregister - unregister a USB interface driver + * @driver: USB operations of the interface driver to unregister * Context: must be able to sleep * * Unlinks the specified driver from the internal USB driver list. @@ -460,12 +775,554 @@ EXPORT_SYMBOL_GPL_FUTURE(usb_register_driver); */ void usb_deregister(struct usb_driver *driver) { - pr_info("%s: deregistering driver %s\n", usbcore_name, driver->name); + pr_info("%s: deregistering interface driver %s\n", + usbcore_name, driver->name); usb_remove_newid_file(driver); usb_free_dynids(driver); - driver_unregister(&driver->driver); + driver_unregister(&driver->drvwrap.driver); usbfs_update_special(); } EXPORT_SYMBOL_GPL_FUTURE(usb_deregister); + +#ifdef CONFIG_PM + +/* Caller has locked udev->pm_mutex */ +static int suspend_device(struct usb_device *udev, pm_message_t msg) +{ + struct usb_device_driver *udriver; + int status = 0; + + if (udev->state == USB_STATE_NOTATTACHED || + udev->state == USB_STATE_SUSPENDED) + goto done; + + /* For devices that don't have a driver, we do a standard suspend. */ + if (udev->dev.driver == NULL) { + udev->do_remote_wakeup = 0; + status = usb_port_suspend(udev); + goto done; + } + + udriver = to_usb_device_driver(udev->dev.driver); + status = udriver->suspend(udev, msg); + +done: + // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); + if (status == 0) + udev->dev.power.power_state.event = msg.event; + return status; +} + +/* Caller has locked udev->pm_mutex */ +static int resume_device(struct usb_device *udev) +{ + struct usb_device_driver *udriver; + int status = 0; + + if (udev->state == USB_STATE_NOTATTACHED || + udev->state != USB_STATE_SUSPENDED) + goto done; + + /* Can't resume it if it doesn't have a driver. */ + if (udev->dev.driver == NULL) { + status = -ENOTCONN; + goto done; + } + + udriver = to_usb_device_driver(udev->dev.driver); + status = udriver->resume(udev); + +done: + // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); + if (status == 0) + udev->dev.power.power_state.event = PM_EVENT_ON; + return status; +} + +/* Caller has locked intf's usb_device's pm_mutex */ +static int suspend_interface(struct usb_interface *intf, pm_message_t msg) +{ + struct usb_driver *driver; + int status = 0; + + /* with no hardware, USB interfaces only use FREEZE and ON states */ + if (interface_to_usbdev(intf)->state == USB_STATE_NOTATTACHED || + !is_active(intf)) + goto done; + + if (intf->condition == USB_INTERFACE_UNBOUND) /* This can't happen */ + goto done; + driver = to_usb_driver(intf->dev.driver); + + if (driver->suspend && driver->resume) { + status = driver->suspend(intf, msg); + if (status == 0) + mark_quiesced(intf); + else if (!interface_to_usbdev(intf)->auto_pm) + dev_err(&intf->dev, "%s error %d\n", + "suspend", status); + } else { + // FIXME else if there's no suspend method, disconnect... + // Not possible if auto_pm is set... + dev_warn(&intf->dev, "no suspend for driver %s?\n", + driver->name); + mark_quiesced(intf); + } + +done: + // dev_dbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status); + if (status == 0) + intf->dev.power.power_state.event = msg.event; + return status; +} + +/* Caller has locked intf's usb_device's pm_mutex */ +static int resume_interface(struct usb_interface *intf) +{ + struct usb_driver *driver; + int status = 0; + + if (interface_to_usbdev(intf)->state == USB_STATE_NOTATTACHED || + is_active(intf)) + goto done; + + /* Don't let autoresume interfere with unbinding */ + if (intf->condition == USB_INTERFACE_UNBINDING) + goto done; + + /* Can't resume it if it doesn't have a driver. */ + if (intf->condition == USB_INTERFACE_UNBOUND) { + status = -ENOTCONN; + goto done; + } + driver = to_usb_driver(intf->dev.driver); + + if (driver->resume) { + status = driver->resume(intf); + if (status) + dev_err(&intf->dev, "%s error %d\n", + "resume", status); + else + mark_active(intf); + } else { + dev_warn(&intf->dev, "no resume for driver %s?\n", + driver->name); + mark_active(intf); + } + +done: + // dev_dbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status); + if (status == 0) + intf->dev.power.power_state.event = PM_EVENT_ON; + return status; +} + +/** + * usb_suspend_both - suspend a USB device and its interfaces + * @udev: the usb_device to suspend + * @msg: Power Management message describing this state transition + * + * This is the central routine for suspending USB devices. It calls the + * suspend methods for all the interface drivers in @udev and then calls + * the suspend method for @udev itself. If an error occurs at any stage, + * all the interfaces which were suspended are resumed so that they remain + * in the same state as the device. + * + * If an autosuspend is in progress (@udev->auto_pm is set), the routine + * checks first to make sure that neither the device itself or any of its + * active interfaces is in use (pm_usage_cnt is greater than 0). If they + * are, the autosuspend fails. + * + * If the suspend succeeds, the routine recursively queues an autosuspend + * request for @udev's parent device, thereby propagating the change up + * the device tree. If all of the parent's children are now suspended, + * the parent will autosuspend in turn. + * + * The suspend method calls are subject to mutual exclusion under control + * of @udev's pm_mutex. Many of these calls are also under the protection + * of @udev's device lock (including all requests originating outside the + * USB subsystem), but autosuspend requests generated by a child device or + * interface driver may not be. Usbcore will insure that the method calls + * do not arrive during bind, unbind, or reset operations. However, drivers + * must be prepared to handle suspend calls arriving at unpredictable times. + * The only way to block such calls is to do an autoresume (preventing + * autosuspends) while holding @udev's device lock (preventing outside + * suspends). + * + * The caller must hold @udev->pm_mutex. + * + * This routine can run only in process context. + */ +int usb_suspend_both(struct usb_device *udev, pm_message_t msg) +{ + int status = 0; + int i = 0; + struct usb_interface *intf; + struct usb_device *parent = udev->parent; + + cancel_delayed_work(&udev->autosuspend); + if (udev->state == USB_STATE_NOTATTACHED) + return 0; + if (udev->state == USB_STATE_SUSPENDED) + return 0; + + udev->do_remote_wakeup = device_may_wakeup(&udev->dev); + + /* For autosuspend, fail fast if anything is in use. + * Also fail if any interfaces require remote wakeup but it + * isn't available. */ + if (udev->auto_pm) { + if (udev->pm_usage_cnt > 0) + return -EBUSY; + if (udev->actconfig) { + for (; i < udev->actconfig->desc.bNumInterfaces; i++) { + intf = udev->actconfig->interface[i]; + if (!is_active(intf)) + continue; + if (intf->pm_usage_cnt > 0) + return -EBUSY; + if (intf->needs_remote_wakeup && + !udev->do_remote_wakeup) { + dev_dbg(&udev->dev, + "remote wakeup needed for autosuspend\n"); + return -EOPNOTSUPP; + } + } + i = 0; + } + } + + /* Suspend all the interfaces and then udev itself */ + if (udev->actconfig) { + for (; i < udev->actconfig->desc.bNumInterfaces; i++) { + intf = udev->actconfig->interface[i]; + status = suspend_interface(intf, msg); + if (status != 0) + break; + } + } + if (status == 0) + status = suspend_device(udev, msg); + + /* If the suspend failed, resume interfaces that did get suspended */ + if (status != 0) { + while (--i >= 0) { + intf = udev->actconfig->interface[i]; + resume_interface(intf); + } + + /* If the suspend succeeded, propagate it up the tree */ + } else if (parent) + usb_autosuspend_device(parent, 0); + + // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); + return status; +} + +/** + * usb_resume_both - resume a USB device and its interfaces + * @udev: the usb_device to resume + * + * This is the central routine for resuming USB devices. It calls the + * the resume method for @udev and then calls the resume methods for all + * the interface drivers in @udev. + * + * Before starting the resume, the routine calls itself recursively for + * the parent device of @udev, thereby propagating the change up the device + * tree and assuring that @udev will be able to resume. If the parent is + * unable to resume successfully, the routine fails. + * + * The resume method calls are subject to mutual exclusion under control + * of @udev's pm_mutex. Many of these calls are also under the protection + * of @udev's device lock (including all requests originating outside the + * USB subsystem), but autoresume requests generated by a child device or + * interface driver may not be. Usbcore will insure that the method calls + * do not arrive during bind, unbind, or reset operations. However, drivers + * must be prepared to handle resume calls arriving at unpredictable times. + * The only way to block such calls is to do an autoresume (preventing + * other autoresumes) while holding @udev's device lock (preventing outside + * resumes). + * + * The caller must hold @udev->pm_mutex. + * + * This routine can run only in process context. + */ +int usb_resume_both(struct usb_device *udev) +{ + int status = 0; + int i; + struct usb_interface *intf; + struct usb_device *parent = udev->parent; + + cancel_delayed_work(&udev->autosuspend); + if (udev->state == USB_STATE_NOTATTACHED) + return -ENODEV; + + /* Propagate the resume up the tree, if necessary */ + if (udev->state == USB_STATE_SUSPENDED) { + if (parent) { + mutex_lock_nested(&parent->pm_mutex, parent->level); + parent->auto_pm = 1; + status = usb_resume_both(parent); + } else { + + /* We can't progagate beyond the USB subsystem, + * so if a root hub's controller is suspended + * then we're stuck. */ + if (udev->dev.parent->power.power_state.event != + PM_EVENT_ON) + status = -EHOSTUNREACH; + } + if (status == 0) + status = resume_device(udev); + if (parent) + mutex_unlock(&parent->pm_mutex); + } else { + + /* Needed only for setting udev->dev.power.power_state.event + * and for possible debugging message. */ + status = resume_device(udev); + } + + /* Now the parent won't suspend until we are finished */ + + if (status == 0 && udev->actconfig) { + for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { + intf = udev->actconfig->interface[i]; + resume_interface(intf); + } + } + + // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); + return status; +} + +#ifdef CONFIG_USB_SUSPEND + +/** + * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces + * @udev - the usb_device to autosuspend + * @dec_usage_cnt - flag to decrement @udev's PM-usage counter + * + * This routine should be called when a core subsystem is finished using + * @udev and wants to allow it to autosuspend. Examples would be when + * @udev's device file in usbfs is closed or after a configuration change. + * + * @dec_usage_cnt should be 1 if the subsystem previously incremented + * @udev's usage counter (such as by passing 1 to usb_autoresume_device); + * otherwise it should be 0. + * + * If the usage counter for @udev or any of its active interfaces is greater + * than 0, the autosuspend request will not be queued. (If an interface + * driver does not support autosuspend then its usage counter is permanently + * positive.) Likewise, if an interface driver requires remote-wakeup + * capability during autosuspend but remote wakeup is disabled, the + * autosuspend will fail. + * + * Often the caller will hold @udev's device lock, but this is not + * necessary. + * + * This routine can run only in process context. + */ +void usb_autosuspend_device(struct usb_device *udev, int dec_usage_cnt) +{ + mutex_lock_nested(&udev->pm_mutex, udev->level); + udev->pm_usage_cnt -= dec_usage_cnt; + if (udev->pm_usage_cnt <= 0) + schedule_delayed_work(&udev->autosuspend, + USB_AUTOSUSPEND_DELAY); + mutex_unlock(&udev->pm_mutex); + // dev_dbg(&udev->dev, "%s: cnt %d\n", + // __FUNCTION__, udev->pm_usage_cnt); +} + +/** + * usb_autoresume_device - immediately autoresume a USB device and its interfaces + * @udev - the usb_device to autoresume + * @inc_usage_cnt - flag to increment @udev's PM-usage counter + * + * This routine should be called when a core subsystem wants to use @udev + * and needs to guarantee that it is not suspended. In addition, the + * caller can prevent @udev from being autosuspended subsequently. (Note + * that this will not prevent suspend events originating in the PM core.) + * Examples would be when @udev's device file in usbfs is opened (autosuspend + * should be prevented until the file is closed) or when a remote-wakeup + * request is received (later autosuspends should not be prevented). + * + * @inc_usage_cnt should be 1 to increment @udev's usage counter and prevent + * autosuspends. This prevention will persist until the usage counter is + * decremented again (such as by passing 1 to usb_autosuspend_device). + * Otherwise @inc_usage_cnt should be 0 to leave the usage counter unchanged. + * Regardless, if the autoresume fails then the usage counter is not + * incremented. + * + * Often the caller will hold @udev's device lock, but this is not + * necessary (and attempting it might cause deadlock). + * + * This routine can run only in process context. + */ +int usb_autoresume_device(struct usb_device *udev, int inc_usage_cnt) +{ + int status; + + mutex_lock_nested(&udev->pm_mutex, udev->level); + udev->pm_usage_cnt += inc_usage_cnt; + udev->auto_pm = 1; + status = usb_resume_both(udev); + if (status != 0) + udev->pm_usage_cnt -= inc_usage_cnt; + mutex_unlock(&udev->pm_mutex); + // dev_dbg(&udev->dev, "%s: status %d cnt %d\n", + // __FUNCTION__, status, udev->pm_usage_cnt); + return status; +} + +/** + * usb_autopm_put_interface - decrement a USB interface's PM-usage counter + * @intf - the usb_interface whose counter should be decremented + * + * This routine should be called by an interface driver when it is + * finished using @intf and wants to allow it to autosuspend. A typical + * example would be a character-device driver when its device file is + * closed. + * + * The routine decrements @intf's usage counter. When the counter reaches + * 0, a delayed autosuspend request for @intf's device is queued. When + * the delay expires, if @intf->pm_usage_cnt is still <= 0 along with all + * the other usage counters for the sibling interfaces and @intf's + * usb_device, the device and all its interfaces will be autosuspended. + * + * Note that @intf->pm_usage_cnt is owned by the interface driver. The + * core will not change its value other than the increment and decrement + * in usb_autopm_get_interface and usb_autopm_put_interface. The driver + * may use this simple counter-oriented discipline or may set the value + * any way it likes. + * + * If the driver has set @intf->needs_remote_wakeup then autosuspend will + * take place only if the device's remote-wakeup facility is enabled. + * + * Suspend method calls queued by this routine can arrive at any time + * while @intf is resumed and its usage counter is equal to 0. They are + * not protected by the usb_device's lock but only by its pm_mutex. + * Drivers must provide their own synchronization. + * + * This routine can run only in process context. + */ +void usb_autopm_put_interface(struct usb_interface *intf) +{ + struct usb_device *udev = interface_to_usbdev(intf); + + mutex_lock_nested(&udev->pm_mutex, udev->level); + if (intf->condition != USB_INTERFACE_UNBOUND) { + if (--intf->pm_usage_cnt <= 0) + schedule_delayed_work(&udev->autosuspend, + USB_AUTOSUSPEND_DELAY); + } + mutex_unlock(&udev->pm_mutex); + // dev_dbg(&intf->dev, "%s: cnt %d\n", + // __FUNCTION__, intf->pm_usage_cnt); +} +EXPORT_SYMBOL_GPL(usb_autopm_put_interface); + +/** + * usb_autopm_get_interface - increment a USB interface's PM-usage counter + * @intf - the usb_interface whose counter should be incremented + * + * This routine should be called by an interface driver when it wants to + * use @intf and needs to guarantee that it is not suspended. In addition, + * the routine prevents @intf from being autosuspended subsequently. (Note + * that this will not prevent suspend events originating in the PM core.) + * This prevention will persist until usb_autopm_put_interface() is called + * or @intf is unbound. A typical example would be a character-device + * driver when its device file is opened. + * + * The routine increments @intf's usage counter. So long as the counter + * is greater than 0, autosuspend will not be allowed for @intf or its + * usb_device. When the driver is finished using @intf it should call + * usb_autopm_put_interface() to decrement the usage counter and queue + * a delayed autosuspend request (if the counter is <= 0). + * + * Note that @intf->pm_usage_cnt is owned by the interface driver. The + * core will not change its value other than the increment and decrement + * in usb_autopm_get_interface and usb_autopm_put_interface. The driver + * may use this simple counter-oriented discipline or may set the value + * any way it likes. + * + * Resume method calls generated by this routine can arrive at any time + * while @intf is suspended. They are not protected by the usb_device's + * lock but only by its pm_mutex. Drivers must provide their own + * synchronization. + * + * This routine can run only in process context. + */ +int usb_autopm_get_interface(struct usb_interface *intf) +{ + struct usb_device *udev = interface_to_usbdev(intf); + int status; + + mutex_lock_nested(&udev->pm_mutex, udev->level); + if (intf->condition == USB_INTERFACE_UNBOUND) + status = -ENODEV; + else { + ++intf->pm_usage_cnt; + udev->auto_pm = 1; + status = usb_resume_both(udev); + if (status != 0) + --intf->pm_usage_cnt; + } + mutex_unlock(&udev->pm_mutex); + // dev_dbg(&intf->dev, "%s: status %d cnt %d\n", + // __FUNCTION__, status, intf->pm_usage_cnt); + return status; +} +EXPORT_SYMBOL_GPL(usb_autopm_get_interface); + +#endif /* CONFIG_USB_SUSPEND */ + +static int usb_suspend(struct device *dev, pm_message_t message) +{ + int status; + + if (is_usb_device(dev)) { + struct usb_device *udev = to_usb_device(dev); + + mutex_lock_nested(&udev->pm_mutex, udev->level); + udev->auto_pm = 0; + status = usb_suspend_both(udev, message); + mutex_unlock(&udev->pm_mutex); + } else + status = 0; + return status; +} + +static int usb_resume(struct device *dev) +{ + int status; + + if (is_usb_device(dev)) { + struct usb_device *udev = to_usb_device(dev); + + mutex_lock_nested(&udev->pm_mutex, udev->level); + udev->auto_pm = 0; + status = usb_resume_both(udev); + mutex_unlock(&udev->pm_mutex); + + /* Rebind drivers that had no suspend method? */ + } else + status = 0; + return status; +} + +#endif /* CONFIG_PM */ + +struct bus_type usb_bus_type = { + .name = "usb", + .match = usb_device_match, + .uevent = usb_uevent, +#ifdef CONFIG_PM + .suspend = usb_suspend, + .resume = usb_resume, +#endif +}; diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index 247b5a4913a..3ebb90149e9 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -207,9 +207,9 @@ static void ep_device_release(struct device *dev) kfree(ep_dev); } -void usb_create_ep_files(struct device *parent, - struct usb_host_endpoint *endpoint, - struct usb_device *udev) +int usb_create_ep_files(struct device *parent, + struct usb_host_endpoint *endpoint, + struct usb_device *udev) { char name[8]; struct ep_device *ep_dev; @@ -242,19 +242,33 @@ void usb_create_ep_files(struct device *parent, retval = device_register(&ep_dev->dev); if (retval) goto error; - sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp); + retval = sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp); + if (retval) + goto error_group; endpoint->ep_dev = ep_dev; /* create the symlink to the old-style "ep_XX" directory */ sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress); - sysfs_create_link(&parent->kobj, &endpoint->ep_dev->dev.kobj, name); - + retval = sysfs_create_link(&parent->kobj, + &endpoint->ep_dev->dev.kobj, name); + if (retval) + goto error_link; exit: - return; + return retval; + +error_link: + sysfs_remove_group(&ep_dev->dev.kobj, &ep_dev_attr_grp); + +error_group: + device_unregister(&ep_dev->dev); + endpoint->ep_dev = NULL; + destroy_endpoint_class(); + return retval; error: kfree(ep_dev); - return; + destroy_endpoint_class(); + return retval; } void usb_remove_ep_files(struct usb_host_endpoint *endpoint) diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index 8de4f8c99d6..c376c655c5d 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -55,7 +55,7 @@ static int usb_open(struct inode * inode, struct file * file) return err; } -static struct file_operations usb_fops = { +static const struct file_operations usb_fops = { .owner = THIS_MODULE, .open = usb_open, }; diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c new file mode 100644 index 00000000000..16332cc5794 --- /dev/null +++ b/drivers/usb/core/generic.c @@ -0,0 +1,208 @@ +/* + * drivers/usb/generic.c - generic driver for USB devices (not interfaces) + * + * (C) Copyright 2005 Greg Kroah-Hartman <gregkh@suse.de> + * + * based on drivers/usb/usb.c which had the following copyrights: + * (C) Copyright Linus Torvalds 1999 + * (C) Copyright Johannes Erdfelt 1999-2001 + * (C) Copyright Andreas Gal 1999 + * (C) Copyright Gregory P. Smith 1999 + * (C) Copyright Deti Fliegl 1999 (new USB architecture) + * (C) Copyright Randy Dunlap 2000 + * (C) Copyright David Brownell 2000-2004 + * (C) Copyright Yggdrasil Computing, Inc. 2000 + * (usb_device_id matching changes by Adam J. Richter) + * (C) Copyright Greg Kroah-Hartman 2002-2003 + * + */ + +#include <linux/config.h> +#include <linux/usb.h> +#include "usb.h" + +static inline const char *plural(int n) +{ + return (n == 1 ? "" : "s"); +} + +static int choose_configuration(struct usb_device *udev) +{ + int i; + int num_configs; + int insufficient_power = 0; + struct usb_host_config *c, *best; + + 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; + + /* + * HP's USB bus-powered keyboard has only one configuration + * and it claims to be self-powered; other devices may have + * 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 */ + if (bus_powered && (c->desc.bmAttributes & + USB_CONFIG_ATT_SELFPOWER)) + continue; +#endif + + /* + * The next test may not be as effective as it should be. + * Some hubs have errors in their descriptor, claiming + * to be self-powered when they are really bus-powered. + * We will overestimate the amount of current such hubs + * make available for each port. + * + * This is a fairly benign sort of failure. It won't + * cause us to reject configurations that we should have + * accepted. + */ + + /* Rule out configs that draw too much bus current */ + if (c->desc.bMaxPower * 2 > udev->bus_mA) { + insufficient_power++; + 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 + && desc->bInterfaceSubClass == 2 + && desc->bInterfaceProtocol == 0xff) { +#ifndef CONFIG_USB_NET_RNDIS_HOST + continue; +#else + best = c; +#endif + } + + /* From the remaining configs, choose the first one whose + * first interface is for a non-vendor-specific class. + * Reason: Linux is more likely to have a class driver + * than a vendor-specific driver. */ + else if (udev->descriptor.bDeviceClass != + USB_CLASS_VENDOR_SPEC && + (!desc || desc->bInterfaceClass != + USB_CLASS_VENDOR_SPEC)) { + best = c; + break; + } + + /* If all the remaining configs are vendor-specific, + * choose the first one. */ + else if (!best) + 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, + "configuration #%d chosen from %d choice%s\n", + i, num_configs, plural(num_configs)); + } else { + i = -1; + dev_warn(&udev->dev, + "no configuration chosen from %d choice%s\n", + num_configs, plural(num_configs)); + } + return i; +} + +static int generic_probe(struct usb_device *udev) +{ + int err, c; + + /* put device-specific files into sysfs */ + usb_create_sysfs_dev_files(udev); + + /* Choose and set the configuration. This registers the interfaces + * with the driver core and lets interface drivers bind to them. + */ + c = choose_configuration(udev); + if (c >= 0) { + err = usb_set_configuration(udev, c); + if (err) { + dev_err(&udev->dev, "can't set config #%d, error %d\n", + c, err); + /* This need not be fatal. The user can try to + * set other configurations. */ + } + } + + /* USB device state == configured ... usable */ + usb_notify_add_device(udev); + + return 0; +} + +static void generic_disconnect(struct usb_device *udev) +{ + usb_notify_remove_device(udev); + + /* if this is only an unbind, not a physical disconnect, then + * unconfigure the device */ + if (udev->actconfig) + usb_set_configuration(udev, 0); + + usb_remove_sysfs_dev_files(udev); +} + +#ifdef CONFIG_PM + +static int generic_suspend(struct usb_device *udev, pm_message_t msg) +{ + /* USB devices enter SUSPEND state through their hubs, but can be + * marked for FREEZE as soon as their children are already idled. + * But those semantics are useless, so we equate the two (sigh). + */ + return usb_port_suspend(udev); +} + +static int generic_resume(struct usb_device *udev) +{ + return usb_port_resume(udev); +} + +#endif /* CONFIG_PM */ + +struct usb_device_driver usb_generic_driver = { + .name = "usb", + .probe = generic_probe, + .disconnect = generic_disconnect, +#ifdef CONFIG_PM + .suspend = generic_suspend, + .resume = generic_resume, +#endif + .supports_autosuspend = 1, +}; diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 5078fb3375e..edf4300a3f7 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -281,7 +281,7 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) (void) usb_hcd_pci_resume (dev); } - } else { + } else if (hcd->state != HC_STATE_HALT) { dev_dbg (hcd->self.controller, "hcd state %d; not suspended\n", hcd->state); WARN_ON(1); @@ -413,4 +413,20 @@ EXPORT_SYMBOL (usb_hcd_pci_resume); #endif /* CONFIG_PM */ +/** + * usb_hcd_pci_shutdown - shutdown host controller + * @dev: USB Host Controller being shutdown + */ +void usb_hcd_pci_shutdown (struct pci_dev *dev) +{ + struct usb_hcd *hcd; + + hcd = pci_get_drvdata(dev); + if (!hcd) + return; + + if (hcd->driver->shutdown) + hcd->driver->shutdown(hcd); +} +EXPORT_SYMBOL (usb_hcd_pci_shutdown); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index fb4d058bbde..e86f6295708 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -36,6 +36,7 @@ #include <linux/mutex.h> #include <asm/irq.h> #include <asm/byteorder.h> +#include <linux/platform_device.h> #include <linux/usb.h> @@ -632,31 +633,20 @@ static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) /*-------------------------------------------------------------------------*/ -/* 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. +/* Unlinks of root-hub control URBs are legal, but they don't do anything + * since these URBs always execute synchronously. */ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) { - if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */ - if (in_interrupt()) - return 0; /* nothing to do */ - - spin_lock_irq(&urb->lock); /* from usb_kill_urb */ - ++urb->reject; - spin_unlock_irq(&urb->lock); - - wait_event(usb_kill_urb_queue, - atomic_read(&urb->use_count) == 0); + unsigned long flags; - spin_lock_irq(&urb->lock); - --urb->reject; - spin_unlock_irq(&urb->lock); + if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */ + ; /* Do nothing */ } else { /* Status URB */ if (!hcd->uses_new_polling) - del_timer_sync (&hcd->rh_timer); - local_irq_disable (); + del_timer (&hcd->rh_timer); + local_irq_save (flags); spin_lock (&hcd_root_hub_lock); if (urb == hcd->status_urb) { hcd->status_urb = NULL; @@ -666,7 +656,7 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) spin_unlock (&hcd_root_hub_lock); if (urb) usb_hcd_giveback_urb (hcd, urb, NULL); - local_irq_enable (); + local_irq_restore (flags); } return 0; @@ -674,31 +664,6 @@ 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) -{ - if (bus) - kref_get(&bus->kref); - return bus; -} - -static void usb_host_release(struct kref *kref) -{ - struct usb_bus *bus = container_of(kref, struct usb_bus, kref); - - if (bus->release) - bus->release(bus); -} - -/* exported only within usbcore */ -void usb_bus_put(struct usb_bus *bus) -{ - if (bus) - kref_put(&bus->kref, usb_host_release); -} - -/*-------------------------------------------------------------------------*/ - static struct class *usb_host_class; int usb_host_init(void) @@ -730,39 +695,12 @@ static void usb_bus_init (struct usb_bus *bus) bus->devnum_next = 1; bus->root_hub = NULL; - bus->hcpriv = NULL; bus->busnum = -1; bus->bandwidth_allocated = 0; bus->bandwidth_int_reqs = 0; bus->bandwidth_isoc_reqs = 0; INIT_LIST_HEAD (&bus->bus_list); - - kref_init(&bus->kref); -} - -/** - * usb_alloc_bus - creates a new USB host controller structure - * @op: pointer to a struct usb_operations that this bus structure should use - * Context: !in_interrupt() - * - * Creates a USB host controller bus structure with the specified - * usb_operations and initializes all the necessary internal objects. - * - * If no memory is available, NULL is returned. - * - * The caller should call usb_put_bus() when it is finished with the structure. - */ -struct usb_bus *usb_alloc_bus (struct usb_operations *op) -{ - struct usb_bus *bus; - - bus = kzalloc (sizeof *bus, GFP_KERNEL); - if (!bus) - return NULL; - usb_bus_init (bus); - bus->op = op; - return bus; } /*-------------------------------------------------------------------------*/ @@ -1112,10 +1050,10 @@ static void urb_unlink (struct urb *urb) * expects usb_submit_urb() to have sanity checked and conditioned all * inputs in the urb */ -static int hcd_submit_urb (struct urb *urb, gfp_t mem_flags) +int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) { int status; - struct usb_hcd *hcd = urb->dev->bus->hcpriv; + struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); struct usb_host_endpoint *ep; unsigned long flags; @@ -1186,7 +1124,7 @@ doit: /* lower level hcd code should use *_dma exclusively, * unless it uses pio or talks to another transport. */ - if (hcd->self.controller->dma_mask) { + if (hcd->self.uses_dma) { if (usb_pipecontrol (urb->pipe) && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) urb->setup_dma = dma_map_single ( @@ -1221,9 +1159,10 @@ done: /*-------------------------------------------------------------------------*/ /* called in any context */ -static int hcd_get_frame_number (struct usb_device *udev) +int usb_hcd_get_frame_number (struct usb_device *udev) { - struct usb_hcd *hcd = (struct usb_hcd *)udev->bus->hcpriv; + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + if (!HC_IS_RUNNING (hcd->state)) return -ESHUTDOWN; return hcd->driver->get_frame_number (hcd); @@ -1263,7 +1202,7 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb) * caller guarantees urb won't be recycled till both unlink() * and the urb's completion function return */ -static int hcd_unlink_urb (struct urb *urb, int status) +int usb_hcd_unlink_urb (struct urb *urb, int status) { struct usb_host_endpoint *ep; struct usb_hcd *hcd = NULL; @@ -1296,7 +1235,7 @@ static int hcd_unlink_urb (struct urb *urb, int status) spin_lock (&hcd_data_lock); sys = &urb->dev->dev; - hcd = urb->dev->bus->hcpriv; + hcd = bus_to_hcd(urb->dev->bus); if (hcd == NULL) { retval = -ENODEV; goto done; @@ -1354,41 +1293,33 @@ done: /*-------------------------------------------------------------------------*/ /* disables the endpoint: cancels any pending urbs, then synchronizes with - * the hcd to make sure all endpoint state is gone from hardware. use for + * the hcd to make sure all endpoint state is gone from hardware, and then + * waits until the endpoint's queue is completely drained. use for * set_configuration, set_interface, driver removal, physical disconnect. * * example: a qh stored in ep->hcpriv, holding state related to endpoint * type, maxpacket size, toggle, halt status, and scheduling. */ -static void -hcd_endpoint_disable (struct usb_device *udev, struct usb_host_endpoint *ep) +void usb_hcd_endpoint_disable (struct usb_device *udev, + struct usb_host_endpoint *ep) { struct usb_hcd *hcd; struct urb *urb; - hcd = udev->bus->hcpriv; + hcd = bus_to_hcd(udev->bus); WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT && udev->state != USB_STATE_NOTATTACHED); local_irq_disable (); - /* FIXME move most of this into message.c as part of its - * endpoint disable logic - */ - /* ep is already gone from udev->ep_{in,out}[]; no more submits */ rescan: spin_lock (&hcd_data_lock); list_for_each_entry (urb, &ep->urb_list, urb_list) { int tmp; - /* another cpu may be in hcd, spinning on hcd_data_lock - * to giveback() this urb. the races here should be - * small, but a full fix needs a new "can't submit" - * urb state. - * FIXME urb->reject should allow that... - */ + /* the urb may already have been unlinked */ if (urb->status != -EINPROGRESS) continue; usb_get_urb (urb); @@ -1430,6 +1361,30 @@ rescan: might_sleep (); if (hcd->driver->endpoint_disable) hcd->driver->endpoint_disable (hcd, ep); + + /* Wait until the endpoint queue is completely empty. Most HCDs + * will have done this already in their endpoint_disable method, + * but some might not. And there could be root-hub control URBs + * still pending since they aren't affected by the HCDs' + * endpoint_disable methods. + */ + while (!list_empty (&ep->urb_list)) { + spin_lock_irq (&hcd_data_lock); + + /* The list may have changed while we acquired the spinlock */ + urb = NULL; + if (!list_empty (&ep->urb_list)) { + urb = list_entry (ep->urb_list.prev, struct urb, + urb_list); + usb_get_urb (urb); + } + spin_unlock_irq (&hcd_data_lock); + + if (urb) { + usb_kill_urb (urb); + usb_put_urb (urb); + } + } } /*-------------------------------------------------------------------------*/ @@ -1476,50 +1431,6 @@ int hcd_bus_resume (struct usb_bus *bus) return status; } -/* - * usb_hcd_suspend_root_hub - HCD autosuspends downstream ports - * @hcd: host controller for this root hub - * - * This call arranges that usb_hcd_resume_root_hub() is safe to call later; - * that the HCD's root hub polling is deactivated; and that the root's hub - * driver is suspended. HCDs may call this to autosuspend when their root - * hub's downstream ports are all inactive: unpowered, disconnected, - * disabled, or suspended. - * - * The HCD will autoresume on device connect change detection (using SRP - * or a D+/D- pullup). The HCD also autoresumes on remote wakeup signaling - * from any ports that are suspended (if that is enabled). In most cases, - * overcurrent signaling (on powered ports) will also start autoresume. - * - * Always called with IRQs blocked. - */ -void usb_hcd_suspend_root_hub (struct usb_hcd *hcd) -{ - struct urb *urb; - - spin_lock (&hcd_root_hub_lock); - usb_suspend_root_hub (hcd->self.root_hub); - - /* force status urb to complete/unlink while suspended */ - if (hcd->status_urb) { - urb = hcd->status_urb; - urb->status = -ECONNRESET; - urb->hcpriv = NULL; - urb->actual_length = 0; - - del_timer (&hcd->rh_timer); - hcd->poll_pending = 0; - hcd->status_urb = NULL; - } else - urb = NULL; - spin_unlock (&hcd_root_hub_lock); - hcd->state = HC_STATE_SUSPENDED; - - if (urb) - usb_hcd_giveback_urb (hcd, urb, NULL); -} -EXPORT_SYMBOL_GPL(usb_hcd_suspend_root_hub); - /** * usb_hcd_resume_root_hub - called by HCD to resume its root hub * @hcd: host controller for this root hub @@ -1583,20 +1494,6 @@ EXPORT_SYMBOL (usb_bus_start_enum); /*-------------------------------------------------------------------------*/ -/* - * usb_hcd_operations - adapts usb_bus framework to HCD framework (bus glue) - */ -static struct usb_operations usb_hcd_operations = { - .get_frame_number = hcd_get_frame_number, - .submit_urb = hcd_submit_urb, - .unlink_urb = hcd_unlink_urb, - .buffer_alloc = hcd_buffer_alloc, - .buffer_free = hcd_buffer_free, - .disable = hcd_endpoint_disable, -}; - -/*-------------------------------------------------------------------------*/ - /** * usb_hcd_giveback_urb - return URB from HCD to device driver * @hcd: host controller returning the URB @@ -1617,8 +1514,9 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs at_root_hub = (urb->dev == hcd->self.root_hub); urb_unlink (urb); - /* lower level hcd code should use *_dma exclusively */ - if (hcd->self.controller->dma_mask && !at_root_hub) { + /* lower level hcd code should use *_dma exclusively if the + * host controller does DMA */ + if (hcd->self.uses_dma && !at_root_hub) { if (usb_pipecontrol (urb->pipe) && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) dma_unmap_single (hcd->self.controller, urb->setup_dma, @@ -1704,14 +1602,6 @@ EXPORT_SYMBOL_GPL (usb_hc_died); /*-------------------------------------------------------------------------*/ -static void hcd_release (struct usb_bus *bus) -{ - struct usb_hcd *hcd; - - hcd = container_of(bus, struct usb_hcd, self); - kfree(hcd); -} - /** * usb_create_hcd - create and initialize an HCD structure * @driver: HC driver that will use this hcd @@ -1736,13 +1626,12 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, return NULL; } dev_set_drvdata(dev, hcd); + kref_init(&hcd->kref); usb_bus_init(&hcd->self); - hcd->self.op = &usb_hcd_operations; - hcd->self.hcpriv = hcd; - hcd->self.release = &hcd_release; hcd->self.controller = dev; hcd->self.bus_name = bus_name; + hcd->self.uses_dma = (dev->dma_mask != NULL); init_timer(&hcd->rh_timer); hcd->rh_timer.function = rh_timer_func; @@ -1756,10 +1645,25 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, } EXPORT_SYMBOL (usb_create_hcd); +static void hcd_release (struct kref *kref) +{ + struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref); + + kfree(hcd); +} + +struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd) +{ + if (hcd) + kref_get (&hcd->kref); + return hcd; +} +EXPORT_SYMBOL (usb_get_hcd); + void usb_put_hcd (struct usb_hcd *hcd) { - dev_set_drvdata(hcd->self.controller, NULL); - usb_bus_put(&hcd->self); + if (hcd) + kref_put (&hcd->kref, hcd_release); } EXPORT_SYMBOL (usb_put_hcd); @@ -1915,6 +1819,16 @@ void usb_remove_hcd(struct usb_hcd *hcd) } EXPORT_SYMBOL (usb_remove_hcd); +void +usb_hcd_platform_shutdown(struct platform_device* dev) +{ + struct usb_hcd *hcd = platform_get_drvdata(dev); + + if (hcd->driver->shutdown) + hcd->driver->shutdown(hcd); +} +EXPORT_SYMBOL (usb_hcd_platform_shutdown); + /*-------------------------------------------------------------------------*/ #if defined(CONFIG_USB_MON) diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 7022aafb2ae..676877c15f8 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -55,12 +55,13 @@ /*-------------------------------------------------------------------------*/ -struct usb_hcd { /* usb_bus.hcpriv points to this */ +struct usb_hcd { /* * housekeeping */ struct usb_bus self; /* hcd is-a bus */ + struct kref kref; /* reference counter */ const char *product_desc; /* product/vendor string */ char irq_descr[24]; /* driver + bus # */ @@ -85,6 +86,7 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */ unsigned uses_new_polling:1; unsigned poll_rh:1; /* poll for rh status? */ unsigned poll_pending:1; /* status has changed? */ + unsigned wireless:1; /* Wireless USB HCD */ int irq; /* irq allocated */ void __iomem *regs; /* device memory/io */ @@ -128,8 +130,10 @@ static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd) return &hcd->self; } - -// urb.hcpriv is really hardware-specific +static inline struct usb_hcd *bus_to_hcd (struct usb_bus *bus) +{ + return container_of(bus, struct usb_hcd, self); +} struct hcd_timeout { /* timeouts we allocate */ struct list_head timeout_list; @@ -138,28 +142,6 @@ struct hcd_timeout { /* timeouts we allocate */ /*-------------------------------------------------------------------------*/ -/* - * FIXME usb_operations should vanish or become hc_driver, - * when usb_bus and usb_hcd become the same thing. - */ - -struct usb_operations { - int (*get_frame_number) (struct usb_device *usb_dev); - int (*submit_urb) (struct urb *urb, gfp_t mem_flags); - int (*unlink_urb) (struct urb *urb, int status); - - /* allocate dma-consistent buffer for URB_DMA_NOMAPPING */ - void *(*buffer_alloc)(struct usb_bus *bus, size_t size, - gfp_t mem_flags, - dma_addr_t *dma); - void (*buffer_free)(struct usb_bus *bus, size_t size, - void *addr, dma_addr_t dma); - - void (*disable)(struct usb_device *udev, - struct usb_host_endpoint *ep); -}; - -/* each driver provides one of these, and hardware init support */ struct pt_regs; @@ -192,6 +174,9 @@ struct hc_driver { /* cleanly make HCD stop writing memory and doing I/O */ void (*stop) (struct usb_hcd *hcd); + /* shutdown HCD */ + void (*shutdown) (struct usb_hcd *hcd); + /* return current frame number */ int (*get_frame_number) (struct usb_hcd *hcd); @@ -218,15 +203,25 @@ struct hc_driver { /* 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); +extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags); +extern int usb_hcd_unlink_urb (struct urb *urb, int status); +extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, + struct pt_regs *regs); +extern void usb_hcd_endpoint_disable (struct usb_device *udev, + struct usb_host_endpoint *ep); +extern int usb_hcd_get_frame_number (struct usb_device *udev); extern struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, struct device *dev, char *bus_name); +extern struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd); extern void usb_put_hcd (struct usb_hcd *hcd); extern int usb_add_hcd(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags); extern void usb_remove_hcd(struct usb_hcd *hcd); +struct platform_device; +extern void usb_hcd_platform_shutdown(struct platform_device* dev); + #ifdef CONFIG_PCI struct pci_dev; struct pci_device_id; @@ -239,6 +234,8 @@ extern int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t state); extern int usb_hcd_pci_resume (struct pci_dev *dev); #endif /* CONFIG_PM */ +extern void usb_hcd_pci_shutdown (struct pci_dev *dev); + #endif /* CONFIG_PCI */ /* pci-ish (pdev null is ok) buffer alloc/mapping support */ @@ -352,8 +349,6 @@ extern long usb_calc_bus_time (int speed, int is_input, /*-------------------------------------------------------------------------*/ -extern struct usb_bus *usb_alloc_bus (struct usb_operations *); - extern void usb_set_device_state(struct usb_device *udev, enum usb_device_state new_state); @@ -365,9 +360,6 @@ extern struct list_head usb_bus_list; extern struct mutex usb_bus_list_lock; 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, @@ -376,17 +368,11 @@ extern int usb_find_interface_driver (struct usb_device *dev, #define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN)) #ifdef CONFIG_PM -extern void usb_hcd_suspend_root_hub (struct usb_hcd *hcd); extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd); extern void usb_root_hub_lost_power (struct usb_device *rhdev); extern int hcd_bus_suspend (struct usb_bus *bus); extern int hcd_bus_resume (struct usb_bus *bus); #else -static inline void usb_hcd_suspend_root_hub(struct usb_hcd *hcd) -{ - return; -} - static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd) { return; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 26c8cb5f3e6..2a8cb3c2b19 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -293,7 +293,7 @@ void usb_kick_khubd(struct usb_device *hdev) /* completion function, fires on port status changes and various faults */ static void hub_irq(struct urb *urb, struct pt_regs *regs) { - struct usb_hub *hub = (struct usb_hub *)urb->context; + struct usb_hub *hub = urb->context; int status; int i; unsigned long bits; @@ -311,7 +311,7 @@ static void hub_irq(struct urb *urb, struct pt_regs *regs) goto resubmit; hub->error = urb->status; /* FALL THROUGH */ - + /* let khubd handle things */ case 0: /* we got data: port status changed */ bits = 0; @@ -452,18 +452,14 @@ static void hub_power_on(struct usb_hub *hub) msleep(max(pgood_delay, (unsigned) 100)); } -static inline void __hub_quiesce(struct usb_hub *hub) +static void hub_quiesce(struct usb_hub *hub) { /* (nonblocking) khubd and related activity won't re-trigger */ hub->quiescing = 1; hub->activating = 0; hub->resume_root_hub = 0; -} -static void hub_quiesce(struct usb_hub *hub) -{ /* (blocking) stop khubd and related activity */ - __hub_quiesce(hub); usb_kill_urb(hub->urb); if (hub->has_indicators) cancel_delayed_work(&hub->leds); @@ -868,13 +864,8 @@ descriptor_error: endpoint = &desc->endpoint[0].desc; - /* Output endpoint? Curiouser and curiouser.. */ - if (!(endpoint->bEndpointAddress & USB_DIR_IN)) - goto descriptor_error; - - /* If it's not an interrupt endpoint, we'd better punt! */ - if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - != USB_ENDPOINT_XFER_INT) + /* If it's not an interrupt in endpoint, we'd better punt! */ + if (!usb_endpoint_is_int_in(endpoint)) goto descriptor_error; /* We found a hub */ @@ -1022,26 +1013,29 @@ void usb_set_device_state(struct usb_device *udev, if (udev->state == USB_STATE_NOTATTACHED) ; /* 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) + if (udev->state == USB_STATE_SUSPENDED + || new_state == USB_STATE_SUSPENDED) + ; /* No change to wakeup settings */ + else 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) + else device_init_wakeup(&udev->dev, 0); } + udev->state = new_state; } else recursively_mark_NOTATTACHED(udev); spin_unlock_irqrestore(&device_state_lock, flags); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM /** * usb_root_hub_lost_power - called by HCD if the root hub lost Vbus power @@ -1059,6 +1053,12 @@ void usb_root_hub_lost_power(struct usb_device *rhdev) unsigned long flags; dev_warn(&rhdev->dev, "root hub lost power or was reset\n"); + + /* Make sure no potential wakeup events get lost, + * by forcing the root hub to be resumed. + */ + rhdev->dev.power.prev_state.event = PM_EVENT_ON; + spin_lock_irqsave(&device_state_lock, flags); hub = hdev_to_hub(rhdev); for (port1 = 1; port1 <= rhdev->maxchild; ++port1) { @@ -1072,7 +1072,7 @@ void usb_root_hub_lost_power(struct usb_device *rhdev) } EXPORT_SYMBOL_GPL(usb_root_hub_lost_power); -#endif +#endif /* CONFIG_PM */ static void choose_address(struct usb_device *udev) { @@ -1148,144 +1148,28 @@ void usb_disconnect(struct usb_device **pdev) * cleaning up all state associated with the current configuration * so that the hardware is now fully quiesced. */ + dev_dbg (&udev->dev, "unregistering device\n"); usb_disable_device(udev, 0); - usb_notify_remove_device(udev); + usb_unlock_device(udev); - /* Free the device number, remove the /proc/bus/usb entry and - * the sysfs attributes, and delete the parent's children[] + /* Unregister the device. The device driver is responsible + * for removing the device files from usbfs and sysfs and for + * de-configuring the device. + */ + device_del(&udev->dev); + + /* Free the device number and delete the parent's children[] * (or root_hub) pointer. */ - dev_dbg (&udev->dev, "unregistering device\n"); release_address(udev); - usb_remove_sysfs_dev_files(udev); /* Avoid races with recursively_mark_NOTATTACHED() */ spin_lock_irq(&device_state_lock); *pdev = NULL; spin_unlock_irq(&device_state_lock); - usb_unlock_device(udev); - - device_unregister(&udev->dev); -} - -static inline const char *plural(int n) -{ - return (n == 1 ? "" : "s"); -} - -static int choose_configuration(struct usb_device *udev) -{ - int i; - int num_configs; - int insufficient_power = 0; - struct usb_host_config *c, *best; - - 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; - - /* - * HP's USB bus-powered keyboard has only one configuration - * and it claims to be self-powered; other devices may have - * 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 */ - if (bus_powered && (c->desc.bmAttributes & - USB_CONFIG_ATT_SELFPOWER)) - continue; -#endif - - /* - * The next test may not be as effective as it should be. - * Some hubs have errors in their descriptor, claiming - * to be self-powered when they are really bus-powered. - * We will overestimate the amount of current such hubs - * make available for each port. - * - * This is a fairly benign sort of failure. It won't - * cause us to reject configurations that we should have - * accepted. - */ - - /* Rule out configs that draw too much bus current */ - if (c->desc.bMaxPower * 2 > udev->bus_mA) { - insufficient_power++; - 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 - && desc->bInterfaceSubClass == 2 - && desc->bInterfaceProtocol == 0xff) { -#ifndef CONFIG_USB_NET_RNDIS_HOST - continue; -#else - best = c; -#endif - } - - /* From the remaining configs, choose the first one whose - * first interface is for a non-vendor-specific class. - * Reason: Linux is more likely to have a class driver - * than a vendor-specific driver. */ - else if (udev->descriptor.bDeviceClass != - USB_CLASS_VENDOR_SPEC && - (!desc || desc->bInterfaceClass != - USB_CLASS_VENDOR_SPEC)) { - best = c; - break; - } - - /* If all the remaining configs are vendor-specific, - * choose the first one. */ - else if (!best) - 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, - "configuration #%d chosen from %d choice%s\n", - i, num_configs, plural(num_configs)); - } else { - i = -1; - dev_warn(&udev->dev, - "no configuration chosen from %d choice%s\n", - num_configs, plural(num_configs)); - } - return i; + put_device(&udev->dev); } #ifdef DEBUG @@ -1328,7 +1212,6 @@ static inline void show_string(struct usb_device *udev, char *id, char *string) int usb_new_device(struct usb_device *udev) { int err; - int c; err = usb_get_configuration(udev); if (err < 0) { @@ -1371,8 +1254,7 @@ int usb_new_device(struct usb_device *udev) USB_DT_OTG, (void **) &desc) == 0) { if (desc->bmAttributes & USB_OTG_HNP) { unsigned port1 = udev->portnum; - struct usb_device *root = udev->parent; - + dev_info(&udev->dev, "Dual-Role OTG device on %sHNP port\n", (port1 == bus->otg_port) @@ -1407,9 +1289,9 @@ int usb_new_device(struct usb_device *udev) * (Includes HNP test device.) */ if (udev->bus->b_hnp_enable || udev->bus->is_b_host) { - static int __usb_suspend_device(struct usb_device *, + static int __usb_port_suspend(struct usb_device *, int port1); - err = __usb_suspend_device(udev, udev->bus->otg_port); + err = __usb_port_suspend(udev, udev->bus->otg_port); if (err < 0) dev_dbg(&udev->dev, "HNP fail, %d\n", err); } @@ -1418,34 +1300,15 @@ int usb_new_device(struct usb_device *udev) } #endif - /* put device-specific files into sysfs */ + /* Register the device. The device driver is responsible + * for adding the device files to usbfs and sysfs and for + * configuring the device. + */ err = device_add (&udev->dev); if (err) { dev_err(&udev->dev, "can't device_add, error %d\n", err); goto fail; } - usb_create_sysfs_dev_files (udev); - - usb_lock_device(udev); - - /* choose and set the configuration. that registers the interfaces - * with the driver core, and lets usb device drivers bind to them. - */ - c = choose_configuration(udev); - if (c >= 0) { - err = usb_set_configuration(udev, c); - if (err) { - dev_err(&udev->dev, "can't set config #%d, error %d\n", - c, err); - /* This need not be fatal. The user can try to - * set other configurations. */ - } - } - - /* USB device state == configured ... usable */ - usb_notify_add_device(udev); - - usb_unlock_device(udev); return 0; @@ -1472,6 +1335,18 @@ static int hub_port_status(struct usb_hub *hub, int port1, return ret; } + +/* Returns 1 if @hub is a WUSB root hub, 0 otherwise */ +static unsigned hub_is_wusb(struct usb_hub *hub) +{ + struct usb_hcd *hcd; + if (hub->hdev->parent != NULL) /* not a root hub? */ + return 0; + hcd = container_of(hub->hdev->bus, struct usb_hcd, self); + return hcd->wireless; +} + + #define PORT_RESET_TRIES 5 #define SET_ADDRESS_TRIES 2 #define GET_DESCRIPTOR_TRIES 2 @@ -1512,7 +1387,9 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, /* if we`ve finished resetting, then break out of the loop */ if (!(portstatus & USB_PORT_STAT_RESET) && (portstatus & USB_PORT_STAT_ENABLE)) { - if (portstatus & USB_PORT_STAT_HIGH_SPEED) + if (hub_is_wusb(hub)) + udev->speed = USB_SPEED_VARIABLE; + else if (portstatus & USB_PORT_STAT_HIGH_SPEED) udev->speed = USB_SPEED_HIGH; else if (portstatus & USB_PORT_STAT_LOW_SPEED) udev->speed = USB_SPEED_LOW; @@ -1607,6 +1484,7 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1) kick_khubd(hub); } +#ifdef CONFIG_PM #ifdef CONFIG_USB_SUSPEND @@ -1633,7 +1511,7 @@ static int hub_port_suspend(struct usb_hub *hub, int port1, * NOTE: OTG devices may issue remote wakeup (or SRP) even when * we don't explicitly enable it here. */ - if (device_may_wakeup(&udev->dev)) { + if (udev->do_remote_wakeup) { status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), USB_REQ_SET_FEATURE, USB_RECIP_DEVICE, USB_DEVICE_REMOTE_WAKEUP, 0, @@ -1659,7 +1537,8 @@ static int hub_port_suspend(struct usb_hub *hub, int port1, USB_CTRL_SET_TIMEOUT); } else { /* device has up to 10 msec to fully suspend */ - dev_dbg(&udev->dev, "usb suspend\n"); + dev_dbg(&udev->dev, "usb %ssuspend\n", + udev->auto_pm ? "auto-" : ""); usb_set_device_state(udev, USB_STATE_SUSPENDED); msleep(10); } @@ -1684,7 +1563,7 @@ static int hub_port_suspend(struct usb_hub *hub, int port1, * the root hub for their bus goes into global suspend ... so we don't * (falsely) update the device power state to say it suspended. */ -static int __usb_suspend_device (struct usb_device *udev, int port1) +static int __usb_port_suspend (struct usb_device *udev, int port1) { int status = 0; @@ -1692,49 +1571,29 @@ static int __usb_suspend_device (struct usb_device *udev, int port1) if (port1 < 0) return port1; - if (udev->state == USB_STATE_SUSPENDED - || udev->state == USB_STATE_NOTATTACHED) { - return 0; - } - - /* all interfaces must already be suspended */ - if (udev->actconfig) { - int i; - - for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { - struct usb_interface *intf; - - intf = udev->actconfig->interface[i]; - if (is_active(intf)) { - dev_dbg(&intf->dev, "nyet suspended\n"); - return -EBUSY; - } - } - } - - /* we only change a device's upstream USB link. - * root hubs have no upstream USB link. + /* we change the device's upstream USB link, + * but root hubs have no upstream USB link. */ if (udev->parent) status = hub_port_suspend(hdev_to_hub(udev->parent), port1, udev); - - if (status == 0) - udev->dev.power.power_state = PMSG_SUSPEND; + else { + dev_dbg(&udev->dev, "usb %ssuspend\n", + udev->auto_pm ? "auto-" : ""); + usb_set_device_state(udev, USB_STATE_SUSPENDED); + } return status; } -#endif - /* - * usb_suspend_device - suspend a usb device + * usb_port_suspend - suspend a usb device's upstream port * @udev: device that's no longer in active use * Context: must be able to sleep; device not locked; pm locks held * * Suspends a USB device that isn't in active use, conserving power. * Devices may wake out of a suspend, if anything important happens, * using the remote wakeup mechanism. They may also be taken out of - * suspend by the host, using usb_resume_device(). It's also routine + * suspend by the host, using usb_port_resume(). It's also routine * to disconnect devices while they are suspended. * * This only affects the USB hardware for a device; its interfaces @@ -1746,17 +1605,9 @@ static int __usb_suspend_device (struct usb_device *udev, int port1) * * Returns 0 on success, else negative errno. */ -int usb_suspend_device(struct usb_device *udev) +int usb_port_suspend(struct usb_device *udev) { -#ifdef CONFIG_USB_SUSPEND - if (udev->state == USB_STATE_NOTATTACHED) - return -ENODEV; - return __usb_suspend_device(udev, udev->portnum); -#else - /* NOTE: udev->state unchanged, it's not lying ... */ - udev->dev.power.power_state = PMSG_SUSPEND; - return 0; -#endif + return __usb_port_suspend(udev, udev->portnum); } /* @@ -1767,7 +1618,7 @@ int usb_suspend_device(struct usb_device *udev) * resume (by host) or remote wakeup (by device) ... now see what changed * in the tree that's rooted at this device. */ -static int finish_device_resume(struct usb_device *udev) +static int finish_port_resume(struct usb_device *udev) { int status; u16 devstatus; @@ -1783,7 +1634,6 @@ static int finish_device_resume(struct usb_device *udev) usb_set_device_state(udev, udev->actconfig ? USB_STATE_CONFIGURED : USB_STATE_ADDRESS); - udev->dev.power.power_state = PMSG_ON; /* 10.5.4.5 says be sure devices in the tree are still there. * For now let's assume the device didn't go crazy on resume, @@ -1798,9 +1648,6 @@ static int finish_device_resume(struct usb_device *udev) "gone after usb resume? status %d\n", status); else if (udev->actconfig) { - unsigned i; - int (*resume)(struct device *); - le16_to_cpus(&devstatus); if ((devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) && udev->parent) { @@ -1811,24 +1658,9 @@ static int finish_device_resume(struct usb_device *udev) USB_DEVICE_REMOTE_WAKEUP, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); - if (status) { + if (status) dev_dbg(&udev->dev, "disable remote " "wakeup, status %d\n", status); - status = 0; - } - } - - /* resume interface drivers; if this is a hub, it - * may have a child resume event to deal with soon - */ - resume = udev->dev.bus->resume; - for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { - struct device *dev = - &udev->actconfig->interface[i]->dev; - - down(&dev->sem); - (void) resume(dev); - up(&dev->sem); } status = 0; @@ -1839,8 +1671,6 @@ static int finish_device_resume(struct usb_device *udev) return status; } -#ifdef CONFIG_USB_SUSPEND - static int hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) { @@ -1848,6 +1678,8 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) // dev_dbg(hub->intfdev, "resume port %d\n", port1); + set_bit(port1, hub->busy_bits); + /* see 7.1.7.7; affects power usage, but not budgeting */ status = clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_SUSPEND); @@ -1861,7 +1693,8 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) /* drive resume for at least 20 msec */ if (udev) - dev_dbg(&udev->dev, "RESUME\n"); + dev_dbg(&udev->dev, "usb %sresume\n", + udev->auto_pm ? "auto-" : ""); msleep(25); #define LIVE_FLAGS ( USB_PORT_STAT_POWER \ @@ -1891,19 +1724,21 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) /* TRSMRCY = 10 msec */ msleep(10); if (udev) - status = finish_device_resume(udev); + status = finish_port_resume(udev); } } if (status < 0) hub_port_logical_disconnect(hub, port1); + clear_bit(port1, hub->busy_bits); + if (!hub->hdev->parent && !hub->busy_bits[0]) + usb_enable_root_hub_irq(hub->hdev->bus); + return status; } -#endif - /* - * usb_resume_device - re-activate a suspended usb device + * usb_port_resume - re-activate a suspended usb device's upstream port * @udev: device to re-activate * Context: must be able to sleep; device not locked; pm locks held * @@ -1915,36 +1750,24 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) * * Returns 0 on success, else negative errno. */ -int usb_resume_device(struct usb_device *udev) +int usb_port_resume(struct usb_device *udev) { int status; - if (udev->state == USB_STATE_NOTATTACHED) - return -ENODEV; - - /* selective resume of one downstream hub-to-device port */ + /* we change the device's upstream USB link, + * but root hubs have no upstream USB link. + */ 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 - status = finish_device_resume(udev); - if (status < 0) - dev_dbg(&udev->dev, "can't resume, status %d\n", - status); - - /* rebind drivers that had no suspend() */ - if (status == 0) { - usb_unlock_device(udev); - bus_rescan_devices(&usb_bus_type); - usb_lock_device(udev); + // NOTE this fails if parent is also suspended... + status = hub_port_resume(hdev_to_hub(udev->parent), + udev->portnum, udev); + } else { + dev_dbg(&udev->dev, "usb %sresume\n", + udev->auto_pm ? "auto-" : ""); + status = finish_port_resume(udev); } + if (status < 0) + dev_dbg(&udev->dev, "can't resume, status %d\n", status); return status; } @@ -1952,23 +1775,60 @@ static int remote_wakeup(struct usb_device *udev) { int status = 0; -#ifdef CONFIG_USB_SUSPEND + /* All this just to avoid sending a port-resume message + * to the parent hub! */ - /* don't repeat RESUME sequence if this device - * was already woken up by some other task - */ usb_lock_device(udev); + mutex_lock_nested(&udev->pm_mutex, udev->level); if (udev->state == USB_STATE_SUSPENDED) { - dev_dbg(&udev->dev, "RESUME (wakeup)\n"); + dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-"); /* TRSMRCY = 10 msec */ msleep(10); - status = finish_device_resume(udev); + status = finish_port_resume(udev); + if (status == 0) + udev->dev.power.power_state.event = PM_EVENT_ON; } + mutex_unlock(&udev->pm_mutex); + + if (status == 0) + usb_autoresume_device(udev, 0); usb_unlock_device(udev); -#endif return status; } +#else /* CONFIG_USB_SUSPEND */ + +/* When CONFIG_USB_SUSPEND isn't set, we never suspend or resume any ports. */ + +int usb_port_suspend(struct usb_device *udev) +{ + return 0; +} + +static inline int +finish_port_resume(struct usb_device *udev) +{ + return 0; +} + +static inline int +hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) +{ + return 0; +} + +int usb_port_resume(struct usb_device *udev) +{ + return 0; +} + +static inline int remote_wakeup(struct usb_device *udev) +{ + return 0; +} + +#endif + static int hub_suspend(struct usb_interface *intf, pm_message_t msg) { struct usb_hub *hub = usb_get_intfdata (intf); @@ -1980,13 +1840,17 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) struct usb_device *udev; udev = hdev->children [port1-1]; - if (udev && (udev->dev.power.power_state.event - == PM_EVENT_ON + if (udev && msg.event == PM_EVENT_SUSPEND && #ifdef CONFIG_USB_SUSPEND - || udev->state != USB_STATE_SUSPENDED + udev->state != USB_STATE_SUSPENDED +#else + udev->dev.power.power_state.event + == PM_EVENT_ON #endif - )) { - dev_dbg(&intf->dev, "port %d nyet suspended\n", port1); + ) { + if (!hdev->auto_pm) + dev_dbg(&intf->dev, "port %d nyet suspended\n", + port1); return -EBUSY; } } @@ -2035,66 +1899,22 @@ static int hub_resume(struct usb_interface *intf) } } + /* tell khubd to look for changes on this hub */ hub_activate(hub); - - /* REVISIT: this recursion probably shouldn't exist. Remove - * this code sometime, after retesting with different root and - * external hubs. - */ -#ifdef CONFIG_USB_SUSPEND - { - unsigned port1; - - for (port1 = 1; port1 <= hdev->maxchild; port1++) { - struct usb_device *udev; - u16 portstat, portchange; - - udev = hdev->children [port1-1]; - status = hub_port_status(hub, port1, &portstat, &portchange); - if (status == 0) { - if (portchange & USB_PORT_STAT_C_SUSPEND) { - clear_port_feature(hdev, port1, - USB_PORT_FEAT_C_SUSPEND); - portchange &= ~USB_PORT_STAT_C_SUSPEND; - } - - /* let khubd handle disconnects etc */ - if (portchange) - continue; - } - - if (!udev || status < 0) - continue; - usb_lock_device(udev); - if (portstat & USB_PORT_STAT_SUSPEND) - status = hub_port_resume(hub, port1, udev); - else { - status = finish_device_resume(udev); - if (status < 0) { - dev_dbg(&intf->dev, "resume port %d --> %d\n", - port1, status); - hub_port_logical_disconnect(hub, port1); - } - } - usb_unlock_device(udev); - } - } -#endif return 0; } -void usb_suspend_root_hub(struct usb_device *hdev) -{ - struct usb_hub *hub = hdev_to_hub(hdev); +#else /* CONFIG_PM */ - /* This also makes any led blinker stop retriggering. We're called - * from irq, so the blinker might still be scheduled. Caller promises - * that the root hub status URB will be canceled. - */ - __hub_quiesce(hub); - mark_quiesced(to_usb_interface(hub->intfdev)); +static inline int remote_wakeup(struct usb_device *udev) +{ + return 0; } +#define hub_suspend NULL +#define hub_resume NULL +#endif + void usb_resume_root_hub(struct usb_device *hdev) { struct usb_hub *hub = hdev_to_hub(hdev); @@ -2214,6 +2034,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, int i, j, retval; unsigned delay = HUB_SHORT_RESET_TIME; enum usb_device_speed oldspeed = udev->speed; + char *speed, *type; /* root hub ports have a slightly longer reset period * (from USB 2.0 spec, section 7.1.7.5) @@ -2246,8 +2067,13 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ... * it's fixed size except for full speed devices. + * For Wireless USB devices, ep0 max packet is always 512 (tho + * reported as 0xff in the device descriptor). WUSB1.0[4.8.1]. */ switch (udev->speed) { + case USB_SPEED_VARIABLE: /* fixed at 512 */ + udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(512); + break; case USB_SPEED_HIGH: /* fixed at 64 */ udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64); break; @@ -2265,17 +2091,21 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, goto fail; } + type = ""; + switch (udev->speed) { + case USB_SPEED_LOW: speed = "low"; break; + case USB_SPEED_FULL: speed = "full"; break; + case USB_SPEED_HIGH: speed = "high"; break; + case USB_SPEED_VARIABLE: + speed = "variable"; + type = "Wireless "; + break; + default: speed = "?"; break; + } dev_info (&udev->dev, - "%s %s speed USB device using %s and address %d\n", - (udev->config) ? "reset" : "new", - ({ char *speed; switch (udev->speed) { - case USB_SPEED_LOW: speed = "low"; break; - case USB_SPEED_FULL: speed = "full"; break; - case USB_SPEED_HIGH: speed = "high"; break; - default: speed = "?"; break; - }; speed;}), - udev->bus->controller->driver->name, - udev->devnum); + "%s %s speed %sUSB device using %s and address %d\n", + (udev->config) ? "reset" : "new", speed, type, + udev->bus->controller->driver->name, udev->devnum); /* Set up TT records, if needed */ if (hdev->tt) { @@ -2317,6 +2147,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, * down tremendously by NAKing the unexpectedly * early status stage. Also, retry on all errors; * some devices are flakey. + * 255 is for WUSB devices, we actually need to use 512. + * WUSB1.0[4.8.1]. */ for (j = 0; j < 3; ++j) { buf->bMaxPacketSize0 = 0; @@ -2326,7 +2158,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, buf, GET_DESCRIPTOR_BUFSIZE, (i ? USB_CTRL_GET_TIMEOUT : 1000)); switch (buf->bMaxPacketSize0) { - case 8: case 16: case 32: case 64: + case 8: case 16: case 32: case 64: case 255: if (buf->bDescriptorType == USB_DT_DEVICE) { r = 0; @@ -2400,7 +2232,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, if (retval) goto fail; - i = udev->descriptor.bMaxPacketSize0; + i = udev->descriptor.bMaxPacketSize0 == 0xff? + 512 : udev->descriptor.bMaxPacketSize0; if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) { if (udev->speed != USB_SPEED_FULL || !(i == 8 || i == 16 || i == 32 || i == 64)) { @@ -2585,6 +2418,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, usb_set_device_state(udev, USB_STATE_POWERED); udev->speed = USB_SPEED_UNKNOWN; udev->bus_mA = hub->mA_per_port; + udev->level = hdev->level + 1; /* set the address */ choose_address(udev); @@ -2736,17 +2570,6 @@ static void hub_events(void) usb_get_intf(intf); spin_unlock_irq(&hub_event_lock); - /* Is this is a root hub wanting to reactivate the downstream - * ports? If so, be sure the interface resumes even if its - * stub "device" node was never suspended. - */ - if (i) { - dpm_runtime_resume(&hdev->dev); - dpm_runtime_resume(&intf->dev); - usb_put_intf(intf); - continue; - } - /* Lock the device, then check to see if we were * disconnected while waiting for the lock to succeed. */ if (locktree(hdev) < 0) { @@ -2763,6 +2586,13 @@ static void hub_events(void) goto loop; } + /* Is this is a root hub wanting to reactivate the downstream + * ports? If so, be sure the interface resumes even if its + * stub "device" node was never suspended. + */ + if (i) + usb_autoresume_device(hdev, 0); + /* If this is an inactive or suspended hub, do nothing */ if (hub->quiescing) goto loop; @@ -2900,7 +2730,7 @@ static void hub_events(void) /* If this is a root hub, tell the HCD it's okay to * re-enable port-change interrupts now. */ - if (!hdev->parent) + if (!hdev->parent && !hub->busy_bits[0]) usb_enable_root_hub_irq(hdev->bus); loop: @@ -3075,6 +2905,9 @@ int usb_reset_device(struct usb_device *udev) break; } clear_bit(port1, parent_hub->busy_bits); + if (!parent_hdev->parent && !parent_hub->busy_bits[0]) + usb_enable_root_hub_irq(parent_hdev->bus); + if (ret < 0) goto re_enumerate; @@ -3128,6 +2961,7 @@ re_enumerate: hub_port_logical_disconnect(parent_hub, port1); return -ENODEV; } +EXPORT_SYMBOL(usb_reset_device); /** * usb_reset_composite_device - warn interface drivers and perform a USB port reset @@ -3163,6 +2997,9 @@ int usb_reset_composite_device(struct usb_device *udev, return -EINVAL; } + /* Prevent autosuspend during the reset */ + usb_autoresume_device(udev, 1); + if (iface && iface->condition != USB_INTERFACE_BINDING) iface = NULL; @@ -3204,5 +3041,7 @@ int usb_reset_composite_device(struct usb_device *udev, } } + usb_autosuspend_device(udev, 1); return ret; } +EXPORT_SYMBOL(usb_reset_composite_device); diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 29d5f45a845..0f8e82a4d48 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -212,7 +212,8 @@ struct usb_hub { unsigned long event_bits[1]; /* status change bitmask */ unsigned long change_bits[1]; /* ports with logical connect status change */ - unsigned long busy_bits[1]; /* ports being reset */ + unsigned long busy_bits[1]; /* ports being reset or + resumed */ #if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */ #error event_bits[] is too short! #endif diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index 3182c2224ba..df3d152f049 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -44,7 +44,7 @@ #include "hcd.h" static struct super_operations usbfs_ops; -static struct file_operations default_file_operations; +static const struct file_operations default_file_operations; static struct vfsmount *usbfs_mount; static int usbfs_mount_count; /* = 0 */ static int ignore_mount = 0; @@ -249,7 +249,6 @@ static struct inode *usbfs_get_inode (struct super_block *sb, int mode, dev_t de inode->i_mode = mode; inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; switch (mode & S_IFMT) { @@ -402,13 +401,13 @@ static loff_t default_file_lseek (struct file *file, loff_t offset, int orig) static int default_open (struct inode *inode, struct file *file) { - if (inode->u.generic_ip) - file->private_data = inode->u.generic_ip; + if (inode->i_private) + file->private_data = inode->i_private; return 0; } -static struct file_operations default_file_operations = { +static const struct file_operations default_file_operations = { .read = default_read_file, .write = default_write_file, .open = default_open, @@ -495,7 +494,7 @@ static int fs_create_by_name (const char *name, mode_t mode, static struct dentry *fs_create_file (const char *name, mode_t mode, struct dentry *parent, void *data, - struct file_operations *fops, + const struct file_operations *fops, uid_t uid, gid_t gid) { struct dentry *dentry; @@ -509,7 +508,7 @@ static struct dentry *fs_create_file (const char *name, mode_t mode, } else { if (dentry->d_inode) { if (data) - dentry->d_inode->u.generic_ip = data; + dentry->d_inode->i_private = data; if (fops) dentry->d_inode->i_fop = fops; dentry->d_inode->i_uid = uid; diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 4cc8d3e67db..85b1cd18336 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -23,59 +23,44 @@ static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs) } -static void timeout_kill(unsigned long data) -{ - struct urb *urb = (struct urb *) data; - - usb_unlink_urb(urb); -} - -// Starts urb and waits for completion or timeout -// note that this call is NOT interruptible, while -// many device driver i/o requests should be interruptible -static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length) +/* + * Starts urb and waits for completion or timeout. Note that this call + * is NOT interruptible. Many device driver i/o requests should be + * interruptible and therefore these drivers should implement their + * own interruptible routines. + */ +static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length) { - struct completion done; - struct timer_list timer; - int status; + struct completion done; + unsigned long expire; + int status; init_completion(&done); urb->context = &done; urb->actual_length = 0; status = usb_submit_urb(urb, GFP_NOIO); - - if (status == 0) { - if (timeout > 0) { - init_timer(&timer); - timer.expires = jiffies + msecs_to_jiffies(timeout); - timer.data = (unsigned long)urb; - timer.function = timeout_kill; - /* grr. timeout _should_ include submit delays. */ - add_timer(&timer); - } - wait_for_completion(&done); + if (unlikely(status)) + goto out; + + expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT; + if (!wait_for_completion_timeout(&done, expire)) { + + dev_dbg(&urb->dev->dev, + "%s timed out on ep%d%s len=%d/%d\n", + current->comm, + usb_pipeendpoint(urb->pipe), + usb_pipein(urb->pipe) ? "in" : "out", + urb->actual_length, + urb->transfer_buffer_length); + + usb_kill_urb(urb); + status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status; + } else status = urb->status; - /* note: HCDs return ETIMEDOUT for other reasons too */ - if (status == -ECONNRESET) { - dev_dbg(&urb->dev->dev, - "%s timed out on ep%d%s len=%d/%d\n", - current->comm, - usb_pipeendpoint(urb->pipe), - usb_pipein(urb->pipe) ? "in" : "out", - urb->actual_length, - urb->transfer_buffer_length - ); - if (urb->actual_length > 0) - status = 0; - else - status = -ETIMEDOUT; - } - if (timeout > 0) - del_timer_sync(&timer); - } - +out: if (actual_length) *actual_length = urb->actual_length; + usb_free_urb(urb); return status; } @@ -263,7 +248,7 @@ static void sg_clean (struct usb_sg_request *io) static void sg_complete (struct urb *urb, struct pt_regs *regs) { - struct usb_sg_request *io = (struct usb_sg_request *) urb->context; + struct usb_sg_request *io = urb->context; spin_lock (&io->lock); @@ -999,8 +984,8 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr) ep = dev->ep_in[epnum]; dev->ep_in[epnum] = NULL; } - if (ep && dev->bus && dev->bus->op && dev->bus->op->disable) - dev->bus->op->disable(dev, ep); + if (ep && dev->bus) + usb_hcd_endpoint_disable(dev, ep); } /** @@ -1381,9 +1366,6 @@ int usb_set_configuration(struct usb_device *dev, int configuration) if (cp && configuration == 0) dev_warn(&dev->dev, "config 0 descriptor??\n"); - if (dev->state == USB_STATE_SUSPENDED) - return -EHOSTUNREACH; - /* Allocate memory for new interfaces before doing anything else, * so that if we run out then nothing will have changed. */ n = nintf = 0; @@ -1418,6 +1400,11 @@ free_interfaces: configuration, -i); } + /* Wake up the device so we can send it the Set-Config request */ + ret = usb_autoresume_device(dev, 1); + if (ret) + goto free_interfaces; + /* if it's already configured, clear out old state first. * getting rid of old interfaces means unbinding their drivers. */ @@ -1437,6 +1424,7 @@ free_interfaces: dev->actconfig = cp; if (!cp) { usb_set_device_state(dev, USB_STATE_ADDRESS); + usb_autosuspend_device(dev, 1); goto free_interfaces; } usb_set_device_state(dev, USB_STATE_CONFIGURED); @@ -1505,8 +1493,68 @@ free_interfaces: usb_create_sysfs_intf_files (intf); } + usb_autosuspend_device(dev, 1); + return 0; +} + +struct set_config_request { + struct usb_device *udev; + int config; + struct work_struct work; +}; + +/* Worker routine for usb_driver_set_configuration() */ +static void driver_set_config_work(void *_req) +{ + struct set_config_request *req = _req; + + usb_lock_device(req->udev); + usb_set_configuration(req->udev, req->config); + usb_unlock_device(req->udev); + usb_put_dev(req->udev); + kfree(req); +} + +/** + * usb_driver_set_configuration - Provide a way for drivers to change device configurations + * @udev: the device whose configuration is being updated + * @config: the configuration being chosen. + * Context: In process context, must be able to sleep + * + * Device interface drivers are not allowed to change device configurations. + * This is because changing configurations will destroy the interface the + * driver is bound to and create new ones; it would be like a floppy-disk + * driver telling the computer to replace the floppy-disk drive with a + * tape drive! + * + * Still, in certain specialized circumstances the need may arise. This + * routine gets around the normal restrictions by using a work thread to + * submit the change-config request. + * + * Returns 0 if the request was succesfully queued, error code otherwise. + * The caller has no way to know whether the queued request will eventually + * succeed. + */ +int usb_driver_set_configuration(struct usb_device *udev, int config) +{ + struct set_config_request *req; + + req = kmalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + req->udev = udev; + req->config = config; + INIT_WORK(&req->work, driver_set_config_work, req); + + usb_get_dev(udev); + if (!schedule_work(&req->work)) { + usb_put_dev(udev); + kfree(req); + return -EINVAL; + } return 0; } +EXPORT_SYMBOL_GPL(usb_driver_set_configuration); // synchronous request completion model EXPORT_SYMBOL(usb_control_msg); diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c index b042676af0a..6b36897ca15 100644 --- a/drivers/usb/core/notify.c +++ b/drivers/usb/core/notify.c @@ -50,8 +50,11 @@ void usb_notify_add_device(struct usb_device *udev) void usb_notify_remove_device(struct usb_device *udev) { + /* Protect against simultaneous usbfs open */ + mutex_lock(&usbfs_mutex); blocking_notifier_call_chain(&usb_notifier_list, USB_DEVICE_REMOVE, udev); + mutex_unlock(&usbfs_mutex); } void usb_notify_add_bus(struct usb_bus *ubus) diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index dec973affb0..55d8f575206 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -60,7 +60,7 @@ static ssize_t set_bConfigurationValue (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct usb_device *udev = udev = to_usb_device (dev); + struct usb_device *udev = to_usb_device (dev); int config, value; if (sscanf (buf, "%u", &config) != 1 || config > 255) @@ -186,6 +186,7 @@ usb_descriptor_attr (bMaxPacketSize0, "%d\n") static struct attribute *dev_attrs[] = { /* current configuration's attributes */ + &dev_attr_configuration.attr, &dev_attr_bNumInterfaces.attr, &dev_attr_bConfigurationValue.attr, &dev_attr_bmAttributes.attr, @@ -209,20 +210,40 @@ static struct attribute_group dev_attr_grp = { .attrs = dev_attrs, }; -void usb_create_sysfs_dev_files (struct usb_device *udev) +int usb_create_sysfs_dev_files(struct usb_device *udev) { struct device *dev = &udev->dev; + int retval; - sysfs_create_group(&dev->kobj, &dev_attr_grp); + retval = sysfs_create_group(&dev->kobj, &dev_attr_grp); + if (retval) + return retval; - if (udev->manufacturer) - device_create_file (dev, &dev_attr_manufacturer); - if (udev->product) - device_create_file (dev, &dev_attr_product); - if (udev->serial) - device_create_file (dev, &dev_attr_serial); - device_create_file (dev, &dev_attr_configuration); - usb_create_ep_files(dev, &udev->ep0, udev); + if (udev->manufacturer) { + retval = device_create_file (dev, &dev_attr_manufacturer); + if (retval) + goto error; + } + if (udev->product) { + retval = device_create_file (dev, &dev_attr_product); + if (retval) + goto error; + } + if (udev->serial) { + retval = device_create_file (dev, &dev_attr_serial); + if (retval) + goto error; + } + retval = usb_create_ep_files(dev, &udev->ep0, udev); + if (retval) + goto error; + return 0; +error: + usb_remove_ep_files(&udev->ep0); + device_remove_file(dev, &dev_attr_manufacturer); + device_remove_file(dev, &dev_attr_product); + device_remove_file(dev, &dev_attr_serial); + return retval; } void usb_remove_sysfs_dev_files (struct usb_device *udev) @@ -238,7 +259,6 @@ void usb_remove_sysfs_dev_files (struct usb_device *udev) device_remove_file(dev, &dev_attr_product); if (udev->serial) device_remove_file(dev, &dev_attr_serial); - device_remove_file (dev, &dev_attr_configuration); } /* Interface fields */ @@ -340,18 +360,28 @@ static inline void usb_remove_intf_ep_files(struct usb_interface *intf) usb_remove_ep_files(&iface_desc->endpoint[i]); } -void usb_create_sysfs_intf_files (struct usb_interface *intf) +int usb_create_sysfs_intf_files(struct usb_interface *intf) { struct usb_device *udev = interface_to_usbdev(intf); struct usb_host_interface *alt = intf->cur_altsetting; + int retval; - sysfs_create_group(&intf->dev.kobj, &intf_attr_grp); + retval = sysfs_create_group(&intf->dev.kobj, &intf_attr_grp); + if (retval) + goto error; if (alt->string == NULL) alt->string = usb_cache_string(udev, alt->desc.iInterface); if (alt->string) - device_create_file(&intf->dev, &dev_attr_interface); + retval = device_create_file(&intf->dev, &dev_attr_interface); usb_create_intf_ep_files(intf, udev); + return 0; +error: + if (alt->string) + device_remove_file(&intf->dev, &dev_attr_interface); + sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp); + usb_remove_intf_ep_files(intf); + return retval; } void usb_remove_sysfs_intf_files (struct usb_interface *intf) diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 9864988377c..9801d08edac 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -57,7 +57,7 @@ struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags) { struct urb *urb; - urb = (struct urb *)kmalloc(sizeof(struct urb) + + urb = kmalloc(sizeof(struct urb) + iso_packets * sizeof(struct usb_iso_packet_descriptor), mem_flags); if (!urb) { @@ -221,7 +221,6 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) { int pipe, temp, max; struct usb_device *dev; - struct usb_operations *op; int is_out; if (!urb || urb->hcpriv || !urb->complete) @@ -233,8 +232,6 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) if (dev->bus->controller->power.power_state.event != PM_EVENT_ON || dev->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; - if (!(op = dev->bus->op) || !op->submit_urb) - return -ENODEV; urb->status = -EINPROGRESS; urb->actual_length = 0; @@ -376,7 +373,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) urb->interval = temp; } - return op->submit_urb (urb, mem_flags); + return usb_hcd_submit_urb (urb, mem_flags); } /*-------------------------------------------------------------------*/ @@ -440,9 +437,9 @@ int usb_unlink_urb(struct urb *urb) { if (!urb) return -EINVAL; - if (!(urb->dev && urb->dev->bus && urb->dev->bus->op)) + if (!(urb->dev && urb->dev->bus)) return -ENODEV; - return urb->dev->bus->op->unlink_urb(urb, -ECONNRESET); + return usb_hcd_unlink_urb(urb, -ECONNRESET); } /** @@ -468,13 +465,13 @@ int usb_unlink_urb(struct urb *urb) void usb_kill_urb(struct urb *urb) { might_sleep(); - if (!(urb && urb->dev && urb->dev->bus && urb->dev->bus->op)) + if (!(urb && urb->dev && urb->dev->bus)) return; spin_lock_irq(&urb->lock); ++urb->reject; spin_unlock_irq(&urb->lock); - urb->dev->bus->op->unlink_urb(urb, -ENOENT); + usb_hcd_unlink_urb(urb, -ENOENT); wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0); spin_lock_irq(&urb->lock); diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 184c24660a4..60ef4ef0101 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -67,7 +67,8 @@ static int nousb; /* Disable USB when built into kernel image */ * Don't call this function unless you are bound to one of the interfaces * on this device or you have locked the device! */ -struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum) +struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev, + unsigned ifnum) { struct usb_host_config *config = dev->actconfig; int i; @@ -100,8 +101,8 @@ struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum) * Don't call this function unless you are bound to the intf interface * or you have locked the device! */ -struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf, - unsigned int altnum) +struct usb_host_interface *usb_altnum_to_altsetting(const struct usb_interface *intf, + unsigned int altnum) { int i; @@ -112,87 +113,6 @@ struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf, return NULL; } -/** - * usb_driver_claim_interface - bind a driver to an interface - * @driver: the driver to be bound - * @iface: the interface to which it will be bound; must be in the - * usb device's active configuration - * @priv: driver data associated with that interface - * - * This is used by usb device drivers that need to claim more than one - * interface on a device when probing (audio and acm are current examples). - * No device driver should directly modify internal usb_interface or - * usb_device structure members. - * - * Few drivers should need to use this routine, since the most natural - * way to bind to an interface is to return the private data from - * the driver's probe() method. - * - * Callers must own the device lock and the driver model's usb_bus_type.subsys - * writelock. So driver probe() entries don't need extra locking, - * but other call contexts may need to explicitly claim those locks. - */ -int usb_driver_claim_interface(struct usb_driver *driver, - struct usb_interface *iface, void* priv) -{ - struct device *dev = &iface->dev; - - if (dev->driver) - return -EBUSY; - - dev->driver = &driver->driver; - usb_set_intfdata(iface, priv); - iface->condition = USB_INTERFACE_BOUND; - mark_active(iface); - - /* if interface was already added, bind now; else let - * the future device_add() bind it, bypassing probe() - */ - if (device_is_registered(dev)) - device_bind_driver(dev); - - return 0; -} - -/** - * usb_driver_release_interface - unbind a driver from an interface - * @driver: the driver to be unbound - * @iface: the interface from which it will be unbound - * - * This can be used by drivers to release an interface without waiting - * for their disconnect() methods to be called. In typical cases this - * also causes the driver disconnect() method to be called. - * - * This call is synchronous, and may not be used in an interrupt context. - * Callers must own the device lock and the driver model's usb_bus_type.subsys - * writelock. So driver disconnect() entries don't need extra locking, - * but other call contexts may need to explicitly claim those locks. - */ -void usb_driver_release_interface(struct usb_driver *driver, - struct usb_interface *iface) -{ - struct device *dev = &iface->dev; - - /* this should never happen, don't release something that's not ours */ - if (!dev->driver || dev->driver != &driver->driver) - return; - - /* don't release from within disconnect() */ - if (iface->condition != USB_INTERFACE_BOUND) - return; - - /* don't release if the interface hasn't been added yet */ - if (device_is_registered(dev)) { - iface->condition = USB_INTERFACE_UNBINDING; - device_release_driver(dev); - } - - dev->driver = NULL; - usb_set_intfdata(iface, NULL); - iface->condition = USB_INTERFACE_UNBOUND; - mark_quiesced(iface); -} - struct find_interface_arg { int minor; struct usb_interface *interface; @@ -204,7 +124,7 @@ static int __find_interface(struct device * dev, void * data) struct usb_interface *intf; /* can't look at usb devices, only interfaces */ - if (dev->driver == &usb_generic_driver) + if (is_usb_device(dev)) return 0; intf = to_usb_interface(dev); @@ -227,127 +147,16 @@ static int __find_interface(struct device * dev, void * data) struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor) { struct find_interface_arg argb; + int retval; argb.minor = minor; argb.interface = NULL; - driver_for_each_device(&drv->driver, NULL, &argb, __find_interface); + /* eat the error, it will be in argb.interface */ + retval = driver_for_each_device(&drv->drvwrap.driver, NULL, &argb, + __find_interface); return argb.interface; } -#ifdef CONFIG_HOTPLUG - -/* - * This sends an uevent to userspace, typically helping to load driver - * or other modules, configure the device, and more. Drivers can provide - * a MODULE_DEVICE_TABLE to help with module loading subtasks. - * - * We're called either from khubd (the typical case) or from root hub - * (init, kapmd, modprobe, rmmod, etc), but the agents need to handle - * delays in event delivery. Use sysfs (and DEVPATH) to make sure the - * device (and this configuration!) are still present. - */ -static int usb_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) -{ - struct usb_interface *intf; - struct usb_device *usb_dev; - struct usb_host_interface *alt; - int i = 0; - int length = 0; - - if (!dev) - return -ENODEV; - - /* driver is often null here; dev_dbg() would oops */ - pr_debug ("usb %s: uevent\n", dev->bus_id); - - /* Must check driver_data here, as on remove driver is always NULL */ - if ((dev->driver == &usb_generic_driver) || - (dev->driver_data == &usb_generic_driver_data)) - return 0; - - intf = to_usb_interface(dev); - usb_dev = interface_to_usbdev (intf); - alt = intf->cur_altsetting; - - if (usb_dev->devnum < 0) { - pr_debug ("usb %s: already deleted?\n", dev->bus_id); - return -ENODEV; - } - if (!usb_dev->bus) { - pr_debug ("usb %s: bus removed?\n", dev->bus_id); - return -ENODEV; - } - -#ifdef CONFIG_USB_DEVICEFS - /* If this is available, userspace programs can directly read - * all the device descriptors we don't tell them about. Or - * even act as usermode drivers. - * - * FIXME reduce hardwired intelligence here - */ - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVICE=/proc/bus/usb/%03d/%03d", - usb_dev->bus->busnum, usb_dev->devnum)) - return -ENOMEM; -#endif - - /* per-device configurations are common */ - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PRODUCT=%x/%x/%x", - le16_to_cpu(usb_dev->descriptor.idVendor), - le16_to_cpu(usb_dev->descriptor.idProduct), - le16_to_cpu(usb_dev->descriptor.bcdDevice))) - return -ENOMEM; - - /* class-based driver binding models */ - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "TYPE=%d/%d/%d", - usb_dev->descriptor.bDeviceClass, - usb_dev->descriptor.bDeviceSubClass, - usb_dev->descriptor.bDeviceProtocol)) - return -ENOMEM; - - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "INTERFACE=%d/%d/%d", - alt->desc.bInterfaceClass, - alt->desc.bInterfaceSubClass, - alt->desc.bInterfaceProtocol)) - return -ENOMEM; - - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", - le16_to_cpu(usb_dev->descriptor.idVendor), - le16_to_cpu(usb_dev->descriptor.idProduct), - le16_to_cpu(usb_dev->descriptor.bcdDevice), - usb_dev->descriptor.bDeviceClass, - usb_dev->descriptor.bDeviceSubClass, - usb_dev->descriptor.bDeviceProtocol, - alt->desc.bInterfaceClass, - alt->desc.bInterfaceSubClass, - alt->desc.bInterfaceProtocol)) - return -ENOMEM; - - envp[i] = NULL; - - return 0; -} - -#else - -static int usb_uevent(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) -{ - return -ENODEV; -} - -#endif /* CONFIG_HOTPLUG */ - /** * usb_release_dev - free a usb device structure when all users of it are finished. * @dev: device that's been disconnected @@ -361,14 +170,33 @@ static void usb_release_dev(struct device *dev) udev = to_usb_device(dev); +#ifdef CONFIG_PM + cancel_delayed_work(&udev->autosuspend); + flush_scheduled_work(); +#endif usb_destroy_configuration(udev); - usb_bus_put(udev->bus); + usb_put_hcd(bus_to_hcd(udev->bus)); kfree(udev->product); kfree(udev->manufacturer); kfree(udev->serial); kfree(udev); } +#ifdef CONFIG_PM + +/* usb_autosuspend_work - callback routine to autosuspend a USB device */ +static void usb_autosuspend_work(void *_udev) +{ + struct usb_device *udev = _udev; + + mutex_lock_nested(&udev->pm_mutex, udev->level); + udev->auto_pm = 1; + usb_suspend_both(udev, PMSG_SUSPEND); + mutex_unlock(&udev->pm_mutex); +} + +#endif + /** * usb_alloc_dev - usb device constructor (usbcore-internal) * @parent: hub to which device is connected; null to allocate a root hub @@ -390,8 +218,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) if (!dev) return NULL; - bus = usb_bus_get(bus); - if (!bus) { + if (!usb_get_hcd(bus_to_hcd(bus))) { kfree(dev); return NULL; } @@ -399,11 +226,12 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) device_initialize(&dev->dev); dev->dev.bus = &usb_bus_type; dev->dev.dma_mask = bus->controller->dma_mask; - dev->dev.driver_data = &usb_generic_driver_data; - dev->dev.driver = &usb_generic_driver; dev->dev.release = usb_release_dev; dev->state = USB_STATE_ATTACHED; + /* This magic assignment distinguishes devices from interfaces */ + dev->dev.platform_data = &usb_generic_driver; + INIT_LIST_HEAD(&dev->ep0.urb_list); dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE; dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; @@ -444,6 +272,10 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) dev->parent = parent; INIT_LIST_HEAD(&dev->filelist); +#ifdef CONFIG_PM + mutex_init(&dev->pm_mutex); + INIT_WORK(&dev->autosuspend, usb_autosuspend_work, dev); +#endif return dev; } @@ -549,7 +381,7 @@ void usb_put_intf(struct usb_interface *intf) * case the driver already owns the device lock.) */ int usb_lock_device_for_reset(struct usb_device *udev, - struct usb_interface *iface) + const struct usb_interface *iface) { unsigned long jiffies_expire = jiffies + HZ; @@ -672,7 +504,139 @@ exit: */ int usb_get_current_frame_number(struct usb_device *dev) { - return dev->bus->op->get_frame_number (dev); + return usb_hcd_get_frame_number (dev); +} + +/** + * usb_endpoint_dir_in - check if the endpoint has IN direction + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type IN, otherwise it returns false. + */ +int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN); +} + +/** + * usb_endpoint_dir_out - check if the endpoint has OUT direction + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type OUT, otherwise it returns false. + */ +int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT); +} + +/** + * usb_endpoint_xfer_bulk - check if the endpoint has bulk transfer type + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type bulk, otherwise it returns false. + */ +int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_BULK); +} + +/** + * usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type interrupt, otherwise it returns + * false. + */ +int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_INT); +} + +/** + * usb_endpoint_xfer_isoc - check if the endpoint has isochronous transfer type + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type isochronous, otherwise it returns + * false. + */ +int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_ISOC); +} + +/** + * usb_endpoint_is_bulk_in - check if the endpoint is bulk IN + * @epd: endpoint to be checked + * + * Returns true if the endpoint has bulk transfer type and IN direction, + * otherwise it returns false. + */ +int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd) +{ + return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_in(epd)); +} + +/** + * usb_endpoint_is_bulk_out - check if the endpoint is bulk OUT + * @epd: endpoint to be checked + * + * Returns true if the endpoint has bulk transfer type and OUT direction, + * otherwise it returns false. + */ +int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd) +{ + return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_out(epd)); +} + +/** + * usb_endpoint_is_int_in - check if the endpoint is interrupt IN + * @epd: endpoint to be checked + * + * Returns true if the endpoint has interrupt transfer type and IN direction, + * otherwise it returns false. + */ +int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd) +{ + return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd)); +} + +/** + * usb_endpoint_is_int_out - check if the endpoint is interrupt OUT + * @epd: endpoint to be checked + * + * Returns true if the endpoint has interrupt transfer type and OUT direction, + * otherwise it returns false. + */ +int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd) +{ + return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_out(epd)); +} + +/** + * usb_endpoint_is_isoc_in - check if the endpoint is isochronous IN + * @epd: endpoint to be checked + * + * Returns true if the endpoint has isochronous transfer type and IN direction, + * otherwise it returns false. + */ +int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd) +{ + return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_in(epd)); +} + +/** + * usb_endpoint_is_isoc_out - check if the endpoint is isochronous OUT + * @epd: endpoint to be checked + * + * Returns true if the endpoint has isochronous transfer type and OUT direction, + * otherwise it returns false. + */ +int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd) +{ + return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_out(epd)); } /*-------------------------------------------------------------------*/ @@ -737,9 +701,9 @@ void *usb_buffer_alloc ( dma_addr_t *dma ) { - if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_alloc) + if (!dev || !dev->bus) return NULL; - return dev->bus->op->buffer_alloc (dev->bus, size, mem_flags, dma); + return hcd_buffer_alloc (dev->bus, size, mem_flags, dma); } /** @@ -760,9 +724,11 @@ void usb_buffer_free ( dma_addr_t dma ) { - if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_free) - return; - dev->bus->op->buffer_free (dev->bus, size, addr, dma); + if (!dev || !dev->bus) + return; + if (!addr) + return; + hcd_buffer_free (dev->bus, size, addr, dma); } /** @@ -911,8 +877,8 @@ void usb_buffer_unmap (struct urb *urb) * * Reverse the effect of this call with usb_buffer_unmap_sg(). */ -int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe, - struct scatterlist *sg, int nents) +int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe, + struct scatterlist *sg, int nents) { struct usb_bus *bus; struct device *controller; @@ -946,8 +912,8 @@ int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe, * Use this when you are re-using a scatterlist's data buffers for * another USB request. */ -void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe, - struct scatterlist *sg, int n_hw_ents) +void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe, + struct scatterlist *sg, int n_hw_ents) { struct usb_bus *bus; struct device *controller; @@ -972,8 +938,8 @@ void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe, * * Reverses the effect of usb_buffer_map_sg(). */ -void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, - struct scatterlist *sg, int n_hw_ents) +void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe, + struct scatterlist *sg, int n_hw_ents) { struct usb_bus *bus; struct device *controller; @@ -988,116 +954,6 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } -static int verify_suspended(struct device *dev, void *unused) -{ - if (dev->driver == NULL) - return 0; - return (dev->power.power_state.event == PM_EVENT_ON) ? -EBUSY : 0; -} - -static int usb_generic_suspend(struct device *dev, pm_message_t message) -{ - struct usb_interface *intf; - struct usb_driver *driver; - int status; - - /* USB devices enter SUSPEND state through their hubs, but can be - * marked for FREEZE as soon as their children are already idled. - * But those semantics are useless, so we equate the two (sigh). - */ - if (dev->driver == &usb_generic_driver) { - if (dev->power.power_state.event == message.event) - return 0; - /* we need to rule out bogus requests through sysfs */ - status = device_for_each_child(dev, NULL, verify_suspended); - if (status) - return status; - return usb_suspend_device (to_usb_device(dev)); - } - - if ((dev->driver == NULL) || - (dev->driver_data == &usb_generic_driver_data)) - return 0; - - intf = to_usb_interface(dev); - driver = to_usb_driver(dev->driver); - - /* with no hardware, USB interfaces only use FREEZE and ON states */ - if (!is_active(intf)) - return 0; - - if (driver->suspend && driver->resume) { - status = driver->suspend(intf, message); - if (status) - dev_err(dev, "%s error %d\n", "suspend", status); - else - mark_quiesced(intf); - } else { - // FIXME else if there's no suspend method, disconnect... - dev_warn(dev, "no suspend for driver %s?\n", driver->name); - mark_quiesced(intf); - status = 0; - } - return status; -} - -static int usb_generic_resume(struct device *dev) -{ - struct usb_interface *intf; - struct usb_driver *driver; - struct usb_device *udev; - int status; - - if (dev->power.power_state.event == PM_EVENT_ON) - return 0; - - /* mark things as "on" immediately, no matter what errors crop up */ - dev->power.power_state.event = PM_EVENT_ON; - - /* devices resume through their hubs */ - if (dev->driver == &usb_generic_driver) { - udev = to_usb_device(dev); - if (udev->state == USB_STATE_NOTATTACHED) - return 0; - return usb_resume_device (to_usb_device(dev)); - } - - if ((dev->driver == NULL) || - (dev->driver_data == &usb_generic_driver_data)) { - dev->power.power_state.event = PM_EVENT_FREEZE; - return 0; - } - - intf = to_usb_interface(dev); - driver = to_usb_driver(dev->driver); - - udev = interface_to_usbdev(intf); - if (udev->state == USB_STATE_NOTATTACHED) - return 0; - - /* if driver was suspended, it has a resume method; - * however, sysfs can wrongly mark things as suspended - * (on the "no suspend method" FIXME path above) - */ - if (driver->resume) { - status = driver->resume(intf); - if (status) { - dev_err(dev, "%s error %d\n", "resume", status); - mark_quiesced(intf); - } - } else - dev_warn(dev, "no resume for driver %s?\n", driver->name); - return 0; -} - -struct bus_type usb_bus_type = { - .name = "usb", - .match = usb_device_match, - .uevent = usb_uevent, - .suspend = usb_generic_suspend, - .resume = usb_generic_resume, -}; - /* format to disable USB on kernel command line is: nousb */ __module_param_call("", nousb, param_set_bool, param_get_bool, &nousb, 0444); @@ -1141,7 +997,7 @@ static int __init usb_init(void) retval = usb_hub_init(); if (retval) goto hub_init_failed; - retval = driver_register(&usb_generic_driver); + retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE); if (!retval) goto out; @@ -1171,7 +1027,7 @@ static void __exit usb_exit(void) if (nousb) return; - driver_unregister(&usb_generic_driver); + usb_deregister_device_driver(&usb_generic_driver); usb_major_cleanup(); usbfs_cleanup(); usb_deregister(&usbfs_driver); @@ -1201,20 +1057,27 @@ EXPORT_SYMBOL(usb_hub_tt_clear_buffer); EXPORT_SYMBOL(usb_lock_device_for_reset); -EXPORT_SYMBOL(usb_driver_claim_interface); -EXPORT_SYMBOL(usb_driver_release_interface); EXPORT_SYMBOL(usb_find_interface); EXPORT_SYMBOL(usb_ifnum_to_if); EXPORT_SYMBOL(usb_altnum_to_altsetting); -EXPORT_SYMBOL(usb_reset_device); -EXPORT_SYMBOL(usb_reset_composite_device); - EXPORT_SYMBOL(__usb_get_extra_descriptor); EXPORT_SYMBOL(usb_find_device); EXPORT_SYMBOL(usb_get_current_frame_number); +EXPORT_SYMBOL_GPL(usb_endpoint_dir_in); +EXPORT_SYMBOL_GPL(usb_endpoint_dir_out); +EXPORT_SYMBOL_GPL(usb_endpoint_xfer_bulk); +EXPORT_SYMBOL_GPL(usb_endpoint_xfer_int); +EXPORT_SYMBOL_GPL(usb_endpoint_xfer_isoc); +EXPORT_SYMBOL_GPL(usb_endpoint_is_bulk_in); +EXPORT_SYMBOL_GPL(usb_endpoint_is_bulk_out); +EXPORT_SYMBOL_GPL(usb_endpoint_is_int_in); +EXPORT_SYMBOL_GPL(usb_endpoint_is_int_out); +EXPORT_SYMBOL_GPL(usb_endpoint_is_isoc_in); +EXPORT_SYMBOL_GPL(usb_endpoint_is_isoc_out); + EXPORT_SYMBOL (usb_buffer_alloc); EXPORT_SYMBOL (usb_buffer_free); diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 49f69236b42..0c09ecced6e 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -1,10 +1,10 @@ /* Functions local to drivers/usb/core/ */ -extern void usb_create_sysfs_dev_files (struct usb_device *dev); +extern int usb_create_sysfs_dev_files (struct usb_device *dev); extern void usb_remove_sysfs_dev_files (struct usb_device *dev); -extern void usb_create_sysfs_intf_files (struct usb_interface *intf); +extern int usb_create_sysfs_intf_files (struct usb_interface *intf); extern void usb_remove_sysfs_intf_files (struct usb_interface *intf); -extern void usb_create_ep_files(struct device *parent, struct usb_host_endpoint *endpoint, +extern int usb_create_ep_files(struct device *parent, struct usb_host_endpoint *endpoint, struct usb_device *udev); extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint); @@ -20,7 +20,6 @@ extern char *usb_cache_string(struct usb_device *udev, int index); extern int usb_set_configuration(struct usb_device *dev, int configuration); extern void usb_kick_khubd(struct usb_device *dev); -extern void usb_suspend_root_hub(struct usb_device *hdev); extern void usb_resume_root_hub(struct usb_device *dev); extern int usb_hub_init(void); @@ -30,28 +29,74 @@ extern void usb_major_cleanup(void); extern int usb_host_init(void); extern void usb_host_cleanup(void); -extern int usb_suspend_device(struct usb_device *dev); -extern int usb_resume_device(struct usb_device *dev); +#ifdef CONFIG_PM -extern struct device_driver usb_generic_driver; -extern int usb_generic_driver_data; -extern int usb_device_match(struct device *dev, struct device_driver *drv); +extern int usb_suspend_both(struct usb_device *udev, pm_message_t msg); +extern int usb_resume_both(struct usb_device *udev); +extern int usb_port_suspend(struct usb_device *dev); +extern int usb_port_resume(struct usb_device *dev); + +#else + +#define usb_suspend_both(udev, msg) 0 +static inline int usb_resume_both(struct usb_device *udev) +{ + return 0; +} +#define usb_port_suspend(dev) 0 +#define usb_port_resume(dev) 0 + +#endif + +#ifdef CONFIG_USB_SUSPEND + +#define USB_AUTOSUSPEND_DELAY (HZ*2) + +extern void usb_autosuspend_device(struct usb_device *udev, int dec_busy_cnt); +extern int usb_autoresume_device(struct usb_device *udev, int inc_busy_cnt); + +#else + +#define usb_autosuspend_device(udev, dec_busy_cnt) do {} while (0) +#define usb_autoresume_device(udev, inc_busy_cnt) 0 + +#endif + +extern struct bus_type usb_bus_type; +extern struct usb_device_driver usb_generic_driver; + +/* Here's how we tell apart devices and interfaces. Luckily there's + * no such thing as a platform USB device, so we can steal the use + * of the platform_data field. */ + +static inline int is_usb_device(const struct device *dev) +{ + return dev->platform_data == &usb_generic_driver; +} + +/* Do the same for device drivers and interface drivers. */ + +static inline int is_usb_device_driver(struct device_driver *drv) +{ + return container_of(drv, struct usbdrv_wrap, driver)-> + for_devices; +} /* Interfaces and their "power state" are owned by usbcore */ static inline void mark_active(struct usb_interface *f) { - f->dev.power.power_state.event = PM_EVENT_ON; + f->is_active = 1; } static inline void mark_quiesced(struct usb_interface *f) { - f->dev.power.power_state.event = PM_EVENT_FREEZE; + f->is_active = 0; } -static inline int is_active(struct usb_interface *f) +static inline int is_active(const struct usb_interface *f) { - return f->dev.power.power_state.event == PM_EVENT_ON; + return f->is_active; } @@ -59,9 +104,10 @@ static inline int is_active(struct usb_interface *f) extern const char *usbcore_name; /* usbfs stuff */ +extern struct mutex usbfs_mutex; extern struct usb_driver usbfs_driver; -extern struct file_operations usbfs_devices_fops; -extern struct file_operations usbfs_device_file_operations; +extern const struct file_operations usbfs_devices_fops; +extern const struct file_operations usbfs_device_file_operations; extern void usbfs_conn_disc_event(void); extern int usbdev_init(void); |