, Ken Hornstein <kenh@cmf.nrl.navy.mil>
From: Bakul Shah <bakul@netcom.com>
List: port-i386
Date: 03/23/1995 09:16:20
> >C->D == *STROBE high to DATA tri-state == 0.5 us min.
bruce says:
> Do you think the software needs to delay for C->D?
Strictly speaking, yes! Unless we set bit5 of the control
port of a bidir. PIO port right after taking *STROBE away
we don't have to worry about it.
> If it returns from an interrupt handler, a relatively huge delay is hard
> to avoid.
Exactly! But that is fine as the .5us are *minimum* times.
> >E->F == *ACK low to BUSY low == 7 us min.
> >F->G == BUSY low to *ACK high = 5 us min.
H&H (i.e. The Art of Electronics) diagram is not too
specific about these times. But I believe these are *NOT*
minimum times but typical times or perhaps, more likely,
they are *maximum* times. Sorry about misleading you. But
these only matter if you care about *ACK in your software.
> This is worse than I thought. I thought F <= E for "good" printers.
> Many printer manuals hint that F == E (approximately) but don't specify
> exact enough timing. The PC interface has the interrupt line connected
> to **ACK, so the interrupt is acknowledged soon after *ACK is asserted
I think that you are wrong about interrupt line, it is connected
to *ACK, not **ACK. Thus you should get the interrupt when
*ACK is _deasserted_; i.e. at time G for a good printer.
What that means is for a good printer BUSY should be low
(i.e. printer is ready) by the time you are in the interrupt
handler.
> Perhaps the "good" printers bend the spec so that
> the PC interface works better.
I don't think so. My characterizing E->F & F->G delays as
min times threw you off. Sorry!
> Does the software have to worry about *ACK? I think only *BUSY matters
> for sending data to the printer, and *ACK is specified so that
> interrupts and hardware latches can work.
The more I think about it, the more I am convinced that the
key is to keep the STROBE asserted until we see BUSY being
asserted by the printer. Software should not worry about
*ACK at all.
> >To guard against errant printers, lptintr() should check
> >BUSY is low in a timed loop (breakout 5 us or BUSY low).
> >Normal printers won't cause any slow down.
>
> I think such checks should be left to a special test mode.
May be. Let us at least get the good printers working :-)
> >I also noticed that the printer is never reset. Normally I
>
> I think it is reset at boot time (if it is turned on :-).
I think it should be resettable via an ioctl if you think
it is wedged. Even the BIOS has support for this!
ken says:
> Judging from this timing diagram, BUSY should go high before you put *STROBE
> high, right? Maybe a check for this is really what's needed instead of
> a delay from C->D.
I think this should fix it.
> Maybe in a spin loop? (Only check 5 times, for example). What's the "right"
> way to do this?
The next time I can take my machine down I am going to try the
following.
int
lptintr(sc)
struct lpt_softc *sc;
{
int iobase = sc->sc_iobase;
#if 0
if ((sc->sc_state & LPT_OPEN) == 0)
return 0;
#endif
/* is printer online and ready for output */
if (NOT_READY_ERR())
return 0;
if (sc->sc_count) {
u_char control = sc->sc_control;
/* send char */
outb(iobase + lpt_data, *sc->sc_cp++);
inb(0x84);
outb(iobase + lpt_control, control | LPC_STROBE);
sc->sc_count--;
if (NOT_READY()) {
int i = 0;
for (i = 0; i < DELAYCNT; i++) {
inb(0x84);
if (!NOT_READY())
break;
}
if (i == DELAYCNT && NOT_READY_ERR()) {
/* XXX recover... */
}
}
outb(iobase + lpt_control, control);
sc->sc_state |= LPT_OBUSY;
} else
sc->sc_state &= ~LPT_OBUSY;
if (sc->sc_count == 0) {
/* none, wake up the top half to get more */
wakeup((caddr_t)sc);
}
return 1;
}
/* send char */ onto the taking away of the STROBE needs to be
put in a separate routine that is also used by the polling code.