编写设备驱动程序

第 20 章 USB 驱动程序

本章介绍如何使用 Solaris 环境的 USBA 2.0 框架编写客户机 USB 设备驱动程序。本章讨论以下主题:

Solaris 环境中的 USB

Solaris USB 体系结构包括 USBA 2.0 框架和 USB 客户机驱动程序。

USBA 2.0 框架

USBA 2.0 框架是向符合 USBA 标准的客户机驱动程序呈现 USB 设备的抽象表示方式的服务层。利用该框架,符合 USBA 标准的客户机驱动程序可以管理其 USB 设备。USBA 2.0 框架支持除高速等时管道之外的 USB 2.0 规范。有关 USB 2.0 规范的信息,请参见 http://www.usb.org/home

USBA 2.0 框架与平台无关。下图显示了 Solaris USB 体系结构。在该图中,USBA 2.0 框架即是 USBA 层。此层通过与硬件无关的主机控制器驱动程序接口连接到特定于硬件的主机控制器驱动程序。主机控制器驱动程序通过其管理的主机控制器访问 USB 物理设备。

图 20–1 Solaris USB 体系结构

图中显示了从客户机和集线器驱动程序经由 USB 体系结构接口,然后到控制器和设备的控制流。

USB 客户机驱动程序

USBA 2.0 框架本身不是设备驱动程序。本章介绍图 20–1图 20–2 中所示的客户机驱动程序。客户机驱动程序与各种类型的 USB 设备(如海量存储设备、打印机和人机接口设备)交互。集线器驱动程序是同时充当结点驱动程序的客户机驱动程序,它枚举其端口上的设备,并为这些设备创建 devinfo 节点,然后连接客户机驱动程序。本章并未介绍如何编写集线器驱动程序。

USB 驱动程序的结构与其他任何 Solaris 驱动程序相同。USB 驱动程序可以是块驱动程序、字符驱动程序或 STREAMS 驱动程序。USB 驱动程序遵循调用约定,并使用 Solaris OS 手册页第 9 节中说明的数据结构和例程。请参见 Intro(9E)Intro(9F)Intro(9S)

USB 驱动程序与其他 Solaris 驱动程序的差别在于,USB 驱动程序通过调用 USBA 2.0 框架函数来访问设备,而不是直接访问设备。USBA 2.0 框架是对标准 Solaris DDI 例程的补充。请参见下图。

图 20–2 驱动程序和控制器接口

图中显示了 DDI 和 USBAI 函数、不同版本的 USBA 框架和不同类型的主机控制器。

图 20–2图 20–1 更为详细地显示了接口。图 20–2 显示 USBA 是客户机驱动程序可以调用的内核子系统,正如客户机驱动程序可以调用 DDI 函数一样。

并非所有系统都具有图 20–2 中所示的所有主机控制器接口。OHCI(Open Host Controller Interface,开放式主机控制器接口)硬件在 SPARC 系统和第三方 USB PCI 卡上最常见。UHCI(Universal Host Controller Interface,通用主机控制器接口)硬件在 x86 系统上最常见。但是,OHCI 和 UHCI 硬件都可以在任何系统上使用。当存在 EHCI(Enhanced Host Controller Interface,增强型主机控制器接口)硬件时,EHCI 硬件与 OHCI 或 UHCI 位于相同的卡上,并共享相同的端口。

主机控制器、主机控制器驱动程序和 HCDI 构成由 USBA 控制的传输层。您不能直接调用 OHCI、EHCI 或 UHCI。可通过与平台无关的 USBA 接口间接调用它们。

绑定客户机驱动程序

本节讨论如何将驱动程序绑定到设备,还讨论具有单个接口的设备和具有多个接口的设备的兼容设备名称。

USB 设备如何显示在系统中

一个 USB 设备可以支持多种配置。在任何给定时间,只有一种配置处于活动状态。活动配置称为当前配置

一种配置可以具有多个接口,其间可能具有针对一个函数分组两个或更多接口的介入式接口关联。一种配置的所有接口同时处于活动状态。不同的接口可由不同的设备驱动程序操作。

接口可以使用替代设置以不同的方式在主机系统中呈现自己。对于任何给定接口只能有一种替代设置处于活动状态。

每种替代设置通过端点提供设备访问。每个端点都有特定用途。主机系统通过建立到端点的通信通道来与设备通信。此通信通道称为管道

USB 设备和 Solaris 设备树

如果 USB 设备具有一种配置、一个接口,没有设备类,则可将该设备表示为单个设备节点。如果 USB 设备具有多个接口,则可将该设备表示为分层设备结构。在分层设备结构中,每个接口的设备节点是顶层设备节点的子节点。例如,音频设备即是具有多个接口的设备,该设备向主机同时呈现为音频控制和音频流两种接口。音频控制接口和音频流接口可以分别由各自的驱动程序控制。

兼容设备名称

Solaris 软件基于每个设备中存储的标识信息为 USB 绑定生成有序的兼容设备名称列表。此信息包括设备类、子类、供应商 ID、产品 ID、修订版和协议。有关 USB 类和子类的列表,请参见 http://www.usb.org/home

采用此名称分层结构,可以在没有特定于设备的驱动程序时,绑定到相对较常用的驱动程序。特定于类的驱动程序即是常规驱动程序。以 usbif 开头的设备名称指定单个接口的设备。有关示例,请参见示例 20–1。USBA 2.0 框架定义设备的所有兼容名称。使用 prtconf 命令可显示这些设备名称,如示例 20–2 中所示。

以下示例显示了 USB 鼠标设备的兼容设备名称。此鼠标设备表示完全由单个驱动程序操作的组合节点。USBA 2.0 框架为此设备节点指定了示例中所示的名称(按所示顺序)。


