PCI Device access under 32-Bit PM DOS
From Open Watcom
Contents |
Introduction
This section contains working code (including comments) for PCI configuration access under 32-Bit PM DOS
What you should know about PCI
How to identify your card
Every PCI device (either an adapter card or a chip on the motherboard) has its Vendor and Device ID. The Vendor ID is given to you by the PCI SIG (Special Interest Group). You can lookup an PCI vendor ID via http://www.pcisig.com/membership/vid_search/. The Device ID is assigned by the vendor. It's a unique ID to distinguish between different devices from the same vendor. There is a handy searchable PCI Database of vendor and device IDs.
If you want to access a device via PCI BIOS you must find your device(s). Your device configuration will be addressed by: bus/dev(ice)/func(tion). A Bus is the highest level of the PCI topology. Additional buses may be accessed through PCI bridges; most PCs have multiple buses, for instance AGP or PCI Express slots are always on a separate bus. The Device is the main device identifier. A PCI device can have more than one function (with different classes). The Function is a "subdevice" of the main device. For example: a SCSI card can have two subdevices for 2 different SCSI bus controllers. The "subdevices" can have different classes. For instance a PCI Bridge can have a PCI Bridge part and an Interrupt controller part.
- Search for your device:
uint8_t bus, dev, func;
uint16_t marker = 0;
while(pci_true==PciSearchForDevice(0x8086, 0x1026, &bus, &dev, &func, &marker))
{
printf("Device 0x8086:0x1026 found at: %d.%d.%d\n", bus, dev, func);
}
Enable the access to the card
If you want to communicate with a PCI device you must ensure that the desired access response bit in the PCI Command register is enabled. A device must not respond to an access if its specific bit in the command register is set to 0. A device will respond to an access if the specified bit in the command register is set to 1. The Command register is defined in pci.h as PCI_CFG_R16_CMD
Enable the desired response via:
uint16_t nCmd; nCmd = PciReadConfigWord(bus, dev, func, PCI_CFG_R16_CMD); // 0x03 is 0000'0011b and means IO and memory response nCmd |= 0x03; PciWriteConfigWord(bus, dev, func, PCI_CFG_R16_CMD, nCmd);
Keep in mind that PCI devices should normally be enabled by the system BIOS. If a device was not enabled and you enable it manually, you must ensure that its memory and I/O address ranges do not conflict with any other device in the system; otherwise the system is likely to malfunction or lock up.
Here is a small list of the most used access mechanisms to a PCI device:
- I/O Space response
Bit 0 of the Command regsiter
- Memory Space response
Bit 1 of the Command register
- Bus master
Bit 2 of the Command register
How to use the PCI library
Check if the PCI BIOS is present
if(pci_false==IsPciBiosPresent())
{
printf("PCI BIOS not present!\n");
}
Find your device
uint8_t bus, dev, func;
uint16_t marker = 0;
uint16_t venid = 0x8086;
uint16_t devid = 0x1209; // Intel 82559er Ethernet chip
while(pci_true==PciSearchForDevice(venid, devid, &bus, &dev, &func, &marker))
{
// Some variables
uint16_t nCmdReg;
uint32_t nBar0, nBar1, nBar2, nBar3, nBar4, nBar5;
// Do something with your device
// eg: enable IO and memory response for the device
nCmdReg = PciReadConfigWord(bus, dev, func, PCI_CFG_R16_CMD);
nCmdReg |= 0x03;
PciWriteConfigWord(bus, dev, func, PCI_CFG_R16_CMD, nCmdReg);
// Show BAR information
nBar0 = PciReadConfigDWord(bus, dev, func, PCI_CFG_R32_BAR0);
nBar1 = PciReadConfigDWord(bus, dev, func, PCI_CFG_R32_BAR1);
nBar2 = PciReadConfigDWord(bus, dev, func, PCI_CFG_R32_BAR2);
nBar3 = PciReadConfigDWord(bus, dev, func, PCI_CFG_R32_BAR3);
nBar4 = PciReadConfigDWord(bus, dev, func, PCI_CFG_R32_BAR4);
nBar5 = PciReadConfigDWord(bus, dev, func, PCI_CFG_R32_BAR5);
printf("BAR0: 0x%08X\n", nBar0);
printf("BAR1: 0x%08X\n", nBar1);
printf("BAR2: 0x%08X\n", nBar2);
printf("BAR3: 0x%08X\n", nBar3);
printf("BAR4: 0x%08X\n", nBar4);
printf("BAR5: 0x%08X\n", nBar5);
}
Example: LED Blinking on 8541GI Ethernet controller (access via Memory map)
currently not retested!
#include <stdio.h>
#include <i86.h>
#include <conio.h>
#include "pci.h"
//
// DpmiMapPhysMemory()
//
// Input: start - address of physical memory
// length - length of memory map
//
// Return: Address of linear mapped memory or NULL if not mapped
//
uint32_t DpmiMapPhysMemory(uint32_t start, uint32_t length)
{
union REGS regs;
regs.w.ax = 0x0800;
regs.w.bx = start>>16;
regs.w.cx = start&0xffff;
regs.w.si = length>>16;
regs.w.di = length&0xffff;
int386(0x31, ®s, ®s);
if(regs.w.cflag&INTR_CF)
return 0;
return ((regs.w.bx<<16)&0xffff0000)|regs.w.cx;
}
//
// DpmiUnMapPhysMemory()
//
// Input: mapmem - address returned by DpmiMapPhysMemory
//
// Return: Nothing
//
void DpmiUnMapPhysMemory(uint32_t mapmem)
{
union REGS regs;
regs.w.ax = 0x0801;
regs.w.bx = mapmem>>16;
regs.w.cx = mapmem&0xFFFF;
int386(0x31, ®s, ®s);
}
#define LEDS_ON 0xE0E0E0E0
#define LEDS_OFF 0xE2E2E2E2
void main(int argc, char**argv)
{
uint8_t bus, dev, func;
uint16_t marker = 0;
uint16_t venid = 0x8086;
uint16_t devid = 0x1076; // Intel 82541GI GB Ethernet
printf("PCI Library demonstration program\n");
printf("Copyright (c) 2006 Philipp Diethelm\n");
// Check if PCI bios present
if(!IsPciBiosPresent())
{
printf("ERROR: PCI System required!\n");
return;
}
// Print some information
printf("PCI BIOS V%X.%X present\n", GetPciBiosVerHi(), GetPciBiosVerLo());
// GetPciBussesInSystem() return the max. PCI bus in system
// The root pci bus is 0. Adding 1 to include bus #0
printf("PCI Bios reports %d PCI busses in system\n", GetPciBussesInSystem()+1);
printf("PCI Device count: %d\n", GetPciDeviceCount());
// Search for Intel Gigabit ethernet card (device id 1026)
while(pci_true==PciSearchForDevice(venid, devid, &bus, &dev, &func, &marker))
{
// Some variables
uint16_t nCmdReg;
uint32_t nBar0;
uint8_t* pBar0;
uint32_t* pLedControl;
uint32_t nSavedLedState;
printf("Found Device %04X:%04X at %X.%X.%X\n", venid, devid, bus, dev, func);
// Do something with your device
// eg: enable IO and memory response for the device
nCmdReg = PciReadConfigWord(bus, dev, func, PCI_CFG_R16_CMD);
nCmdReg |= 0x03;
PciWriteConfigWord(bus, dev, func, PCI_CFG_R16_CMD, nCmdReg);
// Show BAR information
nBar0 = PciReadConfigDWord(bus, dev, func, PCI_CFG_R32_BAR0);
printf("BAR0: 0x%08X\n", nBar0);
// Map the memory
pBar0 = (uint8_t*)DpmiMapPhysMemory(nBar0&(~0xf), 0x1000);
printf("Mapped Memory: 0x%08X\n", pBar0);
// Init LED control pointer
pLedControl = (uint32_t*)(pBar0+0xE00);
// Backup the LED control register
nSavedLedState = *pLedControl;
printf("LED Status: 0x%08X\n", nSavedLedState);
// Blink the LED's
while(!kbhit())
{
// Play with the LED's
*pLedControl = LEDS_ON;
delay(500);
// Play with the LED's
*pLedControl = LEDS_OFF;
delay(500);
}
// Restore the LED control register
*pLedControl = nSavedLedState;
// Unmap the memory
DpmiUnMapPhysMemory((uint32_t)pBar0);
}
}
Links
If you're a pcisig member, you can find more information under these links:
For everyone:
Library Sourcecode
pci.h
// // Copyright (c) 2004, 2006 Philipp Diethelm // // Permission is hereby granted, free of charge, to any person obtaining a copy of this software, to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to // do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE // OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // // // pci.h // Version: 1.1 // // Version history // 1.0 23.01.2006 Initial release // 1.1 30.01.2006 Changed return type of IsPciBiosPresent() to pcibool // 1.2 30.01.2006 Added PciSearchForDevice() // 1.3 31.01.2006 Updated code to uint??_t datatypes // #ifndef __PCI_H__INCLUDED__ #define __PCI_H__INCLUDED__ #ifndef __PCI_TYPES_H__INCLUDED__ #include "pci_types.h" #endif // // Defines for PCI stuff // // Values for GetLastPciError() #define PCI_ERR_SUCCESS 0x00 // No error (success) #define PCI_ERR_UNSUPP 0x81 // Unsupported function #define PCI_ERR_BADVENID 0x83 // Bad vendor id #define PCI_ERR_NODEV 0x86 // Device not found #define PCI_ERR_BADREG 0x87 // Bad register number // Values for BIOS functions #define PCI_INT 0x1A // PCI BIOS Interrupt #define PCI_SIGNATURE ' ICP' // Signature for INSTALL call #define PCI_DEV_MAX 0x1F // Max. value for dev parameter #define PCI_FUNC_MAX 0x07 // Max. value for func parameter #define PCI_BIOS_INSTALL 0xB101 // PCI Bios installation check #define PCI_BIOS_FINDDEV 0xB102 // PCI Bios find device #define PCI_BIOS_FINDCLASS 0xB103 // PCI Bios find class #define PCI_BIOS_CFG_RD8 0xB108 // PCI Bios Read configuration byte #define PCI_BIOS_CFG_RD16 0xB109 // PCI Bios Read configuration word #define PCI_BIOS_CFG_RD32 0xB10A // PCI Bios Read configuration dword #define PCI_BIOS_CFG_WR8 0xB10B // PCI Bios Write configuration byte #define PCI_BIOS_CFG_WR16 0xB10C // PCI Bios Write configuration word #define PCI_BIOS_CFG_WR32 0xB10D // PCI Bios Write configuration dword // Values for Configuration registers // Generic Registers (For all devices) #define PCI_CFG_R16_VENID 0x00 // Vendor ID register #define PCI_CFG_R16_DEVID 0x02 // Device ID register #define PCI_CFG_R16_CMD 0x04 // Command register #define PCI_CFG_R16_STATUS 0x06 // Status register #define PCI_CFG_R16_REV 0x08 // Revision ID register #define PCI_CFG_R24_CLASS 0x09 // Class code #define PCI_CFG_R8_HDRTYPE 0x0E // Class code // Registers for device with type 0 header // There are may more registers, refer to PCI specification #define PCI_CFG_R32_BAR0 0x10 // BAR0 #define PCI_CFG_R32_BAR1 0x14 // BAR1 #define PCI_CFG_R32_BAR2 0x18 // BAR2 #define PCI_CFG_R32_BAR3 0x1C // BAR3 #define PCI_CFG_R32_BAR4 0x20 // BAR4 #define PCI_CFG_R32_BAR5 0x24 // BAR5 #define PCI_CFG_R32_CISPTR 0x28 // Cardbus CIS Pointer #define PCI_CFG_R16_SVID 0x2C // Subsystem vendor id #define PCI_CFG_R16_SDID 0x2E // Subsystem device id #define PCI_CFG_R32_EXROM 0x30 // Expansion ROM base address #define PCI_CFG_R8_CAPPTR 0x34 // Capabilities ptr #define PCI_CFG_R8_INTLINE 0x3C // Interrupt line #define PCI_CFG_R8_INTPIN 0x3D // Interrupt pin // // PCI BIOS generic interfaces // uint8_t PciGetLastError(); pcibool IsPciBiosPresent(); uint8_t GetPciBiosVerLo(); uint8_t GetPciBiosVerHi(); uint8_t GetPciBussesInSystem(); uint16_t GetPciDeviceCount(); pcibool PciSearchForDevice(uint16_t venid, uint16_t devid, uint8_t* bus, uint8_t* dev, uint8_t* func, uint16_t* marker); // // PCI configuration registers read access // uint8_t PciReadConfigByte(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg); uint16_t PciReadConfigWord(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg); uint32_t PciReadConfigDWord(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg); // // PCI configuration registers write access // uint8_t PciWriteConfigByte(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint8_t data); uint8_t PciWriteConfigWord(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint16_t data); uint8_t PciWriteConfigDWord(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint32_t data); #endif
pci_types.h
// // Copyright (c) 2004, 2006 Philipp Diethelm // // Permission is hereby granted, free of charge, to any person obtaining a copy of this software, to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to // do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE // OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // // // pci_types.h // Version: 1.1 // // Version history // 1.0 23.01.2006 Initial release // 1.1 30.01.2006 Added pcibool datatype (stdbool.h is not present in WC11.0c) // 1.2 31.01.2006 No 1.2 Release; Only to be in sync with other Version numbers in library // 1.3 31.01.2006 Updated code to uint??_t datatypes // #ifndef __PCI_TYPES_H__INCLUDED__ #define __PCI_TYPES_H__INCLUDED__ #if __WATCOMC__ > 1220 // For "newer" Watcom Compiler compatibility (OW 1.3 and up) #include <stdint.h> #else // For older Watcom Compiler compatibility typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned long uint32_t; #endif typedef int pcibool; #define pci_true 1 #define pci_false 0 #endif
pci.c
//
// Copyright (c) 2004, 2006 Philipp Diethelm
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software, to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to
// do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//
// pci_types.h
// Version: 1.1
//
// Version history
// 1.0 23.01.2006 Initial release
// 1.1 30.01.2006 Changed return type of IsPciBiosPresent() to pcibool
// 1.2 30.01.2006 Added PciSearchForDevice()
// 1.3 31.01.2006 Updated code to uint??_t datatypes
//
#include <i86.h>
#include "pci.h"
//
// Private variable - Read through PciGetLastError()
//
uint8_t pciLastError = 0;
//
// PciGetLastError()
//
// Input: Nothing
//
// Return: Last error (AH) from a BIOS call
//
uint8_t PciGetLastError()
{
return pciLastError;
}
//
// IsPciBiosPresent
//
// Input: Nothing
//
// Return: TRUE if PCI Bios is present
// FALSE if PCI Bios not present
//
pcibool IsPciBiosPresent()
{
union REGS regs;
regs.w.ax = PCI_BIOS_INSTALL;
regs.x.edi = 0;
int386(PCI_INT, ®s, ®s);
pciLastError = regs.h.ah;
if((regs.h.ah==PCI_ERR_SUCCESS) && (regs.x.edx==PCI_SIGNATURE))
return pci_true;
return pci_false;
}
//
// GetPciBiosVerLo()
//
// Input: Nothing
//
// Return: PCI Bios Minor Version
//
uint8_t GetPciBiosVerLo()
{
union REGS regs;
regs.w.ax = PCI_BIOS_INSTALL;
regs.x.edi = 0;
int386(PCI_INT, ®s, ®s);
pciLastError = regs.h.ah;
if((regs.h.ah==PCI_ERR_SUCCESS) && (regs.x.edx==PCI_SIGNATURE))
return regs.h.bl;
return 0;
}
//
// GetPciBiosVerHi()
//
// Input: Nothing
//
// Return: PCI Bios Major Version
//
uint8_t GetPciBiosVerHi()
{
union REGS regs;
regs.w.ax = PCI_BIOS_INSTALL;
regs.x.edi = 0;
int386(PCI_INT, ®s, ®s);
pciLastError = regs.h.ah;
if((regs.h.ah==PCI_ERR_SUCCESS) && (regs.x.edx==PCI_SIGNATURE))
return regs.h.bh;
return 0;
}
//
// GetPciBussesInSystem()
//
// Input: Nothing
//
// Return: PCI Bus count
//
uint8_t GetPciBussesInSystem()
{
union REGS regs;
regs.w.ax = PCI_BIOS_INSTALL;
regs.x.edi = 0;
int386(PCI_INT, ®s, ®s);
pciLastError = regs.h.ah;
if((regs.h.ah==PCI_ERR_SUCCESS) && (regs.x.edx==PCI_SIGNATURE))
return regs.h.cl;
return 0;
}
//
// GetPciDeviceCount()
//
// Input: Nothing
//
// Return: total PCI device count
//
uint16_t GetPciDeviceCount()
{
union REGS regs;
uint16_t numDev = 0;
uint8_t bus;
uint8_t dev;
uint8_t func;
for(bus=0; bus<=GetPciBussesInSystem(); bus++)
{
for(dev=0; dev<=PCI_DEV_MAX; dev++)
{
// Check if device present
if(0xFFFF!=PciReadConfigWord(bus, dev, 0, PCI_CFG_R16_VENID))
{
uint8_t ucHeaderType = PciReadConfigByte(bus, dev, 0, PCI_CFG_R8_HDRTYPE);
ucHeaderType &= 0x80;
for(func=0; func<=PCI_FUNC_MAX; func++)
{
if(0xFFFF != PciReadConfigWord(bus, dev, func, 0))
{
if(ucHeaderType==0 && func==0)
numDev++;
else if(ucHeaderType==0x80)
numDev++;
}
}
}
}
}
return numDev;
}
//
// PciReadConfigByte()
//
// Input: bus - PCI bus number
// dev - PCI device number
// func - PCI function number
// reg - PCI configuration register
//
// Return: configuration register data
//
uint8_t PciReadConfigByte(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg)
{
union REGS regs;
uint8_t devfunc = 0;
// Mask the input values
dev &= PCI_DEV_MAX;
func &= PCI_FUNC_MAX;
// Make the conbined dev/func parameter
devfunc = dev;
devfunc <<= 3;
devfunc |= func;
// Call the BIOS
regs.w.ax = PCI_BIOS_CFG_RD8;
regs.h.bh = bus;
regs.h.bl = devfunc;
regs.w.di = reg;
int386(PCI_INT, ®s, ®s);
pciLastError = regs.h.ah;
return regs.h.cl;
}
//
// PciReadConfigWord()
//
// Input: bus - PCI bus number
// dev - PCI device number
// func - PCI function number
// reg - PCI configuration register
//
// Return: configuration register data
//
uint16_t PciReadConfigWord(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg)
{
union REGS regs;
uint8_t devfunc = 0;
// Mask the input values
dev &= PCI_DEV_MAX;
func &= PCI_FUNC_MAX;
// Make the conbined dev/func parameter
devfunc = dev;
devfunc <<= 3;
devfunc |= func;
// Call the BIOS
regs.w.ax = PCI_BIOS_CFG_RD16;
regs.h.bh = bus;
regs.h.bl = devfunc;
regs.w.di = reg;
int386(PCI_INT, ®s, ®s);
pciLastError = regs.h.ah;
return regs.w.cx;
}
//
// PciReadConfigDWord()
//
// Input: bus - PCI bus number
// dev - PCI device number
// func - PCI function number
// reg - PCI configuration register
//
// Return: configuration register data
//
uint32_t PciReadConfigDWord(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg)
{
union REGS regs;
uint8_t devfunc = 0;
// Mask the input values
dev &= PCI_DEV_MAX;
func &= PCI_FUNC_MAX;
// Make the conbined dev/func parameter
devfunc = dev;
devfunc <<= 3;
devfunc |= func;
// Call the BIOS
regs.w.ax = PCI_BIOS_CFG_RD32;
regs.h.bh = bus;
regs.h.bl = devfunc;
regs.w.di = reg;
int386(PCI_INT, ®s, ®s);
pciLastError = regs.h.ah;
return regs.x.ecx;
}
//
// PciWriteConfigByte()
//
// Input: bus - PCI bus number
// dev - PCI device number
// func - PCI function number
// reg - PCI configuration register
// data - Data to write to register
//
// Return: pciLastError
//
uint8_t PciWriteConfigByte(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint8_t data)
{
union REGS regs;
uint8_t devfunc = 0;
// Mask the input values
dev &= PCI_DEV_MAX;
func &= PCI_FUNC_MAX;
// Make the conbined dev/func parameter
devfunc = dev;
devfunc <<= 3;
devfunc |= func;
// Call the BIOS
regs.w.ax = PCI_BIOS_CFG_WR8;
regs.h.bh = bus;
regs.h.bl = devfunc;
regs.h.cl = data;
regs.w.di = reg;
int386(PCI_INT, ®s, ®s);
pciLastError = regs.h.ah;
return pciLastError;
}
//
// PciWriteConfigWord()
//
// Input: bus - PCI bus number
// dev - PCI device number
// func - PCI function number
// reg - PCI configuration register
// data - Data to write to register
//
// Return: pciLastError
//
uint8_t PciWriteConfigWord(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint16_t data)
{
union REGS regs;
uint8_t devfunc = 0;
// Mask the input values
dev &= PCI_DEV_MAX;
func &= PCI_FUNC_MAX;
// Make the conbined dev/func parameter
devfunc = dev;
devfunc <<= 3;
devfunc |= func;
// Call the BIOS
regs.w.ax = PCI_BIOS_CFG_WR16;
regs.h.bh = bus;
regs.h.bl = devfunc;
regs.w.cx = data;
regs.w.di = reg;
int386(PCI_INT, ®s, ®s);
pciLastError = regs.h.ah;
return pciLastError;
}
//
// PciWriteConfigDWord()
//
// Input: bus - PCI bus number
// dev - PCI device number
// func - PCI function number
// reg - PCI configuration register
// data - Data to write to register
//
// Return: pciLastError
//
uint8_t PciWriteConfigDWord(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint32_t data)
{
union REGS regs;
uint8_t devfunc = 0;
// Mask the input values
dev &= PCI_DEV_MAX;
func &= PCI_FUNC_MAX;
// Make the conbined dev/func parameter
devfunc = dev;
devfunc <<= 3;
devfunc |= func;
// Call the BIOS
regs.w.ax = PCI_BIOS_CFG_WR32;
regs.h.bh = bus;
regs.h.bl = devfunc;
regs.x.ecx = data;
regs.w.di = reg;
int386(PCI_INT, ®s, ®s);
pciLastError = regs.h.ah;
return pciLastError;
}
//
// PciSearchForDevice()
//
// Input: venid - PCI vendor ID
// devid - PCI device ID
// marker - Set to 0 on first call. will be incremented for every device found!
//
// Return: pci_true if there are more devices to search for
// pci_false if no more devices are present
//
// bus - bus of device found
// dev - dev of device found
// func - function of device found
// marker - marker+1
//
pcibool PciSearchForDevice(uint16_t venid, uint16_t devid, uint8_t* bus, uint8_t* dev, uint8_t* func, uint16_t* marker)
{
union REGS regs;
// Check parameters
if(0==bus || 0==dev || 0==func || 0==marker)
{
return pci_false;
}
// Call the BIOS
regs.w.ax = PCI_BIOS_FINDDEV;
regs.w.dx = venid;
regs.w.cx = devid;
regs.w.si = *marker;
int386(PCI_INT, ®s, ®s);
// Device found?
if(regs.h.ah==PCI_ERR_SUCCESS)
{
// fill in the return values
*bus = regs.h.bh;
*dev = regs.h.bl>>3;
*func = regs.h.bl&0x7;
// search for next device
*marker += 1;
return pci_true;
}
return pci_false;
}
Note: typedefs such as ulong and ushort should not be used here as their size is not fixed and such code is nonportable. Programmers are strongly encouraged to use uint8_t, uint16_t, uint32_t, and other types provided by the standard C99 stdint.h header; the size of those types is guaranteed to be the same on any platform.

