Provide interface for setting for_device function designated in a configuration for handling setup requests directed to device. Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@xxxxxxxxxxx> --- Documentation/ABI/testing/configfs-usb-gadget | 4 +++ drivers/usb/gadget/configfs.c | 49 +++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/Documentation/ABI/testing/configfs-usb-gadget b/Documentation/ABI/testing/configfs-usb-gadget index 95a3658..7f193ce 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget +++ b/Documentation/ABI/testing/configfs-usb-gadget @@ -39,6 +39,10 @@ Description: bmAttributes - configuration characteristics MaxPower - maximum power consumption from the bus + for_device - name of function to be used as the last + fallback when looking for setup request + handlers; the function must be one of + functions linked to this configuration What: /config/usb-gadget/gadget/configs/config/strings Date: Jun 2013 diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index d25f9f3..357f887 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -444,6 +444,8 @@ static int config_usb_cfg_unlink( list_for_each_entry(f, &cfg->func_list, list) { if (f->fi == fi) { + if (f == cfg->c.for_device) + cfg->c.for_device = NULL; list_del(&f->list); usb_put_function(f); mutex_unlock(&gi->lock); @@ -509,6 +511,51 @@ static ssize_t gadget_config_desc_bmAttributes_store(struct config_usb_cfg *cfg, return len; } +static ssize_t gadget_config_desc_for_device_show(struct config_usb_cfg *cfg, + char *page) +{ + return sprintf(page, "%s\n", cfg->c.for_device ? + cfg->c.for_device->fi->group.cg_item.ci_name : ""); +} + +static ssize_t gadget_config_desc_for_device_store(struct config_usb_cfg *cfg, + const char *page, size_t len) +{ + struct usb_composite_dev *cdev = cfg->c.cdev; + struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev); + struct usb_function *f = NULL; + ssize_t ret = -EBUSY; + char *name; + + name = kstrdup(page, GFP_KERNEL); + if (!name) + return -ENOMEM; + if (name[len - 1] == '\n') + name[len - 1] = '\0'; + + mutex_lock(&gi->lock); + if (gi->udc_name) + goto out; + + if (!len || !*page || *page == '\n') + goto set_ret; + + list_for_each_entry(f, &cfg->func_list, list) + if (!strncmp(f->fi->group.cg_item.ci_name, name, len)) + break; + if (&f->list == &cfg->func_list) { + ret = -EINVAL; + goto out; + } +set_ret: + ret = len; + cfg->c.for_device = f; +out: + mutex_unlock(&gi->lock); + kfree(name); + return ret; +} + #define CFG_CONFIG_DESC_ITEM_ATTR(name) \ static struct config_usb_cfg_attribute gadget_usb_cfg_##name = \ __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \ @@ -517,10 +564,12 @@ static ssize_t gadget_config_desc_bmAttributes_store(struct config_usb_cfg *cfg, CFG_CONFIG_DESC_ITEM_ATTR(MaxPower); CFG_CONFIG_DESC_ITEM_ATTR(bmAttributes); +CFG_CONFIG_DESC_ITEM_ATTR(for_device); static struct configfs_attribute *gadget_config_attrs[] = { &gadget_usb_cfg_MaxPower.attr, &gadget_usb_cfg_bmAttributes.attr, + &gadget_usb_cfg_for_device.attr, NULL, }; -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html