QNX Developer Support
![]() |
![]() |
![]() |
![]() |
pci_attach_device()
Attach a driver to a PCI device
Synopsis:
#include <hw/pci.h>
void* pci_attach_device(
void* handle,
uint32_t flags,
uint16_t idx,
struct pci_dev_info* info );
Arguments:
- handle
- A handle that identifies the device. The first time you call this function, set handle to NULL. This function returns a handle that you can use in a subsequent call to allocate resources for the device.
- flags
- Flags that tell the PCI server how you want it to handle resources, which resources to scan for, and which resources to allocate; see "Flags," below.
- idx
- The index of the device: 0 for the first device, 1 for the second, and so on.
- info
- A pointer to a pci_dev_info structure (see below) that specifies the class code, vendor/device ID, or bus number and device/function number that you want to scan for. The function fills in this structure with information about the device.
Library:
libc
Use the -l c option to qcc to link against this library. This library is usually included automatically.
Description:
The pci_attach_device() function attaches a driver to a PCI device.
![]() |
You must successfully call pci_attach() before calling any of the other PCI functions. |
Typically drivers use this function to attach themselves to a PCI device, so that other drivers can't attach to the same device. If you specify the PCI_SHARE flag (see "Flags," below), then multiple drivers can attach to the same device.
The server can scan based on a class code, vendor/device ID, or bus number and device/function number. To control the server scanning, initialize the appropriate fields of the info structure and set the appropriate flags.
When you first attach to an uninitialized device, the PCI server assigns all the I/O ports, memory and IRQs required for the device. It also does the IRQ routing for you. Once this has completed successfully, it fills in all these values into your pci_dev_info structure to return these values to your application.
When a driver attaches to a device, the PCI server allocates the necessary resources for the device from procnto using the rsrcdbmgr* calls. On X86 BIOS systems, these resources are normally allocated by the BIOS, but on non-x86 systems, these resources have to be allocated from procnto.
You can detach the device by passing its handle to pci_detach_device(). If you call pci_detach(), any resources that pci_attach_device() allocates are freed.
pci_dev_info structure
This function fills in a pci_dev_info structure that describes an occurrence of a device.
![]() |
The pci_attach_device() function doesn't map any of the I/O or memory regions into the process's address space. The addresses returned in the pci_dev_info structure are all physical addresses. |
This structure has the following members:
- uint16_t DeviceId
- The device ID (input/output). For a list of supported device IDs, see <hw/pci_devices.h>.
- uint16_t VendorId
- The vendor ID (input/output). For a list of supported vendor IDs, see <hw/pci_devices.h>.
- uint16_t SubsystemId
- The subsystem ID (output).
- uint16_t SubsystemVendorId
- The subsystem vendor ID (output).
- uint8_t BusNumber
- The bus number (input/output).
- uint8_t DevFunc
- The device/function number (input/output).
- uint8_t Revision
- The device revision (output).
- uint32_t Class
- The class code (input/output). For a list of class codes, see <hw/pci.h>. This field is an ORed combination of a class code and a subclass code (e.g. PCI_CLASS_DISPLAY | PCI_SUBCLASS_DISPLAY_XGA).
- uint32_t Irq
- The interrupt number (output).
- uint64_t CpuIoTranslation
- The CPU-to-PCI translation value (pci_addr = cpu_addr - translation).
- uint64_t CpuMemTranslation
- The CPU-to-PCI memory translation (pci_addr = cpu_addr - translation).
- uint64_t CpuIsaTranslation
- The CPU-to-ISA memory translation (pci_addr = cpu_addr - translation).
- uint64_t CpuBmstrTranslation
- The translation from the CPU busmaster address to the PCI busmaster address (pci_addr = cpu_addr + translation).
- uint64_t PciBaseAddress [6]
- The PCI base address (array of six uint64_t items).