示例 20–1 USB 鼠标的兼容设备名称

  1. 'usb430,100.102'      Vendor 430, product 100, revision 102
  2. 'usb430,100'          Vendor 430, product 100
  3. 'usbif430,class3.1.2' Vendor 430, class 3, subclass 1, protocol 2
  4. 'usbif430,class3.1'   Vendor 430, class 3, subclass 1
  5. 'usbif430,class3'     Vendor 430, class 3
  6. 'usbif,class3.1.2'    Class 3, subclass 1, protocol 2
  7. 'usbif,class3.1'      Class 3, subclass 1
  8. 'usbif,class3'        Class 3

请注意,上面示例中的名称按从最具体到最常规的顺序进行排列。第 1 项仅绑定到特定供应商的特定产品的特定修订版。第 3、4 和 5 项用于由供应商 430 生产的类 3 设备。第 6、7 和 8 项用于任何供应商生产的类 3 设备。绑定过程将按从上到下的顺序查找名称匹配项。要进行绑定,必须将驱动程序添加到其别名与上述其中一个名称匹配的系统。要获取在添加驱动程序时要绑定到的兼容设备名称的列表,请在 prtconf -vp 命令的输出中检查设备的 compatible 属性。

以下示例显示了键盘和鼠标的兼容属性列表。使用 prtconf -D 命令可显示绑定的驱动程序。


示例 20–2 列显配置命令显示的兼容设备名称


# prtconf -vD | grep compatible
            compatible: 'usb430,5.200' + 'usb430,5' + 'usbif430,class3.1.1'
+ 'usbif430,class3.1' + 'usbif430,class3' + 'usbif,class3.1.1' +
'usbif,class3.1' + 'usbif,class3'
            compatible: 'usb2222,2071.200' + 'usb2222,2071' +
'usbif2222,class3.1.2' + 'usbif2222,class3.1' + 'usbif2222,class3' +
'usbif,class3.1.2' + 'usbif,class3.1' + 'usbif,class3'

使用最具体的名称可以更准确地确定一个设备或一组设备的驱动程序。要绑定为特定产品的特定修订版编写的驱动程序,请尽可能使用最具体的名称匹配项。例如,如果您有由供应商 430 为其产品 100 的修订版 102 编写的 USB 鼠标驱动程序,则可以使用以下命令将该驱动程序添加到系统中:

add_drv -n -i '"usb430,100.102"' specific_mouse_driver

要添加为供应商 430 的任何 USB 鼠标(类 3、子类 1、协议 2)编写的驱动程序,请使用以下命令:

add_drv -n -i '"usbif430,class3.1.2"' more_generic_mouse_driver

如果安装这两个驱动程序并连接兼容设备,则系统会将正确的驱动程序绑定到所连接的设备。例如,如果安装这两个驱动程序,并连接供应商 430、型号 100、修订版 102 的设备,则此设备将绑定到 specific_mouse_driver。如果连接供应商 430、型号 98 的设备,则此设备将绑定到 more_generic_mouse_driver 。如果连接其他供应商的鼠标,则此设备也将绑定到 more_generic_mouse_driver。如果有多个驱动程序可供特定设备使用,则驱动程序绑定框架将选择与兼容名称列表中第一个兼容名称匹配的驱动程序。

具有多个接口的设备

复合设备是支持多个接口的设备。复合设备的每个接口都有一个兼容名称列表。此兼容名称列表可确保将最有效的驱动程序绑定到该接口。最常规的多接口项是 usb,device

对于 USB 音频复合设备,兼容名称如下:

1. 'usb471,101.100'     Vendor 471, product 101, revision 100
2. 'usb471,101'         Vendor 471, product 101
3. 'usb,device'         Generic USB device

名称 usb,device 是可表示任何整个 USB 设备的兼容名称。如果没有其他驱动程序请求该整个设备,则 usb_mid(7D) 驱动程序(USB 多接口驱动程序)将绑定到 usb,device 设备节点。usb_mid 驱动程序为物理设备的每个接口创建一个子设备节点。usb_mid 驱动程序还为每个接口生成一组兼容名称。生成的所有这些兼容名称都以 usbif 开头。系统将使用生成的这些兼容名称为每一个接口查找最佳的驱动程序。通过这种方法,可以将一个物理设备的不同接口绑定到不同的驱动程序。

例如,usb_mid 驱动程序通过多接口音频设备的 usb,device 节点名称绑定到该音频设备。然后 usb_mid 驱动程序创建特定于接口的设备节点。这些特定于接口的设备节点中的每个节点都有各自的兼容名称列表。对于音频控制接口节点,兼容名称列表可能类似于下例中所示的列表。


示例 20–3 USB 音频兼容设备名称

1. 'usbif471,101.100.config1.0' Vend 471, prod 101, rev 100, cnfg 1, iface 0
2. 'usbif471,101.config1.0'     Vend 471, product 101, config 1, interface 0
3. 'usbif471,class1.1.0'        Vend 471, class 1, subclass 1, protocol 0
4. 'usbif471,class1.1'          Vend 471, class 1, subclass 1
5. 'usbif471,class1'            Vend 471, class 1
6. 'usbif,class1.1.0'           Class 1, subclass 1, protocol 0
7. 'usbif,class1.1'             Class 1, subclass 1
8. 'usbif,class1'               Class 1

使用以下命令可将特定于供应商、特定于设备的客户机驱动程序(名为 vendor_model_audio_usb)绑定到特定于供应商、特定于设备的配置 1、接口 0 的接口兼容名称,如示例 20–3 中所示。

add_drv -n -i '"usbif471,101.config1.0"' vendor_model_audio_usb

使用以下命令可将名为 audio_class_usb_if_driver 的类驱动程序绑定到较常规的类 1、子类 1 的接口兼容名称,如示例 20–3 中所示:

add_drv -n -i '"usbif,class1.1"' audio_class_usb_if_driver

使用 prtconf -D 命令可显示设备及其驱动程序的列表。在以下示例中,prtconf -D 命令显示 usb_mid 驱动程序管理 audio 设备。usb_mid 驱动程序将 audio 设备拆分为多个接口。每个接口在 audio 设备名称下以缩进方式列出。对于缩进列表中所示的每个接口,prtconf -D 命令显示了哪个驱动程序管理该接口。

audio, instance #0 (driver name: usb_mid)
    sound-control, instance #2 (driver name: usb_ac)
    sound, instance #2 (driver name: usb_as)
    input, instance #8 (driver name: hid)

检查设备驱动程序绑定

文件 /etc/driver_aliases 包含对应于系统中已存在的绑定的项。/etc/driver_aliases 文件的每一行都有一个驱动程序名称,后面依次跟随一个空格和一个设备名称。使用此文件可检查现有的设备驱动程序绑定。


注 –

请不要手动编辑 /etc/driver_aliases 文件。使用 add_drv(1M) 命令可建立绑定。使用 update_drv(1M) 命令可更改绑定。


基本设备访问

本节介绍如何访问 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) 函数分配的所有资源。

设备通信

USB 设备的工作方式是通过称为管道的通信通道来传递请求。只有管道处于打开状态时您才能提交请求。也可以刷新、查询和关闭管道。本节讨论管道、数据传输和回调以及数据请求。

USB 端点

与四种类型的 USB 端点通信的四种类型的管道包括:

有关对应于这些端点的传输类型的更多信息,请参见 USB 2.0 规范的第 5 章或参见请求

缺省管道

每个 USB 设备都有称为缺省端点的特殊控制端点。其通信通道称为缺省管道。大多数(可能并非所有)设备的设置都通过此管道进行。许多 USB 设备使用此管道作为其唯一的控制管道。

usb_get_dev_data(9F) 函数为客户机驱动程序提供缺省控制管道。此管道将会被预先打开以适应在打开其他管道之前需要的任何特殊设置。此缺省控制管道的特殊性表现在以下方面:

其他管道(包括其他控制管道)必须明确打开且仅限独占打开。

管道状态

管道处于以下状态之一:

调用 usb_pipe_get_state(9F) 函数可检索管道的状态。

打开管道

要打开管道,请将对应于要打开的管道的端点描述符传递给 usb_pipe_open(9F) 函数。使用 usb_get_dev_data(9F)usb_lookup_ep_data(9F) 函数可检索描述符树中的端点描述符。usb_pipe_open(9F) 函数将句柄返回给管道。

打开管道时必须指定管道策略。管道策略包含并发异步操作的估计数量,这些并发异步操作要求使用此管道将需要的独立线程。线程的估计数量是回调期间可能发生的并行操作的数量。此估计值必须至少为 2。有关管道策略的更多信息,请参见 usb_pipe_open(9F) 手册页。

关闭管道

驱动程序必须使用 usb_pipe_close(9F) 函数关闭缺省管道之外的管道。usb_pipe_close(9F) 函数使管道中的所有剩余请求得以完成。然后该函数还留出一秒钟的时间让这些请求的所有回调得以完成。

数据传输

对于所有管道类型,编程模型如下:

  1. 分配请求。

  2. 使用管道传输函数之一提交该请求。请参见 usb_pipe_bulk_xfer(9F)usb_pipe_ctrl_xfer(9F)usb_pipe_intr_xfer(9F)usb_pipe_isoc_xfer(9F) 手册页。

  3. 等待完成通知。

  4. 释放请求。

有关请求的更多信息,请参见请求。以下各节介绍各种请求类型的特性。

同步传输、异步传输和回调

传输分为同步传输和异步传输。同步传输在完成之前将会一直阻塞。异步传输完成时,将向客户机驱动程序发送回调。在 flags 参数中设置了 USB_FLAGS_SLEEP 标志时调用的传输函数大多数是同步的。

连续传输(如轮询)和等时传输不能是同步的。为了进行连续传输而对传输函数进行的调用(设置了 USB_FLAGS_SLEEP 标志)将会阻塞,目的只是等待资源,然后开始传输。

同步传输是要设置的最简单的传输,因为同步传输不要求任何回调函数。同步传输函数将返回传输开始状态,即使同步传输函数在完成传输前一直阻塞也是如此。完成时,可以在请求的完成原因字段和回调标志字段中查找有关传输状态的其他信息。下面将讨论完成原因字段和回调标志字段。

如果未在 flags 参数中指定 USB_FLAGS_SLEEP 标志,则该传输操作是异步的。此规则的例外是等时传输。异步传输操作将设置并启动传输,然后在传输完成前返回。异步传输操作将返回传输开始状态。客户机驱动程序通过回调处理程序接收传输完成状态。

回调处理程序是在异步传输完成时调用的函数。不要设置不进行回调的异步传输。两种类型的回调处理程序是正常完成处理程序和异常处理程序。您可以指定一个在这两种情况下要调用的处理程序。

完成处理程序和异常处理程序将传输请求作为参数接收。异常处理程序在请求中使用完成原因和回调状态来了解所发生的情况。完成原因 (usb_cr_t) 指示原始事务是如何完成的。例如,完成原因 USB_CR_TIMEOUT 指示传输超时。又如,如果 USB 设备在使用时被移除,则客户机驱动程序可能接收 USB_CR_DEV_NOT_RESP 作为其未完成请求的完成原因。回调状态 (usb_cb_flags_t) 指示 USBA 框架为修正这种情况所执行的操作。例如,回调状态 USB_CB_STALL_CLEARED 指示 USBA 框架清除了运行延迟条件。有关完成原因的更多信息,请参见 usb_completion_reason(9S) 手册页。有关回调状态标志的更多信息,请参见 usb_callback_flags(9S) 手册页。

运行请求的回调上下文和管道策略会对在回调中可以执行的操作实施一些限制。

请求

本节讨论请求结构,以及分配和取消分配不同类型的请求。

分配和取消分配请求

