Chinaunix首页 | 论坛 | 博客
  • 博客访问: 278035
  • 博文数量: 58
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 600
  • 用 户 组: 普通用户
  • 注册时间: 2015-11-27 08:37
个人简介

从linux了解世界

文章分类
文章存档

2017年(5)

2016年(51)

2015年(2)

我的朋友

分类: 嵌入式

2016-01-20 22:30:31

前几天编写字符设备驱动点亮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

欢迎指出错误,会及时改正的

阅读(1966) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~