pci.c

来自「WinCE 3.0 BSP, 包含Inter SA1110, Intel_815」· C语言 代码 · 共 928 行 · 第 1/3 页

C
928
字号
} /* FindPCIParentDevice() */



/* This function will list all devices that are present on the PCI bus	*/
int ListPCIDevices( void ) {

	PCIDevIDRec TargetPCIDevID;
	PCIDevAddrRec CurDevice;
    WORD wVendorID, wDeviceID;
	WORD wPCIStatus;

	/* Initialize search specification record to match anything */
	TargetPCIDevID.wVendorID = TargetPCIDevID.wDeviceID = 0;
	TargetPCIDevID.wSubsystemVendorID = TargetPCIDevID.wSubsystemID = 0;

	/* Initialize search location record to start from beginning */
	CurDevice.bParentDevNo = CurDevice.bDevNo = 0xFF;

	DbgPrintf( "Searching For PCI Devices...\n" );

	do {
		if (FindNextPCIDevice( &TargetPCIDevID, &CurDevice )) {
			DbgPrintf( "ListPCIDevices() - ERROR: Call To FindNextPCIDevice() Failed\n" );
			return 1;
		}
		if (CurDevice.bDevNo != 0xFF) {
			/* Read the Vendor ID   */
			OEM_ReadConfigWord( CurDevice.bBusNo, CurDevice.bDevNo, CurDevice.bFuncNo, 0x00, &wVendorID );
			if ((wPCIStatus = GetPCIBridgeStatus( &CurDevice )) != 0) {
				ClearPCIBridgeStatus( &CurDevice );
				DbgPrintf( "FindNextPCIDevice() - ERROR: Vendor ID Read Failed\n" );
				PrintPCIError( wPCIStatus );
				return 1;
			}
			/* Read the Device ID   */
			OEM_ReadConfigWord( CurDevice.bBusNo, CurDevice.bDevNo, CurDevice.bFuncNo, 0x02, &wDeviceID );
			if ((wPCIStatus = GetPCIBridgeStatus( &CurDevice )) != 0) {
				ClearPCIBridgeStatus( &CurDevice );
				DbgPrintf( "FindNextPCIDevice() - ERROR: Device ID Read Failed\n" );
				PrintPCIError( wPCIStatus );
				return 1;
			}
			DbgPrintf( "    Vendor ID 0x%04X Device ID 0x%04X at Bus %d, Device %d, Function %d\n",
				wVendorID, wDeviceID, CurDevice.bBusNo, CurDevice.bDevNo, CurDevice.bFuncNo );
		}
	}
	while (CurDevice.bDevNo != 0xFF);

	DbgPrintf( "PCI Device Search Complete\n" );

	return 0;

} /* ListPCIDevices() */