请求以初始化的请求结构的形式实现。每种不同的端点类型接受不同类型的请求。每种类型的请求有不同的请求结构类型。下表显示了每种类型请求的结构类型。此表还列出了可用于分配和释放每种类型结构的函数。

表 20–1 请求初始化

管道或端点类型 

请求结构 

请求结构分配函数 

请求结构释放函数 

控制 

usb_ctrl_req_t(请参见 usb_ctrl_request(9S) 手册页)

usb_alloc_ctrl_req(9F)

usb_free_ctrl_req(9F)

批量传输 

usb_bulk_req_t(请参见 usb_bulk_request(9S) 手册页)

usb_alloc_bulk_req(9F)

usb_free_bulk_req(9F)

中断 

usb_intr_req_t(请参见 usb_intr_request(9S) 手册页)

usb_alloc_intr_req(9F)

usb_free_intr_req(9F)

等时 

usb_isoc_req_t(请参见 usb_isoc_request(9S) 手册页)

usb_alloc_isoc_req(9F)

usb_free_isoc_req(9F)

下表列出了可用于每种类型请求的传输函数。

表 20–2 请求传输设置

管道或端点类型 

传输函数 

控制 

usb_pipe_ctrl_xfer(9F)usb_pipe_ctrl_xfer_wait(9F)

批量传输 

usb_pipe_bulk_xfer(9F)

中断 

usb_pipe_intr_xfer(9F)usb_pipe_stop_intr_polling(9F)

等时 

usb_pipe_isoc_xfer(9F)usb_pipe_stop_isoc_polling(9F)

分配和取消分配请求的过程如下:

  1. 使用相应的分配函数为所需的请求类型分配请求结构。表 20–1 中列出了请求结构分配函数的手册页。

  2. 初始化结构中所需的任何字段。有关更多信息,请参见请求特性和字段或相应的请求结构手册页。表 20–1 中列出了请求结构的手册页。

  3. 完成数据传输时,使用相应的释放函数释放请求结构。表 20–1 中列出了请求结构释放函数的手册页。

请求特性和字段

所有请求的数据都以消息块的形式传递,这样,无论驱动程序是 STREAMS 驱动程序、字符驱动程序还是块驱动程序,都将统一地对数据进行处理。消息块类型 mblk_tmblk(9S) 手册页中进行了介绍。DDI 提供了多个用于处理消息块的例程。示例包括 allocb(9F)freemsg(9F)。要了解用于处理消息块的其他例程,请参见 allocb(9F) 和 freemsg(9F) 手册页的“另请参见”部分。此外,还可以参见《STREAMS Programming Guide》

所有传输类型中都包括以下请求字段。在每个字段名称中,xxxx 的可能值包括: ctrlbulkintrisoc

xxxx_client_private

此字段值是一个指针,适用于将与请求一起在客户机驱动程序中传递的内部数据。此指针不用于将数据传输到设备。 

xxxx_attributes

此字段值是一组传输属性。虽然此字段对所有请求结构通用,但对于每种传输类型,此字段的初始化稍有不同。有关更多信息,请参见相应的请求结构手册页。表 20–1 中列出了这些手册页。另请参见 usb_request_attributes(9S) 手册页。

xxxx_cb

此字段值是正常传输完成的回调函数。如果异步传输在没有错误的情况下完成,则会调用此函数。 

xxxx_exc_cb

此字段值是错误处理的回调函数。仅当异步传输完成且出现错误时,才会调用此函数。 

xxxx_completion_reason

此字段存放传输本身的完成状态。如果出现错误,此字段将显示出现错误的内容。有关更多信息,请参见 usb_completion_reason(9S) 手册页。此字段由 USBA 2.0 框架更新。

xxxx_cb_flags

此字段列出在调用回调处理程序之前 USBA 2.0 框架所采取的恢复操作。USB_CB_INTR_CONTEXT 标志指示回调是否在中断上下文中运行。有关更多信息,请参见 usb_callback_flags(9S) 手册页。此字段由 USBA 2.0 框架更新。

以下各节介绍针对四种不同传输类型的不同请求字段。其中介绍如何初始化这些结构字段,还介绍有关属性和参数的各种组合的限制。

控制请求

使用控制请求可沿控制管道向下启动消息传输。您可以手动设置传输,如下所示。也可以使用 usb_pipe_ctrl_xfer_wait(9F) 包装函数设置并发送同步传输。

客户机驱动程序必须初始化 ctrl_bmRequestType ctrl_bRequestctrl_wValue ctrl_wIndexctrl_wLength 字段,如 USB 2.0 规范中所述。

必须将请求的 ctrl_data 字段初始化为指向数据缓冲区。将一个正值作为缓冲区 len 传递时,usb_alloc_ctrl_req(9F) 函数将初始化此字段。当然,还必须初始化缓冲区以便进行任何外发传输。在所有情况下,完成传输时,客户机驱动程序必须释放请求。

可以对多个控制请求进行排队。排队的请求中可以包括同步请求和异步请求。

ctrl_timeout 字段定义等待要被处理的请求的最长时间,但不包括在队列中的等待时间。此字段适用于同步和异步请求。ctrl_timeout 字段中指定的值以秒为单位。

如果出现异常,ctrl_exc_cb 字段接受要调用的函数的地址。usb_ctrl_request(9S) 手册页中指定了此异常处理程序的参数。异常处理程序的第二个参数是 usb_ctrl_req_t 结构。通过将请求结构作为参数传递,异常处理程序可以检查该请求的 ctrl_completion_reasonctrl_cb_flags 字段,以确定最佳恢复操作。

USB_ATTRS_ONE_XFERUSB_ATTRS_ISOC_* 标志对所有控制请求而言都是无效属性。USB_ATTRS_SHORT_XFER_OK 标志仅对主机绑定的请求有效。

批量传输请求

使用批量传输请求可发送非时间关键数据。批量传输请求可以接纳多个要完成的 USB 帧,具体取决于总体总线负载。

