diff options
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) | |||
373 | list_for_each_entry(f, &cdev->config->functions, list) { | 373 | list_for_each_entry(f, &cdev->config->functions, list) { |
374 | if (f->disable) | 374 | if (f->disable) |
375 | f->disable(f); | 375 | f->disable(f); |
376 | |||
377 | bitmap_zero(f->endpoints, 32); | ||
376 | } | 378 | } |
377 | cdev->config = NULL; | 379 | cdev->config = NULL; |
378 | } | 380 | } |
@@ -418,10 +420,35 @@ static int set_config(struct usb_composite_dev *cdev, | |||
418 | /* Initialize all interfaces by setting them to altsetting zero. */ | 420 | /* Initialize all interfaces by setting them to altsetting zero. */ |
419 | for (tmp = 0; tmp < MAX_CONFIG_INTERFACES; tmp++) { | 421 | for (tmp = 0; tmp < MAX_CONFIG_INTERFACES; tmp++) { |
420 | struct usb_function *f = c->interface[tmp]; | 422 | struct usb_function *f = c->interface[tmp]; |
423 | struct usb_descriptor_header **descriptors; | ||
421 | 424 | ||
422 | if (!f) | 425 | if (!f) |
423 | break; | 426 | break; |
424 | 427 | ||
428 | /* | ||
429 | * Record which endpoints are used by the function. This is used | ||
430 | * to dispatch control requests targeted at that endpoint to the | ||
431 | * function's setup callback instead of the current | ||
432 | * configuration's setup callback. | ||
433 | */ | ||
434 | if (gadget->speed == USB_SPEED_HIGH) | ||
435 | descriptors = f->hs_descriptors; | ||
436 | else | ||
437 | descriptors = f->descriptors; | ||
438 | |||
439 | for (; *descriptors; ++descriptors) { | ||
440 | struct usb_endpoint_descriptor *ep; | ||
441 | int addr; | ||
442 | |||
443 | if ((*descriptors)->bDescriptorType != USB_DT_ENDPOINT) | ||
444 | continue; | ||
445 | |||
446 | ep = (struct usb_endpoint_descriptor *)*descriptors; | ||
447 | addr = ((ep->bEndpointAddress & 0x80) >> 3) | ||
448 | | (ep->bEndpointAddress & 0x0f); | ||
449 | set_bit(addr, f->endpoints); | ||
450 | } | ||
451 | |||
425 | result = f->set_alt(f, tmp, 0); | 452 | result = f->set_alt(f, tmp, 0); |
426 | if (result < 0) { | 453 | if (result < 0) { |
427 | DBG(cdev, "interface %d (%s/%p) alt 0 --> %d\n", | 454 | 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) | |||
688 | u16 w_value = le16_to_cpu(ctrl->wValue); | 715 | u16 w_value = le16_to_cpu(ctrl->wValue); |
689 | u16 w_length = le16_to_cpu(ctrl->wLength); | 716 | u16 w_length = le16_to_cpu(ctrl->wLength); |
690 | struct usb_function *f = NULL; | 717 | struct usb_function *f = NULL; |
718 | u8 endp; | ||
691 | 719 | ||
692 | /* partial re-init of the response message; the function or the | 720 | /* partial re-init of the response message; the function or the |
693 | * gadget might need to intercept e.g. a control-OUT completion | 721 | * gadget might need to intercept e.g. a control-OUT completion |
@@ -800,23 +828,33 @@ unknown: | |||
800 | ctrl->bRequestType, ctrl->bRequest, | 828 | ctrl->bRequestType, ctrl->bRequest, |
801 | w_value, w_index, w_length); | 829 | w_value, w_index, w_length); |
802 | 830 | ||
803 | /* functions always handle their interfaces ... punt other | 831 | /* functions always handle their interfaces and endpoints... |
804 | * recipients (endpoint, other, WUSB, ...) to the current | 832 | * punt other recipients (other, WUSB, ...) to the current |
805 | * configuration code. | 833 | * configuration code. |
806 | * | 834 | * |
807 | * REVISIT it could make sense to let the composite device | 835 | * REVISIT it could make sense to let the composite device |
808 | * take such requests too, if that's ever needed: to work | 836 | * take such requests too, if that's ever needed: to work |
809 | * in config 0, etc. | 837 | * in config 0, etc. |
810 | */ | 838 | */ |
811 | if ((ctrl->bRequestType & USB_RECIP_MASK) | 839 | switch (ctrl->bRequestType & USB_RECIP_MASK) { |
812 | == USB_RECIP_INTERFACE) { | 840 | case USB_RECIP_INTERFACE: |
813 | f = cdev->config->interface[intf]; | 841 | f = cdev->config->interface[intf]; |
814 | if (f && f->setup) | 842 | break; |
815 | value = f->setup(f, ctrl); | 843 | |
816 | else | 844 | case USB_RECIP_ENDPOINT: |
845 | endp = ((w_index & 0x80) >> 3) | (w_index & 0x0f); | ||
846 | list_for_each_entry(f, &cdev->config->functions, list) { | ||
847 | if (test_bit(endp, f->endpoints)) | ||
848 | break; | ||
849 | } | ||
850 | if (&f->list == &cdev->config->functions) | ||
817 | f = NULL; | 851 | f = NULL; |
852 | break; | ||
818 | } | 853 | } |
819 | if (value < 0 && !f) { | 854 | |
855 | if (f && f->setup) | ||
856 | value = f->setup(f, ctrl); | ||
857 | else { | ||
820 | struct usb_configuration *c; | 858 | struct usb_configuration *c; |
821 | 859 | ||
822 | c = cdev->config; | 860 | c = cdev->config; |
@@ -1054,7 +1092,8 @@ static struct usb_gadget_driver composite_driver = { | |||
1054 | .speed = USB_SPEED_HIGH, | 1092 | .speed = USB_SPEED_HIGH, |
1055 | 1093 | ||
1056 | .bind = composite_bind, | 1094 | .bind = composite_bind, |
1057 | .unbind = __exit_p(composite_unbind), | 1095 | /* .unbind = __exit_p(composite_unbind), */ |
1096 | .unbind = composite_unbind, | ||
1058 | 1097 | ||
1059 | .setup = composite_setup, | 1098 | .setup = composite_setup, |
1060 | .disconnect = composite_disconnect, | 1099 | .disconnect = composite_disconnect, |
@@ -1103,7 +1142,7 @@ int __init usb_composite_register(struct usb_composite_driver *driver) | |||
1103 | * This function is used to unregister drivers using the composite | 1142 | * This function is used to unregister drivers using the composite |
1104 | * driver framework. | 1143 | * driver framework. |
1105 | */ | 1144 | */ |
1106 | void __exit usb_composite_unregister(struct usb_composite_driver *driver) | 1145 | void /* __exit */ usb_composite_unregister(struct usb_composite_driver *driver) |
1107 | { | 1146 | { |
1108 | if (composite != driver) | 1147 | if (composite != driver) |
1109 | return; | 1148 | return; |