当前位置:首页 期刊杂志

基于S3C2410和LINUX的触摸屏驱动

时间:2024-09-03

内蒙古电子信息职业技术学院 马丽洁 李占岭

Linux设备驱动程序属于Linux内核的一部分,并在Linux内核中扮演着十分重要的角色。它们像一个个“黑盒子”使某个特定的硬件响应一个定义良好的内部编程接口,同时完全隐蔽了设备的工作细节。用户通过一组标准化的调用来完成相关操作,这些标准化的调用是和具体设备驱动无关的,而驱动程序的任务就是把这些调用映射到具体设备对于实际硬件的特定操作上。

可以把设备驱动作为内核的一部分,直接编译到内核中,即静态编译,也可以单独作为一个模块编译,在需要它的时候再动态的把它插入到内核中。在不需要时也可把它从内核中删除,即动态连接。显然动态连接比静态连接有更多的好处,但在嵌入式开发领域往往要求进行静态连接,尤其是像S3C44BO这种不带MMU的芯片。但在S3C241O等带MMU的ARM芯片中我们依然可以使用动态连接。

一、Linux设备分类

目前Linux支持的设备驱动可分为三种:字符设备,块设备,网络接口设备。当然它们之间的也并不是要严格的加以区分。

1.字符设备:所有能够像字节流一样访问的设备比如文件等在Linux中都通过字符设备驱动程序来实现。在Linux中它们也被映射为文件系统的一个节点,常在/dev目录下。字符设备驱动程序一般要包含open,close,read,write等几个系统调用。

2.块设备:Linux的块设备通常是指诸如磁盘,内存,Flash等可以容纳文件系统的存储设备。与字符设备类似,块设备也是通过文件系统来进行访问,它们之间的区别仅仅在于内核内部管理数据的方式不同。它也允许像字符设备一样的访问,可以一次传递任意多的字节。Linux中的块设备包含整数个块,每个块包含2的几次幂的字节。

3.网络接口设备:网络接口设备是Linux中比较复杂的一种设备,通常它们指的是硬件设备,但有时也可是一个软件设备。它们由内核中网络子系统驱动,负责发送和接收数据包,而且它并不需要了解每一项事务是如何映射到实际传送的数据包的。它们的数据传送往往并不是面向流的,所以不容易把它们映射到一个文件系统的节点上。在Linux中采用给网络接口设备分配一个唯一名字的方法来访问该设备。

二、Linux关于字符设备的管理

驱动程序在Linux内核中往往是以模块形式出现的。与应用程序的执行过程不同,模块通常只是预先向内核注册自己,当内核需要时响应请求。模块中包含两个重要的函数:init_module和cleanup_module。前者是模块的入口,它为模块调用做好准备工作,而后者则是在模块即将卸载时被调用,做一些清扫工作。

驱动程序模块通过函数:int register_chrdev(unsigned int major,const char *name,struct file_operations*fops);来完成向内核注册的。其中unsi-gned int major为主设备号,const char *name为设备名,结构指针struct file_operations *fops内核就是通过这个结构来访问驱动程序的。

在Linux中字符设备是通过文件系统中的设备名来进行访问的。这些名称通常放在/dev目录下,通过命令ls-l/dev我们可以看到该目录下的一大堆设备文件,其中第一个字母是“C”的为字符设备,而第一个字母是“b”的为块设备文件。其中每个设备文件都具有一个主设备号和一个次设备号。当驱动程序调用open系统调用时,内核就是利用主设备号把该驱动与具体设备对应起来的。而次设备号内核并不关心,它是给主设备号已经确定的驱动程序使用的,一个驱动程序往往可以控制多个设备,如一个硬盘的多个分区,这时该硬盘拥有一个主设备号,而每个分区拥有自己的次设备号。

我们编写好一个驱动程序模块后,按传统的主次设备号的方法来进行设备管理,则我们应手工为该模块建立一个设备节点。命令:mknod /dev/ts c 254 O其中/dev/ts表示我们的设备名是ts,“C”说明它是字符设备,“254”是主设备号,“O”是次设备号。一旦通过mknod创建了设备文件,它就一直保留下来,除非我们手工删除它。我们用register_chrdev注册模块时,给major赋值为O,则系统就采用动态方式分配设备号。它会在所有未被使用的设备号中为我们选定一个,作为函数返回值返回给我们。一旦分配了设备号,我们就可以在/proc/devices中看到相关内容。/proc在前面关于操作系统移植的实验中我们已经提到,它是一个伪文件系统,它实际并不占用任何硬盘空间,而是在内核运行时在内存中动态生成的。它可以显示当前运行系统的许多相关信息。显然这一点对我们动态分配主设备号是非常有意义的。因为,正如我们前面提到的一样,我们采用主次设备号的方式管理设备文件,我们要在/dev目录下为我们的设备创建一个设备名,可我们的设备号却是动态产生的,每次都不一样,这样我们就不得不每次都从新运行一次mknod命令。这个过程我们通常通过编写自动执行脚本来完成,而其中的主设备号我们就可以通过/proc/devices中获得。

三、触摸屏的控制

本系统触摸屏的控制是使用的S3c241O处理器自带的触摸屏控制器,这部分的开发主要参考S3c241O处理器的芯片手册。这部分的控制主要是设置触摸屏的采样模式,处理器提供的模式:

1.正常的转换模式

2.手动的x/y位置转换模式

3.自动的x/y位置转换模式

我们这里使用的是第3种转换模式。需要注意的是在完成一次x/y坐标采样的过程中需要一次模式转换即在点击触摸屏之前是等待中断模式,当有触摸动作产生触摸屏中断以后,在x/y的坐标采集驱动中设置成自动的x/y位置转换模式,在完成采集以后再转换回等待中断模式,准备下一次的触摸采样。

四、程序分析

剖析S3C241O的触摸屏驱动程序,部分代码及注释如下:

static ssize_t s3c241O_ts_read(str-uct file *filp,char *buffer,size_t count,loff_t *ppos)/*设备读函数,各参数含义:*filp打开的文件,*buffer数据缓存,count请求传送数据长度,*ppos用户在文件中进行存储操作的位置。*/

驱动程序运行在内核空间,而应用程序运行在用户空间。用户空间内存页是可被换出的。当内核空间访问用户空间时有可能当前页并不存在而造成错误。所以当我们要从内核空间拷贝整段数据到用户空间时只能借助于内核函数:

unsigned long copy_to_user(void*to,const void *from,unsigned long count)

同样从用户空间往内核空间拷贝数据也只能借助于内核函数:

unsigned long copy_from_user(void*to,const void *from,unsigned long count)它将在驱动程序写函数中用到。

//在该函数中添加自己的滤波算法,注意函数中对硬件寄存器操作的部分语句和函数static void s3c241O_isr_tc(int irq,void *dev_id,struct pt_regs*reg)//这是中断处理函数,当触摸屏事件发生时触发中断,内核捕捉该中断后交由该函数处理。

static int s3c241O_ts_open(struct inode *inode,struct file *filp)//打开设备,该函数中往往要完成设备初始化和使用记数增值。

static int s3c241O_ts_release(str-uct inode *inode,struct file *filp)//设备释放函数。

s3c241O_isr_adc、S3c241O_isr_tc:它是一个唯一的标志符,通过该指针多个设备可以共享信号线。驱动程序也可以用它指向自己的私有数据区,用来识别哪个设备产生了中断。

由于设备驱动是沟通底层硬件与上层应用程序的桥梁,它所涉及的内容相当多。要编写一个完整的驱动程序,要求你不仅对硬件设备及其工作原理要相当熟悉,同时必需具备一定的内核结构的知识,此外对上层应用程序及开发语言也具有比较过硬的开发能力。

[1]毛德操,胡希明.Linux内核源代码情景分析(上册)[M].浙江:浙江大学出版社.

[2]刘淼.嵌入式系统接口设计与Linux驱动程序开发[M].北京:北京航空航天大学,2006,11.

免责声明

我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自各大过期杂志,内容仅供学习参考,不准确地方联系删除处理!