aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/misc/usbtest.c120
1 files changed, 118 insertions, 2 deletions
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 388cc128072..58a5685fb7d 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -1195,6 +1195,104 @@ static int unlink_simple(struct usbtest_dev *dev, int pipe, int len)
1195 1195
1196/*-------------------------------------------------------------------------*/ 1196/*-------------------------------------------------------------------------*/
1197 1197
1198struct queued_ctx {
1199 struct completion complete;
1200 atomic_t pending;
1201 unsigned num;
1202 int status;
1203 struct urb **urbs;
1204};
1205
1206static void unlink_queued_callback(struct urb *urb)
1207{
1208 int status = urb->status;
1209 struct queued_ctx *ctx = urb->context;
1210
1211 if (ctx->status)
1212 goto done;
1213 if (urb == ctx->urbs[ctx->num - 4] || urb == ctx->urbs[ctx->num - 2]) {
1214 if (status == -ECONNRESET)
1215 goto done;
1216 /* What error should we report if the URB completed normally? */
1217 }
1218 if (status != 0)
1219 ctx->status = status;
1220
1221 done:
1222 if (atomic_dec_and_test(&ctx->pending))
1223 complete(&ctx->complete);
1224}
1225
1226static int unlink_queued(struct usbtest_dev *dev, int pipe, unsigned num,
1227 unsigned size)
1228{
1229 struct queued_ctx ctx;
1230 struct usb_device *udev = testdev_to_usbdev(dev);
1231 void *buf;
1232 dma_addr_t buf_dma;
1233 int i;
1234 int retval = -ENOMEM;
1235
1236 init_completion(&ctx.complete);
1237 atomic_set(&ctx.pending, 1); /* One more than the actual value */
1238 ctx.num = num;
1239 ctx.status = 0;
1240
1241 buf = usb_alloc_coherent(udev, size, GFP_KERNEL, &buf_dma);
1242 if (!buf)
1243 return retval;
1244 memset(buf, 0, size);
1245
1246 /* Allocate and init the urbs we'll queue */
1247 ctx.urbs = kcalloc(num, sizeof(struct urb *), GFP_KERNEL);
1248 if (!ctx.urbs)
1249 goto free_buf;
1250 for (i = 0; i < num; i++) {
1251 ctx.urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
1252 if (!ctx.urbs[i])
1253 goto free_urbs;
1254 usb_fill_bulk_urb(ctx.urbs[i], udev, pipe, buf, size,
1255 unlink_queued_callback, &ctx);
1256 ctx.urbs[i]->transfer_dma = buf_dma;
1257 ctx.urbs[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
1258 }
1259
1260 /* Submit all the URBs and then unlink URBs num - 4 and num - 2. */
1261 for (i = 0; i < num; i++) {
1262 atomic_inc(&ctx.pending);
1263 retval = usb_submit_urb(ctx.urbs[i], GFP_KERNEL);
1264 if (retval != 0) {
1265 dev_err(&dev->intf->dev, "submit urbs[%d] fail %d\n",
1266 i, retval);
1267 atomic_dec(&ctx.pending);
1268 ctx.status = retval;
1269 break;
1270 }
1271 }
1272 if (i == num) {
1273 usb_unlink_urb(ctx.urbs[num - 4]);
1274 usb_unlink_urb(ctx.urbs[num - 2]);
1275 } else {
1276 while (--i >= 0)
1277 usb_unlink_urb(ctx.urbs[i]);
1278 }
1279
1280 if (atomic_dec_and_test(&ctx.pending)) /* The extra count */
1281 complete(&ctx.complete);
1282 wait_for_completion(&ctx.complete);
1283 retval = ctx.status;
1284
1285 free_urbs:
1286 for (i = 0; i < num; i++)
1287 usb_free_urb(ctx.urbs[i]);
1288 kfree(ctx.urbs);
1289 free_buf:
1290 usb_free_coherent(udev, size, buf, buf_dma);
1291 return retval;
1292}
1293
1294/*-------------------------------------------------------------------------*/
1295
1198static int verify_not_halted(struct usbtest_dev *tdev, int ep, struct urb *urb) 1296static int verify_not_halted(struct usbtest_dev *tdev, int ep, struct urb *urb)
1199{ 1297{
1200 int retval; 1298 int retval;
@@ -1970,8 +2068,6 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
1970 dev->in_iso_pipe, dev->iso_in, 0); 2068 dev->in_iso_pipe, dev->iso_in, 0);
1971 break; 2069 break;
1972 2070
1973 /* FIXME unlink from queue (ring with N urbs) */
1974
1975 /* FIXME scatterlist cancel (needs helper thread) */ 2071 /* FIXME scatterlist cancel (needs helper thread) */
1976 2072
1977 /* Tests for bulk I/O using DMA mapping by core and odd address */ 2073 /* Tests for bulk I/O using DMA mapping by core and odd address */
@@ -2064,6 +2160,26 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
2064 dev->in_iso_pipe, dev->iso_in, 1); 2160 dev->in_iso_pipe, dev->iso_in, 1);
2065 break; 2161 break;
2066 2162
2163 /* unlink URBs from a bulk-OUT queue */
2164 case 24:
2165 if (dev->out_pipe == 0 || !param->length || param->sglen < 4)
2166 break;
2167 retval = 0;
2168 dev_info(&intf->dev, "TEST 17: unlink from %d queues of "
2169 "%d %d-byte writes\n",
2170 param->iterations, param->sglen, param->length);
2171 for (i = param->iterations; retval == 0 && i > 0; --i) {
2172 retval = unlink_queued(dev, dev->out_pipe,
2173 param->sglen, param->length);
2174 if (retval) {
2175 dev_err(&intf->dev,
2176 "unlink queued writes failed %d, "
2177 "iterations left %d\n", retval, i);
2178 break;
2179 }
2180 }
2181 break;
2182
2067 } 2183 }
2068 do_gettimeofday(&param->duration); 2184 do_gettimeofday(&param->duration);
2069 param->duration.tv_sec -= start.tv_sec; 2185 param->duration.tv_sec -= start.tv_sec;