linux学习---char设备结构

下图为字符设备驱动的结构框图,图中最重要就是:cdev结构体。

本质上讲写Char驱动就是对cdev结构进行定义:
这里写图片描述

下面小白带你们到<linux/cdev.h>中看一下它的结构:
这里写图片描述
cdev 中定义了六个成员,其中有三个需要我们自己定义。
第一个 struct module *owner /*所属模块*/, ;
这个很简单直接赋值为THIS_MODULE;

接下来这两个成员很重要: dev_t 和 file_operations

dev_t 是设备号,设备号是什么?
当你在系统中生成一个Char设备时,系统怎么知道你是哪个设备?这个时候就需要给每个设备一个唯一的标识符,dev_t 就是干这个的。
dev_t 是一个32位的整型,其中高12位为主设备号(major),低20位为次设备号(minor)。
major 和minor 可以自己定义:
通过MKDEV(int major,int minor)宏,可以将major和minor生成一个dev_t。
MKDEV 就是((u32)major <<12)| minor的宏 。
也可以通过MAJOR(dev_t dev)MINOR (dev_t dev)来查看主设备号和次设备号。

file_operations中的函数是字符设备驱动设计的主要内容,这些函数实际上会被应用程序进行的Linux的open()、read()、close()等函数调用。
下图给出了部分file_operations中的函数:
这里写图片描述

对 cdev 进行赋值,linux中提供了专门的函数(可封装性)。
这里写图片描述

其中cdev_init()是用来初始化cdev:
这里写图片描述
cdev_add () 是用来向系统添加一个cdev,完成字符设备。
这里写图片描述

但是,cdev_add() 给系统添加一个cdev时,系统怎么去识别这个cdev呢?你可能会说不是每个cdev都有设备号吗?用设备号(dev_t)不就行了。
对,确实是用设备号,可是在用设备号之前,字符设备是不是应该告诉一下系统,这个设备号是我的,不允许其他设备使用它。
这个时候就需要注册,注册有两种:
1、是已经有设备号了,给系统报备一下,这时就使用:

register_chrdev_region()

这里写图片描述
2、没有设备号,让系统给它一个,系统将设备号保存到第一个参数返还,这时就使用:

alloc_chrdev_region() //(推荐使用,不容易出错)

这里写图片描述

这边需要注意一下: 两个注册函数都使用了__register_chrdev_region()这个函数。
这里写图片描述
每次一次注册是要加锁的。
当major==0时就由系统来分配设备号,系统内部有个chrdevs的数组,所有注册的设备号都在这里,因此需要从数组中找一个NULL的给新设备用。
这里写图片描述
下面这段代码主要是检查已有的设备号(使用register_chrdev_region)和系统内部是否有冲突。
这里写图片描述
最后,将新的cdev加到系统的cdev的链表中。
这里写图片描述
alloc_chrdev_region()
最后调用cdev_del()函数从系统中注销之后,系统应该调用unregister_chardev_region()来释放原先申请的设备号。

阅读更多

没有更多推荐了,返回首页