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

📄 scanner.c

📁 Linux2.6系统下USB2.0gadget扫描仪驱动器
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * printer.c -- Printer gadget driver * * Copyright (C) 2003-2005 David Brownell * Copyright (C) 2006 Craig W. Nadler * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA *///#define GS_DEBUG 1#define VERBOSE 1#include <linux/module.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/smp_lock.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/timer.h>#include <linux/list.h>#include <linux/interrupt.h>#include <linux/utsname.h>#include <linux/device.h>#include <linux/moduleparam.h>#include <linux/fs.h>#include <linux/poll.h>#include <linux/types.h>#include <linux/ctype.h>#include <linux/cdev.h>#include <asm/byteorder.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/uaccess.h>#include <asm/unaligned.h>#include <linux/usb/ch9.h>#include <linux/usb_gadget.h>#include "gadget_chips.h"//#define S_IRUGO	0x444#define PRINTER_NOT_ERROR	0x08#define PRINTER_SELECTED	0x10#define PRINTER_PAPER_EMPTY	0x20#define DRIVER_DESC		"Hewlett-Packard ScanJet 2100C"	//"Printer Gadget"#define DRIVER_VERSION		"0.2.0 06/04/2007"#define GADGET_GET_PRINTER_STATUS	_IOR('P', 1, unsigned char)#define GADGET_SET_PRINTER_STATUS	_IOWR('P', 2, unsigned char)static const char shortname [] = "g_scanner";static const char driver_desc [] = DRIVER_DESC;static dev_t g_printer_devno;static struct class *usb_gadget_class;/*-------------------------------------------------------------------------*/struct printer_dev {	spinlock_t		lock;	spinlock_t		lock_printer_io;	struct usb_gadget	*gadget;	struct usb_request	req_copy;	struct usb_request	*req;		/* for control responses */	u8			config;	s8			interface;	struct usb_ep		*in_ep, *out_ep;	const struct usb_endpoint_descriptor				*in, *out;	struct list_head	rx_reqs;	struct list_head	rx_reqs_active;	struct list_head	rx_buffers;	/* wait until there is data to be read. */	wait_queue_head_t	rx_wait;	struct list_head	tx_reqs;	struct list_head	tx_reqs_active;	/* Wait until there are write buffers available to use. */	wait_queue_head_t	tx_wait;	/* Wait until all write buffers have been sent. */	wait_queue_head_t	tx_flush_wait;	struct usb_request	*current_rx_req;	size_t			current_rx_bytes;	u8			*current_rx_buf;	u8 			printer_status;	u8			reset_printer;	unsigned		zlp:1;	unsigned		suspended:1;	struct class_device	*printer_class_dev;	struct cdev		printer_cdev;	struct device		*pdev;	u8			printer_cdev_open;	wait_queue_head_t	wait;};static struct printer_dev usb_printer_gadget;/*-------------------------------------------------------------------------*//* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!! * Instead:  allocate your own, using normal USB-IF procedures. *//* Thanks to NetChip Technologies for donating this product ID. */#define PRINTER_VENDOR_NUM	0x03f0	//0x0525		/* NetChip */#define PRINTER_PRODUCT_NUM	0x0505	//0xa4a8		/* Linux-USB Printer Gadget *//* Some systems will want different product identifers published in the * device descriptor, either numbers or strings or both.  These string * parameters are in UTF-8 (superset of ASCII's 7 bit characters). */static ushort __initdata idVendor;module_param(idVendor, ushort, S_IRUGO);MODULE_PARM_DESC(idVendor, "USB Vendor ID");static ushort __initdata idProduct;module_param(idProduct, ushort, S_IRUGO);MODULE_PARM_DESC(idProduct, "USB Product ID");static ushort __initdata bcdDevice;module_param(bcdDevice, ushort, S_IRUGO);MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");static char *__initdata iManufacturer;module_param(iManufacturer, charp, S_IRUGO);MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");static char *__initdata iProduct;module_param(iProduct, charp, S_IRUGO);MODULE_PARM_DESC(iProduct, "USB Product string");static char *__initdata iSerialNum;module_param(iSerialNum, charp, S_IRUGO);MODULE_PARM_DESC(iSerialNum, "1");static char *__initdata iPNPstring;module_param(iPNPstring, charp, S_IRUGO);MODULE_PARM_DESC(iPNPstring, "MFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;");/* Number of requests to allocate per endpoint, not used for ep0. */static unsigned qlen = 10;module_param (qlen, uint, S_IRUGO|S_IWUSR);#define QLEN	qlen#ifdef CONFIG_USB_GADGET_DUALSPEED#define DEVSPEED	USB_SPEED_HIGH#else   /* full speed (low speed doesn't do bulk) */#define DEVSPEED        USB_SPEED_FULL#endif/*-------------------------------------------------------------------------*/#define xprintk(d,level,fmt,args...) \	printk(level "%s: " fmt , DRIVER_DESC , ## args)#ifdef DEBUG//#undef DEBUG#define DBG(dev,fmt,args...) \	xprintk(dev , KERN_DEBUG , fmt , ## args)#else#define DBG(dev,fmt,args...) \	do { } while (0)#endif /* DEBUG */#ifdef VERBOSE#define VDBG(dev,fmt,args...) \	xprintk(dev , KERN_DEBUG , fmt , ## args)#else#define VDBG(dev,fmt,args...) \	xprintk(dev , KERN_DEBUG , fmt , ## args)#endif /* DEBUG */#define ERROR(dev,fmt,args...) \	xprintk(dev , KERN_ERR , fmt , ## args)#define WARN(dev,fmt,args...) \	xprintk(dev , KERN_WARNING , fmt , ## args)#define INFO(dev,fmt,args...) \	xprintk(dev , KERN_INFO , fmt , ## args)/*-------------------------------------------------------------------------*//* USB DRIVER HOOKUP (to the hardware driver, below us), mostly * ep0 implementation:  descriptors, config management, setup(). * also optional class-specific notification interrupt transfer. *//* * DESCRIPTORS ... most are static, but strings and (full) configuration * descriptors are built on demand. */#define STRING_MANUFACTURER		1#define STRING_PRODUCT			2#define STRING_SERIALNUM		3/* holds our biggest descriptor */#define USB_DESC_BUFSIZE		256#define USB_BUFSIZE			8192/* This device advertises one configuration. */#define DEV_CONFIG_VALUE		1#define	PRINTER_INTERFACE		0static struct usb_device_descriptor device_desc = {	.bLength =		sizeof device_desc,	.bDescriptorType =	USB_DT_DEVICE,	.bcdUSB =		__constant_cpu_to_le16 (0x0200),	.bDeviceClass =		USB_CLASS_PER_INTERFACE,	.bDeviceSubClass =	0,	.bDeviceProtocol =	0,	.idVendor =		__constant_cpu_to_le16 (PRINTER_VENDOR_NUM),	.idProduct =		__constant_cpu_to_le16 (PRINTER_PRODUCT_NUM),	.iManufacturer =	STRING_MANUFACTURER,	.iProduct =		STRING_PRODUCT,	.iSerialNumber =	STRING_SERIALNUM,	.bNumConfigurations =	1};static struct usb_otg_descriptor otg_desc = {	.bLength =		sizeof otg_desc,	.bDescriptorType =	USB_DT_OTG,	.bmAttributes =		USB_OTG_SRP};static struct usb_config_descriptor config_desc = {	.bLength =		sizeof config_desc,	.bDescriptorType =	USB_DT_CONFIG,	/* compute wTotalLength on the fly */	.bNumInterfaces =	1,	.bConfigurationValue =	DEV_CONFIG_VALUE,	.iConfiguration =	0,	.bmAttributes =		USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,	.bMaxPower =		1	/* Self-Powered */};static struct usb_interface_descriptor intf_desc = {	.bLength =		sizeof intf_desc,	.bDescriptorType =	USB_DT_INTERFACE,	.bInterfaceNumber =	PRINTER_INTERFACE,	.bNumEndpoints =	3,	.bInterfaceClass =	USB_CLASS_VENDOR_SPEC,	.bInterfaceSubClass =	0,	/* Printer Sub-Class */	.bInterfaceProtocol =	0xff,	/* Ventor */	.iInterface =		0};static struct usb_endpoint_descriptor fs_ep_in_desc = {	.bLength =		USB_DT_ENDPOINT_SIZE,	.bDescriptorType =	USB_DT_ENDPOINT,	.bEndpointAddress =	USB_DIR_IN,	.bmAttributes =		USB_ENDPOINT_XFER_BULK};static struct usb_endpoint_descriptor fs_ep_out_desc = {	.bLength =		USB_DT_ENDPOINT_SIZE,	.bDescriptorType =	USB_DT_ENDPOINT,	.bEndpointAddress =	USB_DIR_OUT,	.bmAttributes =		USB_ENDPOINT_XFER_BULK};static struct usb_endpoint_descriptor fs_ep_int_in_desc = {
	.bLength =		USB_DT_ENDPOINT_SIZE,
	.bDescriptorType =	USB_DT_ENDPOINT,
	.bEndpointAddress =	USB_DIR_IN,
	.bmAttributes =		USB_ENDPOINT_XFER_INT,
	.wMaxPacketSize = __constant_cpu_to_le16(1),
	.bInterval = 0x10
};
static const struct usb_descriptor_header *fs_printer_function [11] = {	(struct usb_descriptor_header *) &otg_desc,	(struct usb_descriptor_header *) &intf_desc,	(struct usb_descriptor_header *) &fs_ep_in_desc,	(struct usb_descriptor_header *) &fs_ep_out_desc,	(struct usb_descriptor_header *) &fs_ep_int_in_desc,
	NULL};#ifdef	CONFIG_USB_GADGET_DUALSPEED/* * usb 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. */static struct usb_endpoint_descriptor hs_ep_in_desc = {	.bLength =		USB_DT_ENDPOINT_SIZE,	.bDescriptorType =	USB_DT_ENDPOINT,	.bmAttributes =		USB_ENDPOINT_XFER_BULK,	.wMaxPacketSize =	__constant_cpu_to_le16 (512)};static struct usb_endpoint_descriptor hs_ep_out_desc = {	.bLength =		USB_DT_ENDPOINT_SIZE,	.bDescriptorType =	USB_DT_ENDPOINT,	.bmAttributes =		USB_ENDPOINT_XFER_BULK,	.wMaxPacketSize =	__constant_cpu_to_le16 (512)};static struct usb_endpoint_descriptor hs_ep_int_in_desc = {
	.bLength =		USB_DT_ENDPOINT_SIZE,
	.bDescriptorType =	USB_DT_ENDPOINT,
	.bmAttributes =		USB_ENDPOINT_XFER_INT,
	.wMaxPacketSize =	__constant_cpu_to_le16 (1)
};

static struct usb_qualifier_descriptor dev_qualifier = {	.bLength =		sizeof dev_qualifier,	.bDescriptorType =	USB_DT_DEVICE_QUALIFIER,	.bcdUSB =		__constant_cpu_to_le16 (0x0200),	.bDeviceClass =		USB_CLASS_PRINTER,	.bNumConfigurations =	1};static const struct usb_descriptor_header *hs_printer_function [11] = {	(struct usb_descriptor_header *) &otg_desc,	(struct usb_descriptor_header *) &intf_desc,	(struct usb_descriptor_header *) &hs_ep_in_desc,	(struct usb_descriptor_header *) &hs_ep_out_desc,	(struct usb_descriptor_header *) &hs_ep_int_in_desc,
	NULL};/* maxpacket and other transfer characteristics vary by speed. */#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))#else/* if there's no high speed support, maxpacket doesn't change. */#define ep_desc(g,hs,fs) (((void)(g)), (fs))#endif	/* !CONFIG_USB_GADGET_DUALSPEED */							     /*-------------------------------------------------------------------------*//* descriptors that are built on-demand */static char				manufacturer [50];static char				product_desc [40] = DRIVER_DESC;static char				serial_num [40] = "1";static char				pnp_string [1024] =	"XXMFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;";/* static strings, in UTF-8 */static struct usb_string		strings [] = {	{ STRING_MANUFACTURER,	manufacturer, },	{ STRING_PRODUCT,	product_desc, },	{ STRING_SERIALNUM,	serial_num, },	{  }		/* end of list */};static struct usb_gadget_strings	stringtab = {	.language	= 0x0409,	/* en-us */	.strings	= strings,};/*-------------------------------------------------------------------------*/static struct usb_request *printer_req_alloc (struct usb_ep *ep, unsigned size, gfp_t gfp_flags){	struct usb_request	*req;	req = usb_ep_alloc_request (ep, gfp_flags);	if (!req)		return NULL;	req->buf = kmalloc(size,GFP_KERNEL);	//req->buf = usb_ep_alloc_buffer (ep, size, &req->dma, gfp_flags);	if (!req->buf) {		usb_ep_free_request (ep, req);		req = NULL;	}	req->length = size;		return req;}static voidprinter_req_free (struct usb_ep *ep, struct usb_request *req){	kfree(req->buf);	//usb_ep_free_buffer (ep, req->buf, req->dma, req->length);	usb_ep_free_request (ep, req);}/*-------------------------------------------------------------------------*/static void rx_complete (struct usb_ep *ep, struct usb_request *req){	struct printer_dev	*dev = ep->driver_data;	int			status = req->status;	unsigned long		flags;	spin_lock_irqsave (&dev->lock, flags);		list_del_init (&req->list);	/* Remode from Active List */	switch (status) {	/* normal completion */	case 0:		list_add_tail (&req->list, &dev->rx_buffers);		wake_up_interruptible(&dev->rx_wait);		DBG(dev, "G_Printer : rx length %d\n", req->actual);		break;	/* software-driven interface shutdown */	case -ECONNRESET:		// unlink	case -ESHUTDOWN:		// disconnect etc		VDBG(dev, "rx shutdown, code %d\n", status);		list_add (&req->list, &dev->rx_reqs);		break;	/* for hardware automagic (such as pxa) */	case -ECONNABORTED:		// endpoint reset		DBG(dev, "rx %s reset\n", ep->name);		list_add (&req->list, &dev->rx_reqs);		break;	/* data overrun */	case -EOVERFLOW:		// FALLTHROUGH	    	default:		DBG(dev, "rx status %d\n", status);		list_add (&req->list, &dev->rx_reqs);		break;	}	spin_unlock_irqrestore (&dev->lock, flags);}static void tx_complete (struct usb_ep *ep, struct usb_request *req){	struct printer_dev	*dev = ep->driver_data;	switch (req->status) {	default:		VDBG(dev, "tx err %d\n", req->status);		/* FALLTHROUGH */	case -ECONNRESET:		// unlink	case -ESHUTDOWN:		// disconnect etc		break;	case 0:		break;	}	spin_lock (&dev->lock);	/* Take the request struct off the active list and put it on the	 * free list.	 */	list_del_init (&req->list);	list_add (&req->list, &dev->tx_reqs);	wake_up_interruptible(&dev->tx_wait);	if (likely (list_empty (&dev->tx_reqs_active))) {		wake_up_interruptible(&dev->tx_flush_wait);	}	spin_unlock (&dev->lock);}/*-------------------------------------------------------------------------*/static intprinter_open (struct inode *inode, struct file *fd){	struct printer_dev	*dev;	unsigned long		flags;	int			ret = -EBUSY;	dev = container_of (inode->i_cdev, struct printer_dev, printer_cdev);	if (dev == NULL) {		printk(KERN_ERR "printer_open: NULL device pointer\n");		return -EIO;	}	spin_lock_irqsave (&dev->lock, flags);	if (!dev->printer_cdev_open) {		dev->printer_cdev_open = 1;		fd->private_data = dev;		ret = 0;	}	/* Change printer status to show that the printer is on-line. */	dev->printer_status |= PRINTER_SELECTED;	spin_unlock_irqrestore (&dev->lock, flags);	DBG(dev, "printer_open returned %x\n", ret);	printk(KERN_INFO "printer_open: returned %x\n", ret);	return ret;}static intprinter_close (struct inode *inode, struct file *fd){	struct printer_dev *dev;	unsigned long		flags;	dev = container_of (inode->i_cdev, struct printer_dev, printer_cdev);	if (dev == NULL) {		printk(KERN_ERR "printer_close: NULL device pointer\n");		return -EIO;	}	/* Change printer status to show that the printer is off-line. */	dev->printer_status &= ~PRINTER_SELECTED;	spin_lock_irqsave (&dev->lock, flags);	dev->printer_cdev_open = 0;	spin_unlock_irqrestore (&dev->lock, flags);	DBG(dev, "printer_close\n");	printk(KERN_INFO "printer_close\n");	return 0;}static ssize_tprinter_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr){	struct printer_dev		*dev = fd->private_data;	unsigned long			flags;	size_t				size;	size_t				bytes_copied;	struct usb_request		*req;	struct usb_request		*current_rx_req;	size_t				current_rx_bytes;	u8				*current_rx_buf;	if (dev == NULL) {		printk(KERN_ERR "printer_read: NULL device pointer\n");		return -EIO;	}	if (len == 0)		return -EINVAL;

⌨️ 快捷键说明

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