/******************************************************************************
 * PCICFG.C - Chapter 3 sample code                                           *
 *                                                                            *
 * This program has various PCI CONFIGURATION SPACE functions that will       *
 * detect the presence of a R128 via the PCI CONFIG space.  The global        *
 * structure R128_AdapterInfo is also filled in with various values           *
 *                                                                            *
 * Copyright (c) 1999 ATI Technologies Inc.  All rights reserved.             *
 ******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <i86.h>
#include <dos.h>
#include "main.h"
#include "regdef.h"
#include "defines.h"


/******************************************************************************
 * PCIInstallCheck                                                            *
 *  Function: calls a BIOS function to determine if a PCI bus is installed,   *
 *            and determine the number of buses available.                    *
 *    Inputs: NONE                                                            *
 *   Outputs: the number of PCI buses installed, or                           *
 *            0xFFFF if no PCI buses are found.                               *
 ******************************************************************************/
WORD PCIInstallCheck (void)
{
    BYTE pci_installed, last_bus;
    union REGS r;

    memset (&r, 0, sizeof (r));

    r.w.ax = 0xB101; // function number to check for PCI BIOS
    int386 (0x1A, &r, &r);

    pci_installed = r.h.ah;
    last_bus = r.h.cl;

    if (pci_installed != 0)
    {
        return (0xFFFF);
    } // if
    return ((WORD) last_bus);
} // PCIInstallCheck


/******************************************************************************
 * GetPCIByte                                                                 *
 *  Function: retrieves a byte from the requested PCI configuration space     *
 *            address.                                                        *
 *    Inputs: WORD bus - the PCI bus number of the target device              *
 *            WORD dev - the PCI device number of the target device           *
 *            WORD reg - the PCI configuration space register to read         *
 *   Outputs: the byte read from the register                                 *
 ******************************************************************************/
BYTE GetPCIByte (WORD bus, WORD dev, WORD reg)
{
    WORD bus_dev;
    BYTE result;
    union REGS r;

    memset (&r, 0, sizeof (r));

    bus_dev = (bus << 8) + (dev << 3);

    r.w.ax = 0xB108; // function number to get a PCI byte
    r.w.bx = bus_dev;
    r.w.di = reg;

    int386 (0x1A, &r, &r);
    result = r.h.cl;

    return (result);
} // GetPCIByte


/******************************************************************************
 * GetPCIWord                                                                 *
 *  Function: retrieves a WORD from the requested PCI configuration space     *
 *            address.                                                        *
 *    Inputs: WORD bus - the PCI bus number of the target device              *
 *            WORD dev - the PCI device number of the target device           *
 *            WORD reg - the PCI configuration space register to read         *
 *   Outputs: the WORD read from the register                                 *
 ******************************************************************************/
WORD GetPCIWord (WORD bus, WORD dev, WORD reg)
{
    WORD bus_dev, result;
    union REGS r;

    memset (&r, 0, sizeof (r));
    bus_dev = (bus << 8) + (dev << 3);

    r.w.ax = 0xB109; // function number to get PCI word
    r.w.bx = bus_dev;
    r.w.di = reg;
    int386 (0x1A, &r, &r);
    result = r.w.cx;

    return (result);
} // GetPCIWord

/******************************************************************************
 * GetPCIDword                                                                *
 *  Function: retrieves a DWORD from the requested PCI configuration space    *
 *            address.                                                        *
 *    Inputs: WORD bus - the PCI bus number of the target device              *
 *            WORD dev - the PCI device number of the target device           *
 *            WORD reg - the PCI configuration space register to read         *
 *   Outputs: the DWORD read from the register                                *
 ******************************************************************************/
DWORD GetPCIDword (WORD bus, WORD dev, WORD reg)
{
    union REGS r;
    DWORD result;

    memset (&r, 0, sizeof (r));

    r.w.ax = 0xB10A;
    r.h.bh = bus;
    r.h.bl = dev << 3;
    r.w.di = (WORD)(reg & 0xFC);
    int386 (0x1A, &r, &r);
    result = r.x.ecx;

    return (result);
} // GetPCIDword


/******************************************************************************
 * SetPCIDword                                                                *
 *  Function: sets a DWORD in the requested PCI configuration space register  *
 *    Inputs: WORD bus - the PCI bus number of the target device              *
 *            WORD dev - the PCI device number of the target device           *
 *            WORD reg - the PCI configuration space register to read         *
 *            DWORD data - the data to be written                             *
 *   Outputs: NONE                                                            *
 ******************************************************************************/
void SetPCIDword (WORD bus, WORD dev, WORD reg, DWORD data)
{
    union REGS r;

    memset (&r, 0, sizeof (r));

    r.w.ax = 0xB10D; // write PCI Config DWORD
    r.h.bh = bus;
    r.h.bl = dev << 3;
    r.w.di = (WORD)(reg & 0xFC);  // mask to make sure it's a DWORD
    r.x.ecx = data;
    int386 (0x1A, &r, &r);

    return;
} // SetPCIDword ()

/******************************************************************************
 * SetPCIWord                                                                 *
 *  Function: sets a WORD in the requested PCI configuration space register   *
 *    Inputs: WORD bus - the PCI bus number of the target device              *
 *            WORD dev - the PCI device number of the target device           *
 *            WORD reg - the PCI configuration space register to read         *
 *            WORD data - the data to be written                              *
 *   Outputs: NONE                                                            *
 ******************************************************************************/
void SetPCIWord (WORD bus, WORD dev, WORD reg, WORD data)
{
    union REGS r;

    memset (&r, 0, sizeof (r));

    r.w.ax = 0xB10C; // write PCI Config WORD
    r.h.bh = bus;
    r.h.bl = dev << 3;
    r.w.di = (WORD)(reg & 0xFE);  // mask to make sure it's a WORD
    r.w.cx = data;
    int386 (0x1A, &r, &r);

    return;
} // SetPCIWord ()

/******************************************************************************
 * SetPCIByte                                                                 *
 *  Function: sets a BYTE in the requested PCI configuration space register   *
 *    Inputs: WORD bus - the PCI bus number of the target device              *
 *            WORD dev - the PCI device number of the target device           *
 *            WORD reg - the PCI configuration space register to read         *
 *            BYTE data - the data to be written                              *
 *   Outputs: NONE                                                            *
 ******************************************************************************/
void SetPCIByte (WORD bus, WORD dev, WORD reg, BYTE data)
{
    union REGS r;

    memset (&r, 0, sizeof (r));

    r.w.ax = 0xB10B; // write PCI Config WORD
    r.h.bh = bus;
    r.h.bl = dev << 3;
    r.w.di = (WORD)(reg & 0xFF);
    r.h.cl = data;
    int386 (0x1A, &r, &r);

    return;
} // SetPCIByte ()

