summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/configfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/configfs.c')
-rw-r--r--drivers/usb/gadget/configfs.c81
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))