前几天编写字符设备驱动点亮led的程序中,核心代码只有一个函数register_chrdev(),想理解字符设备驱动的工作流程,只要展开这个函数就可以:
static inline int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops)
return __register_chrdev(major, 0, 256, name, fops);展开:
int __register_chrdev(unsigned int major, unsigned int baseminor,
unsigned int count, const char *name, const struct file_operations*fops)
cd= __register_chrdev_region(major, baseminor, count, name);展开:
static struct char_device_struct * __register_chrdev_region(unsigned int major, unsigned int baseminor, int minorct, const char *name)
struct char_device_struct *cd, **cp;
cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);//分配一个char_device_struct空间,首地址给cd
if (major == 0) {
for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) {
if (chrdevs[i] == NULL)
break;
}
major = i;//当major为0从最大主设备号255开始找到一个为空的主设备号(这段代码就是为什么major为0会自动分配主设备号)
}
cd->major = major;
cd->baseminor = baseminor;
cd->minorct = minorct;
strlcpy(cd->name, name, sizeof(cd->name));//填充分配的char_device_struct空间(主设备号,次设备号基值等)
i = major_to_index(major);//i=major % CHRDEV_MAJOR_HASH_SIZE(字符设备最大值255);
cp = &chrdevs[i];
*cp = cd;//这里省略了很多代码,主要是检查chrdevs[i]是不是NULL,不是空则进行处理,空则将cd放入
return cd;
cdev = cdev_alloc();//分配一个cdev空间
cdev->owner = fops->owner;
cdev->ops = fops;//将file_operation与该cdev绑定
kobject_set_name(&cdev->kobj, "%s", name);
最核心的函数: cdev_add(cdev, MKDEV(cd->major, baseminor), count);//将cdev加入cdev_map,实际调用kobj_map函数加入kobj_map中的probe数组(下面有说明)
cd->cdev = cdev;//将该char_device_struct和cdev绑定
return major ? 0 : cd->major;//major为0则返回自动分配的主设备号,否则返回0
这里应该注意chrdevs[]这个数组只负责设备注册,可能老内核中用它管理字符设备,现在即使不注册chrdevs也可以使用驱动,这是个历史遗留问题?现在使用cdev_map(也有255个数组)来管理设备。相关定义:
struct kobj_map *cdev_map;
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;
} *probes[255];
struct mutex *lock;
};
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不会参与设备的操作只有注册作用。
} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];//255个
file结构体是打开文件时产生的,里面记录了file_operation等信息,inode结构是建立设备文件就产生的,记录了cdev、file_operation等信息,当我们对设备文件操作时会根据主设备号找到对应的cdev和file_operation。可以参考:
http://blog.chinaunix.net/uid-24517893-id-161446.html
欢迎指出错误,会及时改正的
阅读(2004) | 评论(0) | 转发(0) |