APLawrence.com -  Resources for Unix and Linux Systems, Bloggers and the self-employed

Tony Lawrence: SCO Device Drivers Part III

Previous: SCO Device Drivers

All you have to do is install it and get it to co-exist happily with all the other drivers. Most of the time you aren't even particularly concerned about that, either: you just run "custom" or "xinstall" and watch the kernel re-link. But, things can go wrong, and when they do, it's helpful to have an understanding of how it's all supposed to work.

Let's take a look over in /etc/conf/cf.d. If you've ever re-linked a kernel outside of Sysadmsh, you've been here before. The "configure" and "link_unix" programs live here, and then there's all the confusing stuff like "mtune" and "stune" and more. For the purposes of this article, only "mdevice" and "sdevice" are of interest.

The "mdevice" file contains information about every device driver available to the system, whether or not the device is actually installed or is being used. The "sdevice" file contains slightly different lines describing everything that is actually installed. You might think that the "sdevice" file is pretty important, but actually it gets rebuilt (from the components found in /etc/conf/sdevice.d) every time you run "link_unix", so you can feel free to clobber it or remove it if that will help you vent any frustration you may be having getting a kernel to link. The "mdevice" file is NOT rebuilt, so let's not get too frustrated!

You can tell quite a bit from the "mdevice" file. First, since it's not rebuilt from components, and it's not sorted in any way, the last line in the file is the last device driver added. Therefore, if you are having a problem linking in Device X, the first place you can look for information is at the end of "mdevice".

For example, here are the last three lines of my "mdevice":

ss8 ocrwiI ictH ss8 0 70 40 160 -1

chr1 rI ic chr1 0 71 1 1 -1

lp2 ocIw icoHr lp2 0 6 1 3 -1

The "ss8" line is my 8 port serial card, and the other two lines are simple device drivers that I wrote in conjunction with this article. What does the "ss8" line tell us about the multiport card? Well, the first field after the name tells us the routines that are used in the driver. This driver has Open, Close, Read, Write, Ioctl and an Initialization routine. You would tend to expect that a driver handling serial ports would have to have all of these. Contrast this with the "lp2" driver (a driver for the parallel port), which does not have any Read or Ioctl functions. This makes sense: do you read from your printer very often?

Another way to get the functions for the "ss8" driver would be to type "/etc/conf/cf.d/routines /etc/conf/pack.d/ss8/Driver.o". If there were a disagreement (no ss8write listed by "routines", for example), you might suspect that the Driver.o file was damaged or possibly just wasn't really the "ss8" driver!

The next column tells us that this device is Installable, is a Character device, handles Tty's, and controls Hardware. That all sounds reasonable for a multiport card. Note that "lp2" has an "r" in this column. This means that the device is "required": it must be present in the kernel.

Following this are fields that give us Block Major and then Character Major numbers for the device. These numbers show up when we do an "l" of the /dev/ss8:

crw-rw-rw- 1 root root 70,255 Aug 14 13:18 /dev/ss8

The meaning of the Major number is simply that this is how the Kernel finds the "ss8" driver in itself. Remember that all the drivers are linked together to make one Kernel. When access is made to /dev/ss8, the major number is the index that tells Unix what section of itself will handle this device. It should be apparent from this that two devices cannot share the same major number! It's also true that if /dev/ss8 somehow got marked as "71,255", the proper driver code would not be executed. That's not likely to happen on an install because the utilities that are usually used assign the major number and (in most cases) the driver neither knows or cares what number is assigned. However, a poor installation procedure might end up conflicting with an existing driver. Since the driver shouldn't care what the major is, you could probably change it (in "mdevice") and re-link successfully.

There is also the possibility that the install created no devices. In other words, there is a driver legitimately linked into the kernel, but nothing in "/dev" to reference it! The directory "/etc/ conf/node.d" should contains files that specify what devices need to be created for each driver. When "link_unix" asks you if you "want the kernel environment rebuilt?", it's offering to recreate /dev based on the contents of these files. For example, here are the first few lines from "/etc/conf/node.d/ss8":

ss8 ss8 c 255
ss8 ttyaa c 0
ss8 ttyab c 1

Note that this does not list major numbers, only minor (the "255" of the "70,255" listed for /dev/ss8). Minor numbers are passed to the device driver code when the kernel calls it. As is seen here, ttyaa is minor 0, while ttyab is minor 1. This allows the same piece of driver code differentiate between multiple instance of the same device.

If you know what the minor numbers are supposed to be, you can easily recreate the /dev files even if there is no "node.d" entry. For example, I often see /dev/rct0 wiped out. Usually the driver is linked in the kernel, but something has removed the device. If the major number is 10, a simple "mknod /dev/rct0 c 10 0" will do the trick.

The last three columns of "mdevice" specify the minimum and maximum number of units that can be configured, and the DMA channel used, if any. Obviously there is something rather strange about the "ss8" entry. We can see that it does not use DMA, but it seems that a minimum of 40 units must be configured into the kernel. That might seem to tax the capabilities of your typical 6 or 8 slot motherboard just a tiny bit. But, here we aren't necessarily talking about the single piece of hardware you stick in the machine.

The answer is found in the "sdevice" file. This file is built from the components found in "/etc/conf/sdevice.d". Here is "ss8" from that directory:

ss8 Y 40 0 0 0 0 0 0 0

The "Y" indicates that the device should be configured, and the 40 bears a suspicious resemblance to the 40 that was specified in the minimum units column in "mdevice". To quote from the man page:

