|
Last modified: 18 September 2002.
Please give me any comments or corrections on the feedback page. |
My advice therefore is to provide separate binary versions of your drivers for NT 4 and
W2000. Currently indications are that drivers should be source code compatible.
However you may wish to
consider moving your driver to the Plug and Play (PnP) architecture, supporting Power
Management and Windows Management Instrumentation (WMI).
Test any existing drivers thoroughly in W2000!
WDMdriv3.zip
in the CD root directory.
16 Oct 99
Page 36
In "Deferred Procedure Calls" section, first para, add "run" before "as quickly as possible".
Last para on page should start "A driver" instead of "Drivers".
16 Oct 99
Page 45
In the "Recompiling the book drivers" section:
When recompiling the UsbKbd software in W98, you will need to change the USB
headers include directory to "c:\98ddk\src\usb\inc" or equivalent.
23 Jul 01
Page 47
In the "Registry Editors" section:
replace "RedEdt32" with "RegEdt32".
28 Sep 99
Page 97
The text refers to "Table 5.2". It should refer to "Table 5.1".
28 Sep 99
Table 5.2
Table 5.2 should describe IoAttachDeviceToDeviceStack.
16 Sep 99
DebugPrint web link
The link to the DebugPrint web site should be
www.phdcc.com/debugprint.
21 Oct 99
Table 20.4, page 406
For the GET_DESCRIPTOR request code, the Recipient column should be DIE, not D.
4 Nov 99
Interrupt transfers
Page 403. Section "Transaction packet Structure". Change the start of the third paragraph
from "The host starts interrupt transfers" to "The host starts input interrupt transfers".
Page 414. Top of the page. Change "Interrupt transfers are unidirectional into the host" to
"Interrupt transfers are also bidirectional".
21 Oct 99
Other Get/Set descriptors, page 442
The following function codes should also be listed:
URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE
URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE
The following function code does not exist and should be deleted:
URB_FUNCTION_SET_DESCRIPTOR_TO_OTHER
Date | 7 Sep 99 |
---|---|
Summary | The METHOD_IN_DIRECT and METHOD_OUT_DIRECT description is incorrect |
Topics | DeviceIoControl buffers (page 139) |
Discussion | My description of how drivers receive the parameters that are passed to
DeviceIoControl
for the METHOD_IN_DIRECT and METHOD_OUT_DIRECT buffer methods is wrong.
For both these methods, the driver sees the input buffer in buffered memory at
METHOD_IN_DIRECT is used if you are reading lots of data, or want to use
an MDL in your driver. The Win32 program passes the read data buffer
in the DeviceIoControl output buffer parameter.
The read data buffer is passed to the driver as an
MDL in
METHOD_OUT_DIRECT is used if you are writing lots of data, or want to use
an MDL in your driver. The Win32 program passes the write data buffer
in the DeviceIoControl output buffer parameter.
The write data buffer is passed to the driver as an
MDL in There are two points to note about using these techniques:
|
Summary | Most IRP completion routines need to include this code:if( Irp->PendingReturned) IoMarkIrpPending(); |
---|---|
Topics | IRP Completion routines (page 179) |
Discussion | The paragraph starting "Some completion routines..." on page 179 is inaccurate.
Most completion routines need to use the above code in their completion routines to remember if any lower driver has pended an IRP. If any driver in a stack marks an IRP as pending then the I/O Manager has to take special steps to ensure that the IRP results are returned to user space in the correct thread context.
Calling IoMarkIrpPending sets an internal pending flag in
the current IRP stack location (the SL_PENDING_RETURNED bit in the In two cases, the above code is not strictly necessary (though including the code will cause no bugs).
Thanks to Jamie Hanrahan and others on the NTDEV mailing list for answering my questions on this. |
I found the Wdm2 driver bug: Windows doesn't resume after suspend or hibernate. OS: Windows 2000 SP2 NTSTATUS SendDeviceSetPower(...) { ... NTSTATUS status = PoRequestPowerIrp( dx->pdo, IRP_MN_SET_POWER, NewState, OnCompleteDeviceSetPower, &sdsp, NULL); if( status==STATUS_PENDING) { KeWaitForSingleObject( &sdsp.event, Executive, KernelMode, FALSE, NULL); status = sdsp.Status; } ... } Function KeWaitForSingleObject never return. You write: "DDK documentation says that you cannot wait using events for yourown Power IRP to complete". I think it is right and code must be: NTSTATUS status = PoRequestPowerIrp( dx->pdo, IRP_MN_SET_POWER, NewState, NULL, Irp, NULL); if( status==STATUS_PENDING) { status = STATUS_SUCCESS; } where Irp - or pointer to IRP received or NULL. DDK says: "When the caller requests a device set-power IRP in response to a system set-power IRP, the Context should contain the system set-power IRP that triggered the request. " After these changes driver works Ok.
My driver was blue screening on XP at system shutdown with this error:
Bug Check 0x9F: DRIVER_POWER_STATE_FAILURE
Parm1=0x02 The device object completed the IRP for the system power state request, but failed to call PoStartNextPowerIrp.
I narrowed it down to the code in my Power dispatch routine. This was based on the wdm3 project.
NTSTATUS Wdm3Power( IN PDEVICE_OBJECT fdo,IN PIRP Irp)
The first couple lines check for IODisabled and lock checking, if either of these scenerios are executed, PStartNextPowerIrp is not called. Adding this call fixed the crash.
This problem effects the supplied DebugPrint INF file, which had one section name that was too long. Download the updated DebugPrint INF files if you wish to install DebugPrint in W98.
Summary | Calling Win32 function ControlService SERVICE_CONTROL_INTERROGATE fails in W2000 Beta 3 if the driver is stopped, as the documentation says it should. |
---|---|
Implication | My suggested NT style driver code in install.cpp needs changing...
download the revised install.cpp and copy into the WDMBook NT directory.
|
Preamble | Win32 programs can create and control NT/W2000 device driver services using the Service Control Manager Win32 functions. You should be able to call ControlService with control code SERVICE_CONTROL_INTERROGATE to see if a driver is running. |
Discussion | In Windows 2000 Beta 3, the Win32 ControlService
SERVICE_CONTROL_INTERROGATE call fails if the driver is stopped.
GetLastError then
returns error 1062 (ERROR_SERVICE_NOT_ACTIVE The service has not been started).
This is the documented behaviour.
In NT 4 this call succeeds.
The book software Servicer program should also be altered minorly to cope with this change of functionality. |
Summary | NT4 does provide some support for PNPISA devices |
---|---|
Topics | NT Style Driver Installation (pages 242) |
Implication | You can install PNPISA devices in NT4 using W98/W2000 style INF files. You must install PNPISA.INF first from the NT4 CD \DRVLIB\PNPISA directory first.
Search for "PNPISA" in the MSDN library for some more details. |
Date | 28 Oct 99 |
---|---|
Summary | The Wdm3 code is updated to make WMI method calls work Get the revised driver and code. |
Topics | A WMI driver(pages 261-262) and ExecuteWmiMethod Handle (pages 273-274) |
Discussion | In the WMI chapter I say that I could not get the Wdm3Information data block
PowerDown method to compile. The following code should be used, and
therefore I am issuing a revised Wdm3.mof file.
In addition the ExecuteWmiMethod method in
The
Note 1: I have also added the WMIREG_FLAG_EVENT_ONLY_GUID flag to the Note 2: the mofcomp tool can now generate a VBScript script to test a WMI implementation. |
Date | 20 Aug 99 |
---|---|
Summary | Wdm3 INF file updated to fix EventLog section problem |
Topics | Registering as an Event Source (pages 283-284) |
Discussion | I did not get the book Wdm3 driver INF file to register Wdm3 as an event source.
I have now fixed this problem.
Download the updated Wdm3 INF files.
Listing 13.4 on page 284 should now be as follows:
Thanks to Bob Fruth at Microsoft for helping me sort this problem out. The latest DDK has the
correct information on this topic.
Bob Fruth also pointed out that the latest W2000 DDK has a useful tool,
ChkINF in the DDK Tools directory, for checking INF files.
ChkINF is a perl script so I have not managed to check it out yet. |
Summary | File and Object handles are process dependent, not thread dependent. |
---|---|
Topics | System threads (page 291) and System worker threads (page 294) |
Discussion | I use a system thread for the DebugPrint driver as the Zw... file access functions
cannot access the file handle created in a different context.
I stated that file handles are thread dependent, when in fact they are process
dependent. This does not effect the decision to use a system thread in DebugPrint.
File handles are a type of Object handle. All Object handles process dependent, ie they are only usable by threads running in the same process. Thanks to Jamey Kirby of StorageCraft for this information. James also adds: "If you use kernel worker threads (work queue items), you can assume that your file handle is valid no matter what worker thread happens to be processing the request (because they are all in the system process). |
Summary | Do not assume that an IRP has been completed if IoCancelIrp returns TRUE. |
---|---|
Preamble | An IRP that is held in a queue must be made cancellable using a cancel routine. A driver that allocates its own IRP and sends it to a lower driver can try to cancel it using the IoCancelIrp routine. |
Discussion | My main technique for cancelling IRPs does not remove the cancel routine when an IRP starts
processing in the driver StartIo handler.
Instead it does nothing, relying on StartIo later
(or its follow on routines) to detect the Irp->Cancel
flag, and only then complete the IRP with a cancelled status.
IoCancelIrp returns TRUE if an IRP's cancel routine was called, and FALSE if not, ie if there was no cancel routine (eg if the cancel routine was removed at the beginning of the StartIo handler). The DDK documentation for IoCancelIrp might give the impression that if IoCancelIrp returns TRUE then the IRP has been completed. This is not the case for the technique I used earlier; the IRP's cancel routine has been called but the IRP has not been completed. A quick look at all the W2000 DDK source code examples seems to indicate that none of these examples assume that an IRP has been completed, even if IoCancelIrp returns TRUE. If the IRP has a completion routine, wait for it to run. Only when the IRP has really completed can you free its memory. I do not know what technique the I/O Manager uses if a user mode program cancels an IRP using CancelIo. |
Date | 22 Nov 99 |
---|---|
Summary | Safer time-out handling in multiple processor systems |
Topics | WDMIo and PHDIo time-outs, page 369-370 Note that I have not yet issued updates to the PHDIo and WdmIo drivers. |
Discussion | The following revised code should replace Listing 17.5,
in DeviceIo.cpp in the WdmIo driver.
Similar code should also be used in PHDIo.
There is a chance that the CurrentIrp will have become NULL in my Timeout1s routine, and also a chance that a device interrupt will occur after the Cancel flag has been found true but before the DPC is called. My revised code does its timeout and Cancel checks in the Critical Section routine, Timeout1sSynch.
The revised Timeout1sSynch routine now has to be changed
because Timeout1s
does not call the DPC routine directly. Instead, Timeout1sSynch
asks that my DPC routine be called later in the normal way using
IoRequestDpc.
VOID Timeout1s( IN PDEVICE_OBJECT fdo, IN PWDMIO_DEVICE_EXTENSION dx) { if( dx->Timeout==-1) return; DebugPrint("Timeout1s: Timeout is %d",dx->Timeout); // Check for timeout in synch with interrupt if( KeSynchronizeExecution( dx->InterruptObject, (PKSYNCHRONIZE_ROUTINE)Timeout1sSynch, dx)) { DebugPrint("Timeout1s: Timeout1sSynch cancelled in-progress IRP %x %I",Irp,Irp); } } static BOOLEAN Timeout1sSynch( IN PWDMIO_DEVICE_EXTENSION dx) { if( dx->Timeout==-1) return FALSE; PDEVICE_OBJECT fdo = dx->fdo; PIRP Irp = fdo->CurrentIrp; if( Irp==NULL) return FALSE; // Only complete IRP if it is cancelled or if it has timed out if( !Irp->Cancel && --dx->Timeout>0) return FALSE; // Get DPC to complete the IRP dx->Timeout = -1; dx->TxStatus = STATUS_NO_MEDIA_IN_DEVICE; // Win32: ERROR_NOT_READY IoRequestDpc( fdo, Irp, dx); return TRUE; } |
In this paper they suggest that it may be useful (in NT 4) for post-interrupt processing to be further deferred to a high priority read-time system thread, as it is easier to code threads than DPC routines. See the More Information Page for more details.
Summary | My UsbGetSpecifiedDescriptor routine needs amending to specify whether the GET_DESCRIPTOR request is for the Device, Interface or Endpoint. |
---|---|
Topics | Getting the HID Descriptor, page 429 and 434 |
Discussion | Some people may have found that the UsbKbdTest program could not read the HID report descriptor,
even though the rest of UsbKbdTest ran OK.
The problem is that the USBDI GET_DESCRIPTOR call must be directed to the interface, not the device. My UsbGetSpecifiedDescriptor routine uses the UsbBuildGetDescriptorRequest helper function that always uses the URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE function code. As the desired HID Descriptor is an Interface descriptor, the URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE function code should be used instead. As a temporary hack the following code can be inserted after UsbBuildGetDescriptorRequest has been called.
A full fix for this problem would be add an extra parameter to UsbGetSpecifiedDescriptor to indicate whether a device, interface or endpoint descriptor is required. The IOCTL_USBKBD_GET_SPECIFIED_DESCRIPTOR handler and the corresponding UsbKbdTest code would also need to be amended. I shall leave this an exercise for the reader. It seems as though some devices respond with the desired information even if the request is directed as the device. Thanks to Bruce Ramsland for pointing out this problem. |
Date | 30 Oct 00 |
---|---|
Summary | HID IOCTLs should use IRP_MJ_DEVICE_CONTROL not IRP_MJ_INTERNAL_DEVICE_CONTROL |
Discussion | In W2000, it looks like you must use IRP_MJ_DEVICE_CONTROL (not
IRP_MJ_INTERNAL_DEVICE_CONTROL) when sending messages from kernel mode HID drivers
to the HID class driver.
The HidKbd CallHidIoctl routine calls IoBuildDeviceIoControlRequest to build a HID request. The supplied code builds an IRP_MJ_INTERNAL_DEVICE_CONTROL IRP. Change parameter 7 of IoBuildDeviceIoControlRequest to FALSE to make it build an IRP_MJ_DEVICE_CONTROL IRP instead. Thanks to Will Dean for this information. |
Date | 14 Dec 00 |
---|---|
Summary | The HidPreparsedData parameter to GetPreparsedData
in HidKbd should be passed by reference.
Listing 23.10 page 489. Thanks to Russell Hocken for spotting this. |
Date | 27 Apr 01 |
---|---|
Summary | Russell Hocken suggests changes to the end of
(the commented out version of) SetupHidIrp so that it reads:
dx->HidIrp=NULL; return; // Add this return here } MmBuildMdlForNonPagedPool(dx->HidReportMdl); // new command } "Without this the report wouldn't get put in the right place. It now seems to work correctly." Listing 23.12 page 493/494. |