微盟网站模板,网站每年空间域名费用及维护费,海尔网站建设,wordpress 面包屑导航以下内容转载于微信公众号#xff1a;嵌入式企鹅圈。如有侵权#xff0c;请告知删除。 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动、平台设备驱动、设备驱动模型和sysfs等相关概念和技术。 对于初学者来说会非常困惑#xff0c;甚至对Linux有一定基础的工程师而言…以下内容转载于微信公众号嵌入式企鹅圈。如有侵权请告知删除。 学习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_opertionsOpen函数返回的局部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_cdevcdev_alloc();cdev_init(my_cdev,my_fops);cdev_add(my_fops,devno, 1);//注册设备号和file_opertions} 3module_init(chardev_init);//宏定义该初始化入口函数。卸载流程不做解释。 4insmod加载这个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、属性文件的读写
1sysfs_read_file是sysfs文件系统的读写入口但是驱动需要向系统提供真正的读写操作即struct sysfs_ops数据结构中的show和store接口。 2Sysfs文件系统是基于内存的掉电即消失。sysfs所有的操作接口均是对内存中的内核数据结构进行访问操作。
假如用户用cat命令去读取一个属性文件(如dev)的内容那么会产生以下流程 fdopen(“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和平台设备驱动之间的关系。