]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/usb/gadget/composite.c
USB: composite: usb_composite_unregister() no longer __exit
[net-next-2.6.git] / drivers / usb / gadget / composite.c
index d05397ec8a183ebb4467b10f55fe9b67e1cce189..09289bb1e20fcf984b388b32f55a6c404cc1dcb3 100644 (file)
@@ -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;