#ifndef _PCI_H_
#define _PCI_H_

/*
    PCI设备有三个空间——内存地址空间、IO地址空间和配置空间。
PCI不是占用固定的内存地址空间或I/O地址空间，而是可以由操作系
统决定其映射的基址。

一、配置空间中最重要的有：

    1：Vendor ID：厂商ID。知名的设备厂商的ID。FFFFh是一个非法厂商ID，
可它来判断PCI设备是否存在。

    2：Device ID：设备ID。某厂商生产的设备的ID。操作系统就是凭着 
Vendor ID和Device ID 找到对应驱动程序的。

    3：Class Code：类代码。共三字节，分别是类代码、子类代码、编程接口。
类代码不仅用于区分设备类型，还是编程接口的规范，这就是为什么会有通用
驱动程序。

    4：IRQ Line：IRQ编号。PC机以前是靠两片8259芯片来管理16个硬件中断。
现在为了支持对称多处理器，有了APIC（高级可编程中断控制器），它支持管
理24个中断。

    5：IRQ Pin：中断引脚。PCI有4个中断引脚，该寄存器表明该设备连接的
是哪个引脚。

 二、访问配置空间
	1：0CF8H: CONFIG_ADDRESS。PCI配置空间地址端口。
	2：0CFCH: CONFIG_DATA。PCI配置空间数据端口。

	CONFIG_ADDRESS寄存器格式：
		1：31　  位：Enabled位。
		2：23:16 位：总线编号。
		3：15:11 位：设备编号。
		4：10: 8 位：功能编号。
		5：7: 2  位：配置空间寄存器编号。
		6：1: 0  位：恒为“00”。
	
	我们可以使用__emit__在程序中插入32位机器码。（注意66h是32位指令前缀）：
		1：读32位端口 
			DWORD   inpd(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;
			}
		2：写32位端口 
			void    outpd(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;
			}
 

*/

/*
DW |     Byte3    |     Byte2    |     Byte1    |     Byte0    |  Addr
---+-----------------------------------------------------------+-----
0  | 　　　　Device ID 　　  　　| 　　　　Vendor ID 　　　　  |　00
---+-----------------------------------------------------------+-----
1  | 　　　　　Status　　　　  　| 　　　　 Command　　　　    |　04
---+-----------------------------------------------------------+-----
2  |  Class Base  |  Sub Class   | Interface　　|Revision ID　 |　08
---+-----------------------------------------------------------+-----
3  | 　　BIST　　 | Header Type  | Latency Timer| Cache Line   |　0C
---+-----------------------------------------------------------+-----
4  | 　　　　　　　　　　Base Address 0　　　　　　　　　　　  |　10
---+-----------------------------------------------------------+-----
5  | 　　　　　　　　　　Base Address 1　　　　　　　　　　 　 |　14
---+-----------------------------------------------------------+-----
6  | 　　　　　　　　　　Base Address 2　　　　　　　　　　　  |　18
---+-----------------------------------------------------------+-----
7  | 　　　　　　　　　　Base Address 3　　　　　　　　　　　  |　1C
---+-----------------------------------------------------------+-----
8  | 　　　　　　　　　　Base Address 4　　　　　　　　　　　  |　20
---+-----------------------------------------------------------+-----
9  | 　　　　　　　　　　Base Address 5　　　　　　　　　　　  |　24
---+-----------------------------------------------------------+-----
10 | 　　　　　　　　　CardBus CIS pointer　　　　　　　　　   |　28
---+-----------------------------------------------------------+-----
11 |　　Subsystem Device ID　　  | 　　Subsystem Vendor ID　　 |　2C
---+-----------------------------------------------------------+-----
12 | 　　　　　　　Expansion ROM Base Address　　　　　　　    |　30
---+-----------------------------------------------------------+-----
13 | 　　　　　　　Reserved(Capability List)　　　　　　　 　  |　34
---+-----------------------------------------------------------+-----
14 | 　　　　　　　　　　　Reserved　　　　　　　　　　　　    |　38
---+-----------------------------------------------------------+-----
15 | 　Max_Lat　  | 　Min_Gnt　  | 　IRQ Pin　  | 　IRQ Line　 |　3C
--------------------------------------------------------------------
*/