/* This routine will create the memory and I/O windows specified in pPCIMapInfo */
/*  through all the bridges between the device specified in pCurDevice and the  */
/*  device specified in pTargetDevice.  You must specify the full configuration */
/*  address for pCurDevice unless starting from the host bridge, in which case  */
/*  you must initialize the pTargetDevice->bParentDevNo to 0xFF to indicate     */
/*  starting from the host bridge, and initialize pTargetDevice->bDevNo to 0xFF */
/*  to indicate starting from device 0.                                         */
int MapPCIWindows( PCIMapInfoRec *pPCIMapInfo, PCIDevAddrRec *pCurDevice, PCIDevAddrRec *pTargetDevice ) {

	WORD wPCIStatus;
	BYTE bHeaderType, bSecondaryBusNo, bSubordinateBusNo;

	DbgPrintf("+MapPCIWindows()\n");

	/* If the parent device number is 0xFF, then assume that we are on the	*/
	/*	PCI segment that is directly connected to the host bridge.  It has	*/
	/*	bus number 0.														*/
	if (pCurDevice->bParentDevNo == 0xFF)
		pCurDevice->bBusNo = 0;

    /* Set the current bridge windows  */
    if (SetPCIBridgeWindows( pCurDevice, pPCIMapInfo )) {
        DbgPrintf( "MapPCIWindows() - ERROR: Call To SetPCIBridgeWindows() Failed\n" );
	    return 1;
    }

	DbgPrintf("MapPCIWindows: pCurDevice->bBusNo=%d, pTargetDevice->bBusNo=%d\n",
					pCurDevice->bBusNo, pTargetDevice->bBusNo);

    /* See if we have arrived on the same bus as the target device yet. */
    /*  If so, we're done.												*/
    if (pCurDevice->bBusNo == pTargetDevice->bBusNo)
        return 0;

	if (ScanNextPCIDevice( pCurDevice )) {
		DbgPrintf( "MapPCIWindows() - ERROR: Call To ScanNextPCIDevice() Failed\n" );
		return 1;
	}
    while( pCurDevice->bDevNo != 0xFF ) {

		/* Read the configuration header type in order to determine		*/
		/*	whether or not this is a bridge.							*/
		OEM_ReadConfigByte( pCurDevice->bBusNo, pCurDevice->bDevNo, 0x00, 0x0E, &bHeaderType );
		if ((wPCIStatus = GetPCIBridgeStatus( pCurDevice )) != 0) {
			DbgPrintf( "MapPCIWindows() - ERROR: Configuration Header Type Read Failed\n" );
			ClearPCIBridgeStatus( pCurDevice );
			PrintPCIError( wPCIStatus );
			return 1;
		}

		/* If this is a PCI-PCI bridge we need to determine if the	*/
		/*	target device is behind it.								*/
		if ((bHeaderType & 0x7F) == 0x01) {

			/* Read the secondary bus number	*/
			OEM_ReadConfigByte( pCurDevice->bBusNo, pCurDevice->bDevNo, pCurDevice->bFuncNo, 0x19, &bSecondaryBusNo );
			if ((wPCIStatus = GetPCIBridgeStatus( pCurDevice )) != 0) {
				DbgPrintf( "MapPCIWindows() - ERROR: Secondary Bus Number Read Failed\n" );
				ClearPCIBridgeStatus( pCurDevice );
				PrintPCIError( wPCIStatus );
				return 1;
			}

			/* Read the subordinate bus number	*/
			OEM_ReadConfigByte( pCurDevice->bBusNo, pCurDevice->bDevNo, pCurDevice->bFuncNo, 0x1A, &bSubordinateBusNo );
			if ((wPCIStatus = GetPCIBridgeStatus( pCurDevice )) != 0) {
				DbgPrintf( "MapPCIWindows() - ERROR: Subordinate Bus Number Read Failed\n" );
				ClearPCIBridgeStatus( pCurDevice );
				PrintPCIError( wPCIStatus );
				return 1;
			}

			/* If the RIO is behind this bridge, then we need to recursively	*/
			/*	call ourselves and set it up.									*/
			if (pTargetDevice->bBusNo >= bSecondaryBusNo && pTargetDevice->bBusNo <= bSubordinateBusNo) {

				/* Go look for the RIO on the secondary side of the bridge	*/
				pCurDevice->bParentBusNo = pCurDevice->bBusNo;
				pCurDevice->bParentDevNo = pCurDevice->bDevNo;
				pCurDevice->bParentFuncNo = pCurDevice->bFuncNo;
				pCurDevice->bBusNo = bSecondaryBusNo;
				pCurDevice->bDevNo = 0xFF;
				if (MapPCIWindows( pPCIMapInfo, pCurDevice, pTargetDevice ))
					return 1;
				return 0;

			}
		}

		/* Find the next PCI device on this segment	*/
		if (ScanNextPCIDevice( pCurDevice )) {
			DbgPrintf( "MapPCIWindows() - ERROR: Call To ScanNextPCIDevice() Failed\n" );
			return 1;
		}
    }

	DbgPrintf( "MapPCIWindows() - ERROR: Could Not Find Path To Target Device\n" );
	return 1;

} /* MapPCIWindows() */



