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

比较EHCI和UHCI(一)

 
阅读更多

摄影艺术家陈冠希老师告诉我们:好的作品,与器材无关,好的作品,与器官无关.有人说,有了EHCI,Intel的上一代USB主机控制器UHCI似乎就将走到被淘汰的边缘.但实际情况是,EHCIUHCI往往是并存的,它们各有价值,如果说EHCI是一款数码相机,那么UHCI则是陈冠希老师那款记录了无数不朽历史瞬间的手机.中国是摄影大国,大多数摄影爱好者玩着器材,追着器材,一味的追求顶尖的器材,但他们的作品恐怕永远也不能和陈冠希老师比肩.

冠希老师的作品的影响力,将持续久远,我们不会忘记这位对摄影艺术有着执著追求,有着独特品位,有着完美情趣的艺术家.陈冠希老师永远手持手机战斗在床榻前,这种精神感染着我们,此时此刻,我们确实应该反思一下,与其猜测UHCI将被EHCI替代,不如静下心来,分析一下它们各自的特点.

首先,EHCIUHCI的区别之一就在于探寻她们内心世界的方式不同.甭管EHCI还是UHCI,她们都有自己的内心世界.访问外设的内心世界通常有两种方法,一种是Memory-mapped I/O,一种是Port-mapped I/O.EHCIOHCI都是这种Memory-mapped I/O,UHCI则剑走偏锋,选择了Port-mapped I/O.

这两种映射的区别又在于前者需要再一次映射,后者不需要.

Linux内核代码中,我们第一次感受到EHCIUHCI的不同是在usb_hcd_pci_probe(),这是一个公共函数,任何主机控制器的驱动都会调用它.我们可以看到代码中分别对EHCIUHCI做了不同的处理:

89 if (driver->flags & HCD_MEMORY) { // EHCI, OHCI

90 hcd->rsrc_start = pci_resource_start (dev, 0);

91 hcd->rsrc_len = pci_resource_len (dev, 0);

92 if (!request_mem_region (hcd->rsrc_start, hcd->rsrc_len,

93 driver->description)) {

94 dev_dbg (&dev->dev, "controller already in use/n");

95 retval = -EBUSY;

96 goto err2;

97 }

98 hcd->regs = ioremap_nocache (hcd->rsrc_start, hcd->rsrc_len);

99 if (hcd->regs == NULL) {

100 dev_dbg (&dev->dev, "error mapping memory/n");

101 retval = -EFAULT;

102 goto err3;

103 }

104

105 } else { // UHCI

106 int region;

107

108 for (region = 0; region < PCI_ROM_RESOURCE; region++) {

109 if (!(pci_resource_flags (dev, region) &

110 IORESOURCE_IO))

111 continue;

112

113 hcd->rsrc_start = pci_resource_start (dev, region);

114 hcd->rsrc_len = pci_resource_len (dev, region);

115 if (request_region (hcd->rsrc_start, hcd->rsrc_len,

116 driver->description))

117 break;

118 }

119 if (region == PCI_ROM_RESOURCE) {

120 dev_dbg (&dev->dev, "no i/o regions available/n");

121 retval = -EBUSY;

122 goto err1;

123 }

124 }

对于EHCI,首先得映射成物理地址,然后再把物理地址映射成虚拟地址.

第一步,首先我们知道PCI设备的配置空间里可以有六个基址寄存器.如图所示:

<shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"></path><lock v:ext="edit" aspectratio="t"></lock></shapetype><shape id="_x0000_i1027" style="WIDTH: 414.75pt; HEIGHT: 255pt" type="#_x0000_t75"><imagedata src="file:///C:/DOCUME~1/JASON_~1/LOCALS~1/Temp/msohtml1/01/clip_image001.emz" o:title=""></imagedata></shape>

Base Address 0Base Address 5.位置从0x10开始,0x27结束.而我们从EHCI spec中的得到的信息是:

<shape id="_x0000_i1026" style="WIDTH: 414.75pt; HEIGHT: 272.25pt" type="#_x0000_t75"><imagedata src="file:///C:/DOCUME~1/JASON_~1/LOCALS~1/Temp/msohtml1/01/clip_image003.emz" o:title=""></imagedata></shape>

可以看到USBBASE就是我们提到的那个基址寄存器.而它位于10-13h,换言之,就是6个基址寄存器中的第一个.(这就是为什么我们传递给pci_resource_start的第二个参数是0,而不是1,2,3,4,5)

