X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fusb%2Fcore%2Fusb.c;h=c32811ae128f13e2181ff15ec69a847c5543425b;hb=5512966643adb17483efc5f61481a38fc33088bb;hp=8f142370103d48400d3adb6cb6b6f36eab5e4070;hpb=4a9bee8256a2dec26290a3bfff86ab86b8992547;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 8f14237..c32811a 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -96,10 +97,10 @@ struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev, return NULL; } +EXPORT_SYMBOL_GPL(usb_ifnum_to_if); /** - * usb_altnum_to_altsetting - get the altsetting structure with a given - * alternate setting number. + * usb_altnum_to_altsetting - get the altsetting structure with a given alternate setting number. * @intf: the interface containing the altsetting in question * @altnum: the desired alternate setting number * @@ -115,8 +116,9 @@ struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev, * 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(const 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; @@ -126,19 +128,19 @@ struct usb_host_interface *usb_altnum_to_altsetting(const struct usb_interface * } return NULL; } +EXPORT_SYMBOL_GPL(usb_altnum_to_altsetting); struct find_interface_arg { int minor; struct usb_interface *interface; }; -static int __find_interface(struct device * dev, void * data) +static int __find_interface(struct device *dev, void *data) { struct find_interface_arg *arg = data; struct usb_interface *intf; - /* can't look at usb devices, only interfaces */ - if (is_usb_device(dev)) + if (!is_usb_interface(dev)) return 0; intf = to_usb_interface(dev); @@ -154,7 +156,7 @@ static int __find_interface(struct device * dev, void * data) * @drv: the driver whose current configuration is considered * @minor: the minor number of the desired device * - * This walks the driver device list and returns a pointer to the interface + * This walks the driver device list and returns a pointer to the interface * with the matching minor. Note, this only works for devices that share the * USB major number. */ @@ -170,6 +172,7 @@ struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor) __find_interface); return argb.interface; } +EXPORT_SYMBOL_GPL(usb_find_interface); /** * usb_release_dev - free a usb device structure when all users of it are finished. @@ -216,12 +219,6 @@ static int usb_dev_uevent(struct device *dev, struct kobj_uevent_env *env) } #endif /* CONFIG_HOTPLUG */ -struct device_type usb_device_type = { - .name = "usb_device", - .release = usb_release_dev, - .uevent = usb_dev_uevent, -}; - #ifdef CONFIG_PM static int ksuspend_usb_init(void) @@ -241,13 +238,80 @@ static void ksuspend_usb_cleanup(void) destroy_workqueue(ksuspend_usb_wq); } +/* USB device Power-Management thunks. + * There's no need to distinguish here between quiescing a USB device + * and powering it down; the generic_suspend() routine takes care of + * it by skipping the usb_port_suspend() call for a quiesce. And for + * USB interfaces there's no difference at all. + */ + +static int usb_dev_prepare(struct device *dev) +{ + return 0; /* Implement eventually? */ +} + +static void usb_dev_complete(struct device *dev) +{ + /* Currently used only for rebinding interfaces */ + usb_resume(dev, PMSG_RESUME); /* Message event is meaningless */ +} + +static int usb_dev_suspend(struct device *dev) +{ + return usb_suspend(dev, PMSG_SUSPEND); +} + +static int usb_dev_resume(struct device *dev) +{ + return usb_resume(dev, PMSG_RESUME); +} + +static int usb_dev_freeze(struct device *dev) +{ + return usb_suspend(dev, PMSG_FREEZE); +} + +static int usb_dev_thaw(struct device *dev) +{ + return usb_resume(dev, PMSG_THAW); +} + +static int usb_dev_poweroff(struct device *dev) +{ + return usb_suspend(dev, PMSG_HIBERNATE); +} + +static int usb_dev_restore(struct device *dev) +{ + return usb_resume(dev, PMSG_RESTORE); +} + +static struct dev_pm_ops usb_device_pm_ops = { + .prepare = usb_dev_prepare, + .complete = usb_dev_complete, + .suspend = usb_dev_suspend, + .resume = usb_dev_resume, + .freeze = usb_dev_freeze, + .thaw = usb_dev_thaw, + .poweroff = usb_dev_poweroff, + .restore = usb_dev_restore, +}; + #else #define ksuspend_usb_init() 0 #define ksuspend_usb_cleanup() do {} while (0) +#define usb_device_pm_ops (*(struct dev_pm_ops *)0) #endif /* CONFIG_PM */ +struct device_type usb_device_type = { + .name = "usb_device", + .release = usb_release_dev, + .uevent = usb_dev_uevent, + .pm = &usb_device_pm_ops, +}; + /* Returns 1 if @usb_bus is WUSB, 0 otherwise */ static unsigned usb_bus_is_wusb(struct usb_bus *bus) @@ -269,8 +333,8 @@ static unsigned usb_bus_is_wusb(struct usb_bus *bus) * * This call may not be used in a non-sleeping context. */ -struct usb_device * -usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) +struct usb_device *usb_alloc_dev(struct usb_device *parent, + struct usb_bus *bus, unsigned port1) { struct usb_device *dev; struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self); @@ -288,6 +352,7 @@ 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.type = &usb_device_type; + dev->dev.groups = usb_device_groups; dev->dev.dma_mask = bus->controller->dma_mask; set_dev_node(&dev->dev, dev_to_node(bus->controller)); dev->state = USB_STATE_ATTACHED; @@ -297,14 +362,14 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE; dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; /* ep0 maxpacket comes later, from device descriptor */ - usb_enable_endpoint(dev, &dev->ep0); + usb_enable_endpoint(dev, &dev->ep0, false); dev->can_submit = 1; /* Save readable and stable topology id, distinguishing devices * by location for diagnostics, tools, driver model, etc. The * string is a path along hub ports, from the root. Each device's * dev->devpath will be stable until USB is re-cabled, and hubs - * are often labeled with these port numbers. The bus_id isn't + * are often labeled with these port numbers. The name isn't * as stable: bus->busnum changes easily from modprobe order, * cardbus or pci hotplugging, and so on. */ @@ -312,7 +377,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) dev->devpath[0] = '0'; dev->dev.parent = bus->controller; - sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum); + dev_set_name(&dev->dev, "usb%d", bus->busnum); root_hub = 1; } else { /* match any labeling on the hubs; it's one-based */ @@ -324,8 +389,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) "%s.%d", parent->devpath, port1); dev->dev.parent = &parent->dev; - sprintf(&dev->dev.bus_id[0], "%d-%s", - bus->busnum, dev->devpath); + dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath); /* hub driver sets up TT records */ } @@ -338,7 +402,10 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) #ifdef CONFIG_PM mutex_init(&dev->pm_mutex); INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work); + INIT_WORK(&dev->autoresume, usb_autoresume_work); dev->autosuspend_delay = usb_autosuspend_delay * HZ; + dev->connect_time = jiffies; + dev->active_duration = -jiffies; #endif if (root_hub) /* Root hub always ok [and always wired] */ dev->authorized = 1; @@ -367,6 +434,7 @@ struct usb_device *usb_get_dev(struct usb_device *dev) get_device(&dev->dev); return dev; } +EXPORT_SYMBOL_GPL(usb_get_dev); /** * usb_put_dev - release a use of the usb device structure @@ -380,6 +448,7 @@ void usb_put_dev(struct usb_device *dev) if (dev) put_device(&dev->dev); } +EXPORT_SYMBOL_GPL(usb_put_dev); /** * usb_get_intf - increments the reference count of the usb interface structure @@ -400,6 +469,7 @@ struct usb_interface *usb_get_intf(struct usb_interface *intf) get_device(&intf->dev); return intf; } +EXPORT_SYMBOL_GPL(usb_get_intf); /** * usb_put_intf - release a use of the usb interface structure @@ -414,7 +484,7 @@ void usb_put_intf(struct usb_interface *intf) if (intf) put_device(&intf->dev); } - +EXPORT_SYMBOL_GPL(usb_put_intf); /* USB device locking * @@ -433,8 +503,7 @@ void usb_put_intf(struct usb_interface *intf) */ /** - * usb_lock_device_for_reset - cautiously acquire the lock for a - * usb device structure + * usb_lock_device_for_reset - cautiously acquire the lock for a usb device structure * @udev: device that's being locked * @iface: interface bound to the driver making the request (optional) * @@ -445,10 +514,7 @@ void usb_put_intf(struct usb_interface *intf) * disconnect; in some drivers (such as usb-storage) the disconnect() * or suspend() method will block waiting for a device reset to complete. * - * Returns a negative error code for failure, otherwise 1 or 0 to indicate - * that the device will or will not have to be unlocked. (0 can be - * returned when an interface is given and is BINDING, because in that - * case the driver already owns the device lock.) + * Returns a negative error code for failure, otherwise 0. */ int usb_lock_device_for_reset(struct usb_device *udev, const struct usb_interface *iface) @@ -459,16 +525,9 @@ int usb_lock_device_for_reset(struct usb_device *udev, return -ENODEV; if (udev->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; - if (iface) { - switch (iface->condition) { - case USB_INTERFACE_BINDING: - return 0; - case USB_INTERFACE_BOUND: - break; - default: - return -EINTR; - } - } + if (iface && (iface->condition == USB_INTERFACE_UNBINDING || + iface->condition == USB_INTERFACE_UNBOUND)) + return -EINTR; while (usb_trylock_device(udev) != 0) { @@ -482,12 +541,13 @@ int usb_lock_device_for_reset(struct usb_device *udev, return -ENODEV; if (udev->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; - if (iface && iface->condition != USB_INTERFACE_BOUND) + if (iface && (iface->condition == USB_INTERFACE_UNBINDING || + iface->condition == USB_INTERFACE_UNBOUND)) return -EINTR; } - return 1; + return 0; } - +EXPORT_SYMBOL_GPL(usb_lock_device_for_reset); static struct usb_device *match_device(struct usb_device *dev, u16 vendor_id, u16 product_id) @@ -540,10 +600,10 @@ struct usb_device *usb_find_device(u16 vendor_id, u16 product_id) struct list_head *buslist; struct usb_bus *bus; struct usb_device *dev = NULL; - + mutex_lock(&usb_bus_list_lock); for (buslist = usb_bus_list.next; - buslist != &usb_bus_list; + buslist != &usb_bus_list; buslist = buslist->next) { bus = container_of(buslist, struct usb_bus, bus_list); if (!bus->root_hub) @@ -576,6 +636,7 @@ int usb_get_current_frame_number(struct usb_device *dev) { return usb_hcd_get_frame_number(dev); } +EXPORT_SYMBOL_GPL(usb_get_current_frame_number); /*-------------------------------------------------------------------*/ /* @@ -584,7 +645,7 @@ int usb_get_current_frame_number(struct usb_device *dev) */ int __usb_get_extra_descriptor(char *buffer, unsigned size, - unsigned char type, void **ptr) + unsigned char type, void **ptr) { struct usb_descriptor_header *header; @@ -595,7 +656,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, printk(KERN_ERR "%s: bogus descriptor, type %d length %d\n", usbcore_name, - header->bDescriptorType, + header->bDescriptorType, header->bLength); return -1; } @@ -610,6 +671,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, } return -1; } +EXPORT_SYMBOL_GPL(__usb_get_extra_descriptor); /** * usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_xxx_DMA_MAP @@ -633,17 +695,14 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, * * When the buffer is no longer used, free it with usb_buffer_free(). */ -void *usb_buffer_alloc( - struct usb_device *dev, - size_t size, - gfp_t mem_flags, - dma_addr_t *dma -) +void *usb_buffer_alloc(struct usb_device *dev, size_t size, gfp_t mem_flags, + dma_addr_t *dma) { if (!dev || !dev->bus) return NULL; return hcd_buffer_alloc(dev->bus, size, mem_flags, dma); } +EXPORT_SYMBOL_GPL(usb_buffer_alloc); /** * usb_buffer_free - free memory allocated with usb_buffer_alloc() @@ -656,12 +715,8 @@ void *usb_buffer_alloc( * been allocated using usb_buffer_alloc(), and the parameters must match * those provided in that allocation request. */ -void usb_buffer_free( - struct usb_device *dev, - size_t size, - void *addr, - dma_addr_t dma -) +void usb_buffer_free(struct usb_device *dev, size_t size, void *addr, + dma_addr_t dma) { if (!dev || !dev->bus) return; @@ -669,6 +724,7 @@ void usb_buffer_free( return; hcd_buffer_free(dev->bus, size, addr, dma); } +EXPORT_SYMBOL_GPL(usb_buffer_free); /** * usb_buffer_map - create DMA mapping(s) for an urb @@ -708,14 +764,15 @@ struct urb *usb_buffer_map(struct urb *urb) urb->setup_packet, sizeof(struct usb_ctrlrequest), DMA_TO_DEVICE); - // FIXME generic api broken like pci, can't report errors - // if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; + /* FIXME generic api broken like pci, can't report errors */ + /* if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; */ } else urb->transfer_dma = ~0; urb->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); return urb; } +EXPORT_SYMBOL_GPL(usb_buffer_map); #endif /* 0 */ /* XXX DISABLED, no users currently. If you wish to re-enable this @@ -753,6 +810,7 @@ void usb_buffer_dmasync(struct urb *urb) DMA_TO_DEVICE); } } +EXPORT_SYMBOL_GPL(usb_buffer_dmasync); #endif /** @@ -788,6 +846,7 @@ void usb_buffer_unmap(struct urb *urb) urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); } +EXPORT_SYMBOL_GPL(usb_buffer_unmap); #endif /* 0 */ /** @@ -828,10 +887,11 @@ int usb_buffer_map_sg(const struct usb_device *dev, int is_in, || !controller->dma_mask) return -1; - // FIXME generic api broken like pci, can't report errors + /* FIXME generic api broken like pci, can't report errors */ return dma_map_sg(controller, sg, nents, is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } +EXPORT_SYMBOL_GPL(usb_buffer_map_sg); /* XXX DISABLED, no users currently. If you wish to re-enable this * XXX please determine whether the sync is to transfer ownership of @@ -865,6 +925,7 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in, dma_sync_sg(controller, sg, n_hw_ents, is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } +EXPORT_SYMBOL_GPL(usb_buffer_dmasync_sg); #endif /** @@ -891,9 +952,14 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in, dma_unmap_sg(controller, sg, n_hw_ents, is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } +EXPORT_SYMBOL_GPL(usb_buffer_unmap_sg); -/* format to disable USB on kernel command line is: nousb */ -__module_param_call("", nousb, param_set_bool, param_get_bool, &nousb, 0444); +/* To disable USB, kernel command line is 'nousb' not 'usbcore.nousb' */ +#ifdef MODULE +module_param(nousb, bool, 0444); +#else +core_param(nousb, nousb, bool, 0444); +#endif /* * for external read access to @@ -902,6 +968,67 @@ int usb_disabled(void) { return nousb; } +EXPORT_SYMBOL_GPL(usb_disabled); + +/* + * Notifications of device and interface registration + */ +static int usb_bus_notify(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct device *dev = data; + + switch (action) { + case BUS_NOTIFY_ADD_DEVICE: + if (dev->type == &usb_device_type) + (void) usb_create_sysfs_dev_files(to_usb_device(dev)); + else if (dev->type == &usb_if_device_type) + (void) usb_create_sysfs_intf_files( + to_usb_interface(dev)); + break; + + case BUS_NOTIFY_DEL_DEVICE: + if (dev->type == &usb_device_type) + usb_remove_sysfs_dev_files(to_usb_device(dev)); + else if (dev->type == &usb_if_device_type) + usb_remove_sysfs_intf_files(to_usb_interface(dev)); + break; + } + return 0; +} + +static struct notifier_block usb_bus_nb = { + .notifier_call = usb_bus_notify, +}; + +struct dentry *usb_debug_root; +EXPORT_SYMBOL_GPL(usb_debug_root); + +struct dentry *usb_debug_devices; + +static int usb_debugfs_init(void) +{ + usb_debug_root = debugfs_create_dir("usb", NULL); + if (!usb_debug_root) + return -ENOENT; + + usb_debug_devices = debugfs_create_file("devices", 0444, + usb_debug_root, NULL, + &usbfs_devices_fops); + if (!usb_debug_devices) { + debugfs_remove(usb_debug_root); + usb_debug_root = NULL; + return -ENOENT; + } + + return 0; +} + +static void usb_debugfs_cleanup(void) +{ + debugfs_remove(usb_debug_devices); + debugfs_remove(usb_debug_root); +} /* * Init @@ -914,15 +1041,19 @@ static int __init usb_init(void) return 0; } + retval = usb_debugfs_init(); + if (retval) + goto out; + retval = ksuspend_usb_init(); if (retval) goto out; retval = bus_register(&usb_bus_type); - if (retval) + if (retval) goto bus_register_failed; - retval = usb_host_init(); + retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb); if (retval) - goto host_init_failed; + goto bus_notifier_failed; retval = usb_major_init(); if (retval) goto major_init_failed; @@ -952,8 +1083,8 @@ usb_devio_init_failed: driver_register_failed: usb_major_cleanup(); major_init_failed: - usb_host_cleanup(); -host_init_failed: + bus_unregister_notifier(&usb_bus_type, &usb_bus_nb); +bus_notifier_failed: bus_unregister(&usb_bus_type); bus_register_failed: ksuspend_usb_cleanup(); @@ -976,52 +1107,12 @@ static void __exit usb_exit(void) usb_deregister(&usbfs_driver); usb_devio_cleanup(); usb_hub_cleanup(); - usb_host_cleanup(); + bus_unregister_notifier(&usb_bus_type, &usb_bus_nb); bus_unregister(&usb_bus_type); ksuspend_usb_cleanup(); + usb_debugfs_cleanup(); } subsys_initcall(usb_init); module_exit(usb_exit); - -/* - * USB may be built into the kernel or be built as modules. - * These symbols are exported for device (or host controller) - * driver modules to use. - */ - -EXPORT_SYMBOL(usb_disabled); - -EXPORT_SYMBOL_GPL(usb_get_intf); -EXPORT_SYMBOL_GPL(usb_put_intf); - -EXPORT_SYMBOL(usb_put_dev); -EXPORT_SYMBOL(usb_get_dev); -EXPORT_SYMBOL(usb_hub_tt_clear_buffer); - -EXPORT_SYMBOL(usb_lock_device_for_reset); - -EXPORT_SYMBOL(usb_find_interface); -EXPORT_SYMBOL(usb_ifnum_to_if); -EXPORT_SYMBOL(usb_altnum_to_altsetting); - -EXPORT_SYMBOL(__usb_get_extra_descriptor); - -EXPORT_SYMBOL(usb_get_current_frame_number); - -EXPORT_SYMBOL(usb_buffer_alloc); -EXPORT_SYMBOL(usb_buffer_free); - -#if 0 -EXPORT_SYMBOL(usb_buffer_map); -EXPORT_SYMBOL(usb_buffer_dmasync); -EXPORT_SYMBOL(usb_buffer_unmap); -#endif - -EXPORT_SYMBOL(usb_buffer_map_sg); -#if 0 -EXPORT_SYMBOL(usb_buffer_dmasync_sg); -#endif -EXPORT_SYMBOL(usb_buffer_unmap_sg); - MODULE_LICENSE("GPL");