/****************************************************************************
*
*                   SciTech OS Portability Manager Library
*
*  ========================================================================
*
*    The contents of this file are subject to the SciTech MGL Public
*    License Version 1.0 (the "License"); you may not use this file
*    except in compliance with the License. You may obtain a copy of
*    the License at http://www.scitechsoft.com/mgl-license.txt
*
*    Software distributed under the License is distributed on an
*    "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
*    implied. See the License for the specific language governing
*    rights and limitations under the License.
*
*    The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
*
*    The Initial Developer of the Original Code is SciTech Software, Inc.
*    All Rights Reserved.
*
*  ========================================================================
*
* Language:     ANSI C
* Environment:  Any
*
* Description:  Header file for interface routines to the PCI bus.
*
****************************************************************************/

#ifndef __PCILIB_H
#define __PCILIB_H

#include "scitech.h"

/*---------------------- Macros and type definitions ----------------------*/

#pragma pack(1)

/* Defines for PCIDeviceInfo.HeaderType */

typedef enum {
    PCI_deviceType                  = 0x00,
    PCI_bridgeType                  = 0x01,
    PCI_cardBusBridgeType           = 0x02,
    PCI_multiFunctionType           = 0x80
    } PCIHeaderTypeFlags;

/* Defines for PCIDeviceInfo.Command */

typedef enum {
    PCI_enableIOSpace               = 0x0001,
    PCI_enableMemorySpace           = 0x0002,
    PCI_enableBusMaster             = 0x0004,
    PCI_enableSpecialCylces         = 0x0008,
    PCI_enableWriteAndInvalidate    = 0x0010,
    PCI_enableVGACompatiblePalette  = 0x0020,
    PCI_enableParity                = 0x0040,
    PCI_enableWaitCycle             = 0x0080,
    PCI_enableSerr                  = 0x0100,
    PCI_enableFastBackToBack        = 0x0200
    } PCICommandFlags;

/* Defines for PCIDeviceInfo.Status */

typedef enum {
    PCI_statusCapabilitiesList      = 0x0010,
    PCI_status66MhzCapable          = 0x0020,
    PCI_statusUDFSupported          = 0x0040,
    PCI_statusFastBackToBack        = 0x0080,
    PCI_statusDataParityDetected    = 0x0100,
    PCI_statusDevSel                = 0x0600,
    PCI_statusSignaledTargetAbort   = 0x0800,
    PCI_statusRecievedTargetAbort   = 0x1000,
    PCI_statusRecievedMasterAbort   = 0x2000,
    PCI_statusSignaledSystemError   = 0x4000,
    PCI_statusDetectedParityError   = 0x8000
    } PCIStatusFlags;

/* PCI capability IDs */

typedef enum {
    PCI_capsPowerManagement         = 0x01,
    PCI_capsAGP                     = 0x02,
    PCI_capsMSI                     = 0x05
    } PCICapsType;

/* PCI AGP rate definitions */

typedef enum {
    PCI_AGPRate1X                   = 0x1,
    PCI_AGPRate2X                   = 0x2,
    PCI_AGPRate4X                   = 0x4
    } PCIAGPRateType;

/* NOTE: We define all bitfield's as uint's, specifically so that the IBM
 *       Visual Age C++ compiler does not complain. We need them to be
 *       32-bits wide, and this is the width of an unsigned integer, but
 *       we can't use a ulong to make this explicit or we get errors.
 */

/* Structure defining a PCI slot identifier */

typedef union {
    struct {
        uint    Zero:2;
        uint    Register:6;
        uint    Function:3;
        uint    Device:5;
        uint    Bus:8;
        uint    Reserved:7;
        uint    Enable:1;
        } p;
    ulong   i;
    } PCIslot;

#define PCI_MAX_BUS         16
#define PCI_MAX_DEVICE      32
#define PCI_MAX_FUNCTION    8

/* Structure defining the regular (type 0) PCI configuration register
 * layout. We use this in a union below so we can describe all types of
 * PCI configuration spaces with a single structure.
 */

typedef struct {
    ulong   BaseAddress10;
    ulong   BaseAddress14;
    ulong   BaseAddress18;
    ulong   BaseAddress1C;
    ulong   BaseAddress20;
    ulong   BaseAddress24;
    ulong   CardbusCISPointer;
    ushort  SubSystemVendorID;
    ushort  SubSystemID;
    ulong   ROMBaseAddress;
    uchar   CapabilitiesPointer;
    uchar   reserved1;
    uchar   reserved2;
    uchar   reserved3;
    ulong   reserved4;
    uchar   InterruptLine;
    uchar   InterruptPin;
    uchar   MinimumGrant;
    uchar   MaximumLatency;

    /* These are not in the actual config space, but we enumerate them */
    ulong   BaseAddress10Len;
    ulong   BaseAddress14Len;
    ulong   BaseAddress18Len;
    ulong   BaseAddress1CLen;
    ulong   BaseAddress20Len;
    ulong   BaseAddress24Len;
    ulong   ROMBaseAddressLen;
    } PCIType0Info;

