How I came to write this driver

I once mentioned to a friend that I would someday like to write a device driver. A couple of days later he hands me an old isa card and tells me that it is a dcf77 receiver (Like that would explain it). He elaborates, explaining that it is a card that receives the signal of a transmitter in Germany which transmits the time of an atomic clock. He once thought it would be nice to have Linux support for it so that he could use it to build his own time server at home to synchronise his machines. But since he got decent cable internet access he started using internet time servers and the card became obsolete. So, if I was interested could have it and try to make it work.
Hmmm ok, interesting! Then I forgot about it for a couple of months.

Writing the driver

Later when I got decent internet access, I somehow got to looking into how to write a device driver again and Google was nice enough to point me to an online version of a book on writing kernel drivers for Linux on the O'Reilly site.

After reading some pages of the book online I decided to buy it (which goes to show: online publishing is a good thing). Less than two weeks later a package from Amazon arrived. Woohoo! I start reading and can't wait to get started (I was at work at the time :)

That saturday as soon as I got out of bed (early afternoon) I started out. At first by the book, copying the simple examples and compiling them (making my first 'hello world' module). Then after numerous compile errors (probably because I was smart enough to compile against older kernel sources (d'Oh!)), I decided to skip the basic examples since they were easy enough to understand anyway. I skimmed through the book to find the parts dealing with hardware access and the like. I started out simple and just abused the module_init and printk functions to pry around the hardware somewhat.

Sure enough, accessing the default port (0x310) appeared to work. The mentioned functions return no error codes and the machine keeps running. Next I read some more about hardware access and in particular the part about read and write requests being reordered by the CPU. Hmmm... I do NOT want that to happen. Luckily the book explains about memory barriers, asserting that certain instructions are completed before execution is resumed.
Ok, so that takes care of the function to actually send a command to the card and read a response. Nice.

After some additional experimenting with MSRs (machine specific registers), as mentioned in the book, I once again find out just how slow hardware access is. Just the time between sending a command to the card and waiting for an anwer to be ready takes around 80000 clock cycles on my P3 700. Sure, it is less than a millisecond, so I have plenty of time to read all the data I want. (About half a second).

By then I was contemplating whether to let it rest till the next day before taking the big leap and make it something actually useful by implementing the read method and make it a character device driver.
Nah, who needs sleep anyway
That is when I found out that the real fun starts when you want to exchange data between kernel and user space.

Checking provided pointers to data in user space and actually transferring the data to user space takes up a big chunk of the code of a read function. Considering that that was the only point where I HAD to deal with user space I found it less of a problem if that was just about all it had to do.

After that I registered the driver with the kernel and asked it for a major device number. /proc/devices told me that it was 254. One mknod /dev/dcf77 c 254 0 later I got my access point to my driver. cat /dev/dcf77 told me that I had something to take care of. The cat program opened the device and kept requesting data waiting for an end of file. Hmmm forgot about that :( So I made the read method update the file position and made it return eof if it got a request with a file pointer not set to zero. That seemed to do nicely.

The final product allowed me to do a date -s "`cat /dev/dcf77`" to set both the time and date to the values provided by the card.

Needless to say that early that sunday morning (around 02:30) I was pretty tired but very happy to be able to send my friend a mail with a few lines showing him that the driver worked.

The End

I have had great fun writing my first device driver. Who knows, maybe someday someone else has a piece of ancient hardware. One can hope.





Hosted by SourceForge.net Logo

Thank you generous hosts!- Duke Henry the Red in Sam Raimi's Army of Darkness