/* This routine will clear the PCI secondary status register flags in the PCI	*/
/*	device indicated.  Note that for bus 0 (the PCI host bridge) this will be	*/
/*	the only set of status flags.  For any other bus number, we are going		*/
/*	through a PCI-PCI bridge and we will be working with the secondary			*/
/*	interface status register.													*/
WORD GetPCIBridgeStatus( PCIDevAddrRec *pPCIDevice ) {

	WORD wPCIStatus;

	if (pPCIDevice->bParentDevNo == 0xFF)
		OEM_GetPCIHostBridgeStatus( &wPCIStatus );
	else
		OEM_ReadConfigWord( pPCIDevice->bParentBusNo, pPCIDevice->bParentDevNo,
			pPCIDevice->bParentFuncNo, 0x1E, &wPCIStatus );

	return wPCIStatus & PCIE_MASK;

} /* GetPCIBridgeStatus() */



/* This routine will clear the PCI secondary status register flags in the PCI	*/
/*	device indicated.  Note that for bus 0 (the PCI host bridge) this will be	*/
/*	the only set of status flags.  For any other bus number, we are going		*/
/*	through a normal PCI-PCI bridge and we will be working with the secondary	*/
/*	interface status register.													*/
void ClearPCIBridgeStatus( PCIDevAddrRec *pPCIDevice ) {

	if (pPCIDevice->bParentDevNo == 0xFF)
		OEM_ClearPCIHostBridgeStatus();
	else
		OEM_WriteConfigWord( pPCIDevice->bParentBusNo, pPCIDevice->bParentDevNo,
			pPCIDevice->bParentFuncNo, 0x1E, PCIE_MASK );

} /* ClearPCIBridgeStatus() */



/* This routine will print a description of each of the PCI error codes	*/
/*	that are flagged in an error code word.								*/
void PrintPCIError( WORD wPCIErrorCode ) {

	if (!wPCIErrorCode) {
		DbgPrintf( "No Error" );
		return;
	}
	if (wPCIErrorCode & PCIE_PARITY_ERROR)
		DbgPrintf( "PCI Parity Error Detected\n" );
	if (wPCIErrorCode & PCIE_SYSTEM_ERROR)
		DbgPrintf( "PCI System Error Detected\n" );
	if (wPCIErrorCode & PCIE_MASTER_ABORT)
		DbgPrintf( "PCI Master Abort Detected\n" );
	if (wPCIErrorCode & PCIE_TARGET_ABORT_MASTER)
		DbgPrintf( "PCI Target Abort Detected While Interface Was Master\n" );
	if (wPCIErrorCode & PCIE_TARGET_ABORT_TARGET)
		DbgPrintf( "PCI Target Abort Detected While Interface Was Target\n" );
	if (wPCIErrorCode & PCIE_MASTER_PARITY_ERROR)
		DbgPrintf( "PCI Parity Error Detect While Interface Was Master\n" );

} /* PrintPCIError() */



