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

📄 usbtest.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
 * NOTE that since this is a sanity test, it's not examining boundary cases * to see if usbcore, hcd, and device all behave right.  such testing would * involve varied read sizes and other operation sequences. */static int ch9_postconfig (struct usbtest_dev *dev){	struct usb_interface	*iface = dev->intf;	struct usb_device	*udev = interface_to_usbdev (iface);	int			i, alt, retval;	/* [9.2.3] if there's more than one altsetting, we need to be able to	 * set and get each one.  mostly trusts the descriptors from usbcore.	 */	for (i = 0; i < iface->num_altsetting; i++) {		/* 9.2.3 constrains the range here */		alt = iface->altsetting [i].desc.bAlternateSetting;		if (alt < 0 || alt >= iface->num_altsetting) {			dev_dbg (&iface->dev,					"invalid alt [%d].bAltSetting = %d\n",					i, alt);		}		/* [real world] get/set unimplemented if there's only one */		if (realworld && iface->num_altsetting == 1)			continue;		/* [9.4.10] set_interface */		retval = set_altsetting (dev, alt);		if (retval) {			dev_dbg (&iface->dev, "can't set_interface = %d, %d\n",					alt, retval);			return retval;		}		/* [9.4.4] get_interface always works */		retval = get_altsetting (dev);		if (retval != alt) {			dev_dbg (&iface->dev, "get alt should be %d, was %d\n",					alt, retval);			return (retval < 0) ? retval : -EDOM;		}	}	/* [real world] get_config unimplemented if there's only one */	if (!realworld || udev->descriptor.bNumConfigurations != 1) {		int	expected = udev->actconfig->desc.bConfigurationValue;		/* [9.4.2] get_configuration always works		 * ... although some cheap devices (like one TI Hub I've got)		 * won't return config descriptors except before set_config.		 */		retval = usb_control_msg (udev, usb_rcvctrlpipe (udev, 0),				USB_REQ_GET_CONFIGURATION,				USB_DIR_IN | USB_RECIP_DEVICE,				0, 0, dev->buf, 1, USB_CTRL_GET_TIMEOUT);		if (retval != 1 || dev->buf [0] != expected) {			dev_dbg (&iface->dev, "get config --> %d %d (1 %d)\n",				retval, dev->buf[0], expected);			return (retval < 0) ? retval : -EDOM;		}	}	/* 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_dbg (&iface->dev, "dev descriptor --> %d\n", retval);		return (retval < 0) ? retval : -EDOM;	}	/* 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,				dev->buf, TBUF_SIZE);		if (!is_good_config (dev->buf, retval)) {			dev_dbg (&iface->dev,					"config [%d] descriptor --> %d\n",					i, retval);			return (retval < 0) ? retval : -EDOM;		}		// FIXME cross-checking udev->config[i] to make sure usbcore		// parsed it right (etc) would be good testing paranoia	}	/* and sometimes [9.2.6.6] speed dependent descriptors */	if (le16_to_cpu(udev->descriptor.bcdUSB) == 0x0200) {		struct usb_qualifier_descriptor		*d = NULL;		/* device qualifier [9.6.2] */		retval = usb_get_descriptor (udev,				USB_DT_DEVICE_QUALIFIER, 0, dev->buf,				sizeof (struct usb_qualifier_descriptor));		if (retval == -EPIPE) {			if (udev->speed == USB_SPEED_HIGH) {				dev_dbg (&iface->dev,						"hs dev qualifier --> %d\n",						retval);				return (retval < 0) ? retval : -EDOM;			}			/* usb2.0 but not high-speed capable; fine */		} else if (retval != sizeof (struct usb_qualifier_descriptor)) {			dev_dbg (&iface->dev, "dev qualifier --> %d\n", retval);			return (retval < 0) ? retval : -EDOM;		} else			d = (struct usb_qualifier_descriptor *) dev->buf;		/* might not have [9.6.2] any other-speed configs [9.6.4] */		if (d) {			unsigned max = d->bNumConfigurations;			for (i = 0; i < max; i++) {				retval = usb_get_descriptor (udev,					USB_DT_OTHER_SPEED_CONFIG, i,					dev->buf, TBUF_SIZE);				if (!is_good_config (dev->buf, retval)) {					dev_dbg (&iface->dev,						"other speed config --> %d\n",						retval);					return (retval < 0) ? retval : -EDOM;				}			}		}	}	// FIXME fetch strings from at least the device descriptor	/* [9.4.5] get_status always works */	retval = usb_get_status (udev, USB_RECIP_DEVICE, 0, dev->buf);	if (retval != 2) {		dev_dbg (&iface->dev, "get dev status --> %d\n", retval);		return (retval < 0) ? retval : -EDOM;	}	// FIXME configuration.bmAttributes says if we could try to set/clear	// the device's remote wakeup feature ... if we can, test that here	retval = usb_get_status (udev, USB_RECIP_INTERFACE,			iface->altsetting [0].desc.bInterfaceNumber, dev->buf);	if (retval != 2) {		dev_dbg (&iface->dev, "get interface status --> %d\n", retval);		return (retval < 0) ? retval : -EDOM;	}	// FIXME get status for each endpoint in the interface		return 0;}/*-------------------------------------------------------------------------*//* use ch9 requests to test whether: *   (a) queues work for control, keeping N subtests queued and *       active (auto-resubmit) for M loops through the queue. *   (b) protocol stalls (control-only) will autorecover. *       it's not like bulk/intr; no halt clearing. *   (c) short control reads are reported and handled. *   (d) queues are always processed in-order */struct ctrl_ctx {	spinlock_t		lock;	struct usbtest_dev	*dev;	struct completion	complete;	unsigned		count;	unsigned		pending;	int			status;	struct urb		**urb;	struct usbtest_param	*param;	int			last;};#define NUM_SUBCASES	15		/* how many test subcases here? */struct subcase {	struct usb_ctrlrequest	setup;	int			number;	int			expected;};static void ctrl_complete (struct urb *urb, struct pt_regs *regs){	struct ctrl_ctx		*ctx = urb->context;	struct usb_ctrlrequest	*reqp;	struct subcase		*subcase;	int			status = urb->status;	reqp = (struct usb_ctrlrequest *)urb->setup_packet;	subcase = container_of (reqp, struct subcase, setup);	spin_lock (&ctx->lock);	ctx->count--;	ctx->pending--;	/* queue must transfer and complete in fifo order, unless	 * usb_unlink_urb() is used to unlink something not at the	 * physical queue head (not tested).	 */	if (subcase->number > 0) {		if ((subcase->number - ctx->last) != 1) {			dbg ("subcase %d completed out of order, last %d",					subcase->number, ctx->last);			status = -EDOM;			ctx->last = subcase->number;			goto error;		}	}	ctx->last = subcase->number;	/* succeed or fault in only one way? */	if (status == subcase->expected)		status = 0;	/* async unlink for cleanup? */	else if (status != -ECONNRESET) {		/* some faults are allowed, not required */		if (subcase->expected > 0 && (			  ((urb->status == -subcase->expected	/* happened */			   || urb->status == 0))))		/* didn't */			status = 0;		/* sometimes more than one fault is allowed */		else if (subcase->number == 12 && status == -EPIPE)			status = 0;		else			dbg ("subtest %d error, status %d",					subcase->number, status);	}	/* unexpected status codes mean errors; ideally, in hardware */	if (status) {error:		if (ctx->status == 0) {			int		i;			ctx->status = status;			info ("control queue %02x.%02x, err %d, %d left",					reqp->bRequestType, reqp->bRequest,					status, ctx->count);			/* FIXME this "unlink everything" exit route should			 * be a separate test case.			 */			/* unlink whatever's still pending */			for (i = 1; i < ctx->param->sglen; i++) {				struct urb	*u = ctx->urb [	(i + subcase->number) % ctx->param->sglen];				if (u == urb || !u->dev)					continue;				status = usb_unlink_urb (u);				switch (status) {				case -EINPROGRESS:				case -EBUSY:				case -EIDRM:					continue;				default:					dbg ("urb unlink --> %d", status);				}			}			status = ctx->status;		}	}	/* resubmit if we need to, else mark this as done */	if ((status == 0) && (ctx->pending < ctx->count)) {		if ((status = usb_submit_urb (urb, SLAB_ATOMIC)) != 0) {			dbg ("can't resubmit ctrl %02x.%02x, err %d",				reqp->bRequestType, reqp->bRequest, status);			urb->dev = NULL;		} else			ctx->pending++;	} else		urb->dev = NULL;		/* signal completion when nothing's queued */	if (ctx->pending == 0)		complete (&ctx->complete);	spin_unlock (&ctx->lock);}static inttest_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param){	struct usb_device	*udev = testdev_to_usbdev (dev);	struct urb		**urb;	struct ctrl_ctx		context;	int			i;	spin_lock_init (&context.lock);	context.dev = dev;	init_completion (&context.complete);	context.count = param->sglen * param->iterations;	context.pending = 0;	context.status = -ENOMEM;	context.param = param;	context.last = -1;	/* allocate and init the urbs we'll queue.	 * as with bulk/intr sglists, sglen is the queue depth; it also	 * controls which subtests run (more tests than sglen) or rerun.	 */	urb = kmalloc (param->sglen * sizeof (struct urb *), SLAB_KERNEL);	if (!urb)		return -ENOMEM;	memset (urb, 0, param->sglen * sizeof (struct urb *));	for (i = 0; i < param->sglen; i++) {		int			pipe = usb_rcvctrlpipe (udev, 0);		unsigned		len;		struct urb		*u;		struct usb_ctrlrequest	req;		struct subcase		*reqp;		int			expected = 0;		/* requests here are mostly expected to succeed on any		 * device, but some are chosen to trigger protocol stalls		 * or short reads.		 */		memset (&req, 0, sizeof req);		req.bRequest = USB_REQ_GET_DESCRIPTOR;		req.bRequestType = USB_DIR_IN|USB_RECIP_DEVICE;		switch (i % NUM_SUBCASES) {		case 0:		// get device descriptor			req.wValue = cpu_to_le16 (USB_DT_DEVICE << 8);			len = sizeof (struct usb_device_descriptor);			break;		case 1:		// get first config descriptor (only)			req.wValue = cpu_to_le16 ((USB_DT_CONFIG << 8) | 0);			len = sizeof (struct usb_config_descriptor);			break;		case 2:		// get altsetting (OFTEN STALLS)			req.bRequest = USB_REQ_GET_INTERFACE;			req.bRequestType = USB_DIR_IN|USB_RECIP_INTERFACE;			// index = 0 means first interface			len = 1;			expected = EPIPE;			break;		case 3:		// get interface status			req.bRequest = USB_REQ_GET_STATUS;			req.bRequestType = USB_DIR_IN|USB_RECIP_INTERFACE;			// interface 0			len = 2;			break;		case 4:		// get device status			req.bRequest = USB_REQ_GET_STATUS;			req.bRequestType = USB_DIR_IN|USB_RECIP_DEVICE;			len = 2;			break;		case 5:		// get device qualifier (MAY STALL)			req.wValue = cpu_to_le16 (USB_DT_DEVICE_QUALIFIER << 8);			len = sizeof (struct usb_qualifier_descriptor);			if (udev->speed != USB_SPEED_HIGH)				expected = EPIPE;			break;		case 6:		// get first config descriptor, plus interface			req.wValue = cpu_to_le16 ((USB_DT_CONFIG << 8) | 0);			len = sizeof (struct usb_config_descriptor);			len += sizeof (struct usb_interface_descriptor);			break;		case 7:		// get interface descriptor (ALWAYS STALLS)			req.wValue = cpu_to_le16 (USB_DT_INTERFACE << 8);			// interface == 0			len = sizeof (struct usb_interface_descriptor);			expected = EPIPE;			break;		// NOTE: two consecutive stalls in the queue here.		// that tests fault recovery a bit more aggressively.		case 8:		// clear endpoint halt (USUALLY STALLS)			req.bRequest = USB_REQ_CLEAR_FEATURE;			req.bRequestType = USB_RECIP_ENDPOINT;			// wValue 0 == ep halt			// wIndex 0 == ep0 (shouldn't halt!)			len = 0;			pipe = usb_sndctrlpipe (udev, 0);			expected = EPIPE;			break;		case 9:		// get endpoint status			req.bRequest = USB_REQ_GET_STATUS;			req.bRequestType = USB_DIR_IN|USB_RECIP_ENDPOINT;			// endpoint 0			len = 2;			break;		case 10:	// trigger short read (EREMOTEIO)			req.wValue = cpu_to_le16 ((USB_DT_CONFIG << 8) | 0);			len = 1024;			expected = -EREMOTEIO;			break;		// NOTE: two consecutive _different_ faults in the queue.		case 11:	// get endpoint descriptor (ALWAYS STALLS)			req.wValue = cpu_to_le16 (USB_DT_ENDPOINT << 8);			// endpoint == 0			len = sizeof (struct usb_interface_descriptor);			expected = EPIPE;			break;		// NOTE: sometimes even a third fault in the queue!		case 12:	// get string 0 descriptor (MAY STALL)			req.wValue = cpu_to_le16 (USB_DT_STRING << 8);			// string == 0, for language IDs			len = sizeof (struct usb_interface_descriptor);			// may succeed when > 4 languages			expected = EREMOTEIO;	// or EPIPE, if no strings			break;		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;			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;			switch (len) {			case 8:		len = 24; break;			case 16:	len = 32; break;			}			expected = -EREMOTEIO;			break;		default:			err ("bogus number of ctrl queue testcases!");			context.status = -EINVAL;			goto cleanup;		}		req.wLength = cpu_to_le16 (len);		urb [i] = u = simple_alloc_urb (udev, pipe, len);		if (!u)			goto cleanup;		reqp = usb_buffer_alloc (udev, sizeof *reqp, SLAB_KERNEL,				&u->setup_dma);		if (!reqp)			goto cleanup;		reqp->setup = req;		reqp->number = i % NUM_SUBCASES;		reqp->expected = expected;		u->setup_packet = (char *) &reqp->setup;		u->transfer_flags |= URB_NO_SETUP_DMA_MAP;		u->context = &context;		u->complete = ctrl_complete;	}	/* queue the urbs */	context.urb = urb;	spin_lock_irq (&context.lock);	for (i = 0; i < param->sglen; i++) {		context.status = usb_submit_urb (urb [i], SLAB_ATOMIC);		if (context.status != 0) {			dbg ("can't submit urb[%d], status %d",					i, context.status);			context.count = context.pending;			break;		}		context.pending++;	}	spin_unlock_irq (&context.lock);	/* FIXME  set timer and time out; provide a disconnect hook */	/* wait for the last one to complete */	if (context.pending > 0)		wait_for_completion (&context.complete);cleanup:	for (i = 0; i < param->sglen; i++) {		if (!urb [i])			continue;		urb [i]->dev = udev;		if (urb [i]->setup_packet)			usb_buffer_free (udev, sizeof (struct usb_ctrlrequest),					urb [i]->setup_packet,					urb [i]->setup_dma);		simple_free_urb (urb [i]);	}	kfree (urb);	return context.status;}#undef NUM_SUBCASES/*-------------------------------------------------------------------------*/static void unlink1_callback (struct urb *urb, struct pt_regs *regs){	int	status = urb->status;	// we "know" -EPIPE (stall) never happens	if (!status)		status = usb_submit_urb (urb, SLAB_ATOMIC);	if (status) {		urb->status = status;		complete ((struct completion *) urb->context);	}}static int unlink1 (struct usbtest_dev *dev, int pipe, int size, int async){	struct urb		*urb;	struct completion	completion;	int			retval = 0;	init_completion (&completion);	urb = simple_alloc_urb (testdev_to_usbdev (dev), pipe, size);	if (!urb)		return -ENOMEM;	urb->context = &completion;	urb->complete = unlink1_callback;	/* keep the endpoint busy.  there are lots of hc/hcd-internal	 * states, and testing should get to all of them over time.	 *	 * FIXME want additional tests for when endpoint is STALLing	 * due to errors, or is just NAKing requests.	 */	if ((retval = usb_submit_urb (urb, SLAB_KERNEL)) != 0) {		dev_dbg (&dev->intf->dev, "submit fail %d\n", retval);		return retval;	}	/* unlinking that should always work.  variable delay tests more	 * hcd states and code paths, even with little other system load.	 */	msleep (jiffies % (2 * INTERRUPT_RATE));	if (async) {retry:		retval = usb_unlink_urb (urb);		if (retval == -EBUSY || retval == -EIDRM) {			/* we can't unlink urbs while they're completing.			 * or if they've completed, and we haven't resubmitted.			 * "normal" drivers would prevent resubmission, but			 * since we're testing unlink paths, we can't.			 */			dev_dbg (&dev->intf->dev, "unlink retry\n");			goto retry;		}	} else		usb_kill_urb (urb);	if (!(retval == 0 || retval == -EINPROGRESS)) {		dev_dbg (&dev->intf->dev, "unlink fail %d\n", retval);		return retval;	}

⌨️ 快捷键说明

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