pci_enum.c

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

C
796
字号

		OEM_ReadConfigWord(0, CurSlot, 0, 2, &sval);
  		pPciDev->DeviceID = sval;
  		DEBUGMSG(LEVEL5, (TEXT("Device ID from slot %d = 0x%x\r\n"), CurSlot, sval));

		// Get The Base Class Code of the device.
		OEM_ReadConfigByte(0, CurSlot, 0, BASE_CLASS_CODE, &cval);
		if(cval >= 0x0d && cval <= 0xfe) {
			cval = PCI_CLASS_RESERVED;
		}
		if(cval == 0xff) {
			cval = PCI_CLASS_UNDEFINED;
		}
		pPciDev->BaseClassCode = cval;
		DEBUGMSG(LEVEL5, (TEXT("Device Base Class Code: %s[%d]\r\n"), DeviceClass[cval], cval));

		// Determine whether the device is single function or multi-function
		OEM_ReadConfigByte(0, CurSlot, 0, HEADER_TYPE, &cval);
		pPciDev->HeaderType = cval;
		DEBUGMSG(LEVEL5, (TEXT("Header type = 0x%x\r\n"), (unsigned)cval));

		if(cval != 0x00) {
			DEBUGMSG(LEVEL5, (TEXT("Multifunction devices not supported yet.\r\n")));
			DEBUGMSG(LEVEL5, (TEXT("This device may not work ...\r\n")));

			// Also remove this from the list of recognized devices.
			// pPciDev->VendorID = 0xffff;
			// continue;
		}

		// Assign the system resources now.

		pPciDev->LogInterrupt = 0;	// Default value of Logical Interrupt if the device does not
									// request for an interrupt line.

		// Determine the hardware interrupt line.
		OEM_ReadConfigByte(0, CurSlot, 0, INTERRUPT_PIN, &cval);
		pPciDev->InterruptPin = cval;

		if(cval == 1) {
			// All PCI devices share the same PCI interrupt.
			// Logical interrupts are unique and depend on the slot which the device occupies.
			OEM_WriteConfigByte(0, CurSlot, 0, INTERRUPT_LINE, CurInt);
			pPciDev->InterruptLine = CurInt;

			// Logical Interrupt Assigned to a device is 0 if the device does not request for 
			// an interrupt. Else it is pci interrupt of slot 0 + current slot number.
			pPciDev->LogInterrupt = SYSINTR_PCI_SLOT0 + CurSlot; 

			// for Wince 2.0, the Ne2000 driver always registers SYSINTR_NETWORK
			// instead of registring for the interrupt which has been assigned
			// by the pci driver to it. This problem has been removed in
			// Wince 2.1. 
			// For Wince 2.0, a fix has been made. The network card should
			// always be placed in the lower most slot. For that slot, the
			// interrupt id returned by PCI is SYSINTR_NETWORK.
			// For Wince 2.1 this restriction is not present and you can place
			// the ne2000 card in any slot.

#ifndef M1_WINCE210
			// For the card in lower slot, always return SYSINTR_NETWORK as
			// the logical interrupt. SYSINTR_PCI_SLOT2 is defined as SYSINTR_NETWORK
			// for Wince 2.0
			if(CurSlot == 2) {
				pPciDev->LogInterrupt = SYSINTR_PCI_SLOT2;
			}
#endif

			DEBUGMSG(LEVEL5, (TEXT("INT PIN = %d. Allocating physical interrupt %d, logical interrupt %d\r\n"), cval, CurInt, pPciDev->LogInterrupt));
		}

		// Write the LATENCY_TIMER with the default value.
		pPciDev->LatencyTimer = DEFAULT_LATENCY;
		OEM_WriteConfigByte(0, CurSlot, 0, LATENCY_TIMER, pPciDev->LatencyTimer);

		CommandReg = 0;
		// Program the Base Address register.
		for(i=0x10; i < 0x24; i+=4) {
			int RegNum = (i - 0x10) / 4;
			OEM_WriteConfigDword(0, CurSlot, 0, i, 0xFFFFFFFF);
			OEM_ReadConfigDword(0, CurSlot, 0, i, &uval);
			// WRITE_REGISTER_ULONG(ASLONG(PciIoReg+i), 0xffffffff);
			pPciDev->BaseAddressRegister[RegNum] = uval;
			if(uval == 0)
				continue;
			DEBUGMSG(LEVEL5, (TEXT("Base address register 0x%x read 0x%x.\r\n"), i, uval));
			if((uval & 0x1) == 1) {
				// The device needs IO space. Allocate 256 bytes.
				DEBUGMSG(LEVEL5, (TEXT("Allocating %d bytes starting at 0x%x to IO Base address reg. 0x%x\r\n"), MAX_IO_ALLOCATE, CurIoBase, i));
				OEM_WriteConfigDword(0, CurSlot, 0, i, CurIoBase);
				// WRITE_REGISTER_ULONG(ASLONG(PciIoReg+i), CurIoBase);
				pPciDev->BaseAddressRegister[RegNum] = CurIoBase;
				CurIoBase += MAX_IO_ALLOCATE;
				CommandReg |= COMMAND_IO;
			}
			else {
				// It is requesting Memory space.
				// Find out the amount of memory asked for. Start with bit 4 and
				// find out the first bit which is 1.

				int size = 16; // 2 ** 4.

				uval >>= 4;
				while(uval != 0) {
					// DEBUGMSG(LEVEL5, (TEXT("uval = 0x%x, size = %d\r\n"), uval, size));
					if ((uval & 0x1) == 1) 
						break;
					uval >>= 1;
					size *= 2;
				}
				if(size > MAX_MEM_REQUEST) {
					ERRORMSG(1, (TEXT("PCI: Device asked for too much memory space (%d bytes). Failing to allocate.\r\n"), size));
				}
				else {
					int AllocStart;

					CommandReg |= COMMAND_MEM;
					// If it's a display driver, allocate it starting from 0.
					if((pPciDev->BaseClassCode == PCI_CLASS_DISPLAY_CONTROLLER) && (AllocatedDisplayMemory == FALSE)) {
#ifndef RESERVE_DISPLAY_MEM
						ERRORMSG(1, (TEXT("PCI Error: This configuration does not support a display card.\r\n")));
						ERRORMSG(1, (TEXT("PCI Error: Define RESERVE_DISPLAY_MEM in the file pci.c if you want to use a display card.\r\n")));
#endif
						AllocatedDisplayMemory = TRUE;
						AllocStart = DISPLAY_MEM_BASE;
						if(size > DISPLAY_MEM_SIZE) {
							ERRORMSG(1, (TEXT("PCI Warning: Display Device is requesting for more memory(%d Bytes) than \r\nreserved by the system(%d Bytes)\r\n"), size, DISPLAY_MEM_SIZE, i));
							ERRORMSG(1, (TEXT("PCI Warning: Modify the PCI driver to allocate more memory to Display Device.\r\n")));
							// still go ahead.
							size = DISPLAY_MEM_SIZE;
						}
						DEBUGMSG(LEVEL5, (TEXT("Allocating %d bytes starting at 0x%x to Display Device Base address \r\nregister 0x%x\r\n"), size, AllocStart, i));
					}
					else {
						// Align CurMemBase to size.
						CurMemBase = ALIGN(CurMemBase, size);
						AllocStart = CurMemBase;
						DEBUGMSG(LEVEL5, (TEXT("Allocating %d bytes starting at 0x%x to Memory Base address register 0x%x\r\n"), size, AllocStart, i));
						CurMemBase += size;
					}
					OEM_WriteConfigDword(0, CurSlot, 0, i, AllocStart);
					// WRITE_REGISTER_ULONG(ASLONG(PciIoReg+i), AllocStart);
					pPciDev->BaseAddressRegister[RegNum] = AllocStart;
					pPciDev->Size[RegNum] = size;
				}
			}
		}

		// A display control uses pci io address space but does not request for any io addresses
		// thru the base register. So enable io accesses for that device here.
		// If there are any other devices which may do the same, put them here.
		if((pPciDev->BaseClassCode == PCI_CLASS_DISPLAY_CONTROLLER)) {
				CommandReg |= COMMAND_IO;
		}

