Path: utzoo!utgpu!jarvis.csri.toronto.edu!rutgers!cs.utexas.edu!csd4.milw.wisc.edu!lll-winken!uunet!zephyr!tektronix!tekgen!tekigm2!phils From: phils@tekigm2.MEN.TEK.COM (Philip E Staub) Newsgroups: comp.sys.amiga.tech Subject: Re: help with disk/tape device driver(s) Keywords: device drivers, message ports, tasks Message-ID: <5107@tekigm2.MEN.TEK.COM> Date: 28 Jun 89 19:23:09 GMT References: <1006@olympic.oz> Reply-To: phils@tekigm2.MEN.TEK.COM (Philip E Staub) Organization: Tektronix, Inc., Vancouver, WA. Lines: 107 In article <1006@olympic.oz> enno@olympic.oz (Enno Davids) writes: [questions about device drivers] G'day Enno: Our machine apparently doesn't know how to get to oz, and I don't know the correct routing to do it manually, hence this posting. This is a brief description of a hard disk device driver which I wrote (and am continuing to tinker with). I'm sure it isn't quite the same sort of thing that you're working with, but maybe the structure of the driver will give you some ideas. Basically, I have a module called 'harddisk.device' and partition entries for the hard disk in the mountlist refer to it as their controlling driver. I have split the driver into two logical pieces, for which I have coined the terms 'driver' and 'handler', although they both physically reside in the same file. (I'm not sure that my use of the terms 'driver' and 'handler' are consistent with accepted terminology, so I'll describe the contents and function of each.) The driver consists primarily of a romtag structure, the initialization code and the required entry points for Open, Close, Expunge, Null, BeginIO and AbortIO. It also contains routines to handle functions which don't directly access the disk. These functions are typically things like status reporting or things which are provided for trackdisk.device compatibility, but are really just stubs which return values which won't create errors (or maybe *do* create errors, if that's appropriate). The handler is spun off as a separate process (via CreateProcess()) and a message port is created through which the driver sends requests to the handler. Now, the magic here is that when the driver sends a message to the handler, the message it sends is actually the very same message which was sent to it via the BeginIO call. This being the case, the reply port is the user's reply port, and the handler replies directly to it, instead of to the driver. The bulk of the handler consists of the routines which perform the actual disk I/O operations. Now for a description of the general operation. The first access to one of the hard disk partitions causes 'harddisk.device' to be loaded and the initialization sequence to take place. Note: there are several pre-allocated fields in the 'device' structure which would normally be allocated via AllocMem(), including the MsgPort structure for the handler's message port (which of course includes the list header for the message list), the Task structure for the handler process, the task stack for the handler process, and the Interrupt structure to point to the interrupt service routine. I use the RTF_AUTOINIT flag in the romtag structure to cause automatic creation of the device (alias library) and allocation and initialization of the 'device' structure. The driver initialization sequence looks basically like this in pseudo code: Allocate a signal bit to use for the handler's message port and mark the bit in the MsgPort structure. Initialize the handler's message list to empty Add the handler's message port to the system pool Create the handler process, which causes it to start running, with its own initialization procedure. The handler initialization sets up some registers and the controller hardware, then starts waiting for messages at it's message port. When the driver receives a request via its BeginIO entry point, it determines whether it needs to relay the message on to the handler or to process the request itself. For Quick functions (any function performed by the driver), the driver calls an appropriate routine to perform the requested action, then returns. A ReplyMsg() is not necessary, because the message will be returned with the IO_QUICK flag set. (I suppose I should really be checking the QUICK flag upon entry and doing a ReplyMsg() if it was clear, to support users who might want to call BeginIO() directly with the QUICK flag clear, but I haven't found that to be a problem. Yet.) For Queued functions (any function performed by the handler), the driver clears the QUICK bit in the message flags and calls PutMsg() to send the message to the handler. When this message is received by the handler (remember it may be queued behind other requests), the handler performs the requested disk I/O operation and calls ReplyMsg() to return the request to the user (not the driver). There is a significant difference between the driver process and the handler process. The driver code must be re-entrant. The handler process must *not* be re-entrant. This is because my disk controller hardware can only work on one command at once, even though there may be multiple user processes wishing to perform disk I/O simultaneously (and thus multiple processes may be executing at various points in the driver code). I rely upon the message port to ensure the single-threaded nature of operation of the handler, because it can only be invoked via the message port, and it never asks for a message until all processing from the last command is complete. Well, I hope this information is of some use to you. If there is anything further you'd like to know about my driver, let me know. Regards, Phil -- ------------------------------------------------------------------------------ Phil Staub Tektronix, Inc., Vancouver, Washington 98668 phils@tekigm2.MEN.TEK.COM