Path: news.mitre.org!blanket.mitre.org!nntprelay.mathworks.com!peerfeed.ncal.verio.net!news.he.net!newshub.cts.com!newsfeed.cts.com!cmkrnl!jeh From: jeh@cmkrnl.com (Jamie Hanrahan) Newsgroups: comp.os.ms-windows.programmer.nt.kernel-mode Subject: Re: Synchronize Device Driver Message-ID: <1998Jan25.002454.8442@cmkrnl> Date: 25 Jan 98 00:24:54 PST References: <6ae2ku$a8a@bgtnsc02.worldnet.att.net> Organization: Kernel Mode Systems, San Diego, CA Lines: 78 In article <6ae2ku$a8a@bgtnsc02.worldnet.att.net>, Robert Scott Tracy writes: > I currently take care of a device driver and have a need to synchronize > requests to a particular device. Through experience I have discovered > that many devices cannot handle the transition of the asynchronous calls > hitting the device without error. My driver works in conjuction with a > higer level driver that sends requests to me keeping all calls in my > driver at passive level. I currently translate the request to a > particular SCSI or ATAPI command or series of commands, build an > appropriate SRB and send a request down. If the request fails in a > particular manner, I have a completion routine that will retry my > request. My question is what type of method should I use to synchronize > requests to a particular device, realizing there could be several > devices on a system taking requests from my driver and I only wish to > synchronize requests to a device, not requests through my driver. By the way, the word I like to use for what you want to do is "serializing" the requests to the devices, not "synchronizing". I find that use of the word "serializing" really helps people think of the right things to do, much better than the word "synchronizing". If you have a one-to-one correspondence between your device objects and the lower-level device objects to which you're sending requests, it is very simple. Just set up your driver to use a StartIo routine. Call IoStartPacket in your Dispatch routine, and IoStartNextPacket in your completion routine when the driver you're layered on top of tells you a previous IRP is done. Note that your driver dispatch routines will still see the asynchronous requests, in parallel if you want. This does not serialize requests through your driver - only through your device object. ie if you have multiple device objects each can have its own "current IRP". If you have one device object and you're sending requests that come through it to several different lower-level devices -- or, more generally, if you have fewer device objects than lower-level devices -- it is almost as easy: In your device extension, allocate a KDEVICE_QUEUE for each lower-level device. When you're about to send an IRP to one of your lower-level devices, do a KeInsertDeviceQueue on the IRP's DeviceQueueentry field and the appropriate queue. A return status from this call of FALSE tells you that the busy bit in the device queue structure (I hate to call them 'objects') was not already set (but it is now), and the IRP was NOT put on the queue, and you should send the IRP to your lower-level device. (You will probably want to allocate a "current IRP for each device" in your device extension too.) A return status of TRUE says that the busy bit was already set, the IRP was put on the queue, and you shouldn't tell your lower-level device about it yet. When the lower-level driver reports that the IRP is done, you do a KeRemoveDeviceQueue on your device queue that corresponds to the lower-level device. If the queue is non-empty this call will remove the IRP at the head and return the address of the DeviceQueueEntry field from the IRP; you should start this IRP on the lower-level device. If this call returns a NULL the queue was empty, the busy bit is now clear, and you can just return to caller; the next call to KeInsertDeviceQueue on the same queue will return FALSE in that case. Note that there is an error in the doc re KeRemoveDeviceQueue. The doc claims that the return (if non-NULL) is the address of the IRP; in fact it is the address of whatever was on the queue. Usually this is the DeviceQueueEntry within that huge union/struct/union at the end of the IRP. I say "usually" because there is no actual requirement that what you pass to KeInsertDeviceQueue has to be the DeviceQueueEntry field of an IRP - it has to be a pair of LIST_ENTRYs somewhere, but that's the only requirement. --- Jamie Hanrahan, Kernel Mode Systems, San Diego CA Internet: jeh@cmkrnl.com (JH645) CompuServe: 74140,2055 drivers, internals, networks, applications, and training for VMS and Windows NT NT driver FAQ, links, and other information: http://www.cmkrnl.com/ If you post a reply in news, please don't e-mail it too.