diff options
Diffstat (limited to 'drivers/usb/gadget/configfs.c')
-rw-r--r-- | drivers/usb/gadget/configfs.c | 81 |
1 files changed, 57 insertions, 24 deletions
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 54849fe9cb01..a2c14bb5efa4 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -8,6 +8,7 @@ #include "configfs.h" #include "u_f.h" #include "u_os_desc.h" +#include "debug.h" #ifdef CONFIG_USB_CONFIGFS_UEVENT #include <linux/platform_device.h> @@ -22,6 +23,7 @@ void acc_disconnect(void); static struct class *android_class; static struct device *android_device; static int index; +static int gadget_index; struct device *create_function_device(char *name) { @@ -140,21 +142,28 @@ struct gadget_config_name { struct list_head list; }; +#define MAX_USB_STRING_LEN 126 +#define MAX_USB_STRING_WITH_NULL_LEN (MAX_USB_STRING_LEN+1) + static int usb_string_copy(const char *s, char **s_copy) { int ret; char *str; char *copy = *s_copy; ret = strlen(s); - if (ret > 126) + if (ret > MAX_USB_STRING_LEN) return -EOVERFLOW; - str = kstrdup(s, GFP_KERNEL); - if (!str) - return -ENOMEM; + if (copy) { + str = copy; + } else { + str = kmalloc(MAX_USB_STRING_WITH_NULL_LEN, GFP_KERNEL); + if (!str) + return -ENOMEM; + } + strlcpy(str, s, MAX_USB_STRING_WITH_NULL_LEN); if (str[ret - 1] == '\n') str[ret - 1] = '\0'; - kfree(copy); *s_copy = str; return 0; } @@ -1251,7 +1260,7 @@ static void purge_configs_funcs(struct gadget_info *gi) list_move_tail(&f->list, &cfg->func_list); if (f->unbind) { dev_err(&gi->cdev.gadget->dev, "unbind function" - " '%s'/%p\n", f->name, f); + " '%s'/%pK\n", f->name, f); f->unbind(c, f); } } @@ -1431,28 +1440,28 @@ static void android_work(struct work_struct *data) spin_unlock_irqrestore(&cdev->lock, flags); if (status[0]) { - kobject_uevent_env(&android_device->kobj, + kobject_uevent_env(&gi->dev->kobj, KOBJ_CHANGE, connected); pr_info("%s: sent uevent %s\n", __func__, connected[0]); uevent_sent = true; } if (status[1]) { - kobject_uevent_env(&android_device->kobj, + kobject_uevent_env(&gi->dev->kobj, KOBJ_CHANGE, configured); pr_info("%s: sent uevent %s\n", __func__, configured[0]); uevent_sent = true; } if (status[2]) { - kobject_uevent_env(&android_device->kobj, + kobject_uevent_env(&gi->dev->kobj, KOBJ_CHANGE, disconnected); pr_info("%s: sent uevent %s\n", __func__, disconnected[0]); uevent_sent = true; } if (!uevent_sent) { - pr_info("%s: did not send uevent (%d %d %p)\n", __func__, + pr_info("%s: did not send uevent (%d %d %pK)\n", __func__, gi->connected, gi->sw_connected, cdev->config); } } @@ -1522,7 +1531,14 @@ static int android_setup(struct usb_gadget *gadget, static void android_disconnect(struct usb_gadget *gadget) { struct usb_composite_dev *cdev = get_gadget_data(gadget); - struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev); + struct gadget_info *gi; + + if (!cdev) { + pr_err("%s: gadget is not connected\n", __func__); + return; + } + + gi = container_of(cdev, struct gadget_info, cdev); /* accessory HID support can be active while the accessory function is not actually enabled, @@ -1598,23 +1614,28 @@ static int android_device_create(struct gadget_info *gi) { struct device_attribute **attrs; struct device_attribute *attr; + char str[10]; INIT_WORK(&gi->work, android_work); - android_device = device_create(android_class, NULL, - MKDEV(0, 0), NULL, "android0"); - if (IS_ERR(android_device)) - return PTR_ERR(android_device); + snprintf(str, sizeof(str), "android%d", gadget_index - 1); + pr_debug("Creating android device %s\n", str); + gi->dev = device_create(android_class, NULL, + MKDEV(0, 0), NULL, str); + if (IS_ERR(gi->dev)) + return PTR_ERR(gi->dev); - dev_set_drvdata(android_device, gi); + dev_set_drvdata(gi->dev, gi); + if (gadget_index == 1) + android_device = gi->dev; attrs = android_usb_attributes; while ((attr = *attrs++)) { int err; - err = device_create_file(android_device, attr); + err = device_create_file(gi->dev, attr); if (err) { - device_destroy(android_device->class, - android_device->devt); + device_destroy(gi->dev->class, + gi->dev->devt); return err; } } @@ -1622,15 +1643,15 @@ static int android_device_create(struct gadget_info *gi) return 0; } -static void android_device_destroy(void) +static void android_device_destroy(struct device *dev) { struct device_attribute **attrs; struct device_attribute *attr; attrs = android_usb_attributes; while ((attr = *attrs++)) - device_remove_file(android_device, attr); - device_destroy(android_device->class, android_device->devt); + device_remove_file(dev, attr); + device_destroy(dev->class, dev->devt); } #else static inline int android_device_create(struct gadget_info *gi) @@ -1638,7 +1659,7 @@ static inline int android_device_create(struct gadget_info *gi) return 0; } -static inline void android_device_destroy(void) +static inline void android_device_destroy(struct device *dev) { } #endif @@ -1690,6 +1711,8 @@ static struct config_group *gadgets_make( if (!gi->composite.gadget_driver.function) goto err; + gadget_index++; + pr_debug("Creating gadget index %d\n", gadget_index); if (android_device_create(gi) < 0) goto err; @@ -1704,8 +1727,14 @@ err: static void gadgets_drop(struct config_group *group, struct config_item *item) { + struct gadget_info *gi; + + gi = container_of(to_config_group(item), struct gadget_info, group); config_item_put(item); - android_device_destroy(); + if (gi->dev) { + android_device_destroy(gi->dev); + gi->dev = NULL; + } } static struct configfs_group_operations gadgets_ops = { @@ -1732,6 +1761,7 @@ void unregister_gadget_item(struct config_item *item) { struct gadget_info *gi = to_gadget_info(item); + /* to protect race with gadget_dev_desc_UDC_store*/ mutex_lock(&gi->lock); unregister_gadget(gi); mutex_unlock(&gi->lock); @@ -1744,6 +1774,8 @@ static int __init gadget_cfs_init(void) config_group_init(&gadget_subsys.su_group); + debug_debugfs_init(); + ret = configfs_register_subsystem(&gadget_subsys); #ifdef CONFIG_USB_CONFIGFS_UEVENT @@ -1758,6 +1790,7 @@ module_init(gadget_cfs_init); static void __exit gadget_cfs_exit(void) { + debug_debugfs_exit(); configfs_unregister_subsystem(&gadget_subsys); #ifdef CONFIG_USB_CONFIGFS_UEVENT if (!IS_ERR(android_class)) |