DEBUGMSG(LEVEL5, (TEXT("Setting Command Register to 0x%x, status to 0x%x\r\n"), CommandReg, DEFAULT_STATUS));
		// Set the command register now.
		OEM_WriteConfigWord(0, CurSlot, 0, COMMAND_REGISTER, CommandReg);
		OEM_WriteConfigWord(0, CurSlot, 0, STATUS_REGISTER, DEFAULT_STATUS);
		// WRITE_REGISTER_USHORT(ASSHORT(PciIoReg+COMMAND_REGISTER), CommandReg);
		// WRITE_REGISTER_USHORT(ASSHORT(PciIoReg+STATUS_REGISTER), DEFAULT_STATUS);

		OEM_ReadConfigWord(0, CurSlot, 0, COMMAND_REGISTER, &pPciDev->Command);
		OEM_ReadConfigWord(0, CurSlot, 0, STATUS_REGISTER, &pPciDev->Status);
		// pPciDev->Command = READ_REGISTER_USHORT(ASSHORT(PciIoReg+COMMAND_REGISTER));
		// pPciDev->Status = READ_REGISTER_USHORT(ASSHORT(PciIoReg+STATUS_REGISTER));

  		// WRITE_REGISTER_ULONG(ASLONG(PciControlReg), SlotDisable);
	}
	// Disable PCI configuration space before coming out.
  	// WRITE_REGISTER_ULONG(ASLONG(PciControlReg), SlotDisable);
  	DEBUGMSG(LEVEL5, (TEXT("(Address of PciDevice Array = 0x%x...)\r\n"), (unsigned)PciDevice));
  	dummy();
	return TRUE;
}

