乾坤合一:Linux设备驱动之USB主机和设备驱动

这一章从主机侧角度看到的USB 主机控制器驱动和设备驱动从主机侧的角度而言,需要编写的USB 驱动程序包括主机控制器驱动和设备驱动两类,USB 主机控制器驱动程序控制插入其中的USB 设备,而USB 设备驱动程序控制该设备如何作为从设备与主机通信。

1. Linux USB驱动层次

1.1 主机侧与设备侧USB 驱动

USB 采用树形拓扑结构,每条总线上只有一个主机控制器,负责协调主机和设备间的通信,而设备不能主动向主机发送任何消息。

1.2 设备、配置、接口、端点

在USB 设备的逻辑组织中,包含设备、配置、接口和端点4 个层次,每个USB 设备都提供了不同级别的配置信息,可以包含一个或多个配置,不同的配置使设备表现出不同的功能组合,配置由多个接口组成,接口由多个端点组成,代表一个基本的功能,是USB 设备驱动程序控制的对象,如下图是USB 设备、配置、接口和端点之间的关系。

设备描述符:关于设备的通用信息,如供应商ID 、产品ID 和修订ID,支持的设备类、子类和适用的协议以及默认端点的最大包大小等。在Linux 内核中,USB 设备用 usb_device 结构体来描述,USB 设备描述符定义为usb_device_descriptor 结构体,其代码如下:

配置描述符:此配置中的接口数、支持的挂起和恢复能力以及功率要求。USB配置在内核中使用usb_host_config 结构体描述,USB 配置描述符定义为结构体usb_config_descriptor,其代码如下:

接口描述符:接口类、子类和适用的协议,接口备用配置的数目和端点数目。USB接口在内核中使用 usb_interface 结构体描述,USB 接口描述符定义为结构体 usb_interface_descriptor,其代码如下:

端点描述符:端点地址、方向和类型,支持的最大包大小,如果是中断类型的端点则还包括轮询频率。在 Linux 内核中,U SB 端点使用 usb_host_endpoint 结构体来描述,USB端点描述符定义为 usb_ endpoint_ descriptor 结构体,其代码如下:

字符串描述符:在其他描述符中会为某些字段提供字符串索引,它们被用来检索描述性字符串,可以以多种语言形式提供。字符串描述符是可选的,有的设备有,有的设备没有 ,字符 串描述符对应于usb_string_ descriptor 结构体,其代码如下:

2 USB主机驱动

USB 主机控制器有 3 种规格:OHCI (Open Host Controller Interface) 、UHCI (Universal Host Controller Interface) 和EHCI (Enhanced Host Controller Interface) 。

2.1 主机控制器驱动

在Linux 内核中,用usb_hcd 结构体描述USB 主机控制器驱动,它包含USB 主机控制器的 “家务”信息、硬件资源、状态描述和用于操作主机控制器的 hc_driver等,其代码如下:

Linux中采用以下函数创建HCD:

以下函数用来增加和移除:

2.2 OHCI 主机控制器驱动

OHCI HCD 驱动属于HCD 驱动的实例,它定义了一个ohci_hcd 结构体,使用如下内联函数可实现usb_hcd 和ohci_hcd 的相互转换:

从usb_hcd 得到ohci_hcd 只是取得“私有”数据,而从ohci_hcd 得到usb_hcd 则是通过container_of()从结构体成员获得结构体指,使用如下函数可初始化OHCI 主机控制器:

如下函数分别用于开启、停止及复位OHCI 控制器:

3 USB设备驱动

3.1 USB设备驱动整体结构

有以下设备类

  • 音频设备类。
  • 通信设备类。
  • HID (人机接口)设备类。
  • 显示设备类。
  • 海量存储设备类。
  • 电源设备类。
  • 打印设备类。
  • 集线器设备类。

Linux 内核为各类USB 设备分配了相应的设备号,内核中提供了USB 设备文件系统 (usbdevfs,Linux 2.6 改为usbfs,即USB 文件系统),它和/proc 类似,都是动态产生的。通过在/etc/fstab 文件中添加如下一行:

或者输入命令:

可以实现USB 设备文件系统的挂载。

此外,在sysfs 文件系统中,同样包含了USB 相关信息的描述,但只限于接口级别。USB 设备和USB 接口在sysfs 中均表示为单独的USB 设备,其目录命名规则如下:

根集线器-集线器端口号 (-集线器端口号-…):配置.接口。

3.2 USB请求块(URB)

USB 请求块 (USB request block,urb )是USB 设备驱动中用来描述与USB 设备通信所用的基本载体和核心数据结构,非常类似于网络设备驱动中的sk_buff 结构体,是USB 主机与设备通信的 “电波”,urb 结构体,代码如下:

USB 设备中的每个端点都处理一个urb 队列,在队列被清空之前,一个urb 的典型生命周期有以下几个过程:

  1. 被一个 USB设备驱动创建
  2. 初始化,被安排给一个特定USB 设备的特定端点
  3. 被USB 设备驱动提交给USB
  4. 提交由USB 核心指定的USB 主机控制器驱动。
  5. 被USB 主机控制器处理,进行一次到USB 设备的传送。
  6. 当urb 完成,USB 主机控制器驱动通知USB 设备驱动

3.3 简单的批量与控制URB

1)usb_bulk_msg()

usb_bulk_msg()函数创建一个USB 批量urb 并将它发送到特定设备,这个函数是同步的,它一直等待urb 完成后才返回。usb_bulk_msg()函数的原型为:


// 如果函数调用成功,返回0 ;否则,返回1 个负的错误值。

2 )usb_control_msg()函数

usb_control_msg() 函数与 usb_bulk_msg() 函数类似,不过它提供驱动发送和结束USB 控制信息而非批量信息的能力,该函数的原型为:

3) 探测和断开函数

在USB 设备驱动usb_driver 结构体的探测函数中,应该完成如下工作:

  • 探测设备的端点地址、缓冲区大小,初始化任何可能用于控制 USB 设备的数据结构。
  • 把已初始化数据结构的指 保存到接口设备中
  • 注册USB 设备

对探测函数的调用发生在USB 设备被安装且USB 核心认为该驱动程序与安装的USB 设备对应时 (usb_driver 的id_table 成员在此时发挥作用),而对断开函数的调用则发生在驱动因为种种原因不再控制该设备的时候。对这两个函数的调用都是在内核线程中进行的.

4) USB 骨架程序

Linux 内核源代码中的 driver/usb/usb-skeleton.c 文件为我们提供了一个最基础的USB 驱动程序,即USB 骨架程序,可被看做一个最简单的USB 设备驱动实例。尽管USB驱动驱动程序千差万别,但是骨架程序万变不离其宗。这里我也不多介绍啦~

打赏支持我写出更多好文章,谢谢!

打赏作者

打赏支持我写出更多好文章,谢谢!

任选一种支付方式

1 1 收藏 评论

关于作者:李辉

湖南省天杰信息技术有限公司创始人之一,主要从事基站智能门禁锁、智能蓝牙锁、智慧商城等等的研发。在2015年1月完成《24小时学通Linux内核》的写作,目前其关于嵌入式Linux 驱动的写作仍在进行中。 个人主页 · 我的文章 · 2 ·    

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部