所有请求必须接收已初始化的消息块。有关 mblk_t 消息块类型的说明,请参见 mblk(9S) 手册页。此消息块将提供数据或存储数据,具体取决于传输方向。有关更多详细信息,请参阅 usb_bulk_request(9S) 手册页。

USB_ATTRS_ONE_XFERUSB_ATTRS_ISOC_* 标志对所有批量传输请求而言都是无效属性。USB_ATTRS_SHORT_XFER_OK 标志仅对主机绑定的请求有效。

usb_pipe_get_max_bulk_transfer_size(9F) 函数指定每个请求的最大字节数。检索到的值可以是客户机驱动程序的 minphys(9F) 例程中使用的最大值。

可以对多个批量传输请求进行排队。

中断请求

中断请求通常用于定期传入数据。中断请求定期在设备中轮询数据。但是,USBA 2.0 框架支持一次性的传入中断数据请求以及外发中断数据请求。所有中断请求可以利用 USB 中断传输的及时与重试特性。

USB_ATTRS_ISOC_* 标志对所有中断请求而言都是无效属性。USB_ATTRS_SHORT_XFER_OKUSB_ATTRS_ONE_XFER 标志仅对主机绑定的请求有效。

只有一次性轮询可以作为同步中断传输执行。如果在请求中指定 USB_ATTRS_ONE_XFER 属性,将进行一次性轮询。

定期轮询是作为异步中断传输启动。原始中断请求将被传递到 usb_pipe_intr_xfer(9F)。当轮询操作找到要返回的新数据时,将从原始请求克隆一个新的 usb_intr_req_t 结构,并使用已初始化的数据块填充该结构。分配请求时,请为 usb_alloc_intr_req(9F) 函数的 len 参数指定零。len 参数为零是因为 USBA 2.0 框架将为每个回调分配新请求,并填充该请求。分配请求结构后,请填充 intr_len 字段,以指定希望框架为每个轮询分配的字节数。将不会返回超出 intr_len 字节的数据。

客户机驱动程序必须释放它接收的每个请求。如果逆向发送消息块,请在逆向发送消息块之前从请求中分离该消息块。要从请求中分离消息块,请将该请求的数据指针设置为 NULL。将请求的数据指针设置为 NULL,可在取消分配请求时阻塞释放消息块。

调用 usb_pipe_stop_intr_polling(9F) 函数可取消定期轮询。停止轮询或关闭管道时,将通过异常回调返回原始请求结构。此返回的请求结构的完成原因将被设置为 USB_CR_STOPPED_POLLING

请不要在轮询进行过程中启动轮询。也不要在调用 usb_pipe_stop_intr_polling(9F) 的过程中启动轮询。

等时请求

等时请求用于速率恒定、与时间相关的流数据。出现错误时不会进行重试。等时请求具有以下特定于请求的字段:

isoc_frame_no

当必须从特定的帧编号启动总体传输时,请指定此字段。此字段的值必须大于当前帧编号。使用 usb_get_current_frame_number(9F) 可查找当前帧编号。请注意,当前帧编号为活动目标。对于低速和全速总线,将每 1 毫秒更新一次当前帧。对于高速总线,将每 0.125 毫秒更新一次当前帧。应设置 USB_ATTR_ISOC_START_FRAME 属性以便可以识别 isoc_frame_no 字段。

要忽略此帧编号字段并尽快启动,请设置 USB_ATTR_ISOC_XFER_ASAP 标志。

isoc_pkts_count

此字段是请求中的包数。此值受由 usb_get_max_pkts_per_isoc_request(9F) 函数返回的值和 isoc_pkt_descr 数组(参见下面的内容)的大小限制。该请求中可传输的字节数等于此 isoc_pkts_count 值与端点的 wMaxPacketSize 值的乘积。

isoc_pkts_length

此字段是请求的所有包的长度之和。此值由启动器设置。应将此值设置为零,以便自动使用 isoc_pkt_descr 列表中 isoc_pkts_length 的和,而不对此元素应用任何检查。

isoc_error_count

此字段是完成时出现错误的包数。此值由 USBA 2.0 框架设置。 

isoc_pkt_descr

此字段指向定义每个包传输数据量的包描述符的数组。对于传出请求,此值定义要处理的子请求的专用队列。对于传入请求,此值描述数据块的到达方式。客户机驱动程序将为传出请求分配这些描述符。框架将为传入请求分配和初始化这些描述符。此数组中的描述符包含框架初始化的字段,这些字段存储实际传输的字节数和传输的状态。有关更多详细信息,请参见 usb_isoc_request(9S) 手册页。

所有请求都必须接收已初始化的消息块。此消息块提供数据或存储数据。有关 mblk_t 消息块类型的说明,请参见 mblk(9S) 手册页。

USB_ATTR_ONE_XFER 标志是非法属性,因为系统将决定如何通过可用包数改变数据量。USB_ATTR_SHORT_XFER_OK 标志仅对主机绑定的数据有效。

无论是否设置 USB_FLAGS_SLEEP 标志,usb_pipe_isoc_xfer(9F) 函数都会使所有等时传输成为异步传输。所有等时输入请求都将启动轮询。

调用 usb_pipe_stop_isoc_polling(9F) 函数可取消定期轮询。停止轮询或关闭管道时,将通过异常回调返回原始请求结构。此返回的请求结构的完成原因将被设置为 USB_CR_STOPPED_POLLING

轮询会一直继续,直到发生以下某个事件:

刷新管道

您可能需要在出现错误后清理管道,或者可能想要等待管道清除。可使用下列方法之一刷新或清除管道:

设备状态管理

管理 USB 设备具体涉及到热插拔、系统电源管理(检查点和恢复)以及设备电源管理这几方面。所有客户机驱动程序应实现下图中所示的基本状态机。有关更多信息,请参见 /usr/include/sys/usb/usbai.h

