关于usb的总结 1: usb 枚举过程 通俗的来说就是你插上去让主机知道你的一些基本信息,但是所有的usb设备都是被动的,都是要求主机向你发送命令,才作出反应。 这里所说的主机host端其实就是你电脑或者嵌入式设备里面的controller,你们可以在linux源码中看到 usb目录下有个叫做host子目录,里面就是这些controller的驱动 包括一些像ehci ohci whci 等等。 好了,我们来看看设备是怎么被动的让他们知道自己的信息的。 下面是通过分析仪抓到的枚举过程。
我们可以看到这里 controller发的第一个命令叫做 get_descriptor 就是拿到一些device的描述信息。 在传输之前说说什么叫做端点,整个usb传输的最底层就是一些usb数据包,这些数据包就是对端点进行的操作,向设备in数据或者out数据。一般一个设备会有很多端点,具体多少个要通过controller发命令拿到的描述,按照usb spec 里面的格式解析出来。但是每个设备必须都有一个control端点,枚举过程的操作都是对这个端点进行的。 好了,我们来分析下 整个get_descriptor 过程,我们叫做一个transfer。 可以看到 一个transfer 下面包括了三个transaction 其实很容易理解,controller要拿到设备的数据 必须经过三个步骤。 第一 告诉你我要拿你数据了,这个时候device开始准备了,但是他不会主动发你要的东西给你,一定要等controller再发个transaction过来往里面填,这里就可以体现了 device为啥喜欢被动了,一定要你发过来) 第二 第二个transaction
第三 controller发送一个transaction 表明我收到了数据了 这个transaction 也不是必须的 在那个set_address 里面就省略了这步。
下面来分析单个 transaction 里面会展开成三个packet 这个就是最底层的usb包了,结构大家可以看看usb spec。三个包为 命令,数据,握手。 其实枚举里面大部分都是这些过程,拿device的信息,设置它的address,为什么要设置他的地址,因为 controller出来就两根数据线d+ d- 两个线上面可能会挂好多设备。通过addr来发送到特定的设备,也可以看到最底层的包结构里面包括它了(ADDR) 上面是从协议里面分析了枚举过程。
下面从代码里面看看吧:
代码里面来分析下整个传输的过程吧。参考 linux kernel usb_get_device_descriptor usb_control_msg() usb_submit_urb() ehci_urb_enqueue() 主要看看这个函数吧 ehci_urb_enqueue 主要的两个函数 qh_urb_transaction submit_async qh_urb_transaction 整个意思就是,怎么把上层给我的请求(transfer)变成几个transaction 这里面怎么填写的就要参考ehci的协议了
每个qh(transfer)结构里面有个 qtd pointer就是指向那个transaction的,这些transaction自己又是链在一起的。然后硬件就开始干活的,执行完一个transaction后呢,就搬运下面一个transaction到自己的overlay(qh里面保存qtd的结构)来执行,执行完就按你软件设置的,控制要不要回中断,通知软件。
相应的软件也可以通过里面置一些位来控制,controller是否暂停该qtd,linux里面通过一个叫dummy的qtd来使得该qh暂停,这样做的方便之处是下一个还要用这个qh来传东西的时候,就不要重新去建立qh了,直接把要传的qtd和dummy去替换就ok了。
每个请求(例如:get_device_desriptor)就是一个qh ,如果qh一样呢,就把你变成的那些transaction接着链下去,上层呢不断的发请求下面就不断的链,硬件就不断的跑。
head ->qh->qh->qh->(指到head 环形链表)
controller就运行qh下面的qtd然后就跳到下一个qh的qtd去执行。注意不是把该qh下面所有的qtd执行完再去执行下一个qh。
枚举完成了,主机也知道了你是啥设备,你支持那些协议那些命令了,假设我们的usb设备是u盘,我们来分析一下数据是怎么读写的吧。 枚举的过程中我们知道了这个设备支持走那些协议,一般来说了U盘都是走bulkonly协议的。 什么是bulkonly协议呢。那肯定是bulk传输了,和前面的control传输不一样了,不一样之处就是走的端点不一样了。control传输走的是 ENDP 0(断点0),现在就是ENDP 1或者ENDP 2,其实就是一进一出,读数据写数据啦。 bulkonly协议呢,也分成三步其实思想都差不多。看看下面分析仪抓的包吧:
1:发31bytes告诉device我要干嘛,这里面肯定就是填些命令,什么命令呢就看device支持啥(我用的u盘就支持scsi命令),device收到好,就开始准备了。 2:要么是要device数据(例如usb读操作)要么就是给device数据(写操作)。 3:收13bytes 判断这次传输的状态,是好是坏。
一切传输都比较顺利的话,还是比较简单的,但是要考虑到里面很多出错处理,例如中断的丢失,要让整个系统运行起来还是比较烦的。
下次有空结合linux源码分析分析里面的传输,包括链链表,删链表,软件和硬件的握手,这里赞下linux的源码,写的确实牛。 |