搜索
bottom↓
回复: 13

linux字符设备概念——浅析

[复制链接]

出0入4汤圆

发表于 2020-8-13 16:39:14 | 显示全部楼层 |阅读模式
本帖最后由 batou 于 2020-8-14 12:44 编辑

linux字符设备驱动学的是云里雾里,一团乱麻,剪不断理还乱… 放弃?
不,反正闲着也是闲着,打王者还老遇到坑,免不了上火!
那就一点一点来吧,弄一点是一点
=============================================================
开始可能很多同学跟我一样,从代码入手,点亮一个led,急于看到结果,然后一顿操作猛如虎,驱动学的特别苦,面试一问二百五!
因此,现在我想改变下策略,从基本概念开始,不急着去写代码,先去了解下字符设备驱动框架,然后去弄懂如下几个概念:

1、啥是设备号,用来干嘛的

2、file_operations结构体的作用

3、cdev是啥

上面这三个应该就是字符设备驱动的关键了,把它们弄熟了才能更好的编写字符设备驱动
=============================================================
概念理解

1、字符设备驱动框架

字符设备是Linux三大设备之一,另外两种我就不提了,字符设备就是字节流形式通讯的I/O设备,绝大部分设备都是字符设备,所以学好它是我们嵌入式开发人员势在必行的。

常见的字符设备包括鼠标、键盘、显示器、串口等,用ls -l /dev指令可以查看很多设备文件,c就是字符设备, 后面的数值就是主设备号和次设备号,这个特别重要!

2、啥是设备号,用来干嘛的?

设备号又分为主设备号和次设备号

主设备号用来区分不同硬件设备类型,如串口和USB之间的区别,表示对应的驱动程序,也就是说一个主设备号对应一个驱动程序。

次设备号用来区分同一类型的多个设备,如串口1和串口2之间的区别,由内核使用,用于确定/dev下的设备文件对应的具体设备。

作用:有句话应该大家都知道,linux下兼文件,各种设备都以文件的形式存放在/dev目录下,称为设备文件

应用程序可以打开、关闭和读写这些设备文件,完成对设备的操作,就像操作普通的数据文件一样。为了管理这些设备,系统为设备编了
号,所以每个设备号就分为了主设备号和次设备号。

其中与设备号相关的比较重要的三个宏【代码中尽量使用宏,减少系统兼容性问题,不同系统主次设备号位数可能不同】

#define MAJOR(dev)        ((dev)>>8)
#define MINOR(dev)        ((dev) & 0xff)
#define MKDEV(ma,mi)        ((ma)<<8 | (mi))

3、file_operations结构体的作用

file_operations结构体是字符设备驱动与内核的接口,是用户空间对Linux进行系统调用最终的落实者, 这个结构体包含对文件打开,关闭,读写,控制的一系列成员函数。

//结构体定义如下:
static struct file_operations chrdev_fops = {
        .owner                = THIS_MODULE,        //指向拥有这个结构的模块的指针.用来在它的操作还在被使用时阻止模块被卸载

        .open                = chrdev_open,                //以下都是些常用接口,应用层调用时对应的驱动层实现
        .release                = chrdev_release,
        .write                = chrdev_write,
        .read                        = chrdev_read,
};


4、cdev是啥

cdev是字符设备对象结构体,是linux用来管理字符设备的,其在内核中采用数组结构设计,这样系统中有多少个主设备号就约定了数组大小,此设备号采用链表管理,同一主设备号下可以有多个子设备。

cdev 结构体中包含 设备号 dev_t 和 file_operations 结构指针

说白了,cdev 就是用来描述一个字符设备的,结构体如下:
struct cdev {
        struct kobject kobj;                              //内嵌的内核对象.
        struct module *owner;                           //该字符设备所在的内核模块的对象指针.
        const struct file_operations *ops;          //该结构描述了字符设备所能实现的方法,是非常关键的一个结构体.
        struct list_head list;                             //用来将已经向内核注册的所有字符设备形成链表.
        dev_t dev;                                            //字符设备的设备号,由主设备号和次设备号构成.
        unsigned int count;                             //同一主设备号下的次设备号的个数.
};

跟cdev相关的有四个比较重要的函数:

struct cdev *cdev_alloc(void);        //申请一个cdev,也可以定义变量一样弄一个

void cdev_init(struct cdev*, const struct file_opeartions*); //初始化cdev设备对象,其实就是跟file_opeartions进行绑定, 相当于两个人私定终身了

int cdev_add(struct cdev* , dev_t, unsigned);         //注册字符设备对象cdev到内核,相当于两人结婚领证了,从此系统可查,受国家法律保护

void cdev_del(struct cdev* );        //从内核注销cdev设备对象


扩展:应用程序是怎么跟驱动程序产生联系的呢,比如open函数,其调用大致过程如下:

1、应用程序open打开一个设备节点文件:int open("/dev/text", O_RDWR);

