原文链接:https://docs.google.com/document/d/1EEPLoyupLXS5vCMVo1E9iZbsxmYarQ79EhDxKsMVsak/edit
2008-5-3 USB,几乎天天在用,俺多普达的水货手机,就是USB的数据线,同时兼作充电, 所以有电脑的地方就有能源..暂时以UHCI为例:Universal Host Controller interface, 由intel 制定.虽然驱动高速设备需要EHCI, 但是这里仍旧以UHCI为例. 详细信息参考linux官方网站的FAQ: http://www.lrr.in.tum.de/Par/arch/usb/usbdoc/ UBS device driver Guid USB2.0 specification 在USB的两根信号线上(采用了双绞线,抗干扰D+,D-,串行,PCIE和USB让串行通讯再度辉煌),传输着各种报文(很像packet 网络),和以太网比 较,俺做网络时间长了,难免这么比较:以太网上,每个以太网报文都是独立由驱动发送和接受,并且对实时的支持并不好,但是usb标准充分考虑 了实时性应用要求,并且驱动能(UHCI host controler interface)操作的最小单位是transaction,而不是packets. 对于UHCI,其实时性要求通过host controler硬件予以保证,UHC以1个毫秒为单位,调度transaction的报文收发,这样保证1秒内,实时传输 的数据和中断传输的数据总和不超过传输带宽的90%,而控制传输和批量传输则使用剩余部分的带宽. 传输(transfer)是比transaction更大的一个概念. transaction译为事务?交互?都容易使人忽略transaction是一种把几个操作组合成一 个原子操作的方法的这个含义.一个传输是可以跨越一毫秒这个调度单位的,而transaction则不能.而packet更为原始,基本OS不可直接操作.其 实只有control transfer 最为复杂包含了几个不同的trnsaction: 一个setup transaction+data(bulk) +status (bulk transaction).bulk ISO, int只不过是几个相同的transaction的不断重复. 这里列举下packet的报文格式,至于内核代码,因为packet只能间接操作,而且是分散在UHCI驱动中,并且在驱动只能操作transaction,而每个 中就包含了几个packet:见uhci_submit_control,uhci_submit_bulk,uhci_submit_interrupt,uhci_submit_isochronous.( 这几个函数操作的是transfer, 包含几个transaction,在UHCI中transfer由几个TD构成,一个td代表一个transaction,每个transaction包含 几个packet). 1. token 报文格式 PID = IN/OUT/setup IN: function to host transaction OUT:host to function transaction 2.Split Transaction Special Token Packets 这两种token报文只用在host controler和高速hub之间,并且只有在高速的hub接入一个full speed或者low speed设备时使用. 3. SOF host以每毫秒一个的速度发送SOF,代表一个frame的开始,也是一个调度单位. 4.DATA packet PIDs: DATA0, DATA1, DATA2,and MDATA DATA0 and DATA1 are defined to support data togglesynchronization All four data PIDs are used in data PID sequencing for highbandwidth high-speed isochronous endpoints MDATA, DATA0,DATA1 are used in split transactions . 5. Handshake Packet PIDS: ACK NACK STALL NYET ERR 什么文档才能准确解释并效验内核的USB驱动? 那就是USB标准文档了. Transactions Transaction的类型由通讯的对象:endpoint的类型所决定. 每个tansaction分成几个阶段,每个阶段包含一个或几个报文, 每个报文内都含 有PID /pak-context/CRC几个域.
1. Ping 为High Speed Device所支持的NACK协议, 主机发送PING token来查询设备是否能够接受长度为wMaxPacketSize的报文(data buffer是否够长),如果buffer足够就回应ACK否则回应NAK. 低俗设备没有这个机制,在其回应NCK的时候,bus的带宽已经被浪费掉了.(handsake阶段才发送NACK呢!) 这个机制有效提高高速设备的bus带宽利用率. 2. Bulk Transaction 3.control Transaction SETUP PID和OUT类似,代表一个输出操作,输出一个setup packet给设备,用此决定下一个stage的数据的方向.(有可能没有数据stage) 一个control transfer由一个setup transction 加上几个bulk transaction, uihou一个是status stage 是一个IN类型的bulk transaction比较而言,control transfer是最复杂的transfer了.其他的transfer只包含几个同类型的transaction,主要由数据长 度决transaction的数量. 4.Interrupt Transaction 5.Iso Transaction USB host controler:UHCI 下图是UHCI标准的系统结构框图.UHC在每个1ms内调度ISO,INT,CNTL,BULK的transfer运行,并保证ISO+INT传输总带宽不超过USB总线带宽的 90%.
下图是UHCI的结构框图.
![]() UHCI通过调度一个frame list的结构来完成USB trasaction以及保证带宽分配.其数据结构包括Frame List,Queue Heads和Transfer Descriptors. 一个TD代表一个transaction.其典型的组织结构如下图所示.
TD的link指针和QH的element指针都能指向TD或者QH,其最低极为有类型域. 一般ISO直接作为TD来执行,之后依次是INT,control,和bulk的QH. 深度优先 --- 如果是QH,处理完其所有TD再进行下一个QH,linux下urb提交的传输是在一个QH上的,这显然不公平. 广度优先 ----区一个QH下地第一个TD,然后处理下一个QH.问题是,到达QH尾端的时候,UHC就不干活了,但是这个ms可能还有剩余资源可以利用, 这些剩余资源的回收就叫做FSBR. 下面两个图就是TD和QH的结构.其详细含义请参考intel的UHCI标准,这里做一提示而已. 主义其中的Vf bit ==0 时作广度优先遍历.linux初始华TD的 时候没有理会这个bit,默认采用广度优先遍历.
TD的第一个长字是link指针用以形成链表.接下来的长字用于status和control,第三个个长字用于token,最后一个长字是这个transaction的 数据指针. 不要忽略TD代表一个transaction,一个transaction典型的由一个Token报文+几个数据报文+一个handshake报文组成, ISO不需要 handshake,而CNT L则可能没有数据报文. 注意,在建立一个transfer的时候由几个TD组成,代表由几个transaction组成. 再次提下control transfer,control transfer由 几个stage 组成,并且其transaction类型不同. 第三个长字的PID仅容许setup/in/out三种token. (再注:data1/0 这种PID并不是token,所以操作UHC的时候根本用不到的...,只是用Dbit来 控制 data Toggle而已.) ISO transaction直接以TD的方式挂载在frame list上,就是说不在一个QH的context内,执行完成后依然存在于hw的frame list内,但是 Activebit会 被硬件清除,从而下次调度到这个tD的时候不会被执行.
linux下control/intrrupt/bulk transaction都是在一个QH的队列中被执行的, 硬件会更新qh->element域,从而使td在下一次调度的时候不会被执行 ,就是说被硬件自动脱链了. 祥见UHCI标准或参考下图.
这里不准备对USB驱动详加研究,仅仅从代码的角度理解一下.每个USB设备由几个端点(end point)组成, 每个USB的trasaction都是和一个端点 进行报文传输,类似与tcp 端口号.端点可以以不同的方式组合成一个接口(比如类似T1,E1通道绑定的概念,或者ISDN的那种绑定通道的方式),这些组合方式叫做一个配置. 从软件的角度来讲,就是一个设备有一个设备Descriptor,和可能有的一个或者几个配置,称为配置表比较好,因为配置中包含接口Desc,EP Desc. Class Desc以及Vendor Desc:每个配置表内包含一个配置Descriptor,几个接口Desc,每个接口的Desc后面跟着和这个接口相关的几个EndPoint的描述符. 基本上就是如图下所示: 有了从Standard中提取的这个图,看懂usb_get_configuration不再困难!
|