as the Dpc parameter. This fact could be used in DPC processing, if necessary. For example, for IRP cancelling and time-outs, there is no need to provide a priority boost for the IRP.

Listing 17.5 WdmIo time-out routines

VOID Timeout1s(IN PDEVICE_OBJECT fdo, IN PWDMIO_DEVICE_EXTENSION dx) {

 if (dx->Timeout==-1) return;

 DebugPrint('Timeout1s: Timeout is %d' ,dx->Timeout);

 PIRP Irp = fdo->CurrentIrp;

 if (Irp->Cancel ||

    KeSynchronizeExecution(dx->InterruptObject, (PKSYNCHRONIZE_ROUTINE)Timeout1sSynch, dx))

  WdmIoDpcForIsr(NULL, fdo, fdo->CurrentIrp, dx);

}

static BOOLEAN Timeout1sSync(IN PWDMIO_DEVICE_EXTENSION dx) {

 if (dx->Timeout==-1 || –dx->Timeout>0) return FALSE;

 dx->Timeout = –2;

 dx->TxStatus = STATUS_NO_MEDIA_IN_DEVICE; // Win32: ERROR_NOT_READY

 return TRUE;

}

Custom Timers

Custom timers may be used if you want timer resolutions other than one second. You can detect when the timer goes off in two ways. Either use a Custom DPC callback, or wait for the timer object to become signalled.

NT 3.51 timers are one-shot only. NT 4, W2000, and WDM drivers can use periodic timers. Declare a KTIMER field in nonpaged memory (e.g., in your device extension), and initialize it with KeInitializeTimer or KeInitializeTimerEx. To start a one-shot timer, call KeSetTimer. If the DueTime LARGE_INTEGER parameter is positive, it represents an absolute time. If it is negative, it is a relative time in units of 100ns.

Use KeSetTimerEx if you want to specify a periodic timer. The DueTime parameter is used to specify the first time-out. The Period parameter specifies the period in milliseconds for subsequent time-outs.

You can cancel a timer using KeCancelTimer, and use KeReadStateTimer to find out if the timer has gone off.

A custom DPC routine may used as the timer callback. Initialize a custom DPC as described previously. Pass the KDPC pointer to KeSetTimer or KeSetTimerEx.

System threads can wait for a timer to go off using the KeWaitForSingleObject and KeWaitForMultipleObjects calls. KeInitializeTimerEx lets you specify whether a timer is a NotificationTimer or a SynchronizationTimer. A SynchronizationTimer timer releases only one waiting thread, while a NotificationTimer timer releases all waiting threads.

Conclusion

This chapter has looked at how to write interrupt service routines. Any nonessential processing is best done in a Deferred Procedure Call (DPC) routine at a lower IRQL. A basic one-second interval timer can be used to detect device time-outs. Custom timers can be used with Custom DPCs to receive notification of other time-out periods.

Chapter 18

NT Hardware

This chapter looks at how to find, allocate, and use hardware resources in non-WDM drivers that do not support Plug and Play. I call these 'NT style' drivers because they run in NT 3.51, NT 4, and Windows 2000. These drivers sometimes also work in Windows 98, slightly to my surprise.

I have already shown how to use the translated hardware resource assignments in the last two chapters. The WdmIo and PHDIo drivers use MmMapIoSpace to map I/O ports into memory and IoConnectInterrupt to install an interrupt handler.

An NT style driver has three jobs to do to obtain its translated hardware resources.

1. Find its device's raw resource requirements.

2. Allocate these raw resources: check for conflicts with existing devices and reserve the resources so that other new devices cannot use them.

3. Translate the raw resource information.

The PHDIo driver receives its resource requirements from the Win32 application. The filename passed in the Create IRP specifies the I/O port details and optionally the Interrupt IRQ number. PHDIo can currently only accept ISA resource details.

This chapter shows how PHDIo allocates its raw resources and translates them. At the end of the chapter, I look at how NT and W2000 find various devices and make the resource information available to drivers.

First, I look at how to build and structure an NT style driver.

NT Style Driver Construction

An NT style driver is built in a slightly different way from a WDM driver. It also has none of the Plug and Play infrastructure to support.

DDK Issues

You must build an NT style driver in Windows 2000 or NT 4. The Windows 2000 DDK or NT 4 DDK must be installed as appropriate. If you alter an NT style driver, you must reboot Windows 98 to use the changed driver.

It is possible that crucial kernel structures have been changed between NT 4 and W2000, so it is safest to have one NT 4/NT 3.51 version of your driver and one W2000 version. In practice, it seems as though a driver compiled in W2000 using the W2000 DDK works in the NT platforms and Windows 98. I compared the free build driver made by the Windows 2000 Beta DDK with the same build using the NT 4 DDK. Although the files were both the same size, they were not identical.

An NT style driver can support Power Management and Windows Management Instrumentation (WMI), as long as it is only run on Windows 2000 or Windows 98. The major function code for the Power Management IRP, IRP_MJ_POWER, is defined as 0x16 in the W2000 DDK NTDDK.H. IRP_MJ_POWER is not defined in the NT 4 DDK. Instead, the IRP major function code 0x16 is defined as IRP_MJ_QUERY_POWER in NT 4. I am not sure whether this IRP is issued in NT 4. However, it is best if you do not handle IRP_MJ_POWER or IRP_MJ_SYSTEM_CONTROL in a driver installed in NT 4.

Compile Environment

An NT style driver must use NTDDK.H as its main header file, rather than WDM.H. In general, this gives the driver access to more facilities than would be available to a WDM device driver. In the SOURCES build file, remove the line that says DRIVERTYPE=WDM.

NT Style Driver Structure

An NT style driver like PHDIo creates devices in a different way from WDM device drivers. A WDM device driver has an AddDevice routine and receives Plug and Play IRP notifications. PHDIo does not handle the PnP IRP and, therefore, loses its Pnp.cpp file[44]. It also does not handle Power Management and WMI IRPs.

As a consequence of not using Plug and Play, PHDIo does not deal with PnP device stacks. The device extension does not need to have fields for the Physical Device Object (PDO) or NextStackDevice. Similarly, there is no need for the GotResources, Paused, IoDisabled, and OpenHandleCount fields. The StartDevice and RetrieveResources routines in DeviceIo.cpp have been removed, as there are no PnP Start Device IRPs to process.

Instead, PHDIo creates one device in its DriverEntry routine. This is not a Functional Device Object (FDO) in the PnP sense. Instead, it is just called a 'device object'. The PHDIo device extension now has a phddo field that contains a pointer this device object. phddo is used in exactly the same way as the fdo field in all the previous drivers.

Most NT style drivers that need resources find and allocate them in the DriverEntry call. However, PHDIo only receives its resource requirements when a handle is opened to its device. Later in the chapter, I will look at various techniques for finding a driver's resource requirements.

The one PHDIo device is deleted using PHDIoUnload when the driver is removed.

Device Creation and Deletion

The PHDIo DriverEntry routine delegates its device object creation to PHDIoCreateDevice, also in Init.cpp.

Listing 18.1 shows how PHDIo creates its device in PHDIoCreateDevice. Its kernel device name is DevicePHDIo and the Win32 symbolic link name is ??PHDIo. This is used by Win32 programs with a CreateFile filename of \.PHDIo.

PHDIoCreateDevice first sets up UNICODE_STRINGs for the kernel and symbolic link names. It then calls IoCreateDevice in the same way as

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

0

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

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