Then, when the object is created, the generic part of the PCI device must initialized. The PCI_device_init function is used for this, and is called from the device's new_instance function. It takes several function pointers as arguments. These functions are used to override the generic PCI device behavior. Most of them are optional, but some must be implemented by the new device.
Once the generic part is initialized, the configuration registers should be setup. Several configuration registers are device specific and have be assigned their values here. Example:
PCI_write_config_register(&bcm_ptr->pci, PCI_VENDOR_ID, 0x12ae); PCI_write_config_register(&bcm_ptr->pci, PCI_DEVICE_ID, 0x1647); PCI_write_config_register(&bcm_ptr->pci, PCI_STATUS, 0x02b0); PCI_write_config_register(&bcm_ptr->pci, PCI_REVISION_ID, 0x00); PCI_write_config_register(&bcm_ptr->pci, PCI_CLASS_CODE, 0x020000); PCI_write_config_register(&bcm_ptr->pci, PCI_HEADER_TYPE, 0x00); ...
The PCI Device API has two functions that can be called from new_instance to tell the generic PCI code to handle accesses to a BAR. PCI_handle_mapping32 and PCI_handle_mapping64 are used for 32 and 64-bit mappings respectively. Note that 64-bit mappings use two base address registers.
There are also PCI Device API functions to modify the mappings for the device at runtime. This is usually not needed, but there are PCI devices that allow software to modify the mappings in more ways than with BARs, and in this case the functions in question are useful: PCI_set_map_base, PCI_get_map_base, PCI_set_map_size, PCI_get_map_base, PCI_set_map_enable, PCI_get_map_enable, PCI_set_map_offset and PCI_get_map_offset.
There are several functions in the PCI Device API that can be used to access the configuration, memory and I/O spaces. Calling them is equivalent to issuing PCI bus transactions in a real system. This should only be done by master capable devices.
PCI_data_from_memory and PCI_data_to_memory access raw data from a specified memory space. No endian conversion is performed. These functions are often used for DMA block transactions.
PCI_value_from_memory and PCI_value_to_memory use a value in host-endian order, and performs byte-swapping if needed. This is for example useful when the device reads data from memory that it should interpret.
If the interrupt pin is already asserted, a call to PCI_raise_interrupt has no effect, and similar for PCI_lower_interrupt when the interrupt pin already is lowered. This is important to be able to model level triggered interrupts, where the interrupt target can count the raise and lower calls from different devices to determine the actual interrupt signal level.