📄 pcilib.c
字号:
/****************************************************************************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_enumerateBIOS( PCIDeviceInfo info[]){ uchar hwType,lastBus; int bus,device,function,i,numFound = 0; ulong *lp; PCIslot slot = {{0,0,0,0,0,0,1}}; PCIDeviceInfo pci,prev = {0}; if (PCIBIOS_detect(&hwType,&lastBus)) { /* PCI BIOS access - the ultimate fallback */ for (bus = 0; bus <= lastBus; 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; if (PCIBIOS_readDWORD(0,slot.i) != 0xFFFFFFFFUL) { memset(&pci,0,sizeof(pci)); pci.dwSize = sizeof(pci); pci.mech1 = 2; pci.slot = slot; lp = (ulong*)&(pci.VendorID); for (i = 0; i < NUM_PCI_REG; i++, lp++) *lp = PCIBIOS_readDWORD(i << 2,slot.i); if (!CheckDuplicate(&pci,&prev)) { if (info) COPY_STRUCTURE(&info[numFound],&pci); ++numFound; } prev = pci; } } } } } /* Return number of devices found */ return numFound;}/****************************************************************************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.****************************************************************************/int _ASMAPI PCI_enumerate( PCIDeviceInfo info[]){ int numFound; /* First try via the direct access mechanisms which are faster if we * have them (nearly always). The BIOS is used as a fallback, and for * stuff we can't do directly. */ if ((numFound = PCI_enumerateMech1(info)) == 0) { if ((numFound = PCI_enumerateMech2(info)) == 0) { if ((numFound = PCI_enumerateBIOS(info)) == 0) return 0; } } return numFound;}/****************************************************************************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.****************************************************************************/int _ASMAPI PCI_getNumDevices(void){ return PCI_enumerate(NULL);}/****************************************************************************PARAMETERS:bar - Base address to measurepci - PCI device to accessRETURNS:Size of the PCI base address in bytesREMARKS:This function measures the size of the PCI base address register in bytes,by writing all F's to the register, and reading the value back. The sizeof the base address is determines by the bits that are hardwired to zero's.****************************************************************************/ulong _ASMAPI PCI_findBARSize( int bar, PCIDeviceInfo *pci){ ulong base,size = 0; base = PCI_accessReg(bar,0,PCI_READ_DWORD,pci); if (base && !(base & 0x1)) { /* For some strange reason some devices don't properly decode * their base address registers (Intel PCI/PCI bridges!), and * we read completely bogus values. We check for that here * and clear out those BAR's. * * We check for that here because at least the low 12 bits * of the address range must be zeros, since the page size * on IA32 processors is always 4Kb. */ if ((base & 0xFFF) == 0) { PCI_accessReg(bar,0xFFFFFFFF,PCI_WRITE_DWORD,pci); size = PCI_accessReg(bar,0,PCI_READ_DWORD,pci) & ~0xFF; size = ~size+1; PCI_accessReg(bar,base,PCI_WRITE_DWORD,pci); } } pci->slot.p.Register = 0; return size;}/****************************************************************************PARAMETERS:index - DWORD index of the register to accessvalue - Value to write to the register for write accessfunc - Function to implementRETURNS:The value read from the register for read operationsREMARKS:The function code are defined as followscode - function0 - Read BYTE1 - Read WORD2 - Read DWORD3 - Write BYTE4 - Write WORD5 - Write DWORD****************************************************************************/ulong _ASMAPI PCI_accessReg( int index, ulong value, int func, PCIDeviceInfo *info){ int iobase; if (info->mech1 == 2) { /* Use PCI BIOS access since we dont have direct hardware access */ switch (func) { case PCI_READ_BYTE: return (uchar)_PCIBIOS_service(READ_CONFIG_BYTE,info->slot.i >> 8,index,0,PCIEntry); case PCI_READ_WORD: return (ushort)_PCIBIOS_service(READ_CONFIG_WORD,info->slot.i >> 8,index,0,PCIEntry); case PCI_READ_DWORD: return (ulong)_PCIBIOS_service(READ_CONFIG_DWORD,info->slot.i >> 8,index,0,PCIEntry); case PCI_WRITE_BYTE: _PCIBIOS_service(WRITE_CONFIG_BYTE,info->slot.i >> 8,index,value,PCIEntry); break; case PCI_WRITE_WORD: _PCIBIOS_service(WRITE_CONFIG_WORD,info->slot.i >> 8,index,value,PCIEntry); break; case PCI_WRITE_DWORD: _PCIBIOS_service(WRITE_CONFIG_DWORD,info->slot.i >> 8,index,value,PCIEntry); break; } } else { /* Use direct hardware access mechanisms */ if (info->mech1) { /* PCI access mechanism 1 */ iobase = 0xCFC + (index & 3); info->slot.p.Register = index >> 2; PM_outpd(0xCF8,info->slot.i); } else { /* PCI access mechanism 2 */ PM_outpb(0xCF8,(uchar)((info->slot.p.Function << 1) | 0x10)); PM_outpb(0xCFA,(uchar)info->slot.p.Bus); iobase = 0xC000 + (info->slot.p.Device << 8) + index; } switch (func) { case PCI_READ_BYTE: case PCI_READ_WORD: case PCI_READ_DWORD: value = PM_inpd(iobase); break; case PCI_WRITE_BYTE: PM_outpb(iobase,(uchar)value); break; case PCI_WRITE_WORD: PM_outpw(iobase,(ushort)value); break; case PCI_WRITE_DWORD: PM_outpd(iobase,(ulong)value); break; } PM_outpd(0xCF8,0); } return value;}/****************************************************************************PARAMETERS:numDevices - Number of devices to query info forRETURNS:0 on success, -1 on error, number of devices to enumerate if numDevices = 0REMARKS:This function reads the PCI routing information. If you pass a value of0 for numDevices, this function will return with the number of devicesneeded in the routing buffer that will be filled in by the BIOS.****************************************************************************/ibool _ASMAPI PCI_getIRQRoutingOptions( int numDevices, PCIRouteInfo *buffer){ PCIRoutingOptionsBuffer buf; int ret; if (PCIPhysEntry) { buf.BufferSize = numDevices * sizeof(PCIRouteInfo); buf.DataBuffer = buffer; if ((ret = _PCIBIOS_getRouting(&buf,PCIEntry)) == 0x89) return buf.BufferSize / sizeof(PCIRouteInfo); if (ret != 0) return -1; return 0; } /* We currently only support this via the PCI BIOS functions */ return -1;}/****************************************************************************PARAMETERS:info - PCI device information for the specified deviceintPin - Value to store in the PCI InterruptPin registerIRQ - New ISA IRQ to map the PCI interrupt to (0-15)RETURNS:True on success, or false if this function failed.REMARKS:This function changes the PCI IRQ routing for the specified device to thedesired PCI interrupt and the desired ISA bus compatible IRQ. This functionmay not be supported by the PCI BIOS, in which case this function willfail.****************************************************************************/ibool _ASMAPI PCI_setHardwareIRQ( PCIDeviceInfo *info, uint intPin, uint IRQ){ if (PCIPhysEntry) { if (_PCIBIOS_setIRQ(info->slot.i >> 8,intPin,IRQ,PCIEntry)) { info->u.type0.InterruptPin = intPin; info->u.type0.InterruptLine = IRQ; return true; } return false; } /* We currently only support this via the PCI BIOS functions */ return false;}/****************************************************************************PARAMETERS:bus - Bus number to generate the special cycle forspecialCycleData - Data to send for the special cyleREMARKS:This function generates a special cycle on the specified bus using withthe specified data.****************************************************************************/void _ASMAPI PCI_generateSpecialCyle( uint bus, ulong specialCycleData){ if (PCIPhysEntry) _PCIBIOS_specialCycle(bus,specialCycleData,PCIEntry); /* We currently only support this via the PCI BIOS functions */}/****************************************************************************PARAMETERS:info - PCI device information block for device to accessindex - Index of register to start reading fromdst - Place to store the values read from configuration spacecount - Count of bytes to read from configuration spaceREMARKS:This function is used to read a block of PCI configuration space registersfrom the configuration space into the passed in data block. This functionwill properly handle reading non-DWORD aligned data from the configurationspace correctly.****************************************************************************/void _ASMAPI PCI_readRegBlock( PCIDeviceInfo *info, int index, void *dst, int count){ uchar *pb; ulong *pd; int i; int startCount = (index & 3); int middleCount = (count - startCount) >> 2; int endCount = count - middleCount * 4 - startCount; for (i = 0,pb = dst; i < startCount; i++, index++) { *pb++ = (uchar)PCI_accessReg(index,0,PCI_READ_BYTE,info); } for (i = 0,pd = (ulong*)pb; i < middleCount; i++, index += 4) { *pd++ = (ulong)PCI_accessReg(index,0,PCI_READ_DWORD,info); } for (i = 0,pb = (uchar*)pd; i < endCount; i++, index++) { *pb++ = (uchar)PCI_accessReg(index,0,PCI_READ_BYTE,info); }}/****************************************************************************PARAMETERS:info - PCI device information block for device to accessindex - Index of register to start reading fromdst - Place to store the values read from configuration spacecount - Count of bytes to read from configuration spaceREMARKS:This function is used to write a block of PCI configuration space registersto the configuration space from the passed in data block. This functionwill properly handle writing non-DWORD aligned data to the configurationspace correctly.****************************************************************************/void _ASMAPI PCI_writeRegBlock( PCIDeviceInfo *info, int index, void *src, int count){ uchar *pb; ulong *pd; int i; int startCount = (index & 3); int middleCount = (count - startCount) >> 2; int endCount = count - middleCount * 4 - startCount; for (i = 0,pb = src; i < startCount; i++, index++) { PCI_accessReg(index,*pb++,PCI_WRITE_BYTE,info); } for (i = 0,pd = (ulong*)pb; i < middleCount; i++, index += 4) { PCI_accessReg(index,*pd++,PCI_WRITE_DWORD,info); } for (i = 0,pb = (uchar*)pd; i < endCount; i++, index++) { PCI_accessReg(index,*pb++,PCI_WRITE_BYTE,info); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -