Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usbtest: Add interrupt EP testcases

Two simple test cases for interrupt endpoints are added to the usbtest.c file.
These are simple non-queued interrupt IN and interrupt OUT transfers. Currently,
only gadget zero is capable of executing the interrupt EP test cases. However,
extending the same to other gadgets is extremely simple and can be done
on-demand.

The two new tests added are
- Test 25: To verify Interrupt OUT transfer
- Test 26: To verify Interrupt IN transfer

Since the default value of wMaxPacketSize is set as 1024, so interrupt
IN transfers must be specified with the size parameter = multiple of
1024. Otherwise the default value (512) in the usbtest application fails
the transfer. See [RUN 4] for sample logs

The application logs (usbtest) and corresponding kernel logs are as
following:

[Run 1]
./testusb -a -c 10 -s 2048 -t 26 -v 511
usbtest 7-1:3.0: TEST 26: read 2048 bytes 10 times

[Run 2]
./testusb -a -c 10 -s 1024 -t 25 -v 511
usbtest 7-1:3.0: TEST 25: write 1024 bytes 10 times

[Run 3]
./testusb -a -c 10 -s 1098 -t 25 -v 511
usbtest 7-1:3.0: TEST 25: write 1098 bytes 10 times

[Run 4 - Failure case scenario]
./testusb -a -t 26
unknown speed /dev/bus/usb/007/004 0
/dev/bus/usb/007/004 test 26 --> 75 (Value too large for defined data type)

usbtest 7-1:3.0: TEST 26: read 512 bytes 1000 times
usb 7-1: test26 failed, iterations left 999, status -75 (not 0)

Signed-off-by: Amit Virdi <amit.virdi@st.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>

authored by

Amit Virdi and committed by
Felipe Balbi
457a0955 ef11982d

