diff options
Diffstat (limited to 'drivers/usb/gadget/composite.c')
-rw-r--r-- | drivers/usb/gadget/composite.c | 363 |
1 files changed, 339 insertions, 24 deletions
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 5cbb1a41c223..5ef87794fd32 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c | |||
@@ -27,7 +27,7 @@ | |||
27 | #include <linux/utsname.h> | 27 | #include <linux/utsname.h> |
28 | 28 | ||
29 | #include <linux/usb/composite.h> | 29 | #include <linux/usb/composite.h> |
30 | 30 | #include <asm/unaligned.h> | |
31 | 31 | ||
32 | /* | 32 | /* |
33 | * The code in this file is utility code, used to build a gadget driver | 33 | * The code in this file is utility code, used to build a gadget driver |
@@ -74,6 +74,130 @@ MODULE_PARM_DESC(iSerialNumber, "SerialNumber string"); | |||
74 | static char composite_manufacturer[50]; | 74 | static char composite_manufacturer[50]; |
75 | 75 | ||
76 | /*-------------------------------------------------------------------------*/ | 76 | /*-------------------------------------------------------------------------*/ |
77 | /** | ||
78 | * next_ep_desc() - advance to the next EP descriptor | ||
79 | * @t: currect pointer within descriptor array | ||
80 | * | ||
81 | * Return: next EP descriptor or NULL | ||
82 | * | ||
83 | * Iterate over @t until either EP descriptor found or | ||
84 | * NULL (that indicates end of list) encountered | ||
85 | */ | ||
86 | static struct usb_descriptor_header** | ||
87 | next_ep_desc(struct usb_descriptor_header **t) | ||
88 | { | ||
89 | for (; *t; t++) { | ||
90 | if ((*t)->bDescriptorType == USB_DT_ENDPOINT) | ||
91 | return t; | ||
92 | } | ||
93 | return NULL; | ||
94 | } | ||
95 | |||
96 | /* | ||
97 | * for_each_ep_desc()- iterate over endpoint descriptors in the | ||
98 | * descriptors list | ||
99 | * @start: pointer within descriptor array. | ||
100 | * @ep_desc: endpoint descriptor to use as the loop cursor | ||
101 | */ | ||
102 | #define for_each_ep_desc(start, ep_desc) \ | ||
103 | for (ep_desc = next_ep_desc(start); \ | ||
104 | ep_desc; ep_desc = next_ep_desc(ep_desc+1)) | ||
105 | |||
106 | /** | ||
107 | * config_ep_by_speed() - configures the given endpoint | ||
108 | * according to gadget speed. | ||
109 | * @g: pointer to the gadget | ||
110 | * @f: usb function | ||
111 | * @_ep: the endpoint to configure | ||
112 | * | ||
113 | * Return: error code, 0 on success | ||
114 | * | ||
115 | * This function chooses the right descriptors for a given | ||
116 | * endpoint according to gadget speed and saves it in the | ||
117 | * endpoint desc field. If the endpoint already has a descriptor | ||
118 | * assigned to it - overwrites it with currently corresponding | ||
119 | * descriptor. The endpoint maxpacket field is updated according | ||
120 | * to the chosen descriptor. | ||
121 | * Note: the supplied function should hold all the descriptors | ||
122 | * for supported speeds | ||
123 | */ | ||
124 | int config_ep_by_speed(struct usb_gadget *g, | ||
125 | struct usb_function *f, | ||
126 | struct usb_ep *_ep) | ||
127 | { | ||
128 | struct usb_endpoint_descriptor *chosen_desc = NULL; | ||
129 | struct usb_descriptor_header **speed_desc = NULL; | ||
130 | |||
131 | struct usb_ss_ep_comp_descriptor *comp_desc = NULL; | ||
132 | int want_comp_desc = 0; | ||
133 | |||
134 | struct usb_descriptor_header **d_spd; /* cursor for speed desc */ | ||
135 | |||
136 | if (!g || !f || !_ep) | ||
137 | return -EIO; | ||
138 | |||
139 | /* select desired speed */ | ||
140 | switch (g->speed) { | ||
141 | case USB_SPEED_SUPER: | ||
142 | if (gadget_is_superspeed(g)) { | ||
143 | speed_desc = f->ss_descriptors; | ||
144 | want_comp_desc = 1; | ||
145 | break; | ||
146 | } | ||
147 | /* else: Fall trough */ | ||
148 | case USB_SPEED_HIGH: | ||
149 | if (gadget_is_dualspeed(g)) { | ||
150 | speed_desc = f->hs_descriptors; | ||
151 | break; | ||
152 | } | ||
153 | /* else: fall through */ | ||
154 | default: | ||
155 | speed_desc = f->descriptors; | ||
156 | } | ||
157 | /* find descriptors */ | ||
158 | for_each_ep_desc(speed_desc, d_spd) { | ||
159 | chosen_desc = (struct usb_endpoint_descriptor *)*d_spd; | ||
160 | if (chosen_desc->bEndpointAddress == _ep->address) | ||
161 | goto ep_found; | ||
162 | } | ||
163 | return -EIO; | ||
164 | |||
165 | ep_found: | ||
166 | /* commit results */ | ||
167 | _ep->maxpacket = le16_to_cpu(chosen_desc->wMaxPacketSize); | ||
168 | _ep->desc = chosen_desc; | ||
169 | _ep->comp_desc = NULL; | ||
170 | _ep->maxburst = 0; | ||
171 | _ep->mult = 0; | ||
172 | if (!want_comp_desc) | ||
173 | return 0; | ||
174 | |||
175 | /* | ||
176 | * Companion descriptor should follow EP descriptor | ||
177 | * USB 3.0 spec, #9.6.7 | ||
178 | */ | ||
179 | comp_desc = (struct usb_ss_ep_comp_descriptor *)*(++d_spd); | ||
180 | if (!comp_desc || | ||
181 | (comp_desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP)) | ||
182 | return -EIO; | ||
183 | _ep->comp_desc = comp_desc; | ||
184 | if (g->speed == USB_SPEED_SUPER) { | ||
185 | switch (usb_endpoint_type(_ep->desc)) { | ||
186 | case USB_ENDPOINT_XFER_BULK: | ||
187 | case USB_ENDPOINT_XFER_INT: | ||
188 | _ep->maxburst = comp_desc->bMaxBurst; | ||
189 | break; | ||
190 | case USB_ENDPOINT_XFER_ISOC: | ||
191 | /* mult: bits 1:0 of bmAttributes */ | ||
192 | _ep->mult = comp_desc->bmAttributes & 0x3; | ||
193 | break; | ||
194 | default: | ||
195 | /* Do nothing for control endpoints */ | ||
196 | break; | ||
197 | } | ||
198 | } | ||
199 | return 0; | ||
200 | } | ||
77 | 201 | ||
78 | /** | 202 | /** |
79 | * usb_add_function() - add a function to a configuration | 203 | * usb_add_function() - add a function to a configuration |
@@ -123,6 +247,8 @@ int usb_add_function(struct usb_configuration *config, | |||
123 | config->fullspeed = true; | 247 | config->fullspeed = true; |
124 | if (!config->highspeed && function->hs_descriptors) | 248 | if (!config->highspeed && function->hs_descriptors) |
125 | config->highspeed = true; | 249 | config->highspeed = true; |
250 | if (!config->superspeed && function->ss_descriptors) | ||
251 | config->superspeed = true; | ||
126 | 252 | ||
127 | done: | 253 | done: |
128 | if (value) | 254 | if (value) |
@@ -266,10 +392,17 @@ static int config_buf(struct usb_configuration *config, | |||
266 | list_for_each_entry(f, &config->functions, list) { | 392 | list_for_each_entry(f, &config->functions, list) { |
267 | struct usb_descriptor_header **descriptors; | 393 | struct usb_descriptor_header **descriptors; |
268 | 394 | ||
269 | if (speed == USB_SPEED_HIGH) | 395 | switch (speed) { |
396 | case USB_SPEED_SUPER: | ||
397 | descriptors = f->ss_descriptors; | ||
398 | break; | ||
399 | case USB_SPEED_HIGH: | ||
270 | descriptors = f->hs_descriptors; | 400 | descriptors = f->hs_descriptors; |
271 | else | 401 | break; |
402 | default: | ||
272 | descriptors = f->descriptors; | 403 | descriptors = f->descriptors; |
404 | } | ||
405 | |||
273 | if (!descriptors) | 406 | if (!descriptors) |
274 | continue; | 407 | continue; |
275 | status = usb_descriptor_fillbuf(next, len, | 408 | status = usb_descriptor_fillbuf(next, len, |
@@ -292,9 +425,10 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value) | |||
292 | u8 type = w_value >> 8; | 425 | u8 type = w_value >> 8; |
293 | enum usb_device_speed speed = USB_SPEED_UNKNOWN; | 426 | enum usb_device_speed speed = USB_SPEED_UNKNOWN; |
294 | 427 | ||
295 | if (gadget_is_dualspeed(gadget)) { | 428 | if (gadget->speed == USB_SPEED_SUPER) |
296 | int hs = 0; | 429 | speed = gadget->speed; |
297 | 430 | else if (gadget_is_dualspeed(gadget)) { | |
431 | int hs = 0; | ||
298 | if (gadget->speed == USB_SPEED_HIGH) | 432 | if (gadget->speed == USB_SPEED_HIGH) |
299 | hs = 1; | 433 | hs = 1; |
300 | if (type == USB_DT_OTHER_SPEED_CONFIG) | 434 | if (type == USB_DT_OTHER_SPEED_CONFIG) |
@@ -308,13 +442,20 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value) | |||
308 | w_value &= 0xff; | 442 | w_value &= 0xff; |
309 | list_for_each_entry(c, &cdev->configs, list) { | 443 | list_for_each_entry(c, &cdev->configs, list) { |
310 | /* ignore configs that won't work at this speed */ | 444 | /* ignore configs that won't work at this speed */ |
311 | if (speed == USB_SPEED_HIGH) { | 445 | switch (speed) { |
446 | case USB_SPEED_SUPER: | ||
447 | if (!c->superspeed) | ||
448 | continue; | ||
449 | break; | ||
450 | case USB_SPEED_HIGH: | ||
312 | if (!c->highspeed) | 451 | if (!c->highspeed) |
313 | continue; | 452 | continue; |
314 | } else { | 453 | break; |
454 | default: | ||
315 | if (!c->fullspeed) | 455 | if (!c->fullspeed) |
316 | continue; | 456 | continue; |
317 | } | 457 | } |
458 | |||
318 | if (w_value == 0) | 459 | if (w_value == 0) |
319 | return config_buf(c, speed, cdev->req->buf, type); | 460 | return config_buf(c, speed, cdev->req->buf, type); |
320 | w_value--; | 461 | w_value--; |
@@ -328,16 +469,22 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type) | |||
328 | struct usb_configuration *c; | 469 | struct usb_configuration *c; |
329 | unsigned count = 0; | 470 | unsigned count = 0; |
330 | int hs = 0; | 471 | int hs = 0; |
472 | int ss = 0; | ||
331 | 473 | ||
332 | if (gadget_is_dualspeed(gadget)) { | 474 | if (gadget_is_dualspeed(gadget)) { |
333 | if (gadget->speed == USB_SPEED_HIGH) | 475 | if (gadget->speed == USB_SPEED_HIGH) |
334 | hs = 1; | 476 | hs = 1; |
477 | if (gadget->speed == USB_SPEED_SUPER) | ||
478 | ss = 1; | ||
335 | if (type == USB_DT_DEVICE_QUALIFIER) | 479 | if (type == USB_DT_DEVICE_QUALIFIER) |
336 | hs = !hs; | 480 | hs = !hs; |
337 | } | 481 | } |
338 | list_for_each_entry(c, &cdev->configs, list) { | 482 | list_for_each_entry(c, &cdev->configs, list) { |
339 | /* ignore configs that won't work at this speed */ | 483 | /* ignore configs that won't work at this speed */ |
340 | if (hs) { | 484 | if (ss) { |
485 | if (!c->superspeed) | ||
486 | continue; | ||
487 | } else if (hs) { | ||
341 | if (!c->highspeed) | 488 | if (!c->highspeed) |
342 | continue; | 489 | continue; |
343 | } else { | 490 | } else { |
@@ -349,6 +496,71 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type) | |||
349 | return count; | 496 | return count; |
350 | } | 497 | } |
351 | 498 | ||
499 | /** | ||
500 | * bos_desc() - prepares the BOS descriptor. | ||
501 | * @cdev: pointer to usb_composite device to generate the bos | ||
502 | * descriptor for | ||
503 | * | ||
504 | * This function generates the BOS (Binary Device Object) | ||
505 | * descriptor and its device capabilities descriptors. The BOS | ||
506 | * descriptor should be supported by a SuperSpeed device. | ||
507 | */ | ||
508 | static int bos_desc(struct usb_composite_dev *cdev) | ||
509 | { | ||
510 | struct usb_ext_cap_descriptor *usb_ext; | ||
511 | struct usb_ss_cap_descriptor *ss_cap; | ||
512 | struct usb_dcd_config_params dcd_config_params; | ||
513 | struct usb_bos_descriptor *bos = cdev->req->buf; | ||
514 | |||
515 | bos->bLength = USB_DT_BOS_SIZE; | ||
516 | bos->bDescriptorType = USB_DT_BOS; | ||
517 | |||
518 | bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE); | ||
519 | bos->bNumDeviceCaps = 0; | ||
520 | |||
521 | /* | ||
522 | * A SuperSpeed device shall include the USB2.0 extension descriptor | ||
523 | * and shall support LPM when operating in USB2.0 HS mode. | ||
524 | */ | ||
525 | usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength); | ||
526 | bos->bNumDeviceCaps++; | ||
527 | le16_add_cpu(&bos->wTotalLength, USB_DT_USB_EXT_CAP_SIZE); | ||
528 | usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE; | ||
529 | usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY; | ||
530 | usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT; | ||
531 | usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT); | ||
532 | |||
533 | /* | ||
534 | * The Superspeed USB Capability descriptor shall be implemented by all | ||
535 | * SuperSpeed devices. | ||
536 | */ | ||
537 | ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength); | ||
538 | bos->bNumDeviceCaps++; | ||
539 | le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE); | ||
540 | ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE; | ||
541 | ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY; | ||
542 | ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE; | ||
543 | ss_cap->bmAttributes = 0; /* LTM is not supported yet */ | ||
544 | ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION | | ||
545 | USB_FULL_SPEED_OPERATION | | ||
546 | USB_HIGH_SPEED_OPERATION | | ||
547 | USB_5GBPS_OPERATION); | ||
548 | ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION; | ||
549 | |||
550 | /* Get Controller configuration */ | ||
551 | if (cdev->gadget->ops->get_config_params) | ||
552 | cdev->gadget->ops->get_config_params(&dcd_config_params); | ||
553 | else { | ||
554 | dcd_config_params.bU1devExitLat = USB_DEFULT_U1_DEV_EXIT_LAT; | ||
555 | dcd_config_params.bU2DevExitLat = | ||
556 | cpu_to_le16(USB_DEFULT_U2_DEV_EXIT_LAT); | ||
557 | } | ||
558 | ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat; | ||
559 | ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat; | ||
560 | |||
561 | return le16_to_cpu(bos->wTotalLength); | ||
562 | } | ||
563 | |||
352 | static void device_qual(struct usb_composite_dev *cdev) | 564 | static void device_qual(struct usb_composite_dev *cdev) |
353 | { | 565 | { |
354 | struct usb_qualifier_descriptor *qual = cdev->req->buf; | 566 | struct usb_qualifier_descriptor *qual = cdev->req->buf; |
@@ -361,7 +573,7 @@ static void device_qual(struct usb_composite_dev *cdev) | |||
361 | qual->bDeviceSubClass = cdev->desc.bDeviceSubClass; | 573 | qual->bDeviceSubClass = cdev->desc.bDeviceSubClass; |
362 | qual->bDeviceProtocol = cdev->desc.bDeviceProtocol; | 574 | qual->bDeviceProtocol = cdev->desc.bDeviceProtocol; |
363 | /* ASSUME same EP0 fifo size at both speeds */ | 575 | /* ASSUME same EP0 fifo size at both speeds */ |
364 | qual->bMaxPacketSize0 = cdev->desc.bMaxPacketSize0; | 576 | qual->bMaxPacketSize0 = cdev->gadget->ep0->maxpacket; |
365 | qual->bNumConfigurations = count_configs(cdev, USB_DT_DEVICE_QUALIFIER); | 577 | qual->bNumConfigurations = count_configs(cdev, USB_DT_DEVICE_QUALIFIER); |
366 | qual->bRESERVED = 0; | 578 | qual->bRESERVED = 0; |
367 | } | 579 | } |
@@ -392,28 +604,46 @@ static int set_config(struct usb_composite_dev *cdev, | |||
392 | unsigned power = gadget_is_otg(gadget) ? 8 : 100; | 604 | unsigned power = gadget_is_otg(gadget) ? 8 : 100; |
393 | int tmp; | 605 | int tmp; |
394 | 606 | ||
395 | if (cdev->config) | ||
396 | reset_config(cdev); | ||
397 | |||
398 | if (number) { | 607 | if (number) { |
399 | list_for_each_entry(c, &cdev->configs, list) { | 608 | list_for_each_entry(c, &cdev->configs, list) { |
400 | if (c->bConfigurationValue == number) { | 609 | if (c->bConfigurationValue == number) { |
610 | /* | ||
611 | * We disable the FDs of the previous | ||
612 | * configuration only if the new configuration | ||
613 | * is a valid one | ||
614 | */ | ||
615 | if (cdev->config) | ||
616 | reset_config(cdev); | ||
401 | result = 0; | 617 | result = 0; |
402 | break; | 618 | break; |
403 | } | 619 | } |
404 | } | 620 | } |
405 | if (result < 0) | 621 | if (result < 0) |
406 | goto done; | 622 | goto done; |
407 | } else | 623 | } else { /* Zero configuration value - need to reset the config */ |
624 | if (cdev->config) | ||
625 | reset_config(cdev); | ||
408 | result = 0; | 626 | result = 0; |
627 | } | ||
409 | 628 | ||
410 | INFO(cdev, "%s speed config #%d: %s\n", | 629 | INFO(cdev, "%s speed config #%d: %s\n", |
411 | ({ char *speed; | 630 | ({ char *speed; |
412 | switch (gadget->speed) { | 631 | switch (gadget->speed) { |
413 | case USB_SPEED_LOW: speed = "low"; break; | 632 | case USB_SPEED_LOW: |
414 | case USB_SPEED_FULL: speed = "full"; break; | 633 | speed = "low"; |
415 | case USB_SPEED_HIGH: speed = "high"; break; | 634 | break; |
416 | default: speed = "?"; break; | 635 | case USB_SPEED_FULL: |
636 | speed = "full"; | ||
637 | break; | ||
638 | case USB_SPEED_HIGH: | ||
639 | speed = "high"; | ||
640 | break; | ||
641 | case USB_SPEED_SUPER: | ||
642 | speed = "super"; | ||
643 | break; | ||
644 | default: | ||
645 | speed = "?"; | ||
646 | break; | ||
417 | } ; speed; }), number, c ? c->label : "unconfigured"); | 647 | } ; speed; }), number, c ? c->label : "unconfigured"); |
418 | 648 | ||
419 | if (!c) | 649 | if (!c) |
@@ -435,10 +665,16 @@ static int set_config(struct usb_composite_dev *cdev, | |||
435 | * function's setup callback instead of the current | 665 | * function's setup callback instead of the current |
436 | * configuration's setup callback. | 666 | * configuration's setup callback. |
437 | */ | 667 | */ |
438 | if (gadget->speed == USB_SPEED_HIGH) | 668 | switch (gadget->speed) { |
669 | case USB_SPEED_SUPER: | ||
670 | descriptors = f->ss_descriptors; | ||
671 | break; | ||
672 | case USB_SPEED_HIGH: | ||
439 | descriptors = f->hs_descriptors; | 673 | descriptors = f->hs_descriptors; |
440 | else | 674 | break; |
675 | default: | ||
441 | descriptors = f->descriptors; | 676 | descriptors = f->descriptors; |
677 | } | ||
442 | 678 | ||
443 | for (; *descriptors; ++descriptors) { | 679 | for (; *descriptors; ++descriptors) { |
444 | struct usb_endpoint_descriptor *ep; | 680 | struct usb_endpoint_descriptor *ep; |
@@ -531,8 +767,9 @@ int usb_add_config(struct usb_composite_dev *cdev, | |||
531 | } else { | 767 | } else { |
532 | unsigned i; | 768 | unsigned i; |
533 | 769 | ||
534 | DBG(cdev, "cfg %d/%p speeds:%s%s\n", | 770 | DBG(cdev, "cfg %d/%p speeds:%s%s%s\n", |
535 | config->bConfigurationValue, config, | 771 | config->bConfigurationValue, config, |
772 | config->superspeed ? " super" : "", | ||
536 | config->highspeed ? " high" : "", | 773 | config->highspeed ? " high" : "", |
537 | config->fullspeed | 774 | config->fullspeed |
538 | ? (gadget_is_dualspeed(cdev->gadget) | 775 | ? (gadget_is_dualspeed(cdev->gadget) |
@@ -811,6 +1048,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) | |||
811 | struct usb_composite_dev *cdev = get_gadget_data(gadget); | 1048 | struct usb_composite_dev *cdev = get_gadget_data(gadget); |
812 | struct usb_request *req = cdev->req; | 1049 | struct usb_request *req = cdev->req; |
813 | int value = -EOPNOTSUPP; | 1050 | int value = -EOPNOTSUPP; |
1051 | int status = 0; | ||
814 | u16 w_index = le16_to_cpu(ctrl->wIndex); | 1052 | u16 w_index = le16_to_cpu(ctrl->wIndex); |
815 | u8 intf = w_index & 0xFF; | 1053 | u8 intf = w_index & 0xFF; |
816 | u16 w_value = le16_to_cpu(ctrl->wValue); | 1054 | u16 w_value = le16_to_cpu(ctrl->wValue); |
@@ -838,18 +1076,29 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) | |||
838 | case USB_DT_DEVICE: | 1076 | case USB_DT_DEVICE: |
839 | cdev->desc.bNumConfigurations = | 1077 | cdev->desc.bNumConfigurations = |
840 | count_configs(cdev, USB_DT_DEVICE); | 1078 | count_configs(cdev, USB_DT_DEVICE); |
1079 | cdev->desc.bMaxPacketSize0 = | ||
1080 | cdev->gadget->ep0->maxpacket; | ||
1081 | if (gadget_is_superspeed(gadget)) { | ||
1082 | if (gadget->speed >= USB_SPEED_SUPER) | ||
1083 | cdev->desc.bcdUSB = cpu_to_le16(0x0300); | ||
1084 | else | ||
1085 | cdev->desc.bcdUSB = cpu_to_le16(0x0210); | ||
1086 | } | ||
1087 | |||
841 | value = min(w_length, (u16) sizeof cdev->desc); | 1088 | value = min(w_length, (u16) sizeof cdev->desc); |
842 | memcpy(req->buf, &cdev->desc, value); | 1089 | memcpy(req->buf, &cdev->desc, value); |
843 | break; | 1090 | break; |
844 | case USB_DT_DEVICE_QUALIFIER: | 1091 | case USB_DT_DEVICE_QUALIFIER: |
845 | if (!gadget_is_dualspeed(gadget)) | 1092 | if (!gadget_is_dualspeed(gadget) || |
1093 | gadget->speed >= USB_SPEED_SUPER) | ||
846 | break; | 1094 | break; |
847 | device_qual(cdev); | 1095 | device_qual(cdev); |
848 | value = min_t(int, w_length, | 1096 | value = min_t(int, w_length, |
849 | sizeof(struct usb_qualifier_descriptor)); | 1097 | sizeof(struct usb_qualifier_descriptor)); |
850 | break; | 1098 | break; |
851 | case USB_DT_OTHER_SPEED_CONFIG: | 1099 | case USB_DT_OTHER_SPEED_CONFIG: |
852 | if (!gadget_is_dualspeed(gadget)) | 1100 | if (!gadget_is_dualspeed(gadget) || |
1101 | gadget->speed >= USB_SPEED_SUPER) | ||
853 | break; | 1102 | break; |
854 | /* FALLTHROUGH */ | 1103 | /* FALLTHROUGH */ |
855 | case USB_DT_CONFIG: | 1104 | case USB_DT_CONFIG: |
@@ -863,6 +1112,12 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) | |||
863 | if (value >= 0) | 1112 | if (value >= 0) |
864 | value = min(w_length, (u16) value); | 1113 | value = min(w_length, (u16) value); |
865 | break; | 1114 | break; |
1115 | case USB_DT_BOS: | ||
1116 | if (gadget_is_superspeed(gadget)) { | ||
1117 | value = bos_desc(cdev); | ||
1118 | value = min(w_length, (u16) value); | ||
1119 | } | ||
1120 | break; | ||
866 | } | 1121 | } |
867 | break; | 1122 | break; |
868 | 1123 | ||
@@ -930,6 +1185,61 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) | |||
930 | *((u8 *)req->buf) = value; | 1185 | *((u8 *)req->buf) = value; |
931 | value = min(w_length, (u16) 1); | 1186 | value = min(w_length, (u16) 1); |
932 | break; | 1187 | break; |
1188 | |||
1189 | /* | ||
1190 | * USB 3.0 additions: | ||
1191 | * Function driver should handle get_status request. If such cb | ||
1192 | * wasn't supplied we respond with default value = 0 | ||
1193 | * Note: function driver should supply such cb only for the first | ||
1194 | * interface of the function | ||
1195 | */ | ||
1196 | case USB_REQ_GET_STATUS: | ||
1197 | if (!gadget_is_superspeed(gadget)) | ||
1198 | goto unknown; | ||
1199 | if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE)) | ||
1200 | goto unknown; | ||
1201 | value = 2; /* This is the length of the get_status reply */ | ||
1202 | put_unaligned_le16(0, req->buf); | ||
1203 | if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) | ||
1204 | break; | ||
1205 | f = cdev->config->interface[intf]; | ||
1206 | if (!f) | ||
1207 | break; | ||
1208 | status = f->get_status ? f->get_status(f) : 0; | ||
1209 | if (status < 0) | ||
1210 | break; | ||
1211 | put_unaligned_le16(status & 0x0000ffff, req->buf); | ||
1212 | break; | ||
1213 | /* | ||
1214 | * Function drivers should handle SetFeature/ClearFeature | ||
1215 | * (FUNCTION_SUSPEND) request. function_suspend cb should be supplied | ||
1216 | * only for the first interface of the function | ||
1217 | */ | ||
1218 | case USB_REQ_CLEAR_FEATURE: | ||
1219 | case USB_REQ_SET_FEATURE: | ||
1220 | if (!gadget_is_superspeed(gadget)) | ||
1221 | goto unknown; | ||
1222 | if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE)) | ||
1223 | goto unknown; | ||
1224 | switch (w_value) { | ||
1225 | case USB_INTRF_FUNC_SUSPEND: | ||
1226 | if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) | ||
1227 | break; | ||
1228 | f = cdev->config->interface[intf]; | ||
1229 | if (!f) | ||
1230 | break; | ||
1231 | value = 0; | ||
1232 | if (f->func_suspend) | ||
1233 | value = f->func_suspend(f, w_index >> 8); | ||
1234 | if (value < 0) { | ||
1235 | ERROR(cdev, | ||
1236 | "func_suspend() returned error %d\n", | ||
1237 | value); | ||
1238 | value = 0; | ||
1239 | } | ||
1240 | break; | ||
1241 | } | ||
1242 | break; | ||
933 | default: | 1243 | default: |
934 | unknown: | 1244 | unknown: |
935 | VDBG(cdev, | 1245 | VDBG(cdev, |
@@ -1140,7 +1450,6 @@ static int composite_bind(struct usb_gadget *gadget) | |||
1140 | goto fail; | 1450 | goto fail; |
1141 | 1451 | ||
1142 | cdev->desc = *composite->dev; | 1452 | cdev->desc = *composite->dev; |
1143 | cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket; | ||
1144 | 1453 | ||
1145 | /* standardized runtime overrides for device ID data */ | 1454 | /* standardized runtime overrides for device ID data */ |
1146 | if (idVendor) | 1455 | if (idVendor) |
@@ -1247,7 +1556,11 @@ composite_resume(struct usb_gadget *gadget) | |||
1247 | /*-------------------------------------------------------------------------*/ | 1556 | /*-------------------------------------------------------------------------*/ |
1248 | 1557 | ||
1249 | static struct usb_gadget_driver composite_driver = { | 1558 | static struct usb_gadget_driver composite_driver = { |
1559 | #ifdef CONFIG_USB_GADGET_SUPERSPEED | ||
1560 | .speed = USB_SPEED_SUPER, | ||
1561 | #else | ||
1250 | .speed = USB_SPEED_HIGH, | 1562 | .speed = USB_SPEED_HIGH, |
1563 | #endif | ||
1251 | 1564 | ||
1252 | .unbind = composite_unbind, | 1565 | .unbind = composite_unbind, |
1253 | 1566 | ||
@@ -1293,6 +1606,8 @@ int usb_composite_probe(struct usb_composite_driver *driver, | |||
1293 | driver->iProduct = driver->name; | 1606 | driver->iProduct = driver->name; |
1294 | composite_driver.function = (char *) driver->name; | 1607 | composite_driver.function = (char *) driver->name; |
1295 | composite_driver.driver.name = driver->name; | 1608 | composite_driver.driver.name = driver->name; |
1609 | composite_driver.speed = min((u8)composite_driver.speed, | ||
1610 | (u8)driver->max_speed); | ||
1296 | composite = driver; | 1611 | composite = driver; |
1297 | composite_gadget_bind = bind; | 1612 | composite_gadget_bind = bind; |
1298 | 1613 | ||