Unix people who've been around for a while know that Unix devices have device numbers , and that device numbers are divided into major and minor device numbers. When you do '
ls -l /dev/null
' and one of the fields that
ls
prints is two comma separated numbers, those are the major and minor numbers (on Linux, they are '1, 3'; this varies by Unix). Device numbers and their split into major and minor parts go back a long way, to before Research Unix V7, but V7 makes a convenient point to look at what they meant and how they worked in the original Unixes.
As various sources will tell you, the major number tells you (and the Unix kernel) what sort of device it is and thus what device driver to use to talk to it, while the minor number tells the device driver what specific bit of hardware it's responsible for that you want to talk to. Sometimes the minor number also determines some bit of functionality. Because V7 was a deliberately simple and brute force system and kernel, major device numbers had a very simple implementation. We can see it in the generated V7 kernel configuration file
c.c
:
struct bdevsw bdevsw[] =
{
nulldev, nulldev, rkstrategy, &rktab, /* rk = 0 */
nodev, nodev, nodev, 0, /* rp = 1 */
[...]
nodev, nodev, nodev, 0, /* hp = 6 */
htopen, htclose, htstrategy, &httab, /* ht = 7 */
nodev, nodev, nodev, 0, /* rl = 8 */
0
};
What we're seeing here is that V7 literally had an array of
bdevsw
structures indexed by the major (block) device number, with various function that were called when you did things like open a device (in
fio.c
). There was a similar array for character devices, the
cdevsw
array. In both of them, what driver functions were listed here instead of stubbed out were determined by simple configuration files ( here ) that said what devices you had (among other things).
(The
c.c
file was generated by a program . The particular
c.c
file in the TUHS V7 tree was built with only two block devices configured, the RK disk driver and TJU16 tape driver 'ht' .)
In V7 the minor device number was only interpreted by the device driver, as far as I can see. Device drivers used this for a variety of purposes. For instance, the
mem
character driver implemented
/dev/null
as minor device 2, to go along with access to physical memory and kernel memory. The
rl
disk driver used the minor device number to decide what physical disk it was talking to (it supported up to four of them). Once V7 started getting out in the world, other people wrote drivers for it (such as the RX02 floppy disk driver ) that used minor device numbers both to select what to talk to and control what features to use.
(There's also the
kl
KL/DL-11 serial and console driver , which seems to deal with three different sets of hardware control registers based on the minor number.)
The
/dev/tty
character device was implemented in a clever and very short way in
sys.c
. In V7, there were no pseudo-ttys and no hot-plugged devices, so your underlying physical terminal device always existed and was recorded in your
u
area (see
user.h
) The general tty driver simply used this recorded device number of your controlling tty to call its open, read, write, and ioctl functions through the
cdevsw
array. As far as I can tell, this driver paid no attention at all to the minor device number; as long as
/dev/tty
had major number 7, the minor number was irrelevant.
PS: Note that V7 device drivers tended to be a little relaxed about error checking for their minor device numbers (and other things). For instance, as far as I can tell the
mem
driver actually only distinguishes between minor number 2, minor number 1, and 'everything else', which is treated as minor number 0, giving access to physical memory.