aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Michelau <john.michelau@motorola.com>2010-11-30 15:36:29 -0600
committerBenoit Goby <benoit@android.com>2010-12-03 16:31:42 -0800
commit8da1d5c2542e4adcb45c4e77d876852a6e1d8a47 (patch)
tree425c4c29d39c5a80b6953c826fcbfeb02a76da79
parenta6434b56160d7f8f794a4ba2f812b27452244ba8 (diff)
downloadqemu-8da1d5c2542e4adcb45c4e77d876852a6e1d8a47.tar.gz
usb: gadget: Fixed Android gadget function discovery & product matching
- Don't bind until all required functions have registered - Consider multi-instance functions when matching products Change-Id: I6fa10567db71d49cd81968c01d75e326ff9a17c8 Signed-off-by: John Michelau <john.michelau@motorola.com>
-rw-r--r--drivers/usb/gadget/android.c65
1 files changed, 56 insertions, 9 deletions
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index ed4f5739cb9..d9d4d2fd599 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);
}