/* This function takes the configuration address for a PCI device as the	*/
/*	parameter pPCIDevice.  It will then activate the bridge that is			*/
/*	specified as that device's parent and will open memory and I/O windows	*/
/*	 specified in pPCIMapInfo.												*/
int SetPCIBridgeWindows( PCIDevAddrRec *pPCIDevice, PCIMapInfoRec *pPCIMapInfo ) {

	WORD wPCIStatus;

	DbgPrintf("+SetPCIBridgeWindows(). pPciDevice->bParentDevNo = %d\n", pPCIDevice->bParentDevNo);
	/* If the parent bridge addres pointer is NULL, then the parent is the	*/
	/*	PCI Host Bridge.  Call the OEM function to configure that.			*/
	if (pPCIDevice->bParentDevNo == 0xFF) {
		if (OEM_SetPCIHostBridgeWindows( pPCIMapInfo )) {
			DbgPrintf( "SetBridgeWindows() - ERROR: Call To OEM_SetPCIHostBridgeWindows() Failed\n" );
			return 1;
		}
	}
	else {

		/* Fill in the Memory Address range information.			*/

		/* Fill in the Memory Base Register	*/
		OEM_WriteConfigWord( pPCIDevice->bParentBusNo, pPCIDevice->bParentDevNo, pPCIDevice->bParentFuncNo,
			0x20, (WORD)(pPCIMapInfo->dwPCIMemBase >> 16));
		if ((wPCIStatus = GetPCIBridgeStatus( pPCIDevice )) != 0) {
			DbgPrintf( "SetBridgeWindows() - ERROR: PCI Memory Base Write Failed\n" );
			ClearPCIBridgeStatus( pPCIDevice );
			PrintPCIError( wPCIStatus );
			return 1;
		}
		/* Fill in the Memory Range Register	*/
		OEM_WriteConfigByte( pPCIDevice->bParentBusNo, pPCIDevice->bParentDevNo, pPCIDevice->bParentFuncNo,
			0x22, (WORD)(pPCIMapInfo->dwPCIMemLimit >> 16));
		if ((wPCIStatus = GetPCIBridgeStatus( pPCIDevice )) != 0) {
			DbgPrintf( "SetBridgeWindows() - ERROR: PCI Memory Limit Write Failed\n" );
			ClearPCIBridgeStatus( pPCIDevice );
			PrintPCIError( wPCIStatus );
			return 1;
		}

		/* Fill in the I/O Address range information.				*/
		/* Note that this is for 16-bit address range bridges only	*/
		/*	and I'll make it generic once I get the full PCI-PCI	*/
		/*	bridge specification.  16-bit address bridges only		*/
		/*	allow mapping in the lower 64K address range using 4K	*/
		/*	pages.													*/

DbgPrintf("Setting PCI-PCI bridge I/o Base Register. dwPCIIOBase = 0x%x, Limit = 0x%x\n", pPCIMapInfo->dwPCIIOBase, 
			pPCIMapInfo->dwPCIIOLimit);

		/* Fill in the I/O Base Register	*/
		OEM_WriteConfigByte( pPCIDevice->bParentBusNo, pPCIDevice->bParentDevNo, pPCIDevice->bParentFuncNo,
			0x1C, (BYTE)(pPCIMapInfo->dwPCIIOBase >> 8));
		if ((wPCIStatus = GetPCIBridgeStatus( pPCIDevice )) != 0) {
			DbgPrintf( "SetBridgeWindows() - ERROR: PCI I/O Base Write Failed\n" );
			ClearPCIBridgeStatus( pPCIDevice );
			PrintPCIError( wPCIStatus );
			return 1;
		}
		/* Fill in the I/O Range Register	*/
		OEM_WriteConfigByte( pPCIDevice->bParentBusNo, pPCIDevice->bParentDevNo, pPCIDevice->bParentFuncNo,
			0x1D, (BYTE)(pPCIMapInfo->dwPCIIOLimit >> 8));
		if ((wPCIStatus = GetPCIBridgeStatus( pPCIDevice )) != 0) {
			DbgPrintf( "SetBridgeWindows() - ERROR: PCI I/O Limit Write Failed\n" );
			ClearPCIBridgeStatus( pPCIDevice );
			PrintPCIError( wPCIStatus );
			return 1;
		}

		/* Turn on the bridge to accept memory and I/O accesses and	*/
		/*	also to act as a PCI master.							*/
		OEM_WriteConfigWord( pPCIDevice->bParentBusNo, pPCIDevice->bParentDevNo, pPCIDevice->bParentFuncNo,
			0x04, 0x0157 );
		if ((wPCIStatus = GetPCIBridgeStatus( pPCIDevice )) != 0) {
			DbgPrintf( "SetBridgeWindows() - ERROR: PCI Bridge Command Register Write Failed\n" );
			ClearPCIBridgeStatus( pPCIDevice );
			PrintPCIError( wPCIStatus );
			return 1;
		}
	}

	return 0;

} /* SetPCIBridgeWindows() */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?