HOWTO: Create a PCI Device Driver for Windows NT

Last reviewed: February 17, 1998
Article ID: Q152044

The information in this article applies to:
  • Microsoft Win32 Device Driver Kit (DDK), versions 3.5, 3.51

SUMMARY

This article describes how to create a PCI Device driver for Windows NT. A device driver must perform many functions, such as creating a device object, etc. In addition, there are many more functions that a driver must perform during driver initialization to support a PCI device. Note that some of the functions mentioned below are also used in non-PCI drivers.

MORE INFORMATION

Following are the steps necessary to accomplish this task:

  1. Find the PCI device with HalGetBusData:

    Scan all the buses and slots to find the location of your PCI device. In the buffer returned by HalGetBusData, look for a match to your device's PCI VendorId and DeviceId.

    If your device driver requires additional information from the PCI configuration space, use HalGetBusData or HalGetBusDataByOffset. Fields in the PCI configuration space can be set with HalSetBusData or HalSetBusDataByOffset.

    IMPORTANT: Do not set the base address registers (BARs) or the interrupt information in the PCI configuration space. Also, do not expect the BARs original settings to be those that will be used for your device. Since PCI is dynamically configurable, the operating system reserves the right to move the BARs as it sees fit.

    Find the PCI device with 3 FOR loops: one for the bus, one for the device number, and one for the function number. Note that the structure PCI_SLOT_NUMBER contains the device number and function number information.

  2. Claim the device resources with HalAssignSlotResources:

    Once the PCI device is located, pass the bus and slot information to HalAssignSlotResources. This API will ensure that there are no conflicts with the resources specified in the configuration space. Note that the HAL may move your memory or port ranges, so don't use the values directly from the configuration space. Instead, use the values returned in the resource list and translate them as indicated below.

  3. Parse the resource list for the device resources:

    HalAssignSlotResources will claim the PCI device resources and return the claimed resources in a CM_RESOURCE_LIST structure. The driver will have to parse this resource list to get the interrupt, memory range, and I/O range information. Note that a single PCI device can have multiple memory and I/O ranges. If necessary, save this information in the driver's device extension for later translation. Do not use the raw resource information to access the I/O or memory spaces.

    At this point, if the driver were to examine the PCI configuration space, the BARs should be the same as those returned in the CM_RESOURCE_LIST structure. However, use the information returned in the resource list.

  4. For each memory range claimed, call HalTranslateBusAddress and MmMapIoSpace:

    HalTranslateBusAddress translates a bus-specific address into the corresponding system-logical address. After the call to this API, check the fourth parameter. On entry to the API, zero indicates memory space. On exit from the API, if the value is still zero, as is the normal case for memory translation, the driver must also call MmMapIoSpace.

    Save the translated memory range information in a driver-accessible area like the device extension. Use the translated range to access the memory space.

  5. For each I/O range claimed, call HalTranslateBusAddress, and if needed, MmMapIoSpace:

    Mapping is similar to that for memory space. However, on entry to HalTranslateBusAddress, the fourth parameter is one, which indicates I/O space. On exit, the API may have changed this parameter to zero, in which case the driver must also call MmMapIoSpace.

    Save the translated I/O range information in a driver-accessible area like the device extension. Use the translated range to access the I/O space.

    On some RISC-based systems, there is no I/O space: I/O space is mapped to memory space. In this situation, the fourth parameter will change to indicate that the I/O space has been mapped to memory space. On an x86- based system, translating an I/O space will use HalTranslateBusAddress, but not MmMapIoSpace. On some RISC-based systems, both HalTranslateBusAddress and MmMapIoSpace might be called. It is important to check the fourth parameter of HalTranslateBusAddress after the call to this API.

    This is a common problem when porting from x86-based machines to RISC platforms. Driver writers sometimes assume that if they are translating I/O ranges, they will never need to call MmMapIoSpace. This is an incorrect assumption.

  6. If the device supports interrupts, call HalGetInterruptVector and IoConnectInterrupt:

    Once IoConnectInterrupt has been called, the driver's interrupt service routine (ISR) might be called if the PCI device is interrupting. For this reason, it is best to connect the interrupt after translating all the device registers. If the previous translation has not occurred or the information is not available to the ISR (if, for example, the translated memory and I/O ranges are not saved in the device extension), the ISR will not be able to check the PCI device registers and clear the interrupt. If the interrupt is not cleared, the system will hang.

REFERENCES

Please see the Windows NT Device Driver Kit, Kernel-mode Drivers, Design Guide for an overview of Windows NT device drivers. The APIs mentioned above are explained in detail in the Windows NT Device Driver Kit, Kernel- mode Drivers, Reference section.


Additional query words: PCI HAL
Keywords : NTDDKKMode
Version : WINNT:3.5,3.51;
Platform : winnt
Issue type : kbhowto


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: February 17, 1998
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.