This function decodes bits 1 and 2 to see whether the register is 32 or 64 bits wide, hence the 64-bit values for the base registers.
- uint64_t CpuBaseAddress [6]
- The CPU base address (an array of six uint64_t items).
Some platforms translate addresses across PCI bridges, so that there's one address on the PCI side of the bridge and another on the CPU side. Under x86, the PciBaseAddress and CpuBaseAddress are the same, but under other platforms, these will be different. In your user application you should always use the CpuBaseAddress.
- uint32_t BaseAddressSize [6]
- The size of the base address aperture into the board (an array of six uint32_t items).
- uint64_t PciRom
- The PCI ROM address.
- uint64_t CpuRom
- The CPU ROM address.
- uint32_t RomSize
- The size of the aperture into the board.
Flags
The flags parameter tells the PCI server how resources are to be handled, which resources to scan for, and which resources to allocate.
These bits control how resources are handled:
- PCI_SHARE
- Allow resources to be shared with other drivers. If this isn't set, no other driver can attach to the device.
- PCI_PERSIST
- Resources persist after the device is detached.
The following bits ask the PCI server to scan for a device based on the fields that you specified in the structure pointed to by info:
- PCI_SEARCH_VEND
- VendorID
- PCI_SEARCH_VENDEV
- DeviceId and VendorId
- PCI_SEARCH_CLASS
- Class
- PCI_SEARCH_BUSDEV
- BusNumber and DevFunc
These bits specify which members of the structure the server should initialize:
- PCI_INIT_IRQ
- Irq
- PCI_INIT_ROM
- PciRom and CpuRom
- PCI_INIT_BASE0 ... PCI_INIT_BASE5
- The specified entries of the PciBaseAddress and CpuBaseAddress arrays
- PCI_INIT_ALL
- All members except PciRom and CpuRom
The bits also include:
- PCI_MASTER_ENABLE
- Enable bus mastering on the device.
If you pass 0 for the flags, the default is PCI_SEARCH_VENDEV.
Testing and converting addresses
To facilitate the testing of addresses returned by the PCI server, at least the following macros are defined in the <hw/pci.h> header file:
- PCI_IS_IO( address )
- Test whether the address is an I/O address.
- PCI_IS_MEM( address )
- Test whether the address is a memory address.
- PCI_IO_ADDR( address )
- Convert the address returned by the PCI server to an I/O address.
- PCI_MEM_ADDR( address )
- Convert the address returned by the PCI server to a memory address.
- PCI_ROM_ADDR( address )
- Convert the address returned by the PCI server to a ROM address.
For example:
{
uint64_t port;
/* Test the address returned by the pci server */
if (PCI_IS_IO(addr))
port = (PCI_IO_ADDR(addr));
}
Returns:
A handle to be used for other pci_* calls associated with a handle, or NULL if an error occurs (errno is set).
Errors:
- EBUSY
- An application has already attached to the device. If it's safe to share the device, specify PCI_SHARE in the flags field.
- EINVAL
- The function couldn't attach a resource to the device.
- ENODEV
- This device wasn't found.
Examples:
Attach to and allocate all resources for the first occurrence of an Adaptec 2940 adapter:
#include <hw/pci.h>
#include <hw/pci_devices.h>
#include <stdio.h>
#include <stdlib.h>
int main( void )
{
int pidx;
void* hdl;
int phdl;
struct pci_dev_info inf;
/* Connect to the PCI server */
phdl = pci_attach( 0 );
if( phdl == -1 ) {
fprintf( stderr, "Unable to initialize PCI\n" );
return EXIT_FAILURE;
}
/* Initialize the pci_dev_info structure */
memset( &inf, 0, sizeof( inf ) );
pidx = 0;
inf.VendorId = PCI_VENDOR_ID_ADAPTEC;
inf.DeviceId = PCI_DEVICE_ID_ADAPTEC_2940F;
hdl = pci_attach_device( NULL, PCI_INIT_ALL, pidx, &inf );
if( hdl == NULL ) {
fprintf( stderr, "Unable to locate adapter\n" );
} else {
/* Do something to the adapter */
pci_detach_device( hdl );
}
/* Disconnect from the PCI server */
pci_detach( phdl );
return EXIT_SUCCESS;
}
Attach to the first occurrence of an Adapter 2940 adapter and allocate resources in a second call:
#include <hw/pci.h>
#include <hw/pci_devices.h>
#include <stdio.h>
#include <stdlib.h>
int main( void )
{
int pidx;
void* hdl;
void* retval;
int phdl;
struct pci_dev_info inf;
phdl = pci_attach( 0 );
if( phdl == -1 ) {
fprintf( stderr, "Unable to initialize PCI\n" );
return EXIT_FAILURE;
}
memset( &inf, 0, sizeof( inf ) );
pidx = 0;
inf.VendorId = PCI_VENDOR_ID_ADAPTEC;
inf.DeviceId = PCI_DEVICE_ID_ADAPTEC_2940F;
hdl = pci_attach_device( NULL, 0, pidx, &inf );
if( hdl == NULL ) {
fprintf( stderr, "Unable to locate adapter\n" );
}
retval = pci_attach_device( hdl, PCI_INIT_ALL, pidx, &inf );
if( retval == NULL ) {
fprintf( stderr, "Unable allocate resources\n" );
}
pci_detach( phdl );
return EXIT_SUCCESS;
}
Classification:
| Safety: | |
|---|---|
| Cancellation point | Yes |
| Interrupt handler | No |
| Signal handler | Yes |
| Thread | Yes |
See also:
pci_attach(), pci_detach(), pci_detach_device(), pci_find_class(), pci_find_device(), pci_present(), pci_read_config(), pci_read_config8(), pci_read_config16(), pci_read_config32(), pci_rescan_bus(), pci_write_config()
![]() |
![]() |
![]() |
![]() |

![[Previous]](../prev.gif)
![[Contents]](../contents.gif)
![[Index]](../keyword_index.gif)
![[Next]](../next.gif)
