📄 pcilib.c
字号:
/****************************************************************************** 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: Module for interfacing to the PCI bus and configuration* space registers.*****************************************************************************/#include "pmapi.h"#include "pcilib.h"#if !defined(__WIN32_VXD__) && !defined(__NT_DRIVER__)#include <string.h>#endif/*---------------------- Macros and type definitions ----------------------*/#pragma pack(1)/* Length of the memory mapping for the PCI BIOS */#define BIOS_LIMIT (128 * 1024L - 1)/* Macros for accessing the PCI BIOS functions from 32-bit protected mode */#define BIOS32_SIGNATURE (((ulong)'_' << 0) + ((ulong)'3' << 8) + ((ulong)'2' << 16) + ((ulong)'_' << 24))#define PCI_SIGNATURE (((ulong)'P' << 0) + ((ulong)'C' << 8) + ((ulong)'I' << 16) + ((ulong)' ' << 24))#define PCI_SERVICE (((ulong)'$' << 0) + ((ulong)'P' << 8) + ((ulong)'C' << 16) + ((ulong)'I' << 24))#define PCI_BIOS_PRESENT 0xB101#define FIND_PCI_DEVICE 0xB102#define FIND_PCI_CLASS 0xB103#define GENERATE_SPECIAL 0xB106#define READ_CONFIG_BYTE 0xB108#define READ_CONFIG_WORD 0xB109#define READ_CONFIG_DWORD 0xB10A#define WRITE_CONFIG_BYTE 0xB10B#define WRITE_CONFIG_WORD 0xB10C#define WRITE_CONFIG_DWORD 0xB10D#define GET_IRQ_ROUTING_OPT 0xB10E#define SET_PCI_IRQ 0xB10F/* This is the standard structure used to identify the entry point to the * BIOS32 Service Directory, as documented in PCI 2.1 BIOS Specicition. */typedef union { struct { ulong signature; /* _32_ */ ulong entry; /* 32 bit physical address */ uchar revision; /* Revision level, 0 */ uchar length; /* Length in paragraphs should be 01 */ uchar checksum; /* All bytes must add up to zero */ uchar reserved[5]; /* Must be zero */ } fields; char chars[16]; } PCI_bios32;/* Structure for a far pointer to call the PCI BIOS services with */typedef struct { ulong address; ushort segment; } PCIBIOS_entry;/* Macros to copy a structure that includes dwSize members */#define COPY_STRUCTURE(d,s) memcpy(d,s,MIN((s)->dwSize,(d)->dwSize))#pragma pack()/*--------------------------- Global variables ----------------------------*/static uchar *BIOSImage = NULL; /* BIOS image mapping */static int PCIBIOSVersion = -1;/* PCI BIOS version */static PCIBIOS_entry PCIEntry; /* PCI services entry point */static ulong PCIPhysEntry = 0; /* Physical address *//*----------------------------- Implementation ----------------------------*//* External assembler helper functions */uchar _ASMAPI _BIOS32_service(ulong service,ulong function,ulong *physBase,ulong *length,ulong *serviceOffset,PCIBIOS_entry entry);ushort _ASMAPI _PCIBIOS_isPresent(ulong i_eax,ulong *o_edx,ushort *o_ax,uchar *o_cl,PCIBIOS_entry entry);ulong _ASMAPI _PCIBIOS_service(ulong r_eax,ulong r_ebx,ulong r_edi,ulong r_ecx,PCIBIOS_entry entry);int _ASMAPI _PCIBIOS_getRouting(PCIRoutingOptionsBuffer *buf,PCIBIOS_entry entry);ibool _ASMAPI _PCIBIOS_setIRQ(int busDev,int intPin,int IRQ,PCIBIOS_entry entry);ulong _ASMAPI _PCIBIOS_specialCycle(int bus,ulong data,PCIBIOS_entry entry);ushort _ASMAPI _PCI_getCS(void);/****************************************************************************REMARKS:This functions returns the physical address of the PCI BIOS entry point.****************************************************************************/ulong _ASMAPI PCIBIOS_getEntry(void){ return PCIPhysEntry; }/****************************************************************************PARAMETERS:hwType - Place to store the PCI hardware access mechanism flagslastBus - Place to store the index of the last PCI bus in the systemRETURNS:Version number of the PCI BIOS found.REMARKS:This function determines if the PCI BIOS is present in the system, and ifso returns the information returned by the PCI BIOS detect function.****************************************************************************/static int PCIBIOS_detect( uchar *hwType, uchar *lastBus){ ulong signature; ushort stat,version;#ifndef __16BIT__ PCIBIOS_entry BIOSEntry = {0}; uchar *BIOSEnd; PCI_bios32 *BIOSDir; ulong physBase,length,offset; /* Bail if we have already detected no BIOS is present */ if (PCIBIOSVersion == 0) return 0; /* First scan the memory from 0xE0000 to 0xFFFFF looking for the * BIOS32 service directory, so we can determine if we can call it * from 32-bit protected mode. */ if (PCIBIOSVersion == -1) { PCIBIOSVersion = 0; BIOSImage = PM_mapPhysicalAddr(0xE0000,BIOS_LIMIT,false); if (!BIOSImage) return 0; BIOSEnd = BIOSImage + 0x20000; for (BIOSDir = (PCI_bios32*)BIOSImage; BIOSDir < (PCI_bios32*)BIOSEnd; BIOSDir++) { uchar sum; int i,length; if (BIOSDir->fields.signature != BIOS32_SIGNATURE) continue; length = BIOSDir->fields.length * 16; if (!length) continue; for (sum = i = 0; i < length ; i++) sum += BIOSDir->chars[i]; if (sum != 0) continue; BIOSEntry.address = (ulong)BIOSImage + (BIOSDir->fields.entry - 0xE0000); BIOSEntry.segment = _PCI_getCS(); break; } /* If we found the BIOS32 directory, call it to get the address of the * PCI services. */ if (BIOSEntry.address == 0) return 0; if (_BIOS32_service(PCI_SERVICE,0,&physBase,&length,&offset,BIOSEntry) != 0) return 0; PCIPhysEntry = physBase + offset; PCIEntry.address = (ulong)BIOSImage + (PCIPhysEntry - 0xE0000); PCIEntry.segment = _PCI_getCS(); }#endif /* We found the BIOS entry, so now do the version check */ version = _PCIBIOS_isPresent(PCI_BIOS_PRESENT,&signature,&stat,lastBus,PCIEntry); if (version > 0 && ((stat >> 8) == 0) && signature == PCI_SIGNATURE) { *hwType = stat & 0xFF; return PCIBIOSVersion = version; } return 0;}/****************************************************************************PARAMETERS:info - Array of PCIDeviceInfo structures to check againstindex - Index of the current device to checkRETURNS:True if the device is a duplicate, false if not.REMARKS:This function goes through the list of all devices preceeding the newlyfound device in the info structure, and checks that the device is not aduplicate of a previous device. Some devices incorrectly enumeratethemselves at different function addresses so we check here to excludethose cases.****************************************************************************/static ibool CheckDuplicate( PCIDeviceInfo *info, PCIDeviceInfo *prev){ /* Ignore devices with a vendor ID of 0 */ if (info->VendorID == 0) return true; /* NOTE: We only check against the current device on * the bus to ensure that we do not exclude * multiple controllers of the same device ID. */ if (info->slot.p.Bus == prev->slot.p.Bus && info->slot.p.Device == prev->slot.p.Device && info->DeviceID == prev->DeviceID) return true; return false;}/****************************************************************************PARAMETERS:info - Array of PCIDeviceInfo structures to fill inmaxDevices - Maximum number of of devices to enumerate into arrayRETURNS:Number of PCI devices found and enumerated on the PCI bus, 0 if not PCI.REMARKS:Function to enumerate all available devices on the PCI bus into an arrayof configuration information blocks.****************************************************************************/static int PCI_enumerateMech1( PCIDeviceInfo info[]){ int bus,device,function,i,numFound = 0; ulong *lp,tmp; PCIslot slot = {{0,0,0,0,0,0,1}}; PCIDeviceInfo pci,prev = {0}; /* Try PCI access mechanism 1 */ PM_outpb(0xCFB,0x01); tmp = PM_inpd(0xCF8); PM_outpd(0xCF8,slot.i); if ((PM_inpd(0xCF8) == slot.i) && (PM_inpd(0xCFC) != 0xFFFFFFFFUL)) { /* PCI access mechanism 1 - the preferred mechanism */ for (bus = 0; bus < 8; bus++) { slot.p.Bus = bus; for (device = 0; device < 32; device++) { slot.p.Device = device; for (function = 0; function < 8; function++) { slot.p.Function = function; slot.p.Register = 0; PM_outpd(0xCF8,slot.i); if (PM_inpd(0xCFC) != 0xFFFFFFFFUL) { memset(&pci,0,sizeof(pci)); pci.dwSize = sizeof(pci); pci.mech1 = 1; pci.slot = slot; lp = (ulong*)&(pci.VendorID); for (i = 0; i < NUM_PCI_REG; i++, lp++) { slot.p.Register = i; PM_outpd(0xCF8,slot.i); *lp = PM_inpd(0xCFC); } if (!CheckDuplicate(&pci,&prev)) { if (info) COPY_STRUCTURE(&info[numFound],&pci); ++numFound; } prev = pci; } } } } /* Disable PCI config cycle on exit */ PM_outpd(0xCF8,0); return numFound; } PM_outpd(0xCF8,tmp); /* No hardware access mechanism 1 found */ return 0;}/****************************************************************************PARAMETERS:info - Array of PCIDeviceInfo structures to fill inmaxDevices - Maximum number of of devices to enumerate into arrayRETURNS:Number of PCI devices found and enumerated on the PCI bus, 0 if not PCI.REMARKS:Function to enumerate all available devices on the PCI bus into an arrayof configuration information blocks.****************************************************************************/static int PCI_enumerateMech2( PCIDeviceInfo info[]){ int bus,device,function,i,numFound = 0; ushort deviceIO; ulong *lp; PCIslot slot = {{0,0,0,0,0,0,1}}; PCIDeviceInfo pci,prev = {0}; /* Try PCI access mechanism 2 */ PM_outpb(0xCFB,0x00); PM_outpb(0xCF8,0x00); PM_outpb(0xCFA,0x00); if (PM_inpb(0xCF8) == 0x00 && PM_inpb(0xCFB) == 0x00) { /* PCI access mechanism 2 - the older mechanism for legacy busses */ for (bus = 0; bus < 2; bus++) { slot.p.Bus = bus; PM_outpb(0xCFA,(uchar)bus); for (device = 0; device < 16; device++) { slot.p.Device = device; deviceIO = 0xC000 + (device << 8); for (function = 0; function < 8; function++) { slot.p.Function = function; slot.p.Register = 0; PM_outpb(0xCF8,(uchar)((function << 1) | 0x10)); if (PM_inpd(deviceIO) != 0xFFFFFFFFUL) { memset(&pci,0,sizeof(pci)); pci.dwSize = sizeof(pci); pci.mech1 = 0; pci.slot = slot; lp = (ulong*)&(pci.VendorID); for (i = 0; i < NUM_PCI_REG; i++, lp++) { slot.p.Register = i; *lp = PM_inpd(deviceIO + (i << 2)); } if (!CheckDuplicate(&pci,&prev)) { if (info) COPY_STRUCTURE(&info[numFound],&pci); ++numFound; } prev = pci; } } } } /* Disable PCI config cycle on exit */ PM_outpb(0xCF8,0); return numFound; } /* No hardware access mechanism 2 found */ return 0;}/****************************************************************************REMARKS:This functions reads a configuration dword via the PCI BIOS.****************************************************************************/static ulong PCIBIOS_readDWORD( int index, ulong slot){ return (ulong)_PCIBIOS_service(READ_CONFIG_DWORD,slot >> 8,index,0,PCIEntry);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -