s3c2410的字符型设备驱动程序设计.doc

上传人:豆**** 文档编号:23968536 上传时间:2022-07-03 格式:DOC 页数:44 大小:343.50KB
返回 下载 相关 举报
s3c2410的字符型设备驱动程序设计.doc_第1页
第1页 / 共44页
s3c2410的字符型设备驱动程序设计.doc_第2页
第2页 / 共44页
点击查看更多>>
资源描述

《s3c2410的字符型设备驱动程序设计.doc》由会员分享,可在线阅读,更多相关《s3c2410的字符型设备驱动程序设计.doc(44页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、Four short words sum up what has lifted most successful individuals above the crowd: a little bit more.-author-dates3c2410的字符型设备驱动程序设计源代码fakedev.c 福建工程学院 课程设计报告 实验课题: s3c2410的字符型设备驱动程序设计 指导老师:陈老师 日期:2011年5月24号一、 实验原理:1 Linux系统下驱动程序的相关概念: Linux系统中,设备驱动程序是操作系统内核的重要组成部分,它与硬件设备之间建立了标准的抽象接口。通过这个接口,用户可以像处

2、理普通文件一样,对硬件设备进行打开(open)、关闭(close)、读写(read/write)等操作。通过分析和设计设备驱动程序,可以深入理解Linux系统和进行系统开发。Linux设备分为字符设备、块设备和网络设备。本课程设计研究字符型设备驱动程序设计。 Linux系统为每一个设备分配了一个主设备号和 次设备号,主设备号标识设备对应驱动程序 ,次设备号标识具体设备的实例。例如一块开发板上有2个串口终端 / dev/ tty0, / dev/ tty1 ,它们的主设备号都是4,次设备号分别为0和1。每一类设备使用的主设备号是独一无二的,系统增加一个驱动程序就要赋予它一个主设备号,这一赋值过程

3、在驱动程序的初始化过程中进行。2设备驱动程序的组成 设备驱动在加载时首先需要调用入口函数 init module ( ) ,该函数完成设备驱动的初始化工作 ,比如寄 存器置位、结构体赋值等一系列工作,其中最重要的一个工作就是向内核注册该设备 ,字符设备调用函数register_chrdev 完成注册。注册成功后 ,该设备获得了系统分配或向系统申请的主设备号、自定义的次设备号,并建立起与设备文件的关联。设备驱动在卸载时需要回收相应的资源 ,将设备的响应寄存器值复位并从系统中注销该设备。系统调用部分则是对设备的 操作过程 , 比如 open、read、write、ioctl等操作。设备驱动程序可以

4、分成以下 3个主要部分: (1) 自动配置和初始化子程序。负责检测所需驱动的硬件设备是否存在以及是否能正常工作 ,这部分驱动程序仅在初始化时被调用一次。(2) 服务 I/O 就是请求子程序,是驱动程序的上半部分,这部分是系统调用的结果。 (3) 中断服务程序又称驱动程序的下半部分,设备在 I/O请求结束或其他状态改变时产生中断。因为设备驱动程序一般支持同一类型的若干个设备 ,所以调用中断服务子程序时都带有一个或多个参数以唯一标识请求服务的设备。 3字符设备驱动程序中重要的数据结构和函数对于每个系统调用,驱动程序中都有一个与之对应的函数。对于字符设备驱动程序 ,这些函数集合在一个file_op

5、erations类型的数据结构中,它定义了常见文件I/O 函数的入口.编写字符设备驱动程序就是为具体硬件的 file_ operations结构编写各个函数 ,大多数的驱动程序只是利用了其中的一部分 对于驱动程序中不提供的功能,把相应位置的值设为 NULL ) ,对于字符设备来说 ,要提供的主要入口有: open ( ) 、release ( ) 、read ( ) 、write( ) 、lseek ( ) 、ioctl ( )等。本课程设计中用到的主要有 open ( )、read ( )、write( )、release ( )函数。int (*open)(struct inode*,st

6、ruct file*); 该操作用来打开设备文件。int (*release)(struct inode*,struct file*); 该操作用来释放文件结构。ssize_t(*read)(structfile*,char_user*,size_t,loff_t*); 该操作用来从设备中读取数据。ssize_t(*read)(structfile*,char_user*,size_t,loff_t*); 该操作发送数据给设备。4驱动程序的注册和卸载驱动程序有一个初始化函数 ,在安装驱动程序时会调用它。在初始化函数中会将驱动程序的 file_operations与主设备号一起向内核进行注册。对

7、字符设备使用如下函数进行注册:int register_chrdev ( unsigned int major, const char* name, struct file_operations* fop s) ; 其中,major是为设备驱动程序向系统申请的主设备号,如果为 0则系统动态地分配 l个主设备号, name是设备名。fop s是 file_operation s对各个调用入口点的说明。此函数返回0表示成功;返回 - 1是表示出 错;返回 - E INVAL 表示申请的主设备号非法;返回- EBU SY表示所申请的主设备号正在被其他设备驱动程序使用。模块在调用 rmmod 函数时被

8、卸载 ,此时的入口点是 cleanup_module函数或宏 module_exit,并在其中完成对设备的注销。类似的,字符设备的卸载函数定义为:int unregister_chrdev ( unsigned int major, const char* name) ;二、 实验目的:了解、掌握字符型驱动程序的设计过程、编译、加载以及测试过程,包括了解file_operation数据结构、驱动程序的注册与注销、makefile文件的编写。 三、 实验步骤:写入驱动程序源程序fakedev.c,本程序设计思维为设备输入一串字符,再输出同样的字符。设备驱动程序的主体流程为:module_init

9、-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 #define DEVICE_NAME fake deviceMODULE_LICENSE(Dual BSD/GPL); /*用宏

