#include <linux/kernel.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/mm.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/scatterlist.h> #include <linux/usb.h> /*-------------------------------------------------------------------------*/ // FIXME make these public somewhere; usbdevfs.h?//struct usbtest_param { // inputs unsigned test_num; /* 0..(TEST_CASES-1) */ unsigned iterations; unsigned length; unsigned vary; unsigned sglen; // outputs struct timeval duration;};#define USBTEST_REQUEST _IOWR('U', 100, struct usbtest_param) /*-------------------------------------------------------------------------*/ #define GENERIC /* let probe() bind using module params */ /* Some devices that can be used for testing will have "real" drivers. * Entries for those need to be enabled here by hand, after disabling * that "real" driver. *///#define IBOT2 /* grab iBOT2 webcams *///#define KEYSPAN_19Qi /* grab un-renumerated serial adapter */ /*-------------------------------------------------------------------------*/ struct usbtest_info { const char *name; u8 ep_in; /* bulk/intr source */ u8 ep_out; /* bulk/intr sink */ unsigned autoconf : 1; unsigned ctrl_out : 1; unsigned iso : 1; /* try iso in/out */ int alt;}; /* this is accessed only through usbfs ioctl calls. * one ioctl to issue a test ... one lock per device. * tests create other threads if they need them. * urbs and buffers are allocated dynamically, * and data generated deterministically. */struct usbtest_dev { struct usb_interface *intf; struct usbtest_info *info; int in_pipe; int out_pipe; int in_iso_pipe; int out_iso_pipe; struct usb_endpoint_descriptor *iso_in, *iso_out; struct semaphore sem; #define TBUF_SIZE 256 u8 *buf;}; static struct usb_device *testdev_to_usbdev (struct usbtest_dev *test){ return interface_to_usbdev (test->intf);} /* set up all urbs so they can be used with either bulk or interrupt */#define INTERRUPT_RATE 1 /* msec/transfer */ #define xprintk(tdev,level,fmt,args...) \ dev_printk(level , &(tdev)->intf->dev , fmt , ## args) #ifdef DEBUG#define DBG(dev,fmt,args...) \ xprintk(dev , KERN_DEBUG , fmt , ## args)#else#define DBG(dev,fmt,args...) \ do { } while (0)#endif /* DEBUG */ #ifdef VERBOSE#define VDBG DBG#else#define VDBG(dev,fmt,args...) \ do { } while (0)#endif /* VERBOSE */ #define ERROR(dev,fmt,args...) \ xprintk(dev , KERN_ERR , fmt , ## args)#define WARN(dev,fmt,args...) \ xprintk(dev , KERN_WARNING , fmt , ## args)#define INFO(dev,fmt,args...) \ xprintk(dev , KERN_INFO , fmt , ## args) /*-------------------------------------------------------------------------*/ static intget_endpoints (struct usbtest_dev *dev, struct usb_interface *intf){ int tmp; struct usb_host_interface *alt; struct usb_host_endpoint *in, *out; struct usb_host_endpoint *iso_in, *iso_out; struct usb_device *udev; for (tmp = 0; tmp < intf->num_altsetting; tmp++) { unsigned ep; in = out = NULL; iso_in = iso_out = NULL; alt = intf->altsetting + tmp; /* take the first altsetting with in-bulk + out-bulk; * ignore other endpoints and altsetttings. */ for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) { struct usb_host_endpoint *e; e = alt->endpoint + ep; switch (e->desc.bmAttributes) { case USB_ENDPOINT_XFER_BULK: break; case USB_ENDPOINT_XFER_ISOC: if (dev->info->iso) goto try_iso; // FALLTHROUGH default: continue; } if (usb_endpoint_dir_in(&e->desc)) { if (!in) in = e; } else { if (!out) out = e; } continue;try_iso: if (usb_endpoint_dir_in(&e->desc)) { if (!iso_in) iso_in = e; } else { if (!iso_out) iso_out = e; } } if ((in && out) || (iso_in && iso_out)) goto found; } return -EINVAL; found: udev = testdev_to_usbdev (dev); if (alt->desc.bAlternateSetting != 0) { tmp = usb_set_interface (udev, alt->desc.bInterfaceNumber, alt->desc.bAlternateSetting); if (tmp < 0) return tmp; } if (in) { dev->in_pipe = usb_rcvbulkpipe (udev, in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); dev->out_pipe = usb_sndbulkpipe (udev, out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); } if (iso_in) { dev->iso_in = &iso_in->desc; dev->in_iso_pipe = usb_rcvisocpipe (udev, iso_in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); dev->iso_out = &iso_out->desc; dev->out_iso_pipe = usb_sndisocpipe (udev, iso_out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); } return 0;} /*-------------------------------------------------------------------------*/ /* Support for testing basic non-queued I/O streams. * * These just package urbs as requests that can be easily canceled. * Each urb's data buffer is dynamically allocated; callers can fill * them with non-zero test data (or test for it) when appropriate. */ static void simple_callback (struct urb *urb){ complete ((struct completion *) urb->context);} static struct urb *simple_alloc_urb ( struct usb_device *udev, int pipe, unsigned long bytes){ struct urb *urb; if (bytes < 0) return NULL; urb = usb_alloc_urb (0, GFP_KERNEL); if (!urb) return urb; usb_fill_bulk_urb (urb, udev, pipe, NULL, bytes, simple_callback, NULL); urb->interval = (udev->speed == USB_SPEED_HIGH) ? (INTERRUPT_RATE << 3) : INTERRUPT_RATE; urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; if (usb_pipein (pipe)) urb->transfer_flags |= URB_SHORT_NOT_OK; urb->transfer_buffer = usb_buffer_alloc (udev, bytes, GFP_KERNEL, &urb->transfer_dma); if (!urb->transfer_buffer) { usb_free_urb (urb); urb = NULL; } else memset (urb->transfer_buffer, 0, bytes); return urb;} static unsigned pattern = 0;module_param (pattern, uint, S_IRUGO);// MODULE_PARM_DESC (pattern, "i/o pattern (0 == zeroes)"); static inline void simple_fill_buf (struct urb *urb){ unsigned i; u8 *buf = urb->transfer_buffer; unsigned len = urb->transfer_buffer_length; switch (pattern) { default: // FALLTHROUGH case 0: memset (buf, 0, len); break; case 1: /* mod63 */ for (i = 0; i < len; i++) *buf++ = (u8) (i % 63); break; }} static inline int simple_check_buf (struct urb *urb){ unsigned i; u8 expected; u8 *buf = urb->transfer_buffer; unsigned len = urb->actual_length; for (i = 0; i < len; i++, buf++) { switch (pattern) { /* all-zeroes has no synchronization issues */ case 0: expected = 0; break; /* mod63 stays in sync with short-terminated transfers, * or otherwise when host and gadget agree on how large * each usb transfer request should be. resync is done * with set_interface or set_config. */ case 1: /* mod63 */ expected = i % 63; break; /* always fail unsupported patterns */ default: expected = !*buf; break; } if (*buf == expected) continue; dbg ("buf[%d] = %d (not %d)", i, *buf, expected); return -EINVAL; } return 0;} static void simple_free_urb (struct urb *urb){ usb_buffer_free (urb->dev, urb->transfer_buffer_length, urb->transfer_buffer, urb->transfer_dma); usb_free_urb (urb);} static int simple_io ( struct urb *urb, int iterations, int vary, int expected, const char *label){ struct usb_device *udev = urb->dev; int max = urb->transfer_buffer_length; struct completion completion; int retval = 0; urb->context = &completion; while (retval == 0 && iterations-- > 0) { init_completion (&completion); if (usb_pipeout (urb->pipe)) simple_fill_buf (urb); if ((retval = usb_submit_urb (urb, GFP_KERNEL)) != 0) break; /* NOTE: no timeouts; can't be broken out of by interrupt */ wait_for_completion (&completion); retval = urb->status; urb->dev = udev; if (retval == 0 && usb_pipein (urb->pipe)) retval = simple_check_buf (urb); if (vary) { int len = urb->transfer_buffer_length; len += vary; len %= max; if (len == 0) len = (vary < max) ? vary : max; urb->transfer_buffer_length = len; } /* FIXME if endpoint halted, clear halt (and log) */ } urb->transfer_buffer_length = max; if (expected != retval) dev_dbg (&udev->dev, "%s failed, iterations left %d, status %d (not %d)\n", label, iterations, retval, expected); return retval;} /*-------------------------------------------------------------------------*/ /* We use scatterlist primitives to test queued I/O. * Yes, this also tests the scatterlist primitives. */ static void free_sglist (struct scatterlist *sg, int nents){ unsigned i; if (!sg) return; for (i = 0; i < nents; i++) { if (!sg [i].page) continue; kfree (page_address (sg [i].page) + sg [i].offset); } kfree (sg);} static struct scatterlist *alloc_sglist (int nents, int max, int vary){ struct scatterlist *sg; unsigned i; unsigned size = max; sg = kmalloc (nents * sizeof *sg, GFP_KERNEL); if (!sg) return NULL; for (i = 0; i < nents; i++) { char *buf; unsigned j; buf = kzalloc (size, GFP_KERNEL); if (!buf) { free_sglist (sg, i); return NULL; } /* kmalloc pages are always physically contiguous! */ sg_init_one(&sg[i], buf, size); switch (pattern) { case 0: /* already zeroed */ break; case 1: for (j = 0; j < size; j++) *buf++ = (u8) (j % 63); break; } if (vary) { size += vary; size %= max; if (size == 0) size = (vary < max) ? vary : max; } } return sg;} static int perform_sglist ( struct usb_device *udev, unsigned iterations, int pipe, struct usb_sg_request *req, struct scatterlist *sg, int nents){ int retval = 0; while (retval == 0 && iterations-- > 0) { retval = usb_sg_init (req, udev, pipe, (udev->speed == USB_SPEED_HIGH) ? (INTERRUPT_RATE << 3) : INTERRUPT_RATE, sg, nents, 0, GFP_KERNEL); if (retval) break; usb_sg_wait (req); retval = req->status; /* FIXME check resulting data pattern */ /* FIXME if endpoint halted, clear halt (and log) */ } // FIXME for unlink or fault handling tests, don't report // failure if retval is as we expected ... if (retval) dbg ("perform_sglist failed, iterations left %d, status %d", iterations, retval); return retval;} /*-------------------------------------------------------------------------*/ /* unqueued control message testing * * there's a nice set of device functional requirements in chapter 9 of the * usb 2.0 spec, which we can apply to ANY device, even ones that don't use * special test firmware. * * we know the device is configured (or suspended) by the time it's visible * through usbfs. we can't change that, so we won't test enumeration (which * worked 'well enough' to get here, this time), power management (ditto), * or remote wakeup (which needs human interaction). */ static unsigned realworld = 1;module_param (realworld, uint, 0);MODULE_PARM_DESC (realworld, "clear to demand stricter spec compliance"); static int get_altsetting (struct usbtest_dev *dev){ struct usb_interface *iface = dev->intf; struct usb_device *udev = interface_to_usbdev (iface); int retval; retval = usb_control_msg (udev, usb_rcvctrlpipe (udev, 0), USB_REQ_GET_INTERFACE, USB_DIR_IN|USB_RECIP_INTERFACE, 0, iface->altsetting [0].desc.bInterfaceNumber, dev->buf, 1, USB_CTRL_GET_TIMEOUT); switch (retval) { case 1: return dev->buf [0]; case 0: retval = -ERANGE; // FALLTHROUGH default: return retval; }} static int set_altsetting (struct usbtest_dev *dev, int alternate){ struct usb_interface *iface = dev->intf; struct usb_device *udev; if (alternate < 0 || alternate >= 256) return -EINVAL; udev = interface_to_usbdev (iface);Lines 1–500 of 2200. Load more
#include <linux/kernel.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/mm.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/scatterlist.h> #include <linux/usb.h> /*-------------------------------------------------------------------------*/ // FIXME make these public somewhere; usbdevfs.h? // struct usbtest_param { // inputs unsigned test_num; /* 0..(TEST_CASES-1) */ unsigned iterations; unsigned length; unsigned vary; unsigned sglen; // outputs struct timeval duration; }; #define USBTEST_REQUEST _IOWR('U', 100, struct usbtest_param) /*-------------------------------------------------------------------------*/ #define GENERIC /* let probe() bind using module params */ /* Some devices that can be used for testing will have "real" drivers. * Entries for those need to be enabled here by hand, after disabling * that "real" driver. */ //#define IBOT2 /* grab iBOT2 webcams */ //#define KEYSPAN_19Qi /* grab un-renumerated serial adapter */ /*-------------------------------------------------------------------------*/ struct usbtest_info { const char *name; u8 ep_in; /* bulk/intr source */ u8 ep_out; /* bulk/intr sink */ unsigned autoconf : 1; unsigned ctrl_out : 1; unsigned iso : 1; /* try iso in/out */ int alt; }; /* this is accessed only through usbfs ioctl calls. * one ioctl to issue a test ... one lock per device. * tests create other threads if they need them. * urbs and buffers are allocated dynamically, * and data generated deterministically. */ struct usbtest_dev { struct usb_interface *intf; struct usbtest_info *info; int in_pipe; int out_pipe; int in_iso_pipe; int out_iso_pipe; struct usb_endpoint_descriptor *iso_in, *iso_out; struct semaphore sem; #define TBUF_SIZE 256 u8 *buf; }; static struct usb_device *testdev_to_usbdev (struct usbtest_dev *test) { return interface_to_usbdev (test->intf); } /* set up all urbs so they can be used with either bulk or interrupt */ #define INTERRUPT_RATE 1 /* msec/transfer */ #define xprintk(tdev,level,fmt,args...) \ dev_printk(level , &(tdev)->intf->dev , fmt , ## args) #ifdef DEBUG #define DBG(dev,fmt,args...) \ xprintk(dev , KERN_DEBUG , fmt , ## args) #else #define DBG(dev,fmt,args...) \ do { } while (0) #endif /* DEBUG */ #ifdef VERBOSE #define VDBG DBG #else #define VDBG(dev,fmt,args...) \ do { } while (0) #endif /* VERBOSE */ #define ERROR(dev,fmt,args...) \ xprintk(dev , KERN_ERR , fmt , ## args) #define WARN(dev,fmt,args...) \ xprintk(dev , KERN_WARNING , fmt , ## args) #define INFO(dev,fmt,args...) \ xprintk(dev , KERN_INFO , fmt , ## args) /*-------------------------------------------------------------------------*/ static int get_endpoints (struct usbtest_dev *dev, struct usb_interface *intf) { int tmp; struct usb_host_interface *alt; struct usb_host_endpoint *in, *out; struct usb_host_endpoint *iso_in, *iso_out; struct usb_device *udev; for (tmp = 0; tmp < intf->num_altsetting; tmp++) { unsigned ep; in = out = NULL; iso_in = iso_out = NULL; alt = intf->altsetting + tmp; /* take the first altsetting with in-bulk + out-bulk; * ignore other endpoints and altsetttings. */ for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) { struct usb_host_endpoint *e; e = alt->endpoint + ep; switch (e->desc.bmAttributes) { case USB_ENDPOINT_XFER_BULK: break; case USB_ENDPOINT_XFER_ISOC: if (dev->info->iso) goto try_iso; // FALLTHROUGH default: continue; } if (usb_endpoint_dir_in(&e->desc)) { if (!in) in = e; } else { if (!out) out = e; } continue; try_iso: if (usb_endpoint_dir_in(&e->desc)) { if (!iso_in) iso_in = e; } else { if (!iso_out) iso_out = e; } } if ((in && out) || (iso_in && iso_out)) goto found; } return -EINVAL; found: udev = testdev_to_usbdev (dev); if (alt->desc.bAlternateSetting != 0) { tmp = usb_set_interface (udev, alt->desc.bInterfaceNumber, alt->desc.bAlternateSetting); if (tmp < 0) return tmp; } if (in) { dev->in_pipe = usb_rcvbulkpipe (udev, in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); dev->out_pipe = usb_sndbulkpipe (udev, out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); } if (iso_in) { dev->iso_in = &iso_in->desc; dev->in_iso_pipe = usb_rcvisocpipe (udev, iso_in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); dev->iso_out = &iso_out->desc; dev->out_iso_pipe = usb_sndisocpipe (udev, iso_out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); } return 0; } /*-------------------------------------------------------------------------*/ /* Support for testing basic non-queued I/O streams. * * These just package urbs as requests that can be easily canceled. * Each urb's data buffer is dynamically allocated; callers can fill * them with non-zero test data (or test for it) when appropriate. */ static void simple_callback (struct urb *urb) { complete ((struct completion *) urb->context); } static struct urb *simple_alloc_urb ( struct usb_device *udev, int pipe, unsigned long bytes ) { struct urb *urb; if (bytes < 0) return NULL; urb = usb_alloc_urb (0, GFP_KERNEL); if (!urb) return urb; usb_fill_bulk_urb (urb, udev, pipe, NULL, bytes, simple_callback, NULL); urb->interval = (udev->speed == USB_SPEED_HIGH) ? (INTERRUPT_RATE << 3) : INTERRUPT_RATE; urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; if (usb_pipein (pipe)) urb->transfer_flags |= URB_SHORT_NOT_OK; urb->transfer_buffer = usb_buffer_alloc (udev, bytes, GFP_KERNEL, &urb->transfer_dma); if (!urb->transfer_buffer) { usb_free_urb (urb); urb = NULL; } else memset (urb->transfer_buffer, 0, bytes); return urb; } static unsigned pattern = 0; module_param (pattern, uint, S_IRUGO); // MODULE_PARM_DESC (pattern, "i/o pattern (0 == zeroes)"); static inline void simple_fill_buf (struct urb *urb) { unsigned i; u8 *buf = urb->transfer_buffer; unsigned len = urb->transfer_buffer_length; switch (pattern) { default: // FALLTHROUGH case 0: memset (buf, 0, len); break; case 1: /* mod63 */ for (i = 0; i < len; i++) *buf++ = (u8) (i % 63); break; } } static inline int simple_check_buf (struct urb *urb) { unsigned i; u8 expected; u8 *buf = urb->transfer_buffer; unsigned len = urb->actual_length; for (i = 0; i < len; i++, buf++) { switch (pattern) { /* all-zeroes has no synchronization issues */ case 0: expected = 0; break; /* mod63 stays in sync with short-terminated transfers, * or otherwise when host and gadget agree on how large * each usb transfer request should be. resync is done * with set_interface or set_config. */ case 1: /* mod63 */ expected = i % 63; break; /* always fail unsupported patterns */ default: expected = !*buf; break; } if (*buf == expected) continue; dbg ("buf[%d] = %d (not %d)", i, *buf, expected); return -EINVAL; } return 0; } static void simple_free_urb (struct urb *urb) { usb_buffer_free (urb->dev, urb->transfer_buffer_length, urb->transfer_buffer, urb->transfer_dma); usb_free_urb (urb); } static int simple_io ( struct urb *urb, int iterations, int vary, int expected, const char *label ) { struct usb_device *udev = urb->dev; int max = urb->transfer_buffer_length; struct completion completion; int retval = 0; urb->context = &completion; while (retval == 0 && iterations-- > 0) { init_completion (&completion); if (usb_pipeout (urb->pipe)) simple_fill_buf (urb); if ((retval = usb_submit_urb (urb, GFP_KERNEL)) != 0) break; /* NOTE: no timeouts; can't be broken out of by interrupt */ wait_for_completion (&completion); retval = urb->status; urb->dev = udev; if (retval == 0 && usb_pipein (urb->pipe)) retval = simple_check_buf (urb); if (vary) { int len = urb->transfer_buffer_length; len += vary; len %= max; if (len == 0) len = (vary < max) ? vary : max; urb->transfer_buffer_length = len; } /* FIXME if endpoint halted, clear halt (and log) */ } urb->transfer_buffer_length = max; if (expected != retval) dev_dbg (&udev->dev, "%s failed, iterations left %d, status %d (not %d)\n", label, iterations, retval, expected); return retval; } /*-------------------------------------------------------------------------*/ /* We use scatterlist primitives to test queued I/O. * Yes, this also tests the scatterlist primitives. */ static void free_sglist (struct scatterlist *sg, int nents) { unsigned i; if (!sg) return; for (i = 0; i < nents; i++) { if (!sg [i].page) continue; kfree (page_address (sg [i].page) + sg [i].offset); } kfree (sg); } static struct scatterlist * alloc_sglist (int nents, int max, int vary) { struct scatterlist *sg; unsigned i; unsigned size = max; sg = kmalloc (nents * sizeof *sg, GFP_KERNEL); if (!sg) return NULL; for (i = 0; i < nents; i++) { char *buf; unsigned j; buf = kzalloc (size, GFP_KERNEL); if (!buf) { free_sglist (sg, i); return NULL; } /* kmalloc pages are always physically contiguous! */ sg_init_one(&sg[i], buf, size); switch (pattern) { case 0: /* already zeroed */ break; case 1: for (j = 0; j < size; j++) *buf++ = (u8) (j % 63); break; } if (vary) { size += vary; size %= max; if (size == 0) size = (vary < max) ? vary : max; } } return sg; } static int perform_sglist ( struct usb_device *udev, unsigned iterations, int pipe, struct usb_sg_request *req, struct scatterlist *sg, int nents ) { int retval = 0; while (retval == 0 && iterations-- > 0) { retval = usb_sg_init (req, udev, pipe, (udev->speed == USB_SPEED_HIGH) ? (INTERRUPT_RATE << 3) : INTERRUPT_RATE, sg, nents, 0, GFP_KERNEL); if (retval) break; usb_sg_wait (req); retval = req->status; /* FIXME check resulting data pattern */ /* FIXME if endpoint halted, clear halt (and log) */ } // FIXME for unlink or fault handling tests, don't report // failure if retval is as we expected ... if (retval) dbg ("perform_sglist failed, iterations left %d, status %d", iterations, retval); return retval; } /*-------------------------------------------------------------------------*/ /* unqueued control message testing * * there's a nice set of device functional requirements in chapter 9 of the * usb 2.0 spec, which we can apply to ANY device, even ones that don't use * special test firmware. * * we know the device is configured (or suspended) by the time it's visible * through usbfs. we can't change that, so we won't test enumeration (which * worked 'well enough' to get here, this time), power management (ditto), * or remote wakeup (which needs human interaction). */ static unsigned realworld = 1; module_param (realworld, uint, 0); MODULE_PARM_DESC (realworld, "clear to demand stricter spec compliance"); static int get_altsetting (struct usbtest_dev *dev) { struct usb_interface *iface = dev->intf; struct usb_device *udev = interface_to_usbdev (iface); int retval; retval = usb_control_msg (udev, usb_rcvctrlpipe (udev, 0), USB_REQ_GET_INTERFACE, USB_DIR_IN|USB_RECIP_INTERFACE, 0, iface->altsetting [0].desc.bInterfaceNumber, dev->buf, 1, USB_CTRL_GET_TIMEOUT); switch (retval) { case 1: return dev->buf [0]; case 0: retval = -ERANGE; // FALLTHROUGH default: return retval; } } static int set_altsetting (struct usbtest_dev *dev, int alternate) { struct usb_interface *iface = dev->intf; struct usb_device *udev; if (alternate < 0 || alternate >= 256) return -EINVAL; udev = interface_to_usbdev (iface);