简单字符设备驱动总体代码的详细分析

1 字符设备驱动相关的概念和结构体

本博文来自于视频学习中的笔记,稍加整理得到的,但是相关的代码截图还是比较全!希望能对大家有所帮助!
简单字符设备驱动总体代码的详细分析_第1张图片

2 字符设备驱动代码的分析

2.1

简单字符设备驱动总体代码的详细分析_第2张图片
(1)\当你执行 insmod ***.ko 时,驱动就会被加载,驱动被加载之后,就会从module_init( charDrvInit )这个函数开始执行!【这一个是该驱动的入口函数】
(2)、当你对驱动执行rmmod时,驱动就会执行相应的module_exit(charDrvExit) 驱动卸载函数!对驱动进行卸载!
(3)、MODULE_LICENSE(“GPL”); //这句话用来说明该驱动模块是支持GPL协议的!

2.2 字符设备驱动的架构

简单设备驱动的整体代码分析:
简单字符设备驱动总体代码的详细分析_第3张图片
简单字符设备驱动总体代码的详细分析_第4张图片
简单字符设备驱动总体代码的详细分析_第5张图片
简单字符设备驱动总体代码的详细分析_第6张图片
代码详细分析:

1、
 devNum = MKDEV(reg_major,reg_minor);
 //相应的MKDEV,其为一个宏定义: 
    #define MKDEV(ma,mi) (( (ma) << MINORBITS ) | (mi) )  // MINORBITS = 20 ; 根据设备号的命名规则,意思就是:MKDEV就是根据主设备号和次设备号组成一个唯一的设备号,【 << 实现将主设备号向左偏移20位!】

简单字符设备驱动总体代码的详细分析_第7张图片

2、printk 的详细分析:
printk(KERN_EMERG"devNum is %d\r\n",devNum): // 这个打印函数和其他的实际上是没有太大区别的,只不过这个打印函数会分不同的打印级别,所谓的打印级别就是在打印的时候,让有些信息打印出来,有些信息不要打印出来的意思! 
3、注册设备号信息:
// 设备信息的注册使用一个 register_chrdev_region(dev_t from,unsigned count,const char *name)
 // 对上述函数里面的参数进行相应的说明: 
    //  from : 表示所申请的设备号的范围的起始值
    //  count:表示从from开始你要申请多少个 (一个字符设备对应的此处的值就是 1)
    //  name : 是便于管理设备号而给定的一个名字,可以随便设置!
下面的函数需要注意一点,就是在设备号注册成功之后会打印出注册成功的信息,但是如果注册失败之后,该 charDrvInit()函数就会直接结束。

简单字符设备驱动总体代码的详细分析_第8张图片

4、内核空间申请内存函数:

在内核中,申请内存空间时: kzalloc( ) 和 kmalloc( )函数都是差不多的!

gDev = kzalloc(sizeof(struct cdev),GFP_KERNEL);   // 该函数的返回值是一个指针!
//  第一个参数: sizeof(struct cdev):表示申请的空间大小! 
// 第二个参数:GFP_kernel: 所申请的内存是在内核里使用的!(一般都是这个,假如是给DMA申请的内存,则这里就是 GFP_DMA ,不同参数表示不同的意思!)
补充: 
struct cdev *gDev ;

在这里插入图片描述

5、给 file_operations 里的子函数来赋值(1):

在上一步已经对 gFile函数进行内存空间的申请,所以在这里将直接对里面的函数进行赋值操作!
在这里插入图片描述

 gFile->open = testOpen ;
 gFile->read = testRead;
 gFile->write = testWrite;   
 // 一开始对这三行函数的操作没看懂,其实没有那么难,在这里实现的只是一个简单的替换的作用! 
  // 也就是将: gFile里面的子函数 “open” 换成 外面自定义的 testOpen, 不过需要注意的是:一定要保证在外面写的函数的形参和File_operation里面的形参是一致的,要不然就会报错!(也就是不能做简单的替换! )

**问题: 为什么可以直接这样进行赋值操作? 具体的语法是什么? 详细看此行上面黑框里的解析: **
简单字符设备驱动总体代码的详细分析_第9张图片

6、给 file_operations 里的子函数来赋值(2):

给File_operation里面的 owner 进行赋值,**THIS_MODULE是内核里面自定义的,自己在写驱动函数的时候,完全可以照着这个来进行写! **
在这里插入图片描述

7、cdev_init / cdev_add 这两个函数进行赋值操作:

(1)、cdev_init( )其作用就是:建立设备信息和设备行为之间的联系!
在这里插入图片描述
简单字符设备驱动总体代码的详细分析_第10张图片
(2)、 cdev_add( ) : 把字符设备注册到内核里面!

** struct cdev :这个结构体是对设备进行描述的结构体! **
cdev_add :实现的是,将struc cdev 与设备号之间建立一个联系!
简单字符设备驱动总体代码的详细分析_第11张图片

你可能感兴趣的:(Linux内核相关的学习笔记)