linux 内核中的 USB 代码和所有的 USB 设备通讯使用称为 urb 的东西( USB request
block). 这个请求块用 struct urb 结构描述并且可在 include/linux/usb.h 中找到.
一个 urb 用来发送或接受数据到或者从一个特定 USB 设备上的特定的 USB 端点, 以一
种异步的方式. 它用起来非常象一个 kiocb 结构被用在文件系统异步 I/O 代码, 或者如
同一个 struct skbuff 用在网络代码中. 一个 USB 设备驱动可能分配许多 urb 给一个
端点或者可能重用单个 urb 给多个不同的端点, 根据驱动的需要. 设备中的每个端点都
处理一个 urb 队列, 以至于多个 urb 可被发送到相同的端点, 在队列清空之前. 一个
urb 的典型生命循环如下:
• 被一个 USB 设备驱动创建.
• 安排给一个特定 USB 设备的特定端点.
• 提交给 USB 核心, 被 USB 设备驱动.
• 提交给特定设备的被 USB 核心指定的 USB 主机控制器驱动, .
• 被 USB 主机控制器处理, 它做一个 USB 传送到设备.
• 当 urb 完成, USB 主机控制器驱动通知 USB 设备驱动.
urb 也可被提交这个 urb 的驱动在任何时间取消, 或者被 USB 核心如果设备被从系统中
移出. urb 被动态创建并且包含一个内部引用计数, 使它们在这个 urb 的最后一个用户
释放它时被自动释放.
本章中描述的处理 urb 的过程是有用的, 因为它允许流和其他复杂的, 交叠的通讯以允
许驱动来获得最高可能的数据传送速度. 但是有更少麻烦的过程可用, 如果你只是想发送
单独的块或者控制消息, 并且不关心数据吞吐率.(见"USB 传送不用 urb"一节).
struct urb 结构中和 USB 设备驱动有关的成员是:
struct usb_device *dev
指向这个 urb 要发送到的 struct usb_device 的指针. 这个变量必须被 USB 驱
动初始化, 在这个 urb 被发送到 USB 核心之前.
unsigned int pipe
端点消息, 给这个 urb 要被发送到的特定 struct usb_device. 这个变量必须被
USB 驱动初始化, 在这个 urb 被发送到 USB 核心之前.
为设置这个结构的成员, 驱动使用下面的函数是适当的, 依据流动的方向. 注意每
个端点只可是一个类型.
unsigned int usb_sndctrlpipe(struct usb_device *dev, unsigned int
endpoint)
指定一个控制 OUT 端点给特定的带有特定端点号的 USB 设备.
unsigned int usb_rcvctrlpipe(struct usb_device *dev, unsigned int
endpoint)
指定一个控制 IN 端点给带有特定端点号的特定 USB 设备.
unsigned int usb_sndbulkpipe(struct usb_device *dev, unsigned int
endpoint)
指定一个块 OUT 端点给带有特定端点号的特定 USB 设备
unsigned int usb_rcvbulkpipe(struct usb_device *dev, unsigned int
endpoint)
指定一个块 IN 端点给带有特定端点号的特定 USB 设备
unsigned int usb_sndintpipe(struct usb_device *dev, unsigned int
endpoint)
指定一个中断 OUT 端点给带有特定端点号的特定 USB 设备
unsigned int usb_rcvintpipe(struct usb_device *dev, unsigned int
endpoint)
指定一个中断 IN 端点给带有特定端点号的特定 USB 设备
unsigned int usb_sndisocpipe(struct usb_device *dev, unsigned int
endpoint)
指定一个同步 OUT 端点给带有特定端点号的特定 USB 设备
unsigned int usb_rcvisocpipe(struct usb_device *dev, unsigned int
endpoint)
指定一个同步 IN 端点给带有特定端点号的特定 USB 设备
unsigned int transfer_flags
这个变量可被设置为不同位值, 根据这个 USB 驱动想这个 urb 发生什么. 可用的
值是:
URB_SHORT_NOT_OK
当置位, 它指出任何在一个 IN 端点上可能发生的短读, 应当被 USB 核心当作一
个错误. 这个值只对从 USB 设备读的 urb 有用, 不是写 urbs.
URB_ISO_ASAP
如果这个 urb 是同步的, 这个位可被置位如果驱动想这个 urb 被调度, 只要带宽
允许它这样, 并且在此点设置这个 urb 中的 start_frame 变量. 如果对于同步
urb 这个位没有被置位, 驱动必须指定 start_frame 值并且必须能够正确恢复,
如果没有在那个时刻启动. 见下面的章节关于同步 urb 更多的消息.
URB_NO_TRANSFER_DMA_MAP
应当被置位, 当 urb 包含一个要被发送的 DMA 缓冲. USB 核心使用这个被
transfer_dma 变量指向的缓冲, 不是被 transfer_buffer 变量指向的缓冲.
URB_NO_SETUP_DMA_MAP
象 URB_NO_TRANSFER_DMA_MAP 位, 这个位用来控制有一个 DMA 缓冲已经建立的
urb. 如果它被置位, USB 核心使用这个被 setup_dma 变量而不是 setup_packet
变量指向的缓冲.
URB_ASYNC_UNLINK
如果置位, 给这个 urb 的对 usb_unlink_urb 的调用几乎立刻返回, 并且这个
urb 在后面被解除连接. 否则, 这个函数等待直到 urb 完全被去链并且在返回前
结束. 小心使用这个位, 因为它可有非常难于调试的同步问题.
URB_NO_FSBR
只有 UHCI USB 主机控制器驱动使用, 并且告诉它不要试图做 Front Side Bus
Reclamation 逻辑. 这个位通常应当不设置, 因为有 UHCI 主机控制器的机器创建
了许多 CPU 负担, 并且 PCI 总线被等待设置了这个位的 urb 所饱和.
URB_ZERO_PACKET
如果置位, 一个块 OUT urb 通过发送不包含数据的短报文而结束, 当数据对齐到
一个端点报文边界. 这被一些坏掉的 USB 设备所需要(例如一些 USB 到 IR 的设
备) 为了正确的工作..
URB_NO_INTERRUPT
如果置位, 硬件当 urb 结束时可能不产生一个中断. 这个位应当小心使用并且只
在排队多个到相同端点的 urb 时使用. USB 核心函数使用这个为了做 DMA 缓冲传
送.
void *transfer_buffer
指向用在发送数据到设备(对一个 OUT urb)或者从设备中获取数据(对于一个 IN
urb)的缓冲的指针. 对主机控制器为了正确存取这个缓冲, 它必须被使用一个对
kmalloc 调用来创建, 不是在堆栈或者静态地. 对控制端点, 这个缓冲是给发送的
数据阶段.
dma_addr_t transfer_dma
用来使用 DMA 传送数据到 USB 设备的缓冲.
int transfer_buffer_length
缓冲的长度, 被 transfer_buffer 或者 transfer_dma 变量指向(由于只有一个可
被一个 urb 使用). 如果这是 0, 没有传送缓冲被 USB 核心所使用.
对于一个 OUT 端点, 如果这个端点最大的大小比这个变量指定的值小, 对这个
USB 设备的传送被分成更小的块为了正确的传送数据. 这种大的传送发生在连续的
USB 帧. 提交一个大块数据在一个 urb 中是非常快, 并且使 USB 主机控制器去划
分为更小的快, 比以连续的顺序发送小缓冲.
unsigned char *setup_packet
指向给一个控制 urb 的 setup 报文的指针. 它在位于传送缓冲中的数据之前被传
送. 这个变量只对控制 urb 有效.
dma_addr_t setup_dma
给控制 urb 的 setupt 报文的 DMA 缓冲. 在位于正常传送缓冲的数据之前被传送.
这个变量只对控制 urb 有效.
usb_complete_t complete
指向完成处理者函数的指针, 它被 USB 核心调用当这个 urb 被完全传送或者当
urb 发生一个错误. 在这个函数中, USB 驱动可检查这个 urb, 释放它, 或者重新
提交它给另一次传送.(见"completingUrbs: 完成回调处理者", 关于完成处理者的
更多细节).
usb_complete_t 类型定义如此:
typedef void (*usb_complete_t)(struct urb *, struct pt_regs *);
void *context
指向数据点的指针, 它可被 USB 驱动设置. 它可在完成处理者中使用当 urb 被返
回到驱动. 关于这个变量的细节见后续章节.
int actual_length
当这个 urb 被完成, 这个变量被设置为数据的真实长度, 或者由这个 urb (对于
OUT urb)发送或者由这个 urb(对于 IN urb)接受. 对于 IN urb, 这个必须被用来
替代 transfer_buffer_length 变量, 因为接收的数据可能比整个缓冲大小小.
int status
当这个 urb 被结束, 或者开始由 USB 核心处理, 这个变量被设置为 urb 的当前
状态. 一个 USB 驱动可安全存取这个变量的唯一时间是在 urb 完成处理者函数中
(在"CompletingUrbs: 完成回调处理者"一节中描述). 这个限制是阻止竞争情况,
发生在这个 urb 被 USB 核心处理当中. 对于同步 urb, 在这个变量中的一个成功
的值(0)只指示是否这个 urb 已被去链. 为获得在同步 urb 上的详细状态, 应当
检查 iso_frame_desc 变量.
这个变量的有效值包括:
0
这个 urb 传送是成功的.
-ENOENT
这个 urb 被对 usb_kill_urb 的调用停止.
-ECONNRESET
urb 被对 usb_unlink_urb 的调用去链, 并且 transfer_flags 变量被设置为
URB_ASYNC_UNLINK.
-EINPROGRESS
这个 urb 仍然在被 USB 主机控制器处理中. 如果你的驱动曾见到这个值, 它是一
个你的驱动中的 bug.
-EPROTO
这个 urb 发生下面一个错误:
• 一个 bitstuff 错误在传送中发生.
• 硬件没有及时收到响应帧.
-EILSEQ
在这个 urb 传送中有一个 CRC 不匹配.
-EPIPE
这个端点现在被停止. 如果这个包含的端点不是一个控制端点, 这个错误可被清除
通过一个对函数 usb_clear_halt 的调用.
-ECOMM
在传送中数据接收快于能被写入系统内存. 这个错误值只对 IN urb.
-ENOSR
在传送中数据不能从系统内存中获取得足够快, 以便可跟上请求的 USB 数据速率.
这个错误只对 OUT urb.
-EOVERFLOW
这个 urb 发生一个"babble"错误. 一个"babble"错误发生当端点接受数据多于端
点的特定最大报文大小.
-EREMOTEIO
只发生在当 URB_SHORT_NOT_OK 标志被设置在 urb 的 transfer_flags 变量, 并
且意味着 urb 请求的完整数量的数据没有收到.
-ENODEV
这个 USB 设备现在从系统中消失.
-EXDEV
只对同步 urb 发生, 并且意味着传送只部分完成. 为了决定传送什么, 驱动必须
看单独的帧状态.
-EINVAL
这个 urb 发生了非常坏的事情. USB 内核文档描述了这个值意味着什么:
ISO 疯了, 如果发生这个: 退出并回家.
它也可发生, 如果一个参数在 urb 结构中被不正确地设置了, 或者如果在提交这
个 urb 给 USB 核心的 usb_submit_urb 调用中, 有一个不正确的函数参数.
-ESHUTDOWN
这个 USB 主机控制器驱动有严重的错误; 它现在已被禁止, 或者设备和系统去掉
连接, 并且这个 urb 在设备被去除后被提交. 它也可发生当这个设备的配置改变,
而这个 urb 被提交给设备.
通常, 错误值 -EPROTO, -EILSEQ, 和 -EOVERFLOW 指示设备的硬件问题, 设备固
件, 或者连接设备到计算机的线缆.
int start_frame
设置或返回同步传送要使用的初始帧号.
int interval
urb 被轮询的间隔. 这只对中断或者同步 urb 有效. 这个值的单位依据设备速度
而不同. 对于低速和高速的设备, 单位是帧, 它等同于毫秒. 对于设备, 单位是宏
帧的设备, 它等同于 1/8 微秒单位. 这个值必须被 USB 驱动设置给同步或者中断
urb, 在这个 urb 被发送到 USB 核心之前.
int number_of_packets
只对同步 urb 有效, 并且指定这个 urb 要处理的同步传送缓冲的编号. 这个值必
须被 USB 驱动设置给同步 urb, 在这个 urb 发送给 USB 核心之前.
int error_count
被 USB 核心设置, 只给同步 urb 在它们完成之后. 它指定报告任何类型错误的同
步传送的号码.
struct usb_iso_packet_descriptor iso_frame_desc[0]
只对同步 urb 有效. 这个变量是组成这个 urb 的一个 struct
usb_iso_packet_descriptor 结构数组. 这个结构允许单个 urb 来一次定义多个
同步传送. 它也用来收集每个单独传送的传送状态.
结构 usb_iso_packet_descriptor 由下列成员组成:
unsigned int offset
报文数据所在的传送缓冲中的偏移(第一个字节从 0 开始).
unsigned int length
这个报文的传送缓冲的长度.
unsigned int actual_length
接收到给这个同步报文的传送缓冲的数据长度.
unsigned int status
这个报文的单独同步传送的状态. 它可采用同样的返回值如同主 struct urb 结构
的状态变量.