`
dato0123
  • 浏览: 916478 次
文章分类
社区版块
存档分类
最新评论

Linux那些事儿之我是EHCI(1) 接口体系

 
阅读更多

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
typedefunsigned
charBOOL;
#endif

#ifndefBYTE
typedefunsigned
charBYTE;
#endif

#ifndefDWORD
typedefunsigned
longDWORD;
#endif

#ifndefINT
typedefunsigned
intINT;
#endif

#ifndefULONG
typedefunsigned
longULONG;
#endif

#ifndefWORD
typedefunsigned
shortWORD;
#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;
unsigned
longnumperm=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((unsigned
long)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)影射成虚拟地址后再使用。

我写了一段程序。大家可以试验一下。

#include <asm/io.h>
staticinthello_init(void)
...{
unsigned
longport_value,mem_value;
void__iomem*add;
inti;
printk(KERN_ALERT
"Hello,world ");
add=ioremap(0xfe226400,0x400);
for(i=0;i<100;i++)...{
mem_value
=ioread32(add+i*4);
printk(
"%08Xmemvalueis:%08X ",add+i*4,mem_value);
}

iounmap(add);
return0;
}

以上是基于ldd3中那个最简单的模块hello.ko改的。主要是为了可以在内核空间运行。大家可以把打印出来的内容与ehci spec 2.2对照一下。

3)Schedule Interface Space.

这里就是普通的内存。我们直接就可以访问它。

分享到:
评论

相关推荐

    Linux那些事儿之我是EHCI主机控制器.pdf

    Linux那些事儿之 系列 之 我是EHCI主机控制器 很不错的教程。通俗易懂。 全系列: Linux那些事儿 系列之2 Block+EHCI+PCI+SCSI http://download.csdn.net/source/1369471

    Linux那些事儿

    Linux那些事儿之我是EHCI控制器 Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Block层 Linux那些事儿之我是Sysfs 今天本人将9个单独的文档整理出来,做成了一个单独的文档,配有书签,...

    Linux那些事儿 系列之2 Block+EHCI+PCI+SCSI

    Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是PCI.pdf Linux那些事儿之我是SCSI硬盘.pdf 注: 之前有人已经上传了《Linux那些事儿 系列》,其已经包含了:hub,sysfs,UHCI,usb core,U盘,此处,先...

    Linux那些事儿1-9合集

    由复旦fudan_abc写的,风趣的文笔,深入浅出地讲解了Linux内核相关...Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Block层 linux那些事儿之我是Sysfs

    linux那些事儿(EHCI Block SCSI Sysfs PCI USB U 盘 UHCI Hub)

    Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是Block层.pdf Linux那些事儿之我是SCSI硬盘.pdf Linux那些事儿之我是Sysfs.pdf Linux那些事儿之我是PCI.pdf Linux那些事儿之我是USB core.pdf Linux 那些...

    Linux那些事儿之全集

    导读.doc Linux那些事儿之我是Block层.pdf Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是Hub.pdf Linux那些事儿之我是USB_core.pdf Linux那些事儿之我是U盘.pdf等等 Linux那些事儿系列全在这里了

    linux的那些事儿全集

    Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是Hub Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Sysfs Linux那些事儿之我是UHCI Linux那些事儿之我是USB core Linux那些事儿之...

    linux那些事全集

    Linux那些事儿之我是U盘 Linux那些事儿之我是USB_core Linux那些事儿之我是UHCI Linux那些事儿之我是Sysfs Linux那些事儿之我是SCSI硬盘 ...Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是Block层

    Linux那些事儿.rar

    包括:Linux那些Linux那些事儿之我是SCSI硬盘,Linux那些事儿之我是Block层,Linux那些事儿之我是EHCI主机控制器,Linux那些事儿之我是HUB,Linux那些事儿之我是PCI,Linux那些事儿之我是Sysfs,Linux那些事儿之我是...

    Linux那些事儿之我是XXX全集.rar

    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那些事儿之我是...

    usb那些事的全集

    1 Linux那些事儿之我是Block层 2 Linux那些事儿之我是EHCI主机控制器 3 Linux那些事儿之我是HUB 4 Linux那些事儿之我是PCI 5 Linux那些事儿之我是SCSI硬盘 6 Linux那些事儿之我是Sysfs 7 Linux那些事儿之我是UHCI 8 ...

    Linux那些事儿[完整版]自己整理

    我是U盘 说的是2.6.10的内核 我是Sysfs 说的是2.6.10的内核 戏说USB 说的是2.6.22的内核 我是Hub/UHCI/EHCI 说的是2.6.22.1的内核

    ehci文档,较全,linux驱动

    ehci文档,较全,linux驱动,详细的讲解

    linux那些事儿.rar

    linux那些事儿,Block层,EHCI主机控制器,Hub,PCI,SCSI硬盘,Sysfs,UHCI,USB core,U盘等文档。

    LINUX那些事儿 linux经典之作

    作者用通俗幽默的语言简述了linux的相关知识点,很容易掌握的,建议大家好好学哦 我是U盘 说的是2.6.10的内核 我是Sysfs 说的是2.6.10的内核 戏说USB 说的是2.6.22的内核 我是Hub/UHCI/EHCI 说的是2.6.22.1的内核 ...

    ehci 手册 详细的

    ehci 手册 详细的,几款芯片的EHCI手册

    Linux那些事儿系列

    通俗易懂的设备驱动程序资料,总共有9个PDF文件 U盘、USB、HUB、EHCI、PCI、UHCI、block、SCSI、sysfs

    Linux那些事系列合集pdf

    本文是Linux那些事系列的合集,包括USB,EHCI,PCI,EHCI,BLOCK,U盘等,是非常好的参考资料

Global site tag (gtag.js) - Google Analytics