这里rsrc_start表示这个空间的起始地址,实际上就是这个基址寄存器的高28.(低四位直接取0.)理由如下,因为低四位有别的用途,用来表征其它一些信息.

<shape id="_x0000_i1028" style="WIDTH: 414.75pt; HEIGHT: 248.25pt" type="#_x0000_t75"><imagedata src="file:///C:/DOCUME~1/JASON_~1/LOCALS~1/Temp/msohtml1/01/clip_image005.emz" o:title=""></imagedata></shape>

rsrc_len表示这个寄存器所代表的空间大小.EHCI来说,常见的是0x400.

[root@localhost ~]# cat /proc/iomem

00000000-0009ffff : System RAM

00000000-00000000 : Crash kernel

000a0000-000bffff : Video RAM area

000c0000-000c7fff : Video ROM

000c9000-000c9fff : Adapter ROM

000ca000-000ca1ff : Adapter ROM

000ca800-000cbfff : Adapter ROM

000cc000-000d11ff : Adapter ROM

000f0000-000fffff : System ROM

00100000-cffa7fff : System RAM

00200000-00460c6f : Kernel code

00460c70-00595b07 : Kernel data

cffa8000-cffb7bff : ACPI Tables

cffb7c00-cfffffff : reserved

d0000000-d7ffffff : PCI Bus #10

d0000000-d7ffffff : 0000:10:0d.0

d8000000-d80fffff : PCI Bus #01

d8000000-d80fffff : PCI Bus #02

d80f0000-d80fffff : 0000:02:0e.0

d80f0000-d80fffff : megasas: LSI Logic

d8100000-d81fffff : PCI Bus #0c

d8100000-d813ffff : 0000:0c:00.1

e0000000-efffffff : reserved

f2000000-f7ffffff : PCI Bus #06

f4000000-f7ffffff : PCI Bus #07

f4000000-f7ffffff : PCI Bus #08

f4000000-f7ffffff : PCI Bus #09

f4000000-f5ffffff : 0000:09:00.0

f4000000-f5ffffff : bnx2

f8000000-fbffffff : PCI Bus #04

f8000000-fbffffff : PCI Bus #05

f8000000-f9ffffff : 0000:05:00.0

f8000000-f9ffffff : bnx2

fc100000-fc2fffff : PCI Bus #10

fc100000-fc11ffff : 0000:10:0d.0

fc1f0000-fc1fffff : 0000:10:0d.0

fc300000-fc4fffff : PCI Bus #0e

fc380000-fc39ffff : 0000:0e:00.1

fc380000-fc39ffff : e1000

fc3a0000-fc3bffff : 0000:0e:00.1

fc3a0000-fc3bffff : e1000

fc3c0000-fc3dffff : 0000:0e:00.0

fc3c0000-fc3dffff : e1000

fc3e0000-fc3fffff : 0000:0e:00.0

fc3e0000-fc3fffff : e1000

fc500000-fc6fffff : PCI Bus #0c

fc5f8000-fc5fbfff : 0000:0c:00.1

fc5f8000-fc5fbfff : qla2xxx

fc5fc000-fc5fffff : 0000:0c:00.0

fc5fc000-fc5fffff : qla2xxx

fc600000-fc63ffff : 0000:0c:00.0

fc700000-fc9fffff : PCI Bus #01

fc800000-fc9fffff : PCI Bus #02

fc8e0000-fc8fffff : 0000:02:0e.0

fc8e0000-fc8fffff : megasas: LSI Logic

fc900000-fc907fff : 0000:02:0e.0

fca00000-fca003ff : 0000:00:1d.7

fca00000-fca003ff : ehci_hcd

fe000000-ffffffff : reserved

100000000-22fffffff : System RAM

这里我们看到fca00000-fca003ff,大小就是0x400.那么这个0x400怎么得到的呢?如何得到这个值是PCI spec明确规定了的:

Size calculation can be done from the 32-bit value read by first clearing encoding information bits (bit 0 for I/O, bits 0-3 for memory), inverting all 32 bits (logical NOT), then incrementing by 1. The resultant 32-bit value is the memory/I/O range size decoded by the register. Note that the upper 16 bits of the result is ignored if the Base Address register is for I/O and bits 16-31 returned zero upon read.

具体完成这一工作的是pci_read_bases()函数,在设备枚举的时候这个函数会被调用.枚举的时候,每个pci设备会有一个struct pci_dev *dev结构体指针,该结构体中有这样一个成员:

170 struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */

