⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usbtest.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
	wait_for_completion (&completion);	retval = urb->status;	simple_free_urb (urb);	if (async)		return (retval == -ECONNRESET) ? 0 : retval - 1000;	else		return (retval == -ENOENT || retval == -EPERM) ?				0 : retval - 2000;}static int unlink_simple (struct usbtest_dev *dev, int pipe, int len){	int			retval = 0;	/* test sync and async paths */	retval = unlink1 (dev, pipe, len, 1);	if (!retval)		retval = unlink1 (dev, pipe, len, 0);	return retval;}/*-------------------------------------------------------------------------*/static int verify_not_halted (int ep, struct urb *urb){	int	retval;	u16	status;	/* shouldn't look or act halted */	retval = usb_get_status (urb->dev, USB_RECIP_ENDPOINT, ep, &status);	if (retval < 0) {		dbg ("ep %02x couldn't get no-halt status, %d", ep, retval);		return retval;	}	if (status != 0) {		dbg ("ep %02x bogus status: %04x != 0", ep, status);		return -EINVAL;	}	retval = simple_io (urb, 1, 0, 0, __FUNCTION__);	if (retval != 0)		return -EINVAL;	return 0;}static int verify_halted (int ep, struct urb *urb){	int	retval;	u16	status;	/* should look and act halted */	retval = usb_get_status (urb->dev, USB_RECIP_ENDPOINT, ep, &status);	if (retval < 0) {		dbg ("ep %02x couldn't get halt status, %d", ep, retval);		return retval;	}	if (status != 1) {		dbg ("ep %02x bogus status: %04x != 1", ep, status);		return -EINVAL;	}	retval = simple_io (urb, 1, 0, -EPIPE, __FUNCTION__);	if (retval != -EPIPE)		return -EINVAL;	retval = simple_io (urb, 1, 0, -EPIPE, "verify_still_halted");	if (retval != -EPIPE)		return -EINVAL;	return 0;}static int test_halt (int ep, struct urb *urb){	int	retval;	/* shouldn't look or act halted now */	retval = verify_not_halted (ep, urb);	if (retval < 0)		return retval;	/* set halt (protocol test only), verify it worked */	retval = usb_control_msg (urb->dev, usb_sndctrlpipe (urb->dev, 0),			USB_REQ_SET_FEATURE, USB_RECIP_ENDPOINT,			USB_ENDPOINT_HALT, ep,			NULL, 0, USB_CTRL_SET_TIMEOUT);	if (retval < 0) {		dbg ("ep %02x couldn't set halt, %d", ep, retval);		return retval;	}	retval = verify_halted (ep, urb);	if (retval < 0)		return retval;	/* clear halt (tests API + protocol), verify it worked */	retval = usb_clear_halt (urb->dev, urb->pipe);	if (retval < 0) {		dbg ("ep %02x couldn't clear halt, %d", ep, retval);		return retval;	}	retval = verify_not_halted (ep, urb);	if (retval < 0)		return retval;	/* NOTE:  could also verify SET_INTERFACE clear halts ... */	return 0;}static int halt_simple (struct usbtest_dev *dev){	int		ep;	int		retval = 0;	struct urb	*urb;	urb = simple_alloc_urb (testdev_to_usbdev (dev), 0, 512);	if (urb == NULL)		return -ENOMEM;	if (dev->in_pipe) {		ep = usb_pipeendpoint (dev->in_pipe) | USB_DIR_IN;		urb->pipe = dev->in_pipe;		retval = test_halt (ep, urb);		if (retval < 0)			goto done;	}	if (dev->out_pipe) {		ep = usb_pipeendpoint (dev->out_pipe);		urb->pipe = dev->out_pipe;		retval = test_halt (ep, urb);	}done:	simple_free_urb (urb);	return retval;}/*-------------------------------------------------------------------------*//* Control OUT tests use the vendor control requests from Intel's * USB 2.0 compliance test device:  write a buffer, read it back. * * Intel's spec only _requires_ that it work for one packet, which * is pretty weak.   Some HCDs place limits here; most devices will * need to be able to handle more than one OUT data packet.  We'll * try whatever we're told to try. */static int ctrl_out (struct usbtest_dev *dev,		unsigned count, unsigned length, unsigned vary){	unsigned		i, j, len, retval;	u8			*buf;	char			*what = "?";	struct usb_device	*udev;		if (length < 1 || length > 0xffff || vary >= length)		return -EINVAL;	buf = kmalloc(length, SLAB_KERNEL);	if (!buf)		return -ENOMEM;	udev = testdev_to_usbdev (dev);	len = length;	retval = 0;	/* NOTE:  hardware might well act differently if we pushed it	 * with lots back-to-back queued requests.	 */	for (i = 0; i < count; i++) {		/* write patterned data */		for (j = 0; j < len; j++)			buf [j] = i + j;		retval = usb_control_msg (udev, usb_sndctrlpipe (udev,0),				0x5b, USB_DIR_OUT|USB_TYPE_VENDOR,				0, 0, buf, len, USB_CTRL_SET_TIMEOUT);		if (retval != len) {			what = "write";			if (retval >= 0) {				INFO(dev, "ctrl_out, wlen %d (expected %d)\n",						retval, len);				retval = -EBADMSG;			}			break;		}		/* read it back -- assuming nothing intervened!!  */		retval = usb_control_msg (udev, usb_rcvctrlpipe (udev,0),				0x5c, USB_DIR_IN|USB_TYPE_VENDOR,				0, 0, buf, len, USB_CTRL_GET_TIMEOUT);		if (retval != len) {			what = "read";			if (retval >= 0) {				INFO(dev, "ctrl_out, rlen %d (expected %d)\n",						retval, len);				retval = -EBADMSG;			}			break;		}		/* fail if we can't verify */		for (j = 0; j < len; j++) {			if (buf [j] != (u8) (i + j)) {				INFO (dev, "ctrl_out, byte %d is %d not %d\n",					j, buf [j], (u8) i + j);				retval = -EBADMSG;				break;			}		}		if (retval < 0) {			what = "verify";			break;		}		len += vary;		/* [real world] the "zero bytes IN" case isn't really used.		 * hardware can easily trip up in this wierd case, since its		 * status stage is IN, not OUT like other ep0in transfers.		 */		if (len > length)			len = realworld ? 1 : 0;	}	if (retval < 0)		INFO (dev, "ctrl_out %s failed, code %d, count %d\n",			what, retval, i);	kfree (buf);	return retval;}/*-------------------------------------------------------------------------*//* ISO tests ... mimics common usage *  - buffer length is split into N packets (mostly maxpacket sized) *  - multi-buffers according to sglen */struct iso_context {	unsigned		count;	unsigned		pending;	spinlock_t		lock;	struct completion	done;	unsigned long		errors;	struct usbtest_dev	*dev;};static void iso_callback (struct urb *urb, struct pt_regs *regs){	struct iso_context	*ctx = urb->context;	spin_lock(&ctx->lock);	ctx->count--;	if (urb->error_count > 0)		ctx->errors += urb->error_count;	if (urb->status == 0 && ctx->count > (ctx->pending - 1)) {		int status = usb_submit_urb (urb, GFP_ATOMIC);		switch (status) {		case 0:			goto done;		default:			dev_dbg (&ctx->dev->intf->dev,					"iso resubmit err %d\n",					status);			/* FALLTHROUGH */		case -ENODEV:			/* disconnected */			break;		}	}	simple_free_urb (urb);	ctx->pending--;	if (ctx->pending == 0) {		if (ctx->errors)			dev_dbg (&ctx->dev->intf->dev,				"iso test, %lu errors\n",				ctx->errors);		complete (&ctx->done);	}done:	spin_unlock(&ctx->lock);}static struct urb *iso_alloc_urb (	struct usb_device	*udev,	int			pipe,	struct usb_endpoint_descriptor	*desc,	long			bytes){	struct urb		*urb;	unsigned		i, maxp, packets;	if (bytes < 0 || !desc)		return NULL;	maxp = 0x7ff & le16_to_cpu(desc->wMaxPacketSize);	maxp *= 1 + (0x3 & (le16_to_cpu(desc->wMaxPacketSize) >> 11));	packets = (bytes + maxp - 1) / maxp;	urb = usb_alloc_urb (packets, SLAB_KERNEL);	if (!urb)		return urb;	urb->dev = udev;	urb->pipe = pipe;	urb->number_of_packets = packets;	urb->transfer_buffer_length = bytes;	urb->transfer_buffer = usb_buffer_alloc (udev, bytes, SLAB_KERNEL,			&urb->transfer_dma);	if (!urb->transfer_buffer) {		usb_free_urb (urb);		return NULL;	}	memset (urb->transfer_buffer, 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);		bytes -= urb->iso_frame_desc[i].length;		urb->iso_frame_desc[i].offset = maxp * i;	}	urb->complete = iso_callback;	// urb->context = SET BY CALLER	urb->interval = 1 << (desc->bInterval - 1);	urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;	return urb;}static inttest_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param,		int pipe, struct usb_endpoint_descriptor *desc){	struct iso_context	context;	struct usb_device	*udev;	unsigned		i;	unsigned long		packets = 0;	int			status;	struct urb		*urbs[10];	/* FIXME no limit */	if (param->sglen > 10)		return -EDOM;	context.count = param->iterations * param->sglen;	context.pending = param->sglen;	context.errors = 0;	context.dev = dev;	init_completion (&context.done);	spin_lock_init (&context.lock);	memset (urbs, 0, sizeof urbs);	udev = testdev_to_usbdev (dev);	dev_dbg (&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));	for (i = 0; i < param->sglen; i++) {		urbs [i] = iso_alloc_urb (udev, pipe, desc,				param->length);		if (!urbs [i]) {			status = -ENOMEM;			goto fail;		}		packets += urbs[i]->number_of_packets;		urbs [i]->context = &context;	}	packets *= param->iterations;	dev_dbg (&dev->intf->dev,		"... total %lu msec (%lu packets)\n",		(packets * (1 << (desc->bInterval - 1)))			/ ((udev->speed == USB_SPEED_HIGH) ? 8 : 1),		packets);	spin_lock_irq (&context.lock);	for (i = 0; i < param->sglen; i++) {		status = usb_submit_urb (urbs [i], SLAB_ATOMIC);		if (status < 0) {			ERROR (dev, "submit iso[%d], error %d\n", i, status);			if (i == 0) {				spin_unlock_irq (&context.lock);				goto fail;			}			simple_free_urb (urbs [i]);			context.pending--;		}	}	spin_unlock_irq (&context.lock);	wait_for_completion (&context.done);	return 0;fail:	for (i = 0; i < param->sglen; i++) {		if (urbs [i])			simple_free_urb (urbs [i]);	}	return status;}/*-------------------------------------------------------------------------*//* We only have this one interface to user space, through usbfs. * User mode code can scan usbfs to find N different devices (maybe on * different busses) to use when testing, and allocate one thread per * test.  So discovery is simplified, and we have no device naming issues. * * Don't use these only as stress/load tests.  Use them along with with * other USB bus activity:  plugging, unplugging, mousing, mp3 playback, * video capture, and so on.  Run different tests at different times, in * different sequences.  Nothing here should interact with other devices, * except indirectly by consuming USB bandwidth and CPU resources for test * threads and request completion.  But the only way to know that for sure * is to test when HC queues are in use by many devices. */static intusbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf){	struct usbtest_dev	*dev = usb_get_intfdata (intf);	struct usb_device	*udev = testdev_to_usbdev (dev);	struct usbtest_param	*param = buf;	int			retval = -EOPNOTSUPP;	struct urb		*urb;	struct scatterlist	*sg;	struct usb_sg_request	req;	struct timeval		start;	unsigned		i;	// FIXME USBDEVFS_CONNECTINFO doesn't say how fast the device is.	if (code != USBTEST_REQUEST)		return -EOPNOTSUPP;	if (param->iterations <= 0 || param->length < 0			|| param->sglen < 0 || param->vary < 0)		return -EINVAL;	if (down_interruptible (&dev->sem))		return -ERESTARTSYS;	if (intf->dev.power.power_state.event != PM_EVENT_ON) {		up (&dev->sem);		return -EHOSTUNREACH;	}	/* some devices, like ez-usb default devices, need a non-default	 * altsetting to have any active endpoints.  some tests change	 * altsettings; force a default so most tests don't need to check.	 */	if (dev->info->alt >= 0) {	    	int	res;		if (intf->altsetting->desc.bInterfaceNumber) {			up (&dev->sem);			return -ENODEV;		}		res = set_altsetting (dev, dev->info->alt);		if (res) {			dev_err (&intf->dev,					"set altsetting to %d failed, %d\n",					dev->info->alt, res);			up (&dev->sem);			return res;		}	}	/*	 * Just a bunch of test cases that every HCD is expected to handle.	 *	 * Some may need specific firmware, though it'd be good to have	 * one firmware image to handle all the test cases.	 *	 * FIXME add more tests!  cancel requests, verify the data, control	 * queueing, concurrent read+write threads, and so on.	 */	do_gettimeofday (&start);	switch (param->test_num) {	case 0:		dev_dbg (&intf->dev, "TEST 0:  NOP\n");		retval = 0;		break;	/* Simple non-queued bulk I/O tests */	case 1:		if (dev->out_pipe == 0)			break;		dev_dbg (&intf->dev,				"TEST 1:  write %d bytes %u times\n",				param->length, param->iterations);		urb = simple_alloc_urb (udev, dev->out_pipe, param->length);		if (!urb) {			retval = -ENOMEM;			break;		}		// FIRMWARE:  bulk sink (maybe accepts short writes)		retval = simple_io (urb, param->iterations, 0, 0, "test1");		simple_free_urb (urb);		break;	case 2:		if (dev->in_pipe == 0)			break;		dev_dbg (&intf->dev,				"TEST 2:  read %d bytes %u times\n",				param->length, param->iterations);		urb = simple_alloc_urb (udev, dev->in_pipe, param->length);		if (!urb) {			retval = -ENOMEM;			break;		}		// FIRMWARE:  bulk source (maybe generates short writes)		retval = simple_io (urb, param->iterations, 0, 0, "test2");		simple_free_urb (urb);		break;	case 3:		if (dev->out_pipe == 0 || param->vary == 0)			break;		dev_dbg (&intf->dev,				"TEST 3:  write/%d 0..%d bytes %u times\n",				param->vary, param->length, param->iterations);		urb = simple_alloc_urb (udev, dev->out_pipe, param->length);		if (!urb) {			retval = -ENOMEM;			break;		}		// FIRMWARE:  bulk sink (maybe accepts short writes)		retval = simple_io (urb, param->iterations, param->vary,					0, "test3");		simple_free_urb (urb);		break;	case 4:		if (dev->in_pipe == 0 || param->vary == 0)			break;		dev_dbg (&intf->dev,				"TEST 4:  read/%d 0..%d bytes %u times\n",				param->vary, param->length, param->iterations);		urb = simple_alloc_urb (udev, dev->in_pipe, param->length);		if (!urb) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -