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 <felixhaedi...@web.de>
---
 drivers/usb/gadget/composite.c          | 16 ++++++++++------
 drivers/usb/gadget/function/f_fs.c      |  9 +++++++--
 drivers/usb/gadget/function/f_printer.c |  6 +++++-
 include/linux/usb/composite.h           |  3 ++-
 4 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 524e233..81ed5a8 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1872,17 +1872,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 9eb4003..4cf6efc 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 *);
 
@@ -3016,10 +3017,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 c45104e..aebffc6 100644
--- a/drivers/usb/gadget/function/f_printer.c
+++ b/drivers/usb/gadget/function/f_printer.c
@@ -897,13 +897,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 2b81b24..4616a49 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 *);
 
-- 
2.8.1

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

Reply via email to