Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 85261924 authored by Ajay Agarwal's avatar Ajay Agarwal Committed by Todd Kjos
Browse files

ANDROID: usb: gadget: configfs: Support multiple android instances



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: 429213f5 ("ANDROID: usb: gadget: configfs: Add function devices to the parent")
Change-Id: Idae6f6d0d8811f27e836f5f6399395a15fbf3c2f
Signed-off-by: default avatarAjay Agarwal <ajaya@codeaurora.org>
[jackp@codeaurora.org: reworded commit text]
Signed-off-by: default avatarJack Pham <jackp@codeaurora.org>
parent ad5859c6
Loading
Loading
Loading
Loading
+22 −19
Original line number Diff line number Diff line
@@ -23,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)
{
@@ -1433,22 +1434,19 @@ 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;
	}

	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;
	}
@@ -1713,21 +1711,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;
		}
	}
@@ -1735,15 +1735,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)
@@ -1751,7 +1751,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
@@ -1819,8 +1819,11 @@ static struct config_group *gadgets_make(

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 = {