From owner-freebsd-current Thu Apr 4 04:38:47 1996 Return-Path: owner-current Received: (from root@localhost) by freefall.freebsd.org (8.7.3/8.7.3) id EAA25262 for current-outgoing; Thu, 4 Apr 1996 04:38:47 -0800 (PST) Received: from innocence.interface-business.de (innocence.interface-business.de [193.101.57.101]) by freefall.freebsd.org (8.7.3/8.7.3) with ESMTP id EAA25253 for ; Thu, 4 Apr 1996 04:38:34 -0800 (PST) Received: from ida.interface-business.de (ida.interface-business.de [193.101.57.203]) by innocence.interface-business.de (8.6.11/8.6.9) with SMTP id OAA05167; Thu, 4 Apr 1996 14:40:42 +0200 Received: (from j@localhost) by ida.interface-business.de (8.7.3/8.7.3) id OAA00366; Thu, 4 Apr 1996 14:37:00 +0200 (MET DST) From: J Wunsch Message-Id: <199604041237.OAA00366@ida.interface-business.de> Subject: Interrupt-mode lpt driver and HP printers To: freebsd-current@FreeBSD.org (FreeBSD-current users), bdodson@beowulf.utmb.edu (M. L. Dodson) Date: Thu, 4 Apr 1996 14:37:00 +0200 (MET DST) Reply-To: joerg_wunsch@interface-business.de (Joerg Wunsch) X-Phone: +49-351-31809-14 X-Fax: +49-351-3361187 X-Mailer: ELM [version 2.4 PL23] MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit Sender: owner-current@FreeBSD.org X-Loop: FreeBSD.org Precedence: bulk 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