diff options
-rw-r--r-- | drivers/usb/gadget/composite.c | 54 | ||||
-rw-r--r-- | include/linux/usb/composite.h | 1 |
2 files changed, 47 insertions, 8 deletions
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index d05397ec8a18..8498f1a114d5 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; |
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 4f6bb3d2160e..738ea1a691cb 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h | |||
@@ -127,6 +127,7 @@ struct usb_function { | |||
127 | /* private: */ | 127 | /* private: */ |
128 | /* internals */ | 128 | /* internals */ |
129 | struct list_head list; | 129 | struct list_head list; |
130 | DECLARE_BITMAP(endpoints, 32); | ||
130 | }; | 131 | }; |
131 | 132 | ||
132 | int usb_add_function(struct usb_configuration *, struct usb_function *); | 133 | int usb_add_function(struct usb_configuration *, struct usb_function *); |