📄 lp.c
字号:
lp_table[minor].lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL); if (!lp_table[minor].lp_buffer) { LP_F(minor) &= ~LP_BUSY; return -ENOMEM; } /* Determine if the peripheral supports ECP mode */ lp_claim_parport_or_block (&lp_table[minor]); if ( (lp_table[minor].dev->port->modes & PARPORT_MODE_ECP) && !parport_negotiate (lp_table[minor].dev->port, IEEE1284_MODE_ECP)) { printk (KERN_INFO "lp%d: ECP mode\n", minor); lp_table[minor].best_mode = IEEE1284_MODE_ECP; } else { printk (KERN_INFO "lp%d: compatibility mode\n", minor); lp_table[minor].best_mode = IEEE1284_MODE_COMPAT; } /* Leave peripheral in compatibility mode */ parport_negotiate (lp_table[minor].dev->port, IEEE1284_MODE_COMPAT); lp_release_parport (&lp_table[minor]); lp_table[minor].current_mode = IEEE1284_MODE_COMPAT; return 0;}static int lp_release(struct inode * inode, struct file * file){ unsigned int minor = MINOR(inode->i_rdev); lp_claim_parport_or_block (&lp_table[minor]); parport_negotiate (lp_table[minor].dev->port, IEEE1284_MODE_COMPAT); lp_table[minor].current_mode = IEEE1284_MODE_COMPAT; lp_release_parport (&lp_table[minor]); lock_kernel(); kfree(lp_table[minor].lp_buffer); lp_table[minor].lp_buffer = NULL; LP_F(minor) &= ~LP_BUSY; unlock_kernel(); 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%lx\n", minor, cmd, arg);#endif if (minor >= LP_NO) return -ENODEV; if ((LP_F(minor) & LP_EXIST) == 0) return -ENODEV; switch ( cmd ) { struct timeval par_timeout; long to_jiffies; 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 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_claim_parport_or_block (&lp_table[minor]); status = r_str(minor); lp_release_parport (&lp_table[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 (capable(CAP_SYS_ADMIN)) 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; case LPSETTIMEOUT: if (copy_from_user (&par_timeout, (struct timeval *) arg, sizeof (struct timeval))) { return -EFAULT; } /* Convert to jiffies, place in lp_table */ if ((par_timeout.tv_sec < 0) || (par_timeout.tv_usec < 0)) { return -EINVAL; } to_jiffies = ROUND_UP(par_timeout.tv_usec, 1000000/HZ); to_jiffies += par_timeout.tv_sec * (long) HZ; if (to_jiffies <= 0) { return -EINVAL; } lp_table[minor].timeout = to_jiffies; break; default: retval = -EINVAL; } return retval;}static struct file_operations lp_fops = { owner: THIS_MODULE, write: lp_write, ioctl: lp_ioctl, open: lp_open, release: lp_release,#ifdef CONFIG_PARPORT_1284 read: lp_read,#endif};/* --- support for console on the line printer ----------------- */#ifdef CONFIG_LP_CONSOLE#define CONSOLE_LP 0/* If the printer is out of paper, we can either lose the messages or * stall until the printer is happy again. Define CONSOLE_LP_STRICT * non-zero to get the latter behaviour. */#define CONSOLE_LP_STRICT 1/* The console must be locked when we get here. */static void lp_console_write (struct console *co, const char *s, unsigned count){ struct pardevice *dev = lp_table[CONSOLE_LP].dev; struct parport *port = dev->port; ssize_t written; if (parport_claim (dev)) /* Nothing we can do. */ return; parport_set_timeout (dev, 0); /* Go to compatibility mode. */ parport_negotiate (port, IEEE1284_MODE_COMPAT); do { /* Write the data, converting LF->CRLF as we go. */ ssize_t canwrite = count; char *lf = memchr (s, '\n', count); if (lf) canwrite = lf - s; if (canwrite > 0) { written = parport_write (port, s, canwrite); if (written <= 0) continue; s += written; count -= written; canwrite -= written; } if (lf && canwrite <= 0) { const char *crlf = "\r\n"; int i = 2; /* Dodge the original '\n', and put '\r\n' instead. */ s++; count--; do { written = parport_write (port, crlf, i); if (written > 0) i -= written, crlf += written; } while (i > 0 && (CONSOLE_LP_STRICT || written > 0)); } } while (count > 0 && (CONSOLE_LP_STRICT || written > 0)); parport_release (dev);}static kdev_t lp_console_device (struct console *c){ return MKDEV(LP_MAJOR, CONSOLE_LP);}static struct console lpcons = { name: "lp", write: lp_console_write, device: lp_console_device, flags: CON_PRINTBUFFER,};#endif /* console on line printer *//* --- initialisation code ------------------------------------- */static 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");#ifndef MODULEstatic int __init lp_setup (char *str){ static int parport_ptr; // initially zero int x; if (get_option (&str, &x)) { if (x == 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", x); return 0; } } 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; } return 1;}#endifstatic int lp_register(int nr, struct parport *port){ char name[8]; lp_table[nr].dev = parport_register_device(port, "lp", lp_preempt, NULL, NULL, 0, (void *) &lp_table[nr]); if (lp_table[nr].dev == NULL) return 1; lp_table[nr].flags |= LP_EXIST; if (reset) lp_reset(nr); sprintf (name, "%d", nr); devfs_register (devfs_handle, name, DEVFS_FL_DEFAULT, LP_MAJOR, nr, S_IFCHR | S_IRUGO | S_IWUGO, &lp_fops, NULL); printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, (port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven");#ifdef CONFIG_LP_CONSOLE if (!nr) { if (port->modes & PARPORT_MODE_SAFEININT) { register_console (&lpcons); console_registered = port; printk (KERN_INFO "lp%d: console ready\n", CONSOLE_LP); } else printk (KERN_ERR "lp%d: cannot run console on %s\n", CONSOLE_LP, port->name); }#endif return 0;}static void lp_attach (struct parport *port){ unsigned int i; switch (parport_nr[0]) { case LP_PARPORT_UNSPEC: case LP_PARPORT_AUTO: if (parport_nr[0] == LP_PARPORT_AUTO && port->probe_info[0].class != PARPORT_CLASS_PRINTER) return; if (lp_count == LP_NO) { printk("lp: ignoring parallel port (max. %d)\n",LP_NO); return; } if (!lp_register(lp_count, port)) lp_count++; break; default: for (i = 0; i < LP_NO; i++) { if (port->number == parport_nr[i]) { if (!lp_register(i, port)) lp_count++; break; } } break; }}static void lp_detach (struct parport *port){ /* Write this some day. */#ifdef CONFIG_LP_CONSOLE if (console_registered == port) { unregister_console (&lpcons); console_registered = NULL; }#endif /* CONFIG_LP_CONSOLE */}static struct parport_driver lp_driver = { "lp", lp_attach, lp_detach, NULL};int __init lp_init (void){ int i; if (parport_nr[0] == LP_PARPORT_OFF) return 0; for (i = 0; i < LP_NO; i++) { lp_table[i].dev = NULL; lp_table[i].flags = 0; lp_table[i].chars = LP_INIT_CHAR; lp_table[i].time = LP_INIT_TIME; lp_table[i].wait = LP_INIT_WAIT; lp_table[i].lp_buffer = NULL;#ifdef LP_STATS lp_table[i].lastcall = 0; lp_table[i].runchars = 0; memset (&lp_table[i].stats, 0, sizeof (struct lp_stats));#endif lp_table[i].last_error = 0; init_waitqueue_head (&lp_table[i].waitq); init_waitqueue_head (&lp_table[i].dataq); init_MUTEX (&lp_table[i].port_mutex); lp_table[i].timeout = 10 * HZ; } if (devfs_register_chrdev (LP_MAJOR, "lp", &lp_fops)) { printk ("lp: unable to get major %d\n", LP_MAJOR); return -EIO; } devfs_handle = devfs_mk_dir (NULL, "printers", NULL); if (parport_register_driver (&lp_driver)) { printk ("lp: unable to register with parport\n"); return -EIO; } if (!lp_count) { printk (KERN_INFO "lp: driver loaded but no devices found\n");#ifndef CONFIG_PARPORT_1284 if (parport_nr[0] == LP_PARPORT_AUTO) printk (KERN_INFO "lp: (is IEEE 1284 support enabled?)\n");#endif } return 0;}static int __init lp_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();}static void lp_cleanup_module (void){ unsigned int offset; parport_unregister_driver (&lp_driver);#ifdef CONFIG_LP_CONSOLE unregister_console (&lpcons);#endif devfs_unregister (devfs_handle); devfs_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); }}__setup("lp=", lp_setup);module_init(lp_init_module);module_exit(lp_cleanup_module);MODULE_LICENSE("GPL");EXPORT_NO_SYMBOLS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -