s3c2410的字符型设备驱动程序设计.docx
- 文档编号:6014014
- 上传时间:2023-01-03
- 格式:DOCX
- 页数:10
- 大小:204.08KB
s3c2410的字符型设备驱动程序设计.docx
《s3c2410的字符型设备驱动程序设计.docx》由会员分享,可在线阅读,更多相关《s3c2410的字符型设备驱动程序设计.docx(10页珍藏版)》请在冰豆网上搜索。
s3c2410的字符型设备驱动程序设计
福建工程学院
课程设计报告
实验课题:
s3c2410的字符型设备驱动程序设计
指导老师:
陈老师
日期:
2011年5月24号
1、实验原理:
1Linux系统下驱动程序的相关概念:
Linux系统中,设备驱动程序是操作系统内核的重要组成部分,它与硬件设备之间建立了标准的抽象接口。
通过这个接口,用户可以像处理普通文件一样,对硬件设备进行打开(open)、关闭(close)、读写(read/write)等操作。
通过分析和设计设备驱动程序,可以深入理解Linux系统和进行系统开发。
Linux设备分为字符设备、块设备和网络设备。
本课程设计研究字符型设备驱动程序设计。
Linux系统为每一个设备分配了一个主设备号和次设备号,主设备号标识设备对应驱动程序,次设备号标识具体设备的实例。
例如一块开发板上有2个串口终端/dev/tty0,/dev/tty1,它们的主设备号都是4,次设备号分别为0和1。
每一类设备使用的主设备号是独一无二的,系统增加一个驱动程序就要赋予它一个主设备号,这一赋值过程在驱动程序的初始化过程中进行。
2 设备驱动程序的组成
设备驱动在加载时首先需要调用入口函数initmodule(),该函数完成设备驱动的初始化工作,比如寄存器置位、结构体赋值等一系列工作,其中最重要的一个工作就是向内核注册该设备,字符设备调用函数register_chrdev完成注册。
注册成功后,该设备获得了系统分配或向系统申请的主设备号、自定义的次设备号,并建立起与设备文件的关联。
设备驱动在卸载时需要回收相应的资源,将设备的响应寄存器值复位并从系统中注销该设备。
系统调用部分则是对设备的操作过程,比如open、read、write、ioctl等操作。
设备驱动程序可以分成以下3个主要部分:
(1)自动配置和初始化子程序。
负责检测所需驱动的硬件设备是否存在以及是否能正常工作,这部分驱动程序仅在初始化时被调用一次。
(2)服务I/O就是请求子程序,是驱动程序的上半部分,这部分是系统调用的结果。
(3)中断服务程序又称驱动程序的下半部分,设备在I/O请求结束或其他状态改变时产生中断。
因为设备驱动程序一般支持同一类型的若干个设备,所以调用中断服务子程序时都带有一个或多个参数以唯一标识请求服务的设备。
3 字符设备驱动程序中重要的数据结构和函数
对于每个系统调用,驱动程序中都有一个与之对应的函数。
对于字符设备驱动程序,这些函数集合在一个file_operations类型的数据结构中,它定义了常见文件I/O函数的入口.编写字符设备驱动程序就是为具体硬件的file_operations结构编写各个函数,大多数的驱动程序只是利用了其中的一部分对于驱动程序中不提供的功能,把相应位置的值设为NULL),对于字符设备来说,要提供的主要入口有:
open()、release()、read()、write()、lseek()、ioctl()等。
本课程设计中用到的主要有open()、read()、write()、release()函数。
int(*open)(structinode*,structfile*);该操作用来打开设备文件。
int(*release)(structinode*,structfile*);该操作用来释放文件结构。
ssize_t(*read)(structfile*,char_user*,size_t,loff_t*);该操作用来从设备中读取数据。
ssize_t(*read)(structfile*,char_user*,size_t,loff_t*);该操作发送数据给设备。
4 驱动程序的注册和卸载
驱动程序有一个初始化函数,在安装驱动程序时会调用它。
在初始化函数中会将驱动程序的file_operations与主设备号一起向内核进行注册。
对字符设备使用如下函数进行注册:
intregister_chrdev(unsignedintmajor,constchar*name,structfile_operations*fops);
其中,major是为设备驱动程序向系统申请的主设备号,如果为0则系统动态地分配l个主设备号,name是设备名。
fops是file_operations对各个调用入口点的说明。
此函数返回0表示成功;返回-1是表示出错;返回-EINVAL表示申请的主设备号非法;返回-EBUSY表示所申请的主设备号正在被其他设备驱动程序使用。
模块在调用rmmod函数时被卸载,此时的入口点是cleanup_module函数或宏module_exit,并在其中完成对设备的注销。
类似的,字符设备的卸载函数定义为:
intunregister_chrdev(unsignedintmajor,constchar*name);
2、实验目的:
了解、掌握字符型驱动程序的设计过程、编译、加载以及测试过程,包括了解file_operation数据结构、驱动程序的注册与注销、makefile文件的编写。
3、实验步骤:
①写入驱动程序源程序fakedev.c,本程序设计思维为设备输入一串字符,再输出同样的字符。
设备驱动程序的主体流程为:
module_init->fakedev_init_module-->register_chrdev-->fakedev_fops-->fakkdev_open/release/read/write.
源代码fakedev.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#defineDEVICE_NAME"fakedevice"
MODULE_LICENSE("DualBSD/GPL");/*用宏来声明该模块的许可协议*/
structfake_device{/*该设备其他的私有数据和信号量的信息的定义*/
intusage;
char*data;
intnew_msg;
}
structfake_devicefakedev;
intfakedev_major=200;/*指定设备主设备号为200*/
/*以下为file_operation数据结构*/
staticintfakedev_open(structinode*inode,structfile*file)
/*定义了fakedev_open即打开操作函数,这里函数定义为只打印一行消息*/
{
printk("fakedev_device_open(%p,%p)\n",inode,file);
return0;
}
staticintfakedev_release(structinode*inode,structfile*file)/*定义了{fakedev_release即释放文件结构函数。
*/
staticvoidfakedev_device_release(%p,%p)\n",inode,file);
}
staticssize_tfakedev_read(structfile*f,char*buf,intsize,loff_toff)
/*定义了fakedev_read即从设备中读取数据的函数*/
{
intlength;
intcount=size;
if(count<0)
return-EINVAL;
if(fakedev.usage)
return-EBUSY;
fakedev.usage=1;
if(fakedev.data==0)
return0;
length=strlen(fakedev.data);
if(length count=length; copy_to_user(buf,fakedev.data,count+1); fakedev.new_msg=0; fakedev.usage=0; returncount; } staticssize_tfakedev_write(structfile*f,constchar*buf,intsize,loff_toff)/*定义fakedev_write函数即发送数据给设备函数*/ { intcount=size; if(count<0) return-EINVAL; if(fakedev.usage|fakedev.new_msg) return-EBUSY; fakedev.usage=1; kfree(fakedev.data); fakedev.data=kmalloc(sizeof(char)*(count+1),GFP_KERNEL); if(! fakedev.data) return-ENOMEM; copy_from_user(fakedev.data,buf,count+1); fakedev.usage=0; fakedev.new_msg=1; returncount; } structfile_operationsfakedev_fops={ /*定义该字符设备的具体文件操作,包括read、write、open、release*/ .read=fakedev_read, .write=fakedev_write, .open=fakedev_open, .release=fakedev_release, }; staticintfakedev_init_module(void) /*定义fakedev_init_module,即字符设备向系统注册函数*/ { intresult; result=register_chrdev(fakedev(fakedev_major,DEVICE_NAME,&fakedev_fops); if(result<0) returnresult; if(fakedev_major==0) fakedev_major=result; printk(KERN_INFO"RegisterFAKEDEV.major-number=%d\n",result); return0; } staticvoidfakedev_cleanup_module(void) /*定义fake_exit_module,即字符设备向系统注销函数*/ { printk(KERN_INFO"UnregisterFAKEDEV\n"); unregister_chrdev(fakedev_major,DEVICE_NAME); } module_init(fakedev_init_module);/*包含了注册、注销两个函数的指针*/ module_exit(fakedev_cleanup_module); ②Makefile文件: 在linux2.6内核中,模块的编译需要配置过的内核代码,编译过程首先会到内核源码目录下,读取顶层的makefile文件,然后再返回模块代码所在目录进行编译.可根据网络上公开的针对字符设备驱动程序的makefile模板进行该模块makefile文件设计。 Makefile文件 #Makefile2.6 ifneq($(KERNELRELEASE),) #kbuildsyntax.dependencyrelationshsipoffilesandtargetmodulesarelistedhere. obj-m: =fakedev.o/*指定模块源文件*/ else PWD: =$(shellpwd) KVER? =$(shelluname-r) KDIR: =/lib/modules/$(KVER)/build/*指定内核源码的路径*/ all: $(MAKE)-C$(KDIR)M=$(PWD) clean: rm-rf.*.cmd*.o*.mod.c*.ko.tmp_versions endif 通过执行makefile来编译驱动程序的源文件fakedev.c,以得到可执行目标文件。 截图如下: 由截图可见: 编译之后得到可加载模块fakedev.ko。 ③fakedev源程序的测试程序fakedev_test.c。 测试的例程: 运行之前需要使用mkond命令来创建设备文件,然后执行不带参数的insmod,将上面编译得到的可加载模块fakedev.ko装载到内核。 测试代码fakedev_test.c #include #include #include #include #include #include #defineMAX_LENGTH100 intmian(intargc,char**argv) { charstr[MAX_LENGTH]; charp; printf("pleaseenterthewords(maxcharnum: %d): \n",MAX_LENGTH-1); p=fgets(str,MAX_LENGTH,stdin);/*接收控制台输入的一组字符串*/ intfakedev_fd=open("/dev/fakedev",O_RDWR);/*通过open系统调用打开虚拟设if(fakedev_fd==-1)备并获得文件描述符fakedev_fd*/ { perror("open"); exit (1); } write(fakedev_fd,p,strlen(p));/*通过write系统调用将字符串缓存到该设备中*/ charbuf[MAX_LENGTH];/*将字符取出来打印到标准输出*/ read(fakedev_fd,buf,MAX_LENGTH-1); printf("Getstringsfromfakedev: \n%s\n",buf); close(fakedev_fd); return0; } 截图如下: 由上图可看到: mknod命令指定了主设备号200,其余的参数: -m600设置为设备文件的读写权限;字符c代表这是一个字符设备;200之后的1为次设备号。 使用insmod命令将fakedev.ko加载之后,就可以从/proc/devices看到设备文件fakedevice(在源代码中已经被定义) ④测试运行程序: 运行test,就可在终端中摸拟本设计程序的功能。 如若能够在输入一行字符串之后,终端能自行输出同样的字符串,则说明该程序设计正确。 即输入: #./test 测试结果达到了我们需要的效果: 输入字符22之后,通过write系统调用将其写入/dev/fakedev设备中,再通过read系统调用从该设备中得到了该字符串。 四实验总结: 本文结合简单字符设备驱动程序的开发,详细讨论了嵌入式Linux系统中字符设备驱动程序的设计方法和关键技术,对类似的其他字符设备驱动程序开发过程可以起到一定的启发作用。 在编译过程中会遇到找不到头文件的问题,这时可以通过寻找添加头文件以求编译通过。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- s3c2410 字符 设备 驱动程序 设计