pci_enum.c

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

C
796
字号

struct PciDeviceType PciDevice[NO_PCI_SLOTS] = { 0 };

// Has the PciBus already been enumerated.
int PciEnumerated = FALSE;

int pci_called=FALSE;	// Whether an attempt to load the driver was made earlier.

#pragma data_seg()
/*********** END OF SHARED DATA SECTION VALUES *******************************/

/*****************************************************************************
 * The following should not be shared data.
 ****************************************************************************/

// This structure will contain the Mapped PCI Io/Mem/Control Addresses.
// If any of the members is 0, it means that the particular memory
// range is not mapped.
struct PciBaseAddresses_Type PciBaseAddresses;

int RegistersMapped = FALSE;	// Have the registers been mapped.

// Mapped addresses of the Pci Registers.
unsigned char *PciIoReg, *PciControlReg, *PciMemReg; 
/****************************************************************************/

#if ((!defined CMON) && (!defined SDBTESTS))
#ifdef DEBUG

//
// These defines must match the ZONE_* defines in NE2000SW.H
//
#define DBG_ERROR      1
#define DBG_WARN       2
#define DBG_FUNCTION   4
#define DBG_INIT       8

DBGPARAM dpCurSettings = {
    TEXT("PCI"), {
    TEXT("Errors"),TEXT("Warnings"),TEXT("Functions"),TEXT("Init"),
    TEXT("Undefined"),TEXT("Undefined"),TEXT("Undefined"),TEXT("Undefined"),
    TEXT("Undefined"),TEXT("Undefined"),TEXT("Undefined"),TEXT("Undefined"),
    TEXT("Undefined"),TEXT("Undefined"),TEXT("Undefined"),TEXT("Undefined") },
    0xffff
};
#endif  // DEBUG
#endif

#ifndef SDBTESTS
#ifdef TEST_PCI
void dummy() { }
#else
#define dummy()
#endif
#endif SDBTESTS

/* Function prototypes. */
int OEM_InitPCIHostBridge( void ); 
void OEM_ReadConfigByte( DWORD dwBusNo, DWORD dwDevNo, DWORD dwFuncNo, DWORD dwOffset, BYTE *pbData );
void OEM_WriteConfigByte( DWORD dwBusNo, DWORD dwDevNo, DWORD dwFuncNo, DWORD dwOffset, BYTE bData );
void OEM_ReadConfigWord( DWORD dwBusNo, DWORD dwDevNo, DWORD dwFuncNo, DWORD dwOffset, WORD *pwData );
void OEM_WriteConfigWord( DWORD dwBusNo, DWORD dwDevNo, DWORD dwFuncNo, DWORD dwOffset, WORD wData );
void OEM_ReadConfigDword( DWORD dwBusNo, DWORD dwDevNo, DWORD dwFuncNo, DWORD dwOffset, DWORD *pdwData );
void OEM_WriteConfigDword( DWORD dwBusNo, DWORD dwDevNo, DWORD dwFuncNo, DWORD dwOffset, DWORD dwData );

/******************************************************************************
 * Notes:
 *
 * 1. Some of the PCI cards do not implement the IO Base Addresses registers
 *    properly. The IO Base Address register when written with 0xff... and
 *    read back should indicate the amount of IO space it needs. But sometimes
 *    they do not. So i'm allocating 256 bytes to each of the IO device.
 *    This IS a terrible waste on the IO space, but since the number of devices
 *    for M1 is limited, one can live with it.

 * 2. Some PCI card request an exhorbitant amount of Memory Space. One example
 *    is the S3 Trio64V+ card which i'm working on. The damned thing requests
 *    64 Mb of Memory Space. Well it won't get it all. I restrict the max.
 *    allocated size to 16 Mb. This is because if i allocate the whole range
 *    of memory to this card, the address range allocated to other cards
 *    will be more than 0xb9000000 can handle. In that case for the subsequent
 *    memory addresses, i'll have to do a very dirty thing. For every memory
 *    access, first write to the Control register, and then write to the memory
 *    register.

 * 3. I have reserved the first 4 Mb of Memory space for the first display card.
 *    The reason for doing this is that the existing drivers for Display card
 *    do not inquire the start of the display memory from the registry. So
 *    instead of designing my own mechanism to communicate the start address to
 *    the display driver, i just reserve the first 4 Mb for it. There's nothing
 *    wrong in this approach except that those 4 Mb go waste in case there is
 *    no display driver, or if the display device needs more than 4 Mb. In the
 *    latter case the system would still work if there are not PCI memory cards
 *    installed. Another approach would have been to scan for all PCI display
 *    devices and allocate them memory first and then scan for other devices.
 *    There are not too many merits in favor of this approach, so i'm not using
 *    it.

 * 4. Presently it maps only DISP_MEM_SIZE of Pci Memory space into it's
      virtual address space.
 *****************************************************************************/


