diff --git a/Documentation/ABI/testing/configfs-usb-gadget-rndis b/Documentation/ABI/testing/configfs-usb-gadget-rndis index e32879b84b4d..137399095d74 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-rndis +++ b/Documentation/ABI/testing/configfs-usb-gadget-rndis @@ -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) diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c index 16562e461121..e1d5853ef1e4 100644 --- a/drivers/usb/gadget/function/f_rndis.c +++ b/drivers/usb/gadget/function/f_rndis.c @@ -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, "", diff --git a/drivers/usb/gadget/function/u_ether_configfs.h b/drivers/usb/gadget/function/u_ether_configfs.h index c71133de17e7..e4c3f84af4c3 100644 --- a/drivers/usb/gadget/function/u_ether_configfs.h +++ b/drivers/usb/gadget/function/u_ether_configfs.h @@ -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 */ diff --git a/drivers/usb/gadget/function/u_rndis.h b/drivers/usb/gadget/function/u_rndis.h index 4eafd5050545..a35ee3c2545d 100644 --- a/drivers/usb/gadget/function/u_rndis.h +++ b/drivers/usb/gadget/function/u_rndis.h @@ -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. *