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

📄 zero.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	}	return result;}/*-------------------------------------------------------------------------*/static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req){	if (req->status || req->actual != req->length)		DBG ((struct zero_dev *) ep->driver_data,				"setup complete --> %d, %d/%d\n",				req->status, req->actual, req->length);}/* * The setup() callback implements all the ep0 functionality that's * not handled lower down, in hardware or the hardware driver (like * device and endpoint feature flags, and their status).  It's all * housekeeping for the gadget function we're implementing.  Most of * the work is in config-specific setup. */static intzero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl){	struct zero_dev		*dev = get_gadget_data (gadget);	struct usb_request	*req = dev->req;	int			value = -EOPNOTSUPP;	u16			w_index = le16_to_cpu(ctrl->wIndex);	u16			w_value = le16_to_cpu(ctrl->wValue);	u16			w_length = le16_to_cpu(ctrl->wLength);	/* usually this stores reply data in the pre-allocated ep0 buffer,	 * but config change events will reconfigure hardware.	 */	req->zero = 0;	switch (ctrl->bRequest) {	case USB_REQ_GET_DESCRIPTOR:		if (ctrl->bRequestType != USB_DIR_IN)			goto unknown;		switch (w_value >> 8) {		case USB_DT_DEVICE:			value = min (w_length, (u16) sizeof device_desc);			memcpy (req->buf, &device_desc, value);			break;		case USB_DT_DEVICE_QUALIFIER:			if (!gadget_is_dualspeed(gadget))				break;			value = min (w_length, (u16) sizeof dev_qualifier);			memcpy (req->buf, &dev_qualifier, value);			break;		case USB_DT_OTHER_SPEED_CONFIG:			if (!gadget_is_dualspeed(gadget))				break;			// FALLTHROUGH		case USB_DT_CONFIG:			value = config_buf (gadget, req->buf,					w_value >> 8,					w_value & 0xff);			if (value >= 0)				value = min (w_length, (u16) value);			break;		case USB_DT_STRING:			/* wIndex == language code.			 * this driver only handles one language, you can			 * add string tables for other languages, using			 * any UTF-8 characters			 */			value = usb_gadget_get_string (&stringtab,					w_value & 0xff, req->buf);			if (value >= 0)				value = min (w_length, (u16) value);			break;		}		break;	/* currently two configs, two speeds */	case USB_REQ_SET_CONFIGURATION:		if (ctrl->bRequestType != 0)			goto unknown;		if (gadget->a_hnp_support)			DBG (dev, "HNP available\n");		else if (gadget->a_alt_hnp_support)			DBG (dev, "HNP needs a different root port\n");		else			VDBG (dev, "HNP inactive\n");		spin_lock (&dev->lock);		value = zero_set_config(dev, w_value);		spin_unlock (&dev->lock);		break;	case USB_REQ_GET_CONFIGURATION:		if (ctrl->bRequestType != USB_DIR_IN)			goto unknown;		*(u8 *)req->buf = dev->config;		value = min (w_length, (u16) 1);		break;	/* until we add altsetting support, or other interfaces,	 * only 0/0 are possible.  pxa2xx only supports 0/0 (poorly)	 * and already killed pending endpoint I/O.	 */	case USB_REQ_SET_INTERFACE:		if (ctrl->bRequestType != USB_RECIP_INTERFACE)			goto unknown;		spin_lock (&dev->lock);		if (dev->config && w_index == 0 && w_value == 0) {			u8		config = dev->config;			/* resets interface configuration, forgets about			 * previous transaction state (queued bufs, etc)			 * and re-inits endpoint state (toggle etc)			 * no response queued, just zero status == success.			 * if we had more than one interface we couldn't			 * use this "reset the config" shortcut.			 */			zero_reset_config (dev);			zero_set_config(dev, config);			value = 0;		}		spin_unlock (&dev->lock);		break;	case USB_REQ_GET_INTERFACE:		if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))			goto unknown;		if (!dev->config)			break;		if (w_index != 0) {			value = -EDOM;			break;		}		*(u8 *)req->buf = 0;		value = min (w_length, (u16) 1);		break;	/*	 * These are the same vendor-specific requests supported by	 * Intel's USB 2.0 compliance test devices.  We exceed that	 * device spec by allowing multiple-packet requests.	 */	case 0x5b:	/* control WRITE test -- fill the buffer */		if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))			goto unknown;		if (w_value || w_index)			break;		/* just read that many bytes into the buffer */		if (w_length > USB_BUFSIZ)			break;		value = w_length;		break;	case 0x5c:	/* control READ test -- return the buffer */		if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))			goto unknown;		if (w_value || w_index)			break;		/* expect those bytes are still in the buffer; send back */		if (w_length > USB_BUFSIZ				|| w_length != req->length)			break;		value = w_length;		break;	default:unknown:		VDBG (dev,			"unknown control req%02x.%02x v%04x i%04x l%d\n",			ctrl->bRequestType, ctrl->bRequest,			w_value, w_index, w_length);	}	/* respond with data transfer before status phase? */	if (value >= 0) {		req->length = value;		req->zero = value < w_length;		value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);		if (value < 0) {			DBG (dev, "ep_queue --> %d\n", value);			req->status = 0;			zero_setup_complete (gadget->ep0, req);		}	}	/* device either stalls (value < 0) or reports success */	return value;}static voidzero_disconnect (struct usb_gadget *gadget){	struct zero_dev		*dev = get_gadget_data (gadget);	unsigned long		flags;	spin_lock_irqsave (&dev->lock, flags);	zero_reset_config (dev);	/* a more significant application might have some non-usb	 * activities to quiesce here, saving resources like power	 * or pushing the notification up a network stack.	 */	spin_unlock_irqrestore (&dev->lock, flags);	/* next we may get setup() calls to enumerate new connections;	 * or an unbind() during shutdown (including removing module).	 */}static voidzero_autoresume (unsigned long _dev){	struct zero_dev	*dev = (struct zero_dev *) _dev;	int		status;	/* normally the host would be woken up for something	 * more significant than just a timer firing...	 */	if (dev->gadget->speed != USB_SPEED_UNKNOWN) {		status = usb_gadget_wakeup (dev->gadget);		DBG (dev, "wakeup --> %d\n", status);	}}/*-------------------------------------------------------------------------*/static void /* __init_or_exit */zero_unbind (struct usb_gadget *gadget){	struct zero_dev		*dev = get_gadget_data (gadget);	DBG (dev, "unbind\n");	/* we've already been disconnected ... no i/o is active */	if (dev->req) {		dev->req->length = USB_BUFSIZ;		free_ep_req (gadget->ep0, dev->req);	}	del_timer_sync (&dev->resume);	kfree (dev);	set_gadget_data (gadget, NULL);}static int __initzero_bind (struct usb_gadget *gadget){	struct zero_dev		*dev;	struct usb_ep		*ep;	int			gcnum;	/* FIXME this can't yet work right with SH ... it has only	 * one configuration, numbered one.	 */	if (gadget_is_sh(gadget))		return -ENODEV;	/* Bulk-only drivers like this one SHOULD be able to	 * autoconfigure on any sane usb controller driver,	 * but there may also be important quirks to address.	 */	usb_ep_autoconfig_reset (gadget);	ep = usb_ep_autoconfig (gadget, &fs_source_desc);	if (!ep) {autoconf_fail:		printk (KERN_ERR "%s: can't autoconfigure on %s\n",			shortname, gadget->name);		return -ENODEV;	}	EP_IN_NAME = ep->name;	ep->driver_data = ep;	/* claim */	ep = usb_ep_autoconfig (gadget, &fs_sink_desc);	if (!ep)		goto autoconf_fail;	EP_OUT_NAME = ep->name;	ep->driver_data = ep;	/* claim */	gcnum = usb_gadget_controller_number (gadget);	if (gcnum >= 0)		device_desc.bcdDevice = cpu_to_le16 (0x0200 + gcnum);	else {		/* gadget zero is so simple (for now, no altsettings) that		 * it SHOULD NOT have problems with bulk-capable hardware.		 * so warn about unrcognized controllers, don't panic.		 *		 * things like configuration and altsetting numbering		 * can need hardware-specific attention though.		 */		printk (KERN_WARNING "%s: controller '%s' not recognized\n",			shortname, gadget->name);		device_desc.bcdDevice = __constant_cpu_to_le16 (0x9999);	}	/* ok, we made sense of the hardware ... */	dev = kzalloc(sizeof(*dev), GFP_KERNEL);	if (!dev)		return -ENOMEM;	spin_lock_init (&dev->lock);	dev->gadget = gadget;	set_gadget_data (gadget, dev);	/* preallocate control response and buffer */	dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);	if (!dev->req)		goto enomem;	dev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);	if (!dev->req->buf)		goto enomem;	dev->req->complete = zero_setup_complete;	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;	if (gadget_is_dualspeed(gadget)) {		/* assume ep0 uses the same value for both speeds ... */		dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;		/* and that all endpoints are dual-speed */		hs_source_desc.bEndpointAddress =				fs_source_desc.bEndpointAddress;		hs_sink_desc.bEndpointAddress =				fs_sink_desc.bEndpointAddress;	}	if (gadget_is_otg(gadget)) {		otg_descriptor.bmAttributes |= USB_OTG_HNP,		source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;		loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;	}	usb_gadget_set_selfpowered (gadget);	init_timer (&dev->resume);	dev->resume.function = zero_autoresume;	dev->resume.data = (unsigned long) dev;	if (autoresume) {		source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;		loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;	}	gadget->ep0->driver_data = dev;	INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);	INFO (dev, "using %s, OUT %s IN %s\n", gadget->name,		EP_OUT_NAME, EP_IN_NAME);	snprintf (manufacturer, sizeof manufacturer, "%s %s with %s",		init_utsname()->sysname, init_utsname()->release,		gadget->name);	return 0;enomem:	zero_unbind (gadget);	return -ENOMEM;}/*-------------------------------------------------------------------------*/static voidzero_suspend (struct usb_gadget *gadget){	struct zero_dev		*dev = get_gadget_data (gadget);	if (gadget->speed == USB_SPEED_UNKNOWN)		return;	if (autoresume) {		mod_timer (&dev->resume, jiffies + (HZ * autoresume));		DBG (dev, "suspend, wakeup in %d seconds\n", autoresume);	} else		DBG (dev, "suspend\n");}static voidzero_resume (struct usb_gadget *gadget){	struct zero_dev		*dev = get_gadget_data (gadget);	DBG (dev, "resume\n");	del_timer (&dev->resume);}/*-------------------------------------------------------------------------*/static struct usb_gadget_driver zero_driver = {#ifdef CONFIG_USB_GADGET_DUALSPEED	.speed		= USB_SPEED_HIGH,#else	.speed		= USB_SPEED_FULL,#endif	.function	= (char *) longname,	.bind		= zero_bind,	.unbind		= __exit_p(zero_unbind),	.setup		= zero_setup,	.disconnect	= zero_disconnect,	.suspend	= zero_suspend,	.resume		= zero_resume,	.driver		= {		.name		= (char *) shortname,		.owner		= THIS_MODULE,	},};MODULE_AUTHOR("David Brownell");MODULE_LICENSE("GPL");static int __init init (void){	return usb_gadget_register_driver (&zero_driver);}module_init (init);static void __exit cleanup (void){	usb_gadget_unregister_driver (&zero_driver);}module_exit (cleanup);

⌨️ 快捷键说明

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