📄 pciiomaplib.c
字号:
**/STATUS pciIomapLibInit ( int mechanism, /* configuration mechanism: 1, 2 or 3 */ int addr0, /* config-addr-reg / CSE-reg */ int addr1, /* config-data-reg / Forward-reg */ int addr2 /* none / Base-address */ ) { int ix; if (pciLibInitStatus != NONE) return (pciLibInitStatus); switch (mechanism) { case PCI_MECHANISM_1: case PCI_MECHANISM_2: case PCI_MECHANISM_3: pciConfigMech = mechanism; pciConfigAddr0 = addr0; pciConfigAddr1 = addr1; pciConfigAddr2 = addr2; pciLibInitStatus = OK; break; default: pciLibInitStatus = ERROR; break; } for (ix = 0; ix < PCI_IRQ_LINES; ix++) dllInit (&pciIntList[ix]); return (pciLibInitStatus); }/********************************************************************************* pciFindDevice - find the nth device with the given device & vendor ID** This routine finds the nth device with the given device & vendor ID.** RETURNS: OK or ERROR if the deviceId and vendorId didn't match.**/STATUS pciFindDevice ( int vendorId, /* vendor ID */ int deviceId, /* device ID */ int index, /* desired instance of device */ int * pBusNo, /* bus number */ int * pDeviceNo, /* device number */ int * pFuncNo /* function number */ ) { STATUS status = ERROR; BOOL cont = TRUE; int busNo; int deviceNo; int funcNo; UINT16 device; UINT16 vendor; UINT8 header; UINT32 devClass; int is_a_multi_function_device = 0; if (pciLibInitStatus != OK) cont = FALSE; for (busNo = 0; cont == TRUE && busNo < PCI_MAX_BUS; busNo++) for (deviceNo = 0; cont == TRUE && deviceNo < 31; ++deviceNo) { is_a_multi_function_device = 0; for (funcNo = 0; cont == TRUE && funcNo < PCI_MAX_FUNC; funcNo++) { if ( (funcNo != 0) && !is_a_multi_function_device) continue; pciConfigInWord (busNo, deviceNo, funcNo, PCI_CFG_VENDOR_ID, (short *) &vendor); /* If nonexistent device, skip to next (PCI_NOTFITTED)*/ if (vendor == 0xFFFF) break; pciConfigInByte(busNo, deviceNo, funcNo, PCI_CFG_HEADER_TYPE, &header); if (funcNo == 0) { is_a_multi_function_device = ((header & 0x80) != 0); } pciConfigInWord(busNo, deviceNo, funcNo, PCI_CFG_DEVICE_ID, (short *) &device); if ((vendor == (UINT16)vendorId) && (device == (UINT16)deviceId) && (index-- == 0)) { pciConfigInLong (busNo, deviceNo, funcNo, PCI_CFG_REVISION, (int *) &devClass); devClass = (devClass & 0xFFFFFF00) >> 8; if ( (devClass >> 16) == 0x06) { /* BRIDGE... */ } *pBusNo = busNo; *pDeviceNo = deviceNo; *pFuncNo = funcNo; status = OK; /* terminate all loops */ cont = FALSE; continue; } } } return (status); }/********************************************************************************* pciFindClass - find the nth occurence of a device by PCI class code.** This routine finds the nth device with the given 24-bit PCI class code* (class subclass prog_if).** RETURNS: OK or ERROR if the class didn't match.**/STATUS pciFindClass ( int classCode, /* 24-bit class code */ int index, /* desired instance of device */ int * pBusNo, /* bus number */ int * pDeviceNo, /* device number */ int * pFuncNo /* function number */ ) { STATUS status = ERROR; BOOL cont = TRUE; int busNo; int deviceNo; int funcNo; int classCodeReg; char header; if (pciLibInitStatus != OK) cont = FALSE; for (busNo = 0; cont == TRUE && busNo < PCI_MAX_BUS; busNo++) for (deviceNo = 0; cont == TRUE && deviceNo < ((busNo == 0) ? PCI_MAX_DEV : 16); ++deviceNo) for (funcNo = 0; cont == TRUE && funcNo < PCI_MAX_FUNC; funcNo++) {#if (PCI_MAX_DEV > 31) && (PCI_MAX_FUNC > 7) /* avoid a special bus cycle */ if ((deviceNo == 0x1f) && (funcNo == 0x07)) continue;#endif pciConfigInLong (busNo, deviceNo, funcNo, PCI_CFG_REVISION, &classCodeReg); /* If nonexistent device, skip to next */ if (((UINT32)classCodeReg == 0xFFFFFFFF) && (funcNo == 0)) break; if ((((classCodeReg >> 8) & 0x00ffffff) == classCode) && (index-- == 0)) { *pBusNo = busNo; *pDeviceNo = deviceNo; *pFuncNo = funcNo; status = OK; /* terminate all loops */ cont = FALSE; continue; } /* goto next if current device is single function */ pciConfigInByte (busNo, deviceNo, funcNo, PCI_CFG_HEADER_TYPE, &header); if ((header & PCI_HEADER_MULTI_FUNC) != PCI_HEADER_MULTI_FUNC && funcNo == 0) break; } return (status); }/******************************************************************************** pciDevConfig - configure a device on a PCI bus** This routine configures a device that is on a Peripheral Component* Interconnect (PCI) bus by writing to the configuration header of the* selected device.* It first disables the device by clearing the command register in the* configuration header. It then sets the I/O and/or memory space base* address registers, the latency timer value and the cache line size.* Finally, it re-enables the device by loading the command register with* the specified command.** NOTE: This routine is designed for Type 0 PCI Configuration Headers ONLY.* It is NOT usable for configuring, for example, a PCI-to-PCI bridge.** RETURNS: OK always.*/STATUS pciDevConfig ( int pciBusNo, /* PCI bus number */ int pciDevNo, /* PCI device number */ int pciFuncNo, /* PCI function number */ ULONG devIoBaseAdrs, /* device IO base address */ ULONG devMemBaseAdrs, /* device memory base address */ ULONG command /* command to issue */ ) { INT32 ix; UINT32 tmp32; /* * Disable device by clearing its command register field in its * configuration header. */ pciConfigOutWord (pciBusNo, pciDevNo, pciFuncNo, PCI_CFG_COMMAND, 0); /* * Due to system constraints, this is a partial implementation * of enabling the Base Address Registers (BARs). * It is hoped that all PCI devices only require at most one * I/O space and/or one memory space. * If not, this code will re-allocate the device's memory to * each BAR implemented. Sounds like future trouble! */ for (ix = PCI_CFG_BASE_ADDRESS_0; ix <= PCI_CFG_BASE_ADDRESS_5; ix+=4) { /* Write all f's and read back value */ pciConfigOutLong (pciBusNo, pciDevNo, pciFuncNo, ix, 0xffffffff); pciConfigInLong (pciBusNo, pciDevNo, pciFuncNo, ix, (int *) &tmp32); /* BAR implemented? */ if (tmp32 == 0) { /* * No! According to the spec, BARs must be implemented * in sequence starting at BAR 0. So, all done. */ break; } if (tmp32 & 0x1) { /* I/O space requested, set specified I/O space base address */ pciConfigOutLong (pciBusNo, pciDevNo, pciFuncNo, ix, devIoBaseAdrs | 0x1); } else { /* Memory space required, set specified base address */ pciConfigOutLong (pciBusNo, pciDevNo, pciFuncNo, ix, devMemBaseAdrs & ~0x1); } } /* Configure Latency Timer */ pciConfigOutByte (pciBusNo, pciDevNo, pciFuncNo, PCI_CFG_LATENCY_TIMER, 0xFF); /* Enable the device's capabilities as specified */ pciConfigOutWord (pciBusNo, pciDevNo, pciFuncNo, PCI_CFG_COMMAND, (UINT16)command); return (OK); }/********************************************************************************* pciPack - pack parameters for the Configuration Address Register** This routine packs three parameters into one integer for accessing the* Configuration Address Register** RETURNS: packed integer**/LOCAL int pciPack ( int busNo, /* bus number */ int deviceNo, /* device number */ int funcNo /* function number */ ) { return (((busNo << 16) & 0x00ff0000) | ((deviceNo << 11) & 0x0000f800) | ((funcNo << 8) & 0x00000700)); }/********************************************************************************* pciSpecialCycle - generate a special cycle with a message** This routine generates a special cycle with a message.** RETURNS: OK or ERROR if this library is not initialized.**/STATUS pciSpecialCycle ( int busNo, /* bus number */ int message /* data on AD[31:0] during the special cycle */ ) { int deviceNo = 0x0000001f; int funcNo = 0x00000007; int key; if (pciLibInitStatus != OK) return (ERROR); /* mutual exclusion start */ key = intLock(); switch (pciConfigMech) { case PCI_MECHANISM_1: PCI_OUT_LONG (pciConfigAddr0, pciPack (busNo, deviceNo, funcNo) | 0x80000000); PCI_OUT_LONG (pciConfigAddr1, message); break; case PCI_MECHANISM_2: PCI_OUT_BYTE (pciConfigAddr0, 0xff); PCI_OUT_BYTE (pciConfigAddr1, 0x00); PCI_OUT_LONG ((pciConfigAddr2 | ((deviceNo & 0x000f) << 8)), message); PCI_OUT_BYTE (pciConfigAddr0, 0); break; default: break; } /* mutual exclusion stop */ intUnlock(key); return (OK); }/********************************************************************************* pciInt - interrupt handler for shared PCI interrupt.** This routine executes multiple interrupt handlers for a PCI interrupt.* Each interrupt handler must check the device dependent interrupt status bit* to determine the source of the interrupt, since it simply execute all* interrupt handlers in the link list.** RETURNS: N/A**/VOID pciInt ( int irq /* IRQ associated to the PCI interrupt */ ) { PCI_INT_RTN *pRtn; for (pRtn = (PCI_INT_RTN *)DLL_FIRST (&pciIntList[irq]); pRtn != NULL; pRtn = (PCI_INT_RTN *)DLL_NEXT (&pRtn->node)) (* pRtn->routine) (pRtn->parameter); }/********************************************************************************* pciIntConnect - connect the interrupt handler to the PCI interrupt.** This routine connects an interrupt handler to the PCI interrupt line(A - D).* Link list is created if multiple handlers are assigned to the single PCI* interrupt.** RETURNS: OK or ERROR if the interrupt handler cannot be built.**/STATUS pciIntConnect ( VOIDFUNCPTR *vector, /* interrupt vector to attach to */ VOIDFUNCPTR routine, /* routine to be called */ int parameter /* parameter to be passed to routine */ ) { int irq = IVEC_TO_INUM ((int)vector) - INT_NUM_IRQ0; PCI_INT_RTN *pRtn; int oldLevel; if (pciLibInitStatus != OK) return (ERROR); pRtn = (PCI_INT_RTN *)malloc (sizeof (PCI_INT_RTN)); if (pRtn == NULL) return (ERROR); pRtn->routine = routine; pRtn->parameter = parameter; oldLevel = intLock (); /* LOCK INTERRUPT */ dllAdd (&pciIntList[irq], &pRtn->node); intUnlock (oldLevel); /* UNLOCK INTERRUPT */ return (OK); }/********************************************************************************* pciIntDisconnect - disconnect the interrupt handler from the PCI interrupt.** This routine disconnects the interrupt handler from the PCI interrupt line.** RETURNS: OK or ERROR if the interrupt handler cannot be removed.**/STATUS pciIntDisconnect ( VOIDFUNCPTR *vector, /* interrupt vector to attach to */ VOIDFUNCPTR routine /* routine to be called */ ) { int irq = IVEC_TO_INUM ((int)vector) - INT_NUM_IRQ0; PCI_INT_RTN *pRtn; int oldLevel; if (pciLibInitStatus != OK) return (ERROR); for (pRtn = (PCI_INT_RTN *)DLL_FIRST (&pciIntList[irq]); pRtn != NULL; pRtn = (PCI_INT_RTN *)DLL_NEXT (&pRtn->node)) { if (pRtn->routine == routine) { oldLevel = intLock (); /* LOCK INTERRUPT */ dllRemove (&pciIntList[irq], &pRtn->node); intUnlock (oldLevel); /* UNLOCK INTERRUPT */ free ((char *)pRtn); return (OK); } } return (ERROR); }#endif /* defined(INCLUDE_PCI) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -