linux设备驱动分类
5.1.4.1、驱动分类
(1)分3类:字符设备驱动、块设备驱动、网络设备驱动
(2)分类原则:设备本身读写操作的特点差别
5.1.4.2、三类驱动程序详尽对比剖析
(1)字符设备,确切的说应当叫“字节设备”,软件操作设备时是以字节为单位进行的。典型的如LCD、串口、LED、蜂鸣器、触摸屏······
(2)块设备,块设备是相对于字符设备定义的,块设备被软件操作时是以块(多个字节构成的一个单位)为单位的。设备的块大小是设备本身设计时定义好的,软件是不能去修改的,不同设备的块大小可以不一样。常见的块设备都是储存类设备,如:硬碟、NandFlash、iNand、SD····
(3)网路设备,网路设备是专为网卡设计的驱动模型,linux中网路设备驱动主要目的是为了支持API中socket相关的这些函数工作。
5.1.4.3、为什么字符设备驱动最重要
(1)常见大量设备都属于字符设备
(2)举例说明非标准类型字符设备驱动
开启驱动开发之路
5.2.1.1、驱动开发的打算工作

(1)正常运行linux系统的开发板。要求开发板中的linux的zImage必须是自己编译的,不能是他人编译的。
(2)内核源码树,当然就是一个经过了配置编译以后的内核源码。
(3)nfs挂载的rootfs,主机ubuntu中必须搭建一个nfs服务器。
5.2.1.2、驱动开发的步骤
(1)驱动源码编撰、Makefile编撰、编译
(2)insmod装载模块、测试、rmmod卸载模块
5.2.1.3、实践
(1)copy原先提供的x210kernel.tar.bz2,找一个干净的目录(/root/driver),解压之,而且配置编译。编译完成后得到了:1、内核源码树。2、编译ok的zImage
(2)fastboot将第1步中得到的zImage烧写到开发板中去启动(或则将zImage丢到tftp的共享目录,uboot启动时tftp下载启动),将来驱动编译好后,就可以在这个内核中去测试。由于这个zImage和内核源码树是一伙的,所以驱动安装时版本校准不会出错。
最简单的模块源码剖析1
5.2.2.1、常用的模块操作命令
(1)lsmod(listmodule,将模块列表显示),功能是复印出当前内核中早已安装的模块列表
(2)insmod(installmodule,安装模块),功能是向当前内核中去安装一个模块,用法是insmodxxx.ko

(3)modinfo(moduleinformation,模块信息)linux设备驱动开发详解 下载linux设备驱动开发详解 下载,功能是复印出一个内核模块的自带信息。,用法是modinfoxxx.ko
(4)rmmod(removemodule,卸载模块),功能是从当前内核中卸载一个早已安装了的模块,用法是rmmodxxx(注意卸载模块时只须要输入模块名即可,不能加.ko后缀)
(5)剩下的前面再说,暂时用不到(如modprobe、depmod等)
5.2.2.2、模块的安装
(1)先lsmod再insmod看安装前后系统内模块记录。实践测试标注内核会将最新安装的模块置于lsmod显示的最上面。
(2)insmod与module_init宏。模块源代码中用module_init宏申明了一个函数(在我们这个事例里是chrdev_init函数),作用就是指定chrdev_init这个函数和insmod命令绑定上去,也就是说当我们insmodmodule_test.ko时,insmod命令内部实际执行的操作就是帮我们调用chrdev_init函数。
照此剖析,那insmod时就应当能看见chrdev_init中使用printk复印下来的一个chrdev_init字符串,并且实际没看见。缘由是ubuntu中拦截了,要如何能够看见呢?在ubuntu中使用dmesg命令就可以看见了。
(3)模块安装时insmod内部不仅帮我们调用module_init宏所申明的函数外,实际还做了一些别的事(例如lsmod能见到多了一个模块也是insmod帮我们在内部做了记录)linux下socket编程,而且我们就不用管了。
5.2.2.3、模块的版本信息
(1)使用modinfo查看模块的版本信息
(2)内核zImage中也有一个确定的版本信息
(3)insmod时模块的vermagic必须和内核的相同,否则不能安装,报错信息为:insmod:ERROR:couldnotinsertmodulemodule_test.ko:Invalidmoduleformat
(4)模块的版本信息是为了保证模块和内核的兼容性,是一种安全举措

