Writing a DriverEntry Routine

< BACK  NEXT >
[oR]

Every Windows 2000 kernel-mode or WDM driver, regardless of its purpose, has to expose a routine whose name is DriverEntry. This routine initializes various driver data structures and prepares the environment for all the other driver components.

Execution Context

The I/O Manager calls a DriverEntry routine once it loads the driver. As Table 6.1 shows, the DriverEntry routine runs at PASSIVE_LEVEL IRQL, which means it has access to page system resources.

The DriverEntry routine receives a pointer to its own driver object, which it must initialize. It also receives a UNICODE_STRING containing the path to the driver's service key in the Registry. WDM drivers have little use for this registry name. Kernel-mode drivers rely on the string to extract any driver-specific parameters stored in the system registry. The Registry String takes the form HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\ DriverName.

What a DriverEntry Routine Does

Although the exact details vary based on whether a driver is WDM or kernel-mode, in general the following steps are taken in a DriverEntry routine.

  1. DriverEntry locates hardware that it will be controlling. That hardware is allocated it is marked as under the control of this driver.

  2. The driver object is initialized by announcing other driver entry points. The announcements are accomplished by storing function pointers directly into the driver object.

  3. If the driver manages a multiunit or multifunction controller, IoCreateController is used to create a controller object. A controller extension is then initialized.

  4. IoCreateDevice is used to create a device object for each physical or logical device under the control of this driver. A device extension is then initialized.

  5. The created device is made visible to the Win32 subsystem by calling IoCreateSymbolicLink.

  6. The device is connected to an interrupt object. If the ISR requires the use of a DPC object, it is created and initialized in this step.

  7. Steps 4 to 6 are repeated for each physical or logical device controlled by this driver.

  8. If successful, DriverEntry should return STATUS_SUCCESS to the I/O Manager.

Table 6.1. Function Prototype for DriverEntry
NTSTATUS DriverEntry IRQL == PASSIVE_LEVEL
Parameter Description
IN PDRIVER_OBJECT pDriverObject Address of driver object for this driver
IN PUNICODE_STRING pRegistryPath Registry path string for this driver's key
Return value STATUS_SUCCESS
STATUS_XXX - some error code

It is important to understand that steps 1 and 3 to 6 are not performed by a WDM driver's DriverEntry routine. They are deferred to another routine, AddDevice.

If DriverEntry should fail during initialization for any reason, it should release any system resources it may have allocated up to the failure, and return an appropriate NTSTATUS failure code to the I/O Manager.

The following sections describe some of the steps in more detail. The process of finding and allocating hardware is complex and heavily impacted by the device's ability to be autorecognized. Chapter 9 describes this step in more detail. The use of an interrupt object and DPCs is deferred until chapter 8.

Announcing DriverEntry Points

The I/O Manager is able to locate the DriverEntry routine because it has a well-known name. (Actually, the linker announces the address of DriverEntry using a command line switch. Nevertheless, the DDK documentation mandates that this entry point be called DriverEntry.) Other driver routines don't have fixed names, so the I/O Manager needs some other way to locate them. The linkage mechanism is the driver object, which contains pointers to other driver functions. A DriverEntry routine is responsible for setting up these function pointers.

These function pointers fall into two categories.

  • Functions with explicit slots and names in the driver object.

  • IRP dispatch functions that are listed in the driver object's MajorFunction array. These functions are the subject of chapter 7.

The following code fragment shows how a DriverEntry routine initializes both kinds of function pointers.

 pDO->DriverStartIo = StartIo; pDO->DriverUnload = Unload; // // Initialize the MajorFunction Dispatch table // pDO->MajorFunction[ IRP_ MJ_CREATE ] = DispatchCreate; pDO->MajorFunction[ IRP_MJ_CLOSE ] = DispatchClose; : 

Creating Device Objects

Once hardware is identified and allocated, the next step is to create a device object for each physical or virtual device that is to be exposed to the rest of the system. Most of the work is done by the IoCreateDevice function, which takes a description of the device and returns a device object, complete with an attached device extension. IoCreateDevice also links the new device object into the list of devices managed by this driver object. Table 6. 2 contains a description of this function.

The DeviceType parameter of IoCreateDevice is simply a 16-bit value describing the class of device being added. Microsoft reserves the first half of this range for predefined device types. Above 32767, private device types can be defined. Beware, though, that conflict with another vendor's device is always possible. Currently, Microsoft predefines about 30 device types. The predefined device type values are given symbolic names of the form FILE_DEVICE_XXX (e.g., FILE_DEVICE_DVD).

One final point about creating device objects: Although this chapter describes the use of IoCreateDevice from DriverEntry, it is usually called from AddDevice (WDM) and occasionally from a Dispatch routine. In such a case, it is imperative that the driver reset a bit in the Flags field of the device object once it is created. This bit is called DO_DEVICE_INITIALIZING and is normally reset upon return from DriverEntry. The bit is reset with code similar to the following:

 pDevObject->Flags &= ~DO_DEVICE_INITIAILIZING; 

Do not clear this bit until the device object is actually initialized and ready to process requests.

Table 6.2. Function Prototype for IoCreateDevice
NTSTATUS IoCreateDevice IRQL == PASSIVE_LEVEL
Parameter Description
IN PDRIVER_OBJECT pDriverObject Pointer to driver object
IN ULONG DeviceExtensionSize Requested size of DEVICE_EXTENSION
IN PUNICODE_STRING pDeviceName Internal device name (see below)
IN DEVICE_TYPE DeviceType FILE_DEVICE_XXX (see NTDDK.h)
IN ULONG DeviceCharacteristics Characteristics of mass-storage device:
FILE_REMOVABLE_MEDIA
FILE_READ_ONLY_DEVICE
Etc.
IN BOOLEAN Exclusive TRUE if device is not sharable
OUT PDEVICE_OBJECT *pDeviceObject Variable that receives device object pointer
Return value STATUS_SUCCESS -or-
STATUS_XXX - some error code

Choosing a Buffering Strategy

If the IoCreateDevice call succeeds, the I/O Manager must be notified of whether buffered I/O or direct I/O will be used with the device. The choice is designated by selecting appropriate bits into the Flags field of the new device object.

  • DO_BUFFERED_IO.

    The I/O Manager copies data back and forth between user and system-space buffers.

  • DO_DIRECT_IO.

    The I/O Manager locks user buffers into physical memory for the duration of an I/O request and builds a descriptor list of the pages in the buffer.

The next chapter explains how user buffers are accessed using both techniques. If neither bit is set in the Flags field, the I/O Manager assumes that the driver needs no further help from the I/O Manager when accessing the user's buffer.

Device Names

Devices in Windows 2000 can have more than one name. Internally, the name specified by IoCreateDevice is the name by which the device is known to the Windows 2000 Executive itself. This internal name is (almost) completely hidden from Win32 user applications. In order to expose the device to the Win32 subsystem, the Win16 subsystem, or the virtual DOS environment, the new device must be given a symbolic link name in addition to its internal name.

These two types of names live in different parts of the Object Manager's namespace. The Object Manager maintains a directory of names for all resources managed by the operating system. Internal device names are stored beneath the \Device section of the directory tree. Symbolic link names appear beneath the \?? tree. Figure 6.1 illustrates this relationship. When using IoCreateDevice, the entire \Device name must be supplied. For example, "\\Device\\Minimal0" is a suitable device name string. (The double backslash (\\) is necessary in C so that the character following the first backslash \ will not be considered a special character sequence, like \t.)

Figure 6.1. Internal and Symbolic Link names in the Object Manager's Namespace.
graphics/06fig01.gif

Internal and symbolic link names follow different device naming conventions. Internal device names tend to be longer, and they always end in a zero-based number (e.g., FloppyDisk0 or FloppyDisk1). Symbolic link names follow the usual pattern of A through Z for file-system devices, and names ending in a one-based number for other devices (e.g., LPT1 or LPT2).

To create a symbolic link name, use IoCreateSymbolicLink. This function takes an existing device name and a new symbolic name (both passed as UNICODE_STRING data types).

Finally, it must be noted that the selection of the device name is not necessarily the option of the driver. In the WDM world, bus drivers, class drivers, and many Plug and Play devices define their own names. Chapter 9 describes this process more fully. In the meantime, non-WDM drivers must supply their own unique names for each device added.

< BACK  NEXT >


The Windows 2000 Device Driver Book(c) A Guide for Programmers
The Windows 2000 Device Driver Book: A Guide for Programmers (2nd Edition)
ISBN: 0130204315
EAN: 2147483647
Year: 2000
Pages: 156

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net