// SPDX-License-Identifier: GPL-2.0-only /* * Generic parallel printer driver * * Copyright (C) 1992 by Jim Weigand and Linus Torvalds * Copyright (C) 1992,1993 by Michael K. Johnson * - Thanks much to Gunter Windau for pointing out to me where the error * checking ought to be. * Copyright (C) 1993 by Nigel Gamble (added interrupt code) * Copyright (C) 1994 by Alan Cox (Modularised it) * LPCAREFUL, LPABORT, LPGETSTATUS added by Chris Metcalf, [email protected] * Statistics and support for slow printers by Rob Janssen, [email protected] * "lp=" command line parameters added by Grant Guenther, [email protected] * lp_read (Status readback) support added by Carsten Gross, * [email protected] * Support for parport by Philip Blundell <[email protected]> * Parport sharing hacking by Andrea Arcangeli * Fixed kernel_(to/from)_user memory copy to check for errors * by Riccardo Facchetti <[email protected]> * 22-JAN-1998 Added support for devfs Richard Gooch <[email protected]> * Redesigned interrupt handling for handle printers with buggy handshake * by Andrea Arcangeli, 11 May 1998 * Full efficient handling of printer with buggy irq handshake (now I have * understood the meaning of the strange handshake). This is done sending new * characters if the interrupt is just happened, even if the printer say to * be still BUSY. This is needed at least with Epson Stylus Color. To enable * the new TRUST_IRQ mode read the `LP OPTIMIZATION' section below... * Fixed the irq on the rising edge of the strobe case. * Obsoleted the CAREFUL flag since a printer that doesn' t work with * CAREFUL will block a bit after in lp_check_status(). * Andrea Arcangeli, 15 Oct 1998 * Obsoleted and removed all the lowlevel stuff implemented in the last * month to use the IEEE1284 functions (that handle the _new_ compatibilty * mode fine). */ /* This driver should, in theory, work with any parallel port that has an * appropriate low-level driver; all I/O is done through the parport * abstraction layer. * * If this driver is built into the kernel, you can configure it using the * kernel command-line. For example: * * lp=parport1,none,parport2 (bind lp0 to parport1, disable lp1 and * bind lp2 to parport2) * * lp=auto (assign lp devices to all ports that * have printers attached, as determined * by the IEEE-1284 autoprobe) * * lp=reset (reset the printer during * initialisation) * * lp=off (disable the printer driver entirely) * * If the driver is loaded as a module, similar functionality is available * using module parameters. The equivalent of the above commands would be: * * # insmod lp.o parport=1,none,2 * * # insmod lp.o parport=auto * * # insmod lp.o reset=1 */ /* COMPATIBILITY WITH OLD KERNELS * * Under Linux 2.0 and previous versions, lp devices were bound to ports at * particular I/O addresses, as follows: * * lp0 0x3bc * lp1 0x378 * lp2 0x278 * * The new driver, by default, binds lp devices to parport devices as it * finds them. This means that if you only have one port, it will be bound * to lp0 regardless of its I/O address. If you need the old behaviour, you * can force it using the parameters described above. */ /* * The new interrupt handling code take care of the buggy handshake * of some HP and Epson printer: * ___ * ACK _______________ ___________ * |__| * ____ * BUSY _________ _______ * |____________| * * I discovered this using the printer scanner that you can find at: * * ftp://e-mind.com/pub/linux/pscan/ * * 11 May 98, Andrea Arcangeli * * My printer scanner run on an Epson Stylus Color show that such printer * generates the irq on the _rising_ edge of the STROBE. Now lp handle * this case fine too. * * 15 Oct 1998, Andrea Arcangeli * * The so called `buggy' handshake is really the well documented * compatibility mode IEEE1284 handshake. They changed the well known * Centronics handshake acking in the middle of busy expecting to not * break drivers or legacy application, while they broken linux lp * until I fixed it reverse engineering the protocol by hand some * month ago... * * 14 Dec 1998, Andrea Arcangeli * * Copyright (C) 2000 by Tim Waugh (added LPSETTIMEOUT ioctl) */ #include <linux/module.h> #include <linux/init.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/major.h> #include <linux/sched/signal.h> #include <linux/slab.h> #include <linux/fcntl.h> #include <linux/delay.h> #include <linux/poll.h> #include <linux/console.h> #include <linux/device.h> #include <linux/wait.h> #include <linux/jiffies.h> #include <linux/mutex.h> #include <linux/compat.h> #include <linux/parport.h> #undef LP_STATS #include <linux/lp.h> #include <asm/irq.h> #include <linux/uaccess.h> /* if you have more than 8 printers, remember to increase LP_NO */ #define LP_NO … static DEFINE_MUTEX(lp_mutex); static struct lp_struct lp_table[LP_NO]; static int port_num[LP_NO]; static unsigned int lp_count = …; static const struct class lp_class = …; #ifdef CONFIG_LP_CONSOLE static struct parport *console_registered; #endif /* CONFIG_LP_CONSOLE */ #undef LP_DEBUG /* Bits used to manage claiming the parport device */ #define LP_PREEMPT_REQUEST … #define LP_PARPORT_CLAIMED … /* --- low-level port access ----------------------------------- */ #define r_dtr(x) … #define r_str(x) … #define w_ctr(x,y) … #define w_dtr(x,y) … /* Claim the parport or block trying unless we've already claimed it */ static void lp_claim_parport_or_block(struct lp_struct *this_lp) { … } /* Claim the parport or block trying unless we've already claimed it */ static void lp_release_parport(struct lp_struct *this_lp) { … } static int lp_preempt(void *handle) { … } /* * Try to negotiate to a new mode; if unsuccessful negotiate to * compatibility mode. Return the mode we ended up in. */ static int lp_negotiate(struct parport *port, int mode) { … } static int lp_reset(int minor) { … } static void lp_error(int minor) { … } static int lp_check_status(int minor) { … } static int lp_wait_ready(int minor, int nonblock) { … } static ssize_t lp_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { … } #ifdef CONFIG_PARPORT_1284 /* Status readback conforming to ieee1284 */ static ssize_t lp_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { … } #endif /* IEEE 1284 support */ static int lp_open(struct inode *inode, struct file *file) { … } static int lp_release(struct inode *inode, struct file *file) { … } static int lp_do_ioctl(unsigned int minor, unsigned int cmd, unsigned long arg, void __user *argp) { … } static int lp_set_timeout(unsigned int minor, s64 tv_sec, long tv_usec) { … } static int lp_set_timeout32(unsigned int minor, void __user *arg) { … } static int lp_set_timeout64(unsigned int minor, void __user *arg) { … } static long lp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { … } #ifdef CONFIG_COMPAT static long lp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { … } #endif static const struct file_operations lp_fops = …; /* --- support for console on the line printer ----------------- */ #ifdef CONFIG_LP_CONSOLE #define CONSOLE_LP … /* 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 … /* The console must be locked when we get here. */ static void lp_console_write(struct console *co, const char *s, unsigned count) { … } static struct console lpcons = …; #endif /* console on line printer */ /* --- initialisation code ------------------------------------- */ static int parport_nr[LP_NO] = …; static char *parport[LP_NO]; static bool reset; module_param_array(…); module_param(reset, bool, 0); #ifndef MODULE static int __init lp_setup(char *str) { … } #endif static int lp_register(int nr, struct parport *port) { … } static void lp_attach(struct parport *port) { … } static void lp_detach(struct parport *port) { … } static struct parport_driver lp_driver = …; static int __init lp_init(void) { … } static int __init lp_init_module(void) { … } static void lp_cleanup_module(void) { … } __setup(…); module_init(…) …; module_exit(lp_cleanup_module); MODULE_ALIAS_CHARDEV_MAJOR(…); MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;