EHCI首先是一个PCI设备,我们可以lspci一下看看。
00:1a:7 USB Controller: Intel Corporation USB2 EHCI Controller #1 (rev 03)
我们与外围硬件打交道,可以把数据用in(out)指令传递给外围硬件,还可以把数据传输到cpu和外围硬件共享的内存里面去。这些都是计算机与硬件的接口。(参见ldd3 第9章)
那么我们的程序如何与EHCI联系,交流呢?EHCI定义了三个接口空间。如图
作为一个程序员,我们关心的是如何在代码中读/写这些地方的内容。概念性的东西肯定是LDD3写的最好,我就不赘述了。
1)pci configuration space. (ldd3 第12章)
由于EHCI是一个PCI设备,这里用于系统组件枚举和PCI的电源管理。
以x86为例,读取PCI总线套路是这样的。我们要读取PCI总线上地址为add,长度为4个字节的内容。
outl(add, 0xcf8); // 先把add的out到地址为0xcf8的地方
value = inl(0xcfc); // 然后再读取0xcfc的内容
网上找到了一段程序,大家可以试验一下。
/**//*name:pci.c*/
#include<stdio.h>
#include<assert.h>
#include<sys/io.h>
#defineIO_PORTS11/*ioport<=0x3ff*/
#defineIO_PORTS22/*ioport>0x3ff&&ioport<0xffff*/
#defineIO_PERMOFF0
#defineIO_PERMON1
#defineIO_PERMON23
#defineRW_DELAY10000/*delay100000microsecondsforreadingandwritingI/Oports.*/
#ifndefBOOL
typedefunsignedcharBOOL;
#endif
#ifndefBYTE
typedefunsignedcharBYTE;
#endif
#ifndefDWORD
typedefunsignedlongDWORD;
#endif
#ifndefINT
typedefunsignedintINT;
#endif
#ifndefULONG
typedefunsignedlongULONG;
#endif
#ifndefWORD
typedefunsignedshortWORD;
#endif
/**//*
**Function:WritethevalueofthespecifiedI/Oportbygivingthelengthandthe
**startingaddress.
**Parameter:PortAddr:theportaddress
**PortVal:thevaluetoset
**size:size=1forreading1byte,2forword,4fordoublewords
**Return:1returnedifsuccess,or0returned
*/
BOOLSetPortVal(WORDPortAddr,DWORDPortVal,BYTEsize)
...{
BOOLRet=0;
INTtmpRet=0;
ULONGnumperm=1;
INTprivilege=0;
assert(PortAddr>0);
if(PortAddr<=0x3ff)
...{
tmpRet=ioperm((ULONG)PortAddr,numperm,IO_PERMON);
privilege=IO_PORTS1;
}
elseif(PortAddr>0x3ff)
...{
tmpRet=iopl(IO_PERMON2);
privilege=IO_PORTS2;
}
else
returnRet;
if(tmpRet<0)
...{
fprintf(stderr,"can'tsettheioportpermissionforsetting! ");
returnRet;
}
else
...{
switch(size)
...{
case1:/**//*writeonebytetotheport*/
outb(PortVal,PortAddr);
break;
case2:/**//*writeonewordtotheport*/
outw(PortVal,PortAddr);
break;
case4:/**//*writedoublewordstotheport*/
outl(PortVal,PortAddr);
break;
default:
Ret=0;
break;
}
usleep(RW_DELAY);
Ret=1;
}
if(privilege==IO_PORTS1)
ioperm((ULONG)PortAddr,numperm,IO_PERMOFF);
elseif(privilege==IO_PORTS2)
iopl(IO_PERMOFF);
returnRet;
}
/**//*
**Function:ReadthevalueofthespecifiedI/Oportbygivingthelenghtandthe
**startingaddress.
**Parameter:PortAddr:theportaddress
**PortVal:valuefromport
**size:size=1forreading1byte,2forword,4fordoublewords
**Return:1returnedifsuccess,or0returned.
*/
BOOLGetPortVal(WORDPortAddr,DWORD*PortVal,BYTEsize)
...{
BOOLRet=0;
inttmpRet=0;
unsignedlongnumperm=1;
intprivilege=0;
assert(PortAddr>0);
assert(PortVal!=NULL);
if(PortAddr<=0x3ff)
...{
tmpRet=ioperm((unsignedlong)PortAddr,numperm,IO_PERMON);
privilege=IO_PORTS1;
}
elseif(PortAddr>0x3ff)
...{
tmpRet=iopl(IO_PERMON2);
privilege=IO_PORTS2;
}
else
returnRet;
if(tmpRet<0)
...{
fprintf(stderr,"can'tsettheioportpermissionforreading! ");
returnRet;
}
else
...{
switch(size)
...{
case1:/**//*readonebytefromtheport*/
*PortVal=inb(PortAddr);
break;
case2:/**//*readonewordfromtheport*/
*PortVal=inw(PortAddr);
break;
case4:/**//*readdoublewordsfromtheport*/
*PortVal=inl(PortAddr);
break;
default:
Ret=0;
break;
}
usleep(RW_DELAY);
Ret=1;
}
if(privilege==IO_PORTS1)
ioperm((unsignedlong)PortAddr,numperm,IO_PERMOFF);
elseif(privilege==IO_PORTS2)
iopl(IO_PERMOFF);
returnRet;
}
intmain(intargc,char*argv[])
...{
WORDadd_port=0xcf8;
WORDdata_port=0xcfc;
DWORDaddr=0x80000000;
DWORDport_value;
BYTEsize=4;
intinput;
printf("Pleaseselecttheoptionnumberasfollow: ");
printf("1--bus0:dev:0fun:0asaddress0x80000000 ");
printf("2--bus0:dev:1fun:0asaddress0x80000800 ");
printf("3--inputyourowndefinedaddressvalue: ");
scanf("%d",&input);
switch(input)
...{
case1:
addr=0x80000000;
break;
case2:
addr=0x80000800;
break;
case3:
printf("pleaseinputthe32bitsaddressinHexformat(suchas80007800):");
scanf("%x",&addr);
break;
default:
printf("inputinvalidoptionnum,exitprogram. ");
return-1;
}
printf("Theaddris:%X ",addr);
printf("Theadd_portis:%X ",add_port);
printf("Thedata_portis:%X ",data_port);
if(SetPortVal(add_port,addr,size))
...{
if(GetPortVal(data_port,&port_value,size))
...{
printf("portvalueis:%08X ",port_value);
return0;
}
}
return-1;
}
打印出来的内容与(1)用lspci -xxx 命令输出;(2)EHCI spec 2.1章的内容对照一下。
好了,现在问题是我们怎么知道PCI总线上EHCI的地址add。lspci可以看到所有PCI设备的地址。首先,EHCI不管有没有驱动,它这个PCI设备在PCI总线枚举时就被探测到了,这时候它就被分配了地址。每个PCI 外设有一个总线号, 一个设备号, 一个功能号标识号。比如00:1a:7,00总线号,1a设备号,7功能号。这些个号组成了独一无二的ID。ID和地址的转换关系是这样的:
我们只要ID,就知道了外设的地址,然后就可以读写PCI寄存器的内容。另外可以看看
pci_read(),pci_write() //arch/i386/pci/common.c
的内容,这样会有更深的理解。
2)regster space.
这是基于内的i/o寄存器,就是i/o内存。这里包含了Capability Registers和Operational Registers。我们可以读取/proc/iomem 看看io内存的分配情况。我们可以看到ehci的地址是fe226400-fe2267ff。这段内存不可以直接读写,先要调用ioremap(或是ioremap_nocache)影射成虚拟地址后再使用。
我写了一段程序。大家可以试验一下。
以上是基于ldd3中那个最简单的模块hello.ko改的。主要是为了可以在内核空间运行。大家可以把打印出来的内容与ehci spec 2.2对照一下。
3)Schedule Interface Space.
这里就是普通的内存。我们直接就可以访问它。
分享到:
相关推荐
Linux那些事儿之 系列 之 我是EHCI主机控制器 很不错的教程。通俗易懂。 全系列: Linux那些事儿 系列之2 Block+EHCI+PCI+SCSI http://download.csdn.net/source/1369471
Linux那些事儿之我是EHCI控制器 Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Block层 Linux那些事儿之我是Sysfs 今天本人将9个单独的文档整理出来,做成了一个单独的文档,配有书签,...
Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是PCI.pdf Linux那些事儿之我是SCSI硬盘.pdf 注: 之前有人已经上传了《Linux那些事儿 系列》,其已经包含了:hub,sysfs,UHCI,usb core,U盘,此处,先...
由复旦fudan_abc写的,风趣的文笔,深入浅出地讲解了Linux内核相关...Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Block层 linux那些事儿之我是Sysfs
Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是Block层.pdf Linux那些事儿之我是SCSI硬盘.pdf Linux那些事儿之我是Sysfs.pdf Linux那些事儿之我是PCI.pdf Linux那些事儿之我是USB core.pdf Linux 那些...
导读.doc Linux那些事儿之我是Block层.pdf Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是Hub.pdf Linux那些事儿之我是USB_core.pdf Linux那些事儿之我是U盘.pdf等等 Linux那些事儿系列全在这里了
Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是Hub Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Sysfs Linux那些事儿之我是UHCI Linux那些事儿之我是USB core Linux那些事儿之...
Linux那些事儿之我是U盘 Linux那些事儿之我是USB_core Linux那些事儿之我是UHCI Linux那些事儿之我是Sysfs Linux那些事儿之我是SCSI硬盘 ...Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是Block层
包括:Linux那些Linux那些事儿之我是SCSI硬盘,Linux那些事儿之我是Block层,Linux那些事儿之我是EHCI主机控制器,Linux那些事儿之我是HUB,Linux那些事儿之我是PCI,Linux那些事儿之我是Sysfs,Linux那些事儿之我是...
Linux那些事儿之我是XXX全集 包含USB core U盘 UHCI PCI SCSI硬盘 Block Hub EHCI 。 想学驱动的童鞋,不妨看看。该书主要是进行源代码的分析
包括:Linux那些Linux那些事儿之我是SCSI硬盘,Linux那些事儿之我是Block层,Linux那些事儿之我是EHCI主机控制器,Linux那些事儿之我是HUB,Linux那些事儿之我是PCI,Linux那些事儿之我是Sysfs,Linux那些事儿之我是...
1 Linux那些事儿之我是Block层 2 Linux那些事儿之我是EHCI主机控制器 3 Linux那些事儿之我是HUB 4 Linux那些事儿之我是PCI 5 Linux那些事儿之我是SCSI硬盘 6 Linux那些事儿之我是Sysfs 7 Linux那些事儿之我是UHCI 8 ...
我是U盘 说的是2.6.10的内核 我是Sysfs 说的是2.6.10的内核 戏说USB 说的是2.6.22的内核 我是Hub/UHCI/EHCI 说的是2.6.22.1的内核
ehci文档,较全,linux驱动,详细的讲解
linux那些事儿,Block层,EHCI主机控制器,Hub,PCI,SCSI硬盘,Sysfs,UHCI,USB core,U盘等文档。
作者用通俗幽默的语言简述了linux的相关知识点,很容易掌握的,建议大家好好学哦 我是U盘 说的是2.6.10的内核 我是Sysfs 说的是2.6.10的内核 戏说USB 说的是2.6.22的内核 我是Hub/UHCI/EHCI 说的是2.6.22.1的内核 ...
ehci 手册 详细的,几款芯片的EHCI手册
通俗易懂的设备驱动程序资料,总共有9个PDF文件 U盘、USB、HUB、EHCI、PCI、UHCI、block、SCSI、sysfs
本文是Linux那些事系列的合集,包括USB,EHCI,PCI,EHCI,BLOCK,U盘等,是非常好的参考资料