请高手帮忙研究下啊 linux的USBhost之路
基于Lin u x 系统的USB HOS T 驱动程序设计与实现
图1 USB驱动结构
30
中国集成电路
http: //www.cicmag.com 2007·11·( 总第102 期)
设计
China lntegrated Circult CIC
3) USB 数据的实际传输工作。
4) 实现虚拟根HUB 的功能。
USB 设备之间是通过USB HUB 链接在一起
的, 主机控制器和USB 设备之间一般通过根HUB
相连, 如图2 所示。通常主机控制器芯片提供与根
HUB 相关的状态查询和控制单元。当有设备插入
时, 在枚举过程中, 主机控制器驱动通过查询和控制
单元应答设备来伪装成一个HUB, 所以通常称此
HUB 为虚拟根HUB。
除上述功能以外, 主机控制器驱动还要调用
Linux 提供的回调函数, 协同操作系统完成urb 的维
护和传输。
3 Li nux- usb 主机驱动结构
主机控制器驱动程序按功能结构划分以下模
块: URB_READY 用于解析、维护和缓存urb;
USB_SCHEDULE 用于USB 传输调度; USB_COMM
完成USB 实际通信; USB_VRH 实现主机控制器根
HUB 功能。
3. 1 URB_READY模块
USB 核心传送的urb 请求到达主机控制器后,
驱动要缓存各urb 以便后面的传输。驱动程序为
USB 控制器的每个活动端点都建立一个urb 等待队
列, 收到的urb 按照端点的不同缓存到不同的等待
队列中, 而后再进行调度传输。由于各端点都可以
独立完成通信工作, 互不影响, 达到了最大的并行处
理速度。
3. 2 USB_SCHEDULE 模块
驱动程序在每个USB 传输帧中都要安排调度。
各传输类型占用的带宽要符合USB 协议规定, 这是
由控制器芯片和驱动协同保证的。
为方便调度, USB_SCHEDULE 模块建立了4 个
调度队列, 分别对应四种USB 传输类型。调度模块
首先扫描每个端点的urb 缓冲队列, 然后把每个队
列的当前urb 按照传输类型的不同链接到4 种调度
队列中。
当帧中断到来时, 驱动程序扫描调度队列, 将队
列中的urb 数据传送出去。4 个调度队列的优先级
是按照USB 规范中传输类型的带宽决定的。
3. 3 USB_COMM模块
USB_COMM 模块完成USB 设备之间的通信。
大多数主机控制芯片内部都带有数据通信缓存区,
驱动程序只要按照芯片的要求在系统内存中组织好
数据, 再通过USB 主机控制器接口传送到其内部缓
存区中即可通信。此后, 驱动程序要将传输状态写
回到urb 并将其传送给USB 核心, 对于读数据的
urb 请求, 还要将返回的数据写回到urb 中, 以便返
还给USB 核心。
3. 4 USB_VRH模块
USB_VRH 模块主要实现虚拟根HUB 的功能,
使主机控制器在枚举时注册为一个HUB 设备, 但数
据的传输还是通过主机控制器来完成。
4 I SP1161 主机控制器驱动
Philips 公司的ISP1161 芯片支持OHCI 标准,
它是一个符合USB2.0 全速规范的单片主机控制器
和设备控制器。ISP1161 可以仅作为主机控制器或
设备控制器使用, 也可以同时作为主机和设备控制
器使用。ISP1161 支持存储器扩展, 所以对于没有集
成USB 主机控制器的微处理器, 可以使用ISP1161
来增加系统对USB HOST 的支持。
图2 主机控制器拓扑结构
31
中国集成电路CIC
China lntegrated Circult
设计
( 总第102 期) 2007·11· http: //www.cicmag.com
4. 1 I SP1161 主机控制器驱动的总体结
构
Linux 系统中, USB 主机控制器驱动程序接口
函数中最重要的实现是hci_submit_urb()函数, 该函
数用来处理USB 核心发送下来的urb 请求, 所以该
函数的实现直接影响系统的性能。如前所述, 在本
驱动中hci_submit_urb () 函数仅将上层发送下来的
urb 缓存到端点队列中, 最后的urb 通信响应是在中
断函数中调度完成的。驱动的整体结构如图3 所
示:
图中①等待队列为URB_READY 模块实现部
分; ②激活队列为USB_SCHEDULE 模块实现部分;
③为USB_COMM模块实现部分。图中也给出了连
接各模块的接口函数。
驱动程序有两条并行的执行线路, ①为驱动
顺序执行线路, 负责把urb 缓存; ②③则是在帧中断
服务程序中完成的, 主要用来调度不同种类的数据
传输。
4. 2 I SP1161 驱动URB_READY模块实现
该模块中实现了Linux 驱动接口函数hci_submit_
urb(), 经过一些简单判断后, 调用qu_queue_urb
()函数来将urb 缓存到各端点的等待队列中。对于空
的端点队列, urb 不必缓存, 可以直接放置在激活队
列( 调度队列) 中。qu_queue_urb()函数的伪代码如
下
qu_queue_urb( urb )
{
int ed = Urb_Parse(urb) ;
if ( EdList_head )
list_add( urb , EdList_head) ;
else
qu_queue_active_urb(urb);
}
当urb 到达图中③处, 表示完成此端点的一次
数据通信, 驱动需要在该端点的缓存队列中找到下
一个urb, 加入到激活队列中, 这是通过调用qu_return_
urb()函数来完成的。
4. 3 I SP1161 驱动USB_SCHEDULE 模块实
现
调度功能是在帧中断服务程序中完成的, USB
规范中规定一帧中可以有多个事务处理, 即多次数
据通信, 所以在一帧中要合理安排各传输类型的
urb。中断服务程序的伪代码如下:
void hc_interrupt (int irq, void * __hci, struct
pt_regs * r)
{
int s_uP =READ_REG16 (HcuPInterrupt) ;
bstat=READ_REG16 (HcBufferStatus);
// (1)
if ( ints_uP &(ATLInt |SOFITLInt) ) {
if ((bstat & ATLBufferFull) && (bstat & ATLBufferDone))
{ READ_REGn16 (HcATLBufferPort,
buff_len , buff );
sh_done_list ();
图3 I SP1161 驱动结构说明
32
中国集成电路
http: //www.cicmag.com 2007·11·( 总第102 期)
设计
China lntegrated Circult CIC
}
}
// (2)
if ( !(bstat &ATLBufferFull))
{
sh_schedule_trans ();
}
}
代码的(1)部分表示USB 控制器读数据时的处
理方式: 程序将数据读出后, 调用sh_done_list () 函
数来进行后续处理。(2)部分为帧调度处理: 程序判
断缓冲区可用后, 调用sh_schedule_trans()函数将激
活队列( 调度队列) 中的urb 数据写入到ISP1161
的通信缓冲区中, 进行实际的USB 通信。
4. 4 I SP1161 驱动USB_COMM模块实现
该模块为驱动提供实际的USB 通信的功能, 所
以实现方式与具体的USB host 芯片相关。
具体到ISP1161 芯片, 只要将需传输的数据按
照PTD 格式在内存中组织好后, 再传送到芯片内部
缓冲区中就可通信。
对于返回的数据和状态信息, 也要从缓冲区读
出并解析, 再填写到urb 结构中传回给USB 核心,
图3 中的sh_done_list ()函数完成上述功能。
5 结论
本文给出了Linux 系统下USB host 驱动的设计
方法。该方法采用模块设计, 各模块相互独立, 模块
之间通过特定的接口函数连接, 这样的结构保持了
驱动的最大可移植性。对于不同的USB host 芯片,
只需改写USB_COMM模块, 该驱动就可以很好的
在Linux 系统上工作了。
回 楼主(zhugexiaoning) 的帖子
什么啊~~~看不懂 看不懂,帮顶下 我菜,不懂啊 前排 离楼主这么近 我菜菜菜菜 这个就要支持一下了 晓宁,我来了!你说的用手机连接大容量存储设备这个问题我也想过,有好多MP5就可以的,这需要支持OTG功能,这是需要主板支持的,小六够呛了…等高手研究吧! 太深奥了,帮顶楼主 我很菜,不懂
页:
[1]
2