aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>2012-12-23 15:10:22 -0500
committerFelipe Balbi <balbi@ti.com>2013-01-21 13:52:48 -0500
commit9bb2859f8a8dbc9b42f3100641dd0ae80cfbe86a (patch)
treef40927a9dcdc92325a30261f61b034084d3f6010
parent2d5a88990260d226a69acddf22c04f47c267b33a (diff)
usb: gadget: composite: introduce usb_gstrings_attach()
The USB strings don't (yet) fully work in multiple configs/gadget environment. The string id is assigned to the descriptor and the struct usb_strings. We create a copy of the individual descriptor so we don't clash if we use a function more than once. However, we have only one struct usb_string for each string. Currently each function which is used multiple times checks for "id != 0" and only assigns string ids if it did not happen yet. This works well if we use the same function multiple times as long as we do it within the "one" gadget we have. Trouble starts once we use the same function in a second gadget. In order to solve this I introduce usb_gstrings_attach(). This function will crate a copy all structs except for the strings which are not copied. After the copy it will assign USB ids and attach it to cdev. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r--drivers/usb/gadget/composite.c135
-rw-r--r--include/linux/usb/composite.h4
-rw-r--r--include/linux/usb/gadget.h5
3 files changed, 144 insertions, 0 deletions
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 8a1c3752f75f..9d7a1fabc482 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -28,6 +28,12 @@
28 * with the relevant device-wide data. 28 * with the relevant device-wide data.
29 */ 29 */
30 30
31static struct usb_gadget_strings **get_containers_gs(
32 struct usb_gadget_string_container *uc)
33{
34 return (struct usb_gadget_strings **)uc->stash;
35}
36
31/** 37/**
32 * next_ep_desc() - advance to the next EP descriptor 38 * next_ep_desc() - advance to the next EP descriptor
33 * @t: currect pointer within descriptor array 39 * @t: currect pointer within descriptor array
@@ -904,6 +910,7 @@ static int get_string(struct usb_composite_dev *cdev,
904 void *buf, u16 language, int id) 910 void *buf, u16 language, int id)
905{ 911{
906 struct usb_composite_driver *composite = cdev->driver; 912 struct usb_composite_driver *composite = cdev->driver;
913 struct usb_gadget_string_container *uc;
907 struct usb_configuration *c; 914 struct usb_configuration *c;
908 struct usb_function *f; 915 struct usb_function *f;
909 int len; 916 int len;
@@ -946,6 +953,15 @@ static int get_string(struct usb_composite_dev *cdev,
946 return s->bLength; 953 return s->bLength;
947 } 954 }
948 955
956 list_for_each_entry(uc, &cdev->gstrings, list) {
957 struct usb_gadget_strings **sp;
958
959 sp = get_containers_gs(uc);
960 len = lookup_string(sp, buf, language, id);
961 if (len > 0)
962 return len;
963 }
964
949 /* String IDs are device-scoped, so we look up each string 965 /* String IDs are device-scoped, so we look up each string
950 * table we're told about. These lookups are infrequent; 966 * table we're told about. These lookups are infrequent;
951 * simpler-is-better here. 967 * simpler-is-better here.
@@ -1031,6 +1047,119 @@ int usb_string_ids_tab(struct usb_composite_dev *cdev, struct usb_string *str)
1031} 1047}
1032EXPORT_SYMBOL_GPL(usb_string_ids_tab); 1048EXPORT_SYMBOL_GPL(usb_string_ids_tab);
1033 1049
1050static struct usb_gadget_string_container *copy_gadget_strings(
1051 struct usb_gadget_strings **sp, unsigned n_gstrings,
1052 unsigned n_strings)
1053{
1054 struct usb_gadget_string_container *uc;
1055 struct usb_gadget_strings **gs_array;
1056 struct usb_gadget_strings *gs;
1057 struct usb_string *s;
1058 unsigned mem;
1059 unsigned n_gs;
1060 unsigned n_s;
1061 void *stash;
1062
1063 mem = sizeof(*uc);
1064 mem += sizeof(void *) * (n_gstrings + 1);
1065 mem += sizeof(struct usb_gadget_strings) * n_gstrings;
1066 mem += sizeof(struct usb_string) * (n_strings + 1) * (n_gstrings);
1067 uc = kmalloc(mem, GFP_KERNEL);
1068 if (!uc)
1069 return ERR_PTR(-ENOMEM);
1070 gs_array = get_containers_gs(uc);
1071 stash = uc->stash;
1072 stash += sizeof(void *) * (n_gstrings + 1);
1073 for (n_gs = 0; n_gs < n_gstrings; n_gs++) {
1074 struct usb_string *org_s;
1075
1076 gs_array[n_gs] = stash;
1077 gs = gs_array[n_gs];
1078 stash += sizeof(struct usb_gadget_strings);
1079 gs->language = sp[n_gs]->language;
1080 gs->strings = stash;
1081 org_s = sp[n_gs]->strings;
1082
1083 for (n_s = 0; n_s < n_strings; n_s++) {
1084 s = stash;
1085 stash += sizeof(struct usb_string);
1086 if (org_s->s)
1087 s->s = org_s->s;
1088 else
1089 s->s = "";
1090 org_s++;
1091 }
1092 s = stash;
1093 s->s = NULL;
1094 stash += sizeof(struct usb_string);
1095
1096 }
1097 gs_array[n_gs] = NULL;
1098 return uc;
1099}
1100
1101/**
1102 * usb_gstrings_attach() - attach gadget strings to a cdev and assign ids
1103 * @cdev: the device whose string descriptor IDs are being allocated
1104 * and attached.
1105 * @sp: an array of usb_gadget_strings to attach.
1106 * @n_strings: number of entries in each usb_strings array (sp[]->strings)
1107 *
1108 * This function will create a deep copy of usb_gadget_strings and usb_string
1109 * and attach it to the cdev. The actual string (usb_string.s) will not be
1110 * copied but only a referenced will be made. The struct usb_gadget_strings
1111 * array may contain multiple languges and should be NULL terminated.
1112 * The ->language pointer of each struct usb_gadget_strings has to contain the
1113 * same amount of entries.
1114 * For instance: sp[0] is en-US, sp[1] is es-ES. It is expected that the first
1115 * usb_string entry of es-ES containts the translation of the first usb_string
1116 * entry of en-US. Therefore both entries become the same id assign.
1117 */
1118struct usb_string *usb_gstrings_attach(struct usb_composite_dev *cdev,
1119 struct usb_gadget_strings **sp, unsigned n_strings)
1120{
1121 struct usb_gadget_string_container *uc;
1122 struct usb_gadget_strings **n_gs;
1123 unsigned n_gstrings = 0;
1124 unsigned i;
1125 int ret;
1126
1127 for (i = 0; sp[i]; i++)
1128 n_gstrings++;
1129
1130 if (!n_gstrings)
1131 return ERR_PTR(-EINVAL);
1132
1133 uc = copy_gadget_strings(sp, n_gstrings, n_strings);
1134 if (IS_ERR(uc))
1135 return ERR_PTR(PTR_ERR(uc));
1136
1137 n_gs = get_containers_gs(uc);
1138 ret = usb_string_ids_tab(cdev, n_gs[0]->strings);
1139 if (ret)
1140 goto err;
1141
1142 for (i = 1; i < n_gstrings; i++) {
1143 struct usb_string *m_s;
1144 struct usb_string *s;
1145 unsigned n;
1146
1147 m_s = n_gs[0]->strings;
1148 s = n_gs[i]->strings;
1149 for (n = 0; n < n_strings; n++) {
1150 s->id = m_s->id;
1151 s++;
1152 m_s++;
1153 }
1154 }
1155 list_add_tail(&uc->list, &cdev->gstrings);
1156 return n_gs[0]->strings;
1157err:
1158 kfree(uc);
1159 return ERR_PTR(ret);
1160}
1161EXPORT_SYMBOL_GPL(usb_gstrings_attach);
1162
1034/** 1163/**
1035 * usb_string_ids_n() - allocate unused string IDs in batch 1164 * usb_string_ids_n() - allocate unused string IDs in batch
1036 * @c: the device whose string descriptor IDs are being allocated 1165 * @c: the device whose string descriptor IDs are being allocated
@@ -1377,6 +1506,7 @@ static DEVICE_ATTR(suspended, 0444, composite_show_suspended, NULL);
1377static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver) 1506static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver)
1378{ 1507{
1379 struct usb_composite_dev *cdev = get_gadget_data(gadget); 1508 struct usb_composite_dev *cdev = get_gadget_data(gadget);
1509 struct usb_gadget_string_container *uc, *tmp;
1380 1510
1381 /* composite_disconnect() must already have been called 1511 /* composite_disconnect() must already have been called
1382 * by the underlying peripheral controller driver! 1512 * by the underlying peripheral controller driver!
@@ -1391,6 +1521,10 @@ static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver)
1391 struct usb_configuration, list); 1521 struct usb_configuration, list);
1392 remove_config(cdev, c); 1522 remove_config(cdev, c);
1393 } 1523 }
1524 list_for_each_entry_safe(uc, tmp, &cdev->gstrings, list) {
1525 list_del(&uc->list);
1526 kfree(uc);
1527 }
1394 if (cdev->driver->unbind && unbind_driver) 1528 if (cdev->driver->unbind && unbind_driver)
1395 cdev->driver->unbind(cdev); 1529 cdev->driver->unbind(cdev);
1396 1530
@@ -1514,6 +1648,7 @@ static int composite_bind(struct usb_gadget *gadget,
1514 cdev->gadget = gadget; 1648 cdev->gadget = gadget;
1515 set_gadget_data(gadget, cdev); 1649 set_gadget_data(gadget, cdev);
1516 INIT_LIST_HEAD(&cdev->configs); 1650 INIT_LIST_HEAD(&cdev->configs);
1651 INIT_LIST_HEAD(&cdev->gstrings);
1517 1652
1518 status = composite_dev_prepare(composite, cdev); 1653 status = composite_dev_prepare(composite, cdev);
1519 if (status) 1654 if (status)
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index a212ec3e9d69..3c671c1b37f6 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -375,6 +375,7 @@ struct usb_composite_dev {
375 unsigned int suspended:1; 375 unsigned int suspended:1;
376 struct usb_device_descriptor desc; 376 struct usb_device_descriptor desc;
377 struct list_head configs; 377 struct list_head configs;
378 struct list_head gstrings;
378 struct usb_composite_driver *driver; 379 struct usb_composite_driver *driver;
379 u8 next_string_id; 380 u8 next_string_id;
380 char *def_manufacturer; 381 char *def_manufacturer;
@@ -396,6 +397,9 @@ struct usb_composite_dev {
396extern int usb_string_id(struct usb_composite_dev *c); 397extern int usb_string_id(struct usb_composite_dev *c);
397extern int usb_string_ids_tab(struct usb_composite_dev *c, 398extern int usb_string_ids_tab(struct usb_composite_dev *c,
398 struct usb_string *str); 399 struct usb_string *str);
400extern struct usb_string *usb_gstrings_attach(struct usb_composite_dev *cdev,
401 struct usb_gadget_strings **sp, unsigned n_strings);
402
399extern int usb_string_ids_n(struct usb_composite_dev *c, unsigned n); 403extern int usb_string_ids_n(struct usb_composite_dev *c, unsigned n);
400 404
401extern void composite_disconnect(struct usb_gadget *gadget); 405extern void composite_disconnect(struct usb_gadget *gadget);
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 62156701e4f1..e4c119ee4ebe 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -913,6 +913,11 @@ struct usb_gadget_strings {
913 struct usb_string *strings; 913 struct usb_string *strings;
914}; 914};
915 915
916struct usb_gadget_string_container {
917 struct list_head list;
918 u8 *stash[0];
919};
920
916/* put descriptor for string with that id into buf (buflen >= 256) */ 921/* put descriptor for string with that id into buf (buflen >= 256) */
917int usb_gadget_get_string(struct usb_gadget_strings *table, int id, u8 *buf); 922int usb_gadget_get_string(struct usb_gadget_strings *table, int id, u8 *buf);
918 923