USB驱动程序编写.pdf
《USB驱动程序编写.pdf》由会员分享,可在线阅读,更多相关《USB驱动程序编写.pdf(35页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、324第十三章USB驱动程序通用串行总线(USB)是主机和外围设备之间的一种连接。USB最初是为了替代许多不同的低速总线(包括并行、串行和键盘连接)而设计的,它以单一类型的总线连接各种不同类型的设备(注1)。USB的发展已经超越了这些低速的连接方式,它现在可以支持几乎所有可以连接到 PC 上的设备。最新的 USB 规范修订增加了理论上高达 480 Mbps的高速连接。从拓扑上来看,一个USB子系统并不是以总线的方式来布置的;它是一棵由几个点对点的连接构建而成的树。这些连接是连接设备和集线器(hub)的四线电缆(地线、电源线和两根信号线),这和以太网双绞线类似。USB 主控制器(host con
2、troller)负责询问每一个 USB 设备是否有数据需要发送。因为这种拓扑布局的原因,一个 USB 设备在没有主控制器要求的情况下是不能发送数据的。这种配置便于搭建一个非常简易的即插即用类型的系统,藉此,设备可以由主机自动地配置。USB总线在技术层面上是非常简单的,因为它是一个单主方式的实现,在此方式下,主机轮询各种不同的外围设备。尽管存在这种内在的局限性,USB总线有一些吸引人的特性,例如设备具有要求一个固定的数据传输带宽的能力,以可靠地支持视频和音频I/O。USB另一个重要的特性是它只担当设备和主控制器之间通信通道的角色,对它所发送的数据没有任何特殊的内容和结构上的要求(注 2)。USB
3、协议规范定义了一套任何特定类型的设备都可以遵循的标准。如果一个设备遵循该标准,就不需要一个特殊的驱动程序。这些不同的特定类型称为类(class),包括存储注 1:本章部分内容基于 Linux 内核 USB 代码的内核文档,这些文档由内核的 USB 开发者编写,并且按照 GPL 条款发布。注 2:实际上,还是存在一些结构,但通常被降低为满足某几个预定义类之一的通信需求:例如,键盘不需要分配带宽,而某些摄像头需要。325USB 驱动程序设备、键盘、鼠标、游戏杆、网络设备和调制解调器。对于不符合这些类的其他类型的设备,需要针对特定的设备编写一个特定于供货商的驱动程序。视频设备和USB到串口转换设备是
4、一个很好的例子,对于它们没有已定义的标准,来自不同制造商的每一种不同的设备都需要对应的驱动程序。这些特性,加上设计上与生俱来的热插拔能力,使得 USB 成为一个便利和低成本的机制,它可以连接多个设备到计算机,而不需要关闭系统、打开机箱、拧螺丝钉和插拔电线。Linux内核支持两种主要类型的 USB 驱动程序:宿主(host)系统上的驱动程序和设备(device)上的驱动程序。从宿主的观点来看(一个普通的USB宿主是一个桌面计算机),宿主系统的USB驱动程序控制插入其中的USB设备,而USB设备的驱动程序控制该设备如何作为一个 USB 设备和主机通信。由于术语“USB 设备驱动程序”(USB de
5、vicedrivers)非常易于混淆,USB 开发者创建了术语“USB 器件驱动程序”(USB gadgetdrivers)来描述控制连接到计算机(不要忘了 Linux 还运行于很多小型嵌入式设备上)的 USB 设备的驱动程序。本章将详细介绍运行于桌面计算机上的USB 系统是如何运作的。USB 器件驱动程序此刻还未列入本书的内容范围。如图13-1所示,USB驱动程序存在于不同的内核子系统(块设备、网络设备、字符设备等等)和USB 硬件控制器之中。USB 核心为 USB 驱动程序提供了一个用于访问和控制USB 硬件的接口,而不必考虑系统当前存在的各种不同类型的 USB 硬件控制器。硬件用户USB
6、 主控制器USB 核心USB 设备驱动程序VFS层块设备层网络设备层字符设备层TTY层内核.图 13-1:USB 驱动程序概观第十三章326USB 设备基础USB 设备是一个非常复杂的东西,官方USB 文档(可由 http:/www.usb.org获取)中有详细的描述。幸运的是,Linux内核提供了一个称为 USB 核心(USB core)的子系统来处理大部分的复杂性。本章描述驱动程序和 USB 核心之间的接口。图 13-2展示了 USB设备的构成,包括配置、接口和端点,以及 USB 驱动程序如何绑定到 USB 接口上,而不是整个 USB 设备。DeviceConfigEndpointEndp
7、ointEndpointInterfaceEndpointEndpointEndpointInterfaceUSBdriverUSBdriver图 13-2:USB 设备概观端点USB通信最基本的形式是通过一个名为端点(endpoint)的东西。USB端点只能往一个方向传送数据,从主机到设备(称为输出端点)或者从设备到主机(称为输入端点)。端点可以看作是单向的管道。USB 端点有四种不同的类型,分别具有不同的传送数据的方式:控制控制端点用来控制对 USB 设备不同部分的访问。它们通常用于配置设备、获取设备信息、发送命令到设备,或者获取设备的状态报告。这些端点一般体积较小。每个 USB 设备都有
8、一个名为“端点 0”的控制端点,USB 核心使用该端点在插入时进行设备的配置。USB 协议保证这些传输始终有足够的保留带宽以传送数据到设备。327USB 驱动程序中断每当 USB 宿主要求设备传输数据时,中断端点就以一个固定的速率来传送少量的数据。这些端点是 USB 键盘和鼠标所使用的主要传输方式。它们通常还用于发送数据到 USB 设备以控制设备,不过一般不用来传输大量的数据。USB 协议保证这些传输始终有足够的保留带宽以传送数据。批量批量(bulk)端点传输大批量的数据。这些端点通常比中断端点大得多(它们可以一次持有更多的字符)。它们常见于需要确保没有数据丢失的传输的设备。USB协议不保证这
9、些传输始终可以在特定的时间内完成。如果总线上的空间不足以发送整个批量包,它将被分割为多个包进行传输。这些端点通常出现在打印机、存储设备和网络设备上。等时等时(isochronous)端点同样可以传送大批量的数据,但数据是否到达是没有保证的。这些端点用于可以应付数据丢失情况的设备,这类设备更注重于保持一个恒定的数据流。实时的数据收集(例如音频和视频设备)几乎毫无例外都使用这类端点。控制和批量端点用于异步的数据传输,只要驱动程序决定使用它们。中断和等时端点是周期性的。也就是说,这些端点被设置为在固定的时段连续地传输数据,基于此,USB核心为它们保留了相应的带宽。内核中使用 struct usb_h
10、ost_endpoint结构体来描述 USB 端点。该结构体在另一个名为 struct usb_endpoint_descriptor的结构体中包含了真正的端点信息。后一个结构体包含了所有的USB特定的数据,这些数据的格式是由设备自己定义的。该结构体中驱动程序需要关心的字段有:bEndpointAddress这是特定端点的 USB 地址。这个 8 位的值中还包含了端点的方向。该字段可以结合位掩码USB_DIR_OUT和 USB_DIR_IN来使用,以确定该端点的数据是传向设备还是主机。bmAttributes这是端点的类型。该值可以结合位掩码 USB_ENDPOINT_XFERTYPE_MAS
11、K来使用,以确定此端点的类型是 USB_ENDPOINT_XFER_ISOC、USB_ENDPOINT_XFER_BULK还是USB_ENDPOINT_XFER_INT。这些宏分别表示等时、批量和中断端点。wMaxPacketSize这是该端点一次可以处理的最大字节数。注意,驱动程序可以发送数量大于此值的第十三章328数据到端点,但是在实际传输到设备的时候,数据将被分割为wMaxPacketSize大小的块。对于高速设备,通过使用高位中一些额外的位,该字段可以用来支持端点的高带宽模式。请参考 USB 规范以了解具体实现的详情。bInterval如果端点是中断类型,该值是端点的间隔设置 也就是说
12、,端点的中断请求间隔时间。该值以毫秒为单位。该结构体的字段并没有采用“传统的”Linux 内核命名方案。这是因为这些字段直接对应于USB规范中的字段名字。USB内核程序员认为使用规范指定的名字比使用Linux程序员熟悉的变量命名方式更加重要,因为这样便于规范的阅读。接口USB 端点被捆绑为接口。USB 接口只处理一种 USB 逻辑连接,例如鼠标、键盘或者音频流。一些USB 设备具有多个接口,例如 USB扬声器可以包括两个接口:一个USB 键盘用于按键和一个 USB音频流。因为一个 USB 接口代表了一个基本功能,而每个 USB驱动程序控制一个接口,因此,以扬声器为例,Linux 需要两个不同的
13、驱动程序来处理一个硬件设备。USB接口可以有其他的设置,这些是和接口的参数不同的选择。接口的最初状态是在第一个设置,编号为 0。其他的设置可以用来以不同的方式控制端点,例如为设备保留大小不同的 USB 带宽。每个带有等时端点的设备对同一个接口使用不同的设置。内核使用 struct usb_interface结构体来描述 USB 接口。USB 核心把该结构体传递给 USB 驱动程序,之后由 USB 驱动程序来负责控制该结构体。该结构体中的重要字段有:struct usb_host_interface*altsetting一个接口结构体数组,包含了所有可能用于该接口的可选设置。每个 structu
14、sb_host_interface结构体包含一套由上述struct usb_host_endpoint结构体定义的端点配置。注意,这些接口结构体没有特定的次序。unsigned num_altsettingaltsetting 指针所指的可选设置的数量。struct usb_host_interface*cur_altsetting指向 altsetting 数组内部的指针,表示该接口的当前活动设置。329USB 驱动程序int minor如果捆绑到该接口的USB驱动程序使用USB主设备号,这个变量包含USB核心分配给该接口的次设备号。这仅在一个成功的 usb_register_dev 调用之
15、后才有效(在本章稍后描述)。struct usb_interface结构体中还有其他的字段,不过USB驱动程序不需要考虑它们。配置USB 接口本身被捆绑为配置。一个 USB 设备可以有多个配置,而且可以在配置之间切换以改变设备的状态。例如,一些允许下载固件到其上的设备包含多个配置以完成这个工作,而一个时刻只能激活一个配置。Linux 对多个配置的 USB 设备处理得不是很好,不过,幸好这种情况很少发生。Linux 使用 struct usb_host_config 结构体来描述 USB 配置,使用 structusb_device结构体来描述整个USB设备。USB设备驱动程序通常不需要读取或者
16、写入这些结构体中的任何值,因此这里就不详述它们了。想要深入探究的读者可以在内核源代码树的 include/linux/usb.h 文件中找到对它们的描述。USB设备驱动程序通常需要把一个给定的struct usb_interface结构体的数据转换为一个 struct usb_device 结构体,USB 核心在很多函数调用中都需要该结构体。interface_to_usbdev就是用于该转换功能的函数。可以期待的是,当前需要 struct usb_device结构体的所有 USB调用将来会变为使用一个 struct usb_interface参数,而且驱动程序不再需要去做转换的工作。概言之,
17、USB设备是非常复杂的,它由许多不同的逻辑单元组成。这些逻辑单元之间的关系可以简单地描述如下:设备通常具有一个或者更多的配置配置经常具有一个或者更多的接口接口通常具有一个或者更多的设置接口没有或者具有一个以上的端点USB 和 Sysfs由于单个USB 物理设备的复杂性,在sysfs 中表示该设备也相当复杂。无论是物理USB第十三章330设备(用struct usb_device表示)还是单独的USB接口(用struct usb_interface表示),在 sysfs 中均表示为单独的设备(这是因为这些结构体都包含一个 structdevice结构体)。以仅包含一个 USB接口的简易 USB
18、鼠标为例,下面是该设备的sysfs目录树:/sys/devices/pci0000:00/0000:00:09.0/usb2/2-1|-2-1:1.0|-bAlternateSetting|-bInterfaceClass|-bInterfaceNumber|-bInterfaceProtocol|-bInterfaceSubClass|-bNumEndpoints|-detach_state|-iInterface|-power|-state|-bConfigurationValue|-bDeviceClass|-bDeviceProtocol|-bDeviceSubClass|-bMaxP
19、ower|-bNumConfigurations|-bNumInterfaces|-bcdDevice|-bmAttributes|-detach_state|-devnum|-idProduct|-idVendor|-maxchild|-power|-state|-speed-versionstruct usb_device 表示为目录树中的:/sys/devices/pci0000:00/0000:00:09.0/usb2/2-1而鼠标的 USB 接口(USB 鼠标驱动程序所绑定的接口)位于如下目录:/sys/devices/pci0000:00/0000:00:09.0/usb2/2-1
20、/2-1:1.0我们将描述内核如何分类 USB 设备,以帮助理解上面这些长长的设备路径名的含义。第一个 USB 设备是一个根集线器(root hub)。这是一个 USB 控制器,通常包含在一个PCI 设备中。之所以这样命名该控制器,是因为它控制着连接到其上的整个 USB 总线。该控制器是连接 PCI 总线和 USB 总线的桥,也是该总线上的第一个 USB 设备。331USB 驱动程序所有的根集线器都由USB核心分配了一个独特的编号。在我们的例子中,根集线器名为usb2,因为它是注册到USB 核心的第二个根集线器。单个系统中可以包含的根集线器的编号在任何时候都是没有限制的。USB总线上的每个设备
21、都以根集线器的编号作为其名字中的第一个号码。该号码随后是一个横杠字符和设备所插入的端口号。因为我们例子中的设备插入到第一个端口,1 被添加到了名字中。因此,主 USB 鼠标设备的设备名是 2-1。因为该 USB 设备包含一个接口,导致了树中的另一个设备被添加到 sysfs 路径中。USB 接口的命名方案是设备名直到该接口为止:在我们的例子中,是 2-1 后面加一个冒号和 USB 配置的编号,然后是一个句点和接口的编号。因此对于本例而言,设备名是2-1:1.0,因为它是第一个配置,具有接口编号零。概言之,USB sysfs 设备命名方案为:根集线器-集线器端口号:配置.接口随着设备更深地进入 U
22、SB 树,和越来越多的 USB 集线器的使用,集线器的端口号被添加到跟随着链中前一个集线器端口号的字符串中。对于一个两层的树,其设备名类似于:根集线器-集线器端口号-集线器端口号:配置.接口从前面的USB设备和接口的目录列表可以看到,所有的USB特定信息都可以从sysfs直接获得(例如,idVendor、idProduct 和 bMaxPower 信息)。这些文件中的一个,即bConfigurationValue,可以被写入以改变当前使用的活动USB配置。当内核不能够确定选择哪一个配置以恰当地操作设备时,这对于具有多个配置的设备很有用。许多USB调制解调器需要向该文件中写入适当的配置值,以便把
23、恰当的USB驱动程序绑定到该设备。sysfs 并没有展示 USB 设备所有的不同部分,它只限于接口级别。设备可能包含的任何可选配置都没有显示,还有和接口相关联的端点的细节。这个信息可以从 usbfs 文件系统找到,该文件系统被挂装到系统的/proc/bus/usb/目录。/proc/bus/usb/devices 文件确实显示了和sysfs 所展示的所有信息相同的信息,还有系统中存在的所有 USB设备的可选配置和端点信息。usbfs 还允许用户空间的程序直接访问 USB 设备,这使得许多内核驱动程序可以迁移到用户空间,从而更加容易维护和调试。USB扫描仪是一个很好的例子,它不再存在于内核中,因
24、为它的功能现在包含在了用户空间的 SANE 库程序中。USB urbLinux内核中的 USB代码通过一个称为urb(USB 请求块)的东西和所有的 USB设备通信。这个请求块使用struct urb结构体来描述,可以从include/linux/usb.h文件中找到。第十三章332urb被用来以一种异步的方式往/从特定的USB 设备上的特定USB端点发送/接收数据。它的使用和文件系统异步I/O代码中的kiocb结构体以及网络代码中的struct skbuff很类似。USB 设备驱动程序可能会为单个端点分配许多urb,也可能对许多不同的端点重用单个的 urb,这取决于驱动程序的需要。设备中的每
25、个端点都可以处理一个 urb 队列,所以多个 urb 可以在队列为空之前发送到同一个端点。一个 urb的典型生命周期如下:由 USB 设备驱动程序创建。分配给一个特定 USB 设备的特定端点。由 USB 设备驱动程序递交到 USB 核心。由 USB 核心递交到特定设备的特定 USB 主控制器驱动程序。由 USB 主控制器驱动程序处理,它从设备进行 USB 传送。当 urb 结束之后,USB 主控制器驱动程序通知 USB 设备驱动程序。urb可以在任何时刻被递交该 urb 的驱动程序取消掉,或者被 USB 核心取消,如果该设备已从系统中移除。urb 被动态地创建,它包含一个内部引用计数,使得它们
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- USB 驱动程序 编写
限制150内