博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux驱动程序学习备忘之六
阅读量:5150 次
发布时间:2019-06-13

本文共 2237 字,大约阅读时间需要 7 分钟。

上层应用程序通过对节点的操作,对设备进行控制。这个节点的接口就是由字符设备驱动提供,向前面的HelloWorld驱动是没有上层操作的接口的,它仅仅只有模块加载接口和退出接口。所以也不需要对应的节点。

struct file_operations这个结构体它在linux/fs.h中定义,用来存储驱动内核模块提供的对 设备进行各种操作的函数的指针。该结构体的每个域都对应着驱动内核模块用来处理某个被请求的 事务的函数的地址。

驱动内核模块是不需要实现每个函数的。

 

在内核中没一个设备都有一个cdev结构变量,具体我参考的是这个:

 

cdev有两种初始化方式:静态和动态

静态内存定义初始化:struct cdev my_cdev;cdev_init(&my_cdev, &fops);my_cdev.owner = THIS_MODULE;动态内存定义初始化:struct cdev *my_cdev = cdev_alloc();my_cdev->ops = &fops;my_cdev->owner = THIS_MODULE;两种使用方式的功能是一样的,只是使用的内存区不一样,一般视实际的数据结构需求而定。下面贴出了两个函数的代码,以具体看一下它们之间的差异。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;}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_init() 还多赋了一个 cdev->ops 的值。初始化 cdev 后,需要把它添加到系统中去。为此可以调用 cdev_add() 函数。传入 cdev 结构的指针,起始设备编号,以及设备编号范围。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);}关于 kobj_map() 函数就不展开了,我只是大致讲一下它的原理。内核中所有都字符设备都会记录在一个 kobj_map 结构的 cdev_map 变量中。这个结构的变量中包含一个散列表用来快速存取所有的对象。kobj_map() 函数就是用来把字符设备编号和 cdev 结构变量一起保存到 cdev_map 这个散列表里。当后续要打开一个字符设备文件时,通过调用 kobj_lookup() 函数,根据设备编号就可以找到 cdev 结构变量,从而取出其中的 ops 字段。当一个字符设备驱动不再需要的时候(比如模块卸载),就可以用 cdev_del() 函数来释放 cdev 占用的内存。void cdev_del(struct cdev *p){   cdev_unmap(p->dev, p->count);   kobject_put(&p->kobj);}其中 cdev_unmap() 调用 kobj_unmap() 来释放 cdev_map 散列表中的对象。kobject_put() 释放 cdev 结构本身。

设备号分配

#define NAME "name"int major = xxx;int result;dev_t devno = MKDEV(MAJOR,0);if(MAJOR)    result = register_chrdev_region(devno,1,NAME);//静态else{  result = alloc_chrdev_region(&devno,0,10,NAME);//动态  major = MAJOR(devno);    }

记录以备忘

 

附加:

还可以用misc设备。在书中它是把led字符驱动程序,注册成misc设备,这个步骤也很简单

首先要定义好struct miscdevice misc这个结构体

这个结果体主要初始化minor,name,fops这三个值

.minor = MISC_DYNAMIC_MINOR 这个宏是内核定义好了的

然后在注册时调用misc_register(&misc)注册

misc_deregister(&misc)释放

感觉misc比上面的要方便很多。

 

这是网上关于misc设备的说明

转载于:https://www.cnblogs.com/shouchengcheng/p/3645272.html

你可能感兴趣的文章
内容版本SecureCRT脚本
查看>>
宋体光标vim高亮显示当前行,列
查看>>
Java集合---ConcurrentHashMap原理分析
查看>>
自动挡还有这些技巧?连老司机都不知道
查看>>
碎片6
查看>>
ElasticSearch客户端注解使用介绍
查看>>
矢量空间存储、栅格空间存储 分布式存储的区别
查看>>
JSON.stringify实战用法
查看>>
#ifndef详解
查看>>
C++11 —— 解包 tuple 参数列表
查看>>
结对编程收获
查看>>
最长回文子串(Manacher)
查看>>
古罗马子串加密
查看>>
TensorBoard:可视化学习
查看>>
图文说明Win10上在VitualBox安装Ubuntu
查看>>
C#终于支持可选参数了!
查看>>
Yeoman自动构建js项目(转)
查看>>
jquery
查看>>
帮朋友写的一个自定义选择框
查看>>
CODE[VS] 2221 搬雕像 ——2011年台湾高级中学咨询学科能力竞赛
查看>>