📄 scanner.c
字号:
* applications to use USB scanners.
* - Thanks to Greg KH <greg@kroah.com> for setting up Brian Beattie
* and Henning Meier-Geinitz to be the new USB Scanner maintainer.
*
* 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 */
/*
* For documentation, see Documentation/usb/scanner.txt.
* Website: http://www.meier-geinitz.de/kernel/
* Please contact the maintainer if your scanner is not detected by this
* driver automatically.
*/
#include <asm/byteorder.h>
/*
* Scanner definitions, macros, module info,
* debug/ioctl/data_dump enable, and other constants.
*/
#include "scanner.h"
static void
irq_scanner(struct urb *urb, struct pt_regs *regs)
{
/*
* For the meantime, this is just a placeholder until I figure out what
* all I want to do with it -- or somebody else for that matter.
*/
struct scn_usb_data *scn;
unsigned char *data;
int status;
scn = urb->context;
data = &scn->button;
data += 0; /* Keep gcc from complaining about unused var */
switch (urb->status) {
case 0:
/* success */
break;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
return;
default:
dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
return;
}
dbg("irq_scanner(%d): data:%x", scn->scn_minor, *data);
status = usb_submit_urb (urb, GFP_ATOMIC);
if (status)
err ("%s - usb_submit_urb failed with result %d",
__FUNCTION__, status);
}
static int
open_scanner(struct inode * inode, struct file * file)
{
struct scn_usb_data *scn;
struct usb_device *dev;
struct usb_interface *intf;
int scn_minor;
int err=0;
down(&scn_mutex);
scn_minor = USB_SCN_MINOR(inode);
dbg("open_scanner: scn_minor:%d", scn_minor);
intf = usb_find_interface(&scanner_driver, scn_minor);
if (!intf) {
up(&scn_mutex);
err("open_scanner(%d): Unable to access minor data", scn_minor);
return -ENODEV;
}
scn = usb_get_intfdata(intf);
kobject_get(&scn->kobj);
dev = scn->scn_dev;
down(&(scn->sem)); /* Now protect the scn_usb_data structure */
up(&scn_mutex); /* Now handled by the above */
if (!dev) {
err("open_scanner(%d): Scanner device not present", scn_minor);
err = -ENODEV;
goto out_error;
}
if (!scn->present) {
err("open_scanner(%d): Scanner is not present", scn_minor);
err = -ENODEV;
goto out_error;
}
if (scn->isopen) {
dbg("open_scanner(%d): Scanner device is already open", scn_minor);
err = -EBUSY;
goto out_error;
}
init_waitqueue_head(&scn->rd_wait_q);
scn->isopen = 1;
file->private_data = scn; /* Used by the read and write methods */
out_error:
up(&(scn->sem)); /* Wake up any possible contending processes */
return err;
}
static int
close_scanner(struct inode * inode, struct file * file)
{
struct scn_usb_data *scn = file->private_data;
int scn_minor;
scn_minor = USB_SCN_MINOR (inode);
dbg("close_scanner: scn_minor:%d", scn_minor);
down(&scn_mutex);
down(&(scn->sem));
scn->isopen = 0;
file->private_data = NULL;
up(&scn_mutex);
up(&(scn->sem));
kobject_put(&scn->kobj);
return 0;
}
static ssize_t
write_scanner(struct file * file, const char * buffer,
size_t count, loff_t *ppos)
{
struct scn_usb_data *scn;
struct usb_device *dev;
ssize_t bytes_written = 0; /* Overall count of bytes written */
ssize_t ret = 0;
int scn_minor;
int this_write; /* Number of bytes to write */
int partial; /* Number of bytes successfully written */
int result = 0;
char *obuf;
scn = file->private_data;
down(&(scn->sem));
if (!scn->bulk_out_ep) {
/* This scanner does not have a bulk-out endpoint */
up(&(scn->sem));
return -EINVAL;
}
scn_minor = scn->scn_minor;
obuf = scn->obuf;
dev = scn->scn_dev;
file->f_dentry->d_inode->i_atime = CURRENT_TIME;
while (count > 0) {
if (signal_pending(current)) {
ret = -ERESTARTSYS;
break;
}
this_write = (count >= OBUF_SIZE) ? OBUF_SIZE : count;
if (copy_from_user(scn->obuf, buffer, this_write)) {
ret = -EFAULT;
break;
}
result = usb_bulk_msg(dev,usb_sndbulkpipe(dev, scn->bulk_out_ep), obuf, this_write, &partial, 60*HZ);
dbg("write stats(%d): result:%d this_write:%d partial:%d", scn_minor, result, this_write, partial);
if (result == -ETIMEDOUT) { /* NAK -- shouldn't happen */
warn("write_scanner: NAK received.");
ret = result;
break;
} else if (result < 0) { /* We should not get any I/O errors */
warn("write_scanner(%d): funky result: %d. Consult Documentataion/usb/scanner.txt.", scn_minor, result);
ret = -EIO;
break;
}
#ifdef WR_DATA_DUMP
if (partial) {
unsigned char cnt, cnt_max;
cnt_max = (partial > 24) ? 24 : partial;
printk(KERN_DEBUG "dump(%d): ", scn_minor);
for (cnt=0; cnt < cnt_max; cnt++) {
printk("%X ", obuf[cnt]);
}
printk("\n");
}
#endif
if (partial != this_write) { /* Unable to write all contents of obuf */
ret = -EIO;
break;
}
if (partial) { /* Data written */
buffer += partial;
count -= partial;
bytes_written += partial;
} else { /* No data written */
ret = 0;
break;
}
}
up(&(scn->sem));
mdelay(5); /* This seems to help with SANE queries */
return ret ? ret : bytes_written;
}
static ssize_t
read_scanner(struct file * file, char * buffer,
size_t count, loff_t *ppos)
{
struct scn_usb_data *scn;
struct usb_device *dev;
ssize_t bytes_read; /* Overall count of bytes_read */
ssize_t ret;
int scn_minor;
int partial; /* Number of bytes successfully read */
int this_read; /* Max number of bytes to read */
int result;
int rd_expire = RD_EXPIRE;
char *ibuf;
scn = file->private_data;
down(&(scn->sem));
scn_minor = scn->scn_minor;
ibuf = scn->ibuf;
dev = scn->scn_dev;
bytes_read = 0;
ret = 0;
file->f_dentry->d_inode->i_atime = CURRENT_TIME; /* Update the
atime of
the device
node */
while (count > 0) {
if (signal_pending(current)) {
ret = -ERESTARTSYS;
break;
}
this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
result = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, scn->bulk_in_ep), ibuf, this_read, &partial, scn->rd_nak_timeout);
dbg("read stats(%d): result:%d this_read:%d partial:%d count:%d", scn_minor, result, this_read, partial, count);
/*
* Scanners are sometimes inheriently slow since they are mechanical
* in nature. USB bulk reads tend to timeout while the scanner is
* positioning, resetting, warming up the lamp, etc if the timeout is
* set too low. A very long timeout parameter for bulk reads was used
* to overcome this limitation, but this sometimes resulted in folks
* having to wait for the timeout to expire after pressing Ctrl-C from
* an application. The user was sometimes left with the impression
* that something had hung or crashed when in fact the USB read was
* just waiting on data. So, the below code retains the same long
* timeout period, but splits it up into smaller parts so that
* Ctrl-C's are acted upon in a reasonable amount of time.
*/
if (result == -ETIMEDOUT) { /* NAK */
if (!partial) { /* No data */
if (--rd_expire <= 0) { /* Give it up */
warn("read_scanner(%d): excessive NAK's received", scn_minor);
ret = result;
break;
} else { /* Keep trying to read data */
interruptible_sleep_on_timeout(&scn->rd_wait_q, scn->rd_nak_timeout);
continue;
}
} else { /* Timeout w/ some data */
goto data_recvd;
}
}
if (result == -EPIPE) { /* No hope */
if(usb_clear_halt(dev, scn->bulk_in_ep)) {
err("read_scanner(%d): Failure to clear endpoint halt condition (%Zd).", scn_minor, ret);
}
ret = result;
break;
} else if ((result < 0) && (result != -EREMOTEIO)) {
warn("read_scanner(%d): funky result:%d. Consult Documentation/usb/scanner.txt.", scn_minor, (int)result);
ret = -EIO;
break;
}
data_recvd:
#ifdef RD_DATA_DUMP
if (partial) {
unsigned char cnt, cnt_max;
cnt_max = (partial > 24) ? 24 : partial;
printk(KERN_DEBUG "dump(%d): ", scn_minor);
for (cnt=0; cnt < cnt_max; cnt++) {
printk("%X ", ibuf[cnt]);
}
printk("\n");
}
#endif
if (partial) { /* Data returned */
if (copy_to_user(buffer, ibuf, partial)) {
ret = -EFAULT;
break;
}
count -= this_read; /* Compensate for short reads */
bytes_read += partial; /* Keep tally of what actually was read */
buffer += partial;
} else {
ret = 0;
break;
}
}
up(&(scn->sem));
return ret ? ret : bytes_read;
}
static int
ioctl_scanner(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct usb_device *dev;
struct scn_usb_data *scn = file->private_data;
int retval = -ENOTTY;
int scn_minor;
scn_minor = USB_SCN_MINOR(inode);
down(&(scn->sem));
dev = scn->scn_dev;
switch (cmd)
{
case SCANNER_IOCTL_VENDOR :
retval = (put_user(dev->descriptor.idVendor, (unsigned int *) arg));
break;
case SCANNER_IOCTL_PRODUCT :
retval = (put_user(dev->descriptor.idProduct, (unsigned int *) arg));
break;
case SCANNER_IOCTL_CTRLMSG:
{
struct ctrlmsg_ioctl {
struct usb_ctrlrequest req;
void *data;
} cmsg;
int pipe, nb, ret;
unsigned char buf[64];
retval = 0;
if (copy_from_user(&cmsg, (void *)arg, sizeof(cmsg))) {
retval = -EFAULT;
break;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -