diff options
Diffstat (limited to 'drivers/usb/gadget/f_subset.c')
-rw-r--r-- | drivers/usb/gadget/f_subset.c | 95 |
1 files changed, 71 insertions, 24 deletions
diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c index 8675ca415329..3dc53754ab60 100644 --- a/drivers/usb/gadget/f_subset.c +++ b/drivers/usb/gadget/f_subset.c | |||
@@ -57,18 +57,10 @@ | |||
57 | * caring about specific product and vendor IDs. | 57 | * caring about specific product and vendor IDs. |
58 | */ | 58 | */ |
59 | 59 | ||
60 | struct geth_descs { | ||
61 | struct usb_endpoint_descriptor *in; | ||
62 | struct usb_endpoint_descriptor *out; | ||
63 | }; | ||
64 | |||
65 | struct f_gether { | 60 | struct f_gether { |
66 | struct gether port; | 61 | struct gether port; |
67 | 62 | ||
68 | char ethaddr[14]; | 63 | char ethaddr[14]; |
69 | |||
70 | struct geth_descs fs; | ||
71 | struct geth_descs hs; | ||
72 | }; | 64 | }; |
73 | 65 | ||
74 | static inline struct f_gether *func_to_geth(struct usb_function *f) | 66 | static inline struct f_gether *func_to_geth(struct usb_function *f) |
@@ -209,6 +201,46 @@ static struct usb_descriptor_header *hs_eth_function[] __initdata = { | |||
209 | NULL, | 201 | NULL, |
210 | }; | 202 | }; |
211 | 203 | ||
204 | /* super speed support: */ | ||
205 | |||
206 | static struct usb_endpoint_descriptor ss_subset_in_desc __initdata = { | ||
207 | .bLength = USB_DT_ENDPOINT_SIZE, | ||
208 | .bDescriptorType = USB_DT_ENDPOINT, | ||
209 | |||
210 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
211 | .wMaxPacketSize = cpu_to_le16(1024), | ||
212 | }; | ||
213 | |||
214 | static struct usb_endpoint_descriptor ss_subset_out_desc __initdata = { | ||
215 | .bLength = USB_DT_ENDPOINT_SIZE, | ||
216 | .bDescriptorType = USB_DT_ENDPOINT, | ||
217 | |||
218 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
219 | .wMaxPacketSize = cpu_to_le16(1024), | ||
220 | }; | ||
221 | |||
222 | static struct usb_ss_ep_comp_descriptor ss_subset_bulk_comp_desc __initdata = { | ||
223 | .bLength = sizeof ss_subset_bulk_comp_desc, | ||
224 | .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, | ||
225 | |||
226 | /* the following 2 values can be tweaked if necessary */ | ||
227 | /* .bMaxBurst = 0, */ | ||
228 | /* .bmAttributes = 0, */ | ||
229 | }; | ||
230 | |||
231 | static struct usb_descriptor_header *ss_eth_function[] __initdata = { | ||
232 | (struct usb_descriptor_header *) &subset_data_intf, | ||
233 | (struct usb_descriptor_header *) &mdlm_header_desc, | ||
234 | (struct usb_descriptor_header *) &mdlm_desc, | ||
235 | (struct usb_descriptor_header *) &mdlm_detail_desc, | ||
236 | (struct usb_descriptor_header *) ðer_desc, | ||
237 | (struct usb_descriptor_header *) &ss_subset_in_desc, | ||
238 | (struct usb_descriptor_header *) &ss_subset_bulk_comp_desc, | ||
239 | (struct usb_descriptor_header *) &ss_subset_out_desc, | ||
240 | (struct usb_descriptor_header *) &ss_subset_bulk_comp_desc, | ||
241 | NULL, | ||
242 | }; | ||
243 | |||
212 | /* string descriptors: */ | 244 | /* string descriptors: */ |
213 | 245 | ||
214 | static struct usb_string geth_string_defs[] = { | 246 | static struct usb_string geth_string_defs[] = { |
@@ -243,10 +275,12 @@ static int geth_set_alt(struct usb_function *f, unsigned intf, unsigned alt) | |||
243 | } | 275 | } |
244 | 276 | ||
245 | DBG(cdev, "init + activate cdc subset\n"); | 277 | DBG(cdev, "init + activate cdc subset\n"); |
246 | geth->port.in = ep_choose(cdev->gadget, | 278 | if (config_ep_by_speed(cdev->gadget, f, geth->port.in_ep) || |
247 | geth->hs.in, geth->fs.in); | 279 | config_ep_by_speed(cdev->gadget, f, geth->port.out_ep)) { |
248 | geth->port.out = ep_choose(cdev->gadget, | 280 | geth->port.in_ep->desc = NULL; |
249 | geth->hs.out, geth->fs.out); | 281 | geth->port.out_ep->desc = NULL; |
282 | return -EINVAL; | ||
283 | } | ||
250 | 284 | ||
251 | net = gether_connect(&geth->port); | 285 | net = gether_connect(&geth->port); |
252 | return IS_ERR(net) ? PTR_ERR(net) : 0; | 286 | return IS_ERR(net) ? PTR_ERR(net) : 0; |
@@ -296,12 +330,8 @@ geth_bind(struct usb_configuration *c, struct usb_function *f) | |||
296 | 330 | ||
297 | /* copy descriptors, and track endpoint copies */ | 331 | /* copy descriptors, and track endpoint copies */ |
298 | f->descriptors = usb_copy_descriptors(fs_eth_function); | 332 | f->descriptors = usb_copy_descriptors(fs_eth_function); |
299 | 333 | if (!f->descriptors) | |
300 | geth->fs.in = usb_find_endpoint(fs_eth_function, | 334 | goto fail; |
301 | f->descriptors, &fs_subset_in_desc); | ||
302 | geth->fs.out = usb_find_endpoint(fs_eth_function, | ||
303 | f->descriptors, &fs_subset_out_desc); | ||
304 | |||
305 | 335 | ||
306 | /* support all relevant hardware speeds... we expect that when | 336 | /* support all relevant hardware speeds... we expect that when |
307 | * hardware is dual speed, all bulk-capable endpoints work at | 337 | * hardware is dual speed, all bulk-capable endpoints work at |
@@ -315,11 +345,20 @@ geth_bind(struct usb_configuration *c, struct usb_function *f) | |||
315 | 345 | ||
316 | /* copy descriptors, and track endpoint copies */ | 346 | /* copy descriptors, and track endpoint copies */ |
317 | f->hs_descriptors = usb_copy_descriptors(hs_eth_function); | 347 | f->hs_descriptors = usb_copy_descriptors(hs_eth_function); |
348 | if (!f->hs_descriptors) | ||
349 | goto fail; | ||
350 | } | ||
318 | 351 | ||
319 | geth->hs.in = usb_find_endpoint(hs_eth_function, | 352 | if (gadget_is_superspeed(c->cdev->gadget)) { |
320 | f->hs_descriptors, &hs_subset_in_desc); | 353 | ss_subset_in_desc.bEndpointAddress = |
321 | geth->hs.out = usb_find_endpoint(hs_eth_function, | 354 | fs_subset_in_desc.bEndpointAddress; |
322 | f->hs_descriptors, &hs_subset_out_desc); | 355 | ss_subset_out_desc.bEndpointAddress = |
356 | fs_subset_out_desc.bEndpointAddress; | ||
357 | |||
358 | /* copy descriptors, and track endpoint copies */ | ||
359 | f->ss_descriptors = usb_copy_descriptors(ss_eth_function); | ||
360 | if (!f->ss_descriptors) | ||
361 | goto fail; | ||
323 | } | 362 | } |
324 | 363 | ||
325 | /* NOTE: all that is done without knowing or caring about | 364 | /* NOTE: all that is done without knowing or caring about |
@@ -328,15 +367,21 @@ geth_bind(struct usb_configuration *c, struct usb_function *f) | |||
328 | */ | 367 | */ |
329 | 368 | ||
330 | DBG(cdev, "CDC Subset: %s speed IN/%s OUT/%s\n", | 369 | DBG(cdev, "CDC Subset: %s speed IN/%s OUT/%s\n", |
370 | gadget_is_superspeed(c->cdev->gadget) ? "super" : | ||
331 | gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", | 371 | gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", |
332 | geth->port.in_ep->name, geth->port.out_ep->name); | 372 | geth->port.in_ep->name, geth->port.out_ep->name); |
333 | return 0; | 373 | return 0; |
334 | 374 | ||
335 | fail: | 375 | fail: |
376 | if (f->descriptors) | ||
377 | usb_free_descriptors(f->descriptors); | ||
378 | if (f->hs_descriptors) | ||
379 | usb_free_descriptors(f->hs_descriptors); | ||
380 | |||
336 | /* we might as well release our claims on endpoints */ | 381 | /* we might as well release our claims on endpoints */ |
337 | if (geth->port.out) | 382 | if (geth->port.out_ep->desc) |
338 | geth->port.out_ep->driver_data = NULL; | 383 | geth->port.out_ep->driver_data = NULL; |
339 | if (geth->port.in) | 384 | if (geth->port.in_ep->desc) |
340 | geth->port.in_ep->driver_data = NULL; | 385 | geth->port.in_ep->driver_data = NULL; |
341 | 386 | ||
342 | ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); | 387 | ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); |
@@ -347,6 +392,8 @@ fail: | |||
347 | static void | 392 | static void |
348 | geth_unbind(struct usb_configuration *c, struct usb_function *f) | 393 | geth_unbind(struct usb_configuration *c, struct usb_function *f) |
349 | { | 394 | { |
395 | if (gadget_is_superspeed(c->cdev->gadget)) | ||
396 | usb_free_descriptors(f->ss_descriptors); | ||
350 | if (gadget_is_dualspeed(c->cdev->gadget)) | 397 | if (gadget_is_dualspeed(c->cdev->gadget)) |
351 | usb_free_descriptors(f->hs_descriptors); | 398 | usb_free_descriptors(f->hs_descriptors); |
352 | usb_free_descriptors(f->descriptors); | 399 | usb_free_descriptors(f->descriptors); |