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

📄 scanner.c

📁 Usb1.1驱动c语言源代码
💻 C
字号:
/* -*- linux-c -*- *//*  * Driver for USB Scanners (linux-2.3.33) * * David E. Nelson (dnelson@jump.net) *  * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * * Based upon mouse.c (Brad Keryan) and printer.c (Michael Gee). * * History *  0.1  8/31/1999 * *    Developed/tested using linux-2.3.15 with minor ohci.c changes to *    support short packes during bulk xfer mode.  Some testing was *    done with ohci-hcd but the performace was low.  Very limited *    testing was performed with uhci but I was unable to get it to *    work.  Initial relase to the linux-usb development effort. * *  0.2  10/16/1999 * *    FIXED: *    - Device can't be opened unless a scanner is plugged into the USB. *    - Finally settled on a reasonable value for the I/O buffer's. *    - Cleaned up write_scanner() *    - Disabled read/write stats *    - A little more code cleanup * *  0.3  10/18/1999 * *    FIXED: *    - Device registration changed to reflect new device *      allocation/registration for linux-2.3.22+. *    - Adopted David Brownell's <david-b@pacbell.net> technique for  *      assigning bulk endpoints. *    - Removed unnessesary #include's *    - Scanner model now reported via syslog INFO after being detected  *      *and* configured. *    - Added user specified verdor:product USB ID's which can be passed  *      as module parameters. * *  0.3.1 *    FIXED: *    - Applied patches for linux-2.3.25. *    - Error number reporting changed to reflect negative return codes. * *  0.3.2 *    FIXED: *    - Applied patches for linux-2.3.26 to scanner_init(). *    - Debug read/write stats now report values as signed decimal. * * *  0.3.3 *    FIXED: *    - Updated the bulk_msg() calls to usb usb_bulk_msg(). *    - Added a small delay in the write_scanner() method to aid in *      avoiding NULL data reads on HP scanners.  We'll see how this works. *    - Return values from usb_bulk_msg() now ignore positive values for *      use with the ohci driver. *    - Added conditional debugging instead of commenting/uncommenting *      all over the place. *    - kfree()'d the pointer after using usb_string() as documented in *      linux-usb-api.txt. *    - Added usb_set_configuration().  It got lost in version 0.3 -- ack! *    - Added the HP 5200C USB Vendor/Product ID's * *  TODO *    - Simultaneous multiple device attachment *    - ioctl()'s ? * *  Thanks to: *    - All the folks on the linux-usb list who put up with me. :)  This  *      has been a great learning experience for me. *    - To Linus Torvalds for this great OS. *    - The GNU folks. *    - The folks that forwarded Vendor:Product ID's to me. *    - And anybody else who chimed in with reports and suggestions. * *  Performance: *    System: Pentium 120, 80 MB RAM, OHCI, Linux 2.3.23, HP 4100C USB Scanner *            300 dpi scan of the entire bed *      24 Bit Color ~ 70 secs - 3.6 Mbit/sec *       8 Bit Gray  ~ 17 secs - 4.2 Mbit/sec * */#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <asm/uaccess.h>#include <linux/malloc.h>#include <linux/delay.h>#undef DEBUG		/* Enable to print results of read/write_scanner() calls */#undef RD_DATA_DUMP	/* Enable to dump data - limited to 24 bytes */#undef WR_DATA_DUMP#include "usb.h"#define IBUF_SIZE 32768#define OBUF_SIZE 4096struct hpscan_usb_data {	struct usb_device *hpscan_dev;        int isopen;		/* Not zero if the device is open */	int present;		/* Device is present on the bus */	char *obuf, *ibuf;	/* transfer buffers */	char iep, oep;          /* I/O Endpoints */};static struct hpscan_usb_data hpscan;MODULE_AUTHOR("David E. Nelson, dnelson@jump.net, http://www.jump.net/~dnelson");MODULE_DESCRIPTION("USB Scanner Driver");static __u16 vendor=0, product=0;MODULE_PARM(vendor, "i");MODULE_PARM_DESC(vendor, "User specified USB idVendor");MODULE_PARM(product, "i");MODULE_PARM_DESC(product, "User specified USB idProduct");static intopen_scanner(struct inode * inode, struct file * file){	struct hpscan_usb_data *hps = &hpscan;	if (!hps->present) {		return -ENODEV;	}	if (!hps->hpscan_dev) {		return -ENODEV;	}	if (hps->isopen) {		return -EBUSY;	}	hps->isopen = 1;	MOD_INC_USE_COUNT;	return 0;}static intclose_scanner(struct inode * inode, struct file * file){	struct hpscan_usb_data *hps = &hpscan;	hps->isopen = 0;	MOD_DEC_USE_COUNT;	return 0;}static ssize_twrite_scanner(struct file * file, const char * buffer,              size_t count, loff_t *ppos){	struct hpscan_usb_data *hps = &hpscan;	unsigned long copy_size;	unsigned long bytes_written = 0;	int partial;	ssize_t ret = 0;	int result = 0;		char *obuf = hps->obuf;	set_current_state(TASK_INTERRUPTIBLE);	while (count > 0) {		if (signal_pending(current)) {			ret = -ERESTARTSYS;			break;		}		copy_size = (count > OBUF_SIZE) ? OBUF_SIZE : count;				if (copy_from_user(hps->obuf, buffer, copy_size)) {			ret = -EFAULT;			break;		}		result = usb_bulk_msg(hps->hpscan_dev,usb_sndbulkpipe(hps->hpscan_dev, hps->oep), obuf, copy_size, &partial, 30*HZ);		dbg("write stats: result:%d copy_size:%lu partial:%d", (int)result, copy_size, partial);		if (result == USB_ST_TIMEOUT) {	/* NAK -- shouldn't happen */			warn("write_scanner: NAK recieved.");			ret = -ETIME;			break;		} else if (result < 0) { /* We should not get any I/O errors */			warn("write_scanner: funky result: %d. Please notify the maintainer.", result);			ret = -EIO;			break;		} #ifdef WR_DATA_DUMP		if (partial) {			unsigned char cnt, cnt_max;			cnt_max = (partial > 24) ? 24 : partial;			printk(KERN_DEBUG __FILE__ ": dump: ");			for (cnt=0; cnt < cnt_max; cnt++) {				printk("%X ", obuf[cnt]);			}			printk("\n");		}#endif		if (partial != copy_size) { /* Unable to write complete amount */			ret = -EIO;			break;		}		if (partial) { /* Data written */			obuf += partial;			count -= partial;			bytes_written += partial;		} else { /* No data written */			ret = 0;			bytes_written = 0;			break;		}	}//	mdelay(5);	set_current_state(TASK_RUNNING);	return ret ? ret : bytes_written;}static ssize_tread_scanner(struct file * file, char * buffer,             size_t count, loff_t *ppos){	struct hpscan_usb_data *hps = &hpscan;	ssize_t read_count, ret = 0;	int partial;	int this_read;	int result;	char *ibuf = hps->ibuf;	read_count = 0;	set_current_state(TASK_INTERRUPTIBLE);	while (count) {		if (signal_pending(current)) {			ret = -ERESTARTSYS;			break;		}		this_read = (count > IBUF_SIZE) ? IBUF_SIZE : count;				result = usb_bulk_msg(hps->hpscan_dev, usb_rcvbulkpipe(hps->hpscan_dev, hps->iep), ibuf, this_read, &partial, 60*HZ);		dbg("read stats: result:%d this_read:%u partial:%d", (int)result, this_read, partial);		if (result == USB_ST_TIMEOUT) { /* NAK -- shouldn't happen */			warn("read_scanner: NAK received");			ret = -ETIME;			break;		} else if ((result < 0) && (result != USB_ST_DATAUNDERRUN)) {			warn("read_scanner: funky result: %d. Please notify the maintainer.", (int)result);			ret = -EIO;			break;		}#ifdef RD_DATA_DUMP		if (partial) {			unsigned char cnt, cnt_max;			cnt_max = (partial > 24) ? 24 : partial;			printk(KERN_DEBUG __FILE__ ": dump: ");			for (cnt=0; cnt < cnt_max; cnt++) {				printk("%X ", ibuf[cnt]);			}			printk("\n");		}#endif		if (partial) { /* Data returned */			count = this_read = partial;		} else {			ret = 0;			read_count = 0;			break;		}		if (this_read) {			if (copy_to_user(buffer, ibuf, this_read)) {				ret = -EFAULT;				break;			}			count -= this_read;			read_count += this_read;			buffer += this_read;		}	}	set_current_state(TASK_RUNNING);	return ret ? ret : read_count;}static void *probe_scanner(struct usb_device *dev, unsigned int ifnum){	struct hpscan_usb_data *hps = &hpscan;	struct usb_endpoint_descriptor *endpoint;	char *ident;	hps->present = 0;	if (vendor != 0 || product != 0)		info("USB Scanner Vendor:Product - %x:%x\n", vendor, product);/* There doesn't seem to be an imaging class defined in the USB * Spec. (yet).  If there is, HP isn't following it and it doesn't * look like anybody else is either.  Therefore, we have to test the * Vendor and Product ID's to see what we have.  This makes this * driver a high maintenance driver since it has to be updated with * each release of a product.  Also, other scanners may be able to use * this driver but again, their Vendor and Product ID's must be added. * * NOTE: Just because a product is supported here does not mean that * applications exist that support the product.  It's in the hopes * that this will allow developers a means to produce applications * that will support USB products. * * Until we detect a device which is pleasing, we silently punt. * */	if (dev->descriptor.idVendor != 0x03f0 && /* Hewlett Packard */	    dev->descriptor.idVendor != 0x06bd && /* AGFA */	    dev->descriptor.idVendor != 0x1606 && /* UMAX */	    dev->descriptor.idVendor != vendor ) { /* User specified */		return NULL;	}	if (dev->descriptor.idProduct != 0x0101 && /* HP 4100C */	    dev->descriptor.idProduct != 0x0102 && /* HP 4200C & PhotoSmart S20? */	    dev->descriptor.idProduct != 0x0202 && /* HP 5100C */	    dev->descriptor.idProduct != 0x0401 && /* HP 5200C */	    dev->descriptor.idProduct != 0x0201 && /* HP 6200C */	    dev->descriptor.idProduct != 0x0601 && /* HP 6300C */	    dev->descriptor.idProduct != 0x0001 && /* AGFA SnapScan 1212U */	    dev->descriptor.idProduct != 0x0030 && /* Umax 2000U */	    dev->descriptor.idProduct != product) { /* User specified */		return NULL;	}/* After this point we can be a little noisy about what we are trying to *  configure. */	if (dev->descriptor.bNumConfigurations != 1 || 	    dev->config[0].bNumInterfaces != 1) {		dbg("probe_scanner: only simple configurations supported");		return NULL;	}	endpoint = dev->config[0].interface[0].altsetting[0].endpoint;	if (endpoint[0].bmAttributes != USB_ENDPOINT_XFER_BULK	    || endpoint [1].bmAttributes != USB_ENDPOINT_XFER_BULK) {		dbg("probe_scanner: invalid bulk endpoints");		return NULL;	}	if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {                dbg("probe_scanner: failed usb_set_configuration");		hps->hpscan_dev = NULL;                return NULL;        }/* By the time we get here, we should be dealing with a fairly simple * device that supports at least two bulk endpoints on endpoints 1 and * 2. * * We determine the bulk endpoints so that the read_*() and write_*() * procedures can recv/send data to the correct endpoint. * */	hps->iep = hps->oep = 0;	if ((endpoint[0].bEndpointAddress & 0x80) == 0x80) {		hps->iep = endpoint[0].bEndpointAddress & 0x7f;	} else {		hps->oep = endpoint[0].bEndpointAddress;	}	if ((endpoint[1].bEndpointAddress & 0x80) == 0x80) {		hps->iep = endpoint[1].bEndpointAddress & 0x7f;	} else {		hps->oep = endpoint[1].bEndpointAddress;	}	ident = kmalloc(256, GFP_KERNEL);	if (ident) {		usb_string(dev, dev->descriptor.iProduct, ident, 256);		info("USB Scanner (%s) found at address %d", ident, dev->devnum);		kfree(ident);	}	dbg("probe_scanner: using bulk endpoints - In: %x  Out: %x", hps->iep, hps->oep);	hps->present = 1;	hps->hpscan_dev = dev;	if (!(hps->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) {		return NULL;	}	if (!(hps->ibuf = (char *)kmalloc(IBUF_SIZE, GFP_KERNEL))) {		return NULL;	}	return hps;}static voiddisconnect_scanner(struct usb_device *dev, void *ptr){	struct hpscan_usb_data *hps = (struct hpscan_usb_data *) ptr;	if (hps->isopen) {		/* better let it finish - the release will do whats needed */		hps->hpscan_dev = NULL;		return;	}	kfree(hps->ibuf);	kfree(hps->obuf);	hps->present = 0;}static structfile_operations usb_scanner_fops = {	NULL,		/* seek */	read_scanner,	write_scanner,	NULL,		/* readdir */	NULL,		/* poll */	NULL,    	/* ioctl */	NULL,		/* mmap */	open_scanner,	NULL,		/* flush */	close_scanner,	NULL,         	NULL,         /* fasync */};static structusb_driver scanner_driver = {       "usbscanner",       probe_scanner,       disconnect_scanner,       { NULL, NULL },       &usb_scanner_fops,       48};intusb_scanner_init(void){        if (usb_register(&scanner_driver) < 0)                return -1;	info("USB Scanner support registered.");	return 0;}voidusb_scanner_cleanup(void){	struct hpscan_usb_data *hps = &hpscan;	hps->present = 0;	usb_deregister(&scanner_driver);}#ifdef MODULEintinit_module(void){	return usb_scanner_init();}voidcleanup_module(void){	usb_scanner_cleanup();}#endif

⌨️ 快捷键说明

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