In RISC OS, PCI devices can be identified in one of two ways. Users generally need only be aware of the PCI system when expansion cards are added to the machine, and will use the PCI slot number, in commands like *Unplug or *PCIDevices. Slot numbers are fixed for a given system.
Device drivers use a PCI handle – each function of each PCI device in the system is given a unique, permanent non-zero handle when it is discovered. Handles remain constant as long as the device remains present in the system, but can change when the system is rebooted, or if a card is removed and reinserted (if the system supports hot-plugging). Handles do not change if the PCI Manager is reloaded. Handles are assigned from 1 upwards, so can be searched linearly, much like Expansion Cards.
Since PCI interrupt lines are shared by multiple devices, the interrupt handling mechanism is a little different from that used by traditional expansion cards. To find the device vector number that will be called for a particular card, use PCI_ReadInfo with bit 11 set in the R0 bitmask. To install a device driver, use OS_ClaimDeviceVector and pass in this vector number with bit 31 set to indicate that the call may be passed on to other vector claimants. You must also ensure that interrupts for this vector are enabled by calling the HAL routine HAL_IRQEnable (HAL entry number 1) with this vector number as the parameter. Note however that when you remove a device driver, you should not disable interrupts for this vector.
When your device driver routine is called, check whether your card is interrupting. If it is, perform the necessary interrupt processing and claim the vector by pulling the return address from the stack. If it is not, pass on the call by returning to the address in R14. If you are writing a device driver in C, use the CMHG ‘vector-handlers’ veneer and return 0 to claim the call or 1 to pass it on.
When the interrupt processing code needs to clear the interrupt on the PCI card, there are two things that must be done before interrupts are re-enabled or you return from the handler. Firstly, if clearing the interrupt involves writing to a register on the PCI card, you must ensure that the write has been flushed out to the card. This can be achieved by simply performing a read operation from a safe area or register on the card. Secondly, you should then call the HAL routine HAL_IRQClear (HAL entry number 3) with the vector number as the parameter. Note that this is not actually required for the Iyonix hardware, but should be included for compatibility with possible future hardware platforms.
If no handler claims a vector for a particular interrupt, the kernel will disable that interrupt line. For correct operation of the system it is vital that vector claiming and interrupt clearing are performed correctly.