MSDN Documentation

Driver Entry Points

This document details the fundamental entry points for Windows drivers, specifically focusing on the I/O Subsystem. Understanding these points is crucial for developing robust and efficient kernel-mode drivers.

Overview

Every Windows driver must expose specific functions that the operating system kernel calls to manage the driver's lifecycle and operations. These functions serve as the interfaces between the driver and the I/O Manager. Key entry points include the driver's initialization routine, unload routine, and routines for handling I/O requests.

Core Entry Points

DriverEntry

This is the first function that the I/O Manager calls when it loads a device driver. It's the driver's primary initialization routine.

  • Signature: NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath);
  • Parameters:
    • DriverObject: A pointer to a DRIVER_OBJECT structure, which the I/O Manager allocates and initializes. The driver uses this structure to record information about itself.
    • RegistryPath: A pointer to a UNICODE_STRING that specifies the path to the driver's parameters in the registry.
  • Return Value: STATUS_SUCCESS on successful initialization, or an appropriate NTSTATUS error code if initialization fails.
  • Responsibilities:
    • Initialize the driver's global state.
    • Create device objects for each hardware device the driver controls.
    • Set up dispatch routines in the DriverObject structure to handle various I/O requests (e.g., IRP_MJ_CREATE, IRP_MJ_READ).
    • Initialize any necessary synchronization objects.

AddDevice

This routine is called by the PnP Manager when a device controlled by the driver is enumerated and needs to be started. It's a critical part of Plug and Play driver development.

  • Signature: NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT PhysicalDeviceObject);
  • Parameters:
    • DriverObject: A pointer to the driver's DRIVER_OBJECT.
    • PhysicalDeviceObject: A pointer to the physical device object (PDO) representing the hardware device.
  • Return Value: STATUS_SUCCESS if a functional device object (FDO) was created and attached successfully, or an appropriate NTSTATUS error code.
  • Responsibilities:
    • Create a functional device object (FDO) for the device.
    • Attach the FDO to the device stack, typically above the PDO.
    • Initialize the device's state and hardware.

Unload

This optional routine is called by the I/O Manager when the driver is unloaded from memory. It allows the driver to perform cleanup operations.

  • Signature: VOID Unload(PDRIVER_OBJECT DriverObject);
  • Parameters:
    • DriverObject: A pointer to the driver's DRIVER_OBJECT.
  • Responsibilities:
    • Delete any device objects created by the driver.
    • Free any system resources allocated during initialization (e.g., memory, interrupts, DMA).
    • Clean up any outstanding I/O requests.

Dispatch Routines

Drivers implement a set of dispatch routines to handle specific types of I/O Request Packets (IRPs) sent by the I/O Manager. These routines are assigned to members of the DriverObject structure, indexed by IRP major function codes.

Common dispatch routines include:

Important: A well-behaved driver must handle all relevant IRP major functions. If a driver does not support a particular IRP, it should typically pass the IRP down to the next driver in the stack or return an appropriate error code.

Dispatch Routine Signature

All I/O dispatch routines share a common signature:

NTSTATUS DispatchRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp);

Example Snippet (Conceptual)


// DriverEntry function excerpt
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
    // ... initialization code ...

    // Set up dispatch routines
    DriverObject->MajorFunction[IRP_MJ_CREATE] = MyCreateClose;
    DriverObject->MajorFunction[IRP_MJ_CLOSE] = MyCreateClose;
    DriverObject->MajorFunction[IRP_MJ_READ] = MyRead;
    DriverObject->MajorFunction[IRP_MJ_WRITE] = MyWrite;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MyDeviceControl;
    DriverObject->MajorFunction[IRP_MJ_PNP] = MyPnp;
    DriverObject->MajorFunction[IRP_MJ_POWER] = MyPower;

    // Assign the unload routine
    DriverObject->DriverUnload = MyUnload;

    // ... more initialization ...
    return STATUS_SUCCESS;
}

// Example dispatch routine signature
NTSTATUS MyRead(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
    // Handle read request
    // ...
    return STATUS_SUCCESS; // or STATUS_PENDING, or an error code
}