A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

1. cdev 结构体

(1)在 Linux 内核中,使用 cdev 结构体描述一个字符设备,定义如下:



  • struct cdev {



  •         struct kobject kobj;                                        /* 内嵌的 kobject 对象 */



  •         struct module *owner;                                        /* 所属模块 */



  •         const struct file_operations *ops;                        /* 文件操作结构体 */



  •         struct list_head list;



  •         dev_t dev;                                                /* 设备号 */



  •         unsigned int count;



  • } __randomize_layout;


    cdev 结构体的 dev_t 成员定义了设备号,为 32 位,其中 12 位为主设备号,20 位为次设备号。使用下列宏可以从 dev_t 获得主设备号和次设备号:



  • MAJOR(dev_t dev)



  • MINOR(dev_t dev)


而使用下列宏则可以通过主设备号和次设备号生成 dev_t:

MKDEV(int major, int minor)

    cdev 结构体的另一个重要成员 file_operations 定义了字符设备驱动提供给虚拟文件系统的接口函数。

(2)Linux 内核提供了一组函数用于操作 cdev 结构体:



  • void cdev_init(struct cdev *, const struct file_operations *);



  • struct cdev *cdev_alloc(void);



  • int cdev_add(struct cdev *, dev_t, unsigned);



  • void cdev_del(struct cdev *);


    cdev_init() 函数用于初始化 cdev 的成员,并建立 cdev 和 file_operations 之间的连接,其源代码如下所示:



  • 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 的 ops */



  • }


    cdev_alloc() 函数用于动态申请一个 cdev 内存,其源代码如下所示:



  • struct cdev *cdev_alloc(void)



  • {



  •         struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);



  •         if (p) {



  •                 INIT_LIST_HEAD(&p->list);



  •                 kobject_init(&p->kobj, &ktype_cdev_dynamic);



  •         }



  •         return p;



  • }


    cdev_add() 函数和 cdev_del() 函数分别向系统添加和删除一个 cdev,完成字符设备的注册和注销。对 cdev_add() 的调用通常发生在字符设备驱动模块加载函数中,而对 cdev_del() 函数的调用则通常发生在字符设备驱动模块卸载函数中。


2. 分配和释放设备号

    在调用 cdev_add() 函数向系统注册字符设备之前,应首先调用 register_chrdev_region() 或 alloc_chrdev_region() 函数向系统申请设备号,这两个函数的原型如下:



  • int register_chrdev_region(dev_t from, unsigned count, const char *name);



  • int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name);



    register_chrdev_region() 函数用于已知起始设备的设备号的情况,而 alloc_chrdev_region() 用于设备号未知,向系统动态申请未被占用的设备号的情况,函数调用成功之后,会把得到的设备号放入第一个参数 dev 中。alloc_chrdev_region() 相比于 register_chrdev_region() 的优点在于它会自动避开设备号重复的冲突。

    相应地,在调用 cdev_del() 函数从系统注销字符设备之后,unregister_chrdev_region() 应该被调用以释放原先申请的设备号,这个函数的原型如下:

void unregister_chrdev_region(dev_t from, unsigned count)

3. file_operations 结构体

    file_operations 结构体中的成员函数是字符设备驱动程序设计的主体内容,这些函数实际会在应用程序进行 Linux 的 open()、write()、read()、close() 等系统调用时最终被内核调用。

   

1 个回复

倒序浏览

很不错,受教了
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马