Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 4 Apr 1996 14:37:00 +0200 (MET DST)
From:      J Wunsch <j@ida.interface-business.de>
To:        freebsd-current@FreeBSD.org (FreeBSD-current users), bdodson@beowulf.utmb.edu (M. L. Dodson)
Subject:   Interrupt-mode lpt driver and HP printers
Message-ID:  <199604041237.OAA00366@ida.interface-business.de>

next in thread | raw e-mail | index | archive | help
Many people recently complained that they could not use the lpt driver
in interrupt mode with newer HP DeskJet or LaserJet printers.  The
printer went awfully slow, while polled mode works fine.

Now i've finally got my hands on a DeskJet 600 (customer's device :),
and could reproduce the problem myself.  I seem to have found a
suitable workaround, and have just committed a fix for it.  I would
ask people to test it.  If it works, i'll also commit this one to the
-stable branch, since i believe it couldn't do any harm to configur-
ations that used to work before either.  (It could spin-loop a few
milliseconds inside the interrupt routine for owners of HP printers,
but that still seems to be less load than falling back to polled mode
entirely.)

The idea is to wait a moment inside the interrupt routine to see if
the not-yet-ready condition will clear within reasonable time, and if
it doesn't, to use an incrementally backoff timeout instead of the
fixed 1/2 second timeout we've been using previously.


--- lpt.c.orig	Sun Dec 10 14:38:56 1995
+++ lpt.c	Thu Apr  4 14:00:41 1996
@@ -149,7 +149,8 @@
 
 
 #define	LPINITRDY	4	/* wait up to 4 seconds for a ready */
-#define	LPTOUTTIME	4	/* wait up to 4 seconds for a ready */
+#define	LPTOUTINITIAL	10	/* initial timeout to wait for ready 1/10 s */
+#define	LPTOUTMAX	1	/* maximal timeout 1 s */
 #define	LPPRI		(PZERO+8)
 #define	BUFSIZE		1024
 
@@ -221,6 +222,7 @@
 #define LP_HAS_IRQ	0x01	/* we have an irq available */
 #define LP_USE_IRQ	0x02	/* we are using our irq */
 #define LP_ENABLE_IRQ	0x04	/* enable IRQ on open */
+	u_char	sc_backoff ;	/* time to call lptout() again */
 
 #ifdef INET
 	struct  ifnet	sc_if;
@@ -588,7 +590,8 @@
 	lprintf("irq %x\n", sc->sc_irq);
 	if (sc->sc_irq & LP_USE_IRQ) {
 		sc->sc_state |= TOUT;
-		timeout ((timeout_func_t)lptout, (caddr_t)sc, hz/2);
+		timeout ((timeout_func_t)lptout, (caddr_t)sc,
+			 (sc->sc_backoff = hz/LPTOUTINITIAL));
 	}
 
 	lprintf("opened.\n");
@@ -600,9 +603,12 @@
 {	int pl;
 
 	lprintf ("T %x ", inb(sc->sc_port+lpt_status));
-	if (sc->sc_state & OPEN)
-		timeout ((timeout_func_t)lptout, (caddr_t)sc, hz/2);
-	else
+	if (sc->sc_state & OPEN) {
+		sc->sc_backoff++;
+		if (sc->sc_backoff > hz/LPTOUTMAX)
+			sc->sc_backoff = sc->sc_backoff > hz/LPTOUTMAX;
+		timeout ((timeout_func_t)lptout, (caddr_t)sc, sc->sc_backoff);
+	} else
 		sc->sc_state &= ~TOUT;
 
 	if (sc->sc_state & ERROR)
@@ -783,6 +789,7 @@
 {
 	struct lpt_softc *sc = lpt_sc + unit;
 	int port = sc->sc_port, sts;
+	int i;
 
 #ifdef INET
 	if(sc->sc_if.if_flags & IFF_UP) {
@@ -791,9 +798,19 @@
 	}
 #endif /* INET */
 
-	/* is printer online and ready for output */
-	if (((sts=inb(port+lpt_status)) & RDY_MASK) == LP_READY) {
+	/*
+	 * Is printer online and ready for output?
+	 *
+	 * Avoid falling back to lptout() too quickly.  First spin-loop
+	 * to see if the printer will become ready ``really soon now''.
+	 */
+	for (i = 0;
+	     i < 100 &&
+	     ((sts=inb(port+lpt_status)) & RDY_MASK) != LP_READY;
+	     i++) ;
+	if ((sts & RDY_MASK) == LP_READY) {
 		sc->sc_state = (sc->sc_state | OBUSY) & ~ERROR;
+		sc->sc_backoff = hz/LPTOUTINITIAL;
 
 		if (sc->sc_xfercnt) {
 			/* send char */
@@ -820,6 +837,7 @@
 		if(((sts & (LPS_NERR | LPS_OUT) ) != LPS_NERR) &&
 				(sc->sc_state & OPEN))
 			sc->sc_state |= ERROR;
+		/* lptout() will jump in and try to restart. */
 	}
 	lprintf("sts %x ", sts);
 }


-- 
J"org Wunsch					       Unix support engineer
joerg_wunsch@interface-business.de       http://www.interface-business.de/~j



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199604041237.OAA00366>