UnlockDevice(dx);

 KeWaitForSingleObject(&dx->StoppingEvent, Executive, KernelMode, FALSE, NULL);

 DebugPrint('PnpStopDevice: All pending I/O completed');

 dx->Stopping = false;

 // Stop our device before passing down

 StopDevice(dx);

 // Bump usage count back up again

 LockDevice(dx);

 LockDevice(dx);

}

Listing 9.10 shows how a typical I/O IRP dispatch routine fits into the Wdm2 device Plug and Play handling. Initially, it checks the IODisabled flag and then it tries to lock the device using LockDevice. If LockDevice fails, the correct response is to return STATUS_DELETE_PENDING. The Wdm2 PnpStopDevice routine always sets the IODisabled flag first, so the dispatch routine will never return STATUS_DELETE_PENDING. This could be fixed by adding another suitable flag to the device extension.

The dispatch routine ends by completing the IRP and calling UnlockDevice. If the IRP is not completed straightaway, do not call UnlockDevice straightaway. Instead, wait until the IRP is completed or cancelled before calling UnlockDevice.

All dispatch routines should include calls to LockDevice when an IRP arrives and UnlockDevice when an IRP is completed or passed onto another driver. PnP and WMI IRP handlers should also call these routines.

Listing 9.10 Dispatch routine entry and exit code

NTSTATUS Wdm2Read( IN PDEVICE_OBJECT fdo, IN PIRP Irp) {

 PWDM2_DEVICE_EXTENSION dx = (PWDM2_DEVICE_EXTENSION)fdo->DeviceExtension;

 if (dx->IODisabled) return CompleteIrp(Irp, STATUS_DEVICE_NOT_CONNECTED, 0);

 if (!LockDevice(dx)) return CompleteIrp(Irp, STATUS_DELETE_PENDING, 0);

 // …

 // Complete IRP

 CompleteIrp(Irp,status,BytesTxd);

 UnlockDevice(dx);

 return status;

}

PnpStopDevice also sets another flag in the device extension, Stopping, to true while it is waiting for all pending I/O to complete. Although not strictly necessary in Wdm2, it is another way of forcing an IRP routine to see if it is OK to start during the call to LockDevice.

Listing 9.11 shows the LockDevice and UnlockDevice routines. They use InterlockedIncrement and InterlockedDecrement calls to ensure that UsageCount is maintained safely in multiprocessor systems. If UnlockDevice finds that UsageCount has decremented to zero, it sets the StoppingEvent flag. LockDevice also checks the Stopping flag. If it is set, a PnP IRP is trying to stop the device and so the caller should not continue. In this case, UsageCount is decremented and StoppingEvent is set, if appropriate, before false is returned.

Listing 9.11 LockDevice and UnlockDevice routines

bool LockDevice(IN PWDM2_DEVICE_EXTENSION dx) {

 InterlockedIncrement(&dx->UsageCount);

 if (dx->Stopping) {

  if (InterlockedDecrement(&dx->UsageCount)==0) KeSetEvent(&dx->StoppingEvent, 0, FALSE);

  return false;

 }

 return true;

}

void UnlockDevice(IN PWDM2_DEVICE_EXTENSION dx) {

 LONG UsageCount = InterlockedDecrement(&dx->UsageCount);

 if (UsageCount==0) {

  DebugPrintMsg('UnlockDevice: setting StoppingEvent flag');

  KeSetEvent(&dx->StoppingEvent, 0, FALSE);

 }

}

To wrap up the last loose ends, the handlers for the Stop Device and Surprise Removal messages are exactly the same, as shown in Listing 9.12. They both simply call PnpStopDevice and call PnpDefaultHandler to pass the IRP down the stack.

Listing 9.12 Stop device handler

NTSTATUS PnpStopDeviceHandler(IN PDEVICE_OBJECT fdo, IN PIRP Irp) {

 DebugPrintMsg('PnpStopDeviceHandler');

 PWDM2_DEVICE_EXTENSION dx=(PWDM2_DEVICE_EXTENSI0N)fdo->DeviceExtension;

 // Wait for I/O to complete and stop device

 PnpStopDevice(dx);

 return PnpDefaultHandler(fdo, Irp);

}

W2000 Device Locking

W2000 provides standard routines to replace our LockDevice and UnlockDevice routines, and the associated variables. You must provide an IO_REMOVE_LOCK field in your device extension. Initialise this field using IoInitializeRemoveLock function in your AddDevice routine. Replace all calls to LockDevice with IoAcquireRemoveLock and calls to UnlockDevice with IoReleaseRemoveLock. In the PnpStopDevice routine above, replace the code that waits for all pending I/O to complete with a call to IoReleaseRemoveLockAndWait.

The DDK recommended that you call IoAcquireRemoveLock whenever you pass out a reference to your code, e.g., a timer, DPC, or any other call-back routine. Call IoReleaseRemoveLock when these call-backs are disabled, i.e., usually in your Remove Device handler.

Getting Resource Assignments

A Start Device PnP IRP passes a list of the resources that have been assigned to the device. Although the Wdm2 driver never gets any resources, the code in DeviceIo.cpp goes through the steps to find these out. In addition, there is a lot of commented out code that shows how to use the resources. The WdmIo driver described in Chapters 15-17 show how hardware resources are actually used.

DeviceIo.cpp primarily contains the StartDevice and StopDevice routines. StartDevice must get the list of assigned resources, check that the resources are suitable, allocate them, and do any hardware-related initialization for the driver. If that all goes well, it should set the GotResources flag to true. StopDevice must release any hardware resources and reset the GotResources flag.

StartDevice calls RetrieveResources to find out which resources have been assigned to it by the PnP Configuration Manager. The Start Device PnP message passes two fields in the IRP stack Parameters.StartDevice structure, AllocatedResources, and AllocatedResourcesTranslated. AllocatedResources lists the resources in 'raw form'. This is how the device itself will see addresses, etc. Use AllocatedResources to program the device itself. Usually the 'translated form' of the resource list, AllocatedResourcesTranslated, is of more interest to the driver. Use the AllocatedResourcesTranslated to connect to interrupt vectors, map I/O space, and memory.

If there are no resources assigned, W2000 sets these fields to NULL. In W98, a resource list is allocated but the 'partial resource' count is zero.

Table 9.1 shows the raw and translated resource assignments for an I/O Port and two different interrupts in Windows 98 and Windows 2000.

Table 9.1 Resource assignments

I/O Port Address
Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату
×