1. 主从设备号是用一个32位的整数(dev_t)来表示,这个整数的高12位表示主设备号,后面20位表示从设备号,内核定义了一些宏来转换:
#define MINORBITS 20
#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))
#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))
2. 注册,管理设备
用kobj_map来管理和跟踪各个设备:
// drivers/base/map.c
struct kobj_map {
struct probe {
struct probe *next;
dev_t dev;
unsigned long range; //从设备号的连续范围
struct module *owner;
kobj_probe_t *get;
int (*lock)(dev_t, void *);
void *data; //根据设备的不同,data分别指向字符设备cdev和块设备genhd
} *probes[255];
struct mutex *lock;
};
管理为驱动程序分配的设备号范围:
static struct char_device_struct {
struct char_device_struct *next;
unsigned int major;
unsigned int baseminor; // baseminor是包含minorct个设备号的连续范围中最小的从设备号
int minorct;
char name[64];
struct cdev *cdev;/* will die */
} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
3. 注册过程
字符设备的注册:
1)调用register_chrdev_region或alloc_chrdev_region来分配设备号的范围
2)调用如下两个函数进行注册
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
块设备直接调用一个函数即可以注册:
int register_blkdev(unsigned int major, const char *name);
4. 字符设备的操作
<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; //从设备数
};
字符设备的打开:
在第一次打开一个设备文件时,用fs_devices.c里面的通用函数chrdev_open打开,并根据设备号查找得到cdev实例,同时关联inode和cdev实例,最后调用驱动程序提供的file_operations里的open函数做一些初始化的工作。