专为编程构建,手动写代码机器人,免费开通
明天就跟你们说说有关Linux设备驱动开发的示例剖析,可能好多人都不太了解,为了让你们愈发了解,小编给你们总结了以下内容,希望你们按照这篇文章可以有所收获。
编译和运行
驱动编译要用到kernel的Makefile文件——也就是源码树的编译系统。为此,源码须要被配置和编译,以ubuntu自带的源码为例:
编译外部模块(.ko)的编译命令是:
make-C
M=mak**e−Cpathtokernelsrc>M=PWD
也就是步入到kernel目录,借助kbuild系统来编译驱动文件。obj-m告诉编译系统须要编译成一个module(.ko),foo.o表明须要源文件是foo.c或则foo.S,假如驱动模块包含多个文件(如:foo_main.c,foo_common.c),写法如下:
kbuild将编译$(foo-y)列举的所有文件linux设备驱动开发详解ldd,合并形成foo.ko
在编译期间,模块的Makefile会被kbuild多次读取,因而建议使用$(KERNELRELEASE)来分辨Makefile的使用阶段,优化后的Makefile如下:
第一次运行make的时候,$(KERNELRELEASE)为空,因而,Makefile的‘else’内容首先被读取,之后,执行*‘make-C…..’*,执行过程中,会回读Makefile文件,此次,‘ifneq’条件满足,两次走不同的路径,编译系统配置不同的变量参数。
假如,不使用$(KERNELRELEASE)分辨的话,每次编译系统就会设置所有的变量和规则,可能会与kernel的Makefile变量或则规则冲突,因而,建议在(KERNELRELEASE)为空的情况下,配置driver专用的变量和规则,不仅使用(KERNELRELEASE)为空的情况下,配置drive**r专用的变量和规则,不仅使用(KERNELRELEASE)外,kernel还提供了一些其它的做法,
更多的kernel编译系统信息,请参考kernel源码下的“Documentation/kbuild/”
驱动模块运行相关命令
字符设备
字符设备驱动实际上就是实现一个文件插口,让设备文件可以像一个普通文件那样来访问,这样应用程序就可以使用libc库的’文件IOAPI(open/write/read/close系列函数)‘来访问驱动程序,与驱动交换数据,因而,它的核心就是实现文件系统的插口--文件操作。
程序入口
宏内核与微内核的一个最大区别就是驱动程序的运行空间。微内核系统,驱动程序作为一个应用程序,运行在用户空间,它的入口就是应用程序的‘main’函数。Linux作为一个宏内核系统,它的驱动程序与内核是一体的,运行在内核空间,它的入口是‘module_init’,‘module_exit’则是对应的退出函数,它们一定是成对出现的。
foo_init执行了最基本的字符设备操作:使用cdev_add添加一个‘cdev’到字符设备列表(虽然是一个map结构),这样就把foo这个字符设备托付给kernel进行管理了,当应用程序操作相应的设备文件时,kernel能调度到foo驱动程序。
foo_exit一定要使用cdev_del从列表上面删掉设备,不然,当kernel从列表上面查找到cdev时,返回的将是“过时”的表针,使用它来callback相应操作时,才会出现空表针异常,造成kernel会死掉。谨记!foo_init和foo_exit一定要成对使用,执行相反的操作。
bug实例:
foo_exit不执行cdev_del函数。
insmodfoo.ko--OK。
应用程序对设备文件读写--OK。
rmmodfoo--OK。
insmodfoo.ko--OK。
应用程序对设备文件读写--coredump。
‘rmmodfoo’时,会调用foo_exit,然而红旗linux6.0教程,程序员忘了执行cdev_del函数,致使foo.cdev的表针没有被删掉而弄成了一个空表针,它一直在字符设备列表上面。当第二次插入foo.ko后,读写该设备时,Kernel找的是旧的foo.cdev空表针,用它调用相应的文件操作时suse linux 下载,就发生了空表针的coredump错误。
文件操作
setup_dev:注册当前的设备的文件操作函数,当应用程序操作设备文件时,调用到对应的驱动函数。与用户空间交换数据,copy_from/to_user,这两个函数返回0表示函数执行成功。
应用程序与字符驱动的交互流程
创建设备文件--sudomknod/dev/foodevc5000
更改设备文件权限--sudochmod766/dev/foodev
应用程序使用open函数打开设备文件。
kernel依照文件类型(字符设备文件)找到字符设备列表,并依据设备号(Major,Minor),找到对应的设备驱动模块。
调用设备驱动的open函数foo_open。
应用程序调用read/write函数来读写设备文件。
驱动调用foo_read/write并使用copy_from/to_user来交换数据。
常见问题
Q:读写设备文件时,write或则read函数返回0,不能读写数据?
A:这类设备文件读写失败问题,很有可能是权限问题,确认下文件读写权限,其次是数据是否符合驱动的要求。
块设备
块设备指的是储存设备,块设备驱动就是储存驱动如:HD,SSD。Linux用Block子系统对它们进行管理,把应用层的IO读写恳求,转变为Request,传给相应的会设备驱动。驱动流程比较简单:
register_blkdev→alloc_disk→处理request
Q:文件系统与Block子系统的关系?
A:Block子系统主要是提供最底层的数据读写,也就是rawio,文件系统使用它进行IO操作。
注册
注册块设备(主设备号)
注册设备(MAJOR,MINOR)
添加c盘
这个c盘会出现在/dev目录下边,本例是/dev/frd0,用户可以对设备文件进行低格,分区等c盘相关的操作。如:‘mkfs.ext2/dev/frd0’,‘mount/dev/frd0/mnt’。
初始化恳求队列
处理设备恳求
kernel提供了一些宏来帮助遍历恳求列表。对恳求的处理策略,就是Block驱动最核心最精华的部份,开发者得依据设备的化学特点来提升访问效率,解决并发堵车等问题。
*fr_queue_rq()*--‘**恳求队列’**处理函数,在初始化恳求队列时设置,Loop处理每位恳求:
*fr_transfer()*--化学设备读写数据,依据恳求的上下文内容(context),进行底层数据传输,这儿就是最底层的IO通信了,驱动按照化学设备的插口合同来进行数据的读写。
块设备驱动测试
执行前面命令后,frd_data_r和frd_data_w的内容应当是一样的。
看完上述内容linux设备驱动开发详解ldd,大家对Linux设备驱动开发的示例剖析有进一步的了解吗?假如还想了解更多知识或则相关内容,请关注亿速云行业资讯频道,谢谢你们的支持。