AddDevice Routines in Function or Filter Drivers
An AddDevice routine in a function or filter driver should take the following steps:
Call IoCreateDevice to create a functional or filter device object (an FDO or filter DO) for the device being added.
Do not specify a DeviceName for the device object, because doing so bypasses the PnP manager's security. If a user-mode component needs a symbolic link to the device, register a device interface (see the next step below). If a kernel-mode component needs a legacy device name, the driver must name the device object, but naming is not recommended.
Include FILE_DEVICE_SECURE_OPEN in the DeviceCharacteristics parameter. This characteristic directs the I/O manager to perform security checks against the device object for all open requests, including relative opens and trailing file name opens.
[optional] Create one or more symbolic links to the device.
Call IoRegisterDeviceInterface to register device functionality and create a symbolic link that applications or system components can use to open the device. The driver should enable the interface by calling IoSetDeviceInterfaceState when it handles the IRP_MN_START_DEVICE request. For more information, see Device Interface Classes.
Store the pointer to the device's PDO in the device extension.
The PnP manager supplies a pointer to the PDO as the PhysicalDeviceObject parameter to AddDevice. Drivers use the PDO pointer in calls to routines such as IoGetDeviceProperty.
Define flags in the device extension to track certain PnP states of the device, such as device paused, removed, and surprise-removed.
For example, define one flag to indicate that incoming IRPs should be held while the device is in a paused state. Create a queue for holding IRPs, if the driver does not already have a mechanism for queuing IRPs. See Queuing and Dequeuing IRPs for more information.
Also allocate an IO_REMOVE_LOCK structure in the device extension and call IoInitializeRemoveLock to initialize this structure. For more information, see Using Remove Locks.
Set the DO_BUFFERED_IO or DO_DIRECT_IO flag bit in the device object to specify the type of buffering that the I/O manager is to use for I/O requests that are sent to the device stack. Higher-level drivers OR this member with the same value as the next-lower driver in the stack, except possibly for highest-level drivers. For more information, see Initializing a Device Object.
Set the DO_POWER_INRUSH or DO_POWER_PAGABLE flag for power management, if necessary. Drivers that are pageable must set the DO_POWER_PAGABLE flag. The device object flags are typically set by the bus driver when it creates the PDO for the device. However, higher-level drivers may occasionally need to alter the values of these flags in their AddDevice routines when they create the FDO or filter DO. See Setting Device Object Flags for Power Management for details.
Create and/or initialize any other software resources the driver uses to manage this device, such as events, spin locks, or other objects. (Hardware resources, such as I/O ports, are configured later, in response to an IRP_MN_START_DEVICE request.)
Because an AddDevice routine runs in a system thread context at IRQL = PASSIVE_LEVEL, any memory allocated with ExAllocatePoolWithTag for use exclusively during initialization can be from paged pool, as long as the driver does not control the device that holds the system page file. Such a memory allocation must be released with ExFreePool before AddDevice returns control.
Attach the device object to the device stack (IoAttachDeviceToDeviceStack).
Specify a pointer to the device's PDO in the TargetDevice parameter.
Store the pointer returned by IoAttachDeviceToDeviceStack. This pointer, which points to the device object of the next-lower driver for the device, is a required parameter to IoCallDriver and PoCallDriver when passing IRPs down the device stack.
Clear the DO_DEVICE_INITIALIZING flag in the FDO or filter DO with a statement like the following:
FunctionalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
Be prepared to handle PnP IRPs for the device (such as IRP_MN_QUERY_RESOURCE_REQUIREMENTS and IRP_MN_START_DEVICE).
A driver must not start controlling the device until it receives an IRP_MN_START_DEVICE containing the list of hardware resources assigned to the device by the PnP manager.