#if 0
/*****************************************************************************
 * Map registers needs to be called once in the address space of each of the 
 * calling processes.
 * It will map the physical register to the virtual address space for CE.
 ****************************************************************************/
int MapRegisters()
{
	// If the registers have already been mapped, just return.
	if(RegistersMapped) {
		return TRUE;
	}
	RegistersMapped = TRUE;

#if ((defined CMON) || (defined SDBTESTS))
	PciIoReg = (unsigned char *)PHYSICAL_PCI_IO;
	PciMemReg = (unsigned char *)PHYSICAL_PCI_MEM;
	PciControlReg = (unsigned char *)PHYSICAL_PCI_CONTROL;
	// Fill in the members of PciBaseAddresses.
	PciBaseAddresses.PciIoReg = (ULONG)PciIoReg;
	PciBaseAddresses.PciMemReg = (ULONG)PciMemReg;
	PciBaseAddresses.PciControlReg = (ULONG)PciControlReg;
	return TRUE;
#else
  	DEBUGMSG(LEVEL1, (TEXT("PCI: MapRegisters called\r\n")));

  	//  Map I/O board base address
  	PciControlReg = VirtualAlloc(0, 0x100, MEM_RESERVE, PAGE_NOACCESS);
  	if ( PciControlReg == NULL ) {
    	ERRORMSG(1,	(TEXT("PCI: MapRegisters: VirtualAlloc 1 failed!\r\n")));
		goto Error1;
  	}
  	if ( !VirtualCopy((PVOID)PciControlReg, (PVOID)PHYSICAL_PCI_CONTROL, 0x100, PAGE_READWRITE|PAGE_NOCACHE) ) {
    	ERRORMSG(1,	(TEXT("PCI: MapRegisters: VirtualCopy 1 failed!\r\n")));
    	goto Error1;
  	}


	// PCI Memory is not allocated any more in the pci driver. Any driver which
	// needs pci memory must map it on it's own. This helps in saving virtual
	// address space in the device drivers that don't need it.
	// ALLOCATE_PCI_MEM would not be defined in the final version.
#ifdef PCI_DRIVER_ALLOCATES_PCI_MEM
	// Only DISPLAY_MEM_SIZE bytes are mapped at present. This may be changed later.
  	PciMemReg = VirtualAlloc(0, PCI_MEM_SIZE, MEM_RESERVE, PAGE_NOACCESS);
  	if ( PciMemReg == NULL ) {
    	ERRORMSG(1,	(TEXT("PCI: MapRegisters: VirtualAlloc 2 failed!\r\n")));
		goto Error1;
  	}
  	if ( !VirtualCopy((PVOID)PciMemReg, (PVOID)PHYSICAL_PCI_MEM, PCI_MEM_SIZE, PAGE_READWRITE|PAGE_NOCACHE) ) {
    	ERRORMSG(1,	(TEXT("PCI: MapRegisters: VirtualCopy 2 failed!\r\n")));
    	goto Error1;
  	}
#else
	PciMemReg = 0;
#endif

  	PciIoReg = VirtualAlloc(0, MAX_IO_ADDRESS, MEM_RESERVE, PAGE_NOACCESS);
  	if ( PciIoReg == NULL ) {
    	ERRORMSG(1,	(TEXT("PCI: MapRegisters: VirtualAlloc 3 failed!\r\n")));
		goto Error1;
  	}
  	if ( !VirtualCopy((PVOID)PciIoReg, (PVOID)PHYSICAL_PCI_IO, MAX_IO_ADDRESS, PAGE_READWRITE|PAGE_NOCACHE) ) {
    	ERRORMSG(1,	(TEXT("PCI: MapRegisters: VirtualCopy 3 failed!\r\n")));
    	goto Error1;
  	}
  	DEBUGMSG(LEVEL1, (TEXT("PCI: MapRegisters returning PciControlReg=0x%x, PciMemReg=0x%x, PciIoReg=0x%x\r\n"), PciControlReg, PciMemReg, PciIoReg));
  	DEBUGMSG(LEVEL1, (TEXT("PCI: MapRegisters returning TRUE\r\n")));
	
	// Fill in the members of PciBaseAddresses.
	PciBaseAddresses.PciIoReg = (ULONG)PciIoReg;
	PciBaseAddresses.PciMemReg = (ULONG)PciMemReg;
	PciBaseAddresses.PciControlReg = (ULONG)PciControlReg;
  	return TRUE;

Error1:
    if ( PciControlReg )
      	VirtualFree((PVOID)PciControlReg, 0, MEM_RELEASE);
    if ( PciMemReg )
      	VirtualFree((PVOID)PciMemReg, 0, MEM_RELEASE);
    if ( PciIoReg )
      	VirtualFree((PVOID)PciIoReg, 0, MEM_RELEASE);
    PciControlReg = 0;
    PciMemReg = 0;
    PciIoReg = 0;

	// Fill in the members of PciBaseAddresses.
	PciBaseAddresses.PciIoReg = (ULONG)PciIoReg;
	PciBaseAddresses.PciMemReg = (ULONG)PciMemReg;
	PciBaseAddresses.PciControlReg = (ULONG)PciControlReg;

  	DEBUGMSG(LEVEL1, (TEXT("PCI: MapRegisters returning FALSE\r\n")));
    return FALSE;
#endif
}
#endif 0

	
/***************************************************************************
 * Function: PciGetMappedBaseAddresses
 * Input   : None
 * Output  : pointer to a Structure of type PciBaseAddresses_Type which 
 *           contains the Mapped Pci Io/Mem/Control Addresses.
 * Synopsis: If i call Virtual Copy in the Ne2000 driver, it fails. So i need
 *           some mechanism to pass on the mapped base addresses to the driver.
 *           This is one of the approaches that can be used. The benefit of
 *           this approach is that once the addresses are mapped in this
 *           Dll, they can be used by any of the other dlls which use services
 *           from it. So you don't need to call VirtualCopy in the Dlls which
 *           sit on this Dll.
 * Note:     I'm returning the structure itself and not a pointer to it.
 ***************************************************************************/
