patch-2.1.27 linux/drivers/char/lp.c
Next file: linux/drivers/isdn/Config.in
Previous file: linux/drivers/block/ll_rw_blk.c
Back to the patch index
Back to the overall index
- Lines: 134
- Date:
Fri Feb 21 14:58:33 1997
- Orig file:
v2.1.26/linux/drivers/char/lp.c
- Orig date:
Sun Jan 26 02:07:16 1997
diff -u --recursive --new-file v2.1.26/linux/drivers/char/lp.c linux/drivers/char/lp.c
@@ -8,6 +8,7 @@
* LPCAREFUL, LPABORT, LPGETSTATUS added by Chris Metcalf, metcalf@lcs.mit.edu
* Statistics and support for slow printers by Rob Janssen, rob@knoware.nl
* "lp=" command line parameters added by Grant Guenther, grant@torque.net
+ * lp_read (Status readback) support added by Carsten Gross, carsten@sol.wohnheim.uni-ulm.de
*/
#include <linux/module.h>
@@ -316,6 +317,116 @@
return -ESPIPE;
}
+/* Test if nibble mode for status readback is okay.
+ * returns false if not, otherwise true
+ */
+static int lp_nibble_mode_ok(int minor)
+{
+ int reply=1;
+
+ outb_p(0, LP_B(minor)); /* Request "nibble mode" */
+ udelay(LP_DELAY);
+ outb((inb(LP_C(minor)) & ~8), LP_C(minor)); /* SelectIN low */
+ outb((inb(LP_C(minor)) | 2), LP_C(minor)); /* AutoFeed high */
+ udelay(LP_DELAY);
+ outb((inb(LP_C(minor)) | 1), LP_C(minor)); /* Strobe high */
+ if (( LP_S(minor) & ~0x80) != 0x38) reply=0; /* expected answer? */
+ outb((inb(LP_C(minor)) & ~1 ), LP_C(minor)); /* Strobe low */
+ outb((inb(LP_C(minor)) & ~2 ), LP_C(minor)); /* Autofeed low */
+ udelay(LP_DELAY);
+ return(reply);
+}
+
+
+static int lp_read_nibble(int minor)
+{
+ unsigned char i;
+ i=LP_S(minor)>>3;
+ i&=~8;
+ if ( ( i & 0x10) == 0) i|=8;
+ return(i & 0x0f);
+}
+
+static void lp_select_in_high(int minor) {
+ outb((inb(LP_C(minor)) | 8), LP_C(minor));
+}
+
+/* Status readback confirming to ieee1284 */
+static long lp_read(struct inode * inode, struct file * file,
+ char * buf, unsigned long count)
+{
+ unsigned char z=0, Byte=0, status;
+ char *temp;
+ int retval;
+ unsigned int counter=0;
+ unsigned int i;
+ unsigned int minor=MINOR(inode->i_rdev);
+
+ temp=buf;
+#ifdef LP_READ_DEBUG
+ printk(KERN_INFO "lp%d: read mode\n", minor);
+#endif
+
+ retval = verify_area(VERIFY_WRITE, buf, count);
+ if (retval)
+ return retval;
+ if (lp_nibble_mode_ok(minor)==0) {
+ lp_select_in_high(minor);
+ return temp-buf; /* End of file */
+ }
+ for (i=0; i<=(count*2); i++) {
+ outb((inb(LP_C(minor)) | 2), LP_C(minor)); /* AutoFeed high */
+ do {
+ status=(LP_S(minor) & 0x40);
+ udelay(50);
+ counter++;
+ if (need_resched)
+ schedule();
+ } while ( (status == 0x40) && (counter < 20) );
+ if ( counter == 20 ) { /* Timeout */
+#ifdef LP_READ_DEBUG
+ printk(KERN_DEBUG "lp_read: (Autofeed high) timeout\n");
+#endif
+ outb((inb(LP_C(minor)) & ~2), LP_C(minor));
+ lp_select_in_high(minor);
+ return temp-buf; /* end the read at timeout */
+ }
+ counter=0;
+ z=lp_read_nibble(minor);
+ outb((inb(LP_C(minor)) & ~2), LP_C(minor)); /* AutoFeed low */
+ do {
+ status=(LP_S(minor) & 0x40);
+ udelay(20);
+ counter++;
+ if (need_resched)
+ schedule();
+ } while ( (status == 0) && (counter < 20) );
+ if (counter == 20) { /* Timeout */
+#ifdef LP_READ_DEBUG
+ printk(KERN_DEBUG "lp_read: (Autofeed low) timeout\n");
+#endif
+ if (current->signal & ~current->blocked) {
+ lp_select_in_high(minor);
+ if (temp !=buf)
+ return temp-buf;
+ else
+ return -EINTR;
+ }
+ current->state=TASK_INTERRUPTIBLE;
+ current->timeout=jiffies + LP_TIME(minor);
+ schedule();
+ }
+ counter=0;
+ if (( i & 1) != 0) {
+ Byte= (Byte | z<<4);
+ put_user(Byte, temp);
+ temp++;
+ } else Byte=z;
+ }
+ lp_select_in_high(minor);
+ return temp-buf;
+}
+
static int lp_open(struct inode * inode, struct file * file)
{
unsigned int minor = MINOR(inode->i_rdev);
@@ -524,7 +635,7 @@
static struct file_operations lp_fops = {
lp_lseek,
- NULL, /* lp_read */
+ lp_read,
lp_write,
NULL, /* lp_readdir */
NULL, /* lp_poll */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov