USB: gadget: Add ID numbers to gadget names
authorAlan Stern <stern@rowland.harvard.edu>
Tue, 10 May 2022 15:51:29 +0000 (11:51 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 11 May 2022 16:59:25 +0000 (18:59 +0200)
Putting USB gadgets on a new bus of their own encounters a problem
when multiple gadgets are present: They all have the same name!  The
driver core fails with a "sys: cannot create duplicate filename" error
when creating any of the /sys/bus/gadget/devices/<gadget-name>
symbolic links after the first.

This patch fixes the problem by adding a ".N" suffix to each gadget's
name when the gadget is registered (where N is a unique ID number),
thus making the names distinct.

Reported-and-tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Fixes: fc274c1e9973 ("USB: gadget: Add a new bus for gadgets")
Link: https://lore.kernel.org/r/YnqKAXKyp9Vq/pbn@rowland.harvard.edu
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/gadget/udc/core.c
include/linux/usb/gadget.h

index 3281d8a..7886497 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/list.h>
+#include <linux/idr.h>
 #include <linux/err.h>
 #include <linux/dma-mapping.h>
 #include <linux/sched/task_stack.h>
@@ -23,6 +24,8 @@
 
 #include "trace.h"
 
+static DEFINE_IDA(gadget_id_numbers);
+
 static struct bus_type gadget_bus_type;
 
 /**
@@ -1248,7 +1251,6 @@ static void usb_udc_nop_release(struct device *dev)
 void usb_initialize_gadget(struct device *parent, struct usb_gadget *gadget,
                void (*release)(struct device *dev))
 {
-       dev_set_name(&gadget->dev, "gadget");
        INIT_WORK(&gadget->work, usb_gadget_state_work);
        gadget->dev.parent = parent;
 
@@ -1304,12 +1306,21 @@ int usb_add_gadget(struct usb_gadget *gadget)
        usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
        udc->vbus = true;
 
+       ret = ida_alloc(&gadget_id_numbers, GFP_KERNEL);
+       if (ret < 0)
+               goto err_del_udc;
+       gadget->id_number = ret;
+       dev_set_name(&gadget->dev, "gadget.%d", ret);
+
        ret = device_add(&gadget->dev);
        if (ret)
-               goto err_del_udc;
+               goto err_free_id;
 
        return 0;
 
+ err_free_id:
+       ida_free(&gadget_id_numbers, gadget->id_number);
+
  err_del_udc:
        flush_work(&gadget->work);
        device_del(&udc->dev);
@@ -1417,6 +1428,7 @@ void usb_del_gadget(struct usb_gadget *gadget)
        kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
        flush_work(&gadget->work);
        device_del(&gadget->dev);
+       ida_free(&gadget_id_numbers, gadget->id_number);
        device_unregister(&udc->dev);
 }
 EXPORT_SYMBOL_GPL(usb_del_gadget);
index cf7af8a..3ad58b7 100644 (file)
@@ -386,6 +386,7 @@ struct usb_gadget_ops {
  * @lpm_capable: If the gadget max_speed is FULL or HIGH, this flag
  *     indicates that it supports LPM as per the LPM ECN & errata.
  * @irq: the interrupt number for device controller.
+ * @id_number: a unique ID number for ensuring that gadget names are distinct
  *
  * Gadgets have a mostly-portable "gadget driver" implementing device
  * functions, handling all usb configurations and interfaces.  Gadget
@@ -446,6 +447,7 @@ struct usb_gadget {
        unsigned                        connected:1;
        unsigned                        lpm_capable:1;
        int                             irq;
+       int                             id_number;
 };
 #define work_to_gadget(w)      (container_of((w), struct usb_gadget, work))