Книга: Writing Windows WDM Device Drivers

Finding Resources

Finding Resources

The PHDIo driver is told which resources to use in the filename passed with the Create IRP. However, most NT style drivers do not have this luxury. Instead, they must use one of the following techniques to find out what resources to use.

• Ask what resources the kernel has detected.

• Interrogate configurable buses.

• Save the resource requirements in the driver's registry key when it is installed.

• Poke around in memory to see if you can find your devices.

Calling IoGetConfigurationInformation returns a count of certain types of device.


Auto-Detected Hardware

NT and Windows 2000 attempt to identify all the hardware devices attached to the system when they boot. A driver can look for suitable devices using the IoQueryDeviceDescription kernel call. IoQueryDeviceDescription calls your configuration callback routine for each matching hardware element. I have not tried to find out if this call works in Windows 98.

The automatic detection process finds all the buses on the system, all recognized controllers on each bus, and. if possible, each peripheral attached to a controller. It starts by locating any standard serial and parallel ports and finds any attached mice or printers. Along the way, it finds any disk drivers, network cards, etc. The detected information is put in the registry in the HKLMHARDWAREDESCRIPTION key.

Table 18.2 shows the parameters for IoQueryDeviceDescription. You must supply a BusType parameter, and can optionally provide ControllerType and PeripheralType parameters. These parameters are pointers, so specifying NULL means that you do not want to find this type of hardware. You also pass a callback routine and a context to pass to it.

The possible bus, controller, and peripheral types are found in the INTERFACE_TYPE and CONFIGURATION_TYPE enumerations in NTDDK.H.

Table 18.2 IoQueryDeviceDescription function

NTSTATUS IoQueryDeviceDescription (IRQL==PASSIVE_LEVEL)
Parameter Description
IN PINTERFACE_TYPE BusType Bus type
IN PULONG BusNumber Bus number, zero-based
IN PCONFIGURATION_TYPE ControllerType Controller type
IN PULONG ControllerNumber Controller number, zero-based
IN PCONFIGURATION_TYPE PeripheralType Peripheral type
IN PULONG PeripheralNumber Peripheral number, zero-based
IN PIO_QUERY_DEVICE_ROUTINE CalloutRoutine Configuration callback routine name
IN PVOID Context Context for configuration callback
Returns STATUS_OBJECT_NAME_NOT_FOUND if no match found, or status returned by callback

Listing 18.7 shows some code that finds any parallel ports that have been detected (i.e., where the ControllerType is ParallelController). The code can be found in the book software file PHDIoautodetect.cpp. Note carefully that the code will find parallel ports that are on all the available buses, not just the ISA bus. At the moment, this code just prints out the basic raw resource details using DebugPrint. If you use this code, you will eventually have to claim these resources and translate them into usable values. Do not forget that you need a separate Full Resource Descriptor for each bus type in the resource list passed to IoReportResourceUsage.

FindParallelPort loops through all possible bus types. For each bus type, it keeps incrementing the bus number from zero and checking if the bus instance exists using IoReportResourceUsage. If the bus instance does exist, it calls IoRecortResourceUsage again to find all printers on the bus instance.

The AbcConfigCallback callback is called when a bus instance is found and when a parallel port is found. In the first case, the BusInfo parameter is valid. CtrlrInfo is valid when looking for parallel ports. If looking for a peripheral, PeripheralInfo is valid. If the relevant parameter is non-NULL, it points to some information obtained from the registry: a device identifier, configuration data, and information about its subcomponents. The configuration data has the detected raw resource assignments. Use the code in Listing 18.7 to enumerate these resources.

Listing 18.7 Finding any autodetected parallel ports

NTSTATUS FindParallelPort() {
 NTSTATUS status;
 for (int BusType=0; BusType<MaximumInterfaceType; BusType++) {
  INTERFACE_TYPE iBusType = (INTERFACE_TYPE)BusType;
  CONFIGURATION_TYPE CtrlType = ParallelController;
  ULONG BusNumber =0;
  while (true) {
   // See if this bus instance exists
   status = IoGueryDeviceDescription(&iBusType, &BusNumber, NULL, NULL, NULL, NULL, AbcConfigCallback, NULL);
   if (!NT_SUCCESS(status)) {
    if (status != STATUS_OBJECT_NAME_NOT_FOUND) return status;
    break;
   }
   // See what printers exist on this bus instance
   status = IoQueryDeviceDescription(&iBusType, &BusNumber, &CtrlrType, NULL, NULL, NULL, AbcConfigCallback, NULL);
   if (!NT_SUCCESS(status) && (status != STATUS_OBJECT_NAME_NOT_FOUND)) return status;
   BusNumber++;
  }
 }
 return status;
}
NTSTATUS AbcConfigCallback(IN PVOID Context, IN PUNICODE_STRING PathName, IN INTERFACE_TYPE BusType, IN ULONG BusNumber, IN PKEY_VALUE_FULL_INFORMATION *BusInfo, IN CONFIGURATION_TYPE CtrlrType, IN ULONG CtrlrNumber, IN PKEY_VALUE_FULL_INFORMATION *CtrlrInfo, IN CONFIGURATION_TYPE Peripheral Type, IN ULONG Peripheral Number, IN PKEY_VALUE_FULL_INFORMATION *PeripheralInfo) {
 DebugPrint("ConfigCallback: Bus: %d,%d", BusType, BusNumber);
 DebugPrint("ConfigCallback: Controller: %d,%d", CtrlrType, CtrlrNumber);
 DebugPrint("ConfigCallback: Peripheral: %d,%d", PeripheralType, PeripheralNumber);
 if (CtrlrInfo!=NULL) {
  PCM_FULL_RESOURCE_DESCRIPTOR frd =
   (PCM_FULL_RESOURCE_DESCRIPTOR) (((PUCHAR)CtrlrInfo[IoQueryDeviceConfigurationData]) +
   CtrlrInfo[IoQueryDeviceConfigurationData]->DataOffset);
  for (ULONG i=0; i<frd->PartialResourceList.Count; i++) {
   PCM_PARTIAL_RESOURCE_DESCRIPTOR resource = &frd->PartialResourceList.PartialDescriptors[i];
   switch(resource->Type) {
   case CmResourceTypePort:
    DebugPrint("ConfigCallback: I/O port %x,%d", resource->u.Port.Start.LowPart, resource->u.Port.Length);
    break;
   case CmResourceTypeInterrupt:
    DebugPrint("ConfigCallback: Interrupt level %c vector %d", resource->u.Interrupt.Level, resource->u.Interrupt.Vector);
    break;
   default:
    DebugPrint("ConfigCallback: Resource type %d", resource->Type);
   }
  }
 }
 return STATUS_SUCCESS;
}

Interrogating Configurable Buses

A configurable bus is one that can be configured in software. Devices on these buses must have Plug and Play WDM device drivers. The PCI bus driver will retrieve a device's details and generate an appropriate Hardware ID. This Hardware ID will be used to identify the correct driver. Its AddDevice routine is called, etc.

In NT systems, you will need to use a different technique to get configurable bus data. This method still works in Windows 2000. The HalGetBusData and HalGetBusDataByOffset calls can be made to retrieve configuration data for one slot of a specified bus instance. For example, if you ask for PCIConfiguration bus data, the passed buffer is filled with PCI_COMMON_CONFIG data.

You can then claim the necessary resources using IoAssignResources, in a similar way to IoReportResourceUsage. As an alternative, drivers of PCI-type devices can call HalAssignSlotResources. HalSetBusData and HalSetBusDataByOffset can be used to write back configuration data.

I have not tried it, but it looks as though HalGetBusData and HalSetBusData can be used to access the BIOS CMOS data.

Final Resource Discovery Techniques

There are two final ways of obtaining a driver's resource requirements. The first is to store the relevant information in the driver's registry key, say in its Parameters subkey. This information will typically be set up when the device is installed.

Last and least, you can simply poke around in likely memory locations to see if your device is present. Dangerous.

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


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