2、会产生open系统调用,然后进入内核,调用sys_open函数,就直接到VFS层了,并产生struct file表示一个打开的文件

3、然后VFS虚文件系统open根据传进来的路径转换为inode,通过 inode 节点获取到文件设备号

4、遍历 cdev 链表,与此文件的设备号进行比较,如果相同则表示匹配成功

5、将匹配成功的 cdev 结构体中的 file_operations 赋值给此文件的 struct file,从而关联到驱动层中的file_operations

6、最后根据file_operations中函数指针就可以找到该结构体中对该种文件操作的所有方法

大致过程就是:应用层open --> 系统调用sys_open --> VFS层 --> 得到inode --> 获取设备号 --> 遍历cdev --> 设备号匹配就进行关联

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入42汤圆

发表于 2020-8-13 16:42:36 来自手机 | 显示全部楼层
字体太大了

出40入42汤圆

发表于 2020-8-13 16:46:11 来自手机 | 显示全部楼层
不要用大字体,手机版看着太难受

出0入4汤圆

 楼主| 发表于 2020-8-13 16:54:55 | 显示全部楼层
落叶知秋 发表于 2020-8-13 16:46
不要用大字体,手机版看着太难受

就用默认字体吗,这个排版好像很难对齐?

出0入4汤圆

 楼主| 发表于 2020-8-13 16:55:16 | 显示全部楼层

哪种字体比较好

出0入4汤圆

发表于 2020-8-13 17:41:05 | 显示全部楼层
同感 同感,打王者总遇到坑

字符设备目前都会用了,但是原理还没有搞清楚

出0入4汤圆

 楼主| 发表于 2020-8-13 19:42:41 | 显示全部楼层
xiaoyigechaos 发表于 2020-8-13 17:41
同感 同感,打王者总遇到坑

字符设备目前都会用了,但是原理还没有搞清楚 ...

同道中人,敢问什么段位啦

出0入4汤圆

发表于 2020-8-13 22:32:34 | 显示全部楼层
batou 发表于 2020-8-13 19:42
同道中人,敢问什么段位啦

linux 黄金  王者星耀五

出0入0汤圆

发表于 2020-8-14 10:08:05 | 显示全部楼层
mark字符设备,目前新项目打算上安卓模块核心板了,要用SPI通讯,有ARM STM32的开发经验,android的应用软件也写过,而对于这种android嵌入式底层+驱动的开发,楼主有没有什么建议?我看需要搞清内核 HAL FRAMEWORK之类的,入门的话有没有一些教程或者书籍推荐呢?先感谢一下。

出0入4汤圆

 楼主| 发表于 2020-8-14 12:44:44 | 显示全部楼层
xiaoyigechaos 发表于 2020-8-13 22:32
linux 黄金  王者星耀五

加油,期待你linux也上星耀...

出0入4汤圆

 楼主| 发表于 2020-8-14 12:53:09 | 显示全部楼层
doubelmark 发表于 2020-8-14 10:08
mark字符设备,目前新项目打算上安卓模块核心板了,要用SPI通讯,有ARM STM32的开发经验,android的应用软 ...

你涉及的还挺宽的哈,Framework层貌似跟做应用与做底层驱动关系都不大,它是硬件抽象层HAL上封装的一层,做应用直接调用它的相关接口就好了;搞linux驱动的话,网上资料挺多的,要有很好的C语言基础,然后弄块开发板玩玩~~

出16170入6148汤圆

发表于 2020-8-23 12:11:31 来自手机 | 显示全部楼层
打赏!

庆祝论坛“打赏”功能实施, 现在开始发技术主题,可以获得打赏
https://www.amobbs.com/thread-5735948-1-1.html

出0入4汤圆

 楼主| 发表于 2020-8-24 17:16:49 | 显示全部楼层
armok. 发表于 2020-8-23 12:11
打赏!

庆祝论坛“打赏”功能实施, 现在开始发技术主题,可以获得打赏

还有打赏哈,感谢莫老大~

出0入0汤圆

发表于 2020-9-8 17:29:14 | 显示全部楼层
batou 发表于 2020-8-14 12:53
你涉及的还挺宽的哈,Framework层貌似跟做应用与做底层驱动关系都不大,它是硬件抽象层HAL上封装的一层, ...

楼主又来请教你了。
我们是用的simcom的智能模组,配套有开发板的。
只是这个开发板真的不知道该如何下手,跟着说明下载好了代码和patch,编译也跑通了。
看了一些linux的驱动的书,大概了解了linux下的驱动开发流程。
但是到了安卓感觉又不一样了,linux下可以编写驱动测试的文件,那安卓上呢?
比如要用SPI做通讯的话,除了修改dts,具体驱动该怎么编写呢?
一下子从STM32转到安卓还真是不大适应。烦请楼主指点一二。多谢。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-29 23:14

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表