diff options
-rw-r--r-- | drivers/usb/core/config.c | 189 | ||||
-rw-r--r-- | include/linux/usb.h | 16 | ||||
-rw-r--r-- | include/linux/usb/ch9.h | 16 |
3 files changed, 212 insertions, 9 deletions
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index e9426acf5682..7103758bb486 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c | |||
@@ -19,6 +19,32 @@ static inline const char *plural(int n) | |||
19 | return (n == 1 ? "" : "s"); | 19 | return (n == 1 ? "" : "s"); |
20 | } | 20 | } |
21 | 21 | ||
22 | /* FIXME: this is a kludge */ | ||
23 | static int find_next_descriptor_more(unsigned char *buffer, int size, | ||
24 | int dt1, int dt2, int dt3, int *num_skipped) | ||
25 | { | ||
26 | struct usb_descriptor_header *h; | ||
27 | int n = 0; | ||
28 | unsigned char *buffer0 = buffer; | ||
29 | |||
30 | /* Find the next descriptor of type dt1 or dt2 or dt3 */ | ||
31 | while (size > 0) { | ||
32 | h = (struct usb_descriptor_header *) buffer; | ||
33 | if (h->bDescriptorType == dt1 || h->bDescriptorType == dt2 || | ||
34 | h->bDescriptorType == dt3) | ||
35 | break; | ||
36 | buffer += h->bLength; | ||
37 | size -= h->bLength; | ||
38 | ++n; | ||
39 | } | ||
40 | |||
41 | /* Store the number of descriptors skipped and return the | ||
42 | * number of bytes skipped */ | ||
43 | if (num_skipped) | ||
44 | *num_skipped = n; | ||
45 | return buffer - buffer0; | ||
46 | } | ||
47 | |||
22 | static int find_next_descriptor(unsigned char *buffer, int size, | 48 | static int find_next_descriptor(unsigned char *buffer, int size, |
23 | int dt1, int dt2, int *num_skipped) | 49 | int dt1, int dt2, int *num_skipped) |
24 | { | 50 | { |
@@ -43,6 +69,128 @@ static int find_next_descriptor(unsigned char *buffer, int size, | |||
43 | return buffer - buffer0; | 69 | return buffer - buffer0; |
44 | } | 70 | } |
45 | 71 | ||
72 | static int usb_parse_endpoint_companion(struct device *ddev, int cfgno, | ||
73 | int inum, int asnum, struct usb_host_endpoint *ep, | ||
74 | int num_ep, unsigned char *buffer, int size) | ||
75 | { | ||
76 | unsigned char *buffer_start = buffer; | ||
77 | struct usb_ep_comp_descriptor *desc; | ||
78 | int retval; | ||
79 | int num_skipped; | ||
80 | int max_tx; | ||
81 | int i; | ||
82 | |||
83 | /* Allocate space for the companion descriptor */ | ||
84 | ep->ep_comp = kzalloc(sizeof(struct usb_host_ep_comp), GFP_KERNEL); | ||
85 | if (!ep->ep_comp) | ||
86 | return -ENOMEM; | ||
87 | desc = (struct usb_ep_comp_descriptor *) buffer; | ||
88 | if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP) { | ||
89 | dev_warn(ddev, "No SuperSpeed endpoint companion for config %d " | ||
90 | " interface %d altsetting %d ep %d: " | ||
91 | "using minimum values\n", | ||
92 | cfgno, inum, asnum, ep->desc.bEndpointAddress); | ||
93 | ep->ep_comp->desc.bLength = USB_DT_EP_COMP_SIZE; | ||
94 | ep->ep_comp->desc.bDescriptorType = USB_DT_SS_ENDPOINT_COMP; | ||
95 | ep->ep_comp->desc.bMaxBurst = 0; | ||
96 | /* | ||
97 | * Leave bmAttributes as zero, which will mean no streams for | ||
98 | * bulk, and isoc won't support multiple bursts of packets. | ||
99 | * With bursts of only one packet, and a Mult of 1, the max | ||
100 | * amount of data moved per endpoint service interval is one | ||
101 | * packet. | ||
102 | */ | ||
103 | if (usb_endpoint_xfer_isoc(&ep->desc) || | ||
104 | usb_endpoint_xfer_int(&ep->desc)) | ||
105 | ep->ep_comp->desc.wBytesPerInterval = | ||
106 | ep->desc.wMaxPacketSize; | ||
107 | /* | ||
108 | * The next descriptor is for an Endpoint or Interface, | ||
109 | * no extra descriptors to copy into the companion structure, | ||
110 | * and we didn't eat up any of the buffer. | ||
111 | */ | ||
112 | retval = 0; | ||
113 | goto valid; | ||
114 | } | ||
115 | memcpy(&ep->ep_comp->desc, desc, USB_DT_EP_COMP_SIZE); | ||
116 | desc = &ep->ep_comp->desc; | ||
117 | buffer += desc->bLength; | ||
118 | size -= desc->bLength; | ||
119 | |||
120 | /* Eat up the other descriptors we don't care about */ | ||
121 | ep->ep_comp->extra = buffer; | ||
122 | i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, | ||
123 | USB_DT_INTERFACE, &num_skipped); | ||
124 | ep->ep_comp->extralen = i; | ||
125 | buffer += i; | ||
126 | size -= i; | ||
127 | retval = buffer - buffer_start + i; | ||
128 | if (num_skipped > 0) | ||
129 | dev_dbg(ddev, "skipped %d descriptor%s after %s\n", | ||
130 | num_skipped, plural(num_skipped), | ||
131 | "SuperSpeed endpoint companion"); | ||
132 | |||
133 | /* Check the various values */ | ||
134 | if (usb_endpoint_xfer_control(&ep->desc) && desc->bMaxBurst != 0) { | ||
135 | dev_warn(ddev, "Control endpoint with bMaxBurst = %d in " | ||
136 | "config %d interface %d altsetting %d ep %d: " | ||
137 | "setting to zero\n", desc->bMaxBurst, | ||
138 | cfgno, inum, asnum, ep->desc.bEndpointAddress); | ||
139 | desc->bMaxBurst = 0; | ||
140 | } | ||
141 | if (desc->bMaxBurst > 15) { | ||
142 | dev_warn(ddev, "Endpoint with bMaxBurst = %d in " | ||
143 | "config %d interface %d altsetting %d ep %d: " | ||
144 | "setting to 15\n", desc->bMaxBurst, | ||
145 | cfgno, inum, asnum, ep->desc.bEndpointAddress); | ||
146 | desc->bMaxBurst = 15; | ||
147 | } | ||
148 | if ((usb_endpoint_xfer_control(&ep->desc) || usb_endpoint_xfer_int(&ep->desc)) | ||
149 | && desc->bmAttributes != 0) { | ||
150 | dev_warn(ddev, "%s endpoint with bmAttributes = %d in " | ||
151 | "config %d interface %d altsetting %d ep %d: " | ||
152 | "setting to zero\n", | ||
153 | usb_endpoint_xfer_control(&ep->desc) ? "Control" : "Bulk", | ||
154 | desc->bmAttributes, | ||
155 | cfgno, inum, asnum, ep->desc.bEndpointAddress); | ||
156 | desc->bmAttributes = 0; | ||
157 | } | ||
158 | if (usb_endpoint_xfer_bulk(&ep->desc) && desc->bmAttributes > 16) { | ||
159 | dev_warn(ddev, "Bulk endpoint with more than 65536 streams in " | ||
160 | "config %d interface %d altsetting %d ep %d: " | ||
161 | "setting to max\n", | ||
162 | cfgno, inum, asnum, ep->desc.bEndpointAddress); | ||
163 | desc->bmAttributes = 16; | ||
164 | } | ||
165 | if (usb_endpoint_xfer_isoc(&ep->desc) && desc->bmAttributes > 2) { | ||
166 | dev_warn(ddev, "Isoc endpoint has Mult of %d in " | ||
167 | "config %d interface %d altsetting %d ep %d: " | ||
168 | "setting to 3\n", desc->bmAttributes + 1, | ||
169 | cfgno, inum, asnum, ep->desc.bEndpointAddress); | ||
170 | desc->bmAttributes = 2; | ||
171 | } | ||
172 | if (usb_endpoint_xfer_isoc(&ep->desc)) { | ||
173 | max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1) * | ||
174 | (desc->bmAttributes + 1); | ||
175 | } else if (usb_endpoint_xfer_int(&ep->desc)) { | ||
176 | max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1); | ||
177 | } else { | ||
178 | goto valid; | ||
179 | } | ||
180 | if (desc->wBytesPerInterval > max_tx) { | ||
181 | dev_warn(ddev, "%s endpoint with wBytesPerInterval of %d in " | ||
182 | "config %d interface %d altsetting %d ep %d: " | ||
183 | "setting to %d\n", | ||
184 | usb_endpoint_xfer_isoc(&ep->desc) ? "Isoc" : "Int", | ||
185 | desc->wBytesPerInterval, | ||
186 | cfgno, inum, asnum, ep->desc.bEndpointAddress, | ||
187 | max_tx); | ||
188 | desc->wBytesPerInterval = max_tx; | ||
189 | } | ||
190 | valid: | ||
191 | return retval; | ||
192 | } | ||
193 | |||
46 | static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, | 194 | static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, |
47 | int asnum, struct usb_host_interface *ifp, int num_ep, | 195 | int asnum, struct usb_host_interface *ifp, int num_ep, |
48 | unsigned char *buffer, int size) | 196 | unsigned char *buffer, int size) |
@@ -50,7 +198,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, | |||
50 | unsigned char *buffer0 = buffer; | 198 | unsigned char *buffer0 = buffer; |
51 | struct usb_endpoint_descriptor *d; | 199 | struct usb_endpoint_descriptor *d; |
52 | struct usb_host_endpoint *endpoint; | 200 | struct usb_host_endpoint *endpoint; |
53 | int n, i, j; | 201 | int n, i, j, retval; |
54 | 202 | ||
55 | d = (struct usb_endpoint_descriptor *) buffer; | 203 | d = (struct usb_endpoint_descriptor *) buffer; |
56 | buffer += d->bLength; | 204 | buffer += d->bLength; |
@@ -162,17 +310,38 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, | |||
162 | cfgno, inum, asnum, d->bEndpointAddress, | 310 | cfgno, inum, asnum, d->bEndpointAddress, |
163 | maxp); | 311 | maxp); |
164 | } | 312 | } |
165 | 313 | /* Allocate room for and parse any endpoint companion descriptors */ | |
166 | /* Skip over any Class Specific or Vendor Specific descriptors; | 314 | if (to_usb_device(ddev)->speed == USB_SPEED_SUPER) { |
167 | * find the next endpoint or interface descriptor */ | 315 | endpoint->extra = buffer; |
168 | endpoint->extra = buffer; | 316 | i = find_next_descriptor_more(buffer, size, USB_DT_SS_ENDPOINT_COMP, |
169 | i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, | 317 | USB_DT_ENDPOINT, USB_DT_INTERFACE, &n); |
170 | USB_DT_INTERFACE, &n); | 318 | endpoint->extralen = i; |
171 | endpoint->extralen = i; | 319 | buffer += i; |
320 | size -= i; | ||
321 | |||
322 | if (size > 0) { | ||
323 | retval = usb_parse_endpoint_companion(ddev, cfgno, inum, asnum, | ||
324 | endpoint, num_ep, buffer, size); | ||
325 | if (retval >= 0) { | ||
326 | buffer += retval; | ||
327 | retval = buffer - buffer0; | ||
328 | } | ||
329 | } else { | ||
330 | retval = buffer - buffer0; | ||
331 | } | ||
332 | } else { | ||
333 | /* Skip over any Class Specific or Vendor Specific descriptors; | ||
334 | * find the next endpoint or interface descriptor */ | ||
335 | endpoint->extra = buffer; | ||
336 | i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, | ||
337 | USB_DT_INTERFACE, &n); | ||
338 | endpoint->extralen = i; | ||
339 | retval = buffer - buffer0 + i; | ||
340 | } | ||
172 | if (n > 0) | 341 | if (n > 0) |
173 | dev_dbg(ddev, "skipped %d descriptor%s after %s\n", | 342 | dev_dbg(ddev, "skipped %d descriptor%s after %s\n", |
174 | n, plural(n), "endpoint"); | 343 | n, plural(n), "endpoint"); |
175 | return buffer - buffer0 + i; | 344 | return retval; |
176 | 345 | ||
177 | skip_to_next_endpoint_or_interface_descriptor: | 346 | skip_to_next_endpoint_or_interface_descriptor: |
178 | i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, | 347 | i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, |
@@ -453,6 +622,8 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx, | |||
453 | kref_init(&intfc->ref); | 622 | kref_init(&intfc->ref); |
454 | } | 623 | } |
455 | 624 | ||
625 | /* FIXME: parse the BOS descriptor */ | ||
626 | |||
456 | /* Skip over any Class Specific or Vendor Specific descriptors; | 627 | /* Skip over any Class Specific or Vendor Specific descriptors; |
457 | * find the first interface descriptor */ | 628 | * find the first interface descriptor */ |
458 | config->extra = buffer; | 629 | config->extra = buffer; |
diff --git a/include/linux/usb.h b/include/linux/usb.h index 112a2d6e922f..13bced521b83 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h | |||
@@ -36,6 +36,7 @@ struct wusb_dev; | |||
36 | * - configs have one (often) or more interfaces; | 36 | * - configs have one (often) or more interfaces; |
37 | * - interfaces have one (usually) or more settings; | 37 | * - interfaces have one (usually) or more settings; |
38 | * - each interface setting has zero or (usually) more endpoints. | 38 | * - each interface setting has zero or (usually) more endpoints. |
39 | * - a SuperSpeed endpoint has a companion descriptor | ||
39 | * | 40 | * |
40 | * And there might be other descriptors mixed in with those. | 41 | * And there might be other descriptors mixed in with those. |
41 | * | 42 | * |
@@ -44,6 +45,19 @@ struct wusb_dev; | |||
44 | 45 | ||
45 | struct ep_device; | 46 | struct ep_device; |
46 | 47 | ||
48 | /* For SS devices */ | ||
49 | /** | ||
50 | * struct usb_host_ep_comp - Valid for SuperSpeed devices only | ||
51 | * @desc: endpoint companion descriptor, wMaxPacketSize in native byteorder | ||
52 | * @extra: descriptors following this endpoint companion descriptor | ||
53 | * @extralen: how many bytes of "extra" are valid | ||
54 | */ | ||
55 | struct usb_host_ep_comp { | ||
56 | struct usb_ep_comp_descriptor desc; | ||
57 | unsigned char *extra; /* Extra descriptors */ | ||
58 | int extralen; | ||
59 | }; | ||
60 | |||
47 | /** | 61 | /** |
48 | * struct usb_host_endpoint - host-side endpoint descriptor and queue | 62 | * struct usb_host_endpoint - host-side endpoint descriptor and queue |
49 | * @desc: descriptor for this endpoint, wMaxPacketSize in native byteorder | 63 | * @desc: descriptor for this endpoint, wMaxPacketSize in native byteorder |
@@ -51,6 +65,7 @@ struct ep_device; | |||
51 | * @hcpriv: for use by HCD; typically holds hardware dma queue head (QH) | 65 | * @hcpriv: for use by HCD; typically holds hardware dma queue head (QH) |
52 | * with one or more transfer descriptors (TDs) per urb | 66 | * with one or more transfer descriptors (TDs) per urb |
53 | * @ep_dev: ep_device for sysfs info | 67 | * @ep_dev: ep_device for sysfs info |
68 | * @ep_comp: companion descriptor information for this endpoint | ||
54 | * @extra: descriptors following this endpoint in the configuration | 69 | * @extra: descriptors following this endpoint in the configuration |
55 | * @extralen: how many bytes of "extra" are valid | 70 | * @extralen: how many bytes of "extra" are valid |
56 | * @enabled: URBs may be submitted to this endpoint | 71 | * @enabled: URBs may be submitted to this endpoint |
@@ -63,6 +78,7 @@ struct usb_host_endpoint { | |||
63 | struct list_head urb_list; | 78 | struct list_head urb_list; |
64 | void *hcpriv; | 79 | void *hcpriv; |
65 | struct ep_device *ep_dev; /* For sysfs info */ | 80 | struct ep_device *ep_dev; /* For sysfs info */ |
81 | struct usb_host_ep_comp *ep_comp; /* For SS devices */ | ||
66 | 82 | ||
67 | unsigned char *extra; /* Extra descriptors */ | 83 | unsigned char *extra; /* Extra descriptors */ |
68 | int extralen; | 84 | int extralen; |
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h index 93bfe6352342..9e9c5c0a3d72 100644 --- a/include/linux/usb/ch9.h +++ b/include/linux/usb/ch9.h | |||
@@ -191,6 +191,8 @@ struct usb_ctrlrequest { | |||
191 | #define USB_DT_WIRE_ADAPTER 0x21 | 191 | #define USB_DT_WIRE_ADAPTER 0x21 |
192 | #define USB_DT_RPIPE 0x22 | 192 | #define USB_DT_RPIPE 0x22 |
193 | #define USB_DT_CS_RADIO_CONTROL 0x23 | 193 | #define USB_DT_CS_RADIO_CONTROL 0x23 |
194 | /* From the USB 3.0 spec */ | ||
195 | #define USB_DT_SS_ENDPOINT_COMP 0x30 | ||
194 | 196 | ||
195 | /* Conventional codes for class-specific descriptors. The convention is | 197 | /* Conventional codes for class-specific descriptors. The convention is |
196 | * defined in the USB "Common Class" Spec (3.11). Individual class specs | 198 | * defined in the USB "Common Class" Spec (3.11). Individual class specs |
@@ -535,6 +537,20 @@ static inline int usb_endpoint_is_isoc_out( | |||
535 | 537 | ||
536 | /*-------------------------------------------------------------------------*/ | 538 | /*-------------------------------------------------------------------------*/ |
537 | 539 | ||
540 | /* USB_DT_SS_ENDPOINT_COMP: SuperSpeed Endpoint Companion descriptor */ | ||
541 | struct usb_ep_comp_descriptor { | ||
542 | __u8 bLength; | ||
543 | __u8 bDescriptorType; | ||
544 | |||
545 | __u8 bMaxBurst; | ||
546 | __u8 bmAttributes; | ||
547 | __u16 wBytesPerInterval; | ||
548 | } __attribute__ ((packed)); | ||
549 | |||
550 | #define USB_DT_EP_COMP_SIZE 6 | ||
551 | |||
552 | /*-------------------------------------------------------------------------*/ | ||
553 | |||
538 | /* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */ | 554 | /* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */ |
539 | struct usb_qualifier_descriptor { | 555 | struct usb_qualifier_descriptor { |
540 | __u8 bLength; | 556 | __u8 bLength; |