当前位置: 首页 > Linux

Linux设备驱动开发实例_0

时间:2023-04-06 02:02:21 Linux

编译运行驱动编译需要内核的Makefile——也就是源码树的编译系统。因此需要对源码进行配置编译。以ubuntu自带的源码为例:编译外部模块(.ko)的编译命令为:make-CM=make?CM=PWD就是进入内核目录并使用kbuild系统编译驱动文件。obj-m告诉编译系统需要编译成一个模块(.ko),foo.o表示需要的源文件是foo.c或者foo.S,如果驱动模块包含多个文件(eg:foo_main.c,foo_common.c),写法如下:kbuild会编译$(foo-y)中列出的所有文件并合并生成foo.ko在编译过程中,模块的Makefile会被kbuild多次读取,所以建议使用$(KERNELRELEASE)来区分Makefile在使用阶段,优化后的Makefile如下:第一次运行make时,$(KERNELRELEASE)为空,所以Makefile的'else'内容先读取,然后,执行*'make-C....'*,在执行过程中,会回读Makefile。这次满足'ifneq'条件,走两条不同的路径,编译系统配置了不同的可变参数。如果不使用$(KERNELRELEASE)区分,系统会在每次编译时设置所有的变量和规则,可能会和内核的Makefile变量或规则冲突。因此,建议仅在(KERNELRELEASE)为空时配置驱动程序。除了使用(KERNELRELEASE)为空,配置特定于驱动程序的变量和规则。除了使用(KERNELRELEASE),内核还提供了一些其他的方法。关于内核编译系统的更多信息,请参考内核源代码下的“Documentation/kbuild/”驱动模块运行相关命令insmodfoo.ko——加载驱动到内核运行。rmmodfoo--从内核中删除driver.lsmod--查看内核中当前运行的模块。字符设备字符设备驱动实际上实现了一个文件接口,使得设备文件可以像普通文件一样被访问,从而使应用程序可以使用libc库的'文件IOAPI(打开/写入/读取/关闭系列函数)'因此,访问驱动程序并与驱动程序交换数据,其核心是实现文件系统的接口——文件操作。程序入口宏内核和微内核最大的区别之一就是驱动程序的运行空间。在微内核系统中,驱动程序作为一个应用程序运行在用户空间,它的入口点是应用程序的'main'函数。作为一个宏内核系统,Linux的驱动程序与内核集成在一起,运行在内核空间中。它的入口是'module_init','module_exit'是对应的退出函数。他们必须成对出现。foo_init执行最基本的字符设备操作:使用cdev_add在字符设备列表(实际上是一个map结构)中添加一个'cdev',这样当应用程序操作对应的设备时,字符设备foo就被委托给内核进行管理文件,内核可以分派给foo驱动程序。foo_exit必须使用cdev_del从列表中删除设备,否则,当内核从列表中找到cdev时,它将返回一个“过时”指针。使用它回调相应的操作时,会出现空指针异常,导致内核挂掉。记住!foo_init和foo_exit必须成对使用以执行相反的操作。错误实例:foo_exit不执行cdev_del函数。insmodfoo.ko——好的。应用程序读取和写入设备文件——OK。rmmodfoo——好的。insmodfoo.ko——好的。应用程序读写设备文件——核心转储。'rmmodfoo'时,会调用foo_exit,但是程序员忘记执行cdev_del函数,所以foo.cdev的指针没有被删除,变成空指针,还在字符设备列表中。第二次插入foo.ko时,读写设备时,Kernel在寻找旧的foo.cdev空指针,用它调用对应的文件操作时,出现空指针的coredump错误.文件操作setup_dev:注册当前设备的文件操作函数。应用程序在操作设备文件时,会调用相应的驱动函数。与用户空间交换数据,copy_from/to_user,这两个函数返回0表示函数执行成功。copy_from_user:保存用户写入的数据拷贝驱动数据buf。copy_to_user:copy将数据buf驱动到用户读取数据的buf。应用程序与字符驱动的交互过程创建设备文件--sudomknod/dev/foodevc5000修改设备文件的权限--sudochmod766/dev/foodev应用使用open函数打开设备文件。内核根据文件类型(字符设备文件)找到字符设备列表,根据设备号(Major,Minor)找到对应的设备驱动模块。调用设备驱动的打开函数foo_open。应用程序调用读写函数读写设备文件。驱动程序调用foo_read/write并使用copy_from/to_user来交换数据。常见问题问:读写设备文件时,write或read函数返回0,无法读写数据?A:这类设备文件读写失败很可能是权限问题。确认文件的读写权限,其次是数据是否符合驱动程序的要求。块设备块设备是指存储设备,块设备驱动就是存储驱动如:HD、SSD。Linux使用Block子系统对它们进行管理,将应用层的IO读写请求转化为Requests传递给相应的设备驱动程序。驱动过程比较简单:register_blkdev→alloc_disk→processrequestQ:文件系统和Block子系统是什么关系?A:Block子系统主要提供最底层的数据读写,即rawio,用于文件系统进行IO操作。registerregisterblockdevice(majordevicenumber)registerdevice(MAJOR,MINOR)adddisk该磁盘会出现在/dev目录下,本例为_/dev/frd0_,用户可以格式化设备文件,分区等磁盘相关手术。如:'_mkfs.ext2/dev/frd0_'、'_mount/dev/frd0/mnt_'。初始化请求队列来处理设备请求内核提供了一些宏来帮助遍历请求列表。请求处理策略是Block驱动的核心和最本质的部分。开发者需要根据设备的物理特性,提高访问效率,解决并发拥塞等问题。*fr_queue_rq()*--'请求队列'处理函数,初始化请求队列时设置,循环处理每个请求:*fr_transfer()*--物理设备读写数据,根据请求的上下文Low-level数据传输,这里是最底层的IO通信,驱动根据物理设备的接口协议读写数据。块设备驱动测试执行上述命令后,frd_data_r和frd_data_w的内容应该是一样的。以上是良旭教程网为各位小伙伴分享的Linux设备驱动开发实例。以上就是良序教程网为各位小伙伴们分享的Linux相关知识。