struct resource定义于include/linux/ioport.h:

17 struct resource {

18 resource_size_t start;

19 resource_size_t end;

20 const char *name;

21 unsigned long flags;

22 struct resource *parent, *sibling, *child;

23 };

实际上就是表示一段资源,或者或一段资源区间.枚举的时候就会把这个pci_dev的这个成员赋上值,而咱们这里pci_resource_start以及pci_resouce_len无非就是通过这个结构体来得到资源区间的起始地址和它的长度.

知道了我们应该申请什么资源之后我们就可以正式申请了.为此我们可以调用request_mem_region().这样做就是让申请正式生效,从而也让内核知道咱们要用到这么一段区域.以免别人还对这段区域虎视眈眈.

然而,上面这两个rsrc_startrsrc_len是来自硬件本身,它们指的都是物理地址的概念.那么从驱动程序里来说应该如何访问呢?直接访问物理地址是不行的.调用一个ioremap()函数或者ioremap_nocache()函数就可以了,这叫做重映射,或者如它的名字那样remap.这个函数的返回值我们赋给了hcd->regs,从此以后,hcd->regs就代表了这段寄存器空间,它将指引我们通向EHCI控制器内心世界.

对于UHCI,它基址寄存器所代表的空间大小通常是32.或者说0x20.不信您看:

[root@localhost ~]# cat /proc/ioports

0000-001f : dma1

0020-0021 : pic1

0040-0043 : timer0

0050-0053 : timer1

0060-006f : keyboard

0070-0077 : rtc

0080-008f : dma page reg

00a0-00a1 : pic2

00c0-00df : dma2

00f0-00ff : fpu

01f0-01f7 : ide0

02f8-02ff : serial

03c0-03df : vga+

03f6-03f6 : ide0

03f8-03ff : serial

0800-0803 : ACPI PM1a_EVT_BLK

0804-0805 : ACPI PM1a_CNT_BLK

0808-080b : ACPI PM_TMR

0828-082f : ACPI GPE0_BLK

0880-08bf : pnp 00:08

08c0-08df : pnp 00:08

08e0-08e3 : pnp 00:08

0c00-0c7f : pnp 00:08

0ca0-0ca7 : pnp 00:08

0ca8-0ca8 : pnp 00:09

0ca9-0cab : pnp 00:08

0cac-0cac : pnp 00:09

0cad-0caf : pnp 00:08

bca0-bcbf : 0000:00:1d.2

bca0-bcbf : uhci_hcd

bcc0-bcdf : 0000:00:1d.1

bcc0-bcdf : uhci_hcd

bce0-bcff : 0000:00:1d.0

bce0-bcff : uhci_hcd

c000-cfff : PCI Bus #10

cc00-ccff : 0000:10:0d.0

d000-dfff : PCI Bus #0e

dcc0-dcdf : 0000:0e:00.1

dcc0-dcdf : e1000

dce0-dcff : 0000:0e:00.0

dce0-dcff : e1000

e000-efff : PCI Bus #0c

e800-e8ff : 0000:0c:00.1

e800-e8ff : qla2xxx

ec00-ecff : 0000:0c:00.0

ec00-ecff : qla2xxx

fc00-fc0f : 0000:00:1f.1

fc00-fc07 : ide0

不管是0xbca0-0xbcbf,还是0xbce0-0xbcff,都是占据了0x20的空间.网友只寻花不问柳问到,那么这个0x20有什么依据呢?为啥要取这么一个值?,您别急,这还真是有讲究的,您看下面这幅图,摘自uhci-spec,人家uhci-spec定义了这么些个I/O寄存器,这里占用的地址就是00h13h,不到20h,不过在党的科学发展观的英明指导下,设计者们还是多留出几个地址有备无患,这样即使您设计的硬件需要更多的寄存器那也能行,比如说这里定义的是两个端口,而如果您觉得不够用,多设计几个,那也没问题,PORTSC1,PORTSC2之后您还可以接上PORTSC3,PORTSC4.直到19h也没问题.

<shape id="_x0000_i1025" style="WIDTH: 415.5pt; HEIGHT: 132.75pt" type="#_x0000_t75"><imagedata src="file:///C:/DOCUME~1/JASON_~1/LOCALS~1/Temp/msohtml1/01/clip_image007.emz" o:title=""></imagedata></shape>

