diff options
Diffstat (limited to 'drivers/usb/core/usb.c')
| -rw-r--r-- | drivers/usb/core/usb.c | 510 |
1 files changed, 270 insertions, 240 deletions
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 4ebfbd737905..e740f7852bcd 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -19,17 +19,16 @@ * just a collection of helper routines that implement the * generic USB things that the real drivers can use.. * - * Think of this as a "USB library" rather than anything else. - * It should be considered a slave, with no callbacks. Callbacks - * are evil. + * Think of this as a "USB library" rather than anything else, + * with no callbacks. Callbacks are evil. */ #include <linux/module.h> #include <linux/moduleparam.h> +#include <linux/of.h> #include <linux/string.h> #include <linux/bitops.h> #include <linux/slab.h> -#include <linux/interrupt.h> /* for in_interrupt() */ #include <linux/kmod.h> #include <linux/init.h> #include <linux/spinlock.h> @@ -46,8 +45,8 @@ #include <linux/mm.h> #include <linux/dma-mapping.h> -#include "usb.h" - +#include "hub.h" +#include "trace.h" const char *usbcore_name = "usbcore"; @@ -65,8 +64,8 @@ int usb_disabled(void) EXPORT_SYMBOL_GPL(usb_disabled); #ifdef CONFIG_PM -static int usb_autosuspend_delay = 2; /* Default delay value, - * in seconds */ +/* Default delay value, in seconds */ +static int usb_autosuspend_delay = CONFIG_USB_AUTOSUSPEND_DELAY; module_param_named(autosuspend, usb_autosuspend_delay, int, 0644); MODULE_PARM_DESC(autosuspend, "default autosuspend delay"); @@ -210,6 +209,82 @@ int usb_find_common_endpoints_reverse(struct usb_host_interface *alt, EXPORT_SYMBOL_GPL(usb_find_common_endpoints_reverse); /** + * usb_find_endpoint() - Given an endpoint address, search for the endpoint's + * usb_host_endpoint structure in an interface's current altsetting. + * @intf: the interface whose current altsetting should be searched + * @ep_addr: the endpoint address (number and direction) to find + * + * Search the altsetting's list of endpoints for one with the specified address. + * + * Return: Pointer to the usb_host_endpoint if found, %NULL otherwise. + */ +static const struct usb_host_endpoint *usb_find_endpoint( + const struct usb_interface *intf, unsigned int ep_addr) +{ + int n; + const struct usb_host_endpoint *ep; + + n = intf->cur_altsetting->desc.bNumEndpoints; + ep = intf->cur_altsetting->endpoint; + for (; n > 0; (--n, ++ep)) { + if (ep->desc.bEndpointAddress == ep_addr) + return ep; + } + return NULL; +} + +/** + * usb_check_bulk_endpoints - Check whether an interface's current altsetting + * contains a set of bulk endpoints with the given addresses. + * @intf: the interface whose current altsetting should be searched + * @ep_addrs: 0-terminated array of the endpoint addresses (number and + * direction) to look for + * + * Search for endpoints with the specified addresses and check their types. + * + * Return: %true if all the endpoints are found and are bulk, %false otherwise. + */ +bool usb_check_bulk_endpoints( + const struct usb_interface *intf, const u8 *ep_addrs) +{ + const struct usb_host_endpoint *ep; + + for (; *ep_addrs; ++ep_addrs) { + ep = usb_find_endpoint(intf, *ep_addrs); + if (!ep || !usb_endpoint_xfer_bulk(&ep->desc)) + return false; + } + return true; +} +EXPORT_SYMBOL_GPL(usb_check_bulk_endpoints); + +/** + * usb_check_int_endpoints - Check whether an interface's current altsetting + * contains a set of interrupt endpoints with the given addresses. + * @intf: the interface whose current altsetting should be searched + * @ep_addrs: 0-terminated array of the endpoint addresses (number and + * direction) to look for + * + * Search for endpoints with the specified addresses and check their types. + * + * Return: %true if all the endpoints are found and are interrupt, + * %false otherwise. + */ +bool usb_check_int_endpoints( + const struct usb_interface *intf, const u8 *ep_addrs) +{ + const struct usb_host_endpoint *ep; + + for (; *ep_addrs; ++ep_addrs) { + ep = usb_find_endpoint(intf, *ep_addrs); + if (!ep || !usb_endpoint_xfer_int(&ep->desc)) + return false; + } + return true; +} +EXPORT_SYMBOL_GPL(usb_check_int_endpoints); + +/** * usb_find_alt_setting() - Given a configuration, find the alternate setting * for the given interface. * @config: the configuration to search (not necessarily the current config). @@ -326,9 +401,9 @@ struct find_interface_arg { struct device_driver *drv; }; -static int __find_interface(struct device *dev, void *data) +static int __find_interface(struct device *dev, const void *data) { - struct find_interface_arg *arg = data; + const struct find_interface_arg *arg = data; struct usb_interface *intf; if (!is_usb_interface(dev)) @@ -357,7 +432,7 @@ struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor) struct device *dev; argb.minor = minor; - argb.drv = &drv->drvwrap.driver; + argb.drv = &drv->driver; dev = bus_find_device(&usb_bus_type, NULL, &argb, __find_interface); @@ -426,9 +501,9 @@ static void usb_release_dev(struct device *dev) kfree(udev); } -static int usb_dev_uevent(struct device *dev, struct kobj_uevent_env *env) +static int usb_dev_uevent(const struct device *dev, struct kobj_uevent_env *env) { - struct usb_device *usb_dev; + const struct usb_device *usb_dev; usb_dev = to_usb_device(dev); @@ -508,17 +583,17 @@ static const struct dev_pm_ops usb_device_pm_ops = { #endif /* CONFIG_PM */ -static char *usb_devnode(struct device *dev, +static char *usb_devnode(const struct device *dev, umode_t *mode, kuid_t *uid, kgid_t *gid) { - struct usb_device *usb_dev; + const struct usb_device *usb_dev; usb_dev = to_usb_device(dev); return kasprintf(GFP_KERNEL, "bus/usb/%03d/%03d", usb_dev->bus->busnum, usb_dev->devnum); } -struct device_type usb_device_type = { +const struct device_type usb_device_type = { .name = "usb_device", .release = usb_release_dev, .uevent = usb_dev_uevent, @@ -528,21 +603,35 @@ struct device_type usb_device_type = { #endif }; - -/* Returns 1 if @usb_bus is WUSB, 0 otherwise */ -static unsigned usb_bus_is_wusb(struct usb_bus *bus) +static bool usb_dev_authorized(struct usb_device *dev, struct usb_hcd *hcd) { - struct usb_hcd *hcd = bus_to_hcd(bus); - return hcd->wireless; -} + struct usb_hub *hub; + + if (!dev->parent) + return true; /* Root hub always ok [and always wired] */ + + switch (hcd->dev_policy) { + case USB_DEVICE_AUTHORIZE_NONE: + default: + return false; + + case USB_DEVICE_AUTHORIZE_ALL: + return true; + case USB_DEVICE_AUTHORIZE_INTERNAL: + hub = usb_hub_to_struct_hub(dev->parent); + return hub->ports[dev->portnum - 1]->connect_type == + USB_PORT_CONNECT_TYPE_HARD_WIRED; + } +} /** * usb_alloc_dev - usb device constructor (usbcore-internal) * @parent: hub to which device is connected; null to allocate a root hub * @bus: bus used to access the device * @port1: one-based index of port; ignored for root hubs - * Context: !in_interrupt() + * + * Context: task context, might sleep. * * Only hub drivers (including virtual root hub drivers for host * controllers) should ever call this. @@ -557,7 +646,6 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, { struct usb_device *dev; struct usb_hcd *usb_hcd = bus_to_hcd(bus); - unsigned root_hub = 0; unsigned raw_port = port1; dev = kzalloc(sizeof(*dev), GFP_KERNEL); @@ -580,21 +668,10 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, dev->dev.bus = &usb_bus_type; dev->dev.type = &usb_device_type; dev->dev.groups = usb_device_groups; - /* - * Fake a dma_mask/offset for the USB device: - * We cannot really use the dma-mapping API (dma_alloc_* and - * dma_map_*) for USB devices but instead need to use - * usb_alloc_coherent and pass data in 'urb's, but some subsystems - * manually look into the mask/offset pair to determine whether - * they need bounce buffers. - * Note: calling dma_set_mask() on a USB device would set the - * mask for the entire HCD, so don't do that. - */ - dev->dev.dma_mask = bus->sysdev->dma_mask; - dev->dev.dma_pfn_offset = bus->sysdev->dma_pfn_offset; set_dev_node(&dev->dev, dev_to_node(bus->sysdev)); dev->state = USB_STATE_ATTACHED; dev->lpm_disable_count = 1; + dev->offload_usage = 0; atomic_set(&dev->urbnum, 0); INIT_LIST_HEAD(&dev->ep0.urb_list); @@ -619,17 +696,17 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, dev->dev.parent = bus->controller; device_set_of_node_from_dev(&dev->dev, bus->sysdev); dev_set_name(&dev->dev, "usb%d", bus->busnum); - root_hub = 1; } else { + int n; + /* match any labeling on the hubs; it's one-based */ if (parent->devpath[0] == '0') { - snprintf(dev->devpath, sizeof dev->devpath, - "%d", port1); + n = snprintf(dev->devpath, sizeof(dev->devpath), "%d", port1); /* Root ports are not counted in route string */ dev->route = 0; } else { - snprintf(dev->devpath, sizeof dev->devpath, - "%s.%d", parent->devpath, port1); + n = snprintf(dev->devpath, sizeof(dev->devpath), "%s.%d", + parent->devpath, port1); /* Route string assumes hubs have less than 16 ports */ if (port1 < 15) dev->route = parent->route + @@ -638,6 +715,11 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, dev->route = parent->route + (15 << ((parent->level - 1)*4)); } + if (n >= sizeof(dev->devpath)) { + usb_put_hcd(bus_to_hcd(bus)); + usb_put_dev(dev); + return NULL; + } dev->dev.parent = &parent->dev; dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath); @@ -663,12 +745,9 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, dev->connect_time = jiffies; dev->active_duration = -jiffies; #endif - if (root_hub) /* Root hub always ok [and always wired] */ - dev->authorized = 1; - else { - dev->authorized = !!HCD_DEV_AUTHORIZED(usb_hcd); - dev->wusb = usb_bus_is_wusb(bus) ? 1 : 0; - } + + dev->authorized = usb_dev_authorized(dev, usb_hcd); + trace_usb_alloc_dev(dev); return dev; } EXPORT_SYMBOL_GPL(usb_alloc_dev); @@ -682,6 +761,10 @@ EXPORT_SYMBOL_GPL(usb_alloc_dev); * Drivers for USB interfaces should normally record such references in * their probe() methods, when they bind to an interface, and release * them by calling usb_put_dev(), in their disconnect() methods. + * However, if a driver does not access the usb_device structure after + * its disconnect() method returns then refcounting is not necessary, + * because the USB core guarantees that a usb_device will not be + * deallocated until after all of its interface drivers have been unbound. * * Return: A pointer to the device with the incremented reference counter. */ @@ -716,6 +799,10 @@ EXPORT_SYMBOL_GPL(usb_put_dev); * Drivers for USB interfaces should normally record such references in * their probe() methods, when they bind to an interface, and release * them by calling usb_put_intf(), in their disconnect() methods. + * However, if a driver does not access the usb_interface structure after + * its disconnect() method returns then refcounting is not necessary, + * because the USB core guarantees that a usb_interface will not be + * deallocated until after its driver has been unbound. * * Return: A pointer to the interface with the incremented reference counter. */ @@ -742,6 +829,38 @@ void usb_put_intf(struct usb_interface *intf) } EXPORT_SYMBOL_GPL(usb_put_intf); +/** + * usb_intf_get_dma_device - acquire a reference on the usb interface's DMA endpoint + * @intf: the usb interface + * + * While a USB device cannot perform DMA operations by itself, many USB + * controllers can. A call to usb_intf_get_dma_device() returns the DMA endpoint + * for the given USB interface, if any. The returned device structure must be + * released with put_device(). + * + * See also usb_get_dma_device(). + * + * Returns: A reference to the usb interface's DMA endpoint; or NULL if none + * exists. + */ +struct device *usb_intf_get_dma_device(struct usb_interface *intf) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct device *dmadev; + + if (!udev->bus) + return NULL; + + dmadev = get_device(udev->bus->sysdev); + if (!dmadev || !dmadev->dma_mask) { + put_device(dmadev); + return NULL; + } + + return dmadev; +} +EXPORT_SYMBOL_GPL(usb_intf_get_dma_device); + /* USB device locking * * USB devices and interfaces are locked using the semaphore in their @@ -755,7 +874,7 @@ EXPORT_SYMBOL_GPL(usb_put_intf); * is simple: * * When locking both a device and its parent, always lock the - * the parent first. + * parent first. */ /** @@ -915,226 +1034,134 @@ void usb_free_coherent(struct usb_device *dev, size_t size, void *addr, EXPORT_SYMBOL_GPL(usb_free_coherent); /** - * usb_buffer_map - create DMA mapping(s) for an urb - * @urb: urb whose transfer_buffer/setup_packet will be mapped - * - * URB_NO_TRANSFER_DMA_MAP is added to urb->transfer_flags if the operation - * succeeds. If the device is connected to this system through a non-DMA - * controller, this operation always succeeds. - * - * This call would normally be used for an urb which is reused, perhaps - * as the target of a large periodic transfer, with usb_buffer_dmasync() - * calls to synchronize memory and dma state. + * usb_alloc_noncoherent - allocate dma-noncoherent buffer for URB_NO_xxx_DMA_MAP + * @dev: device the buffer will be used with + * @size: requested buffer size + * @mem_flags: affect whether allocation may block + * @dma: used to return DMA address of buffer + * @dir: DMA transfer direction + * @table: used to return sg_table of allocated memory * - * Reverse the effect of this call with usb_buffer_unmap(). + * To explicit manage the memory ownership for the kernel vs the device by + * USB core, the user needs save sg_table to urb->sgt. Then USB core will + * do DMA sync for CPU and device properly. * - * Return: Either %NULL (indicating no buffer could be mapped), or @urb. + * When the buffer is no longer used, free it with usb_free_noncoherent(). * + * Return: Either null (indicating no buffer could be allocated), or the + * cpu-space pointer to a buffer that may be used to perform DMA to the + * specified device. Such cpu-space buffers are returned along with the DMA + * address (through the pointer provided). */ -#if 0 -struct urb *usb_buffer_map(struct urb *urb) +void *usb_alloc_noncoherent(struct usb_device *dev, size_t size, + gfp_t mem_flags, dma_addr_t *dma, + enum dma_data_direction dir, + struct sg_table **table) { - struct usb_bus *bus; - struct device *controller; + struct device *dmadev; + struct sg_table *sgt; + void *buffer; - if (!urb - || !urb->dev - || !(bus = urb->dev->bus) - || !(controller = bus->sysdev)) + if (!dev || !dev->bus) return NULL; - if (controller->dma_mask) { - urb->transfer_dma = dma_map_single(controller, - urb->transfer_buffer, urb->transfer_buffer_length, - usb_pipein(urb->pipe) - ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - /* 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; - return urb; -} -EXPORT_SYMBOL_GPL(usb_buffer_map); -#endif /* 0 */ + dmadev = bus_to_hcd(dev->bus)->self.sysdev; -/* XXX DISABLED, no users currently. If you wish to re-enable this - * XXX please determine whether the sync is to transfer ownership of - * XXX the buffer from device to cpu or vice verse, and thusly use the - * XXX appropriate _for_{cpu,device}() method. -DaveM - */ -#if 0 - -/** - * usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s) - * @urb: urb whose transfer_buffer/setup_packet will be synchronized - */ -void usb_buffer_dmasync(struct urb *urb) -{ - struct usb_bus *bus; - struct device *controller; - - if (!urb - || !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) - || !urb->dev - || !(bus = urb->dev->bus) - || !(controller = bus->sysdev)) - return; + sgt = dma_alloc_noncontiguous(dmadev, size, dir, mem_flags, 0); + if (!sgt) + return NULL; - if (controller->dma_mask) { - dma_sync_single_for_cpu(controller, - urb->transfer_dma, urb->transfer_buffer_length, - usb_pipein(urb->pipe) - ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - if (usb_pipecontrol(urb->pipe)) - dma_sync_single_for_cpu(controller, - urb->setup_dma, - sizeof(struct usb_ctrlrequest), - DMA_TO_DEVICE); + buffer = dma_vmap_noncontiguous(dmadev, size, sgt); + if (!buffer) { + dma_free_noncontiguous(dmadev, size, sgt, dir); + return NULL; } -} -EXPORT_SYMBOL_GPL(usb_buffer_dmasync); -#endif -/** - * usb_buffer_unmap - free DMA mapping(s) for an urb - * @urb: urb whose transfer_buffer will be unmapped - * - * Reverses the effect of usb_buffer_map(). - */ -#if 0 -void usb_buffer_unmap(struct urb *urb) -{ - struct usb_bus *bus; - struct device *controller; - - if (!urb - || !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) - || !urb->dev - || !(bus = urb->dev->bus) - || !(controller = bus->sysdev)) - return; + *table = sgt; + *dma = sg_dma_address(sgt->sgl); - if (controller->dma_mask) { - dma_unmap_single(controller, - urb->transfer_dma, urb->transfer_buffer_length, - usb_pipein(urb->pipe) - ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - } - urb->transfer_flags &= ~URB_NO_TRANSFER_DMA_MAP; + return buffer; } -EXPORT_SYMBOL_GPL(usb_buffer_unmap); -#endif /* 0 */ +EXPORT_SYMBOL_GPL(usb_alloc_noncoherent); -#if 0 /** - * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint - * @dev: device to which the scatterlist will be mapped - * @is_in: mapping transfer direction - * @sg: the scatterlist to map - * @nents: the number of entries in the scatterlist - * - * Return: Either < 0 (indicating no buffers could be mapped), or the - * number of DMA mapping array entries in the scatterlist. - * - * Note: - * The caller is responsible for placing the resulting DMA addresses from - * the scatterlist into URB transfer buffer pointers, and for setting the - * URB_NO_TRANSFER_DMA_MAP transfer flag in each of those URBs. - * - * Top I/O rates come from queuing URBs, instead of waiting for each one - * to complete before starting the next I/O. This is particularly easy - * to do with scatterlists. Just allocate and submit one URB for each DMA - * mapping entry returned, stopping on the first error or when all succeed. - * Better yet, use the usb_sg_*() calls, which do that (and more) for you. - * - * This call would normally be used when translating scatterlist requests, - * rather than usb_buffer_map(), since on some hardware (with IOMMUs) it - * may be able to coalesce mappings for improved I/O efficiency. + * usb_free_noncoherent - free memory allocated with usb_alloc_noncoherent() + * @dev: device the buffer was used with + * @size: requested buffer size + * @addr: CPU address of buffer + * @dir: DMA transfer direction + * @table: describe the allocated and DMA mapped memory, * - * Reverse the effect of this call with usb_buffer_unmap_sg(). + * This reclaims an I/O buffer, letting it be reused. The memory must have + * been allocated using usb_alloc_noncoherent(), and the parameters must match + * those provided in that allocation request. */ -int usb_buffer_map_sg(const struct usb_device *dev, int is_in, - struct scatterlist *sg, int nents) +void usb_free_noncoherent(struct usb_device *dev, size_t size, + void *addr, enum dma_data_direction dir, + struct sg_table *table) { - struct usb_bus *bus; - struct device *controller; - - if (!dev - || !(bus = dev->bus) - || !(controller = bus->sysdev) - || !controller->dma_mask) - return -EINVAL; - - /* 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) ? : -ENOMEM; -} -EXPORT_SYMBOL_GPL(usb_buffer_map_sg); -#endif + struct device *dmadev; -/* XXX DISABLED, no users currently. If you wish to re-enable this - * XXX please determine whether the sync is to transfer ownership of - * XXX the buffer from device to cpu or vice verse, and thusly use the - * XXX appropriate _for_{cpu,device}() method. -DaveM - */ -#if 0 + if (!dev || !dev->bus) + return; + if (!addr) + return; + + dmadev = bus_to_hcd(dev->bus)->self.sysdev; + dma_vunmap_noncontiguous(dmadev, addr); + dma_free_noncontiguous(dmadev, size, table, dir); +} +EXPORT_SYMBOL_GPL(usb_free_noncoherent); /** - * usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s) - * @dev: device to which the scatterlist will be mapped - * @is_in: mapping transfer direction - * @sg: the scatterlist to synchronize - * @n_hw_ents: the positive return value from usb_buffer_map_sg + * usb_endpoint_max_periodic_payload - Get maximum payload bytes per service + * interval + * @udev: The USB device + * @ep: The endpoint * - * Use this when you are re-using a scatterlist's data buffers for - * another USB request. + * Returns: the maximum number of bytes isochronous or interrupt endpoint @ep + * can transfer during a service interval, or 0 for other endpoints. */ -void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in, - struct scatterlist *sg, int n_hw_ents) +u32 usb_endpoint_max_periodic_payload(struct usb_device *udev, + const struct usb_host_endpoint *ep) { - struct usb_bus *bus; - struct device *controller; - - if (!dev - || !(bus = dev->bus) - || !(controller = bus->sysdev) - || !controller->dma_mask) - return; + if (!usb_endpoint_xfer_isoc(&ep->desc) && + !usb_endpoint_xfer_int(&ep->desc)) + return 0; - dma_sync_sg_for_cpu(controller, sg, n_hw_ents, - is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + switch (udev->speed) { + case USB_SPEED_SUPER_PLUS: + if (USB_SS_SSP_ISOC_COMP(ep->ss_ep_comp.bmAttributes)) + return le32_to_cpu(ep->ssp_isoc_ep_comp.dwBytesPerInterval); + fallthrough; + case USB_SPEED_SUPER: + return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval); + default: + if (usb_endpoint_is_hs_isoc_double(udev, ep)) + return le32_to_cpu(ep->eusb2_isoc_ep_comp.dwBytesPerInterval); + return usb_endpoint_maxp(&ep->desc) * usb_endpoint_maxp_mult(&ep->desc); + } } -EXPORT_SYMBOL_GPL(usb_buffer_dmasync_sg); -#endif +EXPORT_SYMBOL_GPL(usb_endpoint_max_periodic_payload); -#if 0 /** - * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist - * @dev: device to which the scatterlist will be mapped - * @is_in: mapping transfer direction - * @sg: the scatterlist to unmap - * @n_hw_ents: the positive return value from usb_buffer_map_sg + * usb_endpoint_is_hs_isoc_double - Tell whether an endpoint uses USB 2 + * Isochronous Double IN Bandwidth + * @udev: The USB device + * @ep: The endpoint * - * Reverses the effect of usb_buffer_map_sg(). + * Returns: true if an endpoint @ep conforms to USB 2 Isochronous Double IN + * Bandwidth ECN, false otherwise. */ -void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in, - struct scatterlist *sg, int n_hw_ents) +bool usb_endpoint_is_hs_isoc_double(struct usb_device *udev, + const struct usb_host_endpoint *ep) { - struct usb_bus *bus; - struct device *controller; - - if (!dev - || !(bus = dev->bus) - || !(controller = bus->sysdev) - || !controller->dma_mask) - return; - - dma_unmap_sg(controller, sg, n_hw_ents, - is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + return ep->eusb2_isoc_ep_comp.bDescriptorType && + le16_to_cpu(udev->descriptor.bcdUSB) == 0x220 && + usb_endpoint_is_isoc_in(&ep->desc) && + !le16_to_cpu(ep->desc.wMaxPacketSize); } -EXPORT_SYMBOL_GPL(usb_buffer_unmap_sg); -#endif +EXPORT_SYMBOL_GPL(usb_endpoint_is_hs_isoc_double); /* * Notifications of device and interface registration @@ -1166,19 +1193,15 @@ static struct notifier_block usb_bus_nb = { .notifier_call = usb_bus_notify, }; -struct dentry *usb_debug_root; -EXPORT_SYMBOL_GPL(usb_debug_root); - static void usb_debugfs_init(void) { - usb_debug_root = debugfs_create_dir("usb", NULL); debugfs_create_file("devices", 0444, usb_debug_root, NULL, &usbfs_devices_fops); } static void usb_debugfs_cleanup(void) { - debugfs_remove_recursive(usb_debug_root); + debugfs_lookup_and_remove("devices", usb_debug_root); } /* @@ -1205,6 +1228,9 @@ static int __init usb_init(void) retval = usb_major_init(); if (retval) goto major_init_failed; + retval = class_register(&usbmisc_class); + if (retval) + goto class_register_failed; retval = usb_register(&usbfs_driver); if (retval) goto driver_register_failed; @@ -1224,6 +1250,8 @@ hub_init_failed: usb_devio_init_failed: usb_deregister(&usbfs_driver); driver_register_failed: + class_unregister(&usbmisc_class); +class_register_failed: usb_major_cleanup(); major_init_failed: bus_unregister_notifier(&usb_bus_type, &usb_bus_nb); @@ -1251,6 +1279,7 @@ static void __exit usb_exit(void) usb_deregister(&usbfs_driver); usb_devio_cleanup(); usb_hub_cleanup(); + class_unregister(&usbmisc_class); bus_unregister_notifier(&usb_bus_type, &usb_bus_nb); bus_unregister(&usb_bus_type); usb_acpi_unregister(); @@ -1260,4 +1289,5 @@ static void __exit usb_exit(void) subsys_initcall(usb_init); module_exit(usb_exit); +MODULE_DESCRIPTION("USB core host-side support"); MODULE_LICENSE("GPL"); |