struct PciBaseAddresses_Type *PciGetMappedBaseAddresses()
{
	MapRegisters();
	return &PciBaseAddresses;
}

unsigned PhysicalPciIoBase,
		 PhysicalPciMemBase;

unsigned PciEnumerate(void)
{
  	// short forms for the registers.
  	unsigned char cval;
  	unsigned short sval;
	unsigned short CommandReg;
  	unsigned uval, i;
  	BOOL AllocatedDisplayMemory=FALSE;  // Have i allocated display memory.
	struct PciDeviceType *pPciDev;
  	unsigned CurIoBase = IOBASE,
           CurMemBase = MEMBASE,
		   CurInt = INTBASE,	// All PCI devices share this interrupt on current hardware.
		   CurSlot = 0,
		   SlotDisable = 0;

#ifdef CMON
  // Set FRQCR
  //	WRITE_REGISTER_USHORT(WCR2, 0x8359);
#endif

	OEM_InitPCIHostBridge(); 
	// Map the Pci Registers first.
	// MapRegisters();

	for(CurSlot = 0; CurSlot < NO_PCI_SLOTS; CurSlot ++) {
		pPciDev = &PciDevice[CurSlot];
  		DEBUGMSG(LEVEL5, (TEXT("PCI Enumerator scanning slot %d..."), CurSlot));
  		// Perform full PCI enumeration on card in slot CurSlot.
  		// WRITE_REGISTER_ULONG(ASLONG(PciControlReg), SlotEnable[CurSlot]);

		// Step 1: VENDOR ID CHECK
		OEM_ReadConfigWord(0, CurSlot, 0, 0, &sval);
  		pPciDev->VendorID = sval;
  		DEBUGMSG(LEVEL5, (TEXT("Vendor ID from slot %d = 0x%x\r\n"), CurSlot, sval));

  		if((sval == 0xffff) || (sval == 0x0))
  			continue;

		// Assign Physical address values to the members of the pPciDev structure.
		pPciDev ->PhysicalPciIoReg      = PhysicalPciIoBase;
		pPciDev ->PhysicalPciMemReg     = PhysicalPciMemBase;
		// pPciDev ->PhysicalPciControlReg = PHYSICAL_PCI_CONTROL;

⌨️ 快捷键说明

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