"This field can be encoded with a device dependent numeric value. It is usually used to represent the number of subdevices on a controller or pseudo-device. Its value must be within the minimum and maximum values specified in fields 7 and 8 of the mdevice entry."

So why does the Maxspeed SS8 (an 8 port board) use 40 subdevices? Beats me. If you look through your sdevice file you probably won't see anything else with that high a number. If you do, consider that the person who wrote the driver must have had their reasons, so it's probably not something you want to mess with!

For the rest of the fields, it's more interesting to look at "lp2".

lp2 Y 1 2 1 7 378 37f 0 0

Following the number of units we have the Interrupt level, what kind of interrupt scheme will be used, the actual interrupt number (7), followed by memory addresses that the device uses. The first pair of addresses is I/O Port addresses, and the second would be for actual memory addresses. The interrupt scheme (if any) tells whether interrupts can be shared and how they are shared. If you run through your sdevice file, you'll find that very few things share interrupts.

The parallel port uses port addresses (hex) 378 to 3fff. Port addresses are distinguished from memory addresses by the instructions used to read and write data. Port addresses are accessed (in assembly language) by "in" and "out" instructions. Contrast this with memory access which can be accomplished in several different ways using many different instructions.

Earlier I made reference to using "routines" to extract entry points from a Driver.o file. These files are stored in "/etc/conf/pack.d". There is a subdirectory for each driver and within that subdirectory you will find the actual Driver itself. You may also find "space.c" and "stub.c" files. If you've done any C language programming you probably have a good idea what the "space.c" file are for: they are configuration files that can be modified to change the behaviour of a driver by changing the initial values of constants used in the driver. The stubs.c are routines that have to be there but are empty.

So, this is the structure that "link_unix" expects to be in place when it starts pulling things together. As everyone who has ever linked a kernel knows, we all hold our breath just a tiny bit when the linking starts. Things can go wrong, and sometimes it can be more than a little work to get a working kernel.

The first thing that you should do to protect yourself from installation disasters is to verify that you can already link a kernel {I}before{R} you start the installation of a new driver. To do, this, just cd over to /etc/conf/cf.d and (as root) type "./link_unix". If that kernel will not successfully link, you certainly are not going to have a lot of luck with the new driver you are about to install! So make it a habit to check this first: it's boring, time-consuming and usually unnecessary, but someday you may be very glad you did.

Memory and port conflicts absolutely require resolution before even attempting an installation. The documentation for the new card you are installing should tell you the memory addresses used. Your job is to find out if that space is available in your machine. The "hwconfig" program can give you a good start at this, and a simple shell script (Fig. 1) can help too.

                (Figure 1)
"showmem" script
for i in 10 11 12 13 14
case $i in
        10) blk=A;;
        11) blk=B;;
        12) blk=C;;
        13) blk=D;;
        14) blk=E;;
for j in 0 1 2 3
skp=`expr $i \* 4 + $j`
case $j in
        0) echo "       ${blk}0000 contains:";;
        1) echo "       ${blk}4000 contains:";;
        2) echo "       ${blk}8000 contains:";;
        3) echo "       ${blk}C000 contains:";;
dd if=/dev/mem bs=16k skip=$skp count=1 2> /dev/null | hd | sed -n "1,4p" 
done | pg

The "showmem" script will show (if run as root) the contents of each 16K block of memory from A0000 to EC000. If the block is unused, you will get a row of "ff ff ff" as the contents. Otherwise, you will be seeing other characters. Note that while the presence of "ff"'s is a good sign (and the absence definitely means the memory is being used), it really only means that nothing is using that memory just yet, but makes no guarantees that something won't.

The "showmem" script is useful for a sanity check after installing a board, also. Suppose the board is supposed to be at "D0000", but "showmem" still shows hex "ff"'s at that block. It's a pretty good bet the dip switches are set wrong or the documentation is, well, misleading at best.

I discussed having a Major Number conflict above. There is also the possibility of having an interrupt conflict. As was mentioned above, it is possible for devices to share interrupts. However, there are a couple of gotcha's here. First, the drivers for such devices have to operate at the same IPL (Interrupt Priority Level, field 4 of "sdevice"). Secondly, the system has to be advised (through field 5 of "sdevice") that interrupts will be shared. So what can you do if your new driver conflicts with an existing interrupt?

Probably your best bet is to fall back to a defensive position and try to convince one or the other device to use another interrupt. You could get a successful link by jiggering the fields in "sdevice" so that the interrupt is shared, but a successful link doesn't mean your hardware is going to co-exist peacefully!

You might have to consider removing something in order to squeeze your new device in. When multiport cards are present, one or both of the built in COM ports are easy targets. Secondary and even primary parallel ports can often be sacrificed without too much trauma.

© 1998 Anthony Lawrence. All rights reserved.

Got something to add? Send me email.

(OLDER)    <- More Stuff -> (NEWER)    (NEWEST)   

Printer Friendly Version

-> -> SCO Unix Device Drivers Part III

Increase ad revenue 50-250% with Ezoic

More Articles by

Find me on Google+

© Tony Lawrence

Very usefull!!!

Alessandro Monti

Nice to read this.

Mariano Abad

Kerio Samepage

Have you tried Searching this site?

Support Rates

This is a Unix/Linux resource website. It contains technical articles about Unix, Linux and general computing related subjects, opinion, news, help files, how-to's, tutorials and more.

Contact us

A learning experience is one of those things that say, "You know that thing you just did? Don't do that." (Douglas Adams)

This post tagged: