Subject: Re: TTY virtualization driver
To: None <tech-kern@netbsd.org>
From: Greg A. Woods <woods@weird.com>
List: tech-kern
Date: 01/23/2002 01:55:29
[ On Wednesday, January 23, 2002 at 06:08:02 (+0100), wojtek@chylonia.3miasto.net wrote: ]
> Subject: Re: TTY virtualization driver
>
> > But, this aside, *yes, two drivers for the same port*.   Have you looked
> > at your SCSI configuration lately?  How about your NIC card or your
> > video card?
> what about? one driver for one device.

OK, let's pretend we have "foo", "bar", and "bit" boards, each of which
provide some multiple number of tty ports, and several of each might be
installed in our theoretical machine.

	foo* at pci?
	bar* at pci?
	bit* at pci?

Traditionally we would then have three major numbers assigned to these
drivers, and some minor-number allocation scheme which allows some
related algorithm in /dev/MAKEDEV to create nodes with predictable names
for each set of cards and we would have something like "/dev/ttyXCY"
where 'X' is one of "foo", "bar", or "bit", or some abbreviation of them
such as "F", "B", and "b"; and 'C' is perhaps the card identifier
(eg. for multiple cards) and 'Y' is the port identifier on the card.

This is all well and good, except it's very messy in /dev, and tty
allocation and assignment algorithms have to know every possible value
of 'X', etc., etc., etc.  Depending on what you use ttys for, how
flexible the software you use with them is, how many you have, how often
you might have to change or add boards, etc., this may or may not be an
issue for you.

Now if there were a separation of low-level serial-port drivers and
high-level tty interfaces, then we could have:

	foo* at pci?
	bar* at pci?
	bit* at pci?

	tty* at foo? port ?
	tty* at bar?
	tty* at bit? port ?

and then there'd just be /dev/ttyN where 'N' was some number (in
whatever base you like), and user-level things that desire to allocate
and assign ttys need only know how to count and new values of 'X' can be
introduced merely by re-configuring the kernel alone.

I personally think there's more benefit to doing this kind of name
mapping in ttys, network interfaces (at least per physical layer type),
audio interfaces, and anything else that's more likely to be used
directly by ordinary (non-superuser) users, than there is to do it for
the likes of SCSI devices (especially since it's not been done for all
types of disks in general like it is in certain other common derivatives
of Unix).

If I'm not mistaken currently only audio devices, SCSI bus devices (but
not disks, tapes, etc., generically), and potentially wscons devices,
and I suppose USB buses, etc., are truly generically mapped to specific
instances of underlying lowlevel hardware drivers.  Eg. you can access
any and every audio device through the appropriate device node with the
same major number no matter what type chip it uses, or what type bus
it's plugged into, etc.  Same for any given class of USB device, SCSI
device, etc.

Obvioulsy in any kind of layered mapping scheme like this the drawback
is that you've got to hard-wire your kernel configuration if you want
specific pieces of hardware to attach to given sets of names.  However
in a truly platform independent kernel, especially when some target
architectures cannot reliably identify a mapping between controller
instances and physical slots, etc., this is about the best you can hope
for.

For example in my theoretical machine the "foo" cards might be 4-port
cards, the "bar" cards might be single-port units on multi-function
cards, and the "bit" cards might be four-port 64-bit cards, and I've got
two PCI buses, pci1 being the 64-bit one.  I'll include generic entries
so that I can plug new cards in and test them and discover their PCI
mapping before I have to build a new kernel.  I think the following
would be a potential example of a wired-down kernel configuration:

	foo0 at pci0 dev 4 function 0
	foo1 at pci0 dev 5 function 0
	foo* at pci? dev ? function ?
	bar0 at pci0 dev 7 function 4
	bar1 at pci0 dev 7 function 5
	bar2 at pci0 dev 8 function 4
	bar3 at pci0 dev 8 function 5
	bar* at pci? dev ? function ?
	bit0 at pci1 dev 4 function 0
	bit1 at pci1 dev 5 function 0
	bit* at pci? dev ? function ?

	tty00 at foo0 port 0
	tty01 at foo0 port 1
	tty02 at foo0 port 2
	tty03 at foo0 port 3
	tty04 at foo1 port 0
	tty05 at foo2 port 1
	tty06 at foo3 port 2
	tty07 at foo4 port 3
	tty08 at bar0
	tty09 at bar1
	tty10 at bar2
	tty11 at bar3
	tty12 at bit0 port 0
	tty13 at bit0 port 1
	tty14 at bit0 port 2
	tty15 at bit0 port 3
	tty16 at bit1 port 0
	tty17 at bit1 port 1
	tty18 at bit1 port 2
	tty19 at bit1 port 3
	tty* at foo? port ?
	tty* at bar?
	tty* at bit? port ?

(Note that if one wanted to burn minor numbers to define maximum-sized
ranges then you could have direct mapping between a group of digits in
the tty name, both in the kernel config and in the device nodes, and
some specified number used to identify the controller, perhaps by slot
or count or whatever, eg. ttyCCCNNNN where 'CCC' is the controller
number and 'NNNN' is the port number, and we assume there are never
going to be controllers with more than 9999, or 0xFFFF, etc., ports on
any given controller.  That way there could still be some easy-to-learn
logic for the physical-to-/dev mapping for a given system architecture
and implementation.)

Without too much additional complication we could also supply a generic
API so that an ioctl() on a /dev/ttyN would tell what low-level driver
instance it was attached to, either by device number, or even by
"config" name, eg. "bit1", and then by convention an application could
know that it could get direct access to the low-level driver associated
to a given /dev/ttyN for doing special control operations not supported
by the tty driver by directly opening /dev/bit1 (for example).

Now if we could do the same for all IP capable network interfaces, and
maybe even generically for all block-addressed secondary storage devices
(aka disks and things that behave logically like them), then we'd really
be getting somewhere.  For example something like logical disk devices
("ld*") should be able to point at any kind of disk controller, not just
hardware RAID controllers, including SCSI disks.

-- 
								Greg A. Woods

+1 416 218-0098;  <gwoods@acm.org>;  <g.a.woods@ieee.org>;  <woods@robohack.ca>
Planix, Inc. <woods@planix.com>; VE3TCP; Secrets of the Weird <woods@weird.com>