aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorDavid Brownell <dbrownell@users.sourceforge.net>2008-06-19 20:52:25 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2008-07-21 18:16:00 -0400
commita4c39c41bf3592684e36fa0dbbd4ab1a31f969b9 (patch)
tree548a902e3dc3999742fba83ff93c7584f995b73a /drivers/usb
parenta7707adf9ee8de3c5b67e3793b98888f551ad00d (diff)
usb gadget: descriptor copying support
Define three new descriptor manipulation utilities, for use when setting up functions that may have multiple instances: usb_copy_descriptors() to copy a vector of descriptors usb_free_descriptors() to free the copy usb_find_endpoint() to find a copied version These will be used as follows. Functions will continue to have static tables of descriptors they update, now used as __initdata templates. When a function creates a new instance, it patches those tables with relevant interface and string IDs, plus endpoint assignments. Then it copies those morphed descriptors, associates the copies with the new function instance, and records the endpoint descriptors to use when activating the endpoints. When initialization is done, only the copies remain in memory. The copies are freed on driver removal. This ensures that each instance has descriptors which hold the right instance-specific data. Two instances in the same configuration will obviously never share the same interface IDs or use the same endpoints. Instances in different configurations won't do so either, which means this is slightly less memory-efficient in some cases. This also includes a bugfix to the epautoconf code that shows up with this usage model. It must replace the previous endpoint number when updating the template descriptors, not just mask in a few more bits. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/gadget/config.c76
-rw-r--r--drivers/usb/gadget/epautoconf.c1
2 files changed, 76 insertions, 1 deletions
diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
index a4e54b2743f0..1ca1c326392a 100644
--- a/drivers/usb/gadget/config.c
+++ b/drivers/usb/gadget/config.c
@@ -96,7 +96,7 @@ int usb_gadget_config_buf(
96 /* config descriptor first */ 96 /* config descriptor first */
97 if (length < USB_DT_CONFIG_SIZE || !desc) 97 if (length < USB_DT_CONFIG_SIZE || !desc)
98 return -EINVAL; 98 return -EINVAL;
99 *cp = *config; 99 *cp = *config;
100 100
101 /* then interface/endpoint/class/vendor/... */ 101 /* then interface/endpoint/class/vendor/... */
102 len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf, 102 len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf,
@@ -115,3 +115,77 @@ int usb_gadget_config_buf(
115 return len; 115 return len;
116} 116}
117 117
118/**
119 * usb_copy_descriptors - copy a vector of USB descriptors
120 * @src: null-terminated vector to copy
121 * Context: initialization code, which may sleep
122 *
123 * This makes a copy of a vector of USB descriptors. Its primary use
124 * is to support usb_function objects which can have multiple copies,
125 * each needing different descriptors. Functions may have static
126 * tables of descriptors, which are used as templates and customized
127 * with identifiers (for interfaces, strings, endpoints, and more)
128 * as needed by a given function instance.
129 */
130struct usb_descriptor_header **__init
131usb_copy_descriptors(struct usb_descriptor_header **src)
132{
133 struct usb_descriptor_header **tmp;
134 unsigned bytes;
135 unsigned n_desc;
136 void *mem;
137 struct usb_descriptor_header **ret;
138
139 /* count descriptors and their sizes; then add vector size */
140 for (bytes = 0, n_desc = 0, tmp = src; *tmp; tmp++, n_desc++)
141 bytes += (*tmp)->bLength;
142 bytes += (n_desc + 1) * sizeof(*tmp);
143
144 mem = kmalloc(bytes, GFP_KERNEL);
145 if (!mem)
146 return NULL;
147
148 /* fill in pointers starting at "tmp",
149 * to descriptors copied starting at "mem";
150 * and return "ret"
151 */
152 tmp = mem;
153 ret = mem;
154 mem += (n_desc + 1) * sizeof(*tmp);
155 while (*src) {
156 memcpy(mem, *src, (*src)->bLength);
157 *tmp = mem;
158 tmp++;
159 mem += (*src)->bLength;
160 src++;
161 }
162 *tmp = NULL;
163
164 return ret;
165}
166
167/**
168 * usb_find_endpoint - find a copy of an endpoint descriptor
169 * @src: original vector of descriptors
170 * @copy: copy of @src
171 * @ep: endpoint descriptor found in @src
172 *
173 * This returns the copy of the @match descriptor made for @copy. Its
174 * intended use is to help remembering the endpoint descriptor to use
175 * when enabling a given endpoint.
176 */
177struct usb_endpoint_descriptor *__init
178usb_find_endpoint(
179 struct usb_descriptor_header **src,
180 struct usb_descriptor_header **copy,
181 struct usb_endpoint_descriptor *match
182)
183{
184 while (*src) {
185 if (*src == (void *) match)
186 return (void *)*copy;
187 src++;
188 copy++;
189 }
190 return NULL;
191}
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 8bdad221fa91..9462e30192d8 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -159,6 +159,7 @@ ep_matches (
159 /* MATCH!! */ 159 /* MATCH!! */
160 160
161 /* report address */ 161 /* report address */
162 desc->bEndpointAddress &= USB_DIR_IN;
162 if (isdigit (ep->name [2])) { 163 if (isdigit (ep->name [2])) {
163 u8 num = simple_strtol (&ep->name [2], NULL, 10); 164 u8 num = simple_strtol (&ep->name [2], NULL, 10);
164 desc->bEndpointAddress |= num; 165 desc->bEndpointAddress |= num;