vlrugvg@dutrun.UUCP (Ge van Geldorp) (06/01/90)
I'm trying to write a device driver for AIX PS/2 1.1 and find the IBM documentation (Appendix C of the Technical Reference) less than clear. Sometimes the documentation even seems to lie: - It says to compile the driver with the command `cc -c -DKERNEL -Di386 driver.c'. You better add a `-I/usr/include/sys' to this. - The discussion of `ddopen' says the `oflag' argument of the open(2) system call is passed as the `flag' argument to `ddopen'. Most of the bits get passed unmodified, however, the O_RDONLY flag has the value 0 when passed to open(2), but `ddopen' receives a value of 1. O_WRONLY and O_RDWR also exhibit this behaviour. - subyte() is documented to return 0 if the address at which the byte is to be stored is valid, -1 otherwise. It seems that subyte() actually returns the byte which it stored (i.e. the `c' parameter). I looked around /etc/master to find an unused major number. My system had major values in the range 0-49, so I picked 50 as the major number of my driver. This resulted in lots of `no such device or address' messages. In dispair, I tried 19 as my major number (19 was not used in the /etc/master file). Presto, end of problem. Does this mean there is a hard-coded maximum major value of 49 somewhere? If so, is this documented anywhere? Suppose (well, don't suppose, I actually do this) I tell an adapter to do something, then go to sleep, to be waken up from an interrupt routine. Is there a race condition here? I.e. if the adapter immediately generates an interrupt before the user-context routine goes to sleep, will the wakeup() specifying a channel for which there is no correspon- ding sleep() yet be discarded or will the information be saved? Could someone please provide an example of the use of the physio() routine? The 2-line explanation in the documentation is not sufficient for me to determine how to call this routine. Thanks. Ge van Geldorp ge@dutlru2.tudelft.nl ...!uunet!hp4nl!dutlru2.tudelft.nl!ge
tif@commlab1.austin.ibm.com (/32767) (06/01/90)
In article <1517@dutrun.UUCP> ge@dutlru2.tudelft.nl (Ge van Geldorp) writes: >Suppose (well, don't suppose, I actually do this) I tell an adapter to >do something, then go to sleep, to be waken up from an interrupt I've been told and make the habit of doing it like this: disable_interrupts(); while (need_to_sleep()) /* might be "if" */ sleep(); enable_interrupts(); Interrupts are enabled for the duration of the sleep. -- ------ .--. .- ..- .-.. -.-. .... .- -- -... . .-. .-.. .- .. -. Paul Chamberlain IBM VNET: sc30661@ausvm6 IBM OTHERNET: tif@doorstop Austin, TX 78758 ...!cs.utexas.edu!ibmaus!auschs!doorstop.austin.ibm.com!tif (512) 838-7008 Disclaimer: None of the above are official words of IBM
buck@siswat.UUCP (A. Lester Buck) (06/03/90)
In article <1517@dutrun.UUCP>, vlrugvg@dutrun.UUCP (Ge van Geldorp) writes: > I'm trying to write a device driver for AIX PS/2 1.1 and find the IBM > documentation (Appendix C of the Technical Reference) less than clear. > Sometimes the documentation even seems to lie: > - It says to compile the driver with the command `cc -c -DKERNEL -Di386 > driver.c'. You better add a `-I/usr/include/sys' to this. Yes, but this hardly takes much time to notice. > - The discussion of `ddopen' says the `oflag' argument of the open(2) system > call is passed as the `flag' argument to `ddopen'. Most of the bits > get passed unmodified, however, the O_RDONLY flag has the value 0 > when passed to open(2), but `ddopen' receives a value of 1. O_WRONLY > and O_RDWR also exhibit this behaviour. The kernel adds one to flag before passing it to the driver. This gives independent READ and WRITE bits, easier to test, but different from a stock driver interface. And, alas, not documented. > - subyte() is documented to return 0 if the address at which the byte > is to be stored is valid, -1 otherwise. It seems that subyte() > actually returns the byte which it stored (i.e. the `c' parameter). Haven't experienced this one... The one I lost most time over was the backwards documentation for "well-behaved" ioctl's. (They weren't.) The examples #define TIOCGETD _IOW(t, 0, int) /* get line discipline */ ...etc... are backwards. I.e., _IOR gets, _IOW puts. The correct definitions are in the ioctl header file. (This was for V1.1, but I think I checked the new V1.2 manuals available now and the same documentation error was there.) Since there are no examples of actually using these well-behaved ioctl's, I was shooting blind as to why it wasn't working. The idea is very nice, though, with the kernel doing all necessary copying before the driver ioctl() routine is even called, and putting results into user space after the ioctl() routine finishes. There are some ioctl's which do not fit into this scheme. For example, Lachman Associates (now part of ISC) distributed a set of standard ioctl's for Ethernet drivers talking with their TCP/IP stack. Several ioctl's were of a form which passed a count N and returned the first N bytes of an internal structure, such as the multicast table. This is not possible to encode in the "well-behaved" ioctl scheme of AIX (and BSD and SunOS and ...). But then this Lachman scheme is not a well designed ioctl interface. One trick is how to do an ioctl that returns a value directly, such as IOCTYPE, that every AIX driver should (theoretically) support. Here you write the return value into part of the u structure and it is passed back to the caller, unless u.u_error is also set. > I looked around /etc/master to find an unused major number. My system > had major values in the range 0-49, so I picked 50 as the major number > of my driver. This resulted in lots of `no such device or address' > messages. In dispair, I tried 19 as my major number (19 was not used in > the /etc/master file). Presto, end of problem. Does this mean there is a > hard-coded maximum major value of 49 somewhere? If so, is this > documented anywhere? A little history: At one point, AIX/RT 2.2.1 had a monster design defect where they stored the file system type (AIX or DOS(!)) in the high bits of the major number. We were using a development machine that had software loaded for about every adapter available on the RT and after adding major number 32 (AIX merges block and character device switch tables), all hell broke loose. Turns out the kernel masks the 32 -> 0, and guess which device is major 0? The Disk... (Where is that damn VRM maintenance disk?) IBM managed to hack around some and kludged things so that character numbers could go to 256, but block numbers still had to be below 32. And they whined that to fix this for real would require updating virtually every module in the kernel... The simple answer to your question is to not add major numbers by hand. The official way is to use the cfgadev() library routine, which "knows" how to find free major numbers by reading /etc/master. As far as a limit of 50, I have never heard of that. I assume you did mknod the special file for your driver and the driver does a [CB]DEV_INSTALL to put it in the switch table in its ddinit routine. Was the major number in /etc/master when you built the kernel? (If you want to have fun on the RT, try filling up below 32 with character devices, then ask cfgadev() to add a block device. It would merrily hose your kernel without checking... Note: the RT and the PS/2 are not the same kernel code.) > Suppose (well, don't suppose, I actually do this) I tell an adapter to > do something, then go to sleep, to be waken up from an interrupt > routine. Is there a race condition here? I.e. if the adapter immediately > generates an interrupt before the user-context routine goes to sleep, > will the wakeup() specifying a channel for which there is no correspon- > ding sleep() yet be discarded or will the information be saved? The standard method is to surround your code with an splN that blocks interrupts at the device's level. Something similar to: s = spl?(); start_device_working(); while( not_ready_to_awaken() ) { sleep(); } splx(s); Presumably an interrupt routine or watchdog timer will finally post a wakeup and set the condition that causes the while loop to be exited. While the process is sleeping and some other process is executing, the interrupt level is at the level of that other process, whatever that might be. > Could someone please provide an example of the use of the physio() > routine? The 2-line explanation in the documentation is not sufficient > for me to determine how to call this routine. Here is the simplest example of using physio from an actual working driver: void mtread(dev) dev_t dev; { physio (mtstrategy, (struct buf *)0, dev, B_READ); } void mtwrite(dev) dev_t dev; { physio (mtstrategy, (struct buf *)0, dev, B_WRITE); } mtstrategy keeps a queue of work to do and buffer addresses where to put the data. Physio allocates a buffer temporarily (but just uses the buffer header), fills in the important stuff for a physical read/write, calls mtstrategy, and does an iowait() inside physio until the buffer is freed by your driver (with an iodone(bp)), then releases the buffer and returns. If you want the man page on physio, look it up in the book "Writing a UNIX Device Driver" or the AT&T Driver Development manuals. -- A. Lester Buck buck@siswat.lonestar.org ...!texbell!moray!siswat!buck
J.Crowcroft@ucl-cs.UUCP (06/10/90)
From: Jon Crowcroft <J.Crowcroft@uk.ac.ucl.cs> >I'm trying to write a device driver for AIX PS/2 1.1 and find the IBM >documentation (Appendix C of the Technical Reference) less than clear. me too...except i'm writing a network device driver and that part of appendix C is even worse...some example code for token ring or ether output has clearly never seen the light of vgrind...or if it has, something went terribly wrong:-)