对于UHCI来说,获得rsrc_startrsrc_len的方法和上面EHCI是一样的.但之后,需要调用request_region()函数正式申请.并且由于Port-mapped IO我们是直接用专用IO指令访问的,所以不需要映射成虚拟地址.做到这一步就足够了.从此以后我们将通过hcd->rsrc_start来访问UHCI内部的寄存器.(正如我们在uhci_init()函数中看到的那样.)

分享到:
评论

相关推荐

    比较EHCI和UHCI

    只有一节 不建议下载

    ehci、xhci、uhci规范

    ehci、xhci、uhci规范,供软件、硬件设计使用,usb相关接口

    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那些事儿 系列之2 Block+EHCI+PCI+SCSI

    极力推荐。 牛人写的,关于Linux驱动相关模块的详细介绍。 文笔很幽默,能深入浅出地把枯燥的驱动...之前有人已经上传了《Linux那些事儿 系列》,其已经包含了:hub,sysfs,UHCI,usb core,U盘,此处,先感谢原作者。

    指尖操作系统 V0.22

    &lt;br&gt; 简要说明: 基于IA32开发 图形界面 支持最大4G内存 支持软驱驱动 支持COM,PS2鼠标驱动 键盘驱动 多任务 硬盘ATA LAB驱动 硬盘DMA驱动 USB的EHCI和UHCI驱动 FAT32文件...

    指尖操作系统 V0.32

    指尖操作系统具有硬盘分区、格式化功能,可以按分区备份及恢复数据。支持多硬盘。 指尖操作系统可以安装运行在硬盘、U盘上,可独立使用此系统启动计算机。...USB的EHCI和UHCI驱动 FAT32文件读取 中文系统

    LINUX那些事儿 linux经典之作

    然后是usb core(也就是戏说USB),这一阶段是个承上启下的角色,承的是U盘/HUB,启的是UHCI/EHCI,主要描述一个usb设备连接到hub上之后,在HUB和UHCI/EHCI之间也就是usb core里发生的故事. 再然后可以开始看UHCI/EHCI.这...

    FTDI FT-X Series FT200XD FT231 FT240等全系列原理图库+PCB封装库(AD集成库).zip

    FT200XD-R USB to I2C Interface Slave Chip, UHCI/OHCI/EHCI Compatible, USB 2.0 Compatible, -40 to +85 degC, 10-Pin DFN, Pb-Free, Tape and Reel FT200XD-T USB to I2C Interface Slave Chip, UHCI/OHCI/EHCI ...

    USB DOS系列之一:列出你的USB设备

    OHCI(Open Host Controller Interface)、UHCI(Universal Host Controller Interface)支持USB1.1,EHCI(Enhanced Host Controller Interface)支持USB2.0,以后的文章中,我们将侧重介绍OHCI和EHCI。

    USB2.0 for realtime-开源

    USB 2.0 for Real-Time在Linux / Xenomai之上提供了USB 2.0堆栈的硬实时功能实现。 它实现了堆栈核心以及EHCI,UHCI和OHCI主机控制器驱动程序。

    详解linux usb host驱动编写入门

    大家如果打开kernel usb host目录,就会发现下面包含了ohci,uhci,ehci,xhci,whci等多种形式的控制器驱动。那么,对于我们这些不是很了解usb的开发人员,如何了解usb的代码结构呢? 1、代码分布 drivers/usb目录...

    Linux那些事儿

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

    Linux那些事儿系列

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

    Linux那些事儿1-9合集

    由复旦fudan_abc写的,风趣的文笔,深入浅出地讲解了Linux内核相关模块,主要涉及了USB相关的模块,但是同样也解析了Linux驱动模型相关的知识,很值得一读。读过《linux那些事儿之我是U盘》的人,都知道其风格,我就...

    Open Host Controller Interface Specification for USB

    USB的SPEC; USB分3类,UHCI、EHCI、OHCI,本文属于OHCI部分

    Linux那些事儿.rar

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

    USBMap:用于在 macOS 中映射 USB 端口并创建自定义注入器 kext 的 Python 脚本

    可以映射 XHCI(芯片组、第三方和 AMD)、EHCI、OHCI 和 UHCI 端口 可以映射 USB 2 HUB(需要 HUB 的父端口使用类型 255) 基于类名匹配,而不是端口或控制器名称 允许为发现中最后看到的填充端口设置昵称 通过...

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

    Linux那些事系列合集

    这些文档是Linux那些事的合集,包括USB,EHCI,Hub,PCI,SCSI,Sysfs,UHCI,U盘等

Global site tag (gtag.js) - Google Analytics