Книга: Writing Windows WDM Device Drivers

Advanced Plug and Play

Advanced Plug and Play

This section looks at some advanced Plug and Play topics.

Bus Drivers

This section looks briefly at the job a bus driver must do. Please consult the DDK documentation for full details. The W2000 DDK source code kernelserenum example shows how a bus driver is coded.

Bus drivers must manage their device objects carefully. A bus driver has a Functional Device Object (FDO) for each instance of a bus. A bus driver detects any devices on its bus and creates child device objects for each device. These are actually the Physical Device Objects (PDOs) to which higher driver layers attach.

The IRP dispatch routines in a bus driver handle requests for both FDOs and child PDOs. Use a flag in a common portion of the FDO and PDO device extensions to indicate whether the device is an FDO or a child PDO.

If a bus driver detects a Plug and Play device arriving or removing, it must call IoInvalidateDeviceRelations. The PnP Manager then sends an IRP_MN_QUERY_DEVICE_RELATIONS PnP IRP to get the new details. Non-Plug and Play devices can be reported in W2000 using IoReportDetectedDevice.

Creating Child Devices

A bus driver must enumerate its own bus to find any attached devices. It must also keep checking to see if any devices are removed or added. A bus driver might use a system worker thread, described in chapter 14, to schedule its device checks.

A bus driver must call IoInvalidateDeviceRelations if it detects any new devices or if one of its child devices has been removed. This call forces the PnP Manager to issue an IRP_MN_QUERY_DEVICE_RELATIONS BusRelations IRP to the bus driver FDO. The bus driver then enumerates its bus fully. It calls IoCreateDevice to make the child PDO for each new child device.[24] The bus driver returns a list of all valid child PDOs. The PnP Manager works out what PDOs have been added or removed.

If a new device has arrived, the PnP Manager starts to configure this device and build a new device stack. It issues various PnP IRPs to this child PDO. The IRP_MN_QUERY_ID IRP requests the hardware and compatible ids for the device. The PnP Manager also issues IRP_MN_QUERY_CAPABILITIES. IRP_MN_QUERY_DEVICE_TEXT, IRP_MN_QUERY_ RESOURCES and IRP_MN_QUERY_RESOURCE_REQUIREMENTS requests to get further information about the device. Chapter 11 shows how the PnP Manager uses all this information and INF files to determine which drivers should be loaded on top of the child PDO. The stack drivers' AddDevice routines are run and Start Device IRPs issued as usual.

If a function driver decides that a device is no longer present, it can call IoInvalidateDeviceState. The PnP Manager issues an IRP_MN_QUERY_PNP_DEVICE_STATE request. If it finds the PNP_DEVICE_FAILED state bit set, then it issues a (surprise) remove PnP message.

FDO IRP Handling

Normally, a bus driver FDO will receive only AddDevice and Plug and Play IRPs. As mentioned previously, it should enumerate its bus when it receives an IRP_MN_QUERY_DEVICE_ RELATIONS BusRelations PnP IRP. It should return some meaningful information for an IRP_ MN_QUERY_BUS_INFORMATION request.

The bus driver FDO should also process all the standard Plug and Play IRPs in the usual way. Make sure that it can cope if it receives a Remove Device IRP while child devices are still attached to the bus. The DDK documentation says that Query Remove requests are sent to the child devices before being sent to the main FDO.

Child PDO PnP Handling

The child PDO receives IRPs that have been passed down the device stack. Note that it will not receive an AddDevice call. AddDevice is called to create a new device. The bus driver has already done this job, so there is no need for an AddDevice call for a child PDO.

The child PDO handles all the PnP IRPs that come down the device stack. A bus driver handles some of these IRPs differently from function and filter drivers. In particular, it must always complete the PnP IRP so that the IRP can begin its journey up the stack. However, if it does not handle a particular minor function code, it should not change the value in the IoStatus.status field as the PnP Manager sets this field to STATUS_NOT_SUPPORTED in advance.

A bus driver should consider handling these IRPs correctly for the child PDO: IRP_MN_ QUERY_CAPABILITIES, IRP_MN_QUERY_DEVICE_TEXT, IRP_MN_QUERY_ID, and IRP_MN_QUERY_ DEVICE_RELATIONS.

Child PDO I/O IRP Handling

The child PDO also receives any other IRPs that come down the stack. These IRPs will be the create, close, read, write, or IOCTL I/O requests that do a useful job.

The child PDO handler for these requests could interact with the bus directly. However, it is possible that all bus operations have to be performed in a controlled manner, rather than have all child PDOs trying to access it at once. One option, therefore, is to pass any incoming I/O IRPs to the bus driver FDO. The bus driver FDO handler for these IRPs can do whatever is necessary (e.g., serialize all I/O requests).

If you use this technique, you will obviously need to store a pointer to the parent bus driver FDO in the child PDO device extension. Use IoCallDriver as usual to pass on any IRPs.

There is one thing to remember if using this technique. The number of IRP stack locations for the child PDOs will have to be increased as the IRPs will be passed down through more driver layers. Simply add the FDO Stacksize field to the child PDO Stacksize after IoCreateDevice has returned.

Sending PnP IRPs

Most PnP IRPs are sent by the PnP Manager, but some can be sent by drivers (e.g., IRP_MN_ QUERY_INTERFACE). A driver must send a PnP IRP to the driver at the top of the device stack. Call IoGetAttachedDeviceReference to get a pointer to the device object for the driver at the top of the device stack.

Device Properties

In AddDevice (or elsewhere) you can ask for various properties of the PDO using IoGetDeviceProperty. The property information is stored in the registry but is best accessed using IoGetDeviceProperty. The DeviceProperty parameter has the information you want. You also supply a buffer that is filled with the appropriate information.

Among other things, you can ask for the device's hardware ID and the GUID of the bus driver and the device's setup class. Sometimes you may need to call IoGetDeviceProperty twice. The first call informs you of the size of buffer required, while the second call actually gets the data.

Оглавление книги


Генерация: 1.159. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз