USB驱动程序笔记

来源:百度文库 编辑:神马文学网 时间:2024/04/29 05:40:30
  查看文章   USB驱动程序笔记2009-08-28 14:49

通用串行总线(USB)是主机和外围设备之间的一种连接。

最新的USB规范修订增加了理论上高达480Mbps的高速连接。

从拓扑上来看,一个USB子系统是一棵由几个点对点的连接构建而成的树。
这些连接是连接设备和集线器(hub)的四线电缆(底线、电源、两根信号线)。

USB主控制器(host controller)负责询问每一个USB设备是否有数据需要发送。

USB总线是一个单主方式的实现,即主机轮询各种不同的外围设备。

USB总线的特性:
*具有固定的数据传输带宽的能力
*只担当设备和主控制器之间通信通道的角色,对发送数据的结构没有要求

USB协议规范定义了一套任何特定类型的设备都可以遵循的标准。
如果一个设备遵循该标准,就不需要一个特殊的驱动程序。

这些不同的特定类型称为类(class),
包括存储设备、键盘、鼠标、游戏杆、网络设备和调制解调器。

对于不符合这些类的其他类型的设备,需要针对特定的设备编写一个特定的驱动程序。
如视频设备。

Linux内核支持两种类型的USB驱动程序:
宿主(host)系统上的驱动程序和设备(device)上的驱动程序。

宿主系统的USB驱动程序控制插入其中的USB设备,
而USB设备的驱动程序控制该设备如何作为一个USB设备和主机通信。

用 户
|
块设备层
|
USB设备驱动程序
|
USB核心
|
USB主控制器
|
硬 件

USB核心为USB驱动程序提供了一个用于访问和控制USB硬件的接口,
而不必考虑系统当前存在的各种不同类型的USB硬件控制器。

----------------------------------
USB设备基础

本章描述驱动程序和USB核心之间的接口。


USB驱动程序
   |
端点 端点 端点
   |
接 口
   |
配 置
   |
设 备


---------
端点

USB通信最基本的形式是通过一个名为端点(endpoint)的东西,
包括:
*输出端点
*输入端点

端点可以看作单向的管道。

USB端点有4种不同的类型,其传送数据的方式不同:
*控制
*中断
*批量
*等时

内核中使用struct usb_host_endpoint结构体来描述USB端点。
该结构体在另一个名为struct usb_endpoint_descriptor
的结构体中包含了真正的端点信息。

后一个结构体包含了所有的USB特定的数据,
这些数据的格式是由设备自己定义的。
该结构体中驱动程序需要关心的字段有:

bEndpointAddress
特定端点的USB地址。这个8位的值中还包含了端点的方向。
结合位掩码USB_DIR_OUT和USB_DIR_IN来使用,以确定端点的数据
是传向设备还是主机。

bmAttributes
端点的类型。该值结合位掩码USB_ENDPOINT_XFERTYPE_MASK来使用,
以确定此端点的类型是USB_ENDPOINT_XFER_ISOC、USB_ENDPOINT_XFER_BULK
还是USB_ENDPOINT_XFER_INT。分别表示等时、批量和中断端点。

wMaxPacketSize
该端点一次可以处理的最大字节数。

bInterval
如果端点是中断类型,该值是端点的间隔设置。

--------
接口

USB端点被捆绑为接口。

USB接口只处理一种USB逻辑连接。

一些USB设备具有多个接口,例如
USB扬声器可以包括两个接口:一个USB键盘接口和一个USB音频流接口。

一个USB接口代表了一个基本功能,每个USB驱动程序控制一个接口。

以扬声器为例,Linux需要两个不同的驱动程序来处理一个硬件设备。

内核使用struct usb_interface结构体来描述USB接口。

USB核心把该结构体传递给USB驱动程序,
之后由USB驱动程序来负责控制该结构体。

该结构体的重要字段有:

struct usb_host_interface *altsetting
一个接口结构体数组,包含了所有可能用于该接口的可选设置。

unsigned num_altsetting
altsetting指针所指的可选设置的数量。

struct usb_host_interface *cur_altsetting
指向altsetting数组内部的指针,表示该接口的当前活动设置。

int minor
如果捆绑到该接口的USB驱动程序使用USB主设备号,
这个变量包含USB核心分配给该接口的次设备号。

------------
配置

USB接口本身被捆绑为配置。

一个USB设备可以有多个配置,而且可以在配置之间切换以改变设备的状态。


Linux使用struct usb_host_config结构体来描述USB配置,
使用struct usb_device结构体来描述整个USB设备。

USB设备的逻辑单元之间的关系描述如下:
* 设备通常具有一个或者更多的配置
* 配置经常具有一个或者更多的接口
* 接口通常具有一个或者更多的设置
* 接口没有或者具有一个以上的端点

-------------------
USB和Sysfs

USB sysfs设备命名方案为:

根集线器-集线器端口号:配置.接口
如:
2-1:1.0

如果有更多的USB集线器的使用,则设备名类似于:

根集线器-集线器端口号-集线器端口号:配置.接口

--------------------
USB urb

USB请求块

通过urb来和所有的USB设备通信。

这个请求块使用struct urb结构体来描述

设备中的每个端点都可以处理一个urb队列。

一个urb的典型生命周期:
* 由USB设备驱动程序创建
* 分配给一个特定USB设备的特定端点
* 由USB核心递交到特定设备的特定USB主控制器驱动程序
* 由USB主控制器驱动程序处理,它从设备进行USB传送
* 当urb结束之后,USB主控制器驱动程序通知USB设备驱动程序。


----------------------
struct urb

struct urb结构体中USB设备驱动程序关心的字段:

struct usb_device *dev
urb所发送的目标struct usb_device指针。

unsigned int pipe
urb所要发送的特定目标struct usb_device的端点信息。
有一系列函数可以用来设置端点,如usb_sndctrlpipe(),
可以把指定USB设备的指定端点号设置为一个控制OUT端点。

unsingned int transfer_flags
该变量可以被设置为许多不同的位值,
取决于USB驱动程序对urb的具体操作。

void *transfer_buffer
指向用于发送数据到设备(OUT urb)或者从设备接收数据(IN urb)
的缓冲区的指针。

dma_addr_t transfer_dma
用于以DMA方式传输数据到USB设备的缓冲区。

int transfer_buffer_length
transfer_buffer或者transfer_dma变量所指向的缓冲区的大小。

unsigned char *setup_packet
指向控制urb的设置数据包的指针。

dma_addr_t setup_dma
控制urb用于设置数据包的DMA缓冲区。

usb_complete_t complete
指向一个结束处理例程的指针。

void *context
指向一个可以被USB驱动程序设置的数据块。

...

-----------------
创建和销毁urb

struct urb *usb_alloc_urb(int iso_packets,int mem_flags);
void usb_free_urb(struct urb *urb);

----------------
中断urb

批量urb

控制urb

等时urb

----------------
提交urb

一旦urb被USB驱动程序正确地创建和初始化之后,
就可以提交到USB核心以发送到USB设备了。

这是通过调用usb_submit_urb函数来完成的。

int usb_submit_urb(struct urb *urb,int mem_flags);

----------------
结束urb:结束回调处理例程

----------------
取消urb

int usb_kill_urb(struct urb *urb);
int usb_unlink_urb(struct urb *urb);

 

------------------------------------
编写USB驱动程序


驱动程序把驱动程序对象注册到USB子系统中,
稍后再使用制造商和设备标识来判断是否已经安装了硬件。