/* Structure defining PCI to PCI bridge (type 1) PCI configuration register
 * layout. We use this in a union below so we can describe all types of
 * PCI configuration spaces with a single structure.
 */

typedef struct {
    ulong   BaseAddress10;
    ulong   BaseAddress14;
    uchar   PrimaryBusNumber;
    uchar   SecondayBusNumber;
    uchar   SubordinateBusNumber;
    uchar   SecondaryLatencyTimer;
    uchar   IOBase;
    uchar   IOLimit;
    ushort  SecondaryStatus;
    ushort  MemoryBase;
    ushort  MemoryLimit;
    ushort  PrefetchableMemoryBase;
    ushort  PrefetchableMemoryLimit;
    ulong   PrefetchableBaseHi;
    ulong   PrefetchableLimitHi;
    ushort  IOBaseHi;
    ushort  IOLimitHi;
    uchar   CapabilitiesPointer;
    uchar   reserved1;
    uchar   reserved2;
    uchar   reserved3;
    ulong   ROMBaseAddress;
    uchar   InterruptLine;
    uchar   InterruptPin;
    ushort  BridgeControl;
    } PCIType1Info;

/* PCI to CardBus bridge (type 2) configuration information */
typedef struct {
    ulong   SocketRegistersBaseAddress;
    uchar   CapabilitiesPointer;
    uchar   reserved1;
    ushort  SecondaryStatus;
    uchar   PrimaryBus;
    uchar   SecondaryBus;
    uchar   SubordinateBus;
    uchar   SecondaryLatency;
    struct  {
        ulong   Base;
        ulong   Limit;
        } Range[4];
    uchar   InterruptLine;
    uchar   InterruptPin;
    ushort  BridgeControl;
    } PCIType2Info;

/* Structure defining the PCI configuration space information for a
 * single PCI device on the PCI bus. We enumerate all this information
 * for all PCI devices on the bus.
 */

typedef struct {
    ulong               dwSize;
    PCIslot             slot;
    ulong               mech1;
    ushort              VendorID;
    ushort              DeviceID;
    ushort              Command;
    ushort              Status;
    uchar               RevID;
    uchar               Interface;
    uchar               SubClass;
    uchar               BaseClass;
    uchar               CacheLineSize;
    uchar               LatencyTimer;
    uchar               HeaderType;
    uchar               BIST;
    union {
        PCIType0Info    type0;
        PCIType1Info    type1;
        PCIType2Info    type2;
        } u;
    } PCIDeviceInfo;

/* PCI Capability header structure. All PCI capabilities have the
 * following header.
 *
 * capsID is used to identify the type of the structure as define above.
 *
 * next is the offset in PCI configuration space (0x40-0xFC) of the
 * next capability structure in the list, or 0x00 if there are no more
 * entries.
 */

typedef struct {
    uchar   capsID;
    uchar   next;
    } PCICapsHeader;

/* Structure defining the PCI AGP status register contents */

typedef struct {
    uint    rate:3;
    uint    rsvd1:1;
    uint    fastWrite:1;
    uint    fourGB:1;
    uint    rsvd2:3;
    uint    sideBandAddressing:1;
    uint    rsvd3:14;
    uint    requestQueueDepthMaximum:8;
    } PCIAGPStatus;

/* Structure defining the PCI AGP command register contents */

typedef struct {
    uint    rate:3;
    uint    rsvd1:1;
    uint    fastWriteEnable:1;
    uint    fourGBEnable:1;
    uint    rsvd2:2;
    uint    AGPEnable:1;
    uint    SBAEnable:1;
    uint    rsvd3:14;
    uint    requestQueueDepth:8;
    } PCIAGPCommand;

/* AGP Capability structure */

typedef struct {
    PCICapsHeader   h;
    ushort          majMin;
    PCIAGPStatus    AGPStatus;
    PCIAGPCommand   AGPCommand;
    } PCIAGPCapability;

/* Structure for obtaining the PCI IRQ routing information */

typedef struct {
    uchar   bus;
    uchar   device;
    uchar   linkA;
    ushort  mapA;
    uchar   linkB;
    ushort  mapB;
    uchar   linkC;
    ushort  mapC;
    uchar   linkD;
    ushort  mapD;
    uchar   slot;
    uchar   reserved;
    } PCIRouteInfo;

typedef struct {
    ushort          BufferSize;
    PCIRouteInfo    *DataBuffer;
    } PCIRoutingOptionsBuffer;

