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

📄 inode.c

📁 LINUX2.4.18内核下的usb GADGET驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
			value = min (ctrl->wLength, (u16) sizeof *dev->dev);			req->buf = dev->dev;			break;#ifdef	HIGHSPEED		case USB_DT_DEVICE_QUALIFIER:			if (!dev->hs_config)				break;			value = min (ctrl->wLength, (u16)				sizeof (struct usb_qualifier_descriptor));			make_qualifier (dev);			break;		case USB_DT_OTHER_SPEED_CONFIG:			// FALLTHROUGH#endif		case USB_DT_CONFIG:			value = config_buf (dev,					ctrl->wValue >> 8,					ctrl->wValue & 0xff);			if (value >= 0)				value = min (ctrl->wLength, (u16) value);			break;		case USB_DT_STRING:			goto unrecognized;		default:		// all others are errors			break;		}		break;	/* currently one config, two speeds */	case USB_REQ_SET_CONFIGURATION:		if (ctrl->bRequestType != 0)			break;		if (0 == (u8) ctrl->wValue) {			value = 0;			dev->current_config = 0;			// user mode expected to disable endpoints		} else {			u8	config;#ifdef	HIGHSPEED			if (gadget->speed == USB_SPEED_HIGH)				config = dev->hs_config->bConfigurationValue;			else#endif				config = dev->config->bConfigurationValue;			if (config == (u8) ctrl->wValue) {				value = 0;				dev->current_config = config;			}		}		/* report SET_CONFIGURATION like any other control request,		 * except that usermode may not stall this.  the next		 * request mustn't be allowed start until this finishes:		 * endpoints and threads set up, etc.		 *		 * NOTE:  older PXA hardware (before PXA 255: without UDCCFR)		 * has bad/racey automagic that prevents synchronizing here.		 * even kernel mode drivers often miss them.		 */		if (value == 0) {			INFO (dev, "configuration #%d\n", dev->current_config);			if (dev->usermode_setup) {				dev->setup_can_stall = 0;				goto delegate;			}		}		break;#ifndef	CONFIG_USB_GADGETFS_PXA2XX	/* PXA automagically handles this request too */	case USB_REQ_GET_CONFIGURATION:		if (ctrl->bRequestType != 0x80)			break;		*(u8 *)req->buf = dev->current_config;		value = min (ctrl->wLength, (u16) 1);		break;#endif	default:unrecognized:		VDEBUG (dev, "%s req%02x.%02x v%04x i%04x l%d\n",			dev->usermode_setup ? "delegate" : "fail",			ctrl->bRequestType, ctrl->bRequest,			ctrl->wValue, ctrl->wIndex, ctrl->wLength);		/* if there's an ep0 reader, don't stall */		if (dev->usermode_setup) {			dev->setup_can_stall = 1;delegate:			dev->setup_in = (ctrl->bRequestType & USB_DIR_IN)						? 1 : 0;			dev->setup_out_ready = 0;			dev->setup_out_error = 0;			value = 0;			/* read DATA stage for OUT right away */			if (unlikely (!dev->setup_in && ctrl->wLength)) {				value = setup_req (gadget->ep0, dev->req,							ctrl->wLength);				if (value < 0)					break;				value = usb_ep_queue (gadget->ep0, dev->req,							GFP_ATOMIC);				if (value < 0) {					clean_req (gadget->ep0, dev->req);					break;				}				/* we can't currently stall these */				dev->setup_can_stall = 0;			}			/* state changes when reader collects event */			event = next_event (dev, GADGETFS_SETUP);			event->u.setup = *ctrl;			ep0_readable (dev);			spin_unlock (&dev->lock);			return 0;		}	}	/* proceed with data transfer and status phases? */	if (value >= 0 && dev->state != STATE_SETUP) {		req->length = value;		value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);		if (value < 0) {			DBG (dev, "ep_queue --> %d\n", value);			req->status = 0;		}	}	/* device stalls when value < 0 */	spin_unlock (&dev->lock);	return value;}static void destroy_ep_files (struct dev_data *dev){	struct list_head	*entry, *tmp;	DBG (dev, "%s %d\n", __FUNCTION__, dev->state);	/* dev->state must prevent interference */restart:	spin_lock_irq (&dev->lock);	list_for_each_safe (entry, tmp, &dev->epfiles) {		struct ep_data	*ep;		/* break link to FS */		ep = list_entry (entry, struct ep_data, epfiles);		list_del_init (&ep->epfiles);		/* break link to controller */		if (ep->state == STATE_EP_ENABLED)			(void) usb_ep_disable (ep->ep);		ep->state = STATE_EP_UNBOUND;		usb_ep_free_request (ep->ep, ep->req);		ep->ep = 0;		wake_up (&ep->wait);		put_ep (ep);		spin_unlock_irq (&dev->lock);		/* fds may still be open */		goto restart;	}	spin_unlock_irq (&dev->lock);}static int activate_ep_files (struct dev_data *dev){	struct usb_ep	*ep;	gadget_for_each_ep (ep, dev->gadget) {		struct ep_data	*data;		data = kmalloc (sizeof *data, GFP_KERNEL);		if (!data)			goto enomem;		memset (data, 0, sizeof data);		data->state = STATE_EP_DISABLED;		init_MUTEX (&data->lock);		init_waitqueue_head (&data->wait);		strncpy (data->name, ep->name, sizeof (data->name) - 1);		atomic_set (&data->count, 1);		data->dev = dev;		get_dev (dev);		data->ep = ep;		ep->driver_data = data;		data->req = usb_ep_alloc_request (ep, GFP_KERNEL);		if (!data->req)			goto enomem;		list_add_tail (&data->epfiles, &dev->epfiles);	}	return 0;enomem:	DBG (dev, "%s enomem\n", __FUNCTION__);	destroy_ep_files (dev);	return -ENOMEM;}static voidgadgetfs_unbind (struct usb_gadget *gadget){	struct dev_data		*dev = get_gadget_data (gadget);	DBG (dev, "%s\n", __FUNCTION__);	spin_lock_irq (&dev->lock);	dev->state = STATE_DEV_UNBOUND;	spin_unlock_irq (&dev->lock);	destroy_ep_files (dev);	gadget->ep0->driver_data = 0;	set_gadget_data (gadget, 0);	/* we've already been disconnected ... no i/o is active */	if (dev->req)		usb_ep_free_request (gadget->ep0, dev->req);	DBG (dev, "%s done\n", __FUNCTION__);	put_dev (dev);}static struct dev_data		*the_device;static intgadgetfs_bind (struct usb_gadget *gadget){	struct dev_data		*dev = the_device;	if (!dev)		return -ESRCH;	if (0 != strcmp (CHIP, gadget->name)) {		printk (KERN_ERR "%s expected " CHIP " controller not %s\n",			shortname, gadget->name);		return -ENODEV;	}	set_gadget_data (gadget, dev);	dev->gadget = gadget;	gadget->ep0->driver_data = dev;	dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;	/* preallocate control response and buffer */	dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);	if (!dev->req)		goto enomem;	dev->req->context = 0;	dev->req->complete = epio_complete;	if (activate_ep_files (dev) < 0)		goto enomem;	INFO (dev, "bound to %s driver\n", gadget->name);	dev->state = STATE_UNCONNECTED;	get_dev (dev);	return 0;enomem:	gadgetfs_unbind (gadget);	return -ENOMEM;}static voidgadgetfs_disconnect (struct usb_gadget *gadget){	struct dev_data		*dev = get_gadget_data (gadget);	if (dev->state == STATE_UNCONNECTED) {		DBG (dev, "already unconnected\n");		return;	}	dev->state = STATE_UNCONNECTED;	INFO (dev, "disconnected\n");	spin_lock (&dev->lock);	next_event (dev, GADGETFS_DISCONNECT);	ep0_readable (dev);	spin_unlock (&dev->lock);}static voidgadgetfs_suspend (struct usb_gadget *gadget){	struct dev_data		*dev = get_gadget_data (gadget);	INFO (dev, "suspended from state %d\n", dev->state);	spin_lock (&dev->lock);	switch (dev->state) {	case STATE_SETUP:		// VERY odd... host died??	case STATE_CONNECTED:	case STATE_UNCONNECTED:		next_event (dev, GADGETFS_SUSPEND);		ep0_readable (dev);		/* FALLTHROUGH */	default:		break;	}	spin_unlock (&dev->lock);}static struct usb_gadget_driver gadgetfs_driver = {#ifdef	HIGHSPEED	.speed		= USB_SPEED_HIGH,#else	.speed		= USB_SPEED_FULL,#endif	.function	= (char *) driver_desc,	.bind		= gadgetfs_bind,	.unbind		= gadgetfs_unbind,	.setup		= gadgetfs_setup,	.disconnect	= gadgetfs_disconnect,	.suspend	= gadgetfs_suspend,	.driver 	= {		.name		= (char *) shortname,		// .shutdown = ...		// .suspend = ...		// .resume = ...	},};/*----------------------------------------------------------------------*//* DEVICE INITIALIZATION * *     fd = open ("/dev/gadget/$CHIP", O_RDWR) *     status = write (fd, descriptors, sizeof descriptors) * * That write establishes the device configuration, so the kernel can * bind to the controller ... guaranteeing it can handle enumeration * at all necessary speeds.  Descriptor order is: * * . message tag (u32, host order) ... for now, must be zero; it *	would change to support features like multi-config devices * . full/low speed config ... all wTotalLength bytes (with interface, *	class, altsetting, endpoint, and other descriptors) * . high speed config ... all descriptors, for high speed operation; * 	this one's optional except for high-speed hardware * . device descriptor * * Endpoints are not yet enabled. Drivers may want to immediately * initialize them, using the /dev/gadget/ep* files that are available * as soon as the kernel sees the configuration, or they can wait * until device configuration and interface altsetting changes create * the need to configure (or unconfigure) them. * * After initialization, the device stays active for as long as that * $CHIP file is open.  Events may then be read from that descriptor, * such configuration notifications.  More complex drivers will handle * some control requests in user space. */static int is_valid_config (struct usb_config_descriptor *config){	return config->bDescriptorType == USB_DT_CONFIG		&& config->bLength == USB_DT_CONFIG_SIZE		&& config->bConfigurationValue != 0		&& (config->bmAttributes & USB_CONFIG_ATT_ONE) != 0		&& (config->bmAttributes & USB_CONFIG_ATT_WAKEUP) == 0;	/* FIXME check lengths: walk to end */}static ssize_tdev_config (struct file *fd, const char *buf, size_t len, loff_t *ptr){	struct dev_data		*dev = fd->private_data;	ssize_t			value = len, length = len;	unsigned		total;	u32			tag;	char			*kbuf;	if (dev->state != STATE_OPENED)		return -EEXIST;	if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4))		return -EINVAL;	/* we might need to change message format someday */	if (copy_from_user (&tag, buf, 4))		return -EFAULT;	if (tag != 0)		return -EINVAL;	buf += 4;	length -= 4;	kbuf = kmalloc (length, SLAB_KERNEL);	if (!kbuf)		return -ENOMEM;	if (copy_from_user (kbuf, buf, length)) {		kfree (kbuf);		return -EFAULT;	}	spin_lock_irq (&dev->lock);	value = -EINVAL;	if (dev->buf)		goto fail;	dev->buf = kbuf;	/* full or low speed config */	dev->config = (void *) kbuf;	total = le16_to_cpup (&dev->config->wTotalLength);	if (!is_valid_config (dev->config) || total >= length)		goto fail;	kbuf += total;	length -= total;	/* optional high speed config */	if (kbuf [1] == USB_DT_CONFIG) {		dev->hs_config = (void *) kbuf;		total = le16_to_cpup (&dev->hs_config->wTotalLength);		if (!is_valid_config (dev->hs_config) || total >= length)			goto fail;		kbuf += total;		length -= total;	}	/* could support multiple configs, using another encoding! */	/* device descriptor (tweaked for paranoia) */	if (length != USB_DT_DEVICE_SIZE)		goto fail;	dev->dev = (void *)kbuf;	if (dev->dev->bLength != USB_DT_DEVICE_SIZE			|| dev->dev->bDescriptorType != USB_DT_DEVICE			|| dev->dev->bNumConfigurations != 1)		goto fail;	dev->dev->bNumConfigurations = 1;	dev->dev->bcdUSB = __constant_cpu_to_le16 (0x0200);	/* triggers gadgetfs_bind(); then we can enumerate. */	spin_unlock_irq (&dev->lock);	value = usb_gadget_register_driver (&gadgetfs_driver);	if (value != 0) {		kfree (dev->buf);		dev->buf = 0;	} else {		/* at this point "good" hardware has for the first time		 * let the USB the host see us.  alternatively, if users		 * unplug/replug that will clear all the error state.		 *		 * note:  everything running before here was guaranteed		 * to choke driver model style diagnostics.  from here		 * on, they can work ... except in cleanup paths that		 * kick in after the ep0 descriptor is closed.		 */		fd->f_op = &ep0_io_operations;		value = len;	}	return value;fail:	spin_unlock_irq (&dev->lock);	pr_debug ("%s: %s fail %d, %p\n", shortname, __FUNCTION__, value, dev);	kfree (dev->buf);	dev->buf = 0;	return value;}static intdev_open (struct inode *inode, struct file *fd){	struct dev_data		*dev = inode->u.generic_ip;	int			value = -EBUSY;	if (dev->state == STATE_DEV_DISABLED) {		dev->ev_next = 0;		dev->state = STATE_OPENED;		fd->private_data = dev;		get_dev (dev);		value = 0;	}	return value;}static struct file_operations dev_init_operations = {	.owner =	THIS_MODULE,	.open =		dev_open,	.write =	dev_config,	.fasync =	ep0_fasync,	.ioctl =	dev_ioctl,	.release =	dev_release,};/*----------------------------------------------------------------------*//* * implementation for 2.4 uses character special files *  ep0/device file	MKDEV (c_major, 0) *  first data ep	MKDEV (c_major, 1) *  second data ep	MKDEV (c_major, 2) *  ... * *  FIXME can do it as a real filesystem on 2.4 too, without libfs */static int c_major = 240;	/* 240 is local/experimental */MODULE_PARM (c_major, "i");MODULE_PARM_DESC (c_major, "major number for char special files");static int gadget_open (struct inode *ino, struct file *fp){	int			num = minor (ino->i_rdev);	struct dev_data		*dev;	struct file_operations	*ops;	/* ep0 file, "/dev/gadget/$CHIP" */	if (num == 0) {		int		status;		if (the_device != 0)			return -EBUSY;		the_device = dev_new ();		if (the_device == 0)			return -ENOMEM;		dev = the_device;		ino->u.generic_ip = dev;		ops = &dev_init_operations;		fp->f_op = ops;		status = ops->open (ino, fp);		if (status < 0) {			put_dev (dev);			the_device = 0;		}		return status;	/* ep files, "/dev/gadget/$ENDPOINT" */	} else {		struct list_head	*entry;		struct ep_data		*data;		/* unavailable till device is initted */		dev = the_device;		if (dev == 0)			return -ENODEV;		/* order in controller's name listing matters! */		list_for_each (entry, &dev->epfiles) {			if (--num == 0)				goto found;		}		return -ENODEV;found:		data = list_entry (entry, struct ep_data, epfiles);		ino->u.generic_ip = data;		ops = &ep_config_operations;		fp->f_op = ops;		return ops->open (ino, fp);	}}static struct file_operations gadget_fops = {	.owner =	THIS_MODULE,	.open =		gadget_open,};/*----------------------------------------------------------------------*/static int __init init (void){	int status;	status = register_chrdev (c_major, shortname, &gadget_fops);	if (status < 0) {		printk (KERN_WARNING "%s: can't get major %d\n",			shortname, c_major);		return status;	}	/* dynamic assignment */	if (c_major == 0)		c_major = status;	status = 0;	pr_info ("%s: using char major %d\n", shortname, c_major);	if (status == 0)		pr_info ("%s: %s, version " DRIVER_VERSION "\n",			shortname, driver_desc);	return status;}module_init (init);static void __exit cleanup (void){	pr_debug ("unregister %s\n", shortname);	unregister_chrdev (c_major, shortname);}module_exit (cleanup);

⌨️ 快捷键说明

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