diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-12 02:22:55 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-12 02:22:55 +0300 |
commit | 748e566b7e24541e05e3e70be311887a1262f2a1 (patch) | |
tree | 41cc3a9aa04918cc17efa575baf6dbf87f40ddba /drivers/usb/gadget/composite.c | |
parent | 5f1141eb352ea79d849920039503e40dd623fffa (diff) | |
parent | acf509ae28301d78b022c534c26b1e4765c18f2b (diff) | |
download | linux-748e566b7e24541e05e3e70be311887a1262f2a1.tar.xz |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (122 commits)
USB: mos7840: add device IDs for B&B electronics devices
USB: ftdi_sio: add USB device ID's for B&B Electronics line
USB: musb: musb_host: fix sparse warning
USB: musb: musb_gadget: fix sparse warning
USB: musb: omap2430: fix sparse warning
USB: core: message: fix sparse warning
USB: core: hub: fix sparse warning
USB: core: fix sparse warning for static function
USB: Added USB_ETH_RNDIS to use instead of CONFIG_USB_ETH_RNDIS
USB: Check bandwidth when switching alt settings.
USB: Refactor code to find alternate interface settings.
USB: xhci: Fix command completion after a drop endpoint.
USB: xhci: Make reverting an alt setting "unfailable".
USB: usbtmc: Use usb_clear_halt() instead of custom code.
USB: xhci: Add correct email and files to MAINTAINERS entry.
USB: ehci-omap.c: introduce missing kfree
USB: xhci-mem.c: introduce missing kfree
USB: add remove_id sysfs attr for usb drivers
USB: g_multi kconfig: fix depends and help text
USB: option: add pid for ZTE
...
Diffstat (limited to 'drivers/usb/gadget/composite.c')
-rw-r--r-- | drivers/usb/gadget/composite.c | 59 |
1 files changed, 49 insertions, 10 deletions
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index d05397ec8a18..09289bb1e20f 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -373,6 +373,8 @@ static void reset_config(struct usb_composite_dev *cdev) list_for_each_entry(f, &cdev->config->functions, list) { if (f->disable) f->disable(f); + + bitmap_zero(f->endpoints, 32); } cdev->config = NULL; } @@ -418,10 +420,35 @@ static int set_config(struct usb_composite_dev *cdev, /* Initialize all interfaces by setting them to altsetting zero. */ for (tmp = 0; tmp < MAX_CONFIG_INTERFACES; tmp++) { struct usb_function *f = c->interface[tmp]; + struct usb_descriptor_header **descriptors; if (!f) break; + /* + * Record which endpoints are used by the function. This is used + * to dispatch control requests targeted at that endpoint to the + * function's setup callback instead of the current + * configuration's setup callback. + */ + if (gadget->speed == USB_SPEED_HIGH) + descriptors = f->hs_descriptors; + else + descriptors = f->descriptors; + + for (; *descriptors; ++descriptors) { + struct usb_endpoint_descriptor *ep; + int addr; + + if ((*descriptors)->bDescriptorType != USB_DT_ENDPOINT) + continue; + + ep = (struct usb_endpoint_descriptor *)*descriptors; + addr = ((ep->bEndpointAddress & 0x80) >> 3) + | (ep->bEndpointAddress & 0x0f); + set_bit(addr, f->endpoints); + } + result = f->set_alt(f, tmp, 0); if (result < 0) { DBG(cdev, "interface %d (%s/%p) alt 0 --> %d\n", @@ -688,6 +715,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) u16 w_value = le16_to_cpu(ctrl->wValue); u16 w_length = le16_to_cpu(ctrl->wLength); struct usb_function *f = NULL; + u8 endp; /* partial re-init of the response message; the function or the * gadget might need to intercept e.g. a control-OUT completion @@ -800,23 +828,33 @@ unknown: ctrl->bRequestType, ctrl->bRequest, w_value, w_index, w_length); - /* functions always handle their interfaces ... punt other - * recipients (endpoint, other, WUSB, ...) to the current + /* functions always handle their interfaces and endpoints... + * punt other recipients (other, WUSB, ...) to the current * configuration code. * * REVISIT it could make sense to let the composite device * take such requests too, if that's ever needed: to work * in config 0, etc. */ - if ((ctrl->bRequestType & USB_RECIP_MASK) - == USB_RECIP_INTERFACE) { + switch (ctrl->bRequestType & USB_RECIP_MASK) { + case USB_RECIP_INTERFACE: f = cdev->config->interface[intf]; - if (f && f->setup) - value = f->setup(f, ctrl); - else + break; + + case USB_RECIP_ENDPOINT: + endp = ((w_index & 0x80) >> 3) | (w_index & 0x0f); + list_for_each_entry(f, &cdev->config->functions, list) { + if (test_bit(endp, f->endpoints)) + break; + } + if (&f->list == &cdev->config->functions) f = NULL; + break; } - if (value < 0 && !f) { + + if (f && f->setup) + value = f->setup(f, ctrl); + else { struct usb_configuration *c; c = cdev->config; @@ -1054,7 +1092,8 @@ static struct usb_gadget_driver composite_driver = { .speed = USB_SPEED_HIGH, .bind = composite_bind, - .unbind = __exit_p(composite_unbind), + /* .unbind = __exit_p(composite_unbind), */ + .unbind = composite_unbind, .setup = composite_setup, .disconnect = composite_disconnect, @@ -1103,7 +1142,7 @@ int __init usb_composite_register(struct usb_composite_driver *driver) * This function is used to unregister drivers using the composite * driver framework. */ -void __exit usb_composite_unregister(struct usb_composite_driver *driver) +void /* __exit */ usb_composite_unregister(struct usb_composite_driver *driver) { if (composite != driver) return; |