收藏 分享(赏)

实验五-driverdemo设备驱动程序.ppt

上传人:scg750829 文档编号:7996031 上传时间:2019-06-03 格式:PPT 页数:32 大小:154.50KB
下载 相关 举报
实验五-driverdemo设备驱动程序.ppt_第1页
第1页 / 共32页
实验五-driverdemo设备驱动程序.ppt_第2页
第2页 / 共32页
实验五-driverdemo设备驱动程序.ppt_第3页
第3页 / 共32页
实验五-driverdemo设备驱动程序.ppt_第4页
第4页 / 共32页
实验五-driverdemo设备驱动程序.ppt_第5页
第5页 / 共32页
点击查看更多>>
资源描述

1、嵌入式系统设计实验五 设备驱动程序,2,实验内容,5.1 内核驱动设计入门-模块方式驱动实验,3,实验步骤,实验指导书P223-225 进入/arm2410s/exp/drivers/demo目录,使用VI查看源码 编译驱动模块及测试程序 cd /arm2410s/exp/drivers/demo/ make,4,实验步骤,注:如果编译的时候出现问题,可能在/usr/src下没有建立一个linux连接,可以使用下面的命令: cd /usr/src/ ln sf linux-2.4.20-8 linux ls 查看目录文件,可见有如下文件:debug linux linux-2.4 linux-

2、2.4.20-8 redhat,5,实验步骤,如果用gcc编译,需要通过下面的命令来建立设备节点,如果使用交叉编译的话,则不需要建立设备节点。 mknod /dev/demo c 254 0插入驱动模块 root demo# Insmod demo.o 执行命令进行测试: root demo#./test_demo,6,实验步骤,运行结果,7,设备驱动程序,设备驱动程序的作用 设备驱动程序的分类 设备驱动程序在操作系统中的位置 机制与策略 设备驱动程序的基本结构 设备驱动程序如何被使用 一个简单设备驱动程序实例,8,设备驱动程序的作用,设备驱动程序将复杂的硬件抽象成一个结构良好的设备,并通过提

3、供统一的程序接口为系统的其它部分提供使用设备的能力和方法。 设备驱动程序(应该只是)为系统的其它部分提供各种使用设备的能力,使用设备的方法应该由应用程序决定。,9,Linux下对外设的访问只能通过驱动程序Linux对于驱动程序有统一的接口,以文件的形式定义系统的驱动程序: Open、Release、read、write、ioctl驱动程序是内核的一部分,可以使用中断、DMA等操作驱动程序需要在用户态和内核态之间传递数据,10,设备驱动程序的分类,字符设备驱动程序 各种串行接口,并行接口等。 块设备驱动程序 磁盘设备等 网络设备驱动程序 网卡等。 杂项设备驱动程序 不属于上述三种设备之外的一些设

4、备,如SCSI,时钟等。,11,在操作系统中的位置,设备驱动程序是内核代码的一部分。 驱动程序的地址空间是内核的地址空间。 驱动程序的代码直接对设备硬件(实际是设备的各种寄存器)进行控制(实际就是读写操作)。 应用程序通过操作系统的系统调用执行相应的驱动程序函数。中断则直接执行相应的中断程序代码。 设备驱动程序的file_operations结构体的地址被注册到内核中的设备链表中。 块设备和字符设备以设备文件的方式建立在文件系统中的/dev目录下,而且每个设备都有一个主设备号和一个次设备号。,12,块设备驱动程序,字符设备驱动程序,网络设备驱动程序,13,ls -l /devcrw-r- 1

5、root root 1, 1 Jan 1 00:00 mem crw-r- 1 root root 1, 2 Jan 1 00:00 kmem crw-rw-rw- 1 root root 1, 3 Jan 1 00:00 null crw-r- 1 root root 1, 4 Jan 1 00:00 port crw-rw-rw- 1 root root 1, 5 Jan 1 00:00 zero crw-rw-rw- 1 root root 1, 7 Jan 1 00:00 full crw-r-r- 1 root root 1, 8 Jan 1 00:00 random crw-r-r

6、- 1 root root 1, 9 Jan 1 00:00 urandom crw-rw-rw- 1 root root 5, 0 Jan 1 00:00 tty crw- 1 root root 5, 1 Jan 1 00:00 console crw-rw-rw- 1 root root 5, 2 Jan 1 00:00 ptmx drwxr-xr-x 1 root root 0 Jan 1 00:00 pty drwxr-xr-x 2 root root 0 Jan 1 00:00 pts drwxr-xr-x 1 root root 0 Jan 1 00:00 rd drwxr-xr

7、-x 1 root root 0 Jan 1 00:00 mtd drwxr-xr-x 1 root root 0 Jan 1 00:00 mtdblock crw- 1 root root 4, 64 Jan 1 00:15 ttyS0 crw- 1 root root 4, 65 Jan 1 00:00 ttyS1 crw- 1 root root 4, 66 Jan 1 00:00 ttyS2 crw- 1 root root 4, 67 Jan 1 00:00 ttyS3 crw- 1 root root 4, 68 Jan 1 00:00 ttyS4 drwxr-xr-x 1 roo

8、t root 0 Jan 1 00:00 misc,c:字符设备 b:块设备,主设备号,次设备号,14,机制与策略,机制(mechanism) 设备驱动程序所具备的能力 例如:串行设备驱动程序具有设置波特率的能力。 策略(policy) 这些能力如何被使用 例如:根据需要将串口波特率设置成9.6kbps。,设备驱动程序应该是“策略无关”的,即policy free。,15,设备驱动程序源代码的基本结构,/* 驱动程序简单说明:* 驱动程序的作用:这是一个字符设备驱动程序的基本框架结构* 被驱动设备的简单描述:将使用AT91RM9200的PB端口为例进行说明* 一些特殊的考虑等:如PB21作为可

9、以产生中断的输入引脚(本例未实现)* 版本,创建日期,作者等:1.0版,2006年1月6日 */#ifndef _KERNEL_ #define _KERNEL_ #endif #ifndef MODULE #define MODULE #endif#include #include . #include ,表明这个模块将用于内核,也可以在编译时通过 D选项指定,如gcc D_KERNEL_。参见Makefile。,内核头文件,需要根据具体驱动程序和用到的内核模块确定。,表明这个驱动程序将以模块的方式编译和使用,也可以在编译时通过 D选项指定,如 gcc DMODULE。参见Makefile。

10、,16,/* 驱动程序中使用的各种函数的原型声明。标准的作法是将函数原型声明* 放在一个头文件中,然后在该文件开始处使用#include引用,并在该* 文件中定义。* 这里我们将函数的声明和定义放在一起。所以下面的代码既是函数的声明,* 也是函数的定义。*/static ssize_t spioc_read(struct file *filp, char *buffsize_t cnt, loof_t *off) /* 这里是read函数的代码 */return ret; static ssize_t spioc_write(struct file *filp, char *buffsize_

11、t cnt, loff_t *off) /* 这里是write函数的代码 */return ret; ,17,static int spioc_ioctl(struct inode *inode, struct file *filpunsigned int cmd, unsigned long arg) /* 这里是ioctl函数的代码,它的一般格式为一个switch分支语句* switch(cmd) * case CMD1: * .* break;* .* case CMDn:* .* break* default:* .* break;* */return ret; ,ioctl()函数用

12、于控制驱动程序本身的一些特性和参数,如设定驱动 程序使用的缓冲区的大小,设定串行通讯的速率等。,18,static int spioc_open(struct inode *inode, struct file *filp) /* 这里是open函数的代码 */return ret; static int spioc_close(struct inode *inode, struct file *filp) /* 这里是close函数的代码 */return ret; ,上述5个函数,既read(), write(), ioctl(), open(), close(),是一个字符 设备驱动程序

13、最基本的需要由驱动程序的作者完成的函数。这5个函数将对应于相应的5个系统调用:read() - spioc_read()write() - spioc_write()ioctl() - spioc_ioctl()open() - spioc_open()close() - spioc_close(),系统调用,驱动程序函数,19,static struct file_operations spioc_fops = read: spioc_read,write: spioc_write,ioctl: spioc_ioctl,open: spioc_open,release: spioc_clos

14、e, ;,file_operations是一个结构体类型,定义在include/linux/fs.h中。上述代码定义了一个file_operations类型的结构体spioc_fops,并将 其中的一些成员赋了初值。由于spioc_fops是一个静态变量,所以其他成员 的初值是“零”。结构体spioc_fops将作为一个参数在注册一个设备驱动程序时传递给内核。 内核使用设备链表维护各种注册的设备。不同类型的设备使用不同的链表。,20,struct file_operations struct module *owner;loff_t (*llseek) (struct file *, loff

15、_t, int);ssize_t (*read) (struct file *, char *, size_t, loff_t *);ssize_t (*write) (struct file *, const char *, size_t, loff_t *);int (*readdir) (struct file *, void *, filldir_t);unsigned int (*poll) (struct file *, struct poll_table_struct *);int (*ioctl) (struct inode *, struct file *, unsigned

16、 int, unsigned long);int (*mmap) (struct file *, struct vm_area_struct *);int (*open) (struct inode *, struct file *);int (*flush) (struct file *);int (*release) (struct inode *, struct file *);int (*fsync) (struct file *, struct dentry *, int datasync);int (*fasync) (int, struct file *, int);int (*

17、lock) (struct file *, int, struct file_lock *);ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);unsigned long

