fdo->Flags |= DO_BUFFERED_IO;

 dx->PowerIdleCounter = PoRegisterDeviceForIdleDetection(pdo, 30, 60, PowerDeviceD3);

 return STATUS_SUCCESS;

}

Remove Device handler

The code that handles removing devices has been moved to PnpRemoveDeviceHandler, as shown in Listing 9.2. This is the same as before, apart from calling the PnpStopDevice routine, which is explained in the following text.

Listing 9.2 Wdm2 PnpRemoveDeviceHandler

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

 PWDM2_DEVICE_EXTENSION dx=(PWDM2_DEVICE_EXTENSION)fdo->DeviceExtension;

 DebugPrintMsg('PnpRemoveDeviceHandler');

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

 PnpStopDevice(dx);

 // Pass down stack and carry on immediately

 NTSTATUS status = PnpDefaultHandler(fdo, Irp);

 // disable device interface

 IoSetDeviceInterfaceState(&dx->ifSymLinkName, FALSE);

 RtlFreeUnicodeString(&dx->ifSymLinkName);

 // unattach from stack if (dx->NextStackDevice)

 IoDetachDevice(dx->NextStackDevice);

 // delete our fdo

 IoDeleteDevice(fdo); 

 return status;

}

Main PnP IRP Handler

The main IRP_MJ_PNP dispatch routine, Wdm2Pnp, has changed considerably from Wdm1, as shown in Listing 9.3. The bulk of the code is a switch statement based on the PnP minor function code. Most of the interesting minor function handling is delegated to subsidiary routines, but some are handled inline. All other minor function codes are handled by the PnpDefaultHandler routine. The PnpQueryCapabilitiesHandler routine is described in the chapter on Power Management.

Listing 9.3 Wdm2 Wdm2Pnp

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

 PWDM2_DEVICE_EXTENSION dx=(PWDM2_DEVICE_EXTENSION)fdo->DeviceExtension;

 DebugPrint('PnP %I',Irp);

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

 // Remember minor function

 PIO_STACK_LOCATION TrpStack = IoGetCurrentIrpStackLocation(Irp);

 ULONG MinorFunction = IrpStack->MinorFunction;

 NTSTATUS status = STATUS_SUCCESS;

 switch (MinorFunction) {

 case IRP_MN_START_DEVICE:

  status = PnpStartDeviceHandler(fdo,Irp);

  break;

 case IRP_MN_QUERY_REMOVE_DEVICE:

  status = PnpQueryRemoveDeviceHandler(fdo,Irp);

  break;

 case IRP_MN_SURPRISE_REMOVAL:

  status = PnpSurpriseRemovalHandler(fdo, Irp);

  break;

 case IRP_MN_REMOVE_DEVICE:

  status = PnpRemoveDeviceHandler(fdo,Irp);

  return status;

 case IRP_MN_QUERY_STOP_DEVICE:

  dx->Paused = true;

  dx->IODisabled = true;

  status = PnpDefaultHandler(fdo,Irp);

  break;

 case IRP_MN_STOP_DEVICE:

  status = PnpStopDeviceHandler(fdo,Irp);

  break;

 case IRP_MN_QUERY_CAPABILITIES:

  status = PnpQueryCapabilitiesHandler(fdo.Irp);

  break;

 case IRP_MN_CANCEL_REMOVE_DEVICE: // fall thru case IRP_MN_CANCEL_STOP_DEVICE:

  dx->Paused = false;

  dx-> IODisabled = false;

  status = PnpDefaultHandler(fdo,Irp);

  break;

 default:

  status = PnpDefaultHandler(fdo,Irp);

 }

 UnlockDevice(dx);

#if DBG

 if (status!=STATUS_SUCCESS) DebugPrint('PnP completed %x',status);

#endif

 return status;

}

Passing Unsupported IRPs Down the Stack

PnpDefaultHandler (Listing 9.4) passes the PnP IRP down the device stack for processing by all the lower device drivers. Call IoCallDriver whenever you want a driver to process an IRP. If you have created an IRP from scratch, you must set up all the IRP and IRP stack fields correctly. The different ways of allocating and sending your own IRPs are discussed in Chapter 21.

For PnpDefaultHandler, all the IRP structure fields are already set up correctly in the existing PnP IRP that is to be passed onto the next driver. What about the IRP stack?

One IRP stack location is reserved for each possible device in a device stack. When an IRP is passed to the next driver, the next stack location must be set up for it. However, in this case, the Wdm2 driver is never going to need to look at the IRP or its stack location again. IoSkipCurrentIrpStackLocation does not copy the current stack location to the next one. In fact, it simply sets up the IRP internally so that the next driver's call to IoGetCurrentlrpStackLocation returns the same stack location as Wdm2 saw.

You need to set up the next IRP stack location properly if you are going to inspect the IRP processing results or even simply wait for the IRP to complete. Use the routine IoCopyCurrentIrpStackLocationToNext if you simply want to copy the current stack location without changing any of the information. An example of this function is given in Listing 9.4 when Wdm2 waits for an IRP to be processed by all the lower drivers.

IoCallDriver, IoSkipCurrentlrpStackLocation, IoCopyCurrentlrpStackLocationToNext, and the other relevant function IoSetCompletionRoutine

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

0

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

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