设备驱动,字符设备驱动、(总线)设备驱动模型、sysfs文件系统、平台设备驱动

以下内容转载于微信公众号:嵌入式企鹅圈。如有侵权,请告知删除。

    学习Linux设备驱动开发的过程中自然会遇到字符设备驱动、平台设备驱动、设备驱动模型和sysfs等相关概念和技术。

    对于初学者来说会非常困惑,甚至对Linux有一定基础的工程师而言,能够较好理解这些相关技术也相对不错了。

    要深刻理解其中的原理需要非常熟悉设备驱动相关的框架和模型代码。

    网络上有关这些技术的文章不少,但多是对其中的某一点进行阐述,很难找到对这些技术进行比较和关联的分析。

    对于开发者而言,能够熟悉某一点并分享出来已很难得,但对于专注传授技术和经验给学习者而言,横向比较关联各个驱动相关的知识点和纵向剖析Linux整个驱动软件层次是非常有必要的,也非常有意义。

    本文依然是从需求的角度去理解以上知识点,存在即是合理,以上技术知识能够存在,即代表其有一定的作用。我们着重去理解每一个技术点的作用,并明确其在驱动开发中的角色。

一、设备驱动

  • (设备的)驱动;
  • Linux设备驱动分三种,包括字符设备驱动、块设备驱动和网络设备驱动。
  • 字符设备只能按字节流先后顺序访问设备内存,不能随机访问。鼠标、触摸屏、LCD等是字符设备的代表。
  • 块设备可以随机访问设备内存的任意地址,硬盘、SD卡、NAND FLASH是块设备的代表。
  • 网络设备指的是网卡一类使用socket套接字进行通信的设备。

二、字符设备驱动

    字符设备驱动框架,请参考嵌入式企鹅圈的两篇文章:《Linux字符设备驱动剖析》和《Linux设备文件的创建和mdev》。

1、字符设备驱动纵向关系

  • 从《Linux字符设备驱动剖析》可以看出,应用层访问设备驱动非常简单,即通过open接口最终获得设备驱动的操作接口集struct file_opertions。
  • 而open接口传入的参数是/dev目录下的设备名,设备名对应的设备文件节点inode会存储设备号。
  • 而驱动框架中的全局数组cdev_map则维护设备号和file_opertions的关系。
  • 即应用层到底层的关系主要是(忽略VFS这一层):设备名-->设备号-->file_opertions;
  • Open函数返回的局部fd和file_opertions的关系(忽略进程数据结构):fd-->file(当前进程数据结构成员)-> file_opertions;
  • 这样,通过fd即可以获得file_opertions,即可以通过read、write等接口来调用驱动的读操作函数和写操作函数、ioctl函数等。

2、字符设备驱动的任务

  • 字符设备驱动最本质的任务,应该是提供file_opertions的各个open、read、write、ioctl等接口的实现。
  • 另外从以上的描述中,为了让应用层能够调用到底层的file_opertions还涉及到以下任务:
  • 申请设备号,并将设备号和file_opertions注册(cdev_add接口)到驱动框架中的cdev_map数组。这点应该在字符设备驱动中负责,涉及到其主动向系统报备自己的存在。
  • 在/dev目录中创建设备文件,内容包括设备号。这一点是否由字符设备驱动来负责商榷。字符设备驱动位于内核层,如果由其负责这个任务,那么驱动就得知道它要创建的设备名。简单的字符驱动还好,如果是USB等可插拔的设备,驱动怎么知道自己要创建什么设备名呢?有人说可以写明一套规则。确实如此,但如果把这套规则放到应用层,由应用程序开发人员去明确这个规则(mdev正是这样做的),会不会更好?因为是应用程序直接编程访问这个设备名对应的设备驱动的。所以字符设备驱动不应该直接负责设备文件的创建。

3、谁来创建设备文件

  • 一种方法就是用户在shell中使用mknod命令创建设备文件,同时传入设备名和设备号。这是人工的做法,很不科学。但它是一种演示的方法。
  • 另一种方法就是依赖设备模型来辅助创建设备文件。这也是设备模型的作用之一。

4、字符设备驱动编程流程

(1)定义struct file_opertions my_fops并实现其中的各个接口,如open、read、write、ioctl等接口。

