PCI Device access under 32-Bit PM DOS

From Open Watcom

Revision as of 11:23, 23 September 2006; view current revision
←Older revision | Newer revision→
Jump to: navigation, search

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, &regs, &regs);
  
  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, &regs, &regs);
}

#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, &regs, &regs);

  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, &regs, &regs);

  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, &regs, &regs);

  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, &regs, &regs);

  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, &regs, &regs);

  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, &regs, &regs);

  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, &regs, &regs);

  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, &regs, &regs);

  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, &regs, &regs);

  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, &regs, &regs);

  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, &regs, &regs);
	
  // 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.

Personal tools