//PCI BIOS的中断号是01Ah，AH为0B1H，AL为功能号。其功能列表为：
//01h: INSTALLATION CHECK
//02h: FIND PCI DEVICE
//03h: FIND PCI CLASS CODE
//06h: PCI BUS-SPECIFIC OPERATIONS
//08h: READ CONFIGURATION BYTE
//09h: READ CONFIGURATION WORD
//0Ah: READ CONFIGURATION DWORD
//0Bh: WRITE CONFIGURATION BYTE
//0Ch: WRITE CONFIGURATION WORD
//0Dh: WRITE CONFIGURATION DWORD
//0Eh: GET IRQ ROUTING INFORMATION
//0Fh: SET PCI IRQ
//81h: INSTALLATION CHECK (32-bit)
//82h: FIND PCI DEVICE (32-bit)
//83h: FIND PCI CLASS CODE (32-bit)
//86h: PCI BUS-SPECIFIC OPERATIONS (32-bit)
//88h: READ CONFIGURATION BYTE (32-bit)
//89h: READ CONFIGURATION WORD (32-bit)
//8Ah: READ CONFIGURATION DWORD (32-bit)
//8Bh: WRITE CONFIGURATION BYTE (32-bit)
//8Ch: WRITE CONFIGURATION WORD (32-bit)
//8Dh: WRITE CONFIGURATION DWORD (32-bit)
//8Eh: GET IRQ ROUTING INFORMATION (32-bit)
//8Fh: SET PCI IRQ (32-bit)

//Base Class
//00h--Device was build before class code definitons were finalized
//01h--Mass storage controller
//02h--Network controller
//03h--Display Controller
//04h--Multimedia device
//05h--Memory controller
//06h--bridge device
//07h--simple communication controllers
//08h--base system peripherals
//09h--input devices
//0ah--docking stations
//0bh--processors
//0ch--serial bus controllers
//0dh--wireless controller
//0eh--intelligent i/o controllers
//0fh--satellite communication controllers
//10h--Encryption /decryption controllers
//11h--data acquisition and signal processing controllers
//ffh--device does not fit in any defined classes


//PCI配置空间寄存器
#define PCI_CONFIG_ADDRESS    0xCF8
#define PCI_CONFIG_DATA       0xCFC

//总线号
#define PCI_MAX_BUS        256
//设备号
#define PCI_MAX_DEVICE      32
//功能号
#define PCI_MAX_FUNCTION     8

//PCI设备索引。bus-dev-func 共16位
#define MK_PDI(bus,dev,func) \
	((WORD)(WORD)(((bus & 0xFFu) << 8) | \
	((dev & 0x1Fu) << 3) | \
	((func & 0x7u) << 0)))



//填充PCI_CONFIG_ADDRESS
//    PCI配置空间对应于一个PCI逻辑设备，所以要访问一个配置空间的某个寄存器，
//必须要指定：PCI总线号、PCI设备号、PCI设备功能号和寄存器号。配置地址寄存器
//的格式如下：
//B31---------使能位		B30 ~ B24---保留
//B23 ~ B16---总线号		B15 ~ B11---设备号
//B10 ~ B8----功能号		B7  ~ B2----寄存器号
//B1----------保留			B0----------保留
// 填充PCI_CONFIG_ADDRESS
#define MK_PCICFGADDR(bus,dev,func) (DWORD)(0x80000000L | (DWORD)MK_PDI(bus,dev,func)<<8)

#define MK_PCICFGADDR2(bus, dev, func, reg) \
	((DWORD)(0x80000000L | \
	((DWORD)MK_PDI(bus,dev,func) << 8)) | \
	((reg & 0x3F) << 2))

// 读32位端口
DWORD inpd(int portid);
// 写32位端口
void outpd(int portid, DWORD dwVal);
BOOL IsExistPCIDevice(int nBaseClass, int nSubClass, int nInterface);


#endif


