diff options
-rw-r--r-- | drivers/usb/gadget/f_loopback.c | 4 | ||||
-rw-r--r-- | drivers/usb/gadget/f_sourcesink.c | 424 | ||||
-rw-r--r-- | drivers/usb/gadget/g_zero.h | 5 | ||||
-rw-r--r-- | drivers/usb/gadget/zero.c | 19 |
4 files changed, 387 insertions, 65 deletions
diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c index 2c0cd824c667..7275706caeb0 100644 --- a/drivers/usb/gadget/f_loopback.c +++ b/drivers/usb/gadget/f_loopback.c | |||
@@ -286,7 +286,7 @@ static void disable_loopback(struct f_loopback *loop) | |||
286 | struct usb_composite_dev *cdev; | 286 | struct usb_composite_dev *cdev; |
287 | 287 | ||
288 | cdev = loop->function.config->cdev; | 288 | cdev = loop->function.config->cdev; |
289 | disable_endpoints(cdev, loop->in_ep, loop->out_ep); | 289 | disable_endpoints(cdev, loop->in_ep, loop->out_ep, NULL, NULL); |
290 | VDBG(cdev, "%s disabled\n", loop->function.name); | 290 | VDBG(cdev, "%s disabled\n", loop->function.name); |
291 | } | 291 | } |
292 | 292 | ||
@@ -329,7 +329,7 @@ fail0: | |||
329 | * than 'buflen' bytes each. | 329 | * than 'buflen' bytes each. |
330 | */ | 330 | */ |
331 | for (i = 0; i < qlen && result == 0; i++) { | 331 | for (i = 0; i < qlen && result == 0; i++) { |
332 | req = alloc_ep_req(ep); | 332 | req = alloc_ep_req(ep, 0); |
333 | if (req) { | 333 | if (req) { |
334 | req->complete = loopback_complete; | 334 | req->complete = loopback_complete; |
335 | result = usb_ep_queue(ep, req, GFP_ATOMIC); | 335 | result = usb_ep_queue(ep, req, GFP_ATOMIC); |
diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c index 7aa7ac82c02c..5c1b68b63c98 100644 --- a/drivers/usb/gadget/f_sourcesink.c +++ b/drivers/usb/gadget/f_sourcesink.c | |||
@@ -51,6 +51,9 @@ struct f_sourcesink { | |||
51 | 51 | ||
52 | struct usb_ep *in_ep; | 52 | struct usb_ep *in_ep; |
53 | struct usb_ep *out_ep; | 53 | struct usb_ep *out_ep; |
54 | struct usb_ep *iso_in_ep; | ||
55 | struct usb_ep *iso_out_ep; | ||
56 | int cur_alt; | ||
54 | }; | 57 | }; |
55 | 58 | ||
56 | static inline struct f_sourcesink *func_to_ss(struct usb_function *f) | 59 | static inline struct f_sourcesink *func_to_ss(struct usb_function *f) |
@@ -59,18 +62,45 @@ static inline struct f_sourcesink *func_to_ss(struct usb_function *f) | |||
59 | } | 62 | } |
60 | 63 | ||
61 | static unsigned pattern; | 64 | static unsigned pattern; |
62 | module_param(pattern, uint, 0); | 65 | module_param(pattern, uint, S_IRUGO|S_IWUSR); |
63 | MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63 "); | 66 | MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63, 2 = none"); |
67 | |||
68 | static unsigned isoc_interval = 4; | ||
69 | module_param(isoc_interval, uint, S_IRUGO|S_IWUSR); | ||
70 | MODULE_PARM_DESC(isoc_interval, "1 - 16"); | ||
71 | |||
72 | static unsigned isoc_maxpacket = 1024; | ||
73 | module_param(isoc_maxpacket, uint, S_IRUGO|S_IWUSR); | ||
74 | MODULE_PARM_DESC(isoc_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)"); | ||
75 | |||
76 | static unsigned isoc_mult; | ||
77 | module_param(isoc_mult, uint, S_IRUGO|S_IWUSR); | ||
78 | MODULE_PARM_DESC(isoc_mult, "0 - 2 (hs/ss only)"); | ||
79 | |||
80 | static unsigned isoc_maxburst; | ||
81 | module_param(isoc_maxburst, uint, S_IRUGO|S_IWUSR); | ||
82 | MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)"); | ||
64 | 83 | ||
65 | /*-------------------------------------------------------------------------*/ | 84 | /*-------------------------------------------------------------------------*/ |
66 | 85 | ||
67 | static struct usb_interface_descriptor source_sink_intf = { | 86 | static struct usb_interface_descriptor source_sink_intf_alt0 = { |
68 | .bLength = sizeof source_sink_intf, | 87 | .bLength = USB_DT_INTERFACE_SIZE, |
69 | .bDescriptorType = USB_DT_INTERFACE, | 88 | .bDescriptorType = USB_DT_INTERFACE, |
70 | 89 | ||
90 | .bAlternateSetting = 0, | ||
71 | .bNumEndpoints = 2, | 91 | .bNumEndpoints = 2, |
72 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, | 92 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, |
73 | /* .iInterface = DYNAMIC */ | 93 | /* .iInterface = DYNAMIC */ |
94 | }; | ||
95 | |||
96 | static struct usb_interface_descriptor source_sink_intf_alt1 = { | ||
97 | .bLength = USB_DT_INTERFACE_SIZE, | ||
98 | .bDescriptorType = USB_DT_INTERFACE, | ||
99 | |||
100 | .bAlternateSetting = 1, | ||
101 | .bNumEndpoints = 4, | ||
102 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, | ||
103 | /* .iInterface = DYNAMIC */ | ||
74 | }; | 104 | }; |
75 | 105 | ||
76 | /* full speed support: */ | 106 | /* full speed support: */ |
@@ -91,10 +121,36 @@ static struct usb_endpoint_descriptor fs_sink_desc = { | |||
91 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | 121 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
92 | }; | 122 | }; |
93 | 123 | ||
124 | static struct usb_endpoint_descriptor fs_iso_source_desc = { | ||
125 | .bLength = USB_DT_ENDPOINT_SIZE, | ||
126 | .bDescriptorType = USB_DT_ENDPOINT, | ||
127 | |||
128 | .bEndpointAddress = USB_DIR_IN, | ||
129 | .bmAttributes = USB_ENDPOINT_XFER_ISOC, | ||
130 | .wMaxPacketSize = cpu_to_le16(1023), | ||
131 | .bInterval = 4, | ||
132 | }; | ||
133 | |||
134 | static struct usb_endpoint_descriptor fs_iso_sink_desc = { | ||
135 | .bLength = USB_DT_ENDPOINT_SIZE, | ||
136 | .bDescriptorType = USB_DT_ENDPOINT, | ||
137 | |||
138 | .bEndpointAddress = USB_DIR_OUT, | ||
139 | .bmAttributes = USB_ENDPOINT_XFER_ISOC, | ||
140 | .wMaxPacketSize = cpu_to_le16(1023), | ||
141 | .bInterval = 4, | ||
142 | }; | ||
143 | |||
94 | static struct usb_descriptor_header *fs_source_sink_descs[] = { | 144 | static struct usb_descriptor_header *fs_source_sink_descs[] = { |
95 | (struct usb_descriptor_header *) &source_sink_intf, | 145 | (struct usb_descriptor_header *) &source_sink_intf_alt0, |
96 | (struct usb_descriptor_header *) &fs_sink_desc, | 146 | (struct usb_descriptor_header *) &fs_sink_desc, |
97 | (struct usb_descriptor_header *) &fs_source_desc, | 147 | (struct usb_descriptor_header *) &fs_source_desc, |
148 | (struct usb_descriptor_header *) &source_sink_intf_alt1, | ||
149 | #define FS_ALT_IFC_1_OFFSET 3 | ||
150 | (struct usb_descriptor_header *) &fs_sink_desc, | ||
151 | (struct usb_descriptor_header *) &fs_source_desc, | ||
152 | (struct usb_descriptor_header *) &fs_iso_sink_desc, | ||
153 | (struct usb_descriptor_header *) &fs_iso_source_desc, | ||
98 | NULL, | 154 | NULL, |
99 | }; | 155 | }; |
100 | 156 | ||
@@ -116,10 +172,34 @@ static struct usb_endpoint_descriptor hs_sink_desc = { | |||
116 | .wMaxPacketSize = cpu_to_le16(512), | 172 | .wMaxPacketSize = cpu_to_le16(512), |
117 | }; | 173 | }; |
118 | 174 | ||
175 | static struct usb_endpoint_descriptor hs_iso_source_desc = { | ||
176 | .bLength = USB_DT_ENDPOINT_SIZE, | ||
177 | .bDescriptorType = USB_DT_ENDPOINT, | ||
178 | |||
179 | .bmAttributes = USB_ENDPOINT_XFER_ISOC, | ||
180 | .wMaxPacketSize = cpu_to_le16(1024), | ||
181 | .bInterval = 4, | ||
182 | }; | ||
183 | |||
184 | static struct usb_endpoint_descriptor hs_iso_sink_desc = { | ||
185 | .bLength = USB_DT_ENDPOINT_SIZE, | ||
186 | .bDescriptorType = USB_DT_ENDPOINT, | ||
187 | |||
188 | .bmAttributes = USB_ENDPOINT_XFER_ISOC, | ||
189 | .wMaxPacketSize = cpu_to_le16(1024), | ||
190 | .bInterval = 4, | ||
191 | }; | ||
192 | |||
119 | static struct usb_descriptor_header *hs_source_sink_descs[] = { | 193 | static struct usb_descriptor_header *hs_source_sink_descs[] = { |
120 | (struct usb_descriptor_header *) &source_sink_intf, | 194 | (struct usb_descriptor_header *) &source_sink_intf_alt0, |
121 | (struct usb_descriptor_header *) &hs_source_desc, | 195 | (struct usb_descriptor_header *) &hs_source_desc, |
122 | (struct usb_descriptor_header *) &hs_sink_desc, | 196 | (struct usb_descriptor_header *) &hs_sink_desc, |
197 | (struct usb_descriptor_header *) &source_sink_intf_alt1, | ||
198 | #define HS_ALT_IFC_1_OFFSET 3 | ||
199 | (struct usb_descriptor_header *) &hs_source_desc, | ||
200 | (struct usb_descriptor_header *) &hs_sink_desc, | ||
201 | (struct usb_descriptor_header *) &hs_iso_source_desc, | ||
202 | (struct usb_descriptor_header *) &hs_iso_sink_desc, | ||
123 | NULL, | 203 | NULL, |
124 | }; | 204 | }; |
125 | 205 | ||
@@ -136,6 +216,7 @@ static struct usb_endpoint_descriptor ss_source_desc = { | |||
136 | struct usb_ss_ep_comp_descriptor ss_source_comp_desc = { | 216 | struct usb_ss_ep_comp_descriptor ss_source_comp_desc = { |
137 | .bLength = USB_DT_SS_EP_COMP_SIZE, | 217 | .bLength = USB_DT_SS_EP_COMP_SIZE, |
138 | .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, | 218 | .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, |
219 | |||
139 | .bMaxBurst = 0, | 220 | .bMaxBurst = 0, |
140 | .bmAttributes = 0, | 221 | .bmAttributes = 0, |
141 | .wBytesPerInterval = 0, | 222 | .wBytesPerInterval = 0, |
@@ -152,17 +233,64 @@ static struct usb_endpoint_descriptor ss_sink_desc = { | |||
152 | struct usb_ss_ep_comp_descriptor ss_sink_comp_desc = { | 233 | struct usb_ss_ep_comp_descriptor ss_sink_comp_desc = { |
153 | .bLength = USB_DT_SS_EP_COMP_SIZE, | 234 | .bLength = USB_DT_SS_EP_COMP_SIZE, |
154 | .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, | 235 | .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, |
236 | |||
155 | .bMaxBurst = 0, | 237 | .bMaxBurst = 0, |
156 | .bmAttributes = 0, | 238 | .bmAttributes = 0, |
157 | .wBytesPerInterval = 0, | 239 | .wBytesPerInterval = 0, |
158 | }; | 240 | }; |
159 | 241 | ||
242 | static struct usb_endpoint_descriptor ss_iso_source_desc = { | ||
243 | .bLength = USB_DT_ENDPOINT_SIZE, | ||
244 | .bDescriptorType = USB_DT_ENDPOINT, | ||
245 | |||
246 | .bmAttributes = USB_ENDPOINT_XFER_ISOC, | ||
247 | .wMaxPacketSize = cpu_to_le16(1024), | ||
248 | .bInterval = 4, | ||
249 | }; | ||
250 | |||
251 | struct usb_ss_ep_comp_descriptor ss_iso_source_comp_desc = { | ||
252 | .bLength = USB_DT_SS_EP_COMP_SIZE, | ||
253 | .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, | ||
254 | |||
255 | .bMaxBurst = 0, | ||
256 | .bmAttributes = 0, | ||
257 | .wBytesPerInterval = cpu_to_le16(1024), | ||
258 | }; | ||
259 | |||
260 | static struct usb_endpoint_descriptor ss_iso_sink_desc = { | ||
261 | .bLength = USB_DT_ENDPOINT_SIZE, | ||
262 | .bDescriptorType = USB_DT_ENDPOINT, | ||
263 | |||
264 | .bmAttributes = USB_ENDPOINT_XFER_ISOC, | ||
265 | .wMaxPacketSize = cpu_to_le16(1024), | ||
266 | .bInterval = 4, | ||
267 | }; | ||
268 | |||
269 | struct usb_ss_ep_comp_descriptor ss_iso_sink_comp_desc = { | ||
270 | .bLength = USB_DT_SS_EP_COMP_SIZE, | ||
271 | .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, | ||
272 | |||
273 | .bMaxBurst = 0, | ||
274 | .bmAttributes = 0, | ||
275 | .wBytesPerInterval = cpu_to_le16(1024), | ||
276 | }; | ||
277 | |||
160 | static struct usb_descriptor_header *ss_source_sink_descs[] = { | 278 | static struct usb_descriptor_header *ss_source_sink_descs[] = { |
161 | (struct usb_descriptor_header *) &source_sink_intf, | 279 | (struct usb_descriptor_header *) &source_sink_intf_alt0, |
162 | (struct usb_descriptor_header *) &ss_source_desc, | 280 | (struct usb_descriptor_header *) &ss_source_desc, |
163 | (struct usb_descriptor_header *) &ss_source_comp_desc, | 281 | (struct usb_descriptor_header *) &ss_source_comp_desc, |
164 | (struct usb_descriptor_header *) &ss_sink_desc, | 282 | (struct usb_descriptor_header *) &ss_sink_desc, |
165 | (struct usb_descriptor_header *) &ss_sink_comp_desc, | 283 | (struct usb_descriptor_header *) &ss_sink_comp_desc, |
284 | (struct usb_descriptor_header *) &source_sink_intf_alt1, | ||
285 | #define SS_ALT_IFC_1_OFFSET 5 | ||
286 | (struct usb_descriptor_header *) &ss_source_desc, | ||
287 | (struct usb_descriptor_header *) &ss_source_comp_desc, | ||
288 | (struct usb_descriptor_header *) &ss_sink_desc, | ||
289 | (struct usb_descriptor_header *) &ss_sink_comp_desc, | ||
290 | (struct usb_descriptor_header *) &ss_iso_source_desc, | ||
291 | (struct usb_descriptor_header *) &ss_iso_source_comp_desc, | ||
292 | (struct usb_descriptor_header *) &ss_iso_sink_desc, | ||
293 | (struct usb_descriptor_header *) &ss_iso_sink_comp_desc, | ||
166 | NULL, | 294 | NULL, |
167 | }; | 295 | }; |
168 | 296 | ||
@@ -196,9 +324,10 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f) | |||
196 | id = usb_interface_id(c, f); | 324 | id = usb_interface_id(c, f); |
197 | if (id < 0) | 325 | if (id < 0) |
198 | return id; | 326 | return id; |
199 | source_sink_intf.bInterfaceNumber = id; | 327 | source_sink_intf_alt0.bInterfaceNumber = id; |
328 | source_sink_intf_alt1.bInterfaceNumber = id; | ||
200 | 329 | ||
201 | /* allocate endpoints */ | 330 | /* allocate bulk endpoints */ |
202 | ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc); | 331 | ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc); |
203 | if (!ss->in_ep) { | 332 | if (!ss->in_ep) { |
204 | autoconf_fail: | 333 | autoconf_fail: |
@@ -213,12 +342,74 @@ autoconf_fail: | |||
213 | goto autoconf_fail; | 342 | goto autoconf_fail; |
214 | ss->out_ep->driver_data = cdev; /* claim */ | 343 | ss->out_ep->driver_data = cdev; /* claim */ |
215 | 344 | ||
345 | /* sanity check the isoc module parameters */ | ||
346 | if (isoc_interval < 1) | ||
347 | isoc_interval = 1; | ||
348 | if (isoc_interval > 16) | ||
349 | isoc_interval = 16; | ||
350 | if (isoc_mult > 2) | ||
351 | isoc_mult = 2; | ||
352 | if (isoc_maxburst > 15) | ||
353 | isoc_maxburst = 15; | ||
354 | |||
355 | /* fill in the FS isoc descriptors from the module parameters */ | ||
356 | fs_iso_source_desc.wMaxPacketSize = isoc_maxpacket > 1023 ? | ||
357 | 1023 : isoc_maxpacket; | ||
358 | fs_iso_source_desc.bInterval = isoc_interval; | ||
359 | fs_iso_sink_desc.wMaxPacketSize = isoc_maxpacket > 1023 ? | ||
360 | 1023 : isoc_maxpacket; | ||
361 | fs_iso_sink_desc.bInterval = isoc_interval; | ||
362 | |||
363 | /* allocate iso endpoints */ | ||
364 | ss->iso_in_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_source_desc); | ||
365 | if (!ss->iso_in_ep) | ||
366 | goto no_iso; | ||
367 | ss->iso_in_ep->driver_data = cdev; /* claim */ | ||
368 | |||
369 | ss->iso_out_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_sink_desc); | ||
370 | if (ss->iso_out_ep) { | ||
371 | ss->iso_out_ep->driver_data = cdev; /* claim */ | ||
372 | } else { | ||
373 | ss->iso_in_ep->driver_data = NULL; | ||
374 | ss->iso_in_ep = NULL; | ||
375 | no_iso: | ||
376 | /* | ||
377 | * We still want to work even if the UDC doesn't have isoc | ||
378 | * endpoints, so null out the alt interface that contains | ||
379 | * them and continue. | ||
380 | */ | ||
381 | fs_source_sink_descs[FS_ALT_IFC_1_OFFSET] = NULL; | ||
382 | hs_source_sink_descs[HS_ALT_IFC_1_OFFSET] = NULL; | ||
383 | ss_source_sink_descs[SS_ALT_IFC_1_OFFSET] = NULL; | ||
384 | } | ||
385 | |||
386 | if (isoc_maxpacket > 1024) | ||
387 | isoc_maxpacket = 1024; | ||
388 | |||
216 | /* support high speed hardware */ | 389 | /* support high speed hardware */ |
217 | if (gadget_is_dualspeed(c->cdev->gadget)) { | 390 | if (gadget_is_dualspeed(c->cdev->gadget)) { |
218 | hs_source_desc.bEndpointAddress = | 391 | hs_source_desc.bEndpointAddress = |
219 | fs_source_desc.bEndpointAddress; | 392 | fs_source_desc.bEndpointAddress; |
220 | hs_sink_desc.bEndpointAddress = | 393 | hs_sink_desc.bEndpointAddress = |
221 | fs_sink_desc.bEndpointAddress; | 394 | fs_sink_desc.bEndpointAddress; |
395 | |||
396 | /* | ||
397 | * Fill in the HS isoc descriptors from the module parameters. | ||
398 | * We assume that the user knows what they are doing and won't | ||
399 | * give parameters that their UDC doesn't support. | ||
400 | */ | ||
401 | hs_iso_source_desc.wMaxPacketSize = isoc_maxpacket; | ||
402 | hs_iso_source_desc.wMaxPacketSize |= isoc_mult << 11; | ||
403 | hs_iso_source_desc.bInterval = isoc_interval; | ||
404 | hs_iso_source_desc.bEndpointAddress = | ||
405 | fs_iso_source_desc.bEndpointAddress; | ||
406 | |||
407 | hs_iso_sink_desc.wMaxPacketSize = isoc_maxpacket; | ||
408 | hs_iso_sink_desc.wMaxPacketSize |= isoc_mult << 11; | ||
409 | hs_iso_sink_desc.bInterval = isoc_interval; | ||
410 | hs_iso_sink_desc.bEndpointAddress = | ||
411 | fs_iso_sink_desc.bEndpointAddress; | ||
412 | |||
222 | f->hs_descriptors = hs_source_sink_descs; | 413 | f->hs_descriptors = hs_source_sink_descs; |
223 | } | 414 | } |
224 | 415 | ||
@@ -228,13 +419,39 @@ autoconf_fail: | |||
228 | fs_source_desc.bEndpointAddress; | 419 | fs_source_desc.bEndpointAddress; |
229 | ss_sink_desc.bEndpointAddress = | 420 | ss_sink_desc.bEndpointAddress = |
230 | fs_sink_desc.bEndpointAddress; | 421 | fs_sink_desc.bEndpointAddress; |
422 | |||
423 | /* | ||
424 | * Fill in the SS isoc descriptors from the module parameters. | ||
425 | * We assume that the user knows what they are doing and won't | ||
426 | * give parameters that their UDC doesn't support. | ||
427 | */ | ||
428 | ss_iso_source_desc.wMaxPacketSize = isoc_maxpacket; | ||
429 | ss_iso_source_desc.bInterval = isoc_interval; | ||
430 | ss_iso_source_comp_desc.bmAttributes = isoc_mult; | ||
431 | ss_iso_source_comp_desc.bMaxBurst = isoc_maxburst; | ||
432 | ss_iso_source_comp_desc.wBytesPerInterval = | ||
433 | isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1); | ||
434 | ss_iso_source_desc.bEndpointAddress = | ||
435 | fs_iso_source_desc.bEndpointAddress; | ||
436 | |||
437 | ss_iso_sink_desc.wMaxPacketSize = isoc_maxpacket; | ||
438 | ss_iso_sink_desc.bInterval = isoc_interval; | ||
439 | ss_iso_sink_comp_desc.bmAttributes = isoc_mult; | ||
440 | ss_iso_sink_comp_desc.bMaxBurst = isoc_maxburst; | ||
441 | ss_iso_sink_comp_desc.wBytesPerInterval = | ||
442 | isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1); | ||
443 | ss_iso_sink_desc.bEndpointAddress = | ||
444 | fs_iso_sink_desc.bEndpointAddress; | ||
445 | |||
231 | f->ss_descriptors = ss_source_sink_descs; | 446 | f->ss_descriptors = ss_source_sink_descs; |
232 | } | 447 | } |
233 | 448 | ||
234 | DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", | 449 | DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s\n", |
235 | (gadget_is_superspeed(c->cdev->gadget) ? "super" : | 450 | (gadget_is_superspeed(c->cdev->gadget) ? "super" : |
236 | (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")), | 451 | (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")), |
237 | f->name, ss->in_ep->name, ss->out_ep->name); | 452 | f->name, ss->in_ep->name, ss->out_ep->name, |
453 | ss->iso_in_ep ? ss->iso_in_ep->name : "<none>", | ||
454 | ss->iso_out_ep ? ss->iso_out_ep->name : "<none>"); | ||
238 | return 0; | 455 | return 0; |
239 | } | 456 | } |
240 | 457 | ||
@@ -251,6 +468,9 @@ static int check_read_data(struct f_sourcesink *ss, struct usb_request *req) | |||
251 | u8 *buf = req->buf; | 468 | u8 *buf = req->buf; |
252 | struct usb_composite_dev *cdev = ss->function.config->cdev; | 469 | struct usb_composite_dev *cdev = ss->function.config->cdev; |
253 | 470 | ||
471 | if (pattern == 2) | ||
472 | return 0; | ||
473 | |||
254 | for (i = 0; i < req->actual; i++, buf++) { | 474 | for (i = 0; i < req->actual; i++, buf++) { |
255 | switch (pattern) { | 475 | switch (pattern) { |
256 | 476 | ||
@@ -265,7 +485,7 @@ static int check_read_data(struct f_sourcesink *ss, struct usb_request *req) | |||
265 | * each usb transfer request should be. Resync is done | 485 | * each usb transfer request should be. Resync is done |
266 | * with set_interface or set_config. (We *WANT* it to | 486 | * with set_interface or set_config. (We *WANT* it to |
267 | * get quickly out of sync if controllers or their drivers | 487 | * get quickly out of sync if controllers or their drivers |
268 | * stutter for any reason, including buffer duplcation...) | 488 | * stutter for any reason, including buffer duplication...) |
269 | */ | 489 | */ |
270 | case 1: | 490 | case 1: |
271 | if (*buf == (u8)(i % 63)) | 491 | if (*buf == (u8)(i % 63)) |
@@ -292,21 +512,30 @@ static void reinit_write_data(struct usb_ep *ep, struct usb_request *req) | |||
292 | for (i = 0; i < req->length; i++) | 512 | for (i = 0; i < req->length; i++) |
293 | *buf++ = (u8) (i % 63); | 513 | *buf++ = (u8) (i % 63); |
294 | break; | 514 | break; |
515 | case 2: | ||
516 | break; | ||
295 | } | 517 | } |
296 | } | 518 | } |
297 | 519 | ||
298 | static void source_sink_complete(struct usb_ep *ep, struct usb_request *req) | 520 | static void source_sink_complete(struct usb_ep *ep, struct usb_request *req) |
299 | { | 521 | { |
300 | struct f_sourcesink *ss = ep->driver_data; | 522 | struct usb_composite_dev *cdev; |
301 | struct usb_composite_dev *cdev = ss->function.config->cdev; | 523 | struct f_sourcesink *ss = ep->driver_data; |
302 | int status = req->status; | 524 | int status = req->status; |
525 | |||
526 | /* driver_data will be null if ep has been disabled */ | ||
527 | if (!ss) | ||
528 | return; | ||
529 | |||
530 | cdev = ss->function.config->cdev; | ||
303 | 531 | ||
304 | switch (status) { | 532 | switch (status) { |
305 | 533 | ||
306 | case 0: /* normal completion? */ | 534 | case 0: /* normal completion? */ |
307 | if (ep == ss->out_ep) { | 535 | if (ep == ss->out_ep) { |
308 | check_read_data(ss, req); | 536 | check_read_data(ss, req); |
309 | memset(req->buf, 0x55, req->length); | 537 | if (pattern != 2) |
538 | memset(req->buf, 0x55, req->length); | ||
310 | } else | 539 | } else |
311 | reinit_write_data(ep, req); | 540 | reinit_write_data(ep, req); |
312 | break; | 541 | break; |
@@ -344,32 +573,57 @@ static void source_sink_complete(struct usb_ep *ep, struct usb_request *req) | |||
344 | } | 573 | } |
345 | } | 574 | } |
346 | 575 | ||
347 | static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in) | 576 | static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in, |
577 | bool is_iso, int speed) | ||
348 | { | 578 | { |
349 | struct usb_ep *ep; | 579 | struct usb_ep *ep; |
350 | struct usb_request *req; | 580 | struct usb_request *req; |
351 | int status; | 581 | int i, size, status; |
582 | |||
583 | for (i = 0; i < 8; i++) { | ||
584 | if (is_iso) { | ||
585 | switch (speed) { | ||
586 | case USB_SPEED_SUPER: | ||
587 | size = isoc_maxpacket * (isoc_mult + 1) * | ||
588 | (isoc_maxburst + 1); | ||
589 | break; | ||
590 | case USB_SPEED_HIGH: | ||
591 | size = isoc_maxpacket * (isoc_mult + 1); | ||
592 | break; | ||
593 | default: | ||
594 | size = isoc_maxpacket > 1023 ? | ||
595 | 1023 : isoc_maxpacket; | ||
596 | break; | ||
597 | } | ||
598 | ep = is_in ? ss->iso_in_ep : ss->iso_out_ep; | ||
599 | req = alloc_ep_req(ep, size); | ||
600 | } else { | ||
601 | ep = is_in ? ss->in_ep : ss->out_ep; | ||
602 | req = alloc_ep_req(ep, 0); | ||
603 | } | ||
352 | 604 | ||
353 | ep = is_in ? ss->in_ep : ss->out_ep; | 605 | if (!req) |
354 | req = alloc_ep_req(ep); | 606 | return -ENOMEM; |
355 | if (!req) | ||
356 | return -ENOMEM; | ||
357 | 607 | ||
358 | req->complete = source_sink_complete; | 608 | req->complete = source_sink_complete; |
359 | if (is_in) | 609 | if (is_in) |
360 | reinit_write_data(ep, req); | 610 | reinit_write_data(ep, req); |
361 | else | 611 | else if (pattern != 2) |
362 | memset(req->buf, 0x55, req->length); | 612 | memset(req->buf, 0x55, req->length); |
363 | 613 | ||
364 | status = usb_ep_queue(ep, req, GFP_ATOMIC); | 614 | status = usb_ep_queue(ep, req, GFP_ATOMIC); |
365 | if (status) { | 615 | if (status) { |
366 | struct usb_composite_dev *cdev; | 616 | struct usb_composite_dev *cdev; |
367 | 617 | ||
368 | cdev = ss->function.config->cdev; | 618 | cdev = ss->function.config->cdev; |
369 | ERROR(cdev, "start %s %s --> %d\n", | 619 | ERROR(cdev, "start %s%s %s --> %d\n", |
370 | is_in ? "IN" : "OUT", | 620 | is_iso ? "ISO-" : "", is_in ? "IN" : "OUT", |
371 | ep->name, status); | 621 | ep->name, status); |
372 | free_ep_req(ep, req); | 622 | free_ep_req(ep, req); |
623 | } | ||
624 | |||
625 | if (!is_iso) | ||
626 | break; | ||
373 | } | 627 | } |
374 | 628 | ||
375 | return status; | 629 | return status; |
@@ -380,17 +634,20 @@ static void disable_source_sink(struct f_sourcesink *ss) | |||
380 | struct usb_composite_dev *cdev; | 634 | struct usb_composite_dev *cdev; |
381 | 635 | ||
382 | cdev = ss->function.config->cdev; | 636 | cdev = ss->function.config->cdev; |
383 | disable_endpoints(cdev, ss->in_ep, ss->out_ep); | 637 | disable_endpoints(cdev, ss->in_ep, ss->out_ep, ss->iso_in_ep, |
638 | ss->iso_out_ep); | ||
384 | VDBG(cdev, "%s disabled\n", ss->function.name); | 639 | VDBG(cdev, "%s disabled\n", ss->function.name); |
385 | } | 640 | } |
386 | 641 | ||
387 | static int | 642 | static int |
388 | enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss) | 643 | enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss, |
644 | int alt) | ||
389 | { | 645 | { |
390 | int result = 0; | 646 | int result = 0; |
647 | int speed = cdev->gadget->speed; | ||
391 | struct usb_ep *ep; | 648 | struct usb_ep *ep; |
392 | 649 | ||
393 | /* one endpoint writes (sources) zeroes IN (to the host) */ | 650 | /* one bulk endpoint writes (sources) zeroes IN (to the host) */ |
394 | ep = ss->in_ep; | 651 | ep = ss->in_ep; |
395 | result = config_ep_by_speed(cdev->gadget, &(ss->function), ep); | 652 | result = config_ep_by_speed(cdev->gadget, &(ss->function), ep); |
396 | if (result) | 653 | if (result) |
@@ -400,7 +657,7 @@ enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss) | |||
400 | return result; | 657 | return result; |
401 | ep->driver_data = ss; | 658 | ep->driver_data = ss; |
402 | 659 | ||
403 | result = source_sink_start_ep(ss, true); | 660 | result = source_sink_start_ep(ss, true, false, speed); |
404 | if (result < 0) { | 661 | if (result < 0) { |
405 | fail: | 662 | fail: |
406 | ep = ss->in_ep; | 663 | ep = ss->in_ep; |
@@ -409,7 +666,7 @@ fail: | |||
409 | return result; | 666 | return result; |
410 | } | 667 | } |
411 | 668 | ||
412 | /* one endpoint reads (sinks) anything OUT (from the host) */ | 669 | /* one bulk endpoint reads (sinks) anything OUT (from the host) */ |
413 | ep = ss->out_ep; | 670 | ep = ss->out_ep; |
414 | result = config_ep_by_speed(cdev->gadget, &(ss->function), ep); | 671 | result = config_ep_by_speed(cdev->gadget, &(ss->function), ep); |
415 | if (result) | 672 | if (result) |
@@ -419,27 +676,82 @@ fail: | |||
419 | goto fail; | 676 | goto fail; |
420 | ep->driver_data = ss; | 677 | ep->driver_data = ss; |
421 | 678 | ||
422 | result = source_sink_start_ep(ss, false); | 679 | result = source_sink_start_ep(ss, false, false, speed); |
423 | if (result < 0) { | 680 | if (result < 0) { |
681 | fail2: | ||
682 | ep = ss->out_ep; | ||
424 | usb_ep_disable(ep); | 683 | usb_ep_disable(ep); |
425 | ep->driver_data = NULL; | 684 | ep->driver_data = NULL; |
426 | goto fail; | 685 | goto fail; |
427 | } | 686 | } |
428 | 687 | ||
429 | DBG(cdev, "%s enabled\n", ss->function.name); | 688 | if (alt == 0) |
689 | goto out; | ||
690 | |||
691 | /* one iso endpoint writes (sources) zeroes IN (to the host) */ | ||
692 | ep = ss->iso_in_ep; | ||
693 | if (ep) { | ||
694 | result = config_ep_by_speed(cdev->gadget, &(ss->function), ep); | ||
695 | if (result) | ||
696 | goto fail2; | ||
697 | result = usb_ep_enable(ep); | ||
698 | if (result < 0) | ||
699 | goto fail2; | ||
700 | ep->driver_data = ss; | ||
701 | |||
702 | result = source_sink_start_ep(ss, true, true, speed); | ||
703 | if (result < 0) { | ||
704 | fail3: | ||
705 | ep = ss->iso_in_ep; | ||
706 | if (ep) { | ||
707 | usb_ep_disable(ep); | ||
708 | ep->driver_data = NULL; | ||
709 | } | ||
710 | goto fail2; | ||
711 | } | ||
712 | } | ||
713 | |||
714 | /* one iso endpoint reads (sinks) anything OUT (from the host) */ | ||
715 | ep = ss->iso_out_ep; | ||
716 | if (ep) { | ||
717 | result = config_ep_by_speed(cdev->gadget, &(ss->function), ep); | ||
718 | if (result) | ||
719 | goto fail3; | ||
720 | result = usb_ep_enable(ep); | ||
721 | if (result < 0) | ||
722 | goto fail3; | ||
723 | ep->driver_data = ss; | ||
724 | |||
725 | result = source_sink_start_ep(ss, false, true, speed); | ||
726 | if (result < 0) { | ||
727 | usb_ep_disable(ep); | ||
728 | ep->driver_data = NULL; | ||
729 | goto fail3; | ||
730 | } | ||
731 | } | ||
732 | out: | ||
733 | ss->cur_alt = alt; | ||
734 | |||
735 | DBG(cdev, "%s enabled, alt intf %d\n", ss->function.name, alt); | ||
430 | return result; | 736 | return result; |
431 | } | 737 | } |
432 | 738 | ||
433 | static int sourcesink_set_alt(struct usb_function *f, | 739 | static int sourcesink_set_alt(struct usb_function *f, |
434 | unsigned intf, unsigned alt) | 740 | unsigned intf, unsigned alt) |
435 | { | 741 | { |
436 | struct f_sourcesink *ss = func_to_ss(f); | 742 | struct f_sourcesink *ss = func_to_ss(f); |
437 | struct usb_composite_dev *cdev = f->config->cdev; | 743 | struct usb_composite_dev *cdev = f->config->cdev; |
438 | 744 | ||
439 | /* we know alt is zero */ | ||
440 | if (ss->in_ep->driver_data) | 745 | if (ss->in_ep->driver_data) |
441 | disable_source_sink(ss); | 746 | disable_source_sink(ss); |
442 | return enable_source_sink(cdev, ss); | 747 | return enable_source_sink(cdev, ss, alt); |
748 | } | ||
749 | |||
750 | static int sourcesink_get_alt(struct usb_function *f, unsigned intf) | ||
751 | { | ||
752 | struct f_sourcesink *ss = func_to_ss(f); | ||
753 | |||
754 | return ss->cur_alt; | ||
443 | } | 755 | } |
444 | 756 | ||
445 | static void sourcesink_disable(struct usb_function *f) | 757 | static void sourcesink_disable(struct usb_function *f) |
@@ -465,6 +777,7 @@ static int __init sourcesink_bind_config(struct usb_configuration *c) | |||
465 | ss->function.bind = sourcesink_bind; | 777 | ss->function.bind = sourcesink_bind; |
466 | ss->function.unbind = sourcesink_unbind; | 778 | ss->function.unbind = sourcesink_unbind; |
467 | ss->function.set_alt = sourcesink_set_alt; | 779 | ss->function.set_alt = sourcesink_set_alt; |
780 | ss->function.get_alt = sourcesink_get_alt; | ||
468 | ss->function.disable = sourcesink_disable; | 781 | ss->function.disable = sourcesink_disable; |
469 | 782 | ||
470 | status = usb_add_function(c, &ss->function); | 783 | status = usb_add_function(c, &ss->function); |
@@ -536,7 +849,7 @@ unknown: | |||
536 | req->length = value; | 849 | req->length = value; |
537 | value = usb_ep_queue(c->cdev->gadget->ep0, req, GFP_ATOMIC); | 850 | value = usb_ep_queue(c->cdev->gadget->ep0, req, GFP_ATOMIC); |
538 | if (value < 0) | 851 | if (value < 0) |
539 | ERROR(c->cdev, "source/sinkc response, err %d\n", | 852 | ERROR(c->cdev, "source/sink response, err %d\n", |
540 | value); | 853 | value); |
541 | } | 854 | } |
542 | 855 | ||
@@ -545,12 +858,12 @@ unknown: | |||
545 | } | 858 | } |
546 | 859 | ||
547 | static struct usb_configuration sourcesink_driver = { | 860 | static struct usb_configuration sourcesink_driver = { |
548 | .label = "source/sink", | 861 | .label = "source/sink", |
549 | .strings = sourcesink_strings, | 862 | .strings = sourcesink_strings, |
550 | .setup = sourcesink_setup, | 863 | .setup = sourcesink_setup, |
551 | .bConfigurationValue = 3, | 864 | .bConfigurationValue = 3, |
552 | .bmAttributes = USB_CONFIG_ATT_SELFPOWER, | 865 | .bmAttributes = USB_CONFIG_ATT_SELFPOWER, |
553 | /* .iConfiguration = DYNAMIC */ | 866 | /* .iConfiguration = DYNAMIC */ |
554 | }; | 867 | }; |
555 | 868 | ||
556 | /** | 869 | /** |
@@ -567,7 +880,8 @@ int __init sourcesink_add(struct usb_composite_dev *cdev, bool autoresume) | |||
567 | return id; | 880 | return id; |
568 | strings_sourcesink[0].id = id; | 881 | strings_sourcesink[0].id = id; |
569 | 882 | ||
570 | source_sink_intf.iInterface = id; | 883 | source_sink_intf_alt0.iInterface = id; |
884 | source_sink_intf_alt1.iInterface = id; | ||
571 | sourcesink_driver.iConfiguration = id; | 885 | sourcesink_driver.iConfiguration = id; |
572 | 886 | ||
573 | /* support autoresume for remote wakeup testing */ | 887 | /* support autoresume for remote wakeup testing */ |
diff --git a/drivers/usb/gadget/g_zero.h b/drivers/usb/gadget/g_zero.h index e84b3c47ed3c..71ca193358b8 100644 --- a/drivers/usb/gadget/g_zero.h +++ b/drivers/usb/gadget/g_zero.h | |||
@@ -13,10 +13,11 @@ extern unsigned buflen; | |||
13 | extern const struct usb_descriptor_header *otg_desc[]; | 13 | extern const struct usb_descriptor_header *otg_desc[]; |
14 | 14 | ||
15 | /* common utilities */ | 15 | /* common utilities */ |
16 | struct usb_request *alloc_ep_req(struct usb_ep *ep); | 16 | struct usb_request *alloc_ep_req(struct usb_ep *ep, int len); |
17 | void free_ep_req(struct usb_ep *ep, struct usb_request *req); | 17 | void free_ep_req(struct usb_ep *ep, struct usb_request *req); |
18 | void disable_endpoints(struct usb_composite_dev *cdev, | 18 | void disable_endpoints(struct usb_composite_dev *cdev, |
19 | struct usb_ep *in, struct usb_ep *out); | 19 | struct usb_ep *in, struct usb_ep *out, |
20 | struct usb_ep *iso_in, struct usb_ep *iso_out); | ||
20 | 21 | ||
21 | /* configuration-specific linkup */ | 22 | /* configuration-specific linkup */ |
22 | int sourcesink_add(struct usb_composite_dev *cdev, bool autoresume); | 23 | int sourcesink_add(struct usb_composite_dev *cdev, bool autoresume); |
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 31d34832907e..12ad516ada77 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c | |||
@@ -72,7 +72,7 @@ | |||
72 | 72 | ||
73 | static const char longname[] = "Gadget Zero"; | 73 | static const char longname[] = "Gadget Zero"; |
74 | 74 | ||
75 | unsigned buflen = 4096; | 75 | unsigned buflen = 4096; /* only used for bulk endpoints */ |
76 | module_param(buflen, uint, 0); | 76 | module_param(buflen, uint, 0); |
77 | 77 | ||
78 | /* | 78 | /* |
@@ -170,14 +170,17 @@ static struct usb_gadget_strings *dev_strings[] = { | |||
170 | 170 | ||
171 | /*-------------------------------------------------------------------------*/ | 171 | /*-------------------------------------------------------------------------*/ |
172 | 172 | ||
173 | struct usb_request *alloc_ep_req(struct usb_ep *ep) | 173 | struct usb_request *alloc_ep_req(struct usb_ep *ep, int len) |
174 | { | 174 | { |
175 | struct usb_request *req; | 175 | struct usb_request *req; |
176 | 176 | ||
177 | req = usb_ep_alloc_request(ep, GFP_ATOMIC); | 177 | req = usb_ep_alloc_request(ep, GFP_ATOMIC); |
178 | if (req) { | 178 | if (req) { |
179 | req->length = buflen; | 179 | if (len) |
180 | req->buf = kmalloc(buflen, GFP_ATOMIC); | 180 | req->length = len; |
181 | else | ||
182 | req->length = buflen; | ||
183 | req->buf = kmalloc(req->length, GFP_ATOMIC); | ||
181 | if (!req->buf) { | 184 | if (!req->buf) { |
182 | usb_ep_free_request(ep, req); | 185 | usb_ep_free_request(ep, req); |
183 | req = NULL; | 186 | req = NULL; |
@@ -206,10 +209,15 @@ static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep) | |||
206 | } | 209 | } |
207 | 210 | ||
208 | void disable_endpoints(struct usb_composite_dev *cdev, | 211 | void disable_endpoints(struct usb_composite_dev *cdev, |
209 | struct usb_ep *in, struct usb_ep *out) | 212 | struct usb_ep *in, struct usb_ep *out, |
213 | struct usb_ep *iso_in, struct usb_ep *iso_out) | ||
210 | { | 214 | { |
211 | disable_ep(cdev, in); | 215 | disable_ep(cdev, in); |
212 | disable_ep(cdev, out); | 216 | disable_ep(cdev, out); |
217 | if (iso_in) | ||
218 | disable_ep(cdev, iso_in); | ||
219 | if (iso_out) | ||
220 | disable_ep(cdev, iso_out); | ||
213 | } | 221 | } |
214 | 222 | ||
215 | /*-------------------------------------------------------------------------*/ | 223 | /*-------------------------------------------------------------------------*/ |
@@ -311,7 +319,6 @@ static int __init zero_bind(struct usb_composite_dev *cdev) | |||
311 | device_desc.bcdDevice = cpu_to_le16(0x9999); | 319 | device_desc.bcdDevice = cpu_to_le16(0x9999); |
312 | } | 320 | } |
313 | 321 | ||
314 | |||
315 | INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname); | 322 | INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname); |
316 | 323 | ||
317 | snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", | 324 | snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", |