usb: gadget: add RNDIS configfs options for class/subclass/protocol
authorDavid Lechner <david@lechnology.com>
Sun, 30 Jul 2017 01:12:57 +0000 (20:12 -0500)
committerFelipe Balbi <felipe.balbi@linux.intel.com>
Tue, 15 Aug 2017 11:18:56 +0000 (14:18 +0300)
This adds 3 new options to the RNDIS gadget function configs. It allows
overriding the default USB interface class/subclass/protocol.

The motivation for this is that if you set the values to "ef" (Misc),
"04" (RNDIS), "01" (Ethernet) respectively, then the device will be
recognized by the rndiscmp.inf file in Windows Vista and newer and will
cause Windows to load the correct RNDIS driver without the need for a
custom (signed) .inf file.

Signed-off-by: David Lechner <david@lechnology.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
Documentation/ABI/testing/configfs-usb-gadget-rndis
drivers/usb/gadget/function/f_rndis.c
drivers/usb/gadget/function/u_ether_configfs.h
drivers/usb/gadget/function/u_rndis.h

index e32879b84b4d092ffc3aa3c655c470ec5135c9fd..137399095d74b53540deed58ffc10b5329a97136 100644 (file)
@@ -12,3 +12,6 @@ Description:
                                Ethernet over USB link
                dev_addr        - MAC address of device's end of this
                                Ethernet over USB link
+               class           - USB interface class, default is 02 (hex)
+               subclass        - USB interface subclass, default is 06 (hex)
+               protocol        - USB interface protocol, default is 00 (hex)
index 16562e46112179b419a353a6508b6629c7d10d7e..e1d5853ef1e429743637ab546b229a02ee49245c 100644 (file)
@@ -691,6 +691,10 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
                f->os_desc_table[0].os_desc = &rndis_opts->rndis_os_desc;
        }
 
+       rndis_iad_descriptor.bFunctionClass = rndis_opts->class;
+       rndis_iad_descriptor.bFunctionSubClass = rndis_opts->subclass;
+       rndis_iad_descriptor.bFunctionProtocol = rndis_opts->protocol;
+
        /*
         * in drivers/usb/gadget/configfs.c:configfs_composite_bind()
         * configurations are bound in sequence with list_for_each_entry,
@@ -866,11 +870,23 @@ USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(rndis);
 /* f_rndis_opts_ifname */
 USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(rndis);
 
+/* f_rndis_opts_class */
+USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, class);
+
+/* f_rndis_opts_subclass */
+USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, subclass);
+
+/* f_rndis_opts_protocol */
+USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, protocol);
+
 static struct configfs_attribute *rndis_attrs[] = {
        &rndis_opts_attr_dev_addr,
        &rndis_opts_attr_host_addr,
        &rndis_opts_attr_qmult,
        &rndis_opts_attr_ifname,
+       &rndis_opts_attr_class,
+       &rndis_opts_attr_subclass,
+       &rndis_opts_attr_protocol,
        NULL,
 };
 
@@ -916,6 +932,10 @@ static struct usb_function_instance *rndis_alloc_inst(void)
        }
        INIT_LIST_HEAD(&opts->rndis_os_desc.ext_prop);
 
+       opts->class = rndis_iad_descriptor.bFunctionClass;
+       opts->subclass = rndis_iad_descriptor.bFunctionSubClass;
+       opts->protocol = rndis_iad_descriptor.bFunctionProtocol;
+
        descs[0] = &opts->rndis_os_desc;
        names[0] = "rndis";
        config_group_init_type_name(&opts->func_inst.group, "",
index c71133de17e71a950f532a7ab599a1c25abad705..e4c3f84af4c37d86fb0ca0905011dabbad751775 100644 (file)
@@ -153,4 +153,39 @@ out:                                                                       \
                                                                        \
        CONFIGFS_ATTR_RO(_f_##_opts_, ifname)
 
+#define USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(_f_, _n_)                   \
+       static ssize_t _f_##_opts_##_n_##_show(struct config_item *item,\
+                                              char *page)              \
+       {                                                               \
+               struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);  \
+               int ret;                                                \
+                                                                       \
+               mutex_lock(&opts->lock);                                \
+               ret = sprintf(page, "%02x\n", opts->_n_);               \
+               mutex_unlock(&opts->lock);                              \
+                                                                       \
+               return ret;                                             \
+       }                                                               \
+                                                                       \
+       static ssize_t _f_##_opts_##_n_##_store(struct config_item *item,\
+                                               const char *page,       \
+                                               size_t len)             \
+       {                                                               \
+               struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);  \
+               int ret;                                                \
+               u8 val;                                                 \
+                                                                       \
+               mutex_lock(&opts->lock);                                \
+               ret = sscanf(page, "%02hhx", &val);                     \
+               if (ret > 0) {                                          \
+                       opts->_n_ = val;                                \
+                       ret = len;                                      \
+               }                                                       \
+               mutex_unlock(&opts->lock);                              \
+                                                                       \
+               return ret;                                             \
+       }                                                               \
+                                                                       \
+       CONFIGFS_ATTR(_f_##_opts_, _n_)
+
 #endif /* __U_ETHER_CONFIGFS_H */
index 4eafd50505458cf10d2b58e48b8ba1dcd092ed4d..a35ee3c2545d9591aa4ef6b6b947cbedbe3f0093 100644 (file)
@@ -29,6 +29,10 @@ struct f_rndis_opts {
        struct usb_os_desc              rndis_os_desc;
        char                            rndis_ext_compat_id[16];
 
+       u8                              class;
+       u8                              subclass;
+       u8                              protocol;
+
        /*
         * Read/write access to configfs attributes is handled by configfs.
         *