




已阅读5页,还剩9页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
基于嵌入式Linux的字符设备驱动开发第23卷第3期2008年6月成都信息工程学院JOURNALOFCHENGDUUNIVERSITYOFINFORMATIONTECHNOLOGYVo1.23No.3Jun.2008文章编号:671一l742(2008)03027505基于嵌入式Linux的字符设备驱动开发王科,姚振东(成都信息工程学院,四川成都610225)摘要:设备驱动程序是Linux内核的重要组成部分,它控制了操作系统和硬件设备之问的交互,同时让软件开发人员在不用知道底层硬件特性的情况下方便地进行上层软件的开发.基于Arm+Linux系统,内核版本2.6,对字符驱动程序的开发做出详细的讲解,通过调试程序,使驱动正常运行.关键词:嵌入式;Linux;字符设备驱动中图分类号:TP393,04文献标识码:A1引言越来越多的企业和科研机构开始进行嵌入式Linux的开发和应用.究其原因,嵌入式Linux具有天生秉承的优势:开放的源码,丰富的软件资源;功能强大的内核,精简,高效,稳定,支持多任务,且可以灵活剪裁,功能定做;支持多种体系结构;完善的网络通讯,图形,文件管理机制等等.由于嵌入式操作系统本身没有对种类繁多的硬件提供设备驱动,操作系统在没有设备驱动的情况下无法正常运行,同时对于嵌入式开发,更没有通用的驱动程序可以使用,这就要求我们能够独立开发基于自己硬件设备特点的设备驱动.重点讲述了在基于Arm+Linux,内核版本2.6的环境中,字符设备驱动程序的编写方法及调试.2设备驱动类型在Linux操作系统下有两类主要的设备文件类型,一种是字符设备,另一种是块设备.字符设备和块设备的主要区别是:在对字符设备发出读请求时,实际的硬件I/O读就紧接着发生了,块设备则是利用一块系统内存作缓冲区,当用户进程对设备请求能满足用户的要求,就返回请求的数据,如果不能,就调用请求函数来进行实际的I/O操作.块设备主要针对磁盘等慢速设备设计的,以免耗费过多的CPU时间来等待.基于这个特点,一般都是编写字符设备驱动去控制外围芯片,如外围时钟芯片.3内核空间和用户空间设备驱动运行在内核空间,应用程序运行在用户空问,应用程序运行在最低级别的用户态,在这一级别处理器禁止对硬件的直接访问和内存的未授权访问,要使用户空间和内核空间进行数据的传输,这就需要使用几个函数,copyfromuser()实现用户空间到内核空间数据复制,copytouser()实现内核空间到用户空间数据复制.4设备驱动动态加载机制Linux内核是一个整体结构,因此向内核添加或者删除某些功能十分困难,而且添加一个有问题的设备驱动将导致整个系统崩溃.所以通常情况,可以将设备驱动程序动态的加载或者删除.内核版本2.6的Linux其字符设备驱动在加载时,首先需要调用人口函数cdevinit(),该函数完成设备驱动的初始化工作,比如寄存器置位,结构体赋值等.其中最重要的工作就是向内核注册设备,对于字符设备使用cdevadd()完成注册,注册成功后,该设备获得了系统分配的主设备号,次设备号,并建立起与文件系统的关联.设备驱动在卸载时调用cdevdel(),之后就不能访问这个驱动模块了.系统调用部分则是对设备的操作过程.图1是一个设备驱动模块动态加载,卸载和系统调用过程.收稿日期:200709.17;修订日期:20071016276成都信息工程学院第23卷5字符驱动访问外部时钟芯片实例下面基于一块AT91RM9200处理器,通过驱动控制实时时钟芯片DS1307来分析字符驱动的编写原理.首先需要搞懂这个时钟RTC驱动所占用的硬件资源,比如说端口资源.DS1307通过I2C接口和AT91RM9200的12C控制器接口PA25,PA26相连,12C控制器初始化如下.voidAT91一TwIInit(void)AT91PS一1Itwi=(AT91PSTwI)AT91CVABASETWI;/愎用PIOA的25,26脚为I2C的SDA,SCLAT91一SYS一>PIOA一【)ER=0x06000000;AT91一SYS一>PIOAASR=0x06000000;AT91一SYS一>PIOAPDR=0x06000000;/开启外设时钟AT91一SYS一>PMCPCER=OxO0001000;/中断禁止twi一>TWIIDR=Oxffffffff:/开启12C总线数据传输twi一>TWICR=0x24:/设置I2C时钟波形发生寄存器twi一>TWICWGR=0x00019595:需要注意的是,在A11RM9200中,TI(TwowireInterface)就是表示12C总线.图1设备驱动模块在内核中的加载卸载和系统调用在Linux2.6版本的内核中,采用如下的方法初始化一个字符设备:定义一个文件操作的数据结构DS1307一fopsstructfileoperationsDS1307一fops=.open=OPENDS1307.read=READDS1307,.write=WRITEDS1307,.release:CLOSEDS1307.;定义设备的主,次设备号以及设备名称,intmajor=0;intminor=0;charmychrdevice=RTCDS1307:定义一个设备编号变量,此类型是一个32位的数,其中12位用来表示主设备号,其余20位用来表示次设备号,如下:devtdev;采用动态分配设备号的方法注册设备如下:allocchrdevregion(&dev,minor,1,mychrdevice);major=MAJOR(dev);/获得系统分配的主设备号structcdev*DS1307一cdev=cdevalloc();/定义一个字符设备并填充数据空间cdevinit(DS1307一cdev,&DS1307一fops);mycdev一>owner=THISMODULE;cdevops=&DS1307一fops;cdevadd(DS1307一cdev);第3期王科等:基于嵌入式Linux的字符设备驱动开发277字符设备注册完成后,调用AT91一TWIInit(void),整个字符驱动的初始化完成.在应用程序中,对这个设备文件的打开,渎,写,关闭等操作,需要DS1307fops所定义的函数来解释.所以接下来写函数实现对DS1307的读写控制.DS1307的12C地址为0x68,故定义如下:#defineDS1307一I2CADDRESS(0x68<<16)首先需要实现对TWI总线的读写控制,如下:intTwIWrite(charaddress,char*data2send,charsize)A1PSTItwi=(A1PSTI)AT91CVABASE一1WI;/rrWI模式寄存器中设置从机地址,从机地址长度,并且定义为写操作twi一>TwIMMR=(DS130712CADDRESSlAT91CTwIIADRSZ一1一BYTE)&AT91CTWIMREAD;twi一>TWIIADR=address;/从机内部寄存器地址twi一>TWITHR=*(data2send+);/将需要发送的数据写入传送保持寄存器twi一>TWICR=A1CTWISTART;/启动发送while(size一>1)/从机返回应答信号ACK表示传输成功,并且开始下一个字节的传输while(!(twi一>TwISR&AT91CTwITXRDY);twi一>TWITHR=*(data2send+);twi一>TWICR:ATglCrrWISTOP;/停止传输while(!(twi一>TWISR&AT91CTWITXCOMP);/等待传输完成后,rrW1一SR中传输完成标志TWITXCOMP置位return0;lIntTwIRead(charaddress,char*data,charsize)AT91PSTWItwi=(AT91PSTWI)AT91CVABASETWI:twi一>TwIMMR=DS130712CADDRESSlAT91CTwIIADRSZ一1-BYTElAT91CTwIMREAD;twi一>TWICR=AT91CTWISTART;status=twi一>TWISR:while(size一一>1)while(!(twi一>TWISR&AT91CTWIRXRDY):*(data+)=twi>TwIRHR:twi一>TWICR=AT91CTWISTOP:status=twi一>TWISR;while(!(twi一>TWISR&AT91CTWITXCOMP);*data=twi一>TWIRHR;return0;DS1307的内部寄存器OxO0一Ox06依次存放的是秒,分,时,星期,日,月,年,所以需要一次读,写7个寄存器才可以得到或者写入正确的时间信息.同时注意的是,DS1307寄存器中的数据格式BCD需要转换成BIN格式,定义如下转换函数#defineBIN2BCD(va1)(va1)/10)<<4)+(va1)%10)#defineBCD2BIN(va1)(va1)&15)+(va1)>>4)*10)在linux内核中定义了一个,1u7结构体,structrtctime278成都信息工程学院第23卷Inttmyear;Inttm它来表示实时时间.mon;Inttmday;Inttmwday;Inttmhour;Inttmmin;Inttmsec;对应用程序中read()函数的解释用如下函数实现:staftcvoidREADDS1307(structinode*inode,char*buff,sizetcount,structfile*filp)chardata7;Structrtctimertctm,tictm;rtctm=&一rtctm;TwIRead(OxO,data,7);rtctm一>tmyear=2000+BCD2BIN(data6);rtctm一>tmmon=BCD2BIN(data5);rtctm一>tmmday=BCD2BIN(data4);rtctm一>tmwday=BCD2BIN(data3);rtctm一2>tmhour=BCD2BIN(data2);rtctm一>tmmin=BCD2BIN(data1);rtctm一>tmsee=BCD2BIN(data0J);copytouser(structrtctime*)buff,&rtctm,sizeof(structrtctime);对write()函数的解释用如下函数实现:staticvoidWRITEDS1307(structinode*inode,char*buff,sizetcount,structfile*filp)chardata7;Structrtctimertctm,r-tctm;rtctm=&一rtctm;Copyfromuser(&rtctm,(structrtctime*)buff,count);data6=BIN2B(,D(rtctm一2>tmyear一2000);data5=BIN2B(,D(rtctm一2>tmmon);data4=BIN2B(,D(rtctm一>tmmday);data3=BIN2BCD(rtctm一2>tmwday);data2=BIN2BCD(rtctm一2>tmhour);data1=BIN2B(,D(rtctm一2>tmmin);data0=BIN2BCD(rtctm一2>tmsee);TWIWte(OxO,data,7);驱动的基本读写功能就实现了.注意的是当模块调用结束时,需要注销模块并且释放占用的资源.cdevdel(DS1307一cdev);unregisterchrdevregion(dev,0);6加载模块并调试模块通过交叉编译后,把生成的mychrdevice.ko文件下到目标板上,通过如下命令可以动态加载此模块insmodRTCDS1307.ko此时查看文件/proc/devices,可以看到系统自动给RTCDS1307分配的主设备号,添加设备文件节点就可以访问RTCDS1307文件了.mknod/dev/RTCDS1307c主设备号0可以编写如下应用程序,来测试此时钟驱动程序的运行情况.通过调用系统函数read(),write(),读,写DS1307:Structrtctimerealtime.realtime;第3期王科等:基于嵌入式Linux的字符设备驱动开发279/定义一个时间结构体来接收驱动返回的时间信息或者向驱动写入这个结构体信息.realtime=&一Realtime:realtime一>tmyear=2007:realtime一>tmmon=11:realtime一>tmmday=12:realtime一>tmwday=5:realtime一>tmhour=12:realtime一>tmmin=30:realtime一>tmsec=30:intfd=open(/devTCDS1307,ORDwR);write(fd,realtime,sizeof(reaitime);/以上操作将一个时间值写到了DS1307为了验证写时钟是否正确,可以再将时钟值读出来memset(realtime,0,sizeof(realtime);read(fd,realtime,sizeof(realtime);printf(%04d一%02d一%02d,%01d,%02d:%02d:%02d,realtime一>tmyear,realtime一>tmmon,realtime一>tmmday,realtime一>tm-wday,realtime一>tmhour,realtime一>tmmin,realtime一>tmsec);此时将显示读到的实时时钟信息:20071012,5,12:30:30读写操作完后释放此文件句柄:close(fd):当调式完成后,通过如下命令卸载模块rmmodRTCDS13077结论通过编写以上的应用程序进行验证,这个驱动能够正常运行,可以完成基本的时钟读写操作,同时也验证了在Linux2.6内核中,如上的字符驱动编写方法的正确性.需要注意的是,在驱动程序中,需要对并发和竞态做出相应的处理,以防止由于频繁读写操作导致系统崩溃,自旋锁就是很好的解决措施.参考文献:1毛曙福.LinuxC高级程序员指南M.北京:国防_r-,3k出版社,2001.2孙琼.嵌入式Linux应用程序开
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025-2026学年地质版(2024)小学体育与健康二年级全一册《男孩 女孩》教学设计
- 2025年高考生物试题分类汇编:种群及其动态解析版
- 2025年高考生物试题分类汇编:体液调节解析版
- 2025企业劳动合同样本
- 小白杨81章题目及答案
- 消防考试易考题目及答案
- 2025餐厅聘请厨师合同
- 乡土中国说课题目及答案
- 2025医疗设备租赁合同范本
- 物业保安试题及答案
- 超高层带伸臂结构巨型环桁架施工技术总结附图
- 2022年中石化污水处理工应知应会题库(含答案)
- 火焰探测器设计手册
- GB/T 778.1-2018饮用冷水水表和热水水表第1部分:计量要求和技术要求
- GB/T 19839-2005工业燃油燃气燃烧器通用技术条件
- GB/T 19478-2018畜禽屠宰操作规程鸡
- (完整版)人工智能介绍课件
- 陶瓷材料的制备课件
- 中职统计基础知识课件
- 预防校园欺凌-共创和谐校园-模拟法庭剧本
- 《人间词话》十则公开课
评论
0/150
提交评论