Skip to content
This repository has been archived by the owner on Nov 8, 2023. It is now read-only.

Commit

Permalink
usb: gadget: Fixed Android gadget function discovery & product matching
Browse files Browse the repository at this point in the history
- 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>
  • Loading branch information
John Michelau authored and Dima Zavin committed Mar 29, 2011
1 parent 3fa64c7 commit 768b246
Showing 1 changed file with 56 additions and 9 deletions.
65 changes: 56 additions & 9 deletions drivers/usb/gadget/android.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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;
Expand All @@ -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)
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}

Expand Down

0 comments on commit 768b246

Please sign in to comment.