+98 -15
+98 -15
drivers/usb/misc/usbtest.c
··· 54 54 unsigned autoconf:1; 55 55 unsigned ctrl_out:1; 56 56 unsigned iso:1; /* try iso in/out */ 57 + unsigned intr:1; /* try interrupt in/out */ 57 58 int alt; 58 59 }; 59 60 ··· 71 70 int out_pipe; 72 71 int in_iso_pipe; 73 72 int out_iso_pipe; 73 + int in_int_pipe; 74 + int out_int_pipe; 74 75 struct usb_endpoint_descriptor *iso_in, *iso_out; 76 + struct usb_endpoint_descriptor *int_in, *int_out; 75 77 struct mutex lock; 76 78 77 79 #define TBUF_SIZE 256 ··· 105 101 struct usb_host_interface *alt; 106 102 struct usb_host_endpoint *in, *out; 107 103 struct usb_host_endpoint *iso_in, *iso_out; 104 + struct usb_host_endpoint *int_in, *int_out; 108 105 struct usb_device *udev; 109 106 110 107 for (tmp = 0; tmp < intf->num_altsetting; tmp++) { ··· 113 108 114 109 in = out = NULL; 115 110 iso_in = iso_out = NULL; 111 + int_in = int_out = NULL; 116 112 alt = intf->altsetting + tmp; 117 113 118 114 if (override_alt >= 0 && ··· 130 124 switch (usb_endpoint_type(&e->desc)) { 131 125 case USB_ENDPOINT_XFER_BULK: 132 126 break; 127 + case USB_ENDPOINT_XFER_INT: 128 + if (dev->info->intr) 129 + goto try_intr; 133 130 case USB_ENDPOINT_XFER_ISOC: 134 131 if (dev->info->iso) 135 132 goto try_iso; ··· 148 139 out = e; 149 140 } 150 141 continue; 142 + try_intr: 143 + if (usb_endpoint_dir_in(&e->desc)) { 144 + if (!int_in) 145 + int_in = e; 146 + } else { 147 + if (!int_out) 148 + int_out = e; 149 + } 150 + continue; 151 151 try_iso: 152 152 if (usb_endpoint_dir_in(&e->desc)) { 153 153 if (!iso_in) ··· 166 148 iso_out = e; 167 149 } 168 150 } 169 - if ((in && out) || iso_in || iso_out) 151 + if ((in && out) || iso_in || iso_out || int_in || int_out) 170 152 goto found; 171 153 } 172 154 return -EINVAL; ··· 201 183 iso_out->desc.bEndpointAddress 202 184 & USB_ENDPOINT_NUMBER_MASK); 203 185 } 186 + 187 + if (int_in) { 188 + dev->int_in = &int_in->desc; 189 + dev->in_int_pipe = usb_rcvintpipe(udev, 190 + int_in->desc.bEndpointAddress 191 + & USB_ENDPOINT_NUMBER_MASK); 192 + } 193 + 194 + if (int_out) { 195 + dev->int_out = &int_out->desc; 196 + dev->out_int_pipe = usb_sndintpipe(udev, 197 + int_out->desc.bEndpointAddress 198 + & USB_ENDPOINT_NUMBER_MASK); 199 + } 204 200 return 0; 205 201 } 206 202 ··· 237 205 int pipe, 238 206 unsigned long bytes, 239 207 unsigned transfer_flags, 240 - unsigned offset) 208 + unsigned offset, 209 + u8 bInterval) 241 210 { 242 211 struct urb *urb; 243 212 244 213 urb = usb_alloc_urb(0, GFP_KERNEL); 245 214 if (!urb) 246 215 return urb; 247 - usb_fill_bulk_urb(urb, udev, pipe, NULL, bytes, simple_callback, NULL); 216 + 217 + if (bInterval) 218 + usb_fill_int_urb(urb, udev, pipe, NULL, bytes, simple_callback, 219 + NULL, bInterval); 220 + else 221 + usb_fill_bulk_urb(urb, udev, pipe, NULL, bytes, simple_callback, 222 + NULL); 223 + 248 224 urb->interval = (udev->speed == USB_SPEED_HIGH) 249 225 ? (INTERRUPT_RATE << 3) 250 226 : INTERRUPT_RATE; ··· 291 251 static struct urb *simple_alloc_urb( 292 252 struct usb_device *udev, 293 253 int pipe, 294 - unsigned long bytes) 254 + unsigned long bytes, 255 + u8 bInterval) 295 256 { 296 - return usbtest_alloc_urb(udev, pipe, bytes, URB_NO_TRANSFER_DMA_MAP, 0); 257 + return usbtest_alloc_urb(udev, pipe, bytes, URB_NO_TRANSFER_DMA_MAP, 0, 258 + bInterval); 297 259 } 298 260 299 261 static unsigned pattern; ··· 1297 1255 goto cleanup; 1298 1256 } 1299 1257 req.wLength = cpu_to_le16(len); 1300 - urb[i] = u = simple_alloc_urb(udev, pipe, len); 1258 + urb[i] = u = simple_alloc_urb(udev, pipe, len, 0); 1301 1259 if (!u) 1302 1260 goto cleanup; 1303 1261 ··· 1370 1328 int retval = 0; 1371 1329 1372 1330 init_completion(&completion); 1373 - urb = simple_alloc_urb(testdev_to_usbdev(dev), pipe, size); 1331 + urb = simple_alloc_urb(testdev_to_usbdev(dev), pipe, size, 0); 1374 1332 if (!urb) 1375 1333 return -ENOMEM; 1376 1334 urb->context = &completion; ··· 1658 1616 struct usb_device *udev = testdev_to_usbdev(dev); 1659 1617 1660 1618 if (udev->speed == USB_SPEED_SUPER) 1661 - urb = simple_alloc_urb(udev, 0, 1024); 1619 + urb = simple_alloc_urb(udev, 0, 1024, 0); 1662 1620 else 1663 - urb = simple_alloc_urb(udev, 0, 512); 1621 + urb = simple_alloc_urb(udev, 0, 512, 0); 1664 1622 if (urb == NULL) 1665 1623 return -ENOMEM; 1666 1624 ··· 2004 1962 { 2005 1963 int retval; 2006 1964 struct urb *urb = usbtest_alloc_urb( 2007 - testdev_to_usbdev(tdev), pipe, length, transfer_flags, 1); 1965 + testdev_to_usbdev(tdev), pipe, length, transfer_flags, 1, 0); 2008 1966 2009 1967 if (!urb) 2010 1968 return -ENOMEM; ··· 2110 2068 dev_info(&intf->dev, 2111 2069 "TEST 1: write %d bytes %u times\n", 2112 2070 param->length, param->iterations); 2113 - urb = simple_alloc_urb(udev, dev->out_pipe, param->length); 2071 + urb = simple_alloc_urb(udev, dev->out_pipe, param->length, 0); 2114 2072 if (!urb) { 2115 2073 retval = -ENOMEM; 2116 2074 break; ··· 2125 2083 dev_info(&intf->dev, 2126 2084 "TEST 2: read %d bytes %u times\n", 2127 2085 param->length, param->iterations); 2128 - urb = simple_alloc_urb(udev, dev->in_pipe, param->length); 2086 + urb = simple_alloc_urb(udev, dev->in_pipe, param->length, 0); 2129 2087 if (!urb) { 2130 2088 retval = -ENOMEM; 2131 2089 break; ··· 2140 2098 dev_info(&intf->dev, 2141 2099 "TEST 3: write/%d 0..%d bytes %u times\n", 2142 2100 param->vary, param->length, param->iterations); 2143 - urb = simple_alloc_urb(udev, dev->out_pipe, param->length); 2101 + urb = simple_alloc_urb(udev, dev->out_pipe, param->length, 0); 2144 2102 if (!urb) { 2145 2103 retval = -ENOMEM; 2146 2104 break; ··· 2156 2114 dev_info(&intf->dev, 2157 2115 "TEST 4: read/%d 0..%d bytes %u times\n", 2158 2116 param->vary, param->length, param->iterations); 2159 - urb = simple_alloc_urb(udev, dev->in_pipe, param->length); 2117 + urb = simple_alloc_urb(udev, dev->in_pipe, param->length, 0); 2160 2118 if (!urb) { 2161 2119 retval = -ENOMEM; 2162 2120 break; ··· 2453 2411 } 2454 2412 break; 2455 2413 2414 + /* Simple non-queued interrupt I/O tests */ 2415 + case 25: 2416 + if (dev->out_int_pipe == 0) 2417 + break; 2418 + dev_info(&intf->dev, 2419 + "TEST 25: write %d bytes %u times\n", 2420 + param->length, param->iterations); 2421 + urb = simple_alloc_urb(udev, dev->out_int_pipe, param->length, 2422 + dev->int_out->bInterval); 2423 + if (!urb) { 2424 + retval = -ENOMEM; 2425 + break; 2426 + } 2427 + /* FIRMWARE: interrupt sink (maybe accepts short writes) */ 2428 + retval = simple_io(dev, urb, param->iterations, 0, 0, "test25"); 2429 + simple_free_urb(urb); 2430 + break; 2431 + case 26: 2432 + if (dev->in_int_pipe == 0) 2433 + break; 2434 + dev_info(&intf->dev, 2435 + "TEST 26: read %d bytes %u times\n", 2436 + param->length, param->iterations); 2437 + urb = simple_alloc_urb(udev, dev->in_int_pipe, param->length, 2438 + dev->int_in->bInterval); 2439 + if (!urb) { 2440 + retval = -ENOMEM; 2441 + break; 2442 + } 2443 + /* FIRMWARE: interrupt source (maybe generates short writes) */ 2444 + retval = simple_io(dev, urb, param->iterations, 0, 0, "test26"); 2445 + simple_free_urb(urb); 2446 + break; 2456 2447 } 2457 2448 do_gettimeofday(&param->duration); 2458 2449 param->duration.tv_sec -= start.tv_sec; ··· 2522 2447 struct usbtest_info *info; 2523 2448 char *rtest, *wtest; 2524 2449 char *irtest, *iwtest; 2450 + char *intrtest, *intwtest; 2525 2451 2526 2452 udev = interface_to_usbdev(intf); 2527 2453 ··· 2563 2487 */ 2564 2488 rtest = wtest = ""; 2565 2489 irtest = iwtest = ""; 2490 + intrtest = intwtest = ""; 2566 2491 if (force_interrupt || udev->speed == USB_SPEED_LOW) { 2567 2492 if (info->ep_in) { 2568 2493 dev->in_pipe = usb_rcvintpipe(udev, info->ep_in); ··· 2602 2525 irtest = " iso-in"; 2603 2526 if (dev->out_iso_pipe) 2604 2527 iwtest = " iso-out"; 2528 + if (dev->in_int_pipe) 2529 + intrtest = " int-in"; 2530 + if (dev->out_int_pipe) 2531 + intwtest = " int-out"; 2605 2532 } 2606 2533 2607 2534 usb_set_intfdata(intf, dev); 2608 2535 dev_info(&intf->dev, "%s\n", info->name); 2609 - dev_info(&intf->dev, "%s {control%s%s%s%s%s} tests%s\n", 2536 + dev_info(&intf->dev, "%s {control%s%s%s%s%s%s%s} tests%s\n", 2610 2537 usb_speed_string(udev->speed), 2611 2538 info->ctrl_out ? " in/out" : "", 2612 2539 rtest, wtest, 2613 2540 irtest, iwtest, 2541 + intrtest, intwtest, 2614 2542 info->alt >= 0 ? " (+alt)" : ""); 2615 2543 return 0; 2616 2544 } ··· 2689 2607 .autoconf = 1, 2690 2608 .ctrl_out = 1, 2691 2609 .iso = 1, 2610 + .intr = 1, 2692 2611 .alt = 0, 2693 2612 }; 2694 2613