Re: [RFC] Composite gadget: handle EP0 requests sent to endpoints down to functions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Friday 03 July 2009 11:43:02 Laurent Pinchart wrote:
> On Thursday 02 July 2009 17:37:08 Laurent Pinchart wrote:
> > Hi David,
> >
> > On Friday 19 June 2009 14:28:14 David Brownell wrote:
> > > On Friday 08 May 2009, Laurent Pinchart wrote:
> > > > Hi everybody,
> > > >
> > > > the USB composite gadget framework currently handles EP0 control
> > > > requests sent to endpoints (bRequestType[4..0] == USB_RECIP_ENDPOINT)
> > > > down to the current configuration EP0 request handler. Composite
> > > > drivers thus need to parse the request and call the appropriate
> > > > function handlers, making functions not self- contained.
> > > >
> > > > It should be possible to maintain an association between functions
> > > > and endpoints for each configuration, much like we already maintain
> > > > an association between functions and interfaces.
> > >
> > > Ideally something less pricey than an array of function pointers,
> > > indexed by endpoint ...  :)
> > >
> > > A per-function bitmap would suffice, and it's not like those calls
> > > are on critical paths.  Though I suppose the code to walk those
> > > bitmaps is likely to take as much space as the array-of-pointers.  ;)
> >
> > As the USB specification limits the number of endpoints to 32 (16 IN and
> > 16 OUT), this would cost 128 bytes on a 32 bit architecture (256 bytes on
> > a 64 bit architecture). The bitmap would take 4 (8) bytes, but would need
> > to be stored in the function instead of the configuration. If we assume
> > the device has two functions, function pointers have a data overhead of
> > 120 (240) bytes. Given the amount of code required to walk the bitmaps,
> > this might indeed be an overkill, but here you are :-) Could you please
> > review the following patch (based on 2.6.31-rc1) ?
>
> [snip]
>
> And obviously I forgot to include a very important part of the patch, which
> is the update of the per-function bitmap when allocating/deallocating an
> endpoint
>
> :-/ I'll resubmit a new patch soon.

soon = (schedule == AS_TIME_PERMITS) ? REALLY_LATE : NOT_SO_LATE;

:-S

Anyway, here's the new patch version (based on 2.6.31-rc5). I plan to submit a
fix to the audio gadget driver after getting this patch committed (and in this
case "soon" should keep it's normal meaning, as the patch is ready).

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 59e8523..897c2ed 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -688,6 +688,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 +801,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;
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index cd0914e..8640d1a 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -174,6 +174,7 @@ ep_matches (
 			return 0;
 		desc->bEndpointAddress |= epnum;
 	}
+	ep->addr = desc->bEndpointAddress;
 
 	/* report (variable) full speed bulk maxpacket */
 	if (USB_ENDPOINT_XFER_BULK == type) {
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 4f6bb3d..e7e8ab5 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -127,6 +127,7 @@ struct usb_function {
 	/* private: */
 	/* internals */
 	struct list_head		list;
+	DECLARE_BITMAP(endpoints, 32);
 };
 
 int usb_add_function(struct usb_configuration *, struct usb_function *);
@@ -134,6 +135,41 @@ int usb_add_function(struct usb_configuration *, struct usb_function *);
 int usb_function_deactivate(struct usb_function *);
 int usb_function_activate(struct usb_function *);
 
+/**
+ * usb_function_claim_endpoint - bind a function to an endpoint
+ * @f: the function to be bound
+ * @ep: the endpoint to which it will be bound
+ *
+ * This is used by usb function drivers to claim usage of an endpoint. Once
+ * the endpoint is claimed, all control requests targetted at that endpoint
+ * will be dispatched to the function's setup callback instead of the current
+ * configuration's setup callback.
+ */
+static inline void
+usb_function_claim_endpoint(struct usb_function *f, struct usb_ep *ep)
+{
+	int endp = ((ep->addr & 0x80) >> 3) | (ep->addr & 0x0f);
+	set_bit(endp, f->endpoints);
+}
+
+/**
+ * usb_function_release_endpoint - unbind a function from an endpoint
+ * @f: the function to be unbound
+ * @ep: the endpoint from which it will be unbound
+ *
+ * This is used by usb function drivers to release usage of an endpoint. After
+ * the endpoint is released, all control requests targetted at that endpoint
+ * will be dispatched back to current configuration's setup callback.
+ */
+static inline void
+usb_function_release_endpoint(struct usb_function *f, struct usb_ep *ep)
+{
+	if (ep) {
+		int endp = ((ep->addr & 0x80) >> 3) | (ep->addr & 0x0f);
+		clear_bit(endp, f->endpoints);
+	}
+}
+
 int usb_interface_id(struct usb_configuration *, struct usb_function *);
 
 /**
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index bbf45d5..3b74a6f 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -124,6 +124,7 @@ struct usb_ep_ops {
 /**
  * struct usb_ep - device side representation of USB endpoint
  * @name:identifier for the endpoint, such as "ep-a" or "ep9in-bulk"
+ * @addr:endpoint's address (direction and number)
  * @ops: Function pointers used to access hardware-specific operations.
  * @ep_list:the gadget's ep_list holds all of its endpoints
  * @maxpacket:The maximum packet size used on this endpoint.  The initial
@@ -140,6 +141,7 @@ struct usb_ep {
 	void			*driver_data;
 
 	const char		*name;
+	u8			addr;
 	const struct usb_ep_ops	*ops;
 	struct list_head	ep_list;
 	unsigned		maxpacket:16;


Best regards,

Laurent Pinchart

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux