summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIliyan Malchev <malchev@google.com>2010-12-06 18:22:59 -0800
committerIliyan Malchev <malchev@google.com>2010-12-06 18:22:59 -0800
commit8df654ec268e468cf5ee5736f576c9fdbe26c0c1 (patch)
tree11dad4ebb72e2edc56d15717bbbf69983880772c
parentb41914227e944b49368b07b043cda35cd21eefea (diff)
parent10a8f4d52e6260829374e304d091082bce5c2f7d (diff)
Merge remote branch 'common/android-2.6.36' into android-tegra-2.6.36
-rw-r--r--drivers/usb/gadget/android.c65
-rw-r--r--drivers/usb/gadget/f_acm.c40
-rw-r--r--drivers/usb/gadget/u_serial.c2
-rw-r--r--include/linux/usb/android_composite.h5
4 files changed, 98 insertions, 14 deletions
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index ed4f5739cb9c..d9d4d2fd5998 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -108,7 +108,7 @@ static struct usb_device_descriptor device_desc = {
};
static struct list_head _functions = LIST_HEAD_INIT(_functions);
-static int _registered_function_count = 0;
+static bool _are_functions_bound;
static struct android_usb_function *get_function(const char *name)
{
@@ -120,6 +120,50 @@ static struct android_usb_function *get_function(const char *name)
return 0;
}
+static bool are_functions_registered(struct android_dev *dev)
+{
+ char **functions = dev->functions;
+ int i;
+
+ /* Look only for functions required by the board config */
+ for (i = 0; i < dev->num_functions; i++) {
+ char *name = *functions++;
+ bool is_match = false;
+ /* Could reuse get_function() here, but a reverse search
+ * should yield less comparisons overall */
+ struct android_usb_function *f;
+ list_for_each_entry_reverse(f, &_functions, list) {
+ if (!strcmp(name, f->name)) {
+ is_match = true;
+ break;
+ }
+ }
+ if (is_match)
+ continue;
+ else
+ return false;
+ }
+
+ return true;
+}
+
+static bool should_bind_functions(struct android_dev *dev)
+{
+ /* Don't waste time if the main driver hasn't bound */
+ if (!dev->config)
+ return false;
+
+ /* Don't waste time if we've already bound the functions */
+ if (_are_functions_bound)
+ return false;
+
+ /* This call is the most costly, so call it last */
+ if (!are_functions_registered(dev))
+ return false;
+
+ return true;
+}
+
static void bind_functions(struct android_dev *dev)
{
struct android_usb_function *f;
@@ -134,6 +178,8 @@ static void bind_functions(struct android_dev *dev)
else
printk(KERN_ERR "function %s not found in bind_functions\n", name);
}
+
+ _are_functions_bound = true;
}
static int android_bind_config(struct usb_configuration *c)
@@ -143,8 +189,7 @@ static int android_bind_config(struct usb_configuration *c)
printk(KERN_DEBUG "android_bind_config\n");
dev->config = c;
- /* bind our functions if they have all registered */
- if (_registered_function_count == dev->num_functions)
+ if (should_bind_functions(dev))
bind_functions(dev);
return 0;
@@ -188,7 +233,13 @@ static int product_has_function(struct android_usb_product *p,
int i;
for (i = 0; i < count; i++) {
- if (!strcmp(name, *functions++))
+ /* For functions with multiple instances, usb_function.name
+ * will have an index appended to the core name (ex: acm0),
+ * while android_usb_product.functions[i] will only have the
+ * core name (ex: acm). So, only compare up to the length of
+ * android_usb_product.functions[i].
+ */
+ if (!strncmp(name, functions[i], strlen(functions[i])))
return 1;
}
return 0;
@@ -295,12 +346,8 @@ void android_register_function(struct android_usb_function *f)
printk(KERN_INFO "android_register_function %s\n", f->name);
list_add_tail(&f->list, &_functions);
- _registered_function_count++;
- /* bind our functions if they have all registered
- * and the main driver has bound.
- */
- if (dev && dev->config && _registered_function_count == dev->num_functions)
+ if (dev && should_bind_functions(dev))
bind_functions(dev);
}
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index e3e5410d922f..2d7fdcce310d 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -698,6 +698,7 @@ acm_unbind(struct usb_configuration *c, struct usb_function *f)
usb_free_descriptors(f->hs_descriptors);
usb_free_descriptors(f->descriptors);
gs_free_req(acm->notify, acm->notify_req);
+ kfree(acm->port.func.name);
kfree(acm);
}
@@ -769,7 +770,11 @@ int acm_bind_config(struct usb_configuration *c, u8 port_num)
acm->port.disconnect = acm_disconnect;
acm->port.send_break = acm_send_break;
- acm->port.func.name = "acm";
+ acm->port.func.name = kasprintf(GFP_KERNEL, "acm%u", port_num);
+ if (!acm->port.func.name) {
+ kfree(acm);
+ return -ENOMEM;
+ }
acm->port.func.strings = acm_strings;
/* descriptors are per-instance copies */
acm->port.func.bind = acm_bind;
@@ -785,12 +790,38 @@ int acm_bind_config(struct usb_configuration *c, u8 port_num)
}
#ifdef CONFIG_USB_ANDROID_ACM
+#include <linux/platform_device.h>
+
+static struct acm_platform_data *acm_pdata;
+
+static int acm_probe(struct platform_device *pdev)
+{
+ acm_pdata = pdev->dev.platform_data;
+ return 0;
+}
+
+static struct platform_driver acm_platform_driver = {
+ .driver = { .name = "acm", },
+ .probe = acm_probe,
+};
int acm_function_bind_config(struct usb_configuration *c)
{
- int ret = acm_bind_config(c, 0);
- if (ret == 0)
- gserial_setup(c->cdev->gadget, 1);
+ int i;
+ u8 num_inst = acm_pdata ? acm_pdata->num_inst : 1;
+ int ret = gserial_setup(c->cdev->gadget, num_inst);
+
+ if (ret)
+ return ret;
+
+ for (i = 0; i < num_inst; i++) {
+ ret = acm_bind_config(c, i);
+ if (ret) {
+ pr_err("Could not bind acm%u config\n", i);
+ break;
+ }
+ }
+
return ret;
}
@@ -802,6 +833,7 @@ static struct android_usb_function acm_function = {
static int __init init(void)
{
printk(KERN_INFO "f_acm init\n");
+ platform_driver_register(&acm_platform_driver);
android_register_function(&acm_function);
return 0;
}
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index 01e5354a4c20..fdc934523c0f 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -118,7 +118,7 @@ struct gs_port {
};
/* increase N_PORTS if you need more */
-#define N_PORTS 4
+#define N_PORTS 8
static struct portmaster {
struct mutex lock; /* protect open/close */
struct gs_port *port;
diff --git a/include/linux/usb/android_composite.h b/include/linux/usb/android_composite.h
index ac09dcb71775..62e72e3bd2b6 100644
--- a/include/linux/usb/android_composite.h
+++ b/include/linux/usb/android_composite.h
@@ -88,6 +88,11 @@ struct usb_ether_platform_data {
const char *vendorDescr;
};
+/* Platform data for ACM driver. */
+struct acm_platform_data {
+ u8 num_inst;
+};
+
extern void android_register_function(struct android_usb_function *f);
extern void android_enable_function(struct usb_function *f, int enable);