http://hi.baidu.com/litomboy/blog/item/9b04387330baca0a8601b00b.html
编程思路:遍历PCI 设备,根据设备的ClassCode 找到USB设备,根据PCI空间定义找到USB设备的MEM_BASE,根据MEM_BASE 找到各个port
的接口状态,首先说明下HR平台下port口的状态跟SPEC不同,是根据RW观察出来的,代码如下:
/*
File: usbport.c
Name: 访问CF8h、CFCh端口来枚举PCI 中的USB 设备
Author: James lee
Blog: http://hi.baidu.com/litomboy
Version: V1.0
Updata: 2011-04-19
*/
#include <dos.h>
#include <stdio.h>
#include <conio.h>
typedef unsigned char BYTE;
typedef unsigned int WORD;
typedef unsigned long DWORD;
/* PCI设备索引。bus/dev/func 共16位,为了方便处理可放在一个WORD中 */
#define PDI_BUS_SHIFT 8
#define PDI_BUS_SIZE 8
#define PDI_BUS_MAX 0xFF
#define PDI_BUS_MASK 0xFF00
#define PDI_DEVICE_SHIFT 3
#define PDI_DEVICE_SIZE 5
#define PDI_DEVICE_MAX 0x1F
#define PDI_DEVICE_MASK 0x00F8
#define PDI_FUNCTION_SHIFT 0
#define PDI_FUNCTION_SIZE 3
#define PDI_FUNCTION_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配置空间寄存器 */
#define PCI_CONFIG_ADDRESS 0xCF8
#define PCI_CONFIG_DATA 0xCFC
/* 填充PCI_CONFIG_ADDRESS */
#define MK_PCICFGADDR(bus,dev,func) (DWORD)(0x80000000L | (DWORD)MK_PDI(bus,dev,func)<<8)
#define KeyWait() {while(inportb(0x64)&2);}
unsigned long GDT_Table[]=
{
0,0, //NULL - 00H
0x0000FFFF,0x00CF9A00, //Code32 - 08H Base=0 Limit=4G-1 Size=4G
0x0000FFFF,0x00CF9200 //Data32 - 10H Base=0 Limit=4G-1 Size=4G
};
unsigned char OldIDT[6]={0}; //Save The IDTR before Enter Protect Mode.
unsigned char pdescr_tmp[6]={0}; //NULL The IDTR,IDTR's Limit=0 will
//disable all Interrupts,include NMI.
void A20Enable(void)
{
KeyWait();
outportb(0x64,0xD1);
KeyWait();
outportb(0x60,0xDF); //Enable A20 with 8042.
KeyWait();
outportb(0x64,0xFF);
KeyWait();
}
void LoadFSLimit4G(void)
{
A20Enable(); //Enable A20
//**************************************
//* Disable ints & Null IDT *
//**************************************
asm {
CLI //Disable inerrupts
SIDT OldIDT //Save OLD IDTR
LIDT pdescr_tmp //Set up empty IDT.Disable any interrupts,
} //Include NMI.
//***************************************
//* Load GDTR *
//***************************************
asm { //The right Code is Real,But BC++'s Linker NOT Work with 32-bits Code.
db 0x66 //32 bit Operation Prefix in 16 Bit DOS.
MOV CX,DS //MOV ECX,DS
db 0x66 //Get Data segment physical Address
SHL CX,4 //SHL ECX,4
MOV word ptr pdescr_tmp[0],(3*8-1) //MOV word ptr pdescr_tmp[0],(3*8-1)
db 0x66
XOR AX,AX //XOR EAX,EAX
MOV AX,offset GDT_Table //MOV AX,offset GDT_Table
db 0x66
ADD AX,CX //ADD EAX,ECX
MOV word ptr pdescr_tmp[2],AX //GDTR Base high16 bits
db 0x66
SHR AX,16 //SHR EAX,16
MOV word ptr pdescr_tmp[4],AX //GDTR Base high16 bits
LGDT pdescr_tmp //Load GDTR
}
//**************************************
//* Enter 32 bit Flat Protected Mode *
//**************************************
// Set CR0 Bit-0 to 1 Enter 32 Bit Protection
//Mode,And NOT Clear machine perform cache,It Meaning
//the after Code HAD Ready To RUN in 32 Bit Flat Mode,
//Then Load Flat Selector to FS and Description into it's
//Shadow register,After that,ShutDown Protection Mode
//And ReEnter Real Mode immediately.
// The FS holds Base=0 Size=4G Description and
//it can Work in Real Mode as same as Pretect Mode,
//untill FS be reloaded.
// In that time All the other Segment Registers are
//Not Changed,except FS.(They are ERROR Value holded in CPU).
asm {
MOV DX,0x10 //The Data32 Selector
db 0x66,0x0F,0x20,0xC0 //MOV EAX,CR0
db 0x66
MOV BX,AX //MOV EBX,EAX
OR AX,1
db 0x66,0x0F,0x22,0xC0 //MOV CR0,EAX //Set Protection enable bit
JMP Flush
} //Clear machine perform cache.
Flush: //Now In Flat Mode,But The CS is Real Mode Value.
asm { //And it's attrib is 16-Bit Code Segment.
db 0x66
MOV AX,BX //MOV EAX,EBX
db 0x8E,0xE2 //MOV FS,DX //Load FS now
db 0x66,0x0F,0x22,0xC0 //MOV CR0,EAX //Return Real Mode.Now FS's Base=0 Size=4G
LIDT OldIDT //LIDT OldIDT //Restore IDTR
STI //STI //Enable INTR
}
}
//With FS can Access All 4G Memory Now.But if FS be reloaded in Real Mode
//It's Limit will Be Set to FFFFh(Size=64K),then Can not used it to Access
//4G bytes Memory Again,Because FS is Segment:Offset Memory type after that.
//If Use it to Access large than 64K will generate Execption 0D.
unsigned char ReadByte(unsigned long Address)
{
asm db 0x66
asm mov di,word ptr Address //MOV EDI,Address
asm db 0x67 //32 bit Address Prefix
asm db 0x64 //FS:
asm mov al,byte ptr [BX] //=MOV AL,FS:[EDI]
return _AL;
}
unsigned char WriteByte(unsigned long Address)
{
asm db 0x66
asm mov di,word ptr Address //MOV EDI,Address
asm db 0x67 //32 bit Address Prefix
asm db 0x64 //FS:
asm mov byte ptr [BX],al //=MOV FS:[EDI],AL
return _AL;
}
/* 读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;
}
/* 写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;
}
int main(void)
{
int bus, dev, func;
int i,j;
unsigned char index;
DWORD dwAddr;
DWORD dwData;
FILE* hF;
char szFile[0x10];
LoadFSLimit4G();
printf("\n");
//printf("Bus#\tDevice#\tFunc#\tVendor\tDevice\tClass\tIRQ\tIntPin\n");
/* 枚举PCI设备 */
j=0;
for(bus = 0; bus <= PDI_BUS_MAX; ++bus)
{
for(dev = 0; dev <= PDI_DEVICE_MAX; ++dev)
{
for(func = 0; func <= PDI_FUNCTION_MAX; ++func)
{
/* 计算地址 */
dwAddr = MK_PCICFGADDR(bus, dev, func);
/* 获取厂商ID */
outpd(PCI_CONFIG_ADDRESS, dwAddr);
dwData = inpd(PCI_CONFIG_DATA);
/* 判断设备是否存在。FFFFh是非法厂商ID */
if ((WORD)dwData != 0xFFFF)
{
/* Class Code USB Host Controller的Class Code是0x0c03 */
outpd(PCI_CONFIG_ADDRESS, dwAddr | 0x8);
dwData = inpd(PCI_CONFIG_DATA);
if((dwData>>16)==0x0c03)
{
if(((dwData>>8)&0xff)==0x00)
{
printf("Find UHCI USB \n");
}
if(((dwData>>8)&0xff)==0x10)
{
printf("Find OHCI USB \n");
}
if(((dwData>>8)&0xff)==0x20)
{
//printf("Find EHCI USB \n");
outpd(PCI_CONFIG_ADDRESS, dwAddr | 0x10);
dwData = inpd(PCI_CONFIG_DATA);
dwData=dwData+0XF0;
//printf("%lX\n",dwData);
for(i=0;i<=6;i++)
{
//dwData++;
//printf("%lX\n",dwData);
index=ReadByte(dwData);
dwData++;
//printf("Find %d EHCI USB:%02X \n",i+1,index);
if((index==0x18)||(index==0x10))
{
j++;
printf("Find %d EHCI USB\n",j);
}
}
//printf("%lX\n",dwData);
}
}
}
}
}
}
return 0;
}