Subject: Line disciplines on parallel ports
To: None <tech-kern@NetBSD.ORG>
From: Martin Husemann <firstname.lastname@example.org>
Date: 07/27/1995 14:04:11
How to treat "things hanging off a parallel port"
A short discussion on current-users some time ago initiated the idea to
treat different things hanging off a parallel port in some uniform way.
Chris suggested to think of it as line disciplines for ttys.
I have a notebook (without pcmcia) running NetBSD, so I'm very much
interested in this issue. After exchanging some mails with Chris,
this is the idea I would like to implement. Any comments are welcome,
I'm realy not sure this is the Right Thing (tm) to do.
What is a parallel port?
Here I'm talking about parallel ports designed to connect printers.
Many architectures NetBSD runs on have such a device, probably the
most common version has a 25 pin female D-connector and are connected
to a cable ending in a Centronics connector at the printer's side.
There are several kind of devices you can plug into such a port (maybe
through some kind of cabling):
- PLIP cable (kind of a null-modem cable for parallel ports)
- pocket ethernet adaptors
- SCSI adaptors
Unfortunately, as the parallel port originaly was designed as a unidirectional
device, all these devices use incompatible ways to transfer bytes. This makes
things a bit more complicated than the serial ports, where line disciplines
all use the same (hardware dependend) input/output routines and just decide
what bytes to transfer.
I expect several tradeoffs, so here is my priority list of design
1) device and architecture/machine independance in the line disciplines
2) efficiency (I use a i386 system to root between a PLIP and a SLIP
connection and hope to exchange PLIP with a DE620 ethernet adaptor
soon [and SLIP with PPP])
3) easy addition of new parallel port interfaces (independand of
the supported line disciplines)
4) easy addition of new line disciplines (without having to modify
existing device drivers)
The hardware layer
If I don't miss something obvious, a parallel port can be abstracted into:
(1) 8 bits output D0 - D7
(2) (only on some "bidirectional" hardware) 8 bits input D0 - D7
(3) 4 bits output (STROBE, AUTOLF, INIT, SELECT)
(4) 4 bits input (ERROR, SELECT, PAPEROUT, BUSY)
(5) 1 special bit input (ACK) which can be tied to an interrupt
The pc532 port seems to have a LED indicating "port active", which
is togled by another output bit. I'm ignoring this for the moment,
it could be made available with the same interface.
This gives the hardware drivers interface similar to this:
(1) void writedata(struct softc * dev, int data)
(2) int readdata(struct softc * dev)
(3) void writestat(struct softc * dev, int whichBit, int lowOrHigh)
(4) int readstat(struct softc * dev, int whichBit)
(5) int checkack(struct softc * dev)
void setirq(struct softc * dev, int disableOrEnable)
Since on different architectures the way to access ports differs there
will be macros to declare the relevant part of "struct softc". Also
for some hardware the driver may need to store aditional state info
(if your control port can not be read back, like on the i386, you need
to save the value you wrote to this port to togle single bits later),
which will be done through softc. Probably, for efficiency, there may
be a few shortcut macros for individual line disciplines (reading a 4
bit nibble in the PLIP line discipline from the status port can be
done with a single statement on i386 and pc532, but needs several
statements when done bitwise with the generic interface).
The software layers
There are line discipline dependend parts in the hardware interface
implementation, so I would use three parts to build a driver:
a) a hardware description "lpt.c" defining the hardware dependend
part as a set of macros and (maybe) some functions; ending
with #include "ppinterface.c". This is hardware dependend but
line discipline independent (well, maybe with few exceptions).
b) a glue module "ppinterface.c", which uses the hardware dependend
macros to declare the generic interface structures and implement
the needed interface dependend routines. This is hardware independand
but line discipline dependend.
c) one or more global modules implementing the different line disciplines
using the structures defined by "ppinterface.c". This is/are the generic
interface(s) to the kernel.
Between (b) and (c) comunication would be very simmilar as in serial tty's
line disciplines, while separating (b) from (a) makes (a) independend of
the available line disciplines.
>From the users point of view you either have one device per line
discipline sharing the same hardware (like /dev/lp0 and plip0 do in
the existing implementation) or have one network, on block and one
character device for each port (you can't avoid that, I guess) and a
"ppconfig" tool to switch the device between the different line
disciplines. If you don't have too many different network line disciplines
configured, the former would be more convenient, while the later is
the cleaner solution (hmm, I'm not realy sure).
Well, what do you think?