//////////////////////////////////////////////////////////////////
//Program Name:PCIV.c
//Author:Clark Xie
//date:
//Description:Print configration data
////////////////////////////////////////////////////////////////////
//History:
// 31/10/2007 16:00	Clark Xie V0.0.1	complete cmd of 'L' and 'V' 
////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <conio.h>


typedef unsigned char	BYTE;
typedef unsigned int	WORD;
typedef unsigned long	DWORD;


/**/
//#define PDI_BUS_SHIFT   8
//#define PDI_BUS_SIZE    8
#define PCI_BUS_MAX     0xFF
//#define PDI_BUS_MASK    0xFF00

//#define PDI_DEVICE_SHIFT   3
//#define PDI_DEVICE_SIZE    5
#define PCI_DEV_MAX     0x1F
//#define PDI_DEVICE_MASK    0x00F8

//#define PDI_FUNCTION_SHIFT   0
//#define PDI_FUNCTION_SIZE    3
#define PCI_FUN_MAX     0x7
//#define PDI_FUNCTION_MASK    0x0007

//#define MK_PDI(bus,dev,func)	(WORD)((bus&PDI_BUS_MAX)<<PDI_BUS_SHIFT | (dev&PDI_DEVICE_MAX)<<PDI_DEVICE_SHIFT | (func&PDI_FUNCTION_MAX) )


/* PCI Configration Space Port*/
#define PCI_CONFIG_ADDRESS      0xCF8
#define PCI_CONFIG_DATA         0xCFC


/* Get PCI_CONFIG_ADDRESS */
//#define MK_ADDRESS(bus,dev,func)	(DWORD)(0x80000000L | (DWORD)MK_PDI(bus,dev,func)<<8)


DWORD MakeAddress(DWORD bus , DWORD dev , DWORD fun)
{
	DWORD bus_t,dev_t,fun_t,bdf;
	bus_t = (bus)<<16;
	dev_t = (dev)<<11;
	fun_t = (fun)<<8;
	bdf   = (0x80000000L|bus_t|dev_t|fun_t);
	return bdf;

}

void PrintMenu()
{
	printf("PCI Viewer V0.0.1\n");
	printf("Type ? to get more information.\n");
	printf("-");

}
void PrintSelect()
{
	printf("L -- To List all valid BUS\n");
	printf("V -- To View Registers via BUS# DEV# FUN#\n");
	printf("Q -- To Quit.");
	printf("-");
}
/* Read to a 32bits Port*/
DWORD	GetData(int	portid)
{
	DWORD	dwRet;
	asm mov dx, portid;
	asm lea bx, dwRet;
	__emit__(
		0x66,0x50,	// push EAX
		0x66,0xED,	// in EAX,DX
		0x66,0x89,0x07,	// mov [BX],EAX
		0x66,0x58);	// pop EAX
	return dwRet;
}

/* Write to a  32bits Port*/
void	WriteData(int	portid, DWORD	dwVal)
{
	asm mov dx, portid;
	asm lea bx, dwVal;
	__emit__(
		0x66,0x50,	// push EAX
		0x66,0x8B,0x07,	// mov EAX,[BX]
		0x66,0xEF,	// out DX,EAX
		0x66,0x58);	// pop EAX
	return;
}
void ListAllBus()
{
	char strMsgHead[]="Bus#\tDev#\tFun#\tVendor\tDevice\tRevi\tClass Code\n";
	DWORD Read_Value,Address_Value,bus,dev,fun;
   //
	printf("%s",strMsgHead);



	for(bus=0x0;bus<PCI_BUS_MAX;bus++)
		for(dev=0x0;dev<PCI_DEV_MAX;dev++)
			for(fun=0x0;fun<PCI_FUN_MAX;fun++)
			{

			Address_Value=MakeAddress(bus,dev,fun);
			WriteData(PCI_CONFIG_ADDRESS,Address_Value);
			Read_Value = GetData(PCI_CONFIG_DATA);
				if((WORD)Read_Value != 0xFFFF)
				{
				printf("%2.2X\t%2.2X\t%2.2X\t",bus,dev,fun);
				// Vendor id/Device id
				printf("%4.4X\t%4.4X\t",(WORD)Read_Value,Read_Value>>16);
				//Revision id & Class Code
				WriteData(PCI_CONFIG_ADDRESS,Address_Value | 0x08);
				Read_Value = GetData(PCI_CONFIG_DATA);
				//	Read_Value_Bak = Read_Value;
				printf("%2.2X\t%6.6lX\n",(BYTE)Read_Value,Read_Value>>8);
				//Revision id
				//WriteData(PCI_CONFIG_ADDRESS,Address_Value | );
				}
			}
}

void PrintDWORD(DWORD data)
{
	printf("%2.2X %2.2X %2.2X %2.2X ",(BYTE) data,(BYTE) (data>>8),(BYTE) (data>>16),(BYTE) (data>>24));
	//printf("%4.4X\t%4.4X\t",(WORD)data,data>>16);
}

void ViewRegister()
{
	WORD reg;
	DWORD bus,dev,fun,Address_Value,Read_Value;
	printf("\nInput the BUS#:");
	scanf("%x",&bus);
	printf("debug:%2.2X\n",bus);
	printf("\nInput the DEV#:");
	scanf("%x",&dev);
	printf("debug:%2.2X\n",dev);
	printf("\nInput the FUN#:");
	scanf("%x",&fun);
	printf("debug:%2.2X\n",fun);
	Address_Value = MakeAddress(bus,dev,fun);
	WriteData(PCI_CONFIG_ADDRESS,Address_Value);
	if((WORD)Read_Value != 0xFFFF)
	{
		for(reg=0;reg<0x0FF;reg=reg+0x04)
		{
			//Address_Value = MakeAddress(bus,dev,fun);
			WriteData(PCI_CONFIG_ADDRESS,Address_Value | (BYTE)reg);
			//printf("Debug:%8.8X\n",Address_Value);
			Read_Value =  GetData(PCI_CONFIG_DATA);
			//if((WORD)Read_Value != 0xFFFF)
			//{
			//printf("%X\t",reg);
				PrintDWORD(Read_Value);
				if( ( ((BYTE)reg) &0x0F) == 0x0C)
				printf("\n");
			//}
		}
	}

}

void WrongKey()
{
	printf("Something Wrong with your input.Try again.\n");
}
//DWORD MakeAddress();
//DWORD Read
int main()
{
	//DWORD Address_Value,Read_Value,Read_Value_Bak;
	//BYTE bus,dev,fun;
	int flag = 1;
	char key;
	clrscr();
	//PrintMenu();

	while(flag)
	{
	PrintMenu();
	key = getchar();
		switch(key)
		{
		case 'L':
		case 'l':ListAllBus();break;
		case 'V':
		case 'v':ViewRegister();break;
		case 'q':
		case 'Q':flag = 0;break;
		case '?':PrintSelect();break;
		default:WrongKey();
		break;
		}
	}


	//getche();
	return 0;
}