基础

1. OHCI(Open Host Controller Interface)是支持USB1.1的标准,但它不仅仅是针对USB,还支持其他的一些接口,比如它还支持Apple的火线(Firewire,IEEE 1394)接口。与UHCI相比,OHCI的硬件复杂,硬件做的事情更多,所以实现对应的软件驱动的任务,就相对较简单。主要用于非x86的USB,如扩展卡、嵌入式开发板的USB主控。
2. UHCI(Universal Host Controller Interface),是Intel主导的对USB1.0、1.1的接口标准,与OHCI不兼容。UHCI的软件驱动的任务重,需要做得比较复杂,但可以使用较便宜、较简单的硬件的USB控制器。Intel和VIA使用UHCI,而其余的硬件提供商使用OHCI。
3. EHCI(Enhanced Host Controller Interface),是Intel主导的USB2.0的接口标准。EHCI仅提供USB2.0的高速功能,而依靠UHCI或OHCI来提供对全速(full-speed)或低速(low-speed)设备的支持。
4. XHCI(eXtensible Host Controller Interface),是最新的USB3.0的接口标准,它在速度、节能、虚拟化等方面都比前面3中有了较大的提高。xHCI 支持所有种类速度的USB设备(USB 3.0 SuperSpeed, USB 2.0 Low-, Full-, and High-speed, USB 1.1 Low- and Full-speed)。xHCI的目的是为了替换前面3中(UHCI/OHCI/EHCI)。

EDKII 中的USB 协议栈由三部分驱动程序组成:

USB 主控制器驱动,USB 总线驱动 和USB 设备驱动

其中:

USB 主控制器驱动源代码位于MdeModulePkg\Bus\Pci 目录下

USB 总线驱动和USB 设备驱动源代码位于MdeModulePkg\Bus\Usb 目录下