图 20–4 USB 设备状态机

图中显示了在七个不同事件中的每个事件之后设备进入的状态。

可以使用特定于驱动程序的状态扩充此状态机及其四种状态。可以定义设备状态 0x800xff,且只有客户机驱动程序可以使用这些状态。

热插拔 USB 设备

USB 设备支持热插拔。可以随时插入或移除 USB 设备。客户机驱动程序必须处理打开的设备的移除和重新插入。使用热插拔回调可处理打开的设备。关闭的设备的插入和移除由 attach(9E)detach(9E) 入口点处理。

热插拔回调

USBA 2.0 框架支持以下事件通知:

客户机驱动程序必须在其 attach(9E) 例程中调用 usb_register_hotplug_cbs(9F),以便注册事件回调。在中断之前,驱动程序必须在其 detach(9E) 例程中调用 usb_unregister_hotplug_cbs(9F)

热插入

USB 设备的热插入的事件顺序如下:

  1. 集线器驱动程序 hubd(7D) 等待端口连接状态发生变化。

  2. hubd 驱动程序检测到端口连接。

  3. hubd 驱动程序枚举设备,创建子设备节点,然后连接客户机驱动程序。有关兼容名称的定义,请参阅绑定客户机驱动程序

  4. 客户机驱动程序管理设备。驱动程序处于 ONLINE 状态。

热移除

USB 设备的热移除的事件顺序如下:

  1. 集线器驱动程序 hubd(7D) 等待端口连接状态发生变化。

  2. hubd 驱动程序检测到端口断开连接。

  3. hubd 驱动程序将断开连接事件发送到子客户机驱动程序。如果子客户机驱动程序是 hubd 驱动程序或 usb_mid(7D) 多接口驱动程序,则子客户机驱动程序将该事件传播到其子级。

  4. 客户机驱动程序在内核线程上下文中接收断开连接事件通知。内核线程上下文使驱动程序的断开连接处理程序进入阻塞状态。

  5. 客户机驱动程序将转为 DISCONNECTED 状态。未完成的 I/O 传输将失败,完成原因为 device not responding。所有新 I/O 传输以及打开设备节点的尝试也将失败。要关闭管道,不需要客户机驱动程序。而要保存设备以及重新连接设备时需要恢复的驱动程序上下文,需要客户机驱动程序。

  6. hubd 驱动程序试图按照从下到上的顺序使 OS 设备节点及其子节点脱机。

如果在 hubd 驱动程序试图使设备节点脱机时,未打开该设备节点,则会发生以下事件:

  1. 将调用客户机驱动程序的 detach(9E) 入口点。

  2. 销毁设备节点。

  3. 新设备可以使用相应端口。

  4. 重新开始热插拔事件序列。hubd 驱动程序等待端口连接状态发生变化。

如果在 hubd 驱动程序试图使设备节点脱机时已打开该设备节点,则会发生以下事件:

  1. hubd 驱动程序将脱机请求放入定期脱机重试队列。

  2. 新设备仍然不可使用相应端口。

如果在 hubd 驱动程序试图使设备节点脱机时,已打开该设备节点,但用户稍后关闭了该设备节点,则 hubd 驱动程序定期使该设备节点脱机将成功,且会发生以下事件:

  1. 将调用客户机驱动程序的 detach(9E) 入口点。

  2. 销毁设备节点。

  3. 新设备可以使用相应端口。

  4. 重新开始热插拔事件序列。hubd 驱动程序等待端口连接状态发生变化。

如果用户关闭使用该设备的所有应用程序,则端口将重新变为可用。如果应用程序未终止或未关闭该设备,则端口仍然不可用。

热重新插入

如果将先前移除的设备重新插入同一端口,同时该设备的设备节点仍处于打开状态,则会发生以下事件:

  1. 集线器驱动程序 hubd(7D) 检测到端口连接。

  2. hubd 驱动程序恢复总线地址和设备配置。

  3. hubd 驱动程序取消脱机重试请求。

  4. hubd 驱动程序将连接事件发送到客户机驱动程序。

  5. 客户机驱动程序收到连接事件。

  6. 客户机驱动程序确定新设备是否与先前连接的设备相同。客户机驱动程序首先通过比较设备描述符来进行此项确定。客户机驱动程序也可以比较序列号和配置描述符群。

如果客户机驱动程序确定当前设备与先前连接的设备不同,则可能会发生以下事件:

  1. 客户机驱动程序可能向控制台发出警告消息。

  2. 用户可能再次移除该设备。如果用户再次移除该设备,则将重新开始热移除事件序列。hubd 驱动程序检测到端口断开连接。如果用户没有再次移除该设备,则会发生以下事件:

    1. 客户机驱动程序仍然保持 DISCONNECTED 状态,所有请求和打开操作将失败。

    2. 端口仍然不可用。用户必须关闭设备并断开其连接以释放端口。

    3. 释放端口时,将重新开始热插拔事件序列。hubd 驱动程序等待端口连接状态发生变化。

如果客户机驱动程序确定当前设备与先前连接的设备相同,则可能会发生以下事件:

  1. 客户机驱动程序可能恢复其状态,并继续正常操作。此策略由客户机驱动程序负责。音频扬声器就是客户机驱动程序可继续操作的典型示例。

  2. 如果使用重新连接的设备继续操作是安全的,则将重新开始热插拔事件序列。hubd 驱动程序等待端口连接状态发生变化。设备再次可用。

电源管理

本节讨论设备电源管理和系统电源管理。

设备电源管理根据各个 USB 设备的 I/O 是处于活动状态还是空闲状态来管理这些设备。

系统电源管理使用检查点和恢复机制在文件中设置系统状态的检查点,然后完全关闭系统。(检查点有时称为“系统暂停”。)再次打开系统电源时,系统将恢复为其暂停前的状态。

设备电源管理

