diff options
Diffstat (limited to 'drivers/usb')
59 files changed, 716 insertions, 543 deletions
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 89299a5ce16..0716cdb44cd 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -27,6 +27,8 @@ obj-$(CONFIG_USB_WUSB) += wusbcore/ obj-$(CONFIG_USB_ACM) += class/ obj-$(CONFIG_USB_PRINTER) += class/ +obj-$(CONFIG_USB_WDM) += class/ +obj-$(CONFIG_USB_TMC) += class/ obj-$(CONFIG_USB_STORAGE) += storage/ obj-$(CONFIG_USB) += storage/ diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 869d47cb6db..0a69c0977e3 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -546,10 +546,6 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) tty->driver_data = acm; acm->tty = tty; - /* force low_latency on so that our tty_push actually forces the data through, - otherwise it is scheduled, and with high data rates data can get lost. */ - tty->low_latency = 1; - if (usb_autopm_get_interface(acm->control) < 0) goto early_bail; else diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 3771d6e6d0c..0fe434505ac 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -3,7 +3,7 @@ * * This driver supports USB CDC WCM Device Management. * - * Copyright (c) 2007-2008 Oliver Neukum + * Copyright (c) 2007-2009 Oliver Neukum * * Some code taken from cdc-acm.c * @@ -610,7 +610,7 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id) if (!buffer) goto out; - while (buflen > 0) { + while (buflen > 2) { if (buffer [1] != USB_DT_CS_INTERFACE) { dev_err(&intf->dev, "skipping garbage\n"); goto next_desc; @@ -646,16 +646,18 @@ next_desc: spin_lock_init(&desc->iuspin); init_waitqueue_head(&desc->wait); desc->wMaxCommand = maxcom; + /* this will be expanded and needed in hardware endianness */ desc->inum = cpu_to_le16((u16)intf->cur_altsetting->desc.bInterfaceNumber); desc->intf = intf; INIT_WORK(&desc->rxwork, wdm_rxwork); - iface = &intf->altsetting[0]; + rv = -EINVAL; + iface = intf->cur_altsetting; + if (iface->desc.bNumEndpoints != 1) + goto err; ep = &iface->endpoint[0].desc; - if (!usb_endpoint_is_int_in(ep)) { - rv = -EINVAL; + if (!ep || !usb_endpoint_is_int_in(ep)) goto err; - } desc->wMaxPacketSize = le16_to_cpu(ep->wMaxPacketSize); desc->bMaxPacketSize0 = udev->descriptor.bMaxPacketSize0; @@ -711,12 +713,19 @@ next_desc: usb_set_intfdata(intf, desc); rv = usb_register_dev(intf, &wdm_class); - dev_info(&intf->dev, "cdc-wdm%d: USB WDM device\n", - intf->minor - WDM_MINOR_BASE); if (rv < 0) - goto err; + goto err3; + else + dev_info(&intf->dev, "cdc-wdm%d: USB WDM device\n", + intf->minor - WDM_MINOR_BASE); out: return rv; +err3: + usb_set_intfdata(intf, NULL); + usb_buffer_free(interface_to_usbdev(desc->intf), + desc->bMaxPacketSize0, + desc->inbuf, + desc->response->transfer_dma); err2: usb_buffer_free(interface_to_usbdev(desc->intf), desc->wMaxPacketSize, diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index cadb2dc1d28..3ba2fff7149 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -119,7 +119,7 @@ void *hcd_buffer_alloc( if (size <= pool_max [i]) return dma_pool_alloc(hcd->pool [i], mem_flags, dma); } - return dma_alloc_coherent(hcd->self.controller, size, dma, 0); + return dma_alloc_coherent(hcd->self.controller, size, dma, mem_flags); } void hcd_buffer_free( diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index df3c539f652..308609039c7 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -841,7 +841,7 @@ static int proc_resetep(struct dev_state *ps, void __user *arg) ret = checkintf(ps, ret); if (ret) return ret; - usb_settoggle(ps->dev, ep & 0xf, !(ep & USB_DIR_IN), 0); + usb_reset_endpoint(ps->dev, ep); return 0; } diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 81fa8506825..42b93da1085 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1539,6 +1539,32 @@ void usb_hcd_disable_endpoint(struct usb_device *udev, hcd->driver->endpoint_disable(hcd, ep); } +/** + * usb_hcd_reset_endpoint - reset host endpoint state + * @udev: USB device. + * @ep: the endpoint to reset. + * + * Resets any host endpoint state such as the toggle bit, sequence + * number and current window. + */ +void usb_hcd_reset_endpoint(struct usb_device *udev, + struct usb_host_endpoint *ep) +{ + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + + if (hcd->driver->endpoint_reset) + hcd->driver->endpoint_reset(hcd, ep); + else { + int epnum = usb_endpoint_num(&ep->desc); + int is_out = usb_endpoint_dir_out(&ep->desc); + int is_control = usb_endpoint_xfer_control(&ep->desc); + + usb_settoggle(udev, epnum, is_out, 0); + if (is_control) + usb_settoggle(udev, epnum, !is_out, 0); + } +} + /* Protect against drivers that try to unlink URBs after the device * is gone, by waiting until all unlinks for @udev are finished. * Since we don't currently track URBs by device, simply wait until diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index f750eb1ab59..e7d4479de41 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -206,6 +206,11 @@ struct hc_driver { void (*endpoint_disable)(struct usb_hcd *hcd, struct usb_host_endpoint *ep); + /* (optional) reset any endpoint state such as sequence number + and current window */ + void (*endpoint_reset)(struct usb_hcd *hcd, + struct usb_host_endpoint *ep); + /* root hub support */ int (*hub_status_data) (struct usb_hcd *hcd, char *buf); int (*hub_control) (struct usb_hcd *hcd, @@ -234,6 +239,8 @@ extern void usb_hcd_flush_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep); extern void usb_hcd_disable_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep); +extern void usb_hcd_reset_endpoint(struct usb_device *udev, + struct usb_host_endpoint *ep); extern void usb_hcd_synchronize_unlinks(struct usb_device *udev); extern int usb_hcd_get_frame_number(struct usb_device *udev); @@ -279,6 +286,13 @@ extern irqreturn_t usb_hcd_irq(int irq, void *__hcd); extern void usb_hc_died(struct usb_hcd *hcd); extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd); +/* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */ +#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1) +#define usb_dotoggle(dev, ep, out) ((dev)->toggle[out] ^= (1 << (ep))) +#define usb_settoggle(dev, ep, out, bit) \ + ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << (ep))) | \ + ((bit) << (ep))) + /* -------------------------------------------------------------------------- */ /* Enumeration is only for the hub driver, or HCD virtual root hubs */ diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 30a0690f368..b6262837765 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1002,8 +1002,7 @@ int usb_clear_halt(struct usb_device *dev, int pipe) * the copy in usb-storage, for as long as we need two copies. */ - /* toggle was reset by the clear */ - usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); + usb_reset_endpoint(dev, endp); return 0; } @@ -1076,6 +1075,30 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr, } /** + * usb_reset_endpoint - Reset an endpoint's state. + * @dev: the device whose endpoint is to be reset + * @epaddr: the endpoint's address. Endpoint number for output, + * endpoint number + USB_DIR_IN for input + * + * Resets any host-side endpoint state such as the toggle bit, + * sequence number or current window. + */ +void usb_reset_endpoint(struct usb_device *dev, unsigned int epaddr) +{ + unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK; + struct usb_host_endpoint *ep; + + if (usb_endpoint_out(epaddr)) + ep = dev->ep_out[epnum]; + else + ep = dev->ep_in[epnum]; + if (ep) + usb_hcd_reset_endpoint(dev, ep); +} +EXPORT_SYMBOL_GPL(usb_reset_endpoint); + + +/** * usb_disable_interface -- Disable all endpoints for an interface * @dev: the device whose interface is being disabled * @intf: pointer to the interface descriptor @@ -1117,7 +1140,6 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) usb_disable_endpoint(dev, i, true); usb_disable_endpoint(dev, i + USB_DIR_IN, true); } - dev->toggle[0] = dev->toggle[1] = 0; /* getting rid of interfaces will disconnect * any drivers bound to them (a key side effect) @@ -1154,28 +1176,24 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) * usb_enable_endpoint - Enable an endpoint for USB communications * @dev: the device whose interface is being enabled * @ep: the endpoint - * @reset_toggle: flag to set the endpoint's toggle back to 0 + * @reset_ep: flag to reset the endpoint state * - * Resets the endpoint toggle if asked, and sets dev->ep_{in,out} pointers. + * Resets the endpoint state if asked, and sets dev->ep_{in,out} pointers. * For control endpoints, both the input and output sides are handled. */ void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep, - bool reset_toggle) + bool reset_ep) { int epnum = usb_endpoint_num(&ep->desc); int is_out = usb_endpoint_dir_out(&ep->desc); int is_control = usb_endpoint_xfer_control(&ep->desc); - if (is_out || is_control) { - if (reset_toggle) - usb_settoggle(dev, epnum, 1, 0); + if (reset_ep) + usb_hcd_reset_endpoint(dev, ep); + if (is_out || is_control) dev->ep_out[epnum] = ep; - } - if (!is_out || is_control) { - if (reset_toggle) - usb_settoggle(dev, epnum, 0, 0); + if (!is_out || is_control) dev->ep_in[epnum] = ep; - } ep->enabled = 1; } @@ -1183,18 +1201,18 @@ void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep, * usb_enable_interface - Enable all the endpoints for an interface * @dev: the device whose interface is being enabled * @intf: pointer to the interface descriptor - * @reset_toggles: flag to set the endpoints' toggles back to 0 + * @reset_eps: flag to reset the endpoints' state * * Enables all the endpoints for the interface's current altsetting. */ void usb_enable_interface(struct usb_device *dev, - struct usb_interface *intf, bool reset_toggles) + struct usb_interface *intf, bool reset_eps) { struct usb_host_interface *alt = intf->cur_altsetting; int i; for (i = 0; i < alt->desc.bNumEndpoints; ++i) - usb_enable_endpoint(dev, &alt->endpoint[i], reset_toggles); + usb_enable_endpoint(dev, &alt->endpoint[i], reset_eps); } /** @@ -1335,7 +1353,7 @@ EXPORT_SYMBOL_GPL(usb_set_interface); * This issues a standard SET_CONFIGURATION request to the device using * the current configuration. The effect is to reset most USB-related * state in the device, including interface altsettings (reset to zero), - * endpoint halts (cleared), and data toggle (only for bulk and interrupt + * endpoint halts (cleared), and endpoint state (only for bulk and interrupt * endpoints). Other usbcore state is unchanged, including bindings of * usb device drivers to interfaces. * @@ -1343,7 +1361,7 @@ EXPORT_SYMBOL_GPL(usb_set_interface); * (multi-interface) devices. Instead, the driver for each interface may * use usb_set_interface() on the interfaces it claims. Be careful though; * some devices don't support the SET_INTERFACE request, and others won't - * reset all the interface state (notably data toggles). Resetting the whole + * reset all the interface state (notably endpoint state). Resetting the whole * configuration would affect other drivers' interfaces. * * The caller must own the device lock. @@ -1376,8 +1394,6 @@ int usb_reset_configuration(struct usb_device *dev) if (retval < 0) return retval; - dev->toggle[0] = dev->toggle[1] = 0; - /* re-init hc/hcd interface/endpoint state */ for (i = 0; i < config->desc.bNumInterfaces; i++) { struct usb_interface *intf = config->interface[i]; diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index dcfc072630c..7eee400d3e3 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -362,7 +362,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, 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, true); + usb_enable_endpoint(dev, &dev->ep0, false); dev->can_submit = 1; /* Save readable and stable topology id, distinguishing devices diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c index 22c65960c42..38e531ecae4 100644 --- a/drivers/usb/gadget/ci13xxx_udc.c +++ b/drivers/usb/gadget/ci13xxx_udc.c @@ -51,6 +51,7 @@ * - Gadget API (majority of optional features) * - Suspend & Remote Wakeup */ +#include <linux/delay.h> #include <linux/device.h> #include <linux/dmapool.h> #include <linux/dma-mapping.h> @@ -142,7 +143,7 @@ static struct { #define CAP_DEVICEADDR (0x014UL) #define CAP_ENDPTLISTADDR (0x018UL) #define CAP_PORTSC (0x044UL) -#define CAP_DEVLC (0x0B4UL) +#define CAP_DEVLC (0x084UL) #define CAP_USBMODE (hw_bank.lpm ? 0x0C8UL : 0x068UL) #define CAP_ENDPTSETUPSTAT (hw_bank.lpm ? 0x0D8UL : 0x06CUL) #define CAP_ENDPTPRIME (hw_bank.lpm ? 0x0DCUL : 0x070UL) @@ -1986,6 +1987,8 @@ static int ep_enable(struct usb_ep *ep, do { dbg_event(_usb_addr(mEp), "ENABLE", 0); + mEp->qh[mEp->dir].ptr->cap = 0; + if (mEp->type == USB_ENDPOINT_XFER_CONTROL) mEp->qh[mEp->dir].ptr->cap |= QH_IOS; else if (mEp->type == USB_ENDPOINT_XFER_ISOC) diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 5c030b080d4..381a53b3e11 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -738,7 +738,6 @@ static struct fsg_dev *the_fsg; static struct usb_gadget_driver fsg_driver; static void close_backing_file(struct lun *curlun); -static void close_all_backing_files(struct fsg_dev *fsg); /*-------------------------------------------------------------------------*/ @@ -3593,12 +3592,10 @@ static int fsg_main_thread(void *fsg_) fsg->thread_task = NULL; spin_unlock_irq(&fsg->lock); - /* In case we are exiting because of a signal, unregister the - * gadget driver and close the backing file. */ - if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) { + /* If we are exiting because of a signal, unregister the + * gadget driver. */ + if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) usb_gadget_unregister_driver(&fsg_driver); - close_all_backing_files(fsg); - } /* Let the unbind and cleanup routines know the thread has exited */ complete_and_exit(&fsg->thread_notifier, 0); @@ -3703,14 +3700,6 @@ static void close_backing_file(struct lun *curlun) } } -static void close_all_backing_files(struct fsg_dev *fsg) -{ - int i; - - for (i = 0; i < fsg->nluns; ++i) - close_backing_file(&fsg->luns[i]); -} - static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char *buf) { @@ -3845,6 +3834,7 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) if (curlun->registered) { device_remove_file(&curlun->dev, &dev_attr_ro); device_remove_file(&curlun->dev, &dev_attr_file); + close_backing_file(curlun); device_unregister(&curlun->dev); curlun->registered = 0; } @@ -4190,7 +4180,6 @@ autoconf_fail: out: fsg->state = FSG_STATE_TERMINATED; // The thread is dead fsg_unbind(gadget); - close_all_backing_files(fsg); complete(&fsg->thread_notifier); return rc; } @@ -4284,7 +4273,6 @@ static void __exit fsg_cleanup(void) /* Wait for the thread to finish up */ wait_for_completion(&fsg->thread_notifier); - close_all_backing_files(fsg); kref_put(&fsg->ref, fsg_release); } module_exit(fsg_cleanup); diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 57d9641c6bf..a2db0e174f2 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -3104,7 +3104,6 @@ static int omap_udc_resume(struct platform_device *dev) /*-------------------------------------------------------------------------*/ static struct platform_driver udc_driver = { - .probe = omap_udc_probe, .remove = __exit_p(omap_udc_remove), .suspend = omap_udc_suspend, .resume = omap_udc_resume, @@ -3122,7 +3121,7 @@ static int __init udc_init(void) #endif "%s\n", driver_desc, use_dma ? " (dma)" : ""); - return platform_driver_register(&udc_driver); + return platform_driver_probe(&udc_driver, omap_udc_probe); } module_init(udc_init); diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 96d65ca06ec..4007770f7ed 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -175,12 +175,6 @@ static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p) strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof p->bus_info); } -static u32 eth_get_link(struct net_device *net) -{ - struct eth_dev *dev = netdev_priv(net); - return dev->gadget->speed != USB_SPEED_UNKNOWN; -} - /* REVISIT can also support: * - WOL (by tracking suspends and issuing remote wakeup) * - msglevel (implies updated messaging) @@ -189,7 +183,7 @@ static u32 eth_get_link(struct net_device *net) static struct ethtool_ops ops = { .get_drvinfo = eth_get_drvinfo, - .get_link = eth_get_link + .get_link = ethtool_op_get_link, }; static void defer_kevent(struct eth_dev *dev, int flag) diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c index 4154be375c7..58c4d37d312 100644 --- a/drivers/usb/gadget/usbstring.c +++ b/drivers/usb/gadget/usbstring.c @@ -38,7 +38,7 @@ static int utf8_to_utf16le(const char *s, __le16 *cp, unsigned len) uchar = (c & 0x1f) << 6; c = (u8) *s++; - if ((c & 0xc0) != 0xc0) + if ((c & 0xc0) != 0x80) goto fail; c &= 0x3f; uchar |= c; @@ -49,13 +49,13 @@ static int utf8_to_utf16le(const char *s, __le16 *cp, unsigned len) uchar = (c & 0x0f) << 12; c = (u8) *s++; - if ((c & 0xc0) != 0xc0) + if ((c & 0xc0) != 0x80) goto fail; c &= 0x3f; uchar |= c << 6; c = (u8) *s++; - if ((c & 0xc0) != 0xc0) + if ((c & 0xc0) != 0x80) goto fail; c &= 0x3f; uchar |= c; diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index ada5d2ba297..556d0ec0c1f 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -323,7 +323,7 @@ static int tt_available ( * already scheduled transactions */ if (125 < usecs) { - int ufs = (usecs / 125) - 1; + int ufs = (usecs / 125); int i; for (i = uframe; i < (uframe + ufs) && i < 8; i++) if (0 < tt_usecs[i]) { diff --git a/drivers/usb/host/whci/asl.c b/drivers/usb/host/whci/asl.c index 958751ccea4..c2050785a81 100644 --- a/drivers/usb/host/whci/asl.c +++ b/drivers/usb/host/whci/asl.c @@ -122,7 +122,8 @@ static uint32_t process_qset(struct whc *whc, struct whc_qset *qset) process_inactive_qtd(whc, qset, td); } - update |= qset_add_qtds(whc, qset); + if (!qset->remove) + update |= qset_add_qtds(whc, qset); done: /* @@ -254,23 +255,29 @@ int asl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags) spin_lock_irqsave(&whc->lock, flags); + err = usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb); + if (err < 0) { + spin_unlock_irqrestore(&whc->lock, flags); + return err; + } + qset = get_qset(whc, urb, GFP_ATOMIC); if (qset == NULL) err = -ENOMEM; else err = qset_add_urb(whc, qset, urb, GFP_ATOMIC); if (!err) { - usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb); if (!qset->in_sw_list) asl_qset_insert_begin(whc, qset); - } + } else + usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb); spin_unlock_irqrestore(&whc->lock, flags); if (!err) queue_work(whc->workqueue, &whc->async_work); - return 0; + return err; } /** diff --git a/drivers/usb/host/whci/hcd.c b/drivers/usb/host/whci/hcd.c index 1569afd6245..e019a5058ab 100644 --- a/drivers/usb/host/whci/hcd.c +++ b/drivers/usb/host/whci/hcd.c @@ -186,6 +186,28 @@ static void whc_endpoint_disable(struct usb_hcd *usb_hcd, } } +static void whc_endpoint_reset(struct usb_hcd *usb_hcd, + struct usb_host_endpoint *ep) +{ |