/*****************************************************************************
 * Function: PciScan
 * Input:    Type: type of device you are looking for.
 *           Instance: instance of the device. eg. the first display controller
 *                     will have Instance = 0.
 * Output:   PciDeviceType *: Pointer to a structure pointing to the 
 *                            DeviceType entry of this device.
 * Eg:       to get the first instance of the display driver, call this
 *           function as follows :-
 *                PciScan(PCI_CLASS_DISPLAY, PCI_FIRST_INSTANCE)
 ****************************************************************************/
struct PciDeviceType *PciScan(unsigned Type, unsigned Instance)
{
	unsigned curInstance = PCI_FIRST_INSTANCE;
	unsigned Slot;
	unsigned Found = FALSE;

  	DEBUGMSG(LEVEL1, (TEXT("PCI: PciScan called\r\n")));
	// Check whether the Pci bus has been enumerated. If not enumerate it now.
	if(!PciEnumerated) {
		PciEnumerated = TRUE;
		PciEnumerate();
	}

	// Now look for specified Instance of the specified Type of device.
	// eg. : the first Instance of Display controller.
	for(Slot = 0; Slot < NO_PCI_SLOTS; Slot ++) {
  	DEBUGMSG(LEVEL1, (TEXT("PCI: 1PciScan called. DevId = 0x%x\r\n"), PciDevice[Slot].DeviceID));
		if(PciDevice[Slot].BaseClassCode == Type) {
			if(curInstance == Instance) {
				Found = TRUE;
				break;
			}
			else {
				curInstance ++;
			}
		}
	}

	// Check whether you found it or not.
	if(Found) {
  		DEBUGMSG(LEVEL1, (TEXT("PCI: Found Instance %d of Pci Class 0x%x in Slot %d\r\n"), curInstance, Type, Slot));
		return &PciDevice[Slot];
	}
	else {
  		DEBUGMSG(LEVEL1, (TEXT("PCI: Unable to locate Instance %d of Pci Class 0x%x in all Slots.\r\n"), Instance, Type));
		return (struct PciDeviceType *)NULL;
	}
}

#if ((!defined CMON) && (!defined SDBTESTS))
//
// Standard Windows DLL entrypoint.
//
BOOL WINAPI
DllEntry(
  HANDLE hDLL,
  DWORD dwReason,
  LPVOID lpReserved
)
{

    switch (dwReason) {
    case DLL_PROCESS_ATTACH:
		if(pci_called == FALSE) {
			pci_called = TRUE;
        	DEBUGREGISTER(hDLL);
        	DEBUGMSG(LEVEL1, (TEXT("PCI: DLL_PROCESS_ATTACH\r\n")));
			PciEnumerate();
		}
		else {
        	DEBUGMSG(LEVEL1, (TEXT("PCI: DLL_PROCESS_ATTACH message received again...\r\n")));
		}
        break;
    case DLL_PROCESS_DETACH:
        DEBUGMSG(LEVEL1, (TEXT("PCI: DLL_PROCESS_DETACH\r\n")));
        break;
	default:
		// Just ignore it.
        // RETAILMSG(LEVEL1, (TEXT("PCI: called with invalid dwReason=%d\r\n"), dwReason));
        break;
    }
    return TRUE;
}

#endif

⌨️ 快捷键说明

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