aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2009-10-20 18:03:38 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-12-11 14:55:15 -0500
commit5242658d1b97771d658991cf29be32bcf81d5859 (patch)
treea2f5b2afd848619915aa8e1f3cfeb3c94289b20b
parent4de84057598599bbf90bf1deae923bc33f571475 (diff)
USB gadget: Handle endpoint requests at the function level
Control requests targeted at an endpoint (that is sent to EP0 but specifying the target endpoint address in wIndex) are dispatched to the current configuration's setup callback, requiring all gadget drivers to dispatch the requests to the correct function driver. To avoid this, record which endpoints are used by each function in the composite driver SET CONFIGURATION handler and dispatch requests targeted at endpoints to the correct function. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Cc: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/gadget/composite.c54
-rw-r--r--include/linux/usb/composite.h1
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
132int usb_add_function(struct usb_configuration *, struct usb_function *); 133int usb_add_function(struct usb_configuration *, struct usb_function *);