/******************************************************************************
 * pci.c - Chapter 7 SBUFI sample code                                        *
 *                                                                            *
 * functions to handle Peripheral Component Interconnect (PCI) devices        *
 *                                                                            *
 * Copyright (c) 1994-1998 ATI Technologies Inc.  All rights reserved.        *
 ******************************************************************************/

#include <stdio.h>
#include <dos.h>
#include <i86.h>
#include "pci.h"

#define TRUE 1
#define FALSE 0


/******************************************************************************
 * pci_bios_present - determins if the PCI BIOS support is installed          *
 *  Function: This function permits the caller to determine if the PCI        *
 *            BIOS interface function is present.  It also allows the         *
 *            caller to determine the interface version.                      *
 *    Inputs: lppci - far pointer to the PCI_INFO structure which will be     *
 *                    filled with PCI system information.                     *
 *   Outputs: TRUE - if PCI BIOS is present                                   *
 *            FALSE - if PCI BIOS is not present                              *
 ******************************************************************************/

int pci_bios_present (PCI_INFO far *lppci)
{
    union REGS regs;

    regs.h.ah = PCI_FUNCTION_ID;
    regs.h.al = PCI_BIOS_PRESENT;
    int386 (0x1A, &regs, &regs);

    if (!(regs.h.dl == 'P' && regs.h.dh == 'C')) return (FALSE);
    lppci->present_status = regs.h.ah;
    lppci->hw_mechanism = regs.h.al;
    lppci->ver_maj = regs.h.bh;
    lppci->ver_min = regs.h.bl;
    lppci->pci_bus_num = regs.h.cl;

    return (TRUE);

} // pci_bios_present


/******************************************************************************
 * pci_find_device - determines the device number assigned to a device        *
 *  Function: This function will return the Device Number, Bus Number and     *
 *            Function Number of the Nthe Device/Function whose Vendor ID,    *
 *            Device Id, and Index Number (N) match the input parameters.     *
 *            The device number and function number may be used to access     *
 *            the device's configuration space, which contains device         *
 *            information such as the interrupt line number assigned to       *
 *            the device.                                                     *
 *    Inputs: vendor_id : Vender specific identification number.              *
 *            device_id : Device identification number.                       *
 *            index :     Device ndex number.                                 *
 *            lpdevice :  far pointer to a PCI_DEVICE_INFO structure.         *
 *   Outputs: SUCCESSFUL - if successful                                      *
 *            DEVICE_NOT_FOUND - if unsuccessful                              *
 ******************************************************************************/

int pci_find_device (unsigned int device_id, unsigned int vendor_id,
                     unsigned int index, PCI_DEVICE_INFO far *lpdevice)
{
    union REGS regs;

    regs.h.ah = PCI_FUNCTION_ID;
    regs.h.al = FIND_PCI_DEVICE;
    regs.x.ecx = device_id;
    regs.x.edx = vendor_id;
    regs.x.esi = index;
    int386 (0x1A, &regs, &regs);

    if (regs.h.ah == SUCCESSFUL)
    {
        lpdevice->bus_num = regs.h.bh;
        lpdevice->device_num = regs.h.bl;
    } // if

    return ((int) regs.h.ah);

} // pci_find_device


/******************************************************************************
 * pci_read_config_byte - read byte from configuration space.                 *
 *  Function: This function allows the caller to read a specific byte         *
 *            from the configuration space identified by the device and       *
 *            bus number.                                                     *
 *    Inputs: reg_num - offset into confign space for byte to be read.        *
 *            lpdevice - far pointer to a PCI_DEVICE_INFO structure. This     *
 *                  structure must first be filled by the pci_find_device     *
 *                  function in order to access the correct configuration     *
 *                  space.                                                    *
 *   Outputs: result - register value                                         *
 *            BAD-REGISTER_NUMBER - if unsuccessful                           *
 ******************************************************************************/

unsigned char pci_read_config_byte (unsigned int reg_num,
                                    PCI_DEVICE_INFO far *lpdevice)
{
    union REGS regs;
    unsigned char result;

    regs.h.ah = PCI_FUNCTION_ID;
    regs.h.al = READ_CONFIG_BYTE;
    regs.h.bh = lpdevice->bus_num;
    regs.h.bl = lpdevice->device_num;
    regs.x.edi = reg_num;
    int386 (0x1A, &regs, &regs);

    if (regs.h.ah == SUCCESSFUL)
    {
        result = regs.h.cl;
    }
    else
    {
        result = regs.h.ah;
    } // if

    return (result);

} // pci_read_config_byte
