原创
嵌入式Linux下SRAM驱动程序的开发原理及应用
摘要: 嵌入式Linux是目前操作系统领域中的一个热点。其要点与难点是驱动程序的开发。本文简要论述了基于现代公司嵌入式Arm处理器芯片的嵌入式Linux的SRAM驱动程序的开发原理及流程。
关键词:嵌入式Linux;Arm;驱动程序;SRAM;设备文件
1. Linux 设备驱动程序的概念:
系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口。设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件, 应用程序可以象操作普通文件一样对硬件设备进行操作。设备驱动程序是内核的一部分,它完成以下的功能:
1) 对设备初始化和释放。
2) 把数据从内核传送到硬件和从硬件读取数据。
3) 读取应用程序传送给设备文件的数据和回送应用程序请求的数据。
4) 检测和处理设备出现的错误。
在Linux操作系统下有两类主要的设备文件类型,一种是字符设备,另一种是块设备[1]。
本文将以字符型设备-SRAM的设备驱动程序为例,简要论述了基于现代公司嵌入式Arm处理器芯片-HMS30C7202的嵌入式Linux的驱动程序的开发原理及流程。
2. Arm处理器HMS30C7202简介:
Hynix HMS30C7202(32位RISC 微处理器)是由ARM720T内核[3]和其他一些外围接口器件组成,具有高性能低功耗的特点,片内资源非常丰富,具有极高的集成度,非常适用于嵌入式系统应用。
HMS30C7202 微处理器有如下特性:
内核运行速率可达70 MHz;8KB 综合指令/数据的cache;具有内存管理单元MMU;支持小端操作系统;2KB SRAM 可用于内部buffer [4]。
芯片内集成了许多外围设备。其中存储器控制器包括 ROM, Flash, SRAM, SDRAM,图1显示了HMS30C7202与SRAM的硬件连结关系。
图1 HMS30C7202与SRAM的硬件连结
3. SRAM驱动程序的开发原理及具体应用
1) I/O内存的二次映射及释放
使用I/O内存时最普遍的的硬件和软件处理方式是这样的:设备对应于某些约定的物理地地,但是CPU并没有预先定义访问它们的虚拟地址。这些约定的物理地址可以是硬件连接到设备上的,也可以是在启动时由系统固件(如 BIOS)指定的。不管哪种方式,为了让软件可以访问I/O内存,必须有一种把虚拟地址赋予设备的方法。这个任务是由ioremap 函数完成的[2] 。
#i nclude
void *ioremap(unsigned long phys_addr, unsigned long size);
void iounmap(void * addr);
ioremap的作用是把一个物理内存地址点映射为一个内核指针,被映射数据的长度由size参数设定。本模块的功能是把一块SRAM区域二次映射到一个我们可以从驱动程序里访问的虚拟地址上去。
二次映射完成后,就可以直接对其中的数据进行读写了。本模块Iomap使用的是数据长度以long(长整数)为单位的函数。如下所示:
unsigned *readl(void *address);
unsigned *writel(unsigned value, void *address)
readl返回从地址address处读到的字节,而writel把数据写到指定地址去。writel还可以返回它刚才写的数据──如果需要这样做的话。
二次映射的区域必须在卸载模块时解除映射关系和释放。把ioremap函数返回的那个指针传递到iounmap函数可以解除映射关系,如下所示:
void iounmap(void *address);
一旦有了ioremap 和iounmap ,设备驱动程序就能访问任何I/O内存地址,而不管它是否直接映射到虚拟地址空间。
在本模块中ioremap和iounmap被包装成如下两个重要函数:
(Iomap为本模块自定义数据结构,立刻会提到)其中iomap_setup将在ioctl方法中被调用,实现二次映射;iomap_remove将在模块卸载时调用,解除映射关系和释放二次映射的区域。
2) Iomap设备的定义及管理
Iomap设备被定义为下面这个结构:
结构定义里的base是SRAM区的起始地址(基地址),size是SRAM区的长度,ptr将用来保存ioremap函数的返回值。本模块用一个全局性的数组
Iomap *iomap_dev[IOMAP_MAX_DEVS];
(其中#define IOMAP_MAX_DEVS 16)来保存可能创建的设备,数组的下标就是设备的辅编号。这是需要管理多台设备时广泛使用的方法,它的具体应用并不复杂。全局数组iomap_dev里为每个可能会被访问的设备保存着一个指针。在设备每一个功能函数的入口点位置上,将要被操作的具体设备从数组里提取出来,如下所示:
Iomap *idev = iomap_dev[MINOR(inode->i_rdev)];
如果函数不直接使用一个inode节点作为参数,它也会从file文件结构里被间接地提取出来。文件结构里有一个指向与文件关联着的dentry项目("directory entry",目录项)的指针,而inode可以从这个结构里查到[2]。如下所示:
Iomap *idev = iomap_dev[MINOR(file->f_dentry->d_inode->i_rdev)];
3) 填充file_operations结构:
由于用户进程是通过设备文件同硬件打交道,对设备文件的操作方式不外乎就是一些系统调用,如 open, read, write, close ……, 注意,不是fopen, fread ……,但是如何把系统调用和驱动程序关联起来呢?这需要填充file_operations数据结构:
这个结构的每一个成员的名字都对应着一个系统调用。用户进程利用系统调用在对设备文件进行诸如read/write操作时,系统调用通过设备文件的主设备号找到相应的设备驱动程序,然后读取这个数据结构相应的函数指针,接着把控制权交给该函数。下面就讨论本模块几个重要的函数,在这里我们称之为过程或方法。
4) 对Iomap设备操作的几个重要过程及方法
a) Iomap_read()过程:函数定义如下:
static ssize_t iomap_read(struct file *file, char *buf, size_t count, loff_t *offset){} ;图2显示了Iomap_read()过程:
图2 Iomap_read()过程
b) Iomap_write()过程:函数定义如下:
static ssize_t iomap_write(struct file *file, const char *buf, size_t count,loff_t *offset) {}
与Iomap_read()过程类似,不再重复。
c) Iomap_Open方法:函数定义如下:
int iomap_open(struct inode *inode, struct file *file) {};图3显示了Iomap_Open方法:
图3 Iomap_Open方法
d) Iomap_release 方法:函数定义如下:
int iomap_release(struct inode *inode, struct file *file) {}
减少设备使用计数并return 0;
e) Iomap_ioctl方法:函数定义如下:
static int iomap_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg) {};图4显示了Iomap_ioctl方法:
图4 Iomap_ioctl方法
5) Iomap设备注册及注销
int init_module(void) {}:注册iomap设备
res = register_chrdev(IOMAP_MAJOR, "iomap", &iomap_fops);
并为设备数组iomap_dev分配内存;
void cleanup_module(void) {}:释放iomap_dev分配的内存,注销设备iomap。
4. 测试本模块
首先以根用户身份编译模块,然后创建两个设备文件,辅编号一个是0,另一个是1。再把模块插入到内核里去。
现在编辑一个小的测试程序,对上述两个设备文件/ dev/iomap0及/dev/iomap1进行操作。其中/ dev/iomap0基地址为0xc0000000, 大小为1MB; /dev/iomap1基地址为0xc0100000, 大小为1MB。设备文件以读写方式打开。
程序编译后运行,得到预期结果。
5. 小结:
本文论述了嵌入式Linux下SRAM驱动程序的开发原理及流程,并作了测试,得到了预期结果,这样嵌入式Linux就能得到更加广泛的应用。
参考文献:
[1]. alessandro rubini & jonathan corbet.魏永明,等 译.Linux设备驱动程序.北京:中国电力出版社,2002.11
[2]. Neil Matthew, Richard Stone.杨晓云,王建桥,杨涛,高文雅,等 译.Linux程序设计. 北京:机械工业出版社,2002.1
[3].马忠梅,马广云,徐英惠,田泽.ARM嵌入式处理器结构与应用基础. 北京:北京航空航天大学出版社,2002.1
[4] .www.Hynix.com
文章评论(0条评论)
登录后参与讨论