Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 354655
b: refs/heads/master
c: 9bb2859
h: refs/heads/master
i:
  354653: 3fab725
  354651: c1ca84b
  354647: b2170d3
  354639: e600ee8
  354623: ef70e29
v: v3
  • Loading branch information
Sebastian Andrzej Siewior authored and Felipe Balbi committed Jan 21, 2013
1 parent f95cf8d commit e6cd390
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 2d5a88990260d226a69acddf22c04f47c267b33a
refs/heads/master: 9bb2859f8a8dbc9b42f3100641dd0ae80cfbe86a
135 changes: 135 additions & 0 deletions trunk/drivers/usb/gadget/composite.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@
* with the relevant device-wide data.
*/

static struct usb_gadget_strings **get_containers_gs(
struct usb_gadget_string_container *uc)
{
return (struct usb_gadget_strings **)uc->stash;
}

/**
* next_ep_desc() - advance to the next EP descriptor
* @t: currect pointer within descriptor array
Expand Down Expand Up @@ -904,6 +910,7 @@ static int get_string(struct usb_composite_dev *cdev,
void *buf, u16 language, int id)
{
struct usb_composite_driver *composite = cdev->driver;
struct usb_gadget_string_container *uc;
struct usb_configuration *c;
struct usb_function *f;
int len;
Expand Down Expand Up @@ -946,6 +953,15 @@ static int get_string(struct usb_composite_dev *cdev,
return s->bLength;
}

list_for_each_entry(uc, &cdev->gstrings, list) {
struct usb_gadget_strings **sp;

sp = get_containers_gs(uc);
len = lookup_string(sp, buf, language, id);
if (len > 0)
return len;
}

/* String IDs are device-scoped, so we look up each string
* table we're told about. These lookups are infrequent;
* simpler-is-better here.
Expand Down Expand Up @@ -1031,6 +1047,119 @@ int usb_string_ids_tab(struct usb_composite_dev *cdev, struct usb_string *str)
}
EXPORT_SYMBOL_GPL(usb_string_ids_tab);

static struct usb_gadget_string_container *copy_gadget_strings(
struct usb_gadget_strings **sp, unsigned n_gstrings,
unsigned n_strings)
{
struct usb_gadget_string_container *uc;
struct usb_gadget_strings **gs_array;
struct usb_gadget_strings *gs;
struct usb_string *s;
unsigned mem;
unsigned n_gs;
unsigned n_s;
void *stash;

mem = sizeof(*uc);
mem += sizeof(void *) * (n_gstrings + 1);
mem += sizeof(struct usb_gadget_strings) * n_gstrings;
mem += sizeof(struct usb_string) * (n_strings + 1) * (n_gstrings);
uc = kmalloc(mem, GFP_KERNEL);
if (!uc)
return ERR_PTR(-ENOMEM);
gs_array = get_containers_gs(uc);
stash = uc->stash;
stash += sizeof(void *) * (n_gstrings + 1);
for (n_gs = 0; n_gs < n_gstrings; n_gs++) {
struct usb_string *org_s;

gs_array[n_gs] = stash;
gs = gs_array[n_gs];
stash += sizeof(struct usb_gadget_strings);
gs->language = sp[n_gs]->language;
gs->strings = stash;
org_s = sp[n_gs]->strings;

for (n_s = 0; n_s < n_strings; n_s++) {
s = stash;
stash += sizeof(struct usb_string);
if (org_s->s)
s->s = org_s->s;
else
s->s = "";
org_s++;
}
s = stash;
s->s = NULL;
stash += sizeof(struct usb_string);

}
gs_array[n_gs] = NULL;
return uc;
}

/**
* usb_gstrings_attach() - attach gadget strings to a cdev and assign ids
* @cdev: the device whose string descriptor IDs are being allocated
* and attached.
* @sp: an array of usb_gadget_strings to attach.
* @n_strings: number of entries in each usb_strings array (sp[]->strings)
*
* This function will create a deep copy of usb_gadget_strings and usb_string
* and attach it to the cdev. The actual string (usb_string.s) will not be
* copied but only a referenced will be made. The struct usb_gadget_strings
* array may contain multiple languges and should be NULL terminated.
* The ->language pointer of each struct usb_gadget_strings has to contain the
* same amount of entries.
* For instance: sp[0] is en-US, sp[1] is es-ES. It is expected that the first
* usb_string entry of es-ES containts the translation of the first usb_string
* entry of en-US. Therefore both entries become the same id assign.
*/
struct usb_string *usb_gstrings_attach(struct usb_composite_dev *cdev,
struct usb_gadget_strings **sp, unsigned n_strings)
{
struct usb_gadget_string_container *uc;
struct usb_gadget_strings **n_gs;
unsigned n_gstrings = 0;
unsigned i;
int ret;

for (i = 0; sp[i]; i++)
n_gstrings++;

if (!n_gstrings)
return ERR_PTR(-EINVAL);

uc = copy_gadget_strings(sp, n_gstrings, n_strings);
if (IS_ERR(uc))
return ERR_PTR(PTR_ERR(uc));

n_gs = get_containers_gs(uc);
ret = usb_string_ids_tab(cdev, n_gs[0]->strings);
if (ret)
goto err;

for (i = 1; i < n_gstrings; i++) {
struct usb_string *m_s;
struct usb_string *s;
unsigned n;

m_s = n_gs[0]->strings;
s = n_gs[i]->strings;
for (n = 0; n < n_strings; n++) {
s->id = m_s->id;
s++;
m_s++;
}
}
list_add_tail(&uc->list, &cdev->gstrings);
return n_gs[0]->strings;
err:
kfree(uc);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(usb_gstrings_attach);

/**
* usb_string_ids_n() - allocate unused string IDs in batch
* @c: the device whose string descriptor IDs are being allocated
Expand Down Expand Up @@ -1377,6 +1506,7 @@ static DEVICE_ATTR(suspended, 0444, composite_show_suspended, NULL);
static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver)
{
struct usb_composite_dev *cdev = get_gadget_data(gadget);
struct usb_gadget_string_container *uc, *tmp;

/* composite_disconnect() must already have been called
* by the underlying peripheral controller driver!
Expand All @@ -1391,6 +1521,10 @@ static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver)
struct usb_configuration, list);
remove_config(cdev, c);
}
list_for_each_entry_safe(uc, tmp, &cdev->gstrings, list) {
list_del(&uc->list);
kfree(uc);
}
if (cdev->driver->unbind && unbind_driver)
cdev->driver->unbind(cdev);

Expand Down Expand Up @@ -1514,6 +1648,7 @@ static int composite_bind(struct usb_gadget *gadget,
cdev->gadget = gadget;
set_gadget_data(gadget, cdev);
INIT_LIST_HEAD(&cdev->configs);
INIT_LIST_HEAD(&cdev->gstrings);

status = composite_dev_prepare(composite, cdev);
if (status)
Expand Down
4 changes: 4 additions & 0 deletions trunk/include/linux/usb/composite.h
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ struct usb_composite_dev {
unsigned int suspended:1;
struct usb_device_descriptor desc;
struct list_head configs;
struct list_head gstrings;
struct usb_composite_driver *driver;
u8 next_string_id;
char *def_manufacturer;
Expand All @@ -396,6 +397,9 @@ struct usb_composite_dev {
extern int usb_string_id(struct usb_composite_dev *c);
extern int usb_string_ids_tab(struct usb_composite_dev *c,
struct usb_string *str);
extern struct usb_string *usb_gstrings_attach(struct usb_composite_dev *cdev,
struct usb_gadget_strings **sp, unsigned n_strings);

extern int usb_string_ids_n(struct usb_composite_dev *c, unsigned n);

extern void composite_disconnect(struct usb_gadget *gadget);
Expand Down
5 changes: 5 additions & 0 deletions trunk/include/linux/usb/gadget.h
Original file line number Diff line number Diff line change
Expand Up @@ -913,6 +913,11 @@ struct usb_gadget_strings {
struct usb_string *strings;
};

struct usb_gadget_string_container {
struct list_head list;
u8 *stash[0];
};

/* put descriptor for string with that id into buf (buflen >= 256) */
int usb_gadget_get_string(struct usb_gadget_strings *table, int id, u8 *buf);

Expand Down

0 comments on commit e6cd390

Please sign in to comment.