资源预览内容
第1页 / 共23页
第2页 / 共23页
第3页 / 共23页
第4页 / 共23页
第5页 / 共23页
第6页 / 共23页
第7页 / 共23页
第8页 / 共23页
第9页 / 共23页
第10页 / 共23页
亲,该文档总共23页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
内核驱动设计入门模块方式驱动实验一、实验目的一、实验目的学习在 LINUX 下进行驱动设计的原理 掌握使用模块方式进行驱动开发调试的过程二、实验内容二、实验内容在 PC 机上编写简单的虚拟硬件驱动程序并进行调试,实验驱动的各个接口函数的实现,分析并理解驱动与应用程序的交互过程。三、预备知识三、预备知识有 C 语言基础。 掌握在 Linux 下常用编辑器的使用。 掌握 Makefile 的编写和使用。 掌握 Linux 下的程序编译与交叉编译过程。 有驱动开发的基本知识。四、实验设备及工具四、实验设备及工具硬件:PC 机 Pentium 500 以上, 硬盘 40G 以上,内存大于 128M。 软件:PC 机操作系统 REDHAT LINUX 9.0 MINICOM AMR-LINUX 开发环境五、实验原理五、实验原理Linux 中的驱动设计是嵌入式 Linux 开发中十分重要的部分,它要求开发者不仅要熟悉Linux 的内核机制、驱动程序与用户级应用程序的接口关系、考虑系统中对设备的并发操作等等,而且还要非常熟悉所开发硬件的工作原理。这对驱动开发者提出了比较高的要求,这个实验主要是给大家进入驱动设计提供一个简单入门的一个实例,并不需要提供太多与硬件相关的内容,这部分应该是通过仔细阅读芯片厂家提供的资料来解决。驱动程序的作用是应用程序与硬件之间的一个中间软件层,驱动程序应该为应用程序展现硬件的所有功能,不应该强加其他的约束,对于硬件使用的权限和限制应该由应用程序层控制。但是有时驱动程序的设计是跟所开发的项目相关的,这时就可能在驱动层加入一些与应用相关的设计考虑,主要是因为在驱动层的效率比应用层高,同时为了项目的需要可能只强化或优化硬件的某个功能,而弱化或关闭其他一些功能;到底需要展现硬件的哪些功能全都由开发者根据需要而定。驱动程序有时会被多个进程同时使用,这时我们要考虑如何处理并发的问题,就需要调用一些内核的函数使用互斥量和锁等机制。驱动程序主要需要考虑下面三个方面:提供尽量多的选项给用户,提高驱动程序的速度和效率,尽量使驱动程序简单,使之易于维护。Linux 的驱动开发调试有两种方法,一种是直接编译到内核,再运行新的内核来测试;二是编译为模块的形式,单独加载运行调试。第一种方法效率较低,但在某些场合是唯一的方法。模块方式调试效率很高,它使用 insmod 工具将编译的模块直接插入内核,如果出现故障,可以使用 rmmod 从内核中卸载模块。不需要重新启动内核,这使驱动调试效率大大提高。我们的实验在 PC 机和 UP-NETARM2410-S 上都可以运行,编译时使用不同的编译器就可以了。1.驱动程序与应用程序的区别应用程序一般有一个 main 函数,从头到尾执行一个任务;驱动程序却不同,它没有 main函数,通过使用宏 module_init(初始化函数名); 将初始化函数加入内核全局初始化函数列表中,在内核初始化时执行驱动的初始化函数,从而完成驱动的初始化和注册,之后驱动便停止等待被应用软件调用。驱动程序中有一个宏 moudule_exit(退出处理函数名)注册退出处理函数。它在驱动退出时被调用。应用程序可以和 GLIBC 库连接,因此可以包含标准的头文件,比如 ,在驱动程序中是不能使用标准 C 库的,因此不能调用所有的 C 库函数,比如输出打印函数只能使用内核的 printk 函数,包含的头文件只能是内核的头文件,比如。2.内核版本与编译器的版本依赖当模块与内核链接时,insmod 会检查模块和当前内核版本是否匹配,每个模块都定义了版本符号_module_kernel_version,这个符号位于模块文件的 ELF 头的.modinfo 段中。只要在模块中包含,编译器就会自动定义这个符号。每个内核版本都需要特定版本的编译器的支持,高版本的编译器并不适合低版本的内核,比如 UP-NETARM2410-S 实验仪中的 LINUX-2.4.19 的内核需要 2.95.3 的 GCC 版本编译器。Linux-2.4 版本的 insmod 命令装载模块时,首先从/lib/modules 目录和内核相关的子目录中查找模块文件,如果需要从当前目录装载,使用 insmod module.o。3.主设备号和次设备号传统方式中的设备管理中,除了设备类型外,内核还需要一对称作主次设备号的参数,才能唯一标识一个设备。主设备号相同的设备使用相同的驱动程序,次设备号用于区分具体设备的实例。比如 PC 机中的 IDE 设备,一般主设备号使用 3,WINDOWS 下进行的分区,一般将主分区的次设备号为 1,扩展分区的次设备号为 2、3、4,逻辑分区使用 5、6.。设备操作宏 MAJOR()和 MINOR()可分别用于获取主次设备号,宏 MKDEV()用于将主设备号和次设备号合并为设备号,这些宏定义在 include/linux/kdev_t.h 中。对于 LINUX 中对设备号的分配原则可以参考 Documentation/devices.txt。对于查看/dev 目录下的设备的主次设备号可以使用如下命令:/mnt/yaffsls /dev -l crw- 1 root root 5, 1 Jan 1 00:00 console crw- 1 root root 5, 64 Jan 1 00:00 cua0 crw- 1 root root 5, 65 Jan 1 00:00 cua1 crw-rw-rw- 1 root root 1, 7 Jan 1 00:00 full drwxr-xr-x 1 root root 0 Jan 1 00:00 keyboard crw-r- 1 root root 1, 2 Jan 1 00:00 kmemcrw-r- 1 root root 1, 1 Jan 1 00:00 memdrwxr-xr-x 1 root root 0 Jan 1 00:00 mtddrwxr-xr-x 1 root root 0 Jan 1 00:00 mtdblockcrw-rw-rw- 1 root root 1, 3 Jan 1 00:00 nullcrw-r- 1 root root 1, 4 Jan 1 00:00 portcrw- 1 root root 108, 0 Jan 1 00:00 pppcrw-rw-rw- 1 root root 5, 2 Jan 1 00:00 ptmxcrw-r-r- 1 root root 1, 8 Jan 1 00:00 randomlr-xr-xr-x 1 root root 4 Jan 1 00:00 root - rd/0crw-rw-rw- 1 root root 5, 0 Jan 1 00:00 ttycrw- 1 root root 4, 64 Jan 1 00:11 ttyS0crw- 1 root root 4, 65 Jan 1 00:00 ttyS1crw-r-r- 1 root root 1, 9 Jan 1 00:00 urandomcrw-rw-rw- 1 root root 1, 5 Jan 1 00:00 zero4.设备文件设备类型、主次设备号是内核与设备驱动程序通信时所使用的,但是对于开发应用程序的用户来说比较难于理解和记忆,所以 Linux 使用了设备文件的概念来统一对设备的访问接口,在引入设备文件系统(devfs)之前 Linux 将设备文件放在/dev 目录下,设备的命名一般为设备文件名数字或字母表示的子类,例如/dev/hda1、/dev/hda2 等。在 Linux2.4 内核中引入了设备文件系统(devfs) ,所有的设备文件作为一个可以挂装的文件系统,这样就可以被文件系统进行统一管理,从而设备文件就可以挂装到任何需要的地方。命名规则也发生了变化,一般将主设备建立一个目录,再将具体的子设备文件建立在此目录下。比如在 UP-NETARM2410-S 中的 MTD 设备为:/dev/mtdblock/0。5.设备驱动程序接口通常所说的设备驱动程序接口是指结构 file_operations,它定义在include/linux/fs.h 中。file_operations 数据结构说明数据结构说明struct file_operations struct module *owner;loff_t (*llseek) (struct file *, loff_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 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 (*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 (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long,
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号