zoukankan      html  css  js  c++  java
  • 字符设备驱动、平台设备驱动、设备驱动模型、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注册驱动。

  • 相关阅读:
    自定义组件要加@click方法
    绑定样式
    647. Palindromic Substrings
    215. Kth Largest Element in an Array
    448. Find All Numbers Disappeared in an Array
    287. Find the Duplicate Number
    283. Move Zeroes
    234. Palindrome Linked List
    202. Happy Number
    217. Contains Duplicate
  • 原文地址:https://www.cnblogs.com/Ocean-Star/p/9249966.html
Copyright © 2011-2022 走看看