summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Hädicke <felixhaedicke@web.de>2016-06-22 01:12:08 +0200
committerFelipe Balbi <felipe.balbi@linux.intel.com>2016-08-25 12:13:17 +0300
commit1a00b457a5482c3822bfc0fd64c088b2dba93e26 (patch)
tree5fa3a86d38d3d521845a3b93ea9c83ec9d0f34a1
parent54dfce6d07b0391e23d006579bba488de4f7d6aa (diff)
usb: gadget: composite: let USB functions process ctrl reqs in cfg0
It can sometimes be necessary for gadget drivers to process non-standard control requests, which host devices can send without having sent USB_REQ_SET_CONFIGURATION. Therefore, the req_match() usb_function method is enhanced with the new parameter "config0". When a USB configuration is active, this parameter is false. When a non-core control request is processed in composite_setup(), without an active configuration, req_match() of the USB functions of all available configurations which implement this function, is called with config0=true. Then the control request gets processed by the first usb_function instance whose req_match() returns true. Signed-off-by: Felix Hädicke <felixhaedicke@web.de> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
-rw-r--r--drivers/usb/gadget/composite.c16
-rw-r--r--drivers/usb/gadget/function/f_fs.c9
-rw-r--r--drivers/usb/gadget/function/f_printer.c6
-rw-r--r--include/linux/usb/composite.h3
4 files changed, 24 insertions, 10 deletions
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 5ebe6af7976e..32176f779861 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1893,17 +1893,21 @@ unknown:
/* 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 (cdev->config) {
list_for_each_entry(f, &cdev->config->functions, list)
- if (f->req_match && f->req_match(f, ctrl))
+ if (f->req_match &&
+ f->req_match(f, ctrl, false))
goto try_fun_setup;
- f = NULL;
+ } else {
+ struct usb_configuration *c;
+ list_for_each_entry(c, &cdev->configs, list)
+ list_for_each_entry(f, &c->functions, list)
+ if (f->req_match &&
+ f->req_match(f, ctrl, true))
+ goto try_fun_setup;
}
+ f = NULL;
switch (ctrl->bRequestType & USB_RECIP_MASK) {
case USB_RECIP_INTERFACE:
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index d7acab873836..d8f46f6233ac 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -99,7 +99,8 @@ static void ffs_func_disable(struct usb_function *);
static int ffs_func_setup(struct usb_function *,
const struct usb_ctrlrequest *);
static bool ffs_func_req_match(struct usb_function *,
- const struct usb_ctrlrequest *);
+ const struct usb_ctrlrequest *,
+ bool config0);
static void ffs_func_suspend(struct usb_function *);
static void ffs_func_resume(struct usb_function *);
@@ -3136,10 +3137,14 @@ static int ffs_func_setup(struct usb_function *f,
}
static bool ffs_func_req_match(struct usb_function *f,
- const struct usb_ctrlrequest *creq)
+ const struct usb_ctrlrequest *creq,
+ bool config0)
{
struct ffs_function *func = ffs_func_from_usb(f);
+ if (config0)
+ return false;
+
switch (creq->bRequestType & USB_RECIP_MASK) {
case USB_RECIP_INTERFACE:
return ffs_func_revmap_intf(func,
diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c
index 64706a789580..0de36cda6e41 100644
--- a/drivers/usb/gadget/function/f_printer.c
+++ b/drivers/usb/gadget/function/f_printer.c
@@ -889,13 +889,17 @@ static void printer_soft_reset(struct printer_dev *dev)
/*-------------------------------------------------------------------------*/
static bool gprinter_req_match(struct usb_function *f,
- const struct usb_ctrlrequest *ctrl)
+ const struct usb_ctrlrequest *ctrl,
+ bool config0)
{
struct printer_dev *dev = func_to_printer(f);
u16 w_index = le16_to_cpu(ctrl->wIndex);
u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength);
+ if (config0)
+ return false;
+
if ((ctrl->bRequestType & USB_RECIP_MASK) != USB_RECIP_INTERFACE ||
(ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS)
return false;
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 2b81b24eb5aa..4616a49a1c2e 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -220,7 +220,8 @@ struct usb_function {
int (*setup)(struct usb_function *,
const struct usb_ctrlrequest *);
bool (*req_match)(struct usb_function *,
- const struct usb_ctrlrequest *);
+ const struct usb_ctrlrequest *,
+ bool config0);
void (*suspend)(struct usb_function *);
void (*resume)(struct usb_function *);