USB主控制器驱动(HCDI:EFI_USB2_HC_PROTOCOL

USB总线驱动(USBDI:EFI_USB_IO_PROTOCOL

USB 设备驱动

以EHCI为例:

咱们先从USB主控制器驱动说起,代码主要关注EhciDxe这个driver,这是什么driver?符合UEFI驱动模型的driver。

在Ehci.c:

主要看下面这个函数:

EFI_STATUS
EFIAPI
EhcDriverBindingStart (IN EFI_DRIVER_BINDING_PROTOCOL *This,IN EFI_HANDLE                  Controller,IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath)
{。。。。。

该函数逻辑如下:

EhcDriverBindingStart开始-----打开PciIo协议,启用USB主控制器-------打开USB主控制器上的设备路径协议----保存原始的PCI属性----获取Pci设备class code-----确定设备是否为UHCI或OHCI主机控制器。如果是,则找出配套usb ehci主机控制器,并在UHCI或OHCI驱动程序连接到UHCI或OHCI主机控制器之前,强制将ehci驱动程序连接到该控制器------配套usb主机控制器的判断是否通过,如果通过,开始实例化USB2_HC_DEV并安装EFI_USB2_HC_PROTOCOL,然后就是上图的顺序了

//// Init EFI_USB2_HC_PROTOCOL interface and private data structure//Ehc->Signature                        = USB2_HC_DEV_SIGNATURE;Ehc->Usb2Hc.GetCapability             = EhcGetCapability;Ehc->Usb2Hc.Reset                     = EhcReset;Ehc->Usb2Hc.GetState                  = EhcGetState;Ehc->Usb2Hc.SetState                  = EhcSetState;Ehc->Usb2Hc.ControlTransfer           = EhcControlTransfer;Ehc->Usb2Hc.BulkTransfer              = EhcBulkTransfer;Ehc->Usb2Hc.AsyncInterruptTransfer    = EhcAsyncInterruptTransfer;Ehc->Usb2Hc.SyncInterruptTransfer     = EhcSyncInterruptTransfer;Ehc->Usb2Hc.IsochronousTransfer       = EhcIsochronousTransfer;Ehc->Usb2Hc.AsyncIsochronousTransfer  = EhcAsyncIsochronousTransfer;Ehc->Usb2Hc.GetRootHubPortStatus      = EhcGetRootHubPortStatus;Ehc->Usb2Hc.SetRootHubPortFeature     = EhcSetRootHubPortFeature;Ehc->Usb2Hc.ClearRootHubPortFeature   = EhcClearRootHubPortFeature;Ehc->Usb2Hc.MajorRevision             = 0x2;Ehc->Usb2Hc.MinorRevision             = 0x0;Ehc->PciIo                 = PciIo;Ehc->DevicePath            = DevicePath;Ehc->OriginalPciAttributes = OriginalPciAttributes;

上图只讲到了Ehci.C中的函数,实际这里面的接口有的最终需要调用Ehcisched.c里面的函数,这里需要明白一个概念:什么是URB

URB:USB请求块,包含各种数据的信息

struct _URB {UINT32                          Signature;LIST_ENTRY                      UrbList;//// Transaction information//USB_ENDPOINT                    Ep;EFI_USB_DEVICE_REQUEST          *Request;     // Control transfer onlyVOID                            *RequestPhy;  // Address of the mapped requestVOID                            *RequestMap;VOID                            *Data;UINTN                           DataLen;VOID                            *DataPhy;     // Address of the mapped user dataVOID                            *DataMap;EFI_ASYNC_USB_TRANSFER_CALLBACK Callback;VOID                            *Context;//// Schedule data//EHC_QH                          *Qh;//// Transaction result//UINT32                          Result;UINTN                           Completed;    // completed data lengthUINT8                           DataToggle;
};

1.Struct USB2_HC_DEV是Host controller的核心数据结构,在初始化过程中创建;QTD、QH的数据结构的定义位于 EHCI spec 3.5/3.6;

2.管理controller和bulk传输:插入Asynchronous Schedule list

//把组装好的Qh插入EHCI主控制器的Asynchronous Schedule List,以便硬件执行传输命令EhcLinkQhToAsync (Ehc, Urb->Qh);
//阻塞式的执行此次controller传输Status = EhcExecTransfer (Ehc, Urb, TimeOut);
//从Asynchronous Schedule List中将其移除EhcUnlinkQhFromAsync (Ehc, Urb->Qh);

3.管理isochronous和interrupt传输:插入Periodic schedule frame list

//把组装好的Qh插入EHCI主控制器的Periodic schedule frame list,以便硬件执行传输命令EhcLinkQhToPeriod (Ehc, Urb->Qh);
//并把URB插入异步中断传输链表 &Ehc->AsyncIntTransfersInsertHeadList (&Ehc->AsyncIntTransfers, &Urb->UrbList);

4.插入硬件链表的URB,硬件会自动执行发送;

5.链表&Ehc->AsyncIntTransfers是由驱动程序创建并管理的,由EhcMonitorAsyncRequests()管理;

(1)他会循环&Ehc->AsyncIntTransfers上的每个urb;

(2)通过判断QTD.status来判断执行结果(一个urb中包含一个QH和一串QTD);

(3)更新QH,为下一轮异步传输准备;

(4)如果有回调函数,执行回调函数。

着重讲一下:阻塞式的执行此次controller传输:Status = EhcExecTransfer (Ehc, Urb, TimeOut);

EFI_STATUS
EhcExecTransfer (IN  USB2_HC_DEV         *Ehc,IN  URB                 *Urb,IN  UINTN               TimeOut)
{EFI_STATUS              Status;UINTN                   Index;UINTN                   Loop;BOOLEAN                 Finished;BOOLEAN                 InfiniteLoop;Status       = EFI_SUCCESS;Loop         = TimeOut * EHC_1_MILLISECOND;Finished     = FALSE;InfiniteLoop = FALSE;//// According to UEFI spec section 16.2.4, If Timeout is 0, then the caller// must wait for the function to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR// is returned.//if (TimeOut == 0) {InfiniteLoop = TRUE;}for (Index = 0; InfiniteLoop || (Index < Loop); Index++) {Finished = EhcCheckUrbResult (Ehc, Urb);if (Finished) {break;}gBS->Stall (EHC_1_MICROSECOND);}if (!Finished) {DEBUG ((EFI_D_ERROR, "EhcExecTransfer: transfer not finished in %dms\n", (UINT32)TimeOut));EhcDumpQh (Urb->Qh, NULL, FALSE);Status = EFI_TIMEOUT;} else if (Urb->Result != EFI_USB_NOERROR) {DEBUG ((EFI_D_ERROR, "EhcExecTransfer: transfer failed with %x\n", Urb->Result));EhcDumpQh (Urb->Qh, NULL, FALSE);Status = EFI_DEVICE_ERROR;}return Status;
}

这个函数如果设备出错了咋办?现象就是会一直去重试,达到最大重试次数,如果设备依然出错,那么直接跳过,但是有个问题,达到最大重试次数一般得好几分钟,这就容易造成不能进系统的假象,得等到重试完成,这种情况一般出现在工控机中,由于外界USB设备较多,不排除USB设备异常。

ok,下一节再分析USB device

EDK II 源码剖析---USB协议之EHCI(例子)一相关推荐

  1. Dubbo协议模块源码剖析

    Dubbo协议模块源码剖析 目录 概 述 RPC协议报文编码与实现详解 RPC 传输实现: 拆包与粘包解决办法: Dubbo 报文格式 分析: 小结: 参考资料和推荐阅读 LD is tigger f ...

  2. 老李推荐:第6章1节《MonkeyRunner源码剖析》Monkey原理分析-事件源-事件源概览 1...

    老李推荐:第6章1节<MonkeyRunner源码剖析>Monkey原理分析-事件源-事件源概览 在上一章中我们有简要的介绍了事件源是怎么一回事,但是并没有进行详细的描述.那么往下的这几个 ...

  3. 老李推荐:第14章4节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-装备ViewServer-端口转发 1...

    老李推荐:第14章4节<MonkeyRunner源码剖析> HierarchyViewer实现原理-装备ViewServer-端口转发 在初始化HierarchyViewer的实例过程中, ...

  4. Mongoose源码剖析:Introduction and Installation

    引言 要剖析Mongoose的源码,首先你得知道它的一些基本情况和特性.并去使用它.本文就是介绍Mongoose是个什么东西?及如何安装和使用?这里假设你知道什么web服务器软件.web服务器使用什么 ...

  5. Mongoose源码剖析:外篇之web服务器

    引言 在深入Mongoose源码剖析之前,我们应该清楚web服务器是什么?它提供什么服务?怎样提供服务?使用什么协议?客户端如何唯一标识web服务器的资源?下面我们抛开Mongoose,来介绍一个we ...

  6. tomcat(12)org.apache.catalina.core.StandardContext源码剖析

    [0]README 0)本文部分文字描述转自 "how tomcat works",旨在学习 "tomcat(12)StandardContext源码剖析" 的 ...

  7. 《STL源码剖析》相关面试题总结

    一.STL简介 STL提供六大组件,彼此可以组合套用: 容器 容器就是各种数据结构,我就不多说,看看下面这张图回忆一下就好了,从实现角度看,STL容器是一种class template. 算法 各种常 ...

  8. pymavlink 源码剖析(二)之生成代码

    文章目录 1 引言 2 C 代码生成 3 generate_one 函数分析 4 MAVTemplate 5 头文件生成 相关: pymavlink 源码剖析(一)之XML文件的数据解析 MAVLin ...

  9. pymavlink 源码剖析(一)之XML文件的数据解析

    文章目录 1 引言 2 pymavlink 的代码自动生成方法 3 XML 文件的数据解析 3.1 XML 文件预处理 3.2 解析 XML 的数据 3.2.1 依据协议版本初始化一些版本特征变量 3 ...

最新文章

  1. 安装PHP5、PHP7
  2. 非程序员如何使用 Git——版本控制你的生活
  3. JDK 12:实际中的切换语句/表达式
  4. 解决SVN提交代码时的错误:“Could not execute PROPPATCH”
  5. 半素数c语言,非常简单的c题目 不懂 紧急求助
  6. Asp.net2.0 中自定义过滤器对Response内容进行处理
  7. 调用sap函数接口_部署在SAP云平台CloudFoundry环境的应用如何消费SAP Leonardo机器学习API...
  8. 工控HMI界面设计基本原则
  9. php如何用sql语句修改数据库,SQL语句进行数据表的增删改查教程(phpMyAdmin使用教程)...
  10. ApacheCN 翻译活动进度公告 2019.6.15
  11. [幽默小故事大道理]励志幽默小故事大道理20个
  12. iOS 跑马灯带图片可点击
  13. 如何利用新浪博客做外链
  14. P1458 [USACO2.1]顺序的分数 Ordered Fractions
  15. 牛客练习赛85-哲学家的沉思-(上升子序列变形+树状数组+线段树+离散化+set)
  16. 阿里云ECS最新的实例规格族有哪些
  17. Java面试题3(jsp)
  18. Yolov5图像识别教程
  19. JetBrains IDEA 2019.3 plugins|插件 搜索不到任何东西
  20. APS系统发展现状随笔--唯有坚守本心,方可前行

热门文章

  1. python for遍历字符串_Python之字符串的遍历的4种方式
  2. php隐藏指定id的div,CSS_纯css3显示隐藏一个div特效的具体实现,复制代码代码如下: !DOCTYPE H - phpStudy...
  3. C语言实现RC4加解密算法
  4. 海康DDNS远程访问用户手册
  5. python爬取优美图库海量图片,附加代码,一键爬取
  6. javaScript中的map对象
  7. php的 d,环保增塑剂DPHP
  8. VRML/X3D相关资源网站
  9. java基于ssm的在线家电维修系统网站
  10. 基于阿里云服务器环境搭建到项目上线系列文章之六——项目部署