usb: gadget: composite: let USB functions process ctrl reqs in cfg0
authorFelix Hädicke <felixhaedicke@web.de>
Tue, 21 Jun 2016 23:12:08 +0000 (01:12 +0200)
committerFelipe Balbi <felipe.balbi@linux.intel.com>
Thu, 25 Aug 2016 09:13:17 +0000 (12:13 +0300)
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>
drivers/usb/gadget/composite.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/function/f_printer.c
include/linux/usb/composite.h

index 5ebe6af7976ec4189363651dfe505cf6ec79fb12..32176f779861624578b47be6dd4975a269b7f664 100644 (file)
@@ -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:
index d7acab873836afb88fa34ffde23c838448e014bf..d8f46f6233aced7b274ecdf1ef09c20ff135984d 100644 (file)
@@ -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,
index 64706a789580dd3bb1641b151d15f0b0831c43ed..0de36cda6e4106156821e4d024c800cf6c4af206 100644 (file)
@@ -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;
index 2b81b24eb5aa30d852046d7ab8ef39d46145250d..4616a49a1c2e58c61e3bc602fa214e0be40f8820 100644 (file)
@@ -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 *);