10、来声明该模块的许可协议*/struct fake_device /* 该设备其他的私有数据和信号量的信息的定义 */int usage;char *data;int new_msg;struct fake_device fakedev; int fakedev_major = 200; /*指定设备主设备号为200*/ /*以下为file_operation数据结构*/static int fakedev_open(struct inode *inode, struct file *file) /*定义了fakedev_open即打开操作函数,这里函数定义为只打印一行消息*/ printk (

11、fakedev_device_open(%p,%p)n, inode, file); return 0;static int fakedev_release(struct inode *inode, struct file *file) /*定义了 fakedev_release即释放文件结构函数。*/static void fakedev_device_release(%p,%p)n, inode, file);static ssize_t fakedev_read(struct file *f,char *buf,int size,loff_t off) /*定义了 fakedev_rea

12、d即从设备中读取数据的函数*/ int length;int count=size;if(count0)return -EINVAL;if(fakedev.usage)return -EBUSY;fakedev.usage=1;if(fakedev.data =0 )return 0;length = strlen(fakedev.data);if (length count)count=length;copy_to_user(buf,fakedev.data,count+1);fakedev.new_msg=0;fakedev.usage=0;return count;static ssiz

13、e_t fakedev_write(struct file *f,const char *buf,int size,loff_t off) /*定义fakedev_write函数即发送数据给设备函数*/ int count=size;if(count0)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.d

14、ata)return -ENOMEM;copy_from_user(fakedev.data,buf,count + 1);fakedev.usage = 0;fakedev.new_msg = 1;return count;struct file_operations fakedev_fops = /*定义该字符设备的具体文件操作,包括read、write、open、release*/.read = fakedev_read, .write = fakedev_write,.open = fakedev_open,.release = fakedev_release,;static int

15、fakedev_init_module(void) /*定义fakedev_init_module,即字符设备向 系统注册函数*/ int result;result = register_chrdev(fakedev(fakedev_major,DEVICE_NAME,&fakedev_fops);if (result 0)return result;if (fakedev_major = 0)fakedev_major = result;printk(KERN_INFO Register FAKEDEV.major-number=%dn,result);return 0;static vo

16、id fakedev_cleanup_module(void) /*定义fake_exit_module,即字符设备向系统注销函数*/ printk(KERN_INFO Unregister FAKEDEVn);unregister_chrdev(fakedev_major, DEVICE_NAME);module_init(fakedev_init_module); /*包含了注册、注销两个函数的指针*/module_exit(fakedev_cleanup_module);Makefile文件:在linux2.6内核中,模块的编译需要配置过的内核代码,编译过程首先会到内核源码目录下,读取顶

17、层的makefile文件,然后再返回模块代码所在目录进行编译.可根据网络上公开的针对字符设备驱动程序的makefile模板进行该模块makefile文件设计。 Makefile文件# Makefile2.6ifneq ($(KERNELRELEASE),)#kbuild syntax. dependency relationshsip of files and target modules are listed here.obj-m := fakedev.o /*指定模块源文件*/elsePWD := $(shell pwd)KVER ?= $(shell uname -r)KDIR := /

18、lib/modules/$(KVER)/build /*指定内核源码的路径*/all : $(MAKE) -C $(KDIR) M=$(PWD)clean : rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versionsendif通过执行makefile来编译驱动程序的源文件fakedev.c,以得到可执行目标文件。截图如下:由截图可见:编译之后得到可加载模块fakedev.ko。fakedev源程序的测试程序fakedev_test.c。测试的例程:运行之前需要使用mkond命令来创建设备文件,然后执行不带参数的insmod,将上面编译得到的可加载模块fakede

19、v.ko装载到内核。测试代码fakedev_test.c#include /*所需头文件与预定义*/#include#include#include#include#include#define MAX_LENGTH 100int mian (int argc, char *argv)char strMAX_LENGTH;char p;printf(please enter the words(max char num:%d):n,MAX_LENGTH -1);p = fgets(str,MAX_LENGTH,stdin); /*接收控制台输入的一组字符串*/int fakedev_fd=op

20、en(/dev/fakedev,O_RDWR);/*通过open系统调用打开虚拟设 if (fakedev_fd=-1) 备并获得文件描述符fakedev_fd*/perror(open);exit (1);write (fakedev_fd,p,strlen(p); /*通过write系统调用将字符串缓存到该设备中*/char bufMAX_LENGTH; /*将字符取出来打印到标准输出*/read(fakedev_fd,buf,MAX_LENGTH -1);printf(Get strings from fakedev:n%sn, buf);close (fakedev_fd);retur

21、n 0;截图如下: 由上图可看到:mknod命令指定了主设备号200,其余的参数:-m600设置为设备文件的读写权限;字符c代表这是一个字符设备;200之后的1为次设备号。使用insmod命令将fakedev.ko加载之后,就可以从/proc/devices看到设备文件fake device( 在源代码中已经被定义)测试运行程序:运行test,就可在终端中摸拟本设计程序的功能。如若能够在输入一行字符串之后,终端能自行输出同样的字符串,则说明该程序设计正确。即输入: #./test 测试结果达到了我们需要的效果:输入字符22之后,通过write系统调用将其写入/dev/fakedev设备中,再通过read系统调用从该设备中得到了该字符串。四 实验总结:本文结合简单字符设备驱动程序的开发,详细讨论了嵌入式 L inux系统中字符设备驱动程序的设计方法和关键技术 ,对类似的其他字符设备驱动程序开发过程可以起到一定的启发作用。在编译过程中会遇到找不到头文件的问题,这时可以通过寻找添加头文件以求编译通过。-

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 教育专区 > 小学资料

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