(2)实现驱动的入口函数,如chardev_init

static int __init chardev_init(void)
{alloc_chrdev_region(&devno,…);//申请设备号my_cdev=cdev_alloc();cdev_init(my_cdev,&my_fops);cdev_add(my_fops,devno, 1);//注册设备号和file_opertions}


(3)module_init(chardev_init);//宏定义该初始化入口函数。卸载流程不做解释。

(4)insmod加载这个module后,可以人工在shell命令行利用mknod创建设备文件。

(5)应用层即可以用open来打开设备文件来进行访问了。

5、总结

  • 可以看出,字符设备驱动的核心框架跟设备模型、平台设备驱动没有直接关系,不用他们也一样能够正常工作。

三、(总线)设备驱动模型

    我们主要谈及设备驱动模型在linux驱动中的作用和角色,有关设备模型的原理和实现我们另文再述。

1、(总线)设备驱动模型的作用

(1)设备驱动模型实现uevent机制,调用应用层的medv来自动创建设备文件。这在上面已经论述过。

(2)设备驱动模型通过sysfs文件系统向用户层提供设备驱动视图,如下。



 

 

  • 上图只是可视化的一种表达,有助于大家去理解设备模型,类似于windows的设备管理程序;
  • 在嵌入式linux里面并没有相关应用通过图形的方式来展现这种关系。但是用户可以通过命令窗口利用ls命名逐级访问/sys文件夹来获得各种总线、设备、驱动的信息和关系。可以看出,在/sys顶级目录,有三个关键的子目录,就是设备类、设备和总线。
  • 设备是具体的一个个设备,在/sys/devices/是创建了实际的文件节点。而其他目录,如设备类和总线以下的子目录中出现的设备,都是用符号链接指向/sys/devices/目录下的文件。
  • 设备类是对/sys/devices/下的各种设备进行归类,以体现一类设备的公共属性,如鼠标和触摸屏都是属于input设备类。
  • 总线目录是总线、设备、驱动模型的核心目录。因为设备和驱动都是依附在某种总线上的,如USB、PCI和平台总线等。设备和驱动正是依靠总线的管理功能才能找到对方,如设备注册到总线时去寻找驱动,而驱动注册的时候去寻找其能够支持的设备。
  • 最重要的是,如果没有设备模型,那应用层很难知晓驱动和设备的关系,因为字符设备驱动并没有提供这些信息,那对于设备驱动的管理者而言会非常麻烦。事实上,内核中的总线class、设备device和驱动device_driver都不会将所有的信息暴露给用户层,例如这三个数据结构都有对应的private数据结构,它用于内核对上下级总线设备驱动的链表关系维护。如果暴露给用户层,那容易被用户层修改而使系统混乱。实际上,用户层只关心三者的视图关联,至于他们的关联在底层怎么实现则不需要关心。

(3)设备驱动模型提供统一的电源管理机制。

  • 很明显,我们在字符设备驱动的file_operations接口中并没有看到电源管理方面的接口。但对于操作系统来说,电源功耗管理必不可少。
  • 电源管理其实不应该由应用开发人员来负责,而是应该由系统来负责,例如手机很久没有触摸了,那会进入休眠状态。
  • 这种状态的改变应该由系统来完成,而各种设备进入睡眠模式也应该由系统来完成。因此file_operations不提供电源管理的接口给应用程序是合理的。
  • 而设备模型作为系统管理的一种机制,由它来提供电源管理是非常合理的。
  • 如设备device数据结构有struct dev_pm_info power功耗属性参数,驱动device_driver数据结构有struct dev_pm_ops *pm功耗操作接口。

(4)设备驱动模型提供各种对象实例的引用计数,防止对象被应用层误删。

  • 设备模型的所有数据结构均是继承kobject而来,而kobject就提供基础的计数功能。

(5)设备驱动模型提供多一种方式给应用层,用户和内核可以通过sysfs进行交互,如通过修改/sys目录下设备的文件内容,即可以直接修改设备对应的参数。

2、设备驱动模型的核心接口

bus_register(struct bus_type *bus) 注册总线
device_add(struct device *dev) 注册设备
driver_register(struct device_driver*drv) 注册驱动
class_create(owner, name) 创建设备类
……

3、设备驱动模型和字符设备驱动区别

  • 设备驱动模型侧重于内核对总线、设备和驱动的管理,并向应用层暴露这些管理的信息,而字符设备驱动则侧重于设备驱动的功能实现。

四、sysfs文件系统

1、sysfs文件系统和设备驱动模型的关系

Sysfs文件系统是设备驱动模型得以向用户暴露其管理信息的载体。它们之间的关系如下:

(1)设备驱动模型的上下级关系(如子设备和所属父设备)通过sysfs文件系统的父目录和子目录来体现。

(2)设备驱动模型的平级关系(如设备类管理的设备和具体的设备的关系)则通过sysfs文件系统的目录符号链接来实现。

(3)设备驱动模型的属性(如设备的参数和设备名,设备号等)则通过sysfs文件系统的文件内容来记录实现。

(4)设备驱动模型数据结构中的kobject对应于sysfs文件系统中的目录,而数据结构中的struct attribute成员则对应于sysfs文件系统中的文件。

  • 对应的意思是指含有kobject的device、device_driver、bus等在向系统注册时,会(调用sysfs的create_dir接口来)创建对应的目录;
  • 含有struct attribute成员属性的device、device_driver、bus等在向系统注册时,会(调用sysfs的sysfs_create_file接口来)创建文件。

2、sysfs核心接口

sysfs_create_file(struct kobject * kobj,const struct attribute * attr)创建属性文件
sysfs_create_dir(struct kobject * kobj)创建目录
int sysfs_open_file(struct inode *inode,struct file *file)打开sysfs文件系统格式的文件
sysfs_read_file(struct file *file, char__user *buf, size_t count, loff_t *ppos) 读操作
sysfs_write_file(struct file *file, constchar __user *buf, size_t count, loff_t *ppos) 写操作

3、属性文件的读写

(1)sysfs_read_file是sysfs文件系统的读写入口,但是驱动需要向系统提供真正的读写操作,即struct sysfs_ops数据结构中的show和store接口。

(2)Sysfs文件系统是基于内存的,掉电即消失。sysfs所有的操作接口均是对内存中的内核数据结构进行访问操作。

假如用户用cat命令去读取一个属性文件(如dev)的内容,那么会产生以下流程:

  • fd=open(“dev”)->vfs_open(“dev”)->sysfs_open(“dev”),获取该文件的句柄;
  • read()->vfs_read()->sysfs_read_file()->sysfs_ops->show(),该show接口即是设备在注册时产生属性文件,并向系统提供该文件的读接口。而读接口的实现,自然是对该属性参数的读访问。

(3)/sys挂载了sysfs文件系统,因此所有对/sys目录下的文件或者目录的操作,都会通过sysfs文件的接口进行访问。
 

五、平台设备驱动

  • “平台设备驱动”中的“平台”,指的是平台总线,即platform_bus_type,是linux众多总线中的一种,如USB总线、PCI总线、I2C总线等等。
  • 平台总线是一种虚拟的总线,专门用来管理SOC上的控制器(如看门狗、LCD、RTC等等),它们都是(CPU的总线上)直接取址访问设备的。而USB、PCI等设备都有通过特定的时序来访问SOC芯片以外的设备。
  • 平台设备驱动是总线设备驱动模型上的一个子集。将平台视为一种总线的概念,那两者的关系就会容易理解。

1、平台设备驱动和设备驱动模型的关系

(1)在设备驱动模型视图上,平台设备驱动接口创建了相关的平台设备类(/sys/class/platform_bus)、平台总线(/sys/bus/platform)、平台设备(/sys/devices/)。

(2)平台设备(platform_device)、平台设备驱动(platform_driver)均注册到平台总线上,即在/sys/bus/platform/目录下创建相应的设备和驱动目录。而平台总线负责匹配注册到其上面的设备和驱动,匹配成功后会调用驱动的probe接口。

(3)平台设备驱动,利用设备驱动模型接口,来辅助创建对应的设备文件(位于/dev/目录下)。

(4)相关的接口包括

platform_device_register(struct platform_device *pdev) 注册平台设备
platform_driver_register(struct platform_driver *drv) 注册平台设备驱动

两个接口的实现里面都会对平台驱动和设备进行匹配,匹配成功会调用驱动的probe接口。

2. 平台设备驱动和字符设备驱动的关系

我们假设这个平台设备是字符设备。

  • 平台设备驱动和字符设备驱动的关系始于驱动的probe接口,即在probe接口中实现字符设备驱动所要完成的任务,即通过alloc_chrdev_region申请设备号,和通过cdev_add注册驱动的struct file_opertions。
  • 另外为了自动创建应用层访问的设备文件,还要调用class_create和device_create接口在平台设备类下创建对应的设备类和设备,并发出uevent事件,调用mdev来创建设备文件。

3、平台设备驱动的开发流程

(1)将字符设备驱动的char_init函数的实现搬到platform_driver的probe接口中。

(2)在char_init中调用platform_device_register和platform_driver_register分别注册设备和驱动。

  • 其实对于移植好的系统,platform_device_register是在linux启动的过程中完成的。
  • 因此char_init一般只有platform_driver_register注册驱动。

详细的平台设备驱动的实现原理和开发流程另文再述。本次的重点是为了阐述字符设备驱动、设备驱动模型、sysfs和平台设备驱动之间的关系。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/461311.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

对于局部变量_对于SQL常用查询优化方法的整理

查询进行优化,应尽量避免全表扫描,首先应考虑在where 及order by 涉及的列上建立索引:尝试下面的技巧以避免优化器错选了表扫描:使用ANALYZE TABLE tbl_name为扫描的表更新关键字分布。对扫描的表使用FORCE INDEX告知MySQL,相对于…

黄聪:如何使用CodeSmith批量生成代码(原创系列教程)

在上一篇我们已经用PowerDesigner创建好了需要的测试数据库,下面就可以开始用它完成批量代码生成的工作啦. 下面我会一步步的解释如何用CodeSmith实现预期的结果的,事先声明一下,在此只做一个简单的Demo,并不详细的讲解CodeSmith各个强大的功能,有兴趣的朋友可以打开CodeSmith的…

c语音异或运算符_C语言中的按位异或运算符有什么用处?

原标题:C语言中的按位异或运算符有什么用处?想知道C语言中的按位异、运算符有什么用处,首先C语言中^为按位异或运算符,若两个二进制位相同,则结果为0,不同为1例:#include "stdio.h"ma…

HDU2201

水~ 分析:n,m。对于第一个人不抽到m号座位概率为(n-1)/n,第二个人为(n-2)/(n-1).。。。第m个人为1/(n-m1).。。。 相乘之后则为 1/n V…

字符设备驱动基础1——简单的驱动源代码分析

以下内容源于朱有鹏嵌入式课程的学习&#xff0c;如有侵权请告知删除。 参考博客&#xff1a;linux驱动开发&#xff08;一&#xff09; - biaohc - 博客园 一、驱动源代码示例 /********module_test.c代码*********/#include <linux/module.h> // module_init module…

字符设备驱动基础3——使用register_chrdev()函数注册字符设备

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 一、系统工作原理 1、工作流程 系统的整体工作流程是&#xff1a;应用层—>API—>设备驱动—>硬件。 操作系统提供的API包括open、read、write、close等函数&#xff0c;它们只是一种操作逻…

win7在未关闭vmware情况下直接关机,导致虚拟机无法克隆

今天有点小激动啊&#xff0c;着急关机&#xff0c;结果发现重启之后的虚拟机不能进行克隆操作。系统提示如下&#xff1a;the Specific Virtual Disk Needs Repair .查询“度娘”&#xff0c;突然看到一篇文章说&#xff0c;删除这啊&#xff0c;修改那的....特别复杂&#xf…

hdu 1159(最长公共子序列)

题目链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid1159 思路&#xff1a;dp[i][j]表示s1从0~i-1,s2从0~j-1的最长公共子序列&#xff1b; 递推方程为&#xff1a;dp[i][j](s1[i-1]s2[j-1])?d[i-1][j-1]1:max(dp[i-1][j],dp[i][j-1]); View Code 1 #include<…

mysql applier_MySQL推出Applier,可实时复制数据到Hadoop-阿里云开发者社区

http://labs.mysql.comMySQL复制操作可以将数据从一个MySQL服务器(主)复制到其他的一个或多个MySQL服务器(从)。试想一下&#xff0c;如果从服务器不再局限为一个MySQL服务器&#xff0c;而是其他任何数据库服务器或平台&#xff0c;并且复制事件要求实时进行&#xff0c;是否可…

字符设备驱动基础4——读写接口的操作实践

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 一、细节提要 1、与用户与内核数据交换有关的函数 &#xff08;1&#xff09;copy_from_user()函数 该将数据从用户空间复制到内核空间。 如果成功复制则返回0&#xff0c;如果不成功复制则返回尚未…

mysql分区表mycat_MySQL 中间件之Mycat垂直分表配置

垂直分表就是将一个库下的多个表拆分到多个MySQL实例&#xff0c;实现库压力分流。通过GTID模式复制&#xff0c;db01与db02之间不进行任何连接与复制当前环境&#xff1a;mycat --> db01与db02db01 --> db03db02 --> db04当前垂直分表架构&#xff1a;后端数据库创建…

深入浅出mysql gtid_深入理解MySQL GTID

GTID的概念何为GITDGTID(global transaction identifier)是全局事务标识符&#xff0c;在MySQL5.6版本中作为一个超级特性被推出。事务标识不仅对于Master(起源)的服务器来说是惟一的&#xff0c;而且在整个复制拓扑架构来说&#xff0c;也是全局唯一的。1.GTID的格式GTID sou…

winform 64位系统中使用

WINFOR编译成X86的 转载于:https://blog.51cto.com/agilitygod/1419939

long 转为string_面试必问 Redis数据结构底层原理String、List篇

点击关注上方“Java大厂面试官”&#xff0c;第一时间送达技术干货。阅读文本大概需要 8 分钟。前言今天来整理学习下Redis有哪些常用数据结构&#xff0c;都是怎么使用的呢&#xff1f;首先看下全局存储结构。全局存储结构基础你们肯定都知道&#xff0c;redis支持的基础数据结…

wpf 3D学习

最近在看一些关于wpf 3d的效果&#xff0c;研究了一些代码特效&#xff0c;现在和广大博友共享一下. 首先用到的是MeshGeometry3D&#xff0c;msdn上介绍&#xff1a;用于生成三维形状的三角形基元。主要有4个依赖属性&#xff1a;NormalsProperty&#xff0c;PositionsPropert…

unicode字符、python乱码问题

http://www.cnblogs.com/BeginMan/archive/2013/08/08/3246619.html#a1 Python常见常用知识点http://blog.csdn.net/tingsking18/article/details/4033645 Unicode和Python的中文处理如何让Python的Unicode字符串支持中文&#xff1f;要想利用Python的Unicode机制处理字符串&…

win10下如何安装vb6.0sp6_Mac如何安装win10系统?Parallels Desktop 15 Mac安装win10系统教程...

Parallels Desktop 15 mac版是mac上非常强大也非常好用的虚拟机软件&#xff0c;最新版本的parallels desktop mac 15针对最新的Windows 10更新和macOS Catalina&#xff08;10.15&#xff09;进行了优化。今天分享的内容就是Parallels Desktop 15 mac版如何安装win10系统。PD虚…

字符设备驱动高级篇5——静态映射表的建立过程,动态映射结构体方式操作寄存器

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 补充内容&#xff1a;字符设备驱动基础5——驱动如何操控硬件_天糊土的博客-CSDN博客 一、静态映射表的建立过程 关于“静态映射表的建立”这部分内容&#xff0c;有以下三个关键&#xff1a; &…

python 分布图_python数据分布型图表柱形分布图系列带误差线的柱形图

柱形分布图系列柱形分布图系列使用柱形图的方式展示数据的分布规律&#xff1b;可以借助误差线或散点图&#xff1b;带误差线的柱形图就是使用每个类别的均值作为柱形的高度&#xff1b;再根据每个类别的标准差绘制误差线&#xff1b;缺点&#xff1a;无法显示数据的分布情况&a…

[汇编] 002基础知识-CPU和寄存器

CPU是什么 当然这里的内存不仅仅指电脑上的内存&#xff0c;例如&#xff1a;我的金士顿8G内存&#xff0c;七彩虹1G独显&#xff0c;在这里来说&#xff0c;显卡也是有内存的(寄存器) CPU如何控制其它部件的&#xff1f; 问题&#xff1a;CPU是如何和电脑主机中其它芯片有条不…