USB 驱动程序开发之几个重要函数分析

来源:互联网 发布:软件企业认定证书 编辑:程序博客网 时间:2024/05/23 23:00

  下面介绍的函数都出自以下的Linux源码文件:

driver/usb/core/message.c

  该文件内包含许多关于同步信息处理的函数,具体内容在文件中都有注释介绍,该处我只选择在USB驱动程序设计中常用到的几个函数进行分析,当然,都是我个人理解,有问题请指教。

  另外,这里我想说,美国人真的很喜欢递归,不论是makefile文件的语法,还是编程习惯,几乎无处不用递归。他们总是从问题的根源开始,慢慢告知你这些东西的用处,写代码的时候,也是最基础的函数写在前,最终的大型函数在后。这里我就不再用这种方式去讲了,我还是从大的开始讲。

  

  1. usb_get_device_descriptor(struct usb_device *dev,unsigned int size)

    该函数的作用是:获取设备描述符,同时该函数是同步的,也就是说,不可用在中断上下文。

    函数主要做的事,就是内部调用了 usb_get_descriptor() 函数,下面会介绍。

  2. usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)

    该函数的作用是:获取设备的描述符,置于是什么类型的描述符,由 type 参数决定。

    函数主要做的事,就是内部调用了 usb_control_msg() 函数,下面会介绍。

  3. usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout)

    该函数的作用是:向设备发送控制信息,置于什么样的控制信息,由 request 和 requesttype 参数决定。

    函数主要做的事,就是内部调用了 usb_internal_control_msg() 函数,下面会介绍。

  4. static int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, struct usb_ctrlrequest *cmd, void *data, int len, int timeout)

    该函数的作用是:创建urb包,填充urb包,发送并等待urb包。

    从该函数开始,已经是比较底层的函数,不能随意被其他程序随意调用。一般的驱动程序 bulk 和 control 数据包的发送只需要用到 usb_control_msg 和 usb_bulk_msg 就可以。但是,研究这个函数有个很大的好处,就是可以理解urb数据包的整个处理过程,对理解urb很有帮助。

    该函数中在填充urb包时,在 usb_fill_control_urb 调用的时候,给 complete_t 参数赋值为一个很简单的 usb_api_blocking_completion 函数,该函数只是让 urb 的成员变量 context 完成,但是这有什么用呢?其实,这是整个 urb 操作的关键所在。

 

    我这里讲的只是我自己的理解,必定有错误的地方,高手见了请不惜赐教。

    我们知道整个处理 urb  包的过程是:创建,填充,发送,释放。

    在发送出urb包之后,貌似我们不需要做什么处理,USB CORE就会帮我们将我们需要的数据返回到我们提交给它的Buff里。但是,在填充urb时,我尝试给 complete_t 参数赋值为NULL,出现了许许多多错误。最终考虑到他的重要性认为是这么一个原因:我们填充完urb之后,给系统提交,提交的函数 usb_submit_urb 会立即返回,返回的结果只是告知我们是否发送,大多情况下是0,即成功。但是,urb提交之后,未必就拿到了 usb core 给予的数据,我们需要等待urb真正传输完毕之后,才能对其进行操作,怎么确定其是否真正传输完毕呢?就是利用 complete_t 参数,该参数指向一个函数,也就是,在urb真正传输完毕后,会调用该函数,从上面知道,该函数只是简单的让 urb 的 context 成员完成。我们回到 usb_internal_control_msg 函数中,发现其调用了 usb_start_wait_urb 函数。

    usb_start_wait_urb 函数初始化了 urb->context,并等待它的结束才进行对 urb 的真正处理,由此可见,如果我们没有等到 urb 真正传输结束就对其进行操作,操作在大部分情况下都会返回错误,因为外设的速度远远比不上CPU的执行速度。

    最终总结成一句话,发送urb包后,要等待其真正处理完毕才能进行我们自己想要它实现的操作,利用 urb->context 对这个过程进行控制是一种非常好的方式。

 

    初学的朋友可能还有疑问说是,usb_get_descriptor 等函数怎么知道要获取哪种描述符呢?这就利用到了参数 type 。这个参数的可选值很多,详情参看以下linux源码,文件中讲述了很多宏定义,与linux USB驱动程序设计有很大关联,建议好好看看。

                include/linux/usb_ch9.h