📄 usbtest.c
字号:
retval = -ENOMEM; break; } // FIRMWARE: bulk source (maybe generates short writes) retval = simple_io (urb, param->iterations, param->vary, 0, "test4"); simple_free_urb (urb); break; /* Queued bulk I/O tests */ case 5: if (dev->out_pipe == 0 || param->sglen == 0) break; dev_dbg (&intf->dev, "TEST 5: write %d sglists %d entries of %d bytes\n", param->iterations, param->sglen, param->length); sg = alloc_sglist (param->sglen, param->length, 0); if (!sg) { retval = -ENOMEM; break; } // FIRMWARE: bulk sink (maybe accepts short writes) retval = perform_sglist (udev, param->iterations, dev->out_pipe, &req, sg, param->sglen); free_sglist (sg, param->sglen); break; case 6: if (dev->in_pipe == 0 || param->sglen == 0) break; dev_dbg (&intf->dev, "TEST 6: read %d sglists %d entries of %d bytes\n", param->iterations, param->sglen, param->length); sg = alloc_sglist (param->sglen, param->length, 0); if (!sg) { retval = -ENOMEM; break; } // FIRMWARE: bulk source (maybe generates short writes) retval = perform_sglist (udev, param->iterations, dev->in_pipe, &req, sg, param->sglen); free_sglist (sg, param->sglen); break; case 7: if (dev->out_pipe == 0 || param->sglen == 0 || param->vary == 0) break; dev_dbg (&intf->dev, "TEST 7: write/%d %d sglists %d entries 0..%d bytes\n", param->vary, param->iterations, param->sglen, param->length); sg = alloc_sglist (param->sglen, param->length, param->vary); if (!sg) { retval = -ENOMEM; break; } // FIRMWARE: bulk sink (maybe accepts short writes) retval = perform_sglist (udev, param->iterations, dev->out_pipe, &req, sg, param->sglen); free_sglist (sg, param->sglen); break; case 8: if (dev->in_pipe == 0 || param->sglen == 0 || param->vary == 0) break; dev_dbg (&intf->dev, "TEST 8: read/%d %d sglists %d entries 0..%d bytes\n", param->vary, param->iterations, param->sglen, param->length); sg = alloc_sglist (param->sglen, param->length, param->vary); if (!sg) { retval = -ENOMEM; break; } // FIRMWARE: bulk source (maybe generates short writes) retval = perform_sglist (udev, param->iterations, dev->in_pipe, &req, sg, param->sglen); free_sglist (sg, param->sglen); break; /* non-queued sanity tests for control (chapter 9 subset) */ case 9: retval = 0; dev_dbg (&intf->dev, "TEST 9: ch9 (subset) control tests, %d times\n", param->iterations); for (i = param->iterations; retval == 0 && i--; /* NOP */) retval = ch9_postconfig (dev); if (retval) dbg ("ch9 subset failed, iterations left %d", i); break; /* queued control messaging */ case 10: if (param->sglen == 0) break; retval = 0; dev_dbg (&intf->dev, "TEST 10: queue %d control calls, %d times\n", param->sglen, param->iterations); retval = test_ctrl_queue (dev, param); break; /* simple non-queued unlinks (ring with one urb) */ case 11: if (dev->in_pipe == 0 || !param->length) break; retval = 0; dev_dbg (&intf->dev, "TEST 11: unlink %d reads of %d\n", param->iterations, param->length); for (i = param->iterations; retval == 0 && i--; /* NOP */) retval = unlink_simple (dev, dev->in_pipe, param->length); if (retval) dev_dbg (&intf->dev, "unlink reads failed %d, " "iterations left %d\n", retval, i); break; case 12: if (dev->out_pipe == 0 || !param->length) break; retval = 0; dev_dbg (&intf->dev, "TEST 12: unlink %d writes of %d\n", param->iterations, param->length); for (i = param->iterations; retval == 0 && i--; /* NOP */) retval = unlink_simple (dev, dev->out_pipe, param->length); if (retval) dev_dbg (&intf->dev, "unlink writes failed %d, " "iterations left %d\n", retval, i); break; /* ep halt tests */ case 13: if (dev->out_pipe == 0 && dev->in_pipe == 0) break; retval = 0; dev_dbg (&intf->dev, "TEST 13: set/clear %d halts\n", param->iterations); for (i = param->iterations; retval == 0 && i--; /* NOP */) retval = halt_simple (dev); if (retval) DBG (dev, "halts failed, iterations left %d\n", i); break; /* control write tests */ case 14: if (!dev->info->ctrl_out) break; dev_dbg (&intf->dev, "TEST 14: %d ep0out, %d..%d vary %d\n", param->iterations, realworld ? 1 : 0, param->length, param->vary); retval = ctrl_out (dev, param->iterations, param->length, param->vary); break; /* iso write tests */ case 15: if (dev->out_iso_pipe == 0 || param->sglen == 0) break; dev_dbg (&intf->dev, "TEST 15: write %d iso, %d entries of %d bytes\n", param->iterations, param->sglen, param->length); // FIRMWARE: iso sink retval = test_iso_queue (dev, param, dev->out_iso_pipe, dev->iso_out); break; /* iso read tests */ case 16: if (dev->in_iso_pipe == 0 || param->sglen == 0) break; dev_dbg (&intf->dev, "TEST 16: read %d iso, %d entries of %d bytes\n", param->iterations, param->sglen, param->length); // FIRMWARE: iso source retval = test_iso_queue (dev, param, dev->in_iso_pipe, dev->iso_in); break; // FIXME unlink from queue (ring with N urbs) // FIXME scatterlist cancel (needs helper thread) } do_gettimeofday (¶m->duration); param->duration.tv_sec -= start.tv_sec; param->duration.tv_usec -= start.tv_usec; if (param->duration.tv_usec < 0) { param->duration.tv_usec += 1000 * 1000; param->duration.tv_sec -= 1; } up (&dev->sem); return retval;}/*-------------------------------------------------------------------------*/static unsigned force_interrupt = 0;module_param (force_interrupt, uint, 0);MODULE_PARM_DESC (force_interrupt, "0 = test default; else interrupt");#ifdef GENERICstatic unsigned short vendor;module_param(vendor, ushort, 0);MODULE_PARM_DESC (vendor, "vendor code (from usb-if)");static unsigned short product;module_param(product, ushort, 0);MODULE_PARM_DESC (product, "product code (from vendor)");#endifstatic intusbtest_probe (struct usb_interface *intf, const struct usb_device_id *id){ struct usb_device *udev; struct usbtest_dev *dev; struct usbtest_info *info; char *rtest, *wtest; char *irtest, *iwtest; udev = interface_to_usbdev (intf);#ifdef GENERIC /* specify devices by module parameters? */ if (id->match_flags == 0) { /* vendor match required, product match optional */ if (!vendor || le16_to_cpu(udev->descriptor.idVendor) != (u16)vendor) return -ENODEV; if (product && le16_to_cpu(udev->descriptor.idProduct) != (u16)product) return -ENODEV; dbg ("matched module params, vend=0x%04x prod=0x%04x", le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct)); }#endif dev = kmalloc (sizeof *dev, SLAB_KERNEL); if (!dev) return -ENOMEM; memset (dev, 0, sizeof *dev); info = (struct usbtest_info *) id->driver_info; dev->info = info; init_MUTEX (&dev->sem); dev->intf = intf; /* cacheline-aligned scratch for i/o */ if ((dev->buf = kmalloc (TBUF_SIZE, SLAB_KERNEL)) == NULL) { kfree (dev); return -ENOMEM; } /* NOTE this doesn't yet test the handful of difference that are * visible with high speed interrupts: bigger maxpacket (1K) and * "high bandwidth" modes (up to 3 packets/uframe). */ rtest = wtest = ""; irtest = iwtest = ""; if (force_interrupt || udev->speed == USB_SPEED_LOW) { if (info->ep_in) { dev->in_pipe = usb_rcvintpipe (udev, info->ep_in); rtest = " intr-in"; } if (info->ep_out) { dev->out_pipe = usb_sndintpipe (udev, info->ep_out); wtest = " intr-out"; } } else { if (info->autoconf) { int status; status = get_endpoints (dev, intf); if (status < 0) { dbg ("couldn't get endpoints, %d\n", status); return status; } /* may find bulk or ISO pipes */ } else { if (info->ep_in) dev->in_pipe = usb_rcvbulkpipe (udev, info->ep_in); if (info->ep_out) dev->out_pipe = usb_sndbulkpipe (udev, info->ep_out); } if (dev->in_pipe) rtest = " bulk-in"; if (dev->out_pipe) wtest = " bulk-out"; if (dev->in_iso_pipe) irtest = " iso-in"; if (dev->out_iso_pipe) iwtest = " iso-out"; } usb_set_intfdata (intf, dev); dev_info (&intf->dev, "%s\n", info->name); dev_info (&intf->dev, "%s speed {control%s%s%s%s%s} tests%s\n", ({ char *tmp; switch (udev->speed) { case USB_SPEED_LOW: tmp = "low"; break; case USB_SPEED_FULL: tmp = "full"; break; case USB_SPEED_HIGH: tmp = "high"; break; default: tmp = "unknown"; break; }; tmp; }), info->ctrl_out ? " in/out" : "", rtest, wtest, irtest, iwtest, info->alt >= 0 ? " (+alt)" : ""); return 0;}static int usbtest_suspend (struct usb_interface *intf, pm_message_t message){ return 0;}static int usbtest_resume (struct usb_interface *intf){ return 0;}static void usbtest_disconnect (struct usb_interface *intf){ struct usbtest_dev *dev = usb_get_intfdata (intf); down (&dev->sem); usb_set_intfdata (intf, NULL); dev_dbg (&intf->dev, "disconnect\n"); kfree (dev);}/* Basic testing only needs a device that can source or sink bulk traffic. * Any device can test control transfers (default with GENERIC binding). * * Several entries work with the default EP0 implementation that's built * into EZ-USB chips. There's a default vendor ID which can be overridden * by (very) small config EEPROMS, but otherwise all these devices act * identically until firmware is loaded: only EP0 works. It turns out * to be easy to make other endpoints work, without modifying that EP0 * behavior. For now, we expect that kind of firmware. *//* an21xx or fx versions of ez-usb */static struct usbtest_info ez1_info = { .name = "EZ-USB device", .ep_in = 2, .ep_out = 2, .alt = 1,};/* fx2 version of ez-usb */static struct usbtest_info ez2_info = { .name = "FX2 device", .ep_in = 6, .ep_out = 2, .alt = 1,};/* ezusb family device with dedicated usb test firmware, */static struct usbtest_info fw_info = { .name = "usb test device", .ep_in = 2, .ep_out = 2, .alt = 1, .autoconf = 1, // iso and ctrl_out need autoconf .ctrl_out = 1, .iso = 1, // iso_ep's are #8 in/out};/* peripheral running Linux and 'zero.c' test firmware, or * its user-mode cousin. different versions of this use * different hardware with the same vendor/product codes. * host side MUST rely on the endpoint descriptors. */static struct usbtest_info gz_info = { .name = "Linux gadget zero", .autoconf = 1, .ctrl_out = 1, .alt = 0,};static struct usbtest_info um_info = { .name = "Linux user mode test driver", .autoconf = 1, .alt = -1,};static struct usbtest_info um2_info = { .name = "Linux user mode ISO test driver", .autoconf = 1, .iso = 1, .alt = -1,};#ifdef IBOT2/* this is a nice source of high speed bulk data; * uses an FX2, with firmware provided in the device */static struct usbtest_info ibot2_info = { .name = "iBOT2 webcam", .ep_in = 2, .alt = -1,};#endif#ifdef GENERIC/* we can use any device to test control traffic */static struct usbtest_info generic_info = { .name = "Generic USB device", .alt = -1,};#endif// FIXME remove this static struct usbtest_info hact_info = { .name = "FX2/hact", //.ep_in = 6, .ep_out = 2, .alt = -1,};static struct usb_device_id id_table [] = { { USB_DEVICE (0x0547, 0x1002), .driver_info = (unsigned long) &hact_info, }, /*-------------------------------------------------------------*/ /* EZ-USB devices which download firmware to replace (or in our * case augment) the default device implementation. */ /* generic EZ-USB FX controller */ { USB_DEVICE (0x0547, 0x2235), .driver_info = (unsigned long) &ez1_info, }, /* CY3671 development board with EZ-USB FX */ { USB_DEVICE (0x0547, 0x0080), .driver_info = (unsigned long) &ez1_info, }, /* generic EZ-USB FX2 controller (or development board) */ { USB_DEVICE (0x04b4, 0x8613), .driver_info = (unsigned long) &ez2_info, }, /* re-enumerated usb test device firmware */ { USB_DEVICE (0xfff0, 0xfff0), .driver_info = (unsigned long) &fw_info, }, /* "Gadget Zero" firmware runs under Linux */ { USB_DEVICE (0x0525, 0xa4a0), .driver_info = (unsigned long) &gz_info, }, /* so does a user-mode variant */ { USB_DEVICE (0x0525, 0xa4a4), .driver_info = (unsigned long) &um_info, }, /* ... and a user-mode variant that talks iso */ { USB_DEVICE (0x0525, 0xa4a3), .driver_info = (unsigned long) &um2_info, },#ifdef KEYSPAN_19Qi /* Keyspan 19qi uses an21xx (original EZ-USB) */ // this does not coexist with the real Keyspan 19qi driver! { USB_DEVICE (0x06cd, 0x010b), .driver_info = (unsigned long) &ez1_info, },#endif /*-------------------------------------------------------------*/#ifdef IBOT2 /* iBOT2 makes a nice source of high speed bulk-in data */ // this does not coexist with a real iBOT2 driver! { USB_DEVICE (0x0b62, 0x0059), .driver_info = (unsigned long) &ibot2_info, },#endif /*-------------------------------------------------------------*/#ifdef GENERIC /* module params can specify devices to use for control tests */ { .driver_info = (unsigned long) &generic_info, },#endif /*-------------------------------------------------------------*/ { }};MODULE_DEVICE_TABLE (usb, id_table);static struct usb_driver usbtest_driver = { .owner = THIS_MODULE, .name = "usbtest", .id_table = id_table, .probe = usbtest_probe, .ioctl = usbtest_ioctl, .disconnect = usbtest_disconnect, .suspend = usbtest_suspend, .resume = usbtest_resume,};/*-------------------------------------------------------------------------*/static int __init usbtest_init (void){#ifdef GENERIC if (vendor) dbg ("params: vend=0x%04x prod=0x%04x", vendor, product);#endif return usb_register (&usbtest_driver);}module_init (usbtest_init);static void __exit usbtest_exit (void){ usb_deregister (&usbtest_driver);}module_exit (usbtest_exit);MODULE_DESCRIPTION ("USB Core/HCD Testing Driver");MODULE_LICENSE ("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -