| 摘
要: 本文讨论了怎样在嵌入式Linux开发平台下设计USB 主机接口设备,以及在遵循GPL协议下开发该设备的驱动程序。
关键词: USB接口;嵌入式Linux;驱动程序;主机控制器
前 言:
USB(通用串行总线),是最近几年逐步在PC领域广为应用的新型接口技术。USB接口通用性好、实时性强、传输方式多样、成本低、易于扩展且便于使用,这些优点使它受到许多硬件厂商的青睐,各种类型的USB设备产品大量涌入市场,应用如火如荼。
USB设备是通过USB总线连接到USB主机上。主机通过与设备相连的逻辑通道与设备进行通信,在通信过程中,USB主机充当数据流的源端或者目的端。在USB系统设计中,USB主机接口的设计一直是其难点所在。
嵌入式Linux开发平台是嵌入式系统的一个新成员,近两年以来成为研究热点,其最大的特点是操作系统源代码公开并且遵循GPL协议。Linux是一种能运行于多种平台的类Unix操作系统,将Linux应用于嵌入式系统在国外也是近两年的事,但发展非常快。目前在世界范围内有许多科研机构和商业公司展开了对嵌入式Linux软、硬件开发平台的开发研究和应用研究。
USB Host接口的硬件设计
USB总线与计算机系统的接口部分就是主机控制器,它可以被看作一个硬件、固件和软件的综合体。USB主机与设备之间的通信最终都将通过USB主机控制器和USB设备的总线接口之间相连的电缆进行,任何一个输出请求都是由主机控制器组织成包的形式发往总线的。USB总线中只有一个主机,它是USB树形结构的根,通过一个根Hub来提供一个或多个连接点,从它分发连接着各个USB设备。
USB主机控制器完成了主机与设备之间的电气和协议层的匹配,主要包括以下功能:串并转换、帧起始、数据处理、协议使用、传输错误处理、远程唤醒、根Hub、主机系统接口等。
开发环境: 目标系统和开发主机;
开发主机: Redhat7.1 Linux,PIII 700MHz,128M RAM;
目标系统: 万禾嵌入式Linux系统,包括SOM5307A与WH5307DB两块电路板。
SOM5307A与WH5307DB两块电路板通过两个84线的接插件相连在一起,构成一个有两个异步串行接口和一个10M以太网口的微处理器系统,能够装载和运行嵌入式Linux操作系统mCLinux-Coldfire和应用软件。开发主机通过以太网或串行口与目标系统相连。用户能够通过以太网或串行口登录到目标系统上对其进行操作和控制。开发主机上还装有目标系统上运行的mCLinux-Coldfire操作系统和应用软件的所有源代码,以及编译、调试这些源代码所需的工具软件。
USB主机控制器硬件接口设计的目的是在万禾嵌入式Linux系统开发板上增加一个USB Host接口,使其能够作为USB主机与各种USB
Slave设备进行通讯。
在本文的设计中,USB Host接口芯片选用Scanlogic公司的SL811HS/T,这是市场唯一既能用作Host模式又能用作Slave模式的具有标准微处理器总线接口USB控制芯片,它适合于非PC设备。在Host模式下,它支持嵌入式主机与USB外围设备的通信,在Slave模式下,可以作为主机的一个外设。
图1给出了使用SL811HS/T扩展万禾嵌入式Linux系统USB主机接口的框图。
USB Host接口的软件设计
在Linux操作系统中,驱动程序的加载方式为:
1、将驱动程序作为可加载的模块(Module),在系统超级用户(Root)权限下使用insmod命令动态加载,使之成为系统核心的一部分。对于USB设备而言,由于可热插拔,一般采用模块化的设备驱动程序。USB主机控制器驱动程序一般也采用这种方法。
2、将设备驱动程序的源代码加进系统核心,系统启动后自动将加载驱动。USB协议栈程序一般采用这种方法加入内核,进而产生一个叫做“USB核心”的子系统。这个子系统提供了许多数据结构、宏定义、功能函数和应用程序接口(API)来对硬件或设备进行支持。
目前,并不是所有的嵌入式Linux都支持USB设备,对USB设备是否支持是由Linux核心决定的。因此,嵌入式Linux操作系统采用什么版本的核心就成为是否支持USB设备的关键。一般而言,Release版的2.2.XX及以前的版本都不支持USB设备,2.4.XX及以后的版本都加入了对USB设备的支持。万禾嵌入式Linux开发平台采用的是uClinux,其内核版本为2.2.38。此版本的内核不支持USB设备,因此,应该首先将其内核升级为2.4.10。
SL811HS/T驱动程序
开发过程主要针对SL811HS/T主机控制器芯片编写USB主机控制器驱动程序。这个驱动程序是万禾嵌入式Linux开发平台下USB协议栈和SL811HS/T主机控制器芯片的一个接口,其作用类似于Linux中由Intel制定的UHCI标准。其硬件设计比较简单,但软件较为复杂。该驱动程序主要有3个源文件组成:sl811h-usb.c
、sl811h.h、 sl811h-usb.h。在两个头文件中主要定义了一些关于SL811HS/T寄存器的宏,由于Linux是一个开源系统,与“USB核心”相关的代码将不再讨论。这里只介绍几个sl811h-usb.c中的主要的函数,这几个函数都是针对于SL811HS/T芯片的特定函数。
/* 四个I/O操作函数,其中a为SL811HS/T的寄存器或内存地址,d为数据,c为字节数,s为字符缓冲区。函数中采用了“自动地址增加模式”,降低了SL811HS/T读/写设备时占用的存储数量。*/
__u8 SL811Read(__u8 a) { /* 从SL811HS/T读字节 */
outb(a, SL811_ADDR);
return (inb(SL811_ADDR+1));
return(0); }
_static void SL811Write(__u16 a, __u8 d){ /* 向
SL811HS/T写字节 */
outb(a, SL811_ADDR);
outb(d, SL811_ADDR+1); }
_static void SL811BufRead(__u16 addr, __u8 *s, __u16
c){ /* 从SL811HS/T读缓冲区 */
if(c<=0) return;
outb(addr, SL811_ADDR);
while (c--) *s++ = (__u8)inb(SL811_ADDR+1); }
_static void SL811BufWrite(__u16 addr, __u8 *s, __u16
c){ /* 向SL811HS/T写缓冲区 */
if(c<=0) return;
outb(addr, SL811_ADDR);
while (c--) outb(*s++, SL811_ADDR+1); }
/* 下面两个函数和内存检测函数 _static int SL811HMemTest()保证了系统启动时对芯片的成功自动检测,是操作系统调用驱动程序首先要完成的任务。*/
__u8 SLDetect(void) { /* 检测SL811HS/T芯片,返回
1为检测成功 */
__u8 res;
res = SL811Read(DATASet) >> 4;
if(res != 1) return(SL_HW_NOT_DETECTED); /
* 检测失败 */
else return(res); }
_static void SL811IntStop(void) { /* 终止芯片运行 */
SL811Write(IntEna, 0x0); /* 写中断使能寄存器 */
SL811Write(IntStatus, 0xff); /* 写中断状态寄存器 */ }
另外比较重要的函数还有:
_static int rh_submit_urb (urb_t *urb)/* 完成根集线器控制管道 */
_static void detect_set(unsigned long data)/* 如果设备存在就重启动总线将其连接到根集线器上
*/
_static void uhci_interrupt (int irq, void *__uhci, struct pt_regs
*regs)/* 作为中断处理器处理SOF(Start of Frame)、送出包和插入/移出中断的函数 */
_static int __devinit alloc_uhci (int set_irq, unsigned int io_addr,
unsigned int io_size)/* 分配各种硬件和软件资源,在驱动程序初始化函数_static int init_module(void)中调用
*/
_static void uhci_free_all(uhci_t *s) /* 释放所有的由驱动程序分配的虚拟和物理资源:断开与根集线器的连接、释放I/O地址和中断。在驱动程序模块卸载函数void
cleanup_module(void) 中调用 */
系统配置
1.编写Makefile文件。在/home/uCLinux-coldfire/drivers/usb下建立sl811h的子目录,将源代码文件sl811h-usb.c
、sl811h.h、 sl811h-usb.h存入该目录,并编写Makefile文件:
#SL811HS/T----- USB Host Controller driver
INCLUDEDIR = /usr/src/linux/include
CFLAGS = -D__KERNEL__ -DMODULE -O -Wall -
static -I$(INCLUDEDIR)
VER = $(shell awk -F" '/REL/ {print $$2}'
$(INCLUDEDIR)/linux/version.h)
all : sl811h-usb.o
sl811h-usb.o: sl811h-usb.c sl811h-usb.h sl811h.h
gcc sl811h-usb.c -c $(CFLAGS)
# End this file
2.增加设备文件。在/home/uCLinux-coldfire/romfs/dev中增加一个设备文件。因为USB设备主要都是通过快速串行通讯来读写数据,故一般作为字符设备:@sl811husb,c,180,0。其中sl811husb是设备名(device
name),c代表字符设备(char device),180是主设备号(major),0是次设备号(minor)。
3.在目标系统上插入驱动程序模块到内核。编译完成后,驱动程序可以作为一个模块动态加入到uClinux内核中,使用如下命令:
# insmod sl811h-usb.o
例如:
# insmod sl811h-usb.o io=0x540 irq=15 packet_len=192
至此, USB主机控制器的软件设计完成,可以在万禾嵌入式Linux平台上运行USB主机,作为嵌入式设备与USB Slave设备进行通信。
结语
本文对在万禾嵌入式Linux平台上进行USB主机控制器的软、硬件设计做了较为详细的介绍。设计的重点和难点主要在于主机控制器芯片的驱动程序开发,但作为开源系统,在Linux上开发设备驱动程序有着其它嵌入式系统不可比拟的优势,大量的开放源码无疑可以加速开发的进程并使得其应用更加的广泛。因此,USB作为一种新型的高速外设总线,在嵌入式Linux领域必定有着广阔的应用前景。 |