ANDROID: usb: gadget: configfs: Support multiple android instances 69/252669/1
authorAjay Agarwal <ajaya@codeaurora.org>
Tue, 30 May 2017 04:57:23 +0000 (10:27 +0530)
committerSeung-Woo Kim <sw0312.kim@samsung.com>
Mon, 1 Feb 2021 08:30:15 +0000 (17:30 +0900)
Some platforms may choose to create more than one gadget ConfigFS
instance, often due to the hardware having multiple USB gadget
controllers which can be used simultaneously. Currently
android_device_create() assumes only one gadget instance is ever
created and creates a single "android0" device under the "android_usb"
class, resulting in a crash if a second gadget is registered since the
global android_device pointer gets overwritten with -EEXIST.

Fix this by properly supporting multiple instances and naming the
devices "android0", "android1", etc. when each instance is created
(via mkdir). For now keep the global singleton android_device pointing
to android0 for ease of use since f_midi and f_audio_source currently
use create_function_device() without any context as to which gadget
they will be bound to.

Bug: 120441124
Fixes: 429213f5d9eb ("ANDROID: usb: gadget: configfs: Add function devices to the parent")
Signed-off-by: Ajay Agarwal <ajaya@codeaurora.org>
[jackp@codeaurora.org: reworded commit text]
Signed-off-by: Jack Pham <jackp@codeaurora.org>
[sw0312.kim: backport from android common kernel commit 852619242c94 to support multiple udc]
Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Change-Id: Iade5973db69a2a4a1800c8218b9f5fba6b59a1c8

drivers/usb/gadget/configfs.c

index 2a8528e..1f21941 100644 (file)
@@ -26,6 +26,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)
 {
@@ -1463,15 +1464,13 @@ static void android_work(struct work_struct *data)
        spin_unlock_irqrestore(&cdev->lock, flags);
 
        if (status[0]) {
-               kobject_uevent_env(&android_device->kobj,
-                                       KOBJ_CHANGE, connected);
+               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,
-                                       KOBJ_CHANGE, configured);
+               kobject_uevent_env(&gi->dev->kobj, KOBJ_CHANGE, configured);
                pr_info("%s: sent uevent %s\n", __func__, configured[0]);
                uevent_sent = true;
 #ifdef CONFIG_AMLOGIC_USB
@@ -1480,8 +1479,7 @@ static void android_work(struct work_struct *data)
        }
 
        if (status[2]) {
-               kobject_uevent_env(&android_device->kobj,
-                                       KOBJ_CHANGE, disconnected);
+               kobject_uevent_env(&gi->dev->kobj, KOBJ_CHANGE, disconnected);
                pr_info("%s: sent uevent %s\n", __func__, disconnected[0]);
                uevent_sent = true;
 #ifdef CONFIG_AMLOGIC_USB
@@ -1753,21 +1751,23 @@ static int android_device_create(struct gadget_info *gi)
        struct device_attribute *attr;
 
        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);
+       gi->dev = device_create(android_class, NULL,
+                       MKDEV(0, 0), NULL, "android%d", gadget_index++);
+       if (IS_ERR(gi->dev))
+               return PTR_ERR(gi->dev);
 
-       dev_set_drvdata(android_device, gi);
+       dev_set_drvdata(gi->dev, gi);
+       if (!android_device)
+               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;
                }
        }
@@ -1775,15 +1775,15 @@ static int android_device_create(struct gadget_info *gi)
        return 0;
 }
 
-static void android_device_destroy(void)
+static void android_device_destroy(struct gadget_info *gi)
 {
        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(gi->dev, attr);
+       device_destroy(gi->dev->class, gi->dev->devt);
 }
 #else
 static inline int android_device_create(struct gadget_info *gi)
@@ -1791,7 +1791,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 gadget_info *gi)
 {
 }
 #endif
@@ -1860,8 +1860,11 @@ 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();
+       android_device_destroy(gi);
 }
 
 static struct configfs_group_operations gadgets_ops = {