当前位置: 代码迷 >> 综合 >> usb-skeleton 代码分析
  详细解决方案

usb-skeleton 代码分析

热度:13   发布时间:2024-03-08 11:39:41.0

usb-skeleton 代码分析

文章目录

  • usb-skeleton 代码分析
    • 驱动注册
    • 主端探测函数 probe
    • 设备操作集
      • 打开设备
      • 关闭设备
      • 写操作
      • 读操作
      • flush

usb-skeleton.c是USB Host端代码的一个骨架,如果想要编写自己的Host端 bulk传输的代码,可以参考这个部分的代码进行编写,至于其他 isoc的传输方式,可能还需要参考其他的驱动代码进行编写。

当前内核版本linux-4.9.37

驱动注册

使用module_usb_driver注册HOST端驱动,声明匹配的gadget驱动列表(主要依赖VID与PID),完善相关的探测、断开连接等函数:
在这里插入图片描述

主端探测函数 probe

看一下skel_probe的第一部分里面做了什么:遍历接口的当前配置的所有端点,找到bulk in端点地址并申请urb传输描述符。

在这里插入图片描述

一开始用到的usb_skel结构体如下,成员变量大部分都有注释,主要的也增加了中文的注释。

在这里插入图片描述

再看一下第二部分的skel_probe,主要是执行一个USB设备注册,传入一个struct usb_class_driver类型的skel_class
在这里插入图片描述

看一下skel_class的内容,主要关注是设备的操作集合skel_fops

在这里插入图片描述

设备操作集

看一下skel_fops的概况,主要关注打开、关闭、读写和flush函数。

在这里插入图片描述

打开设备

skel_open()根据传入的inode节点,找到次设备号后,使用次设备号找到对应的设备接口,再从设备接口中找到私有的usb_skel结构体指针,并保存在file结构体中,方便后续read/write等函数使用。

在这里插入图片描述

关闭设备

skel_release()主要作用是释放资源。

在这里插入图片描述

看一下skel_delete(),就是各种资源的释放。

在这里插入图片描述

写操作

函数分为三个部分截图,看第一部分,这里主要就是一些参数的检查,以及如果上一次传输错误的话直接报告出错。

在这里插入图片描述

看第二部分的工作就是申请urb,申请内核态的内存,并将用户态的数据拷贝过来,填充urb的回调函数等信息后提交给硬件控制器。copy_form_user/copy_to_user是比较耗时的工作,如果想要提高传输的效率,可以考虑将这个拷贝部分去掉,比如使用mmap方式;有些特殊情况可以更加方便,比如MMZ的内存可以直接将码流的物理地址交给USB驱动,然后也不需要进行DMA映射,填充urb直接交给USB控制器,就可以进行传输,省略拷贝的过程速度提高是很可观的。
在这里插入图片描述

看第三部分主要是urb的释放以及出错处理。

在这里插入图片描述

看一下填充urb时的回调函数skel_write_bulk_callback(),内容也比较简单,如果有错误,保存错误码;释放申请的一致性内存。

在这里插入图片描述

读操作

读操作和写操作有些不一样,我们一般的read操作是阻塞的,而write操作直接提交给USB控制器之后就可以了,而阻塞的read需要等待数据的回来并报告应用层。

这里也分为两部分,看第一部分,进行检查相关的参数后,如果发现正在等待数据回来的过程,不是阻塞IO的则返回-EAGAIN,阻塞IO的话则等待读等待队列的唤醒。

在这里插入图片描述

第二部分就是根据用户空间要读取的数据和已经读取到数据的数量,进行发起实际的IO操作。

在这里插入图片描述

在这里插入图片描述

看一下实际发起IO操作的函数skel_do_read_io(),也是填充urb并提交给控制器,以及私有的数据初始化。

在这里插入图片描述

以及读回调函数skel_read_bulk_callback(),与写回掉函数的差异多了实际接收长度的记录以及唤醒等待队列。

在这里插入图片描述

flush

至于这个skel_flush()函数,主要就是调用skel_draw_down()进行停止相关的传输,如果有错误的话将错误返回。

在这里插入图片描述

skel_draw_down()函数等待以及提交的写urb返回,如果超时则停止;同时停止读的urb

在这里插入图片描述

至此整个代码就基本分析完成了,关于控制器驱动部分,比较复杂,有机会再写些文档分析一下,其实这个代码我进行修改来适配从端的驱动,当前从端的驱动也有修改,主要作用是将MMZ码流从一端传输到另一端,中间的优化过程就是上面的省略拷贝的过程。