下面简要列出了要对 USB 设备进行电源管理时驱动程序需要执行的操作。后面对电源管理进行了较详细的说明。

  1. 在执行 attach(9E) 期间创建电源管理组件。请参见 usb_create_pm_components(9F) 手册页。

  2. 实现 power(9E) 入口点。

  3. 在访问设备之前调用 pm_busy_component(9F)pm_raise_power(9F)

  4. 完成设备访问后调用 pm_idle_component(9F)

USBA 2.0 框架支持 USB 接口电源管理规范指定的四种电源级别。有关 USB 电源级别与操作系统电源级别对应关系的信息,请参见 /usr/include/sys/usb/usbai.h

当设备进入 USB_DEV_OS_PWR_OFF 状态时,hubd 驱动程序将暂停端口。当设备进入 USB_DEV_OS_PWR_1 及以上状态时,hubd 驱动程序将恢复端口。请注意,端口暂停不同于系统暂停。端口暂停时,将仅关闭 USB 端口。系统电源管理中定义了系统暂停。

客户机驱动程序可以选择在设备上启用远程唤醒。请参见 usb_handle_remote_wakeup(9F) 手册页。当 hubd 驱动程序在端口上发现远程唤醒时,hubd 驱动程序将完成唤醒操作,并调用 pm_raise_power(9F) 以通知子级。

下图显示了电源管理的不同部分之间的关系。

图 20–5 USB 电源管理

图中显示了使用两种不同电源管理方案的时机。

驱动程序可以实现图 20–5 底部说明的两种电源管理方案之一。被动方案比主动方案简单,这是因为被动方案在设备传输期间不进行电源管理。

主动电源管理

本节介绍实现主动电源管理方案需使用的函数。

在驱动程序的 attach(9E) 入口点执行以下工作:

  1. 调用 usb_create_pm_components(9F)

  2. 可选择调用 usb_handle_remote_wakeup(9F)(使用 USB_REMOTE_WAKEUP_ENABLE 作为第二个参数),以在设备上启用远程唤醒。

  3. 调用 pm_busy_component(9F)

  4. 调用 pm_raise_power(9F) 以使功耗达到 USB_DEV_OS_FULL_PWR 级别。

  5. 与设备通信以初始化该设备。

  6. 调用 pm_idle_component(9F)

在驱动程序的 detach(9E) 入口点执行以下工作:

  1. 调用 pm_busy_component(9F)

  2. 调用 pm_raise_power(9F) 以使功耗达到 USB_DEV_OS_FULL_PWR 级别。

  3. 如果在 attach(9E) 入口点中调用了 usb_handle_remote_wakeup (9F) 函数,请在此处调用 usb_handle_remote_wakeup(9F)(使用 USB_REMOTE_WAKEUP_DISABLE 作为第二个参数)。

  4. 与设备通信以干净地关闭该设备。

  5. 调用 pm_lower_power(9F) 以使功耗达到 USB_DEV_OS_PWR_OFF 级别。

    这是唯一一次客户机驱动程序调用 pm_lower_power(9F)。

  6. 调用 pm_idle_component(9F)

当驱动程序线程要启动在设备上执行 I/O 操作时,该线程将执行以下任务:

  1. 调用 pm_busy_component(9F)

  2. 调用 pm_raise_power(9F) 以使功耗达到 USB_DEV_OS_FULL_PWR 级别。

  3. 开始 I/O 传输。

当驱动程序收到 I/O 传输已完成的通知时,驱动程序将调用 pm_idle_component(9F)

在驱动程序的 power(9E) 入口点中,检查您要转换到的电源级别是否有效。此外,还可能需要考虑同时调用 power(9E) 的不同线程。

如果设备已空闲一段时间或者系统正在关闭,则可以调用 power(9E) 例程以使设备进入 USB_DEV_OS_PWR_OFF 状态。此状态对应于图 20–4 中所示的 PWRED_DWN 状态。如果设备将进入 USB_DEV_OS_PWR_OFF 状态,请在 power(9E) 例程中执行以下工作:

  1. 使所有打开的管道进入空闲状态。例如,停止对中断管道进行的轮询。

  2. 保存任何设备或需要保存的驱动程序上下文。

    在完成 power(9E) 调用后,将暂停设备所连接到的端口。

收到设备启动的远程唤醒或系统启动的唤醒时,可以调用 power(9E) 例程以打开设备电源。由于超出空闲时间或系统暂停而关闭设备电源后,将会发生唤醒通知。如果设备将进入 USB_DEV_OS_PWR_1 或以上状态,请在 power(9E) 例程中执行以下工作:

  1. 恢复任何所需的设备和驱动程序上下文。

  2. 在管道中重新启动适合指定电源级别的活动。例如,对中断管道启动轮询。

如果先前暂停了设备所连接到的端口,则在调用 power(9E) 之前将恢复该端口。

被动电源管理

被动电源管理方案比上面介绍的主动电源管理方案简单。在此被动方案中,在传输期间不执行任何电源管理。要实现此被动方案,请在打开设备时调用 pm_busy_component(9F)pm_raise_power(9F)。然后在关闭设备时调用 pm_idle_component(9F)

系统电源管理

系统电源管理包括:在保存整个系统的状态后关闭系统,以及在重新打开系统后恢复状态。此过程称为 CPR(checkpoint and resume,检查点和恢复)。在 CPR 相关方面,USB 客户机驱动程序的运行方式与其他客户机驱动程序相同。要暂停设备,请在 cmd 参数为 DDI_SUSPEND 的情况下调用驱动程序的 detach(9E) 入口点。要恢复设备,请在 cmd 参数为 DDI_RESUME 的情况下调用驱动程序的 attach(9E) 入口点。处理 detach(9E) 例程中的 DDI_SUSPEND 命令时,请尽可能地清理设备状态和驱动程序状态,以满足后面清理恢复操作的需要。(请注意,这对应于图 20–4 中的 SUSPENDED 状态。)处理 attach(9E) 例程中的 DDI_RESUME 命令时,务必使设备达到全功率状态,以使设备与系统同步。

