www.pudn.com > ScriptsSample.zip > SPCI.C


/*--------------------------------------------------*/ 
/*                                                  */ 
/* Module SPCI.C                                    */ 
/*                                                  */ 
/* PCI access functions for sample code.            */ 
/*                                                  */ 
/* Adapted from Symbios Logic                       */ 
/*    Software Development Kit                      */ 
/*                                                  */ 
/* Project: A Programmer's Guide to SCSI            */ 
/* Copyright (C) 1997, Brian Sawert.                */ 
/* All rights reserved.                             */ 
/*                                                  */ 
/*--------------------------------------------------*/ 
 
 
#include  
#include  
#include  
 
#include "gen_tool.h"         // generic tools 
#include "spci.h"             // PCI definitions 
#include "s8xx.h"             // Symbios 8XX definitions 
 
#pragma inline                // enable inline assembly 
 
 
/*---------- defines and macros ----------*/ 
 
/*---------- global variables ----------*/ 
 
/*---------- external variables ----------*/ 
 
/*---------- local functions ----------*/ 
 
/*---------- external functions ----------*/ 
 
/*---------- function definitions ----------*/ 
 
 
/*--------------------------------------------------*/ 
/*                                                  */ 
/* Routine to get PCI BIOS information.             */ 
/*                                                  */ 
/* Usage:   WORD PCI_GetPCIBIOSVersion(             */ 
/*    pci_bios *ppcibios);                          */ 
/*                                                  */ 
/* Parameters:                                      */ 
/*    ppcibios:      pointer to pci_bios struct     */ 
/*                                                  */ 
/* Return value:                                    */ 
/*    Returns PCI BIOS version number on success,   */ 
/*    0 if PCI BIOS not found. Fills pci_bios       */ 
/*    struct on success.                            */ 
/*                                                  */ 
/*--------------------------------------------------*/ 
 
WORD PCI_GetPCIBIOSVersion(pci_bios *ppcibios) 
{ 
   WORD r_ax, r_bx, r_cx, r_dx;  // register variables 
   DWORD r_edx; 
   DWORD pci_sig;                // PCI signature 
   WORD retval = PCI_NO_BIOS; 
 
 
   pci_sig = 0x20494350L;        // " ICP" signature 
 
   // call PCI function to check for BIOS 
   r_ax = ((PCI_FUNCTION_ID << 8) | PCI_BIOS_PRESENT); 
 
   asm { 
      .386 
      mov ax, [r_ax] 
      int PCI_BIOS_INT 
      mov DWORD PTR [r_edx], edx 
      mov [r_dx], dx 
      mov [r_cx], cx 
      mov [r_bx], bx 
      mov [r_ax], ax 
   } 
 
   if (r_dx == LOWORD(pci_sig)) { 
   // PCI BIOS is present 
 
      if (r_cx == HIWORD(pci_sig) && 
         (r_bx & 0xff00) == 0x0100) { 
      // PCI BIOS version 1.x 
         retval = PCI_BIOS_REV_1X; 
      } 
      else if (r_edx == pci_sig) { 
      // PCI BIOS version 2.x 
         retval = PCI_BIOS_REV_2X; 
      } 
      else { 
      // unknown version 
         retval = PCI_UNKNOWN_BIOS; 
      } 
 
      if (ppcibios != NULL) { 
      // fill BIOS info struct 
         ppcibios->access = (r_ax & 0xff); 
         ppcibios->version = r_bx; 
         ppcibios->lastbus = (r_cx & 0xff); 
      } 
   } 
 
   return retval; 
} 
 
 
 
/*--------------------------------------------------*/ 
/*                                                  */ 
/* Routine to locate PCI device.                    */ 
/*                                                  */ 
/* Usage:   int PCI_FindDevice(                     */ 
/*    pci_device *ppcidevice);                      */ 
/*                                                  */ 
/* Parameters:                                      */ 
/*    ppcidevice:    pointer to pci_device struct   */ 
/*                                                  */ 
/* Return value:                                    */ 
/*    Returns 1 if device found, 0 otherwise.       */ 
/*    Fills pci_device struct on success.           */ 
/*                                                  */ 
/*--------------------------------------------------*/ 
 
