编写设备驱动程序

基本设备访问

本节介绍如何访问 USB 设备以及如何注册客户机驱动程序。本节还将讨论描述符树。

连接客户机驱动程序之前

在连接客户机驱动程序之前发生下列事件:

  1. PROM (OBP/BIOS) 和 USBA 框架在连接任何客户机驱动程序之前获取访问设备的权限。

  2. 集线器驱动程序将在其集线器的每个端口上探测设备的标识和配置。

  3. 将打开每个设备的缺省控制管道,并探测每个设备的设备描述符。

  4. 使用设备和接口描述符为每个设备构建兼容名称属性。

兼容名称属性定义可单独绑定到客户机驱动程序的设备的不同部分。可以将客户机驱动程序绑定到整个设备或仅绑定到一个接口。请参见绑定客户机驱动程序

描述符树

解析描述符涉及在自然边界对齐结构成员,以及将结构成员转换为主机 CPU 的字节序。解析后的标准 USB 配置描述符、接口描述符和端点描述符可用于每种配置的分层树格式的客户机驱动程序。任何特定于原始类或特定于供应商的描述符信息也可用于同一分层树中的客户机驱动程序。

调用 usb_get_dev_data(9F) 函数可检索分层描述符树。usb_get_dev_data (9F) 手册页的“另请参见”部分列出了每个标准 USB 描述符的手册页。使用 usb_parse_data(9F) 函数可解析原始描述符信息。

具有两种配置的设备的描述符树可能与下图中所示的树类似。

图 20–3 分层 USB 描述符树

图中显示了每个接口(具有两种配置的设备的每个接口)的描述符对树。

上图中所示的 dev_cfg 数组包含对应于相应配置的节点。每个节点包含以下信息:

表示第二个索引配置的第二个接口的节点位于图中的 dev_cfg[1].cfg_if[1] 位置。该节点包含表示该接口的替代设置的节点数组。USB 描述符的分层结构通过该树传播。字符串描述符数据中的 ASCII 字符串连接到 USB 规范说明的存在这些字符串的位置。

配置数组是非稀疏数组,按配置索引进行索引。第一个有效配置(配置 1)是 dev_cfg[0]。接口和替代设置具有与其编号对齐的索引。对于每个替代设置的端点,都以连续方式进行索引。每个替代设置的第一个端点位于索引 0 位置。

此编号方案使得很容易对树进行遍历。例如,端点索引为 0、替代项为 0、接口为 1、配置索引为 1 的原始描述符数据位于以下路径定义的节点:

dev_cfg[1].cfg_if[1].if_alt[0].altif_ep[0].ep_descr

另一种直接使用描述符树的方法是使用 usb_lookup_ep_data(9F) 函数。usb_lookup_ep_data(9F) 函数采用接口、替代项、端点、端点类型和指令作为参数。您可以使用 usb_lookup_ep_data(9F) 函数遍历描述符树以获取特定端点。有关更多信息,请参见 usb_get_dev_data(9F) 手册页。

注册驱动程序以获取设备访问权限

在 USBA 2.0 框架中,客户机驱动程序执行的前两个调用是对 usb_client_attach(9F) 函数和 usb_get_dev_data(9F) 函数的调用。这两个调用来自客户机驱动程序的 attach(9E) 入口点。在调用 usb_get_dev_data(9F) 函数之前,必须先调用 usb_client_attach(9F) 函数。

usb_client_attach(9F) 函数用于向 USBA 2.0 框架注册客户机驱动程序。usb_client_attach(9F) 函数用于强制进行版本控制。所有客户机驱动程序源文件必须使用下列行开头:


#define USBDRV_MAJOR_VER        2
#define USBDRV_MINOR_VER        minor-version
#include <sys/usb/usba.h>

minor-version 的值必须小于或等于 USBA_MINOR_VER。符号 USBA_MINOR_VER<sys/usb/usbai.h> 头文件中定义。<sys/usb/usbai.h> 头文件通过 <sys/usb/usba.h> 头文件包含进来。

USBDRV_VERSION 是根据 USBDRV_MAJOR_VERSIONUSBDRV_MINOR_VERSION 生成版本号的宏。usb_client_attach() 的第二个参数必须是 USBDRV_VERSION。如果第二个参数不是 USBDRV_VERSION,或者如果 USBDRV_VERSION 反映的是无效的版本,则 usb_client_attach() 函数将失败。此限制可确保编程接口兼容性。

usb_get_dev_data() 函数可返回正确管理 USB 设备所需的信息。例如,usb_get_dev_data() 函数返回以下信息:

必须调用 usb_get_dev_data() 函数。调用 usb_get_dev_data() 是检索缺省控制管道以及检索互斥锁初始化所需的 iblock_cookie 的唯一方法。

调用 usb_get_dev_data() 后,客户机驱动程序的 attach(9E) 例程通常会将所需的描述符和 数据从描述符树复制到驱动程序的软状态。复制到软状态的端点描述符在以后打开到这些端点的管道时会用到。attach(9E) 例程通常在复制描述符后调用 usb_free_descr_tree(9F) 以释放描述符树。或者,可以选择保留描述符树,且不复制描述符。

可以为 usb_get_dev_data(9F) 函数指定以下三个解析级别之一,以请求想要返回的描述符树的广度。如果驱动程序需要绑定到的对象不仅仅是设备,则需要更大的树广度。

客户机驱动程序的 detach(9E) 例程必须调用 usb_free_dev_data(9F) 函数来释放由 usb_get_dev_data() 函数分配的所有资源。usb_free_dev_data() 函数接受已使用 usb_free_descr_tree() 函数释放了描述符树的句柄。客户机驱动程序的 detach() 例程还必须调用 usb_client_detach(9F) 函数以释放由 usb_client_attach(9F) 函数分配的所有资源。