#define NUM_PCI_REG                 (sizeof(PCIDeviceInfo) / 4) - 10
#define PCI_BRIDGE_CLASS            0x06
#define PCI_HOST_BRIDGE_SUBCLASS    0x00
#define PCI_EARLY_VGA_CLASS         0x00
#define PCI_EARLY_VGA_SUBCLASS      0x01
#define PCI_DISPLAY_CLASS           0x03
#define PCI_DISPLAY_VGA_SUBCLASS    0x00
#define PCI_DISPLAY_XGA_SUBCLASS    0x01
#define PCI_DISPLAY_OTHER_SUBCLASS  0x80
#define PCI_MM_CLASS                0x04
#define PCI_AUDIO_SUBCLASS          0x01

/* Macros to detect specific classes of devices */

#define PCI_IS_3DLABS_NONVGA_CLASS(pci) \
   (((pci)->BaseClass == PCI_DISPLAY_CLASS && (pci)->SubClass == PCI_DISPLAY_OTHER_SUBCLASS) \
 && ((pci)->VendorID == 0x3D3D || (pci)->VendorID == 0x104C))

#define PCI_IS_DISPLAY_CLASS(pci) \
   (((pci)->BaseClass == PCI_DISPLAY_CLASS && (pci)->SubClass == PCI_DISPLAY_VGA_SUBCLASS) \
 || ((pci)->BaseClass == PCI_DISPLAY_CLASS && (pci)->SubClass == PCI_DISPLAY_XGA_SUBCLASS) \
 || ((pci)->BaseClass == PCI_EARLY_VGA_CLASS && (pci)->SubClass == PCI_EARLY_VGA_SUBCLASS) \
 || PCI_IS_3DLABS_NONVGA_CLASS(pci))

/* Function codes to pass to PCI_accessReg */

#define PCI_READ_BYTE               0
#define PCI_READ_WORD               1
#define PCI_READ_DWORD              2
#define PCI_WRITE_BYTE              3
#define PCI_WRITE_WORD              4
#define PCI_WRITE_DWORD             5

/* Macros to read/write PCI registers. These assume a global PCI array
 * of device information.
 */

#define PCI_readPCIRegB(index,device)   \
    PCI_accessReg(index,0,0,&PCI[DeviceIndex[device]])

#define PCI_readPCIRegW(index,device)   \
    PCI_accessReg(index,0,1,&PCI[DeviceIndex[device]])

#define PCI_readPCIRegL(index,device)   \
    PCI_accessReg(index,0,2,&PCI[DeviceIndex[device]])

#define PCI_writePCIRegB(index,value,device)    \
    PCI_accessReg(index,value,3,&PCI[DeviceIndex[device]])

#define PCI_writePCIRegW(index,value,device)    \
    PCI_accessReg(index,value,4,&PCI[DeviceIndex[device]])

#define PCI_writePCIRegL(index,value,device)    \
    PCI_accessReg(index,value,5,&PCI[DeviceIndex[device]])

#pragma pack()

/*-------------------------- Function Prototypes --------------------------*/

#ifdef  __cplusplus
extern "C" {                        /* Use "C" linkage when in C++ mode */
#endif

/* Function to determine the number of PCI devices in the system */

int     _ASMAPI PCI_getNumDevices(void);

/* Function to enumerate all device on the PCI bus */

int     _ASMAPI PCI_enumerate(PCIDeviceInfo info[]);

/* Function to access PCI configuration registers */

ulong   _ASMAPI PCI_accessReg(int index,ulong value,int func,PCIDeviceInfo *info);

/* Function to get PCI IRQ routing options for a card */

int     _ASMAPI PCI_getIRQRoutingOptions(int numDevices,PCIRouteInfo *buffer);

/* Function to re-route the PCI IRQ setting for a device */

ibool   _ASMAPI PCI_setHardwareIRQ(PCIDeviceInfo *info,uint intPin,uint IRQ);

/* Function to generate a special cyle on the specified PCI bus */

void    _ASMAPI PCI_generateSpecialCyle(uint bus,ulong specialCycleData);

/* Function to determine the size of a PCI base address register */

ulong   _ASMAPI PCI_findBARSize(int bar,PCIDeviceInfo *pci);

/* Function to read a block of PCI configuration space registers */

void    _ASMAPI PCI_readRegBlock(PCIDeviceInfo *info,int index,void *dst,int count);

/* Function to write a block of PCI configuration space registers */

void    _ASMAPI PCI_writeRegBlock(PCIDeviceInfo *info,int index,void *src,int count);

/* Function to return the 32-bit PCI BIOS entry point */

ulong   _ASMAPI PCIBIOS_getEntry(void);

#ifdef  __cplusplus
}                                   /* End of "C" linkage for C++       */
#endif

#endif  /* __PCILIB_H */