int PCI_FindDevice(pci_device *ppcidevice) 
{ 
// struct REGPACK regs; 
   WORD r_ax, r_bx, r_cx, r_dx, r_si; 
   DWORD config; 
   int retval = 0; 
 
 
   // make sure we have a PCI BIOS 
      if (PCI_GetPCIBIOSVersion(NULL) != PCI_NO_BIOS) { 
   // PCI BIOS is present 
 
      // call PCI function to find device 
      r_ax = ((PCI_FUNCTION_ID << 8) | 
         (PCI_FIND_DEVICE)); 
 
      r_cx = ppcidevice->dev_id; 
      r_dx = ppcidevice->vend_id; 
      r_si = ppcidevice->dev_index; 
 
      asm { 
         .386 
         mov ax, [r_ax] 
         mov cx, [r_cx] 
         mov dx, [r_dx] 
         mov si, [r_si] 
         int PCI_BIOS_INT 
         mov ax, 0 
         adc ax, 0 
         mov [r_bx], bx 
         mov [r_ax], ax 
 
      } 
 
      if (r_ax == 0) { 
      // carry bit is clear - call succeeded 
 
         // save device bus number 
         ppcidevice->bus_num = ((r_bx & 0xFF00) >> 8); 
 
         // save device number 
         ppcidevice->dev_num = (r_bx & 0x00FF); 
 
         // save device function 
         ppcidevice->function = (r_bx & 0x0007); 
 
         // get command register 
         ppcidevice->command = 
            (WORD) PCI_GetConfigRegister( 
            ppcidevice, PCI_CONFIG_REG_CMD); 
 
         // get revision ID 
         ppcidevice->rev_id = 
            (BYTE) PCI_GetConfigRegister( 
            ppcidevice, PCI_CONFIG_REG_REVID); 
 
         // get subsystem and vendor ID 
         config = PCI_GetConfigRegister( 
            ppcidevice, PCI_CONFIG_REG_SUBV); 
         ppcidevice->sub_vend_id = (WORD) config; 
         ppcidevice->sub_id = (WORD) (config >> 16); 
 
         // get I/O base address 
         config = PCI_GetConfigRegister( 
            ppcidevice, C8XX_CONFIG_REG_IOB); 
         ppcidevice->io_base = (config & 0xFFFFFFFEL); 
 
         // get SCRIPTS RAM base address 
         ppcidevice->ram_base = PCI_GetConfigRegister( 
            ppcidevice, C8XX_CONFIG_REG_RAMB); 
 
         // get ROM base address 
         ppcidevice->rom_base = PCI_GetConfigRegister( 
            ppcidevice, PCI_CONFIG_REG_ROM); 
 
         // get interrupt number 
         config = PCI_GetConfigRegister( 
            ppcidevice, PCI_CONFIG_REG_INTL); 
         ppcidevice->intl = (BYTE) config; 
 
         retval = 1; 
      } 
   } 
 
   return retval; 
} 
 
 
 
/*--------------------------------------------------*/ 
/*                                                  */ 
/* Routine to read PCI configuration register.      */ 
/*                                                  */ 
/* Usage:   DWORD PCI_GetConfigRegister(            */ 
/*    pci_device *ppcidevice, WORD offset)          */ 
/*                                                  */ 
/* Parameters:                                      */ 
/*    ppcidevice:    pointer to pci_device struct   */ 
/*    offset:        config register offset         */ 
/*                                                  */ 
/* Return value:                                    */ 
/*    Returns register value on success,            */ 
/*    0 otherwise.                                  */ 
/*                                                  */ 
/*--------------------------------------------------*/ 
 
