字符设备驱动、平台设备驱动、设备驱动模型、sysfs的比较和关联

1、设备驱动
https://blog.csdn.net/fivedoumi/article/details/50913615
linux设备驱动分3种,包括字符设备驱动,块设备驱动和网络设备驱动。

* 字符设备驱动智能按字节流先后顺序访问设备内存,不能随机访问。鼠标,触摸屏,LCD等实时字符设备的代表。
* 块设备可以随机访问设备内存的任意地址,硬盘,SD卡,NandFlash等。
* 网络设备是指网卡一类使用socket套接字进行通信的设备。

2、字符设备驱动

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

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

2.2 字符设备驱动的任务

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

2.3、谁来创建设备文件
总有人出来做吧,否则应用层怎么访问?
一种方法是用户在shell中使用mknod命令创建设备文件,同时传入设备名和设备号。用来演示
另一种方法是依赖设备模型来辅助创建设备文件。这也是设备模型的作用之一。

2.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来打开设备文件来进行访问了。

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

3、设备驱动模型

3.1 设备驱动模型的作用
1> 设备驱动模型实现uevent机制,调用应用层的mdev来自动创建设备文件。
2> 设备驱动模型通过sysfs文件系统向应用层提供设备驱动视图。

上图只是可视化的一种表达,有助于大家去理解设备模型,类似于windows的设备管理程序,在嵌入式linux里面并没有相关应用通过图形的方式来展现这种关系。但是用户可以通过命令窗口利用ls命令逐级访问/sys文件夹来获得各种总线、设备、驱动的信息和关系。可以看出,在/sys顶级目录,有三个关键的子目录,就是设备类,设备和总线。

设备是具体的一个个设备,在/sys/devices是创建了实际的文件节点。而其他目录,如设备类和总线以下的子目录中出现的设备都是用符号链接指向/sys/devices/目录下的文件。

设备类是对/sys/device/下的各种设备进行归类,以体现一类设备的公共属性,如鼠标和触摸屏都是属于input设备类。

总线目录是总线、设备、驱动模型的核心目录,因为设备和驱动都是依附在某种总线上的,如USB,PCI和平台总线等。设备和驱动正是依靠总线的管理功能才能找到对方,如设备注册到总线时去寻找驱动,而驱动注册的时候去寻找其能够支持的设备。
最重要的是,如果没有设备模型,那应用层很难知道驱动和设备的关系,因为字符设备驱动并没有提供这些信息,那对于设备驱动的管理者而言会非常麻烦。

事实上,内核中的总线class,设备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目录下的文件内容,即可以直接修改设备对应的参数。

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

3.2 设备驱动模型的核心接口
bus_register(struct bus_type bus)注册总线
device_add(struct device
dev)注册设备
driver_register(struct device_driver *drv)注册驱动
class_create(ower, name)创建设备类

3.3 设备驱动模型和字符设备驱动区别

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

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

* 设备驱动模型的上下级关系(如子设备和所属父设备)通过sysfs文件系统的父目录和子目录来体现
* 设备取模模型的平级关系(如设备类管理的设备和具体的设备的关系)通过sysfs文件系统的目录符号链接来实现
* 设备驱动模型的属性(如设备的参数和设备名,设备号等)则通过sysfs文件系统的文件内容来记录实现。
* 设备驱动模型数据结构中的kobject对应于sysfs文件系统中的目录,而数据结构中的struct attribute成员则对应于sysfs文件系统中的文件。对应的意思是继续与kobject的device、device_driver和bus等在向系统注册的过程中会调用sysfs的create_dir接口来创建对应的目录,而含有struct attribute成员属性的device、device_driver和bus等在向系统注册的过程中则会调用sysfs的sysfs_create_file接口来创建文件。

4.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) 写操作
4.3 sysfs文件系统与属性文件的读写
sysfs_read_file是sysfs文件系统的读写入口,但是驱动需要向系统提供真正的读写操作,也就是struct sysfs_ops数据结构中的show和store接口。
sysfs是基于内存的文件系统,掉电即消失,sysfs所有的操作接口均是对内存中的内核数据结构进行访问的操作。假如用户用cat命令去读取一个属性文件如dev的内容,那么会产生如下流程:

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

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

5、平台设备驱动
平台设备驱动的“平台”指的是平台总线,即platform_bus_type,是linux众多总线中的一种,如USB总线,PCI总线,I2C总线等等,只不过平台总线是一种虚拟总线,专门用来管理SoC上的控制器如看门狗,LCD,RTC等等,他们都是CPU的总线上直接取址访问的。而USB、PCI等设备都有通过特定的时序来访问SoC芯片以外的设备。平台设备驱动体现的关系是设备驱动模型上的一个子集,将平台视为一种总线的概念即可。
5.1、平台设备驱动和设备驱动模型的关系
1>平台设备驱动接口在设备驱动模型视图上创建了相关的平台设备类(/sys/class/platform_bus)、平台总线(/sys/bus/platform)、平台设备(/sys/devices)
2>平台设备(platform_device)和平台设备驱动(platform_driver)均注册到平台总线上,即在/sys/bus/platform目录下创建相应的设备去驱动目录。
3>平台总线负责匹配注册到其上面的设备和驱动,匹配成功后回调用驱动的probe接口。
4>平台设备驱动利用设备驱动模型接口来辅助创建相应的设备文件(位于/dev目录下)。
相关的接口包括:
platform_device_register(structplatform_device pdev) 注册平台设备
platform_driver_register(structplatform_driver
drv) 注册平台设备驱动
两个接口的实现里面都会对平台驱动和设备进行匹配,匹配成功会调用驱动的probe接口。

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

5.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注册驱动。

猜你喜欢

转载自www.cnblogs.com/Ocean-Star/p/9249966.html
今日推荐