(5)怎样保证模块的vermagic和内核的vermagic一致?编译模块的内核源码树就是我们编译正在运行的这个内核的那种内核源码树即可。说白了就是模块和内核要同出一门。
最简单的模块源码剖析2
5.2.3.1、模块卸载
(1)module_exit和rmmod的对应关系
(2)lsmod查看rmmod前后系统的模块记录变化
5.2.3.2、模块中常用宏
(1)MODULE_LICENSE,模块的许可证。通常申明为GPL许可证,并且最好不要少,否则可能会出现莫名其妙的错误(例如一些显著存在的函数提高找不到)。
(2)MODULE_AUTHOR
(3)MODULE_DESCRIPTION
(4)MODULE_ALIAS
5.2.3.3、函数修饰符
(1)__init,本质上是个宏定义,在内核源代码中就有#define__initxxxx。这个__init的作用就是将被他修饰的函数装入.init.text段中去(原本默认情况下函数是被装入.text段中)。
整个内核中的所有的这类函数就会被链接器链接装入.init.text段中,所以所有的内核模块的__init修饰的函数显然是被统一放到一起的。内核启动时统一会加载.init.text段中的这种模块安装函数,加载完后都会把这个段给释放掉以节约显存。
(2)__exit

同(__init),模块卸载时的段
5.2.3.4、static
关于驱动模块中的头文件
(1)驱动源代码中包含的头文件和原先应用编程程序中包含的头文件不是一回事。应用编程中包含的头文件是应用层的头文件,是应用程序的编译器带来的(例如gcc的头文件路径在/usr/include下,这种东西是和操作系统无关的)。驱动源码属于内核源码的一部份,驱动源码中的头文件或许就是内核源代码目录下的include目录下的头文件。
驱动编译的Makefile剖析
(1)KERN_DIR,变量的值就是我们拿来编译这个模块的内核源码树的目录
(2)obj-m+=module_test.o,这一行就表示我们要将module_test.c文件编译成一个模块
(3)make-C$(KERN_DIR)M=pwdmodules这个命令拿来实际编译模块,工作原理就是:借助make-C步入到我们指定的内核源码树目录下,之后在源码目录树下借用内核源码中定义的模块编译规则去编译这个模块,编译完成后把生成的文件还拷贝到当前目录下,完成编译。
(4)makeclean,拿来消除编译痕迹
总结:模块的makefile十分简单,本身并不能完成模块的编译,而是通过make-C步入到内核源码树下借用内核源码的体系来完成模块的编译链接的。这个Makefile本身是特别模式化的,3和4部份是永远不用动的linux操作系统怎么样,只有1和2须要动。1是内核源码树的目录,你必须依照自己的编译环境
5.2.6.字符设备驱动工作原理1
file_operations结构体
(1)元素主要是函数表针,拿来挂接实体函数地址
(2)每位设备驱动都须要一个该结构体类型的变量

(3)设备驱动向内核注册时提供该结构体类型的变量
5.2.7.字符设备驱动工作原理2
5.2.7.1、register_chrdev解读(#include)
(1)作用,驱动向内核注册自己的file_operations
内核怎样管理字符设备驱动
(1)内核中有一个链表拿来储存注册的字符设备驱动
(2)register_chrdev内部将我们要注册的驱动的信息(主要是)储存在链表中相应的位置
(3)cat/proc/devices查看内核中早已注册过的字符设备驱动(和块设备驱动)
(4)好好理解主设备号(major)的概念
5.2.8.字符设备驱动代码实践1
开始动手
(1)先定义file_operations结构体变量
(2)open和close函数原型确定、内容填充
