📄 scanner.c
字号:
down(&scn_mutex); scn_minor = USB_SCN_MINOR(inode); 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 intclose_scanner(struct inode * inode, struct file * file){ struct scn_usb_data *scn; kdev_t 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_twrite_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; kdev_t 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_tread_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; kdev_t 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 != USB_ST_DATAUNDERRUN)) { 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 intioctl_scanner(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct usb_device *dev; kdev_t 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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -