📄 scanner.c
字号:
dbg("open_scanner: scn_minor:%d", scn_minor);
if (!p_scn_table[scn_minor]) {
up(&scn_mutex);
MOD_DEC_USE_COUNT;
err("open_scanner(%d): Unable to access minor data", scn_minor);
return -ENODEV;
}
scn = p_scn_table[scn_minor];
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) {
err("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 */
if (err)
MOD_DEC_USE_COUNT;
return err;
}
static int
close_scanner(struct inode * inode, struct file * file)
{
struct scn_usb_data *scn;
int scn_minor;
scn_minor = USB_SCN_MINOR (inode);
dbg("close_scanner: scn_minor:%d", scn_minor);
if (!p_scn_table[scn_minor]) {
err("close_scanner(%d): invalid scn_minor", scn_minor);
return -ENODEV;
}
down(&scn_mutex);
scn = p_scn_table[scn_minor];
down(&(scn->sem));
scn->isopen = 0;
file->private_data = NULL;
up(&scn_mutex);
up(&(scn->sem));
MOD_DEC_USE_COUNT;
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));
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;
int scn_minor;
scn_minor = USB_SCN_MINOR(inode);
if (!p_scn_table[scn_minor]) {
err("ioctl_scanner(%d): invalid scn_minor", scn_minor);
return -ENODEV;
}
dev = p_scn_table[scn_minor]->scn_dev;
switch (cmd)
{
case SCANNER_IOCTL_VENDOR :
return (put_user(dev->descriptor.idVendor, (unsigned int *) arg));
case SCANNER_IOCTL_PRODUCT :
return (put_user(dev->descriptor.idProduct, (unsigned int *) arg));
#ifdef PV8630
case PV8630_IOCTL_INREQUEST :
{
int result;
struct {
__u8 data;
__u8 request;
__u16 value;
__u16 index;
} args;
if (copy_from_user(&args, (void *)arg, sizeof(args)))
return -EFAULT;
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
args.request, USB_TYPE_VENDOR|
USB_RECIP_DEVICE|USB_DIR_IN,
args.value, args.index, &args.data,
1, HZ*5);
dbg("ioctl_scanner(%d): inreq: args.data:%x args.value:%x args.index:%x args.request:%x\n", scn_minor, args.data, args.value, args.index, args.request);
if (copy_to_user((void *)arg, &args, sizeof(args)))
return -EFAULT;
dbg("ioctl_scanner(%d): inreq: result:%d\n", scn_minor, result);
return result;
}
case PV8630_IOCTL_OUTREQUEST :
{
int result;
struct {
__u8 request;
__u16 value;
__u16 index;
} args;
if (copy_from_user(&args, (void *)arg, sizeof(args)))
return -EFAULT;
dbg("ioctl_scanner(%d): outreq: args.value:%x args.index:%x args.request:%x\n", scn_minor, args.value, args.index, args.request);
result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
args.request, USB_TYPE_VENDOR|
USB_RECIP_DEVICE|USB_DIR_OUT,
args.value, args.index, NULL,
0, HZ*5);
dbg("ioctl_scanner(%d): outreq: result:%d\n", scn_minor, result);
return result;
}
#endif /* PV8630 */
case SCANNER_IOCTL_CTRLMSG:
{
struct ctrlmsg_ioctl {
struct usb_ctrlrequest req;
void *data;
} cmsg;
int pipe, nb, ret;
unsigned char buf[64];
if (copy_from_user(&cmsg, (void *)arg, sizeof(cmsg)))
return -EFAULT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -