📄 scanner.c
字号:
/* * 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 + -