18、 (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); ;,struct file_operations,include/linux/fs.h,21,static int _init spioc_init(void) /* 设备初始化代码等 */if(register_chrdev(SPIOC_MAJOR, “spioc”, ,22,module_init(spioc_init); module_exit(spioc_exit);,这两个函数,module

19、_init()和module_exit(),用于告诉内核,当一个驱动程序加载和退出(或撤消)时,需要执行的操作。不同驱动程序在加载和退出时,除了基本的向内核注册设备驱动程序外,还有各自的针对具体设备的操作。,23,要点总结:宏:_KERNEL_, MODULE, _VERSION_ _KERNEL_:表明这将是用于内核的代码,否则很多内核过程将无法使用。 MODULE:如果是以模块方式编译,需要定义这个宏;如果是静态连接则不用。 _VERSION_:定义这个宏则需要驱动程序的内核版本要和内核版本一致。module_init()/module_exit(): spioc_init()/spioc

20、_exit() 每个驱动程序都要有这两个函数,它们分别用于设备驱动程序的加载和撤消。static struct file_operations spioc_fops: 每个驱动程序都要有这样的结构体,可能不止一个。用register_chrdev() 注册驱动程序时这个结构体的起始地址被传送到内核的设备表中。SPIOC_MAJOR: 每个设备驱动程序有一个主设备号(major number)。不同设备驱动程序不能 使用相同的主设备号。一个设备驱动程序可以管理不同的(但一般是同一类的) 设备,通过次设备号(minor number)区分。spioc_ open()/close(),read()/

21、write(), ioctl(): 根据具体驱动程序定义和使用。一般open()/close()总是需要的,而且 open()和close()一定要成对出现。,24,设备驱动程序的使用,驱动程序模块的动态链接和静态链接 创建设备文件 使用设备,25,设备驱动程序被静态编译到内核中的情况: module_init()指示内核在启动过程中运行设备的初始化函数,如spioc_init()函数。驱动程序的加载随内核的启动一起完成。 静态编译的内核模块不能被动态卸载,只有到系统关闭时由内核执行相应的卸载函数,如spioc_exit()。 嵌入式操作系统一般使用静态内核模块以减少系统的尺寸和复杂性。,驱动

22、程序模块的加载,设备驱动程序被动态加载到内核中的情况: 首先,驱动程序需要被编译成目标文件,如spioc.o。 在操作系统运行之后,使用insmod命令将驱动程序模块动态加载到内核中 $ insmod spioc.o 使用insmod命令动态加载的内核模块可以使用rmmod命令动态地从内核中卸载 $ rmmod spioc 使用内核的动态模块加载/卸载功能需要内核支持kmod功能。,26,module_init(),module_exit(),27,创建设备文件,Linux操作系统将字符设备和块设备作为一种特殊的文件对待,这 就是设备文件。使用mknod命令建立设备文件。,$ mknod c

23、21 0 /dev/spioc,c:字符设备 b:块设备,主设备号,次设备号,设备文件,crw- 1 root root 21, 0 Jan 1 00:15 spioc,/dev,28,使用设备驱动程序,应用程序系统调用设备驱动程序设备(寄存器),使用一个设备一般需要执行如下一些操作: 打开设备文件。 对设备进行必要的设置,如设置串口速率。 对设备进行读、写等操作,如通过串口收发数据。 结束对设备的使用之前,如果改变了设备的某些设置,则将其恢复到缺省状态,保证设备停用后没有任何不好的副作用。 关闭设备。,一个设备如何被使用属于“策略”,应该由应用程序决定,而不是设备驱动程序。设备驱动程序应该只

24、实现“机制”。,29,int main(int argc, char *argv) .pd = open(“/dev/spioc”, O_RDWT);. ,应用程序,crw- 1 root root 21, 0 Jan 1 00:15 spioc,/dev,open(const char *, int),系统调用,static struct file_operations spioc_fops = read: spioc_read,write: spioc_write,ioctl: spioc_ioctl,open: spioc_open,release: spioc_close, ;,设备驱

25、动程序,static int spioc_open(struct inode *inode, struct file *filp) /* 这里是open函数的代码 */return ret; ,设备驱动程序,设备和驱动程序的使用,30,简单实例demo,字符设备驱动程序 使用动态内核模块加载 实现初始化(加载)和退出(卸载)功能 实现设备读写等功能 实现ioctl功能,31,编译设备驱动程序,使用静态内核模块 在内核源代码目录的相应子目录下建立设备驱动程序目录。 在设备驱动程序目录下建立Makefile文件。 修改上一级目录的Makefile文件。 使用动态内核模块 内核模块需要使用内核的头文件,因此需要安装内核源代码。 编写Makefile。,32,参考资料,Linux设备驱动程序,第二版,第一、二、三、四章,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报