diff options
Diffstat (limited to 'drivers/usb/misc/usbtest.c')
| -rw-r--r-- | drivers/usb/misc/usbtest.c | 676 | 
1 files changed, 600 insertions, 76 deletions
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index a35b427c0ba..829f446064e 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -7,9 +7,16 @@  #include <linux/moduleparam.h>  #include <linux/scatterlist.h>  #include <linux/mutex.h> - +#include <linux/timer.h>  #include <linux/usb.h> +#define SIMPLE_IO_TIMEOUT	10000	/* in milliseconds */ + +/*-------------------------------------------------------------------------*/ + +static int override_alt = -1; +module_param_named(alt, override_alt, int, 0644); +MODULE_PARM_DESC(alt, ">= 0 to override altsetting selection");  /*-------------------------------------------------------------------------*/ @@ -83,6 +90,8 @@ static struct usb_device *testdev_to_usbdev(struct usbtest_dev *test)  #define WARNING(tdev, fmt, args...) \  	dev_warn(&(tdev)->intf->dev , fmt , ## args) +#define GUARD_BYTE	0xA5 +  /*-------------------------------------------------------------------------*/  static int @@ -101,14 +110,18 @@ get_endpoints(struct usbtest_dev *dev, struct usb_interface *intf)  		iso_in = iso_out = NULL;  		alt = intf->altsetting + tmp; +		if (override_alt >= 0 && +				override_alt != alt->desc.bAlternateSetting) +			continue; +  		/* take the first altsetting with in-bulk + out-bulk; -		 * ignore other endpoints and altsetttings. +		 * ignore other endpoints and altsettings.  		 */  		for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) {  			struct usb_host_endpoint	*e;  			e = alt->endpoint + ep; -			switch (e->desc.bmAttributes) { +			switch (usb_endpoint_type(&e->desc)) {  			case USB_ENDPOINT_XFER_BULK:  				break;  			case USB_ENDPOINT_XFER_ISOC: @@ -142,6 +155,7 @@ try_iso:  found:  	udev = testdev_to_usbdev(dev); +	dev->info->alt = alt->desc.bAlternateSetting;  	if (alt->desc.bAlternateSetting != 0) {  		tmp = usb_set_interface(udev,  				alt->desc.bInterfaceNumber, @@ -186,11 +200,12 @@ static void simple_callback(struct urb *urb)  	complete(urb->context);  } -static struct urb *simple_alloc_urb( +static struct urb *usbtest_alloc_urb(  	struct usb_device	*udev,  	int			pipe, -	unsigned long		bytes -) +	unsigned long		bytes, +	unsigned		transfer_flags, +	unsigned		offset)  {  	struct urb		*urb; @@ -201,19 +216,46 @@ static struct urb *simple_alloc_urb(  	urb->interval = (udev->speed == USB_SPEED_HIGH)  			? (INTERRUPT_RATE << 3)  			: INTERRUPT_RATE; -	urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; +	urb->transfer_flags = transfer_flags;  	if (usb_pipein(pipe))  		urb->transfer_flags |= URB_SHORT_NOT_OK; -	urb->transfer_buffer = usb_alloc_coherent(udev, bytes, GFP_KERNEL, -			&urb->transfer_dma); + +	if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) +		urb->transfer_buffer = usb_alloc_coherent(udev, bytes + offset, +			GFP_KERNEL, &urb->transfer_dma); +	else +		urb->transfer_buffer = kmalloc(bytes + offset, GFP_KERNEL); +  	if (!urb->transfer_buffer) {  		usb_free_urb(urb); -		urb = NULL; -	} else -		memset(urb->transfer_buffer, 0, bytes); +		return NULL; +	} + +	/* To test unaligned transfers add an offset and fill the +		unused memory with a guard value */ +	if (offset) { +		memset(urb->transfer_buffer, GUARD_BYTE, offset); +		urb->transfer_buffer += offset; +		if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) +			urb->transfer_dma += offset; +	} + +	/* For inbound transfers use guard byte so that test fails if +		data not correctly copied */ +	memset(urb->transfer_buffer, +			usb_pipein(urb->pipe) ? GUARD_BYTE : 0, +			bytes);  	return urb;  } +static struct urb *simple_alloc_urb( +	struct usb_device	*udev, +	int			pipe, +	unsigned long		bytes) +{ +	return usbtest_alloc_urb(udev, pipe, bytes, URB_NO_TRANSFER_DMA_MAP, 0); +} +  static unsigned pattern;  static unsigned mod_pattern;  module_param_named(pattern, mod_pattern, uint, S_IRUGO | S_IWUSR); @@ -238,13 +280,38 @@ static inline void simple_fill_buf(struct urb *urb)  	}  } -static inline int simple_check_buf(struct usbtest_dev *tdev, struct urb *urb) +static inline unsigned long buffer_offset(void *buf) +{ +	return (unsigned long)buf & (ARCH_KMALLOC_MINALIGN - 1); +} + +static int check_guard_bytes(struct usbtest_dev *tdev, struct urb *urb) +{ +	u8 *buf = urb->transfer_buffer; +	u8 *guard = buf - buffer_offset(buf); +	unsigned i; + +	for (i = 0; guard < buf; i++, guard++) { +		if (*guard != GUARD_BYTE) { +			ERROR(tdev, "guard byte[%d] %d (not %d)\n", +				i, *guard, GUARD_BYTE); +			return -EINVAL; +		} +	} +	return 0; +} + +static int simple_check_buf(struct usbtest_dev *tdev, struct urb *urb)  {  	unsigned	i;  	u8		expected;  	u8		*buf = urb->transfer_buffer;  	unsigned	len = urb->actual_length; +	int ret = check_guard_bytes(tdev, urb); +	if (ret) +		return ret; +  	for (i = 0; i < len; i++, buf++) {  		switch (pattern) {  		/* all-zeroes has no synchronization issues */ @@ -274,8 +341,16 @@ static inline int simple_check_buf(struct usbtest_dev *tdev, struct urb *urb)  static void simple_free_urb(struct urb *urb)  { -	usb_free_coherent(urb->dev, urb->transfer_buffer_length, -			  urb->transfer_buffer, urb->transfer_dma); +	unsigned long offset = buffer_offset(urb->transfer_buffer); + +	if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) +		usb_free_coherent( +			urb->dev, +			urb->transfer_buffer_length + offset, +			urb->transfer_buffer - offset, +			urb->transfer_dma - offset); +	else +		kfree(urb->transfer_buffer - offset);  	usb_free_urb(urb);  } @@ -292,19 +367,28 @@ static int simple_io(  	int			max = urb->transfer_buffer_length;  	struct completion	completion;  	int			retval = 0; +	unsigned long		expire;  	urb->context = &completion;  	while (retval == 0 && iterations-- > 0) {  		init_completion(&completion); -		if (usb_pipeout(urb->pipe)) +		if (usb_pipeout(urb->pipe)) {  			simple_fill_buf(urb); +			urb->transfer_flags |= URB_ZERO_PACKET; +		}  		retval = usb_submit_urb(urb, GFP_KERNEL);  		if (retval != 0)  			break; -		/* NOTE:  no timeouts; can't be broken out of by interrupt */ -		wait_for_completion(&completion); -		retval = urb->status; +		expire = msecs_to_jiffies(SIMPLE_IO_TIMEOUT); +		if (!wait_for_completion_timeout(&completion, expire)) { +			usb_kill_urb(urb); +			retval = (urb->status == -ENOENT ? +				  -ETIMEDOUT : urb->status); +		} else { +			retval = urb->status; +		} +  		urb->dev = udev;  		if (retval == 0 && usb_pipein(urb->pipe))  			retval = simple_check_buf(tdev, urb); @@ -358,7 +442,10 @@ alloc_sglist(int nents, int max, int vary)  	unsigned		i;  	unsigned		size = max; -	sg = kmalloc(nents * sizeof *sg, GFP_KERNEL); +	if (max == 0) +		return NULL; + +	sg = kmalloc_array(nents, sizeof(*sg), GFP_KERNEL);  	if (!sg)  		return NULL;  	sg_init_table(sg, nents); @@ -397,6 +484,14 @@ alloc_sglist(int nents, int max, int vary)  	return sg;  } +static void sg_timeout(unsigned long _req) +{ +	struct usb_sg_request	*req = (struct usb_sg_request *) _req; + +	req->status = -ETIMEDOUT; +	usb_sg_cancel(req); +} +  static int perform_sglist(  	struct usbtest_dev	*tdev,  	unsigned		iterations, @@ -408,6 +503,9 @@ static int perform_sglist(  {  	struct usb_device	*udev = testdev_to_usbdev(tdev);  	int			retval = 0; +	struct timer_list	sg_timer; + +	setup_timer_on_stack(&sg_timer, sg_timeout, (unsigned long) req);  	while (retval == 0 && iterations-- > 0) {  		retval = usb_sg_init(req, udev, pipe, @@ -418,7 +516,10 @@ static int perform_sglist(  		if (retval)  			break; +		mod_timer(&sg_timer, jiffies + +				msecs_to_jiffies(SIMPLE_IO_TIMEOUT));  		usb_sg_wait(req); +		del_timer_sync(&sg_timer);  		retval = req->status;  		/* FIXME check resulting data pattern */ @@ -494,7 +595,7 @@ static int is_good_config(struct usbtest_dev *tdev, int len)  {  	struct usb_config_descriptor	*config; -	if (len < sizeof *config) +	if (len < sizeof(*config))  		return 0;  	config = (struct usb_config_descriptor *) tdev->buf; @@ -527,6 +628,76 @@ static int is_good_config(struct usbtest_dev *tdev, int len)  	return 0;  } +static int is_good_ext(struct usbtest_dev *tdev, u8 *buf) +{ +	struct usb_ext_cap_descriptor *ext; +	u32 attr; + +	ext = (struct usb_ext_cap_descriptor *) buf; + +	if (ext->bLength != USB_DT_USB_EXT_CAP_SIZE) { +		ERROR(tdev, "bogus usb 2.0 extension descriptor length\n"); +		return 0; +	} + +	attr = le32_to_cpu(ext->bmAttributes); +	/* bits[1:15] is used and others are reserved */ +	if (attr & ~0xfffe) {	/* reserved == 0 */ +		ERROR(tdev, "reserved bits set\n"); +		return 0; +	} + +	return 1; +} + +static int is_good_ss_cap(struct usbtest_dev *tdev, u8 *buf) +{ +	struct usb_ss_cap_descriptor *ss; + +	ss = (struct usb_ss_cap_descriptor *) buf; + +	if (ss->bLength != USB_DT_USB_SS_CAP_SIZE) { +		ERROR(tdev, "bogus superspeed device capability descriptor length\n"); +		return 0; +	} + +	/* +	 * only bit[1] of bmAttributes is used for LTM and others are +	 * reserved +	 */ +	if (ss->bmAttributes & ~0x02) {	/* reserved == 0 */ +		ERROR(tdev, "reserved bits set in bmAttributes\n"); +		return 0; +	} + +	/* bits[0:3] of wSpeedSupported is used and others are reserved */ +	if (le16_to_cpu(ss->wSpeedSupported) & ~0x0f) {	/* reserved == 0 */ +		ERROR(tdev, "reserved bits set in wSpeedSupported\n"); +		return 0; +	} + +	return 1; +} + +static int is_good_con_id(struct usbtest_dev *tdev, u8 *buf) +{ +	struct usb_ss_container_id_descriptor *con_id; + +	con_id = (struct usb_ss_container_id_descriptor *) buf; + +	if (con_id->bLength != USB_DT_USB_SS_CONTN_ID_SIZE) { +		ERROR(tdev, "bogus container id descriptor length\n"); +		return 0; +	} + +	if (con_id->bReserved) {	/* reserved == 0 */ +		ERROR(tdev, "reserved bits set\n"); +		return 0; +	} + +	return 1; +} +  /* sanity test for standard requests working with usb_control_mesg() and some   * of the utility functions which use it.   * @@ -604,12 +775,96 @@ static int ch9_postconfig(struct usbtest_dev *dev)  	/* there's always [9.4.3] a device descriptor [9.6.1] */  	retval = usb_get_descriptor(udev, USB_DT_DEVICE, 0, -			dev->buf, sizeof udev->descriptor); -	if (retval != sizeof udev->descriptor) { +			dev->buf, sizeof(udev->descriptor)); +	if (retval != sizeof(udev->descriptor)) {  		dev_err(&iface->dev, "dev descriptor --> %d\n", retval);  		return (retval < 0) ? retval : -EDOM;  	} +	/* +	 * there's always [9.4.3] a bos device descriptor [9.6.2] in USB +	 * 3.0 spec +	 */ +	if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0210) { +		struct usb_bos_descriptor *bos = NULL; +		struct usb_dev_cap_header *header = NULL; +		unsigned total, num, length; +		u8 *buf; + +		retval = usb_get_descriptor(udev, USB_DT_BOS, 0, dev->buf, +				sizeof(*udev->bos->desc)); +		if (retval != sizeof(*udev->bos->desc)) { +			dev_err(&iface->dev, "bos descriptor --> %d\n", retval); +			return (retval < 0) ? retval : -EDOM; +		} + +		bos = (struct usb_bos_descriptor *)dev->buf; +		total = le16_to_cpu(bos->wTotalLength); +		num = bos->bNumDeviceCaps; + +		if (total > TBUF_SIZE) +			total = TBUF_SIZE; + +		/* +		 * get generic device-level capability descriptors [9.6.2] +		 * in USB 3.0 spec +		 */ +		retval = usb_get_descriptor(udev, USB_DT_BOS, 0, dev->buf, +				total); +		if (retval != total) { +			dev_err(&iface->dev, "bos descriptor set --> %d\n", +					retval); +			return (retval < 0) ? retval : -EDOM; +		} + +		length = sizeof(*udev->bos->desc); +		buf = dev->buf; +		for (i = 0; i < num; i++) { +			buf += length; +			if (buf + sizeof(struct usb_dev_cap_header) > +					dev->buf + total) +				break; + +			header = (struct usb_dev_cap_header *)buf; +			length = header->bLength; + +			if (header->bDescriptorType != +					USB_DT_DEVICE_CAPABILITY) { +				dev_warn(&udev->dev, "not device capability descriptor, skip\n"); +				continue; +			} + +			switch (header->bDevCapabilityType) { +			case USB_CAP_TYPE_EXT: +				if (buf + USB_DT_USB_EXT_CAP_SIZE > +						dev->buf + total || +						!is_good_ext(dev, buf)) { +					dev_err(&iface->dev, "bogus usb 2.0 extension descriptor\n"); +					return -EDOM; +				} +				break; +			case USB_SS_CAP_TYPE: +				if (buf + USB_DT_USB_SS_CAP_SIZE > +						dev->buf + total || +						!is_good_ss_cap(dev, buf)) { +					dev_err(&iface->dev, "bogus superspeed device capability descriptor\n"); +					return -EDOM; +				} +				break; +			case CONTAINER_ID_TYPE: +				if (buf + USB_DT_USB_SS_CONTN_ID_SIZE > +						dev->buf + total || +						!is_good_con_id(dev, buf)) { +					dev_err(&iface->dev, "bogus container id descriptor\n"); +					return -EDOM; +				} +				break; +			default: +				break; +			} +		} +	} +  	/* there's always [9.4.3] at least one config descriptor [9.6.3] */  	for (i = 0; i < udev->descriptor.bNumConfigurations; i++) {  		retval = usb_get_descriptor(udev, USB_DT_CONFIG, i, @@ -668,9 +923,9 @@ static int ch9_postconfig(struct usbtest_dev *dev)  	/* [9.4.5] get_status always works */  	retval = usb_get_status(udev, USB_RECIP_DEVICE, 0, dev->buf); -	if (retval != 2) { +	if (retval) {  		dev_err(&iface->dev, "get dev status --> %d\n", retval); -		return (retval < 0) ? retval : -EDOM; +		return retval;  	}  	/* FIXME configuration.bmAttributes says if we could try to set/clear @@ -679,9 +934,9 @@ static int ch9_postconfig(struct usbtest_dev *dev)  	retval = usb_get_status(udev, USB_RECIP_INTERFACE,  			iface->altsetting[0].desc.bInterfaceNumber, dev->buf); -	if (retval != 2) { +	if (retval) {  		dev_err(&iface->dev, "get interface status --> %d\n", retval); -		return (retval < 0) ? retval : -EDOM; +		return retval;  	}  	/* FIXME get status for each endpoint in the interface */ @@ -711,7 +966,7 @@ struct ctrl_ctx {  	int			last;  }; -#define NUM_SUBCASES	15		/* how many test subcases here? */ +#define NUM_SUBCASES	16		/* how many test subcases here? */  struct subcase {  	struct usb_ctrlrequest	setup; @@ -839,6 +1094,9 @@ test_ctrl_queue(struct usbtest_dev *dev, struct usbtest_param *param)  	struct ctrl_ctx		context;  	int			i; +	if (param->sglen == 0 || param->iterations > UINT_MAX / param->sglen) +		return -EOPNOTSUPP; +  	spin_lock_init(&context.lock);  	context.dev = dev;  	init_completion(&context.complete); @@ -872,7 +1130,7 @@ test_ctrl_queue(struct usbtest_dev *dev, struct usbtest_param *param)  		 * device, but some are chosen to trigger protocol stalls  		 * or short reads.  		 */ -		memset(&req, 0, sizeof req); +		memset(&req, 0, sizeof(req));  		req.bRequest = USB_REQ_GET_DESCRIPTOR;  		req.bRequestType = USB_DIR_IN|USB_RECIP_DEVICE; @@ -960,13 +1218,18 @@ test_ctrl_queue(struct usbtest_dev *dev, struct usbtest_param *param)  		case 13:	/* short read, resembling case 10 */  			req.wValue = cpu_to_le16((USB_DT_CONFIG << 8) | 0);  			/* last data packet "should" be DATA1, not DATA0 */ -			len = 1024 - udev->descriptor.bMaxPacketSize0; +			if (udev->speed == USB_SPEED_SUPER) +				len = 1024 - 512; +			else +				len = 1024 - udev->descriptor.bMaxPacketSize0;  			expected = -EREMOTEIO;  			break;  		case 14:	/* short read; try to fill the last packet */  			req.wValue = cpu_to_le16((USB_DT_DEVICE << 8) | 0);  			/* device descriptor size == 18 bytes */  			len = udev->descriptor.bMaxPacketSize0; +			if (udev->speed == USB_SPEED_SUPER) +				len = 512;  			switch (len) {  			case 8:  				len = 24; @@ -977,6 +1240,15 @@ test_ctrl_queue(struct usbtest_dev *dev, struct usbtest_param *param)  			}  			expected = -EREMOTEIO;  			break; +		case 15: +			req.wValue = cpu_to_le16(USB_DT_BOS << 8); +			if (udev->bos) +				len = le16_to_cpu(udev->bos->desc->wTotalLength); +			else +				len = sizeof(struct usb_bos_descriptor); +			if (le16_to_cpu(udev->descriptor.bcdUSB) < 0x0201) +				expected = -EPIPE; +			break;  		default:  			ERROR(dev, "bogus number of ctrl queue testcases!\n");  			context.status = -EINVAL; @@ -987,7 +1259,7 @@ test_ctrl_queue(struct usbtest_dev *dev, struct usbtest_param *param)  		if (!u)  			goto cleanup; -		reqp = kmalloc(sizeof *reqp, GFP_KERNEL); +		reqp = kmalloc(sizeof(*reqp), GFP_KERNEL);  		if (!reqp)  			goto cleanup;  		reqp->setup = req; @@ -1062,6 +1334,11 @@ static int unlink1(struct usbtest_dev *dev, int pipe, int size, int async)  	urb->context = &completion;  	urb->complete = unlink1_callback; +	if (usb_pipeout(urb->pipe)) { +		simple_fill_buf(urb); +		urb->transfer_flags |= URB_ZERO_PACKET; +	} +  	/* keep the endpoint busy.  there are lots of hc/hcd-internal  	 * states, and testing should get to all of them over time.  	 * @@ -1082,6 +1359,9 @@ static int unlink1(struct usbtest_dev *dev, int pipe, int size, int async)  		while (!completion_done(&completion)) {  			retval = usb_unlink_urb(urb); +			if (retval == 0 && usb_pipein(urb->pipe)) +				retval = simple_check_buf(dev, urb); +  			switch (retval) {  			case -EBUSY:  			case -EIDRM: @@ -1132,6 +1412,109 @@ static int unlink_simple(struct usbtest_dev *dev, int pipe, int len)  /*-------------------------------------------------------------------------*/ +struct queued_ctx { +	struct completion	complete; +	atomic_t		pending; +	unsigned		num; +	int			status; +	struct urb		**urbs; +}; + +static void unlink_queued_callback(struct urb *urb) +{ +	int			status = urb->status; +	struct queued_ctx	*ctx = urb->context; + +	if (ctx->status) +		goto done; +	if (urb == ctx->urbs[ctx->num - 4] || urb == ctx->urbs[ctx->num - 2]) { +		if (status == -ECONNRESET) +			goto done; +		/* What error should we report if the URB completed normally? */ +	} +	if (status != 0) +		ctx->status = status; + + done: +	if (atomic_dec_and_test(&ctx->pending)) +		complete(&ctx->complete); +} + +static int unlink_queued(struct usbtest_dev *dev, int pipe, unsigned num, +		unsigned size) +{ +	struct queued_ctx	ctx; +	struct usb_device	*udev = testdev_to_usbdev(dev); +	void			*buf; +	dma_addr_t		buf_dma; +	int			i; +	int			retval = -ENOMEM; + +	init_completion(&ctx.complete); +	atomic_set(&ctx.pending, 1);	/* One more than the actual value */ +	ctx.num = num; +	ctx.status = 0; + +	buf = usb_alloc_coherent(udev, size, GFP_KERNEL, &buf_dma); +	if (!buf) +		return retval; +	memset(buf, 0, size); + +	/* Allocate and init the urbs we'll queue */ +	ctx.urbs = kcalloc(num, sizeof(struct urb *), GFP_KERNEL); +	if (!ctx.urbs) +		goto free_buf; +	for (i = 0; i < num; i++) { +		ctx.urbs[i] = usb_alloc_urb(0, GFP_KERNEL); +		if (!ctx.urbs[i]) +			goto free_urbs; +		usb_fill_bulk_urb(ctx.urbs[i], udev, pipe, buf, size, +				unlink_queued_callback, &ctx); +		ctx.urbs[i]->transfer_dma = buf_dma; +		ctx.urbs[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + +		if (usb_pipeout(ctx.urbs[i]->pipe)) { +			simple_fill_buf(ctx.urbs[i]); +			ctx.urbs[i]->transfer_flags |= URB_ZERO_PACKET; +		} +	} + +	/* Submit all the URBs and then unlink URBs num - 4 and num - 2. */ +	for (i = 0; i < num; i++) { +		atomic_inc(&ctx.pending); +		retval = usb_submit_urb(ctx.urbs[i], GFP_KERNEL); +		if (retval != 0) { +			dev_err(&dev->intf->dev, "submit urbs[%d] fail %d\n", +					i, retval); +			atomic_dec(&ctx.pending); +			ctx.status = retval; +			break; +		} +	} +	if (i == num) { +		usb_unlink_urb(ctx.urbs[num - 4]); +		usb_unlink_urb(ctx.urbs[num - 2]); +	} else { +		while (--i >= 0) +			usb_unlink_urb(ctx.urbs[i]); +	} + +	if (atomic_dec_and_test(&ctx.pending))		/* The extra count */ +		complete(&ctx.complete); +	wait_for_completion(&ctx.complete); +	retval = ctx.status; + + free_urbs: +	for (i = 0; i < num; i++) +		usb_free_urb(ctx.urbs[i]); +	kfree(ctx.urbs); + free_buf: +	usb_free_coherent(udev, size, buf, buf_dma); +	return retval; +} + +/*-------------------------------------------------------------------------*/ +  static int verify_not_halted(struct usbtest_dev *tdev, int ep, struct urb *urb)  {  	int	retval; @@ -1166,7 +1549,6 @@ static int verify_halted(struct usbtest_dev *tdev, int ep, struct urb *urb)  				ep, retval);  		return retval;  	} -	le16_to_cpus(&status);  	if (status != 1) {  		ERROR(tdev, "ep %02x bogus status: %04x != 1\n", ep, status);  		return -EINVAL; @@ -1199,8 +1581,17 @@ static int test_halt(struct usbtest_dev *tdev, int ep, struct urb *urb)  		return retval;  	}  	retval = verify_halted(tdev, ep, urb); -	if (retval < 0) +	if (retval < 0) { +		int ret; + +		/* clear halt anyways, else further tests will fail */ +		ret = usb_clear_halt(urb->dev, urb->pipe); +		if (ret) +			ERROR(tdev, "ep %02x couldn't clear halt, %d\n", +			      ep, ret); +  		return retval; +	}  	/* clear halt (tests API + protocol), verify it worked */  	retval = usb_clear_halt(urb->dev, urb->pipe); @@ -1219,11 +1610,15 @@ static int test_halt(struct usbtest_dev *tdev, int ep, struct urb *urb)  static int halt_simple(struct usbtest_dev *dev)  { -	int		ep; -	int		retval = 0; -	struct urb	*urb; +	int			ep; +	int			retval = 0; +	struct urb		*urb; +	struct usb_device	*udev = testdev_to_usbdev(dev); -	urb = simple_alloc_urb(testdev_to_usbdev(dev), 0, 512); +	if (udev->speed == USB_SPEED_SUPER) +		urb = simple_alloc_urb(udev, 0, 1024); +	else +		urb = simple_alloc_urb(udev, 0, 512);  	if (urb == NULL)  		return -ENOMEM; @@ -1256,7 +1651,7 @@ done:   * try whatever we're told to try.   */  static int ctrl_out(struct usbtest_dev *dev, -		unsigned count, unsigned length, unsigned vary) +		unsigned count, unsigned length, unsigned vary, unsigned offset)  {  	unsigned		i, j, len;  	int			retval; @@ -1267,10 +1662,11 @@ static int ctrl_out(struct usbtest_dev *dev,  	if (length < 1 || length > 0xffff || vary >= length)  		return -EINVAL; -	buf = kmalloc(length, GFP_KERNEL); +	buf = kmalloc(length + offset, GFP_KERNEL);  	if (!buf)  		return -ENOMEM; +	buf += offset;  	udev = testdev_to_usbdev(dev);  	len = length;  	retval = 0; @@ -1337,7 +1733,7 @@ static int ctrl_out(struct usbtest_dev *dev,  		ERROR(dev, "ctrl_out %s failed, code %d, count %d\n",  			what, retval, i); -	kfree(buf); +	kfree(buf - offset);  	return retval;  } @@ -1373,6 +1769,8 @@ static void iso_callback(struct urb *urb)  		ctx->errors += urb->number_of_packets;  	else if (urb->actual_length != urb->transfer_buffer_length)  		ctx->errors++; +	else if (check_guard_bytes(ctx->dev, urb) != 0) +		ctx->errors++;  	if (urb->status == 0 && ctx->count > (ctx->pending - 1)  			&& !ctx->submit_error) { @@ -1408,7 +1806,8 @@ static struct urb *iso_alloc_urb(  	struct usb_device	*udev,  	int			pipe,  	struct usb_endpoint_descriptor	*desc, -	long			bytes +	long			bytes, +	unsigned offset  )  {  	struct urb		*urb; @@ -1416,8 +1815,8 @@ static struct urb *iso_alloc_urb(  	if (bytes < 0 || !desc)  		return NULL; -	maxp = 0x7ff & le16_to_cpu(desc->wMaxPacketSize); -	maxp *= 1 + (0x3 & (le16_to_cpu(desc->wMaxPacketSize) >> 11)); +	maxp = 0x7ff & usb_endpoint_maxp(desc); +	maxp *= 1 + (0x3 & (usb_endpoint_maxp(desc) >> 11));  	packets = DIV_ROUND_UP(bytes, maxp);  	urb = usb_alloc_urb(packets, GFP_KERNEL); @@ -1428,13 +1827,24 @@ static struct urb *iso_alloc_urb(  	urb->number_of_packets = packets;  	urb->transfer_buffer_length = bytes; -	urb->transfer_buffer = usb_alloc_coherent(udev, bytes, GFP_KERNEL, -			&urb->transfer_dma); +	urb->transfer_buffer = usb_alloc_coherent(udev, bytes + offset, +							GFP_KERNEL, +							&urb->transfer_dma);  	if (!urb->transfer_buffer) {  		usb_free_urb(urb);  		return NULL;  	} -	memset(urb->transfer_buffer, 0, bytes); +	if (offset) { +		memset(urb->transfer_buffer, GUARD_BYTE, offset); +		urb->transfer_buffer += offset; +		urb->transfer_dma += offset; +	} +	/* For inbound transfers use guard byte so that test fails if +		data not correctly copied */ +	memset(urb->transfer_buffer, +			usb_pipein(urb->pipe) ? GUARD_BYTE : 0, +			bytes); +  	for (i = 0; i < packets; i++) {  		/* here, only the last packet will be short */  		urb->iso_frame_desc[i].length = min((unsigned) bytes, maxp); @@ -1452,7 +1862,7 @@ static struct urb *iso_alloc_urb(  static int  test_iso_queue(struct usbtest_dev *dev, struct usbtest_param *param, -		int pipe, struct usb_endpoint_descriptor *desc) +		int pipe, struct usb_endpoint_descriptor *desc, unsigned offset)  {  	struct iso_context	context;  	struct usb_device	*udev; @@ -1464,23 +1874,23 @@ test_iso_queue(struct usbtest_dev *dev, struct usbtest_param *param,  	if (param->sglen > 10)  		return -EDOM; -	memset(&context, 0, sizeof context); +	memset(&context, 0, sizeof(context));  	context.count = param->iterations * param->sglen;  	context.dev = dev;  	init_completion(&context.done);  	spin_lock_init(&context.lock); -	memset(urbs, 0, sizeof urbs); +	memset(urbs, 0, sizeof(urbs));  	udev = testdev_to_usbdev(dev);  	dev_info(&dev->intf->dev,  		"... iso period %d %sframes, wMaxPacket %04x\n",  		1 << (desc->bInterval - 1),  		(udev->speed == USB_SPEED_HIGH) ? "micro" : "", -		le16_to_cpu(desc->wMaxPacketSize)); +		usb_endpoint_maxp(desc));  	for (i = 0; i < param->sglen; i++) {  		urbs[i] = iso_alloc_urb(udev, pipe, desc, -				param->length); +					param->length, offset);  		if (!urbs[i]) {  			status = -ENOMEM;  			goto fail; @@ -1542,6 +1952,26 @@ fail:  	return status;  } +static int test_unaligned_bulk( +	struct usbtest_dev *tdev, +	int pipe, +	unsigned length, +	int iterations, +	unsigned transfer_flags, +	const char *label) +{ +	int retval; +	struct urb *urb = usbtest_alloc_urb( +		testdev_to_usbdev(tdev), pipe, length, transfer_flags, 1); + +	if (!urb) +		return -ENOMEM; + +	retval = simple_io(tdev, urb, iterations, 0, 0, label); +	simple_free_urb(urb); +	return retval; +} +  /*-------------------------------------------------------------------------*/  /* We only have this one interface to user space, through usbfs. @@ -1565,7 +1995,6 @@ fail:   * off just killing the userspace task and waiting for it to exit.   */ -/* No BKL needed */  static int  usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)  { @@ -1782,8 +2211,6 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)  	/* queued control messaging */  	case 10: -		if (param->sglen == 0) -			break;  		retval = 0;  		dev_info(&intf->dev,  				"TEST 10:  queue %d control calls, %d times\n", @@ -1843,7 +2270,7 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)  				realworld ? 1 : 0, param->length,  				param->vary);  		retval = ctrl_out(dev, param->iterations, -				param->length, param->vary); +				param->length, param->vary, 0);  		break;  	/* iso write tests */ @@ -1856,7 +2283,7 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)  				param->sglen, param->length);  		/* FIRMWARE:  iso sink */  		retval = test_iso_queue(dev, param, -				dev->out_iso_pipe, dev->iso_out); +				dev->out_iso_pipe, dev->iso_out, 0);  		break;  	/* iso read tests */ @@ -1869,13 +2296,121 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)  				param->sglen, param->length);  		/* FIRMWARE:  iso source */  		retval = test_iso_queue(dev, param, -				dev->in_iso_pipe, dev->iso_in); +				dev->in_iso_pipe, dev->iso_in, 0);  		break; -	/* FIXME unlink from queue (ring with N urbs) */ -  	/* FIXME scatterlist cancel (needs helper thread) */ +	/* Tests for bulk I/O using DMA mapping by core and odd address */ +	case 17: +		if (dev->out_pipe == 0) +			break; +		dev_info(&intf->dev, +			"TEST 17:  write odd addr %d bytes %u times core map\n", +			param->length, param->iterations); + +		retval = test_unaligned_bulk( +				dev, dev->out_pipe, +				param->length, param->iterations, +				0, "test17"); +		break; + +	case 18: +		if (dev->in_pipe == 0) +			break; +		dev_info(&intf->dev, +			"TEST 18:  read odd addr %d bytes %u times core map\n", +			param->length, param->iterations); + +		retval = test_unaligned_bulk( +				dev, dev->in_pipe, +				param->length, param->iterations, +				0, "test18"); +		break; + +	/* Tests for bulk I/O using premapped coherent buffer and odd address */ +	case 19: +		if (dev->out_pipe == 0) +			break; +		dev_info(&intf->dev, +			"TEST 19:  write odd addr %d bytes %u times premapped\n", +			param->length, param->iterations); + +		retval = test_unaligned_bulk( +				dev, dev->out_pipe, +				param->length, param->iterations, +				URB_NO_TRANSFER_DMA_MAP, "test19"); +		break; + +	case 20: +		if (dev->in_pipe == 0) +			break; +		dev_info(&intf->dev, +			"TEST 20:  read odd addr %d bytes %u times premapped\n", +			param->length, param->iterations); + +		retval = test_unaligned_bulk( +				dev, dev->in_pipe, +				param->length, param->iterations, +				URB_NO_TRANSFER_DMA_MAP, "test20"); +		break; + +	/* control write tests with unaligned buffer */ +	case 21: +		if (!dev->info->ctrl_out) +			break; +		dev_info(&intf->dev, +				"TEST 21:  %d ep0out odd addr, %d..%d vary %d\n", +				param->iterations, +				realworld ? 1 : 0, param->length, +				param->vary); +		retval = ctrl_out(dev, param->iterations, +				param->length, param->vary, 1); +		break; + +	/* unaligned iso tests */ +	case 22: +		if (dev->out_iso_pipe == 0 || param->sglen == 0) +			break; +		dev_info(&intf->dev, +			"TEST 22:  write %d iso odd, %d entries of %d bytes\n", +				param->iterations, +				param->sglen, param->length); +		retval = test_iso_queue(dev, param, +				dev->out_iso_pipe, dev->iso_out, 1); +		break; + +	case 23: +		if (dev->in_iso_pipe == 0 || param->sglen == 0) +			break; +		dev_info(&intf->dev, +			"TEST 23:  read %d iso odd, %d entries of %d bytes\n", +				param->iterations, +				param->sglen, param->length); +		retval = test_iso_queue(dev, param, +				dev->in_iso_pipe, dev->iso_in, 1); +		break; + +	/* unlink URBs from a bulk-OUT queue */ +	case 24: +		if (dev->out_pipe == 0 || !param->length || param->sglen < 4) +			break; +		retval = 0; +		dev_info(&intf->dev, "TEST 24:  unlink from %d queues of " +				"%d %d-byte writes\n", +				param->iterations, param->sglen, param->length); +		for (i = param->iterations; retval == 0 && i > 0; --i) { +			retval = unlink_queued(dev, dev->out_pipe, +						param->sglen, param->length); +			if (retval) { +				dev_err(&intf->dev, +					"unlink queued writes failed %d, " +					"iterations left %d\n", retval, i); +				break; +			} +		} +		break; +  	}  	do_gettimeofday(¶m->duration);  	param->duration.tv_sec -= start.tv_sec; @@ -1962,13 +2497,15 @@ usbtest_probe(struct usb_interface *intf, const struct usb_device_id *id)  			wtest = " intr-out";  		}  	} else { -		if (info->autoconf) { +		if (override_alt >= 0 || info->autoconf) {  			int status;  			status = get_endpoints(dev, intf);  			if (status < 0) {  				WARNING(dev, "couldn't get endpoints, %d\n",  						status); +				kfree(dev->buf); +				kfree(dev);  				return status;  			}  			/* may find bulk or ISO pipes */ @@ -1992,22 +2529,8 @@ usbtest_probe(struct usb_interface *intf, const struct usb_device_id *id)  	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; }), +	dev_info(&intf->dev, "%s {control%s%s%s%s%s} tests%s\n", +			usb_speed_string(udev->speed),  			info->ctrl_out ? " in/out" : "",  			rtest, wtest,  			irtest, iwtest, @@ -2083,6 +2606,7 @@ static struct usbtest_info gz_info = {  	.name		= "Linux gadget zero",  	.autoconf	= 1,  	.ctrl_out	= 1, +	.iso		= 1,  	.alt		= 0,  };  | 
