aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget/function/f_sourcesink.c
diff options
context:
space:
mode:
authorAmit Virdi <amit.virdi@st.com>2014-08-22 05:06:36 -0400
committerFelipe Balbi <balbi@ti.com>2014-08-27 15:13:18 -0400
commitef11982dd7a657512c362242508bb4021e0d67b6 (patch)
treec8f164cdbca20bb1543c381793a058d77a4e64d2 /drivers/usb/gadget/function/f_sourcesink.c
parentc572a217d1b81209ae5a4fe09a96db758f86f10b (diff)
usb: gadget: zero: Add support for interrupt EP
Interrupt endpoints behave quite similar to the bulk endpoints with the difference that the endpoints expect data sending/reception request at particular intervals till the whole data has not been transmitted. The interrupt EP support is added to gadget zero. A new alternate setting (=2) has been added. It has 2 interrupt endpoints. The default parameters are set as: bInterval: 1 ms for FS and 8 uFrames (implying 1 ms) for HS/SS wMaxPacketSize: 64 bytes for FS and 1024 bytes for HS/SS However, the same can be overridden through the module parameter interface. The code is tested for HS and SS on a platform having DWC3 controller. Signed-off-by: Amit Virdi <amit.virdi@st.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/gadget/function/f_sourcesink.c')
-rw-r--r--drivers/usb/gadget/function/f_sourcesink.c511
1 files changed, 491 insertions, 20 deletions
diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c
index d3cd52db78fe..7c091a328228 100644
--- a/drivers/usb/gadget/function/f_sourcesink.c
+++ b/drivers/usb/gadget/function/f_sourcesink.c
@@ -23,6 +23,15 @@
23#include "gadget_chips.h" 23#include "gadget_chips.h"
24#include "u_f.h" 24#include "u_f.h"
25 25
26#define USB_MS_TO_SS_INTERVAL(x) USB_MS_TO_HS_INTERVAL(x)
27
28enum eptype {
29 EP_CONTROL = 0,
30 EP_BULK,
31 EP_ISOC,
32 EP_INTERRUPT,
33};
34
26/* 35/*
27 * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripheral 36 * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripheral
28 * controller drivers. 37 * controller drivers.
@@ -55,6 +64,8 @@ struct f_sourcesink {
55 struct usb_ep *out_ep; 64 struct usb_ep *out_ep;
56 struct usb_ep *iso_in_ep; 65 struct usb_ep *iso_in_ep;
57 struct usb_ep *iso_out_ep; 66 struct usb_ep *iso_out_ep;
67 struct usb_ep *int_in_ep;
68 struct usb_ep *int_out_ep;
58 int cur_alt; 69 int cur_alt;
59}; 70};
60 71
@@ -68,6 +79,10 @@ static unsigned isoc_interval;
68static unsigned isoc_maxpacket; 79static unsigned isoc_maxpacket;
69static unsigned isoc_mult; 80static unsigned isoc_mult;
70static unsigned isoc_maxburst; 81static unsigned isoc_maxburst;
82static unsigned int_interval; /* In ms */
83static unsigned int_maxpacket;
84static unsigned int_mult;
85static unsigned int_maxburst;
71static unsigned buflen; 86static unsigned buflen;
72 87
73/*-------------------------------------------------------------------------*/ 88/*-------------------------------------------------------------------------*/
@@ -92,6 +107,16 @@ static struct usb_interface_descriptor source_sink_intf_alt1 = {
92 /* .iInterface = DYNAMIC */ 107 /* .iInterface = DYNAMIC */
93}; 108};
94 109
110static struct usb_interface_descriptor source_sink_intf_alt2 = {
111 .bLength = USB_DT_INTERFACE_SIZE,
112 .bDescriptorType = USB_DT_INTERFACE,
113
114 .bAlternateSetting = 2,
115 .bNumEndpoints = 2,
116 .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
117 /* .iInterface = DYNAMIC */
118};
119
95/* full speed support: */ 120/* full speed support: */
96 121
97static struct usb_endpoint_descriptor fs_source_desc = { 122static struct usb_endpoint_descriptor fs_source_desc = {
@@ -130,6 +155,26 @@ static struct usb_endpoint_descriptor fs_iso_sink_desc = {
130 .bInterval = 4, 155 .bInterval = 4,
131}; 156};
132 157
158static struct usb_endpoint_descriptor fs_int_source_desc = {
159 .bLength = USB_DT_ENDPOINT_SIZE,
160 .bDescriptorType = USB_DT_ENDPOINT,
161
162 .bEndpointAddress = USB_DIR_IN,
163 .bmAttributes = USB_ENDPOINT_XFER_INT,
164 .wMaxPacketSize = cpu_to_le16(64),
165 .bInterval = GZERO_INT_INTERVAL,
166};
167
168static struct usb_endpoint_descriptor fs_int_sink_desc = {
169 .bLength = USB_DT_ENDPOINT_SIZE,
170 .bDescriptorType = USB_DT_ENDPOINT,
171
172 .bEndpointAddress = USB_DIR_OUT,
173 .bmAttributes = USB_ENDPOINT_XFER_INT,
174 .wMaxPacketSize = cpu_to_le16(64),
175 .bInterval = GZERO_INT_INTERVAL,
176};
177
133static struct usb_descriptor_header *fs_source_sink_descs[] = { 178static struct usb_descriptor_header *fs_source_sink_descs[] = {
134 (struct usb_descriptor_header *) &source_sink_intf_alt0, 179 (struct usb_descriptor_header *) &source_sink_intf_alt0,
135 (struct usb_descriptor_header *) &fs_sink_desc, 180 (struct usb_descriptor_header *) &fs_sink_desc,
@@ -140,6 +185,10 @@ static struct usb_descriptor_header *fs_source_sink_descs[] = {
140 (struct usb_descriptor_header *) &fs_source_desc, 185 (struct usb_descriptor_header *) &fs_source_desc,
141 (struct usb_descriptor_header *) &fs_iso_sink_desc, 186 (struct usb_descriptor_header *) &fs_iso_sink_desc,
142 (struct usb_descriptor_header *) &fs_iso_source_desc, 187 (struct usb_descriptor_header *) &fs_iso_source_desc,
188 (struct usb_descriptor_header *) &source_sink_intf_alt2,
189#define FS_ALT_IFC_2_OFFSET 8
190 (struct usb_descriptor_header *) &fs_int_sink_desc,
191 (struct usb_descriptor_header *) &fs_int_source_desc,
143 NULL, 192 NULL,
144}; 193};
145 194
@@ -179,6 +228,24 @@ static struct usb_endpoint_descriptor hs_iso_sink_desc = {
179 .bInterval = 4, 228 .bInterval = 4,
180}; 229};
181 230
231static struct usb_endpoint_descriptor hs_int_source_desc = {
232 .bLength = USB_DT_ENDPOINT_SIZE,
233 .bDescriptorType = USB_DT_ENDPOINT,
234
235 .bmAttributes = USB_ENDPOINT_XFER_INT,
236 .wMaxPacketSize = cpu_to_le16(1024),
237 .bInterval = USB_MS_TO_HS_INTERVAL(GZERO_INT_INTERVAL),
238};
239
240static struct usb_endpoint_descriptor hs_int_sink_desc = {
241 .bLength = USB_DT_ENDPOINT_SIZE,
242 .bDescriptorType = USB_DT_ENDPOINT,
243
244 .bmAttributes = USB_ENDPOINT_XFER_INT,
245 .wMaxPacketSize = cpu_to_le16(1024),
246 .bInterval = USB_MS_TO_HS_INTERVAL(GZERO_INT_INTERVAL),
247};
248
182static struct usb_descriptor_header *hs_source_sink_descs[] = { 249static struct usb_descriptor_header *hs_source_sink_descs[] = {
183 (struct usb_descriptor_header *) &source_sink_intf_alt0, 250 (struct usb_descriptor_header *) &source_sink_intf_alt0,
184 (struct usb_descriptor_header *) &hs_source_desc, 251 (struct usb_descriptor_header *) &hs_source_desc,
@@ -189,6 +256,10 @@ static struct usb_descriptor_header *hs_source_sink_descs[] = {
189 (struct usb_descriptor_header *) &hs_sink_desc, 256 (struct usb_descriptor_header *) &hs_sink_desc,
190 (struct usb_descriptor_header *) &hs_iso_source_desc, 257 (struct usb_descriptor_header *) &hs_iso_source_desc,
191 (struct usb_descriptor_header *) &hs_iso_sink_desc, 258 (struct usb_descriptor_header *) &hs_iso_sink_desc,
259 (struct usb_descriptor_header *) &source_sink_intf_alt2,
260#define HS_ALT_IFC_2_OFFSET 8
261 (struct usb_descriptor_header *) &hs_int_source_desc,
262 (struct usb_descriptor_header *) &hs_int_sink_desc,
192 NULL, 263 NULL,
193}; 264};
194 265
@@ -264,6 +335,42 @@ static struct usb_ss_ep_comp_descriptor ss_iso_sink_comp_desc = {
264 .wBytesPerInterval = cpu_to_le16(1024), 335 .wBytesPerInterval = cpu_to_le16(1024),
265}; 336};
266 337
338static struct usb_endpoint_descriptor ss_int_source_desc = {
339 .bLength = USB_DT_ENDPOINT_SIZE,
340 .bDescriptorType = USB_DT_ENDPOINT,
341
342 .bmAttributes = USB_ENDPOINT_XFER_INT,
343 .wMaxPacketSize = cpu_to_le16(1024),
344 .bInterval = USB_MS_TO_SS_INTERVAL(GZERO_INT_INTERVAL),
345};
346
347struct usb_ss_ep_comp_descriptor ss_int_source_comp_desc = {
348 .bLength = USB_DT_SS_EP_COMP_SIZE,
349 .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
350
351 .bMaxBurst = 0,
352 .bmAttributes = 0,
353 .wBytesPerInterval = cpu_to_le16(1024),
354};
355
356static struct usb_endpoint_descriptor ss_int_sink_desc = {
357 .bLength = USB_DT_ENDPOINT_SIZE,
358 .bDescriptorType = USB_DT_ENDPOINT,
359
360 .bmAttributes = USB_ENDPOINT_XFER_INT,
361 .wMaxPacketSize = cpu_to_le16(1024),
362 .bInterval = USB_MS_TO_SS_INTERVAL(GZERO_INT_INTERVAL),
363};
364
365struct usb_ss_ep_comp_descriptor ss_int_sink_comp_desc = {
366 .bLength = USB_DT_SS_EP_COMP_SIZE,
367 .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
368
369 .bMaxBurst = 0,
370 .bmAttributes = 0,
371 .wBytesPerInterval = cpu_to_le16(1024),
372};
373
267static struct usb_descriptor_header *ss_source_sink_descs[] = { 374static struct usb_descriptor_header *ss_source_sink_descs[] = {
268 (struct usb_descriptor_header *) &source_sink_intf_alt0, 375 (struct usb_descriptor_header *) &source_sink_intf_alt0,
269 (struct usb_descriptor_header *) &ss_source_desc, 376 (struct usb_descriptor_header *) &ss_source_desc,
@@ -280,6 +387,12 @@ static struct usb_descriptor_header *ss_source_sink_descs[] = {
280 (struct usb_descriptor_header *) &ss_iso_source_comp_desc, 387 (struct usb_descriptor_header *) &ss_iso_source_comp_desc,
281 (struct usb_descriptor_header *) &ss_iso_sink_desc, 388 (struct usb_descriptor_header *) &ss_iso_sink_desc,
282 (struct usb_descriptor_header *) &ss_iso_sink_comp_desc, 389 (struct usb_descriptor_header *) &ss_iso_sink_comp_desc,
390 (struct usb_descriptor_header *) &source_sink_intf_alt2,
391#define SS_ALT_IFC_2_OFFSET 14
392 (struct usb_descriptor_header *) &ss_int_source_desc,
393 (struct usb_descriptor_header *) &ss_int_source_comp_desc,
394 (struct usb_descriptor_header *) &ss_int_sink_desc,
395 (struct usb_descriptor_header *) &ss_int_sink_comp_desc,
283 NULL, 396 NULL,
284}; 397};
285 398
@@ -301,6 +414,21 @@ static struct usb_gadget_strings *sourcesink_strings[] = {
301}; 414};
302 415
303/*-------------------------------------------------------------------------*/ 416/*-------------------------------------------------------------------------*/
417static const char *get_ep_string(enum eptype ep_type)
418{
419 switch (ep_type) {
420 case EP_ISOC:
421 return "ISOC-";
422 case EP_INTERRUPT:
423 return "INTERRUPT-";
424 case EP_CONTROL:
425 return "CTRL-";
426 case EP_BULK:
427 return "BULK-";
428 default:
429 return "UNKNOWN-";
430 }
431}
304 432
305static inline struct usb_request *ss_alloc_ep_req(struct usb_ep *ep, int len) 433static inline struct usb_request *ss_alloc_ep_req(struct usb_ep *ep, int len)
306{ 434{
@@ -328,7 +456,8 @@ static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep)
328 456
329void disable_endpoints(struct usb_composite_dev *cdev, 457void disable_endpoints(struct usb_composite_dev *cdev,
330 struct usb_ep *in, struct usb_ep *out, 458 struct usb_ep *in, struct usb_ep *out,
331 struct usb_ep *iso_in, struct usb_ep *iso_out) 459 struct usb_ep *iso_in, struct usb_ep *iso_out,
460 struct usb_ep *int_in, struct usb_ep *int_out)
332{ 461{
333 disable_ep(cdev, in); 462 disable_ep(cdev, in);
334 disable_ep(cdev, out); 463 disable_ep(cdev, out);
@@ -336,6 +465,10 @@ void disable_endpoints(struct usb_composite_dev *cdev,
336 disable_ep(cdev, iso_in); 465 disable_ep(cdev, iso_in);
337 if (iso_out) 466 if (iso_out)
338 disable_ep(cdev, iso_out); 467 disable_ep(cdev, iso_out);
468 if (int_in)
469 disable_ep(cdev, int_in);
470 if (int_out)
471 disable_ep(cdev, int_out);
339} 472}
340 473
341static int 474static int
@@ -352,6 +485,7 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
352 return id; 485 return id;
353 source_sink_intf_alt0.bInterfaceNumber = id; 486 source_sink_intf_alt0.bInterfaceNumber = id;
354 source_sink_intf_alt1.bInterfaceNumber = id; 487 source_sink_intf_alt1.bInterfaceNumber = id;
488 source_sink_intf_alt2.bInterfaceNumber = id;
355 489
356 /* allocate bulk endpoints */ 490 /* allocate bulk endpoints */
357 ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc); 491 ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc);
@@ -412,14 +546,55 @@ no_iso:
412 if (isoc_maxpacket > 1024) 546 if (isoc_maxpacket > 1024)
413 isoc_maxpacket = 1024; 547 isoc_maxpacket = 1024;
414 548
549 /* sanity check the interrupt module parameters */
550 if (int_interval < 1)
551 int_interval = 1;
552 if (int_interval > 4096)
553 int_interval = 4096;
554 if (int_mult > 2)
555 int_mult = 2;
556 if (int_maxburst > 15)
557 int_maxburst = 15;
558
559 /* fill in the FS interrupt descriptors from the module parameters */
560 fs_int_source_desc.wMaxPacketSize = int_maxpacket > 64 ?
561 64 : int_maxpacket;
562 fs_int_source_desc.bInterval = int_interval > 255 ?
563 255 : int_interval;
564 fs_int_sink_desc.wMaxPacketSize = int_maxpacket > 64 ?
565 64 : int_maxpacket;
566 fs_int_sink_desc.bInterval = int_interval > 255 ?
567 255 : int_interval;
568
569 /* allocate int endpoints */
570 ss->int_in_ep = usb_ep_autoconfig(cdev->gadget, &fs_int_source_desc);
571 if (!ss->int_in_ep)
572 goto no_int;
573 ss->int_in_ep->driver_data = cdev; /* claim */
574
575 ss->int_out_ep = usb_ep_autoconfig(cdev->gadget, &fs_int_sink_desc);
576 if (ss->int_out_ep) {
577 ss->int_out_ep->driver_data = cdev; /* claim */
578 } else {
579 ss->int_in_ep->driver_data = NULL;
580 ss->int_in_ep = NULL;
581no_int:
582 fs_source_sink_descs[FS_ALT_IFC_2_OFFSET] = NULL;
583 hs_source_sink_descs[HS_ALT_IFC_2_OFFSET] = NULL;
584 ss_source_sink_descs[SS_ALT_IFC_2_OFFSET] = NULL;
585 }
586
587 if (int_maxpacket > 1024)
588 int_maxpacket = 1024;
589
415 /* support high speed hardware */ 590 /* support high speed hardware */
416 hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; 591 hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
417 hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; 592 hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
418 593
419 /* 594 /*
420 * Fill in the HS isoc descriptors from the module parameters. 595 * Fill in the HS isoc and interrupt descriptors from the module
421 * We assume that the user knows what they are doing and won't 596 * parameters. We assume that the user knows what they are doing and
422 * give parameters that their UDC doesn't support. 597 * won't give parameters that their UDC doesn't support.
423 */ 598 */
424 hs_iso_source_desc.wMaxPacketSize = isoc_maxpacket; 599 hs_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
425 hs_iso_source_desc.wMaxPacketSize |= isoc_mult << 11; 600 hs_iso_source_desc.wMaxPacketSize |= isoc_mult << 11;
@@ -432,6 +607,17 @@ no_iso:
432 hs_iso_sink_desc.bInterval = isoc_interval; 607 hs_iso_sink_desc.bInterval = isoc_interval;
433 hs_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress; 608 hs_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
434 609
610 hs_int_source_desc.wMaxPacketSize = int_maxpacket;
611 hs_int_source_desc.wMaxPacketSize |= int_mult << 11;
612 hs_int_source_desc.bInterval = USB_MS_TO_HS_INTERVAL(int_interval);
613 hs_int_source_desc.bEndpointAddress =
614 fs_int_source_desc.bEndpointAddress;
615
616 hs_int_sink_desc.wMaxPacketSize = int_maxpacket;
617 hs_int_sink_desc.wMaxPacketSize |= int_mult << 11;
618 hs_int_sink_desc.bInterval = USB_MS_TO_HS_INTERVAL(int_interval);
619 hs_int_sink_desc.bEndpointAddress = fs_int_sink_desc.bEndpointAddress;
620
435 /* support super speed hardware */ 621 /* support super speed hardware */
436 ss_source_desc.bEndpointAddress = 622 ss_source_desc.bEndpointAddress =
437 fs_source_desc.bEndpointAddress; 623 fs_source_desc.bEndpointAddress;
@@ -439,9 +625,9 @@ no_iso:
439 fs_sink_desc.bEndpointAddress; 625 fs_sink_desc.bEndpointAddress;
440 626
441 /* 627 /*
442 * Fill in the SS isoc descriptors from the module parameters. 628 * Fill in the SS isoc and interrupt descriptors from the module
443 * We assume that the user knows what they are doing and won't 629 * parameters. We assume that the user knows what they are doing and
444 * give parameters that their UDC doesn't support. 630 * won't give parameters that their UDC doesn't support.
445 */ 631 */
446 ss_iso_source_desc.wMaxPacketSize = isoc_maxpacket; 632 ss_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
447 ss_iso_source_desc.bInterval = isoc_interval; 633 ss_iso_source_desc.bInterval = isoc_interval;
@@ -460,17 +646,37 @@ no_iso:
460 isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1); 646 isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1);
461 ss_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress; 647 ss_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
462 648
649 ss_int_source_desc.wMaxPacketSize = int_maxpacket;
650 ss_int_source_desc.bInterval = USB_MS_TO_SS_INTERVAL(int_interval);
651 ss_int_source_comp_desc.bmAttributes = int_mult;
652 ss_int_source_comp_desc.bMaxBurst = int_maxburst;
653 ss_int_source_comp_desc.wBytesPerInterval =
654 int_maxpacket * (int_mult + 1) * (int_maxburst + 1);
655 ss_int_source_desc.bEndpointAddress =
656 fs_int_source_desc.bEndpointAddress;
657
658 ss_int_sink_desc.wMaxPacketSize = int_maxpacket;
659 ss_int_sink_desc.bInterval = USB_MS_TO_SS_INTERVAL(int_interval);
660 ss_int_sink_comp_desc.bmAttributes = int_mult;
661 ss_int_sink_comp_desc.bMaxBurst = int_maxburst;
662 ss_int_sink_comp_desc.wBytesPerInterval =
663 int_maxpacket * (int_mult + 1) * (int_maxburst + 1);
664 ss_int_sink_desc.bEndpointAddress = fs_int_sink_desc.bEndpointAddress;
665
463 ret = usb_assign_descriptors(f, fs_source_sink_descs, 666 ret = usb_assign_descriptors(f, fs_source_sink_descs,
464 hs_source_sink_descs, ss_source_sink_descs); 667 hs_source_sink_descs, ss_source_sink_descs);
465 if (ret) 668 if (ret)
466 return ret; 669 return ret;
467 670
468 DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s\n", 671 DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s, "
672 "INT-IN/%s, INT-OUT/%s\n",
469 (gadget_is_superspeed(c->cdev->gadget) ? "super" : 673 (gadget_is_superspeed(c->cdev->gadget) ? "super" :
470 (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")), 674 (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")),
471 f->name, ss->in_ep->name, ss->out_ep->name, 675 f->name, ss->in_ep->name, ss->out_ep->name,
472 ss->iso_in_ep ? ss->iso_in_ep->name : "<none>", 676 ss->iso_in_ep ? ss->iso_in_ep->name : "<none>",
473 ss->iso_out_ep ? ss->iso_out_ep->name : "<none>"); 677 ss->iso_out_ep ? ss->iso_out_ep->name : "<none>",
678 ss->int_in_ep ? ss->int_in_ep->name : "<none>",
679 ss->int_out_ep ? ss->int_out_ep->name : "<none>");
474 return 0; 680 return 0;
475} 681}
476 682
@@ -601,14 +807,15 @@ static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
601} 807}
602 808
603static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in, 809static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
604 bool is_iso, int speed) 810 enum eptype ep_type, int speed)
605{ 811{
606 struct usb_ep *ep; 812 struct usb_ep *ep;
607 struct usb_request *req; 813 struct usb_request *req;
608 int i, size, status; 814 int i, size, status;
609 815
610 for (i = 0; i < 8; i++) { 816 for (i = 0; i < 8; i++) {
611 if (is_iso) { 817 switch (ep_type) {
818 case EP_ISOC:
612 switch (speed) { 819 switch (speed) {
613 case USB_SPEED_SUPER: 820 case USB_SPEED_SUPER:
614 size = isoc_maxpacket * (isoc_mult + 1) * 821 size = isoc_maxpacket * (isoc_mult + 1) *
@@ -624,9 +831,28 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
624 } 831 }
625 ep = is_in ? ss->iso_in_ep : ss->iso_out_ep; 832 ep = is_in ? ss->iso_in_ep : ss->iso_out_ep;
626 req = ss_alloc_ep_req(ep, size); 833 req = ss_alloc_ep_req(ep, size);
627 } else { 834 break;
835 case EP_INTERRUPT:
836 switch (speed) {
837 case USB_SPEED_SUPER:
838 size = int_maxpacket * (int_mult + 1) *
839 (int_maxburst + 1);
840 break;
841 case USB_SPEED_HIGH:
842 size = int_maxpacket * (int_mult + 1);
843 break;
844 default:
845 size = int_maxpacket > 1023 ?
846 1023 : int_maxpacket;
847 break;
848 }
849 ep = is_in ? ss->int_in_ep : ss->int_out_ep;
850 req = ss_alloc_ep_req(ep, size);
851 break;
852 default:
628 ep = is_in ? ss->in_ep : ss->out_ep; 853 ep = is_in ? ss->in_ep : ss->out_ep;
629 req = ss_alloc_ep_req(ep, 0); 854 req = ss_alloc_ep_req(ep, 0);
855 break;
630 } 856 }
631 857
632 if (!req) 858 if (!req)
@@ -644,12 +870,12 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
644 870
645 cdev = ss->function.config->cdev; 871 cdev = ss->function.config->cdev;
646 ERROR(cdev, "start %s%s %s --> %d\n", 872 ERROR(cdev, "start %s%s %s --> %d\n",
647 is_iso ? "ISO-" : "", is_in ? "IN" : "OUT", 873 get_ep_string(ep_type), is_in ? "IN" : "OUT",
648 ep->name, status); 874 ep->name, status);
649 free_ep_req(ep, req); 875 free_ep_req(ep, req);
650 } 876 }
651 877
652 if (!is_iso) 878 if (!(ep_type == EP_ISOC))
653 break; 879 break;
654 } 880 }
655 881
@@ -662,7 +888,7 @@ static void disable_source_sink(struct f_sourcesink *ss)
662 888
663 cdev = ss->function.config->cdev; 889 cdev = ss->function.config->cdev;
664 disable_endpoints(cdev, ss->in_ep, ss->out_ep, ss->iso_in_ep, 890 disable_endpoints(cdev, ss->in_ep, ss->out_ep, ss->iso_in_ep,
665 ss->iso_out_ep); 891 ss->iso_out_ep, ss->int_in_ep, ss->int_out_ep);
666 VDBG(cdev, "%s disabled\n", ss->function.name); 892 VDBG(cdev, "%s disabled\n", ss->function.name);
667} 893}
668 894
@@ -674,6 +900,62 @@ enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss,
674 int speed = cdev->gadget->speed; 900 int speed = cdev->gadget->speed;
675 struct usb_ep *ep; 901 struct usb_ep *ep;
676 902
903 if (alt == 2) {
904 /* Configure for periodic interrupt endpoint */
905 ep = ss->int_in_ep;
906 if (ep) {
907 result = config_ep_by_speed(cdev->gadget,
908 &(ss->function), ep);
909 if (result)
910 return result;
911
912 result = usb_ep_enable(ep);
913 if (result < 0)
914 return result;
915
916 ep->driver_data = ss;
917 result = source_sink_start_ep(ss, true, EP_INTERRUPT,
918 speed);
919 if (result < 0) {
920fail1:
921 ep = ss->int_in_ep;
922 if (ep) {
923 usb_ep_disable(ep);
924 ep->driver_data = NULL;
925 }
926 return result;
927 }
928 }
929
930 /*
931 * one interrupt endpoint reads (sinks) anything OUT (from the
932 * host)
933 */
934 ep = ss->int_out_ep;
935 if (ep) {
936 result = config_ep_by_speed(cdev->gadget,
937 &(ss->function), ep);
938 if (result)
939 goto fail1;
940
941 result = usb_ep_enable(ep);
942 if (result < 0)
943 goto fail1;
944
945 ep->driver_data = ss;
946 result = source_sink_start_ep(ss, false, EP_INTERRUPT,
947 speed);
948 if (result < 0) {
949 ep = ss->int_out_ep;
950 usb_ep_disable(ep);
951 ep->driver_data = NULL;
952 goto fail1;
953 }
954 }
955
956 goto out;
957 }
958
677 /* one bulk endpoint writes (sources) zeroes IN (to the host) */ 959 /* one bulk endpoint writes (sources) zeroes IN (to the host) */
678 ep = ss->in_ep; 960 ep = ss->in_ep;
679 result = config_ep_by_speed(cdev->gadget, &(ss->function), ep); 961 result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
@@ -684,7 +966,7 @@ enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss,
684 return result; 966 return result;
685 ep->driver_data = ss; 967 ep->driver_data = ss;
686 968
687 result = source_sink_start_ep(ss, true, false, speed); 969 result = source_sink_start_ep(ss, true, EP_BULK, speed);
688 if (result < 0) { 970 if (result < 0) {
689fail: 971fail:
690 ep = ss->in_ep; 972 ep = ss->in_ep;
@@ -703,7 +985,7 @@ fail:
703 goto fail; 985 goto fail;
704 ep->driver_data = ss; 986 ep->driver_data = ss;
705 987
706 result = source_sink_start_ep(ss, false, false, speed); 988 result = source_sink_start_ep(ss, false, EP_BULK, speed);
707 if (result < 0) { 989 if (result < 0) {
708fail2: 990fail2:
709 ep = ss->out_ep; 991 ep = ss->out_ep;
@@ -726,7 +1008,7 @@ fail2:
726 goto fail2; 1008 goto fail2;
727 ep->driver_data = ss; 1009 ep->driver_data = ss;
728 1010
729 result = source_sink_start_ep(ss, true, true, speed); 1011 result = source_sink_start_ep(ss, true, EP_ISOC, speed);
730 if (result < 0) { 1012 if (result < 0) {
731fail3: 1013fail3:
732 ep = ss->iso_in_ep; 1014 ep = ss->iso_in_ep;
@@ -749,13 +1031,14 @@ fail3:
749 goto fail3; 1031 goto fail3;
750 ep->driver_data = ss; 1032 ep->driver_data = ss;
751 1033
752 result = source_sink_start_ep(ss, false, true, speed); 1034 result = source_sink_start_ep(ss, false, EP_ISOC, speed);
753 if (result < 0) { 1035 if (result < 0) {
754 usb_ep_disable(ep); 1036 usb_ep_disable(ep);
755 ep->driver_data = NULL; 1037 ep->driver_data = NULL;
756 goto fail3; 1038 goto fail3;
757 } 1039 }
758 } 1040 }
1041
759out: 1042out:
760 ss->cur_alt = alt; 1043 ss->cur_alt = alt;
761 1044
@@ -771,6 +1054,8 @@ static int sourcesink_set_alt(struct usb_function *f,
771 1054
772 if (ss->in_ep->driver_data) 1055 if (ss->in_ep->driver_data)
773 disable_source_sink(ss); 1056 disable_source_sink(ss);
1057 else if (alt == 2 && ss->int_in_ep->driver_data)
1058 disable_source_sink(ss);
774 return enable_source_sink(cdev, ss, alt); 1059 return enable_source_sink(cdev, ss, alt);
775} 1060}
776 1061
@@ -883,6 +1168,10 @@ static struct usb_function *source_sink_alloc_func(
883 isoc_maxpacket = ss_opts->isoc_maxpacket; 1168 isoc_maxpacket = ss_opts->isoc_maxpacket;
884 isoc_mult = ss_opts->isoc_mult; 1169 isoc_mult = ss_opts->isoc_mult;
885 isoc_maxburst = ss_opts->isoc_maxburst; 1170 isoc_maxburst = ss_opts->isoc_maxburst;
1171 int_interval = ss_opts->int_interval;
1172 int_maxpacket = ss_opts->int_maxpacket;
1173 int_mult = ss_opts->int_mult;
1174 int_maxburst = ss_opts->int_maxburst;
886 buflen = ss_opts->bulk_buflen; 1175 buflen = ss_opts->bulk_buflen;
887 1176
888 ss->function.name = "source/sink"; 1177 ss->function.name = "source/sink";
@@ -1179,6 +1468,182 @@ static struct f_ss_opts_attribute f_ss_opts_bulk_buflen =
1179 f_ss_opts_bulk_buflen_show, 1468 f_ss_opts_bulk_buflen_show,
1180 f_ss_opts_bulk_buflen_store); 1469 f_ss_opts_bulk_buflen_store);
1181 1470
1471static ssize_t f_ss_opts_int_interval_show(struct f_ss_opts *opts, char *page)
1472{
1473 int result;
1474
1475 mutex_lock(&opts->lock);
1476 result = sprintf(page, "%d", opts->int_interval);
1477 mutex_unlock(&opts->lock);
1478
1479 return result;
1480}
1481
1482static ssize_t f_ss_opts_int_interval_store(struct f_ss_opts *opts,
1483 const char *page, size_t len)
1484{
1485 int ret;
1486 u8 num;
1487
1488 mutex_lock(&opts->lock);
1489 if (opts->refcnt) {
1490 ret = -EBUSY;
1491 goto end;
1492 }
1493
1494 ret = kstrtou8(page, 0, &num);
1495 if (ret)
1496 goto end;
1497
1498 if (num > 4096) {
1499 ret = -EINVAL;
1500 goto end;
1501 }
1502
1503 opts->int_interval = num;
1504 ret = len;
1505end:
1506 mutex_unlock(&opts->lock);
1507 return ret;
1508}
1509
1510static struct f_ss_opts_attribute f_ss_opts_int_interval =
1511 __CONFIGFS_ATTR(int_interval, S_IRUGO | S_IWUSR,
1512 f_ss_opts_int_interval_show,
1513 f_ss_opts_int_interval_store);
1514
1515static ssize_t f_ss_opts_int_maxpacket_show(struct f_ss_opts *opts, char *page)
1516{
1517 int result;
1518
1519 mutex_lock(&opts->lock);
1520 result = sprintf(page, "%d", opts->int_maxpacket);
1521 mutex_unlock(&opts->lock);
1522
1523 return result;
1524}
1525
1526static ssize_t f_ss_opts_int_maxpacket_store(struct f_ss_opts *opts,
1527 const char *page, size_t len)
1528{
1529 int ret;
1530 u16 num;
1531
1532 mutex_lock(&opts->lock);
1533 if (opts->refcnt) {
1534 ret = -EBUSY;
1535 goto end;
1536 }
1537
1538 ret = kstrtou16(page, 0, &num);
1539 if (ret)
1540 goto end;
1541
1542 if (num > 1024) {
1543 ret = -EINVAL;
1544 goto end;
1545 }
1546
1547 opts->int_maxpacket = num;
1548 ret = len;
1549end:
1550 mutex_unlock(&opts->lock);
1551 return ret;
1552}
1553
1554static struct f_ss_opts_attribute f_ss_opts_int_maxpacket =
1555 __CONFIGFS_ATTR(int_maxpacket, S_IRUGO | S_IWUSR,
1556 f_ss_opts_int_maxpacket_show,
1557 f_ss_opts_int_maxpacket_store);
1558
1559static ssize_t f_ss_opts_int_mult_show(struct f_ss_opts *opts, char *page)
1560{
1561 int result;
1562
1563 mutex_lock(&opts->lock);
1564 result = sprintf(page, "%d", opts->int_mult);
1565 mutex_unlock(&opts->lock);
1566
1567 return result;
1568}
1569
1570static ssize_t f_ss_opts_int_mult_store(struct f_ss_opts *opts,
1571 const char *page, size_t len)
1572{
1573 int ret;
1574 u8 num;
1575
1576 mutex_lock(&opts->lock);
1577 if (opts->refcnt) {
1578 ret = -EBUSY;
1579 goto end;
1580 }
1581
1582 ret = kstrtou8(page, 0, &num);
1583 if (ret)
1584 goto end;
1585
1586 if (num > 2) {
1587 ret = -EINVAL;
1588 goto end;
1589 }
1590
1591 opts->int_mult = num;
1592 ret = len;
1593end:
1594 mutex_unlock(&opts->lock);
1595 return ret;
1596}
1597
1598static struct f_ss_opts_attribute f_ss_opts_int_mult =
1599 __CONFIGFS_ATTR(int_mult, S_IRUGO | S_IWUSR,
1600 f_ss_opts_int_mult_show,
1601 f_ss_opts_int_mult_store);
1602
1603static ssize_t f_ss_opts_int_maxburst_show(struct f_ss_opts *opts, char *page)
1604{
1605 int result;
1606
1607 mutex_lock(&opts->lock);
1608 result = sprintf(page, "%d", opts->int_maxburst);
1609 mutex_unlock(&opts->lock);
1610
1611 return result;
1612}
1613
1614static ssize_t f_ss_opts_int_maxburst_store(struct f_ss_opts *opts,
1615 const char *page, size_t len)
1616{
1617 int ret;
1618 u8 num;
1619
1620 mutex_lock(&opts->lock);
1621 if (opts->refcnt) {
1622 ret = -EBUSY;
1623 goto end;
1624 }
1625
1626 ret = kstrtou8(page, 0, &num);
1627 if (ret)
1628 goto end;
1629
1630 if (num > 15) {
1631 ret = -EINVAL;
1632 goto end;
1633 }
1634
1635 opts->int_maxburst = num;
1636 ret = len;
1637end:
1638 mutex_unlock(&opts->lock);
1639 return ret;
1640}
1641
1642static struct f_ss_opts_attribute f_ss_opts_int_maxburst =
1643 __CONFIGFS_ATTR(int_maxburst, S_IRUGO | S_IWUSR,
1644 f_ss_opts_int_maxburst_show,
1645 f_ss_opts_int_maxburst_store);
1646
1182static struct configfs_attribute *ss_attrs[] = { 1647static struct configfs_attribute *ss_attrs[] = {
1183 &f_ss_opts_pattern.attr, 1648 &f_ss_opts_pattern.attr,
1184 &f_ss_opts_isoc_interval.attr, 1649 &f_ss_opts_isoc_interval.attr,
@@ -1186,6 +1651,10 @@ static struct configfs_attribute *ss_attrs[] = {
1186 &f_ss_opts_isoc_mult.attr, 1651 &f_ss_opts_isoc_mult.attr,
1187 &f_ss_opts_isoc_maxburst.attr, 1652 &f_ss_opts_isoc_maxburst.attr,
1188 &f_ss_opts_bulk_buflen.attr, 1653 &f_ss_opts_bulk_buflen.attr,
1654 &f_ss_opts_int_interval.attr,
1655 &f_ss_opts_int_maxpacket.attr,
1656 &f_ss_opts_int_mult.attr,
1657 &f_ss_opts_int_maxburst.attr,
1189 NULL, 1658 NULL,
1190}; 1659};
1191 1660
@@ -1215,6 +1684,8 @@ static struct usb_function_instance *source_sink_alloc_inst(void)
1215 ss_opts->isoc_interval = GZERO_ISOC_INTERVAL; 1684 ss_opts->isoc_interval = GZERO_ISOC_INTERVAL;
1216 ss_opts->isoc_maxpacket = GZERO_ISOC_MAXPACKET; 1685 ss_opts->isoc_maxpacket = GZERO_ISOC_MAXPACKET;
1217 ss_opts->bulk_buflen = GZERO_BULK_BUFLEN; 1686 ss_opts->bulk_buflen = GZERO_BULK_BUFLEN;
1687 ss_opts->int_interval = GZERO_INT_INTERVAL;
1688 ss_opts->int_maxpacket = GZERO_INT_MAXPACKET;
1218 1689
1219 config_group_init_type_name(&ss_opts->func_inst.group, "", 1690 config_group_init_type_name(&ss_opts->func_inst.group, "",
1220 &ss_func_type); 1691 &ss_func_type);