DWORD PCI_GetConfigRegister(pci_device *ppcidevice, 
   WORD offset) 
{ 
   WORD r_ax, r_bx, r_di, r_dx, r_cx; 
   DWORD r_ecx; 
   WORD pci_version; 
   DWORD retval = 0L; 
 
 
   // get PCI version 
   pci_version = PCI_GetPCIBIOSVersion(NULL); 
 
   if (!(pci_version == PCI_NO_BIOS || 
      pci_version == PCI_UNKNOWN_BIOS)) { 
   // PCI BIOS present 
 
      // call PCI function to read register 
      r_ax = ((PCI_FUNCTION_ID << 8) | 
         (PCI_READ_CONFIG_DWORD)); 
 
      // set bus number and device number 
      r_bx = ((ppcidevice->bus_num & 0xff) << 8) | 
         (ppcidevice->dev_num & 0xff); 
 
      // set configuration register offset 
      r_di = offset; 
 
      asm { 
         .386 
         mov ax, [r_ax] 
         mov bx, [r_bx] 
         mov di, [r_di] 
         int PCI_BIOS_INT 
         mov DWORD PTR [r_ecx], ecx 
         mov [r_dx], dx 
         mov [r_cx], cx 
      } 
 
      if (pci_version == PCI_BIOS_REV_1X) { 
      // PCI version 1.x 
         retval = r_dx; 
         retval = (retval << 16) | r_cx; 
      } 
      else if (pci_version == PCI_BIOS_REV_2X) { 
      // PCI version 2.x 
         retval = r_ecx; 
      } 
   } 
 
   return retval; 
} 
 
 
 
/*--------------------------------------------------*/ 
/*                                                  */ 
/* Routine to write to PCI configuration register.  */ 
/*                                                  */ 
/* Usage:   void PCI_SetConfigRegister(             */ 
/*    pci_device *ppcidevice, WORD offset,          */ 
/*    DWORD value)                                  */ 
/*                                                  */ 
/* Parameters:                                      */ 
/*    ppcidevice:    pointer to pci_device struct   */ 
/*    offset:        config register offset         */ 
/*    value:         value to write to register     */ 
/*                                                  */ 
/* Return value:                                    */ 
/*    Returns 0 if no PCI BIOS, 1 otherwise.        */ 
/*                                                  */ 
/*--------------------------------------------------*/ 
 
WORD PCI_SetConfigRegister(pci_device *ppcidevice, 
   WORD offset, DWORD value) 
{ 
   WORD r_ax, r_bx, r_di, r_dx, r_cx; 
   DWORD r_ecx; 
   WORD pci_version; 
   WORD retval = 0; 
 
 
   // get PCI version 
   pci_version = PCI_GetPCIBIOSVersion(NULL); 
 
   if (!(pci_version == PCI_NO_BIOS || 
      pci_version == PCI_UNKNOWN_BIOS)) { 
   // PCI BIOS present 
 
      retval = 1; 
 
      // call PCI function to write to register 
      r_ax = ((PCI_FUNCTION_ID << 8) | 
         (PCI_WRITE_CONFIG_DWORD)); 
 
      // set bus number and device number 
      r_bx = ((ppcidevice->bus_num & 0xff) << 8) | 
         (ppcidevice->dev_num & 0xff); 
 
      // set configuration register offset 
      r_di = offset; 
 
      if (pci_version == PCI_BIOS_REV_1X) { 
      // PCI version 1.x 
         r_cx = (WORD) value; 
         r_dx = (WORD) (value >> 16); 
      } 
      else if (pci_version == PCI_BIOS_REV_2X) { 
      // PCI version 2.x 
         r_ecx = value; 
      } 
 
      asm { 
         .386 
         mov ax, [r_ax] 
         mov bx, [r_bx] 
         mov cx, [r_cx] 
         mov dx, [r_dx] 
         mov di, [r_di] 
         mov ecx, DWORD PTR [r_ecx] 
         int PCI_BIOS_INT 
      } 
   } 
 
   return retval; 
}