1. 字符设备相关结构体
include/linux/cdev.h
struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
};
f
s/char_dev.c
static struct char_device_struct {
struct char_device_struct *next;
unsigned int major;
unsigned int baseminor;
int minorct;
char name[64];
struct cdev *cdev; /* will die */
} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
include/linux/fs.h
#define CHRDEV_MAJOR_HASH_SIZE 255
2.字符设备的注册
(1)相关的接口函数
int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops)
major:主设备号(int类型的一个数字,可以为0,表示内核自动分配【多希望房子也可以由国家自动分配😏】)
name:设备的名字
fops:文件操作函数实现的‘类’
register_chrdev 是一个早期的字符注册函数,随着linux 的使用越来越广,需要管理的字符设备越来越多,有了新的注册函数,以提供更多的设备号
int register_chrdev_region(dev_t from, unsigned count, const char *name)
from:设备号起始号,等同于上述的主设备号
count:本次需要注册的设备的个数
name:设备名字
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)
dev: 输出一个注册了的设备号
baseminor:起始的次设备号
count:次设备个数
name:设备名字
(2)调用关系:
static struct char_device_struct *
__register_chrdev_region(unsigned int major, unsigned int baseminor, int minorct, const char *name)
根据主次设备号注册一个字符设备。(1)中的三个注册函数都可以注册一个字符设备,区别是:
register_chrdev 封装比较全,传入设备号、名字和fops就可以创建了一个字符设备
alloc_chrdev_region 主要是用于设备号确定或者一个主设备号对应多个次设备号的情况,即多个设备可以通过该函数共享 fops函数。适用于同类设备的情况,如多个led的情况,那么他们的主设备号相同,次设备号不同,一个设备的设备号是由主次设备号共同组成;注册后还需要添调用cdev_init() and cdev_add(),才能完成真正的注册。
alloc_chrdev_region 用法和 register_chrdev_region类似,唯一不同的是这里的 dev 参数是 “output parameter for first assigned number” 这是什么意思呢?就是说该参数是在alloc_chrdev_region 内部赋一个整数值,作为输出参数;即动态分配一个设备号。
(3) cdev 的完善
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{
memset(cdev, 0, sizeof *cdev);
INIT_LIST_HEAD(&cdev->list);
kobject_init(&cdev->kobj, &ktype_cdev_default);
cdev->ops = fops;
}
初始化cdev结构体变量,所作的操作是:
清空cdev变量
初始化cdev链表(头尾指针相互指向对方0)
初始化kobject(这是内核设备模型,稍后的博客中会讲述)
fops的挂接
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
{
p->dev = dev;
p->count = count;
return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);
}
字符设备添加到系统中,xxx_chrdev_region()申请了设备号并在字符设备数组中做了标记,cdev_init()初始化了cdev变量;但是他们都是独立的两个个体,彼此间没有丝毫的关系。这里cdev_add将两者挂接起来,使得两者彼此知道了对方的存在,并相互依靠直到该设备的消亡。
p cdev变量指针
dev 设备号
count 设备个数