对于 USB 设备,暂停和恢复的处理与热插拔断开连接和重新连接类似(请参见热插拔 USB 设备)。CPR 与热插拔之间的重要差别是,在 CPR 的情况下,如果设备处于不可暂停的状态,驱动程序的检查点过程可能会失败。例如,如果设备正在进行错误恢复,则无法暂停设备。如果设备正忙,无法安全将其停止,也无法暂停该设备。

序列化

通常,驱动程序在持有互斥锁时不应调用 USBA 函数。因此,客户机驱动程序中的竞态条件可能很难防止。

不允许在处理异步事件(如断开连接或 CPR)的同时运行正常操作代码。这些类型的异步事件通常会清理和中断管道,可能会破坏正常操作代码。

一种管理竞态条件和保护正常操作代码的方法是,编写可以获取和释放独占访问同步对象的序列化工具。您可以按以下方法编写序列化工具:通过调用 USBA 函数安全地持有同步对象。usbskel 驱动程序样例中就采用了这种方法。有关 usbskel 驱动程序的信息,请参见USB 设备驱动程序样例

实用程序函数

本节介绍几个常规用途的函数。

设备配置工具

本节介绍与设备配置相关的函数。

获取接口编号

如果您使用的是多接口设备,usb_mid(7D) 驱动程序只会使其接口之一可用于调用驱动程序,此时您可能需要知道调用驱动程序所绑定到的接口的编号。使用 usb_get_if_number(9F) 函数执行以下任一任务:

管理整个设备

如果驱动程序管理整个复合设备,则可通过使用包含供应商 ID、产品 ID 和修订版 ID 的兼容名称将该驱动程序绑定到整个设备。绑定到整个复合设备的驱动程序必须像结点驱动程序一样管理该设备的所有接口。通常,不应将驱动程序绑定到整个复合设备。应改为使用一般的多接口驱动程序 usb_mid(7D)

使用 usb_owns_device(9F) 函数可确定驱动程序是否拥有整个设备。设备可以是复合设备。如果驱动程序拥有整个设备,则 usb_owns_device(9F) 函数将返回 TRUE

多配置设备

在任何特定时间,主机上只能使用 USB 设备的一种配置。大多数设备仅支持一种配置。但是,少数 USB 设备支持多种配置。

对于具有多种配置的任何设备,都是采用可使用某驱动程序的第一种配置。查找匹配项时,设备配置以数字顺序处理。如果未找到任何匹配的驱动程序,则设备将被设置采用第一种配置。在这种情况下,usb_mid 驱动程序将接管该设备,并将设备拆分为多个接口节点。使用 usb_get_cfg(9F) 函数可返回设备的当前配置。

您可以使用以下两种方法中的任何一种来请求采用其他配置。使用其中任何一种方法修改设备配置,均可确保 USBA 模块保持与设备同步。


注意 – 注意 –

不要通过手动执行 SET_CONFIGURATION USB 请求来更改设备配置。不支持使用 SET_CONFIGURATION 请求更改配置。


修改或获取替代设置

客户机驱动程序可以调用 usb_set_alt_if(9F) 函数以更改当前选定接口的选定替代设置。请确保关闭已明确打开的所有管道。切换替代设置时,usb_set_alt_if(9F) 函数将验证是否仅打开了缺省管道。确保在调用 usb_set_alt_if(9F) 之前已正确设置了设备。

更改替代设置可能会影响对驱动程序可用的端点以及特定于类和特定于供应商的描述符。有关端点和描述符的更多信息,请参见描述符树

调用 usb_get_alt_if(9F) 函数可检索当前替代设置的编号。


注 –

请求新替代设置、新配置或新接口时,必须关闭设备的除缺省管道外的所有管道。这是因为更改替代设置、配置或接口会更改设备的运行模式。此外,更改替代设置、配置或接口还会更改设备在系统中的呈现方式。


其他实用程序函数

本节介绍在 USB 设备驱动程序中有用的其他函数。

检索字符串描述符

调用 usb_get_string_descr(9F) 函数可检索给定了索引的字符串描述符。一些配置、接口或设备描述符具有关联的字符串 ID。这样的描述符包含具有非零值的字符串索引字段。将字符串索引字段值传递给 usb_get_string_descr(9F) 可检索对应的字符串。

管道专用数据工具

每个管道都有一个空间指针,专供客户机驱动程序使用。使用 usb_pipe_set_private(9F) 函数可安装一个值。使用 usb_pipe_get_private(9F) 函数可检索该值。当管道可能需要将其自己的客户机定义状态传递到回调,以进行特定处理时,此工具在回调中很有用。

清除 USB 条件

使用 usb_clr_feature(9F) 函数可执行以下任务:

获取设备、接口或端点状态

使用 usb_get_status(9F) 函数可发出 USB GET_STATUS 请求,以检索设备、接口或端点的状态。

获取设备的总线地址

使用 usb_get_addr(9F) 函数可获取设备的 USB 总线地址以用于调试目的。此地址映射到特定的 USB 端口。

USB 设备驱动程序样例

本节介绍使用 Solaris 环境的 USBA 2.0 框架的 USB 设备驱动程序模板。此驱动程序演示了本章中讨论的许多功能。此模板或框架驱动程序的名称为 usbskel

usbskel 驱动程序是可用于启动您自己的 USB 设备驱动程序的模板。usbskel 驱动程序演示了以下功能:

usbskel 驱动程序可在 Sun Web 站点 http://www.sun.com/bigadmin/software/usbskel/ 上获取。

有关其他 USB 驱动程序的源代码,请参见 OpenSolaris Web 站点。请访问 http://hub.opensolaris.org/bin/view/Main/,然后单击页面左侧菜单中的 "Source Browser"(源代码浏览器)。