📄 lp.c
字号:
else return -EINTR; }#ifdef LP_STATS lp->runchars = 0;#endif if (lp_check_status(minor)) { w_ctr(minor, LP_PSELECP | LP_PINITP); return rc ? rc : -EIO; } if (LP_POLLED(minor) || lp_table[minor].irq_missed) { lp_polling:#if defined(LP_DEBUG) && defined(LP_STATS) printk(KERN_DEBUG "lp%d sleeping at %d characters for %d jiffies\n", minor, lp->runchars, LP_TIME(minor));#endif current->state = TASK_INTERRUPTIBLE; lp_schedule(minor, LP_TIME(minor)); } else { cli(); if (LP_PREEMPTED(minor)) { /* * We can' t sleep on the interrupt * since another pardevice need the port. * We must check this in a cli() protected * envinroment to avoid parport sharing * starvation. */ sti(); goto lp_polling; } if (!lp_table[minor].irq_detected) interruptible_sleep_on_timeout(&lp->wait_q, LP_TIMEOUT_INTERRUPT); sti(); } } } total_bytes_written += bytes_written; buf += bytes_written; count -= bytes_written; } while (count > 0); w_ctr(minor, LP_PSELECP | LP_PINITP); return total_bytes_written;}static ssize_t lp_write(struct file * file, const char * buf, size_t count, loff_t *ppos){ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); ssize_t retv;#ifdef LP_STATS if (jiffies-lp_table[minor].lastcall > LP_TIME(minor)) lp_table[minor].runchars = 0; lp_table[minor].lastcall = jiffies;#endif /* Claim Parport or sleep until it becomes available */ lp_parport_claim (minor); retv = lp_write_buf(minor, buf, count); lp_parport_release (minor); return retv;}static long long lp_lseek(struct file * file, long long offset, int origin){ return -ESPIPE;}#ifdef CONFIG_PRINTER_READBACKstatic int lp_read_nibble(int minor) { unsigned char i; i = r_str(minor)>>3; i &= ~8; if ((i & 0x10) == 0) i |= 8; return (i & 0x0f);}static void lp_read_terminate(struct parport *port) { parport_write_control(port, (parport_read_control(port) & ~2) | 8); /* SelectIN high, AutoFeed low */ if (parport_wait_peripheral(port, 0x80, 0)) /* timeout, SelectIN high, Autofeed low */ return; parport_write_control(port, parport_read_control(port) | 2); /* AutoFeed high */ parport_wait_peripheral(port, 0x80, 0x80); /* no timeout possible, Autofeed low, SelectIN high */ parport_write_control(port, (parport_read_control(port) & ~2) | 8);}/* Status readback confirming to ieee1284 */static ssize_t lp_read(struct file * file, char * buf, size_t length, loff_t *ppos){ int i; unsigned int minor=MINOR(file->f_dentry->d_inode->i_rdev); char *temp = buf; ssize_t count = 0; unsigned char z = 0; unsigned char Byte = 0; struct parport *port = lp_table[minor].dev->port; lp_parport_claim (minor); switch (parport_ieee1284_nibble_mode_ok(port, 0)) { case 0: /* Handshake failed. */ lp_read_terminate(port); lp_parport_release (minor); return -EIO; case 1: /* No data. */ lp_read_terminate(port); lp_parport_release (minor); return 0; default: /* Data available. */ /* Hack: Wait 10ms (between events 6 and 7) */ current->state = TASK_INTERRUPTIBLE; schedule_timeout((HZ+99)/100); break; } for (i=0; ; i++) { parport_frob_control(port, 2, 2); /* AutoFeed high */ if (parport_wait_peripheral(port, 0x40, 0)) {#ifdef LP_READ_DEBUG /* Some peripherals just time out when they've sent all their data. */ printk("%s: read1 timeout.\n", port->name);#endif parport_frob_control(port, 2, 0); /* AutoFeed low */ break; } z = lp_read_nibble(minor); parport_frob_control(port, 2, 0); /* AutoFeed low */ if (parport_wait_peripheral(port, 0x40, 0x40)) { printk("%s: read2 timeout.\n", port->name); break; } if ((i & 1) != 0) { Byte |= (z<<4); if (__put_user (Byte, temp)) { count = -EFAULT; break; } else { temp++; if (++count == length) break; } /* Does the error line indicate end of data? */ if ((parport_read_status(port) & LP_PERRORP) == LP_PERRORP) break; } else Byte=z; } lp_read_terminate(port); lp_parport_release (minor); return count;}#endifstatic int lp_open(struct inode * inode, struct file * file){ unsigned int minor = MINOR(inode->i_rdev); if (minor >= LP_NO) return -ENXIO; if ((LP_F(minor) & LP_EXIST) == 0) return -ENXIO; if (test_and_set_bit(LP_BUSY_BIT_POS, &LP_F(minor))) return -EBUSY; MOD_INC_USE_COUNT; /* If ABORTOPEN is set and the printer is offline or out of paper, we may still want to open it to perform ioctl()s. Therefore we have commandeered O_NONBLOCK, even though it is being used in a non-standard manner. This is strictly a Linux hack, and should most likely only ever be used by the tunelp application. */ if ((LP_F(minor) & LP_ABORTOPEN) && !(file->f_flags & O_NONBLOCK)) { int status; lp_parport_claim (minor); status = r_str(minor); lp_parport_release (minor); if (status & LP_POUTPA) { printk(KERN_INFO "lp%d out of paper\n", minor); MOD_DEC_USE_COUNT; LP_F(minor) &= ~LP_BUSY; return -ENOSPC; } else if (!(status & LP_PSELECD)) { printk(KERN_INFO "lp%d off-line\n", minor); MOD_DEC_USE_COUNT; LP_F(minor) &= ~LP_BUSY; return -EIO; } else if (!(status & LP_PERRORP)) { printk(KERN_ERR "lp%d printer error\n", minor); MOD_DEC_USE_COUNT; LP_F(minor) &= ~LP_BUSY; return -EIO; } } lp_table[minor].lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL); if (!lp_table[minor].lp_buffer) { MOD_DEC_USE_COUNT; LP_F(minor) &= ~LP_BUSY; return -ENOMEM; } return 0;}static int lp_release(struct inode * inode, struct file * file){ unsigned int minor = MINOR(inode->i_rdev); kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE); lp_table[minor].lp_buffer = NULL; MOD_DEC_USE_COUNT; LP_F(minor) &= ~LP_BUSY; return 0;}static int lp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ unsigned int minor = MINOR(inode->i_rdev); int status; int retval = 0;#ifdef LP_DEBUG printk(KERN_DEBUG "lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);#endif if (minor >= LP_NO) return -ENODEV; if ((LP_F(minor) & LP_EXIST) == 0) return -ENODEV; switch ( cmd ) { case LPTIME: LP_TIME(minor) = arg * HZ/100; break; case LPCHAR: LP_CHAR(minor) = arg; break; case LPABORT: if (arg) LP_F(minor) |= LP_ABORT; else LP_F(minor) &= ~LP_ABORT; break; case LPABORTOPEN: if (arg) LP_F(minor) |= LP_ABORTOPEN; else LP_F(minor) &= ~LP_ABORTOPEN; break; case LPCAREFUL: if (arg) LP_F(minor) |= LP_CAREFUL; else LP_F(minor) &= ~LP_CAREFUL; break; case LPTRUSTIRQ: if (arg) LP_F(minor) |= LP_TRUST_IRQ; else LP_F(minor) &= ~LP_TRUST_IRQ; break; case LPWAIT: LP_WAIT(minor) = arg; break; case LPSETIRQ: return -EINVAL; break; case LPGETIRQ: if (copy_to_user((int *) arg, &LP_IRQ(minor), sizeof(int))) return -EFAULT; break; case LPGETSTATUS: lp_parport_claim(minor); status = r_str(minor); lp_parport_release(minor); if (copy_to_user((int *) arg, &status, sizeof(int))) return -EFAULT; break; case LPRESET: lp_reset(minor); break;#ifdef LP_STATS case LPGETSTATS: if (copy_to_user((int *) arg, &LP_STAT(minor), sizeof(struct lp_stats))) return -EFAULT; if (suser()) memset(&LP_STAT(minor), 0, sizeof(struct lp_stats)); break;#endif case LPGETFLAGS: status = LP_F(minor); if (copy_to_user((int *) arg, &status, sizeof(int))) return -EFAULT; break; default: retval = -EINVAL; } return retval;}static struct file_operations lp_fops = { lp_lseek,#ifdef CONFIG_PRINTER_READBACK lp_read,#else NULL,#endif lp_write, NULL, /* lp_readdir */ NULL, /* lp_poll */ lp_ioctl, NULL, /* lp_mmap */ lp_open, NULL, /* flush */ lp_release};/* --- initialisation code ------------------------------------- */#ifdef MODULEstatic int parport_nr[LP_NO] = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };static char *parport[LP_NO] = { NULL, };static int reset = 0;MODULE_PARM(parport, "1-" __MODULE_STRING(LP_NO) "s");MODULE_PARM(reset, "i");#elsestatic int parport_nr[LP_NO] __initdata = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };static int reset __initdata = 0;static int parport_ptr = 0;__initfunc(void lp_setup(char *str, int *ints)){ if (!str) { if (ints[0] == 0 || ints[1] == 0) { /* disable driver on "lp=" or "lp=0" */ parport_nr[0] = LP_PARPORT_OFF; } else { printk(KERN_WARNING "warning: 'lp=0x%x' is deprecated, ignored\n", ints[1]); } } else if (!strncmp(str, "parport", 7)) { int n = simple_strtoul(str+7, NULL, 10); if (parport_ptr < LP_NO) parport_nr[parport_ptr++] = n; else printk(KERN_INFO "lp: too many ports, %s ignored.\n", str); } else if (!strcmp(str, "auto")) { parport_nr[0] = LP_PARPORT_AUTO; } else if (!strcmp(str, "none")) { parport_nr[parport_ptr++] = LP_PARPORT_NONE; } else if (!strcmp(str, "reset")) { reset = 1; }}#endifint lp_register(int nr, struct parport *port){ lp_table[nr].dev = parport_register_device(port, "lp", lp_preempt, NULL, lp_interrupt, 0, (void *) &lp_table[nr]); if (lp_table[nr].dev == NULL) return 1; lp_table[nr].flags |= LP_EXIST; if (reset) lp_reset(nr); printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, (port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven"); return 0;}int lp_init(void){ unsigned int count = 0; unsigned int i; struct parport *port; switch (parport_nr[0]) { case LP_PARPORT_OFF: return 0; case LP_PARPORT_UNSPEC: case LP_PARPORT_AUTO: for (port = parport_enumerate(); port; port = port->next) { if (parport_nr[0] == LP_PARPORT_AUTO && port->probe_info.class != PARPORT_CLASS_PRINTER) continue; if (!lp_register(count, port)) if (++count == LP_NO) break; } break; default: for (i = 0; i < LP_NO; i++) { for (port = parport_enumerate(); port; port = port->next) { if (port->number == parport_nr[i]) { if (!lp_register(i, port)) count++; break; } } } break; } if (count) { if (register_chrdev(LP_MAJOR, "lp", &lp_fops)) { printk("lp: unable to get major %d\n", LP_MAJOR); return -EIO; } } else { printk(KERN_INFO "lp: no devices found\n"); return -ENODEV; } return 0;}#ifdef MODULEint init_module(void){ if (parport[0]) { /* The user gave some parameters. Let's see what they were. */ if (!strncmp(parport[0], "auto", 4)) parport_nr[0] = LP_PARPORT_AUTO; else { int n; for (n = 0; n < LP_NO && parport[n]; n++) { if (!strncmp(parport[n], "none", 4)) parport_nr[n] = LP_PARPORT_NONE; else { char *ep; unsigned long r = simple_strtoul(parport[n], &ep, 0); if (ep != parport[n]) parport_nr[n] = r; else { printk(KERN_ERR "lp: bad port specifier `%s'\n", parport[n]); return -ENODEV; } } } } } return lp_init();}void cleanup_module(void){ unsigned int offset; unregister_chrdev(LP_MAJOR, "lp"); for (offset = 0; offset < LP_NO; offset++) { if (lp_table[offset].dev == NULL) continue; parport_unregister_device(lp_table[offset].dev); }}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -