diff options
Diffstat (limited to 'drivers/usb/gadget/configfs.c')
| -rw-r--r-- | drivers/usb/gadget/configfs.c | 73 |
1 files changed, 53 insertions, 20 deletions
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 7e63dd7b3834..9ba61939eed6 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) { @@ -85,6 +87,7 @@ struct gadget_info { struct usb_composite_driver composite; struct usb_composite_dev cdev; bool use_os_desc; + bool unbinding; char b_vendor_code; char qw_sign[OS_STRING_QW_SIGN_LEN]; spinlock_t spinlock; @@ -282,9 +285,11 @@ static int unregister_gadget(struct gadget_info *gi) if (!gi->udc_name) return -ENODEV; + gi->unbinding = true; ret = usb_gadget_unregister_driver(&gi->composite.gadget_driver); if (ret) return ret; + gi->unbinding = false; kfree(gi->udc_name); gi->udc_name = NULL; return 0; @@ -1263,7 +1268,7 @@ static void purge_configs_funcs(struct gadget_info *gi) list_move(&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); } } @@ -1444,28 +1449,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); } } @@ -1496,6 +1501,7 @@ static void configfs_composite_unbind(struct usb_gadget *gadget) spin_unlock_irqrestore(&gi->spinlock, flags); } +#if !IS_ENABLED(CONFIG_USB_CONFIGFS_UEVENT) static int configfs_composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) { @@ -1542,6 +1548,7 @@ static void configfs_composite_disconnect(struct usb_gadget *gadget) composite_disconnect(gadget); spin_unlock_irqrestore(&gi->spinlock, flags); } +#endif static void configfs_composite_suspend(struct usb_gadget *gadget) { @@ -1632,7 +1639,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); /* FIXME: There's a race between usb_gadget_udc_stop() which is likely * to set the gadget driver to NULL in the udc driver and this drivers @@ -1655,7 +1669,8 @@ static void android_disconnect(struct usb_gadget *gadget) acc_disconnect(); #endif gi->connected = 0; - schedule_work(&gi->work); + if (!gi->unbinding) + schedule_work(&gi->work); composite_disconnect(gadget); } #endif @@ -1720,23 +1735,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; } } @@ -1744,15 +1764,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) @@ -1760,7 +1780,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 @@ -1799,6 +1819,7 @@ static struct config_group *gadgets_make( mutex_init(&gi->lock); INIT_LIST_HEAD(&gi->string_list); INIT_LIST_HEAD(&gi->available_func); + spin_lock_init(&gi->spinlock); composite_init_dev(&gi->cdev); gi->cdev.desc.bLength = USB_DT_DEVICE_SIZE; @@ -1813,6 +1834,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; @@ -1827,8 +1850,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 = { @@ -1855,6 +1884,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); @@ -1867,6 +1897,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 @@ -1881,6 +1913,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)) |
