...making Linux just a little more fun!
Rick Moen [rick at linuxmafia.com]
Wed, 6 Sep 2006 11:20:17 -0700
boggle
----- Forwarded message from ronan at iaa.es -----
Date: Wed, 6 Sep 2006 19:07:10 +0200 To: ilug at linux.ie From: ronan@iaa.es To: TAG <tag@lists.linuxgazette.net> Subject: [ILUG] Porting drivers from Windows (rant)
Hi all, I'm currently writing Linux support for a piece of custom hardware - I have Windows source code for hardware drivers and data conversion algorithms, and I'm porting/re-writing that to Linux and I am beyond unhappy at some of the intrinsically stupid things I am seeing.
Today's little bundle of joy regards writing to device registers. It's not actually so complicated - the I/O regions are set up automagically during boot, your driver basically just has to tell the kernel (a) that it now owns the appropriate region, and (b) how it wants the region to be made visible to it. Then you go and poke the registers that live there, and the hardware goes and does what you said to. Drive carefully.
Now, in the Windows driver, there is a little snippet of code like the following. It's part of the wake-up sequence for the hardware:
#define CTR_REG 0x4000 ... WRITE_REGISTER_ULONG(CTR_REG,0);How obvious - it writes the value 0 to a 32-bit register located at 0x4000. This is kindergarten stuff. If you don't believe me, read this page: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/Kernel_r/hh/Kernel_r/k103_af58a3ec-4102-4a89-9c58-e56f99d793d0.xml.asp
which says (the very first line): The WRITE_REGISTER_ULONG macro writes a ULONG value to the specified address.
So, yea, we nod wisely, and write the equivalent under Linux, which happens to be
iowrite32(0,CTR_REG);And yea, we would make many attempts to get a response. We would poke and prod. We would reboot into Windows and check that the hardware still worked. Was the hardware sulking because we missed some vanishingly obscure initialisation step? We would examine our documentation again and again - was it possible? We would try and trick the damn thing. We would sacrifice goats. Nada. Not a whisper of response.
Because, of course, the register isn't at 0x4000 at all.
It is (where else?) at 0x10000 (i.e. 0x4000 * 4).
Think about it...... and let the nausea sink in.
For those it hasn't hit yet, some genius in Redmond decided that, when talking about 32-bit quantities, they were going to count 32-bits at a time, like C array notation. ("Hey Bill! I know this really cool way of implementing WRITE_REGISTER_ULONG!"). Of course, they're still going to call them "addresses".
Of course, this means:
- the value 0x4000 is now mercifully free of the ravages of MEANING. It's useless now, unless the programmer separately knows that it refers to a 32-bit quantity. - what a pointer refers to can't be changed without a conversion function. - they've created a new class of bugs that the compiler can't catch. - rather than being opaque or confusing, the code now deceives anybody who isn't from their part of town (for 2 days of zero progress, in my case) - But hey! It'll be dead easy to implement!I don't know whether this crock of stupidity is the worst I'm going to see, but for oh-so-carefully using the word "address" in the documentation, they get maximum fscking points for style.
Regards
Ronan
-- Irish Linux Users' Group mailing list About this list : http://mail.linux.ie/mailman/listinfo/ilug Who we are : http://www.linux.ie/ Where we are : http://www.linux.ie/map/