linux新型字符设备驱动五种框架

目录

一、无设备树

二、有设备树,无其它驱动模型

三、gpio子系统(pintrl子系统),带设备树

四、平台设备驱动模型

五、MISC(杂项)驱动模型,带设备树

附件:     


一、无设备树

1、不同点

        (1) 使用 ioremap() 将寄存器地址映射成虚拟地址才能被访问:

        (2) 用linux驱动提供相应的函数读(readb、readw、readl)写(writeb、writew、writel)映射后的               寄存器:

        (3) ioremap之后,退出出口函数的时候,记得要有对应的 iounmap。   

    gitee代码链接:https://gitee.com/can_mo/gitee_linux_driver/tree/master/03_newchrled

  github代码链接:https://github.com/CanvMo/Can/tree/master/03_newchrled

二、有设备树,无其它驱动模型

1、不同点

        (1) 编写设备树文件(.dts),在根节点下添加设备树节点:

        (2)用 of 函数获取设备树节点或者属性信息:

        (3) 可以用 of_iomap() 将寄存器地址映射成虚拟地址,也是使用 iounmap() 取消映射:

             

             

        (4) 也是用linux驱动提供相应的函数读(readb、readw、readl)写(writeb、writew、writel)映射               后的寄存器;

          gitee代码链接:https://gitee.com/can_mo/gitee_linux_driver/tree/master/04_dtsled

        github代码链接:Can/04_dtsled at master · CanvMo/Can · GitHub

2、内核匹配设备树文件,函数调用过程

3、内核解析设备树文件,函数调用过程

三、gpio子系统(pintrl子系统),带设备树

1、不同点

        (1) 设备树文件需要固定格式 

         (2) 相关 of 函数获取设备树信息

        (3) 用 gpio子系统相关库函数控制GPIO

     gitee代码链接:https://gitee.com/can_mo/gitee_linux_driver/tree/master/05_gpioled

   github代码链接:Can/05_gpioled at master · CanvMo/Can · GitHub

      (4) 普通设备树驱动与gpio子系统的区别:

            普通设备树驱动:读取了设备树的一些硬件信息(地址等),得到寄存器的值,可以通过                                                 readl writel等函数操作对应寄存器;

           gpio子系统(分层、分离思想):用设备树设置好硬件信息之后,有自己一套更加简单的操作                           函数去控制硬件设备,gpio_direction_output(),gpio_set_value()等函数;

            难点:设备树是的配置

四、平台设备驱动模型

1、目的:把设备信息和驱动分开;

2、platform驱动模型与设备树驱动模型的区别和联系: 

      (1) 相当于在设备树驱动模型上加了一层(platform驱动模型),两者设备树相关代码都是一样的。

3、四种匹配方式

      第一种匹配方式(常用): OF 类型的匹配,也就是设备树采用的匹配方式

     第二种匹配方式: ACPI 匹配方式

     第三种匹配方式: id_table 匹配

     第四种匹配方式:如果第三种匹配方式的 id_table 不存在的话就直接比较驱动和设备的                          name  字段

4、 设备和驱动匹配成功之后,会执行 probe 函数,自己实现;

5、分为无设备树和有设备树两种驱动模型

        (1)无设备树模型

                a. 要自己编写一个 device(设备) 文件和一个 driver(驱动) 文件;

                b. device文件用于描述硬件信息:

                   

             

               c. driver文件用于驱动设备:

      

             gitee代码链接:https://gitee.com/can_mo/gitee_linux_driver/tree/master/17_platform

             github代码链接:https://github.com/CanvMo/Can/tree/master/17_platform

        (2)有设备树模型(常用)

                a. 设备的描述被放到了设备树中,通过compatible属性与驱动匹配

                b. 驱动框架 

                    ①通过 platform_driver_register()注册platform驱动结构体

         

                   ②通过compatible属性设备和驱动匹配,匹配成功之后执行 .probe 函数:

                  ③ led_probe (.probe) 函数主要是字符设备驱动框架基本内容:设置设备号、注册设                           备、创建类、创建设备、初始化;

               gitee代码链接:https://gitee.com/can_mo/gitee_linux_driver/tree/master/18_dtsplatform

               github 代码链接:https://github.com/CanvMo/Can/tree/master/18_dtsplatform

        (3)两种设备和驱动匹配方式不一样,其中name 属性用于传统的驱动与设备匹配,也就是检                 查驱动和设备的 name 字段是不是相同;of_match_table 属性就是用于设备树下的驱动与               设备检查。

             

五、MISC(杂项)驱动模型,带设备树

1、优点:MISC 驱动是最简单的字符设备驱动,最大程度缩减了代码;

2、当我们板子上的某些外设无法进行分类的时候就可以使用 MISC(杂项)驱动;MISC(杂项)驱动          通常也是用平台设备驱动模型。

3、所有的 MISC 设备驱动的主设备号都为 10,不同的设备使用不同的从设备号。

4、还是平台设备驱动,主要是简化了注册和反注册

        (1)注册

        (2)反注册

 gitee代码链接:gitee_linux_driver: 个人理解编写的linux驱动 - Gitee.com

 github 代码链接:Can/19_miscbeep at master · CanvMo/Can · GitHub

附件:     

1、自动分配设备号的原理:mdev机制     

        (1) mdev机制:使用 busybox 构建根文件系统的时候, busybox 会创建一个 udev 的简化版                                     本—mdevLinux 系统中的热插拔事件也由 mdev 管理

        (2) mdev机制的目的:利用信息自动创建设备节点。那么利用哪些信息呢?

               mdev扫描/sys/class和/sys/block中所有的类设备目录,如果在目录中含有名为"dev"的          文件,且文件中包含的是设备号,则mdev就利用这些信息为这个设备在/dev下创建设备节点。

          

2、设备树常用 OF 操作函数获取设备树中的节点或者属性信息函数,这些 OF 函          数原型都定义在 include/linux/of.h 文件中       

     (1)查找节点的 5个OF 函数

         ① of_find_node_by_name 函数通过节点名字查找指定的节点

         ② of_find_node_by_type 函数通过 device_type 属性查找指定的节点 

        ③of_find_compatible_node 函数根据 device_type 和 compatible 这两个属性查找指定的                  节点

        ④ of_find_matching_node_and_match 函数:通过 of_device_id 匹配表来查找指定的节点

        ⑤ of_find_node_by_path 函数通过路径来查找指定的节点

           

    (2) 查找父/子节点的 OF 函数

        ① of_get_parent 函数用于获取指定节点的父节点(如果有父节点)

        ② of_get_next_child 函数用迭代的方式查找子节点

    (3) 提取属性值的 OF 函数

        ①of_find_property 函数用于查找指定的属性

        ②of_property_count_elems_of_size 函数用于获取属性中元素

       ③of_property_read_u32_index 函数用于从属性中获取指定标号的 u32 类型数据值(无符号              32位)

       ④of_property_read_u8_array 函数

          of_property_read_u16_array 函数
          of_property_read_u32_array 函数
          of_property_read_u64_array 函数

                这 4 个函数分别是读取属性中 u8u16u32 u64 类型的数组数据,比如大多数的           reg 属性都是数组数据,可以使用这 4 个函数一次读取出 reg 属性中的所有数据

       ⑤of_property_read_u8 函数
          of_property_read_u16 函数
          of_property_read_u32 函数
          of_property_read_u64 函数  

            这四个函数就是用于读取这种只有一个整形值的属性,分别用于读取 u8

        u16、  u32  和  u64  类型属性值

       ⑥of_property_read_string 函数用于读取属性中字符串值

       ⑦of_n_addr_cells 函数用于获取#address-cells 属性值

       of_n_size_cells 函数用于获取#size-cells 属性值  

   (4) 其他常用的 OF 函数

       ①of_device_is_compatible 函数用于查看节点的 compatible 属性是否有包含 compat 指定               的字符串,也就是检查设备节点的兼容性;

       ②of_get_address 函数用于获取地址相关属性

       ③of_translate_address 函数负责将从设备树读取到的地址转换为物理地址

       ④of_address_to_resource 函数将 reg 属性值转换为 resource 结构体类型

       ⑤of_iomap 函数用于直接内存映射

    (5) 设备树常用操作GPIO的OF函数这些函数原型都定义在 include/linux/of_gpio.h 文件中

               ① of_get_named_gpio 函数:通过设备树节点获取GPIO编号: 

                 函数原型:

                 

                  np: 设备节点,可通过of_find_node_by_path函数获得;

                  propname: 包含要获取 GPIO 信息的属性名;

                 index: GPIO 索引,因为一个属性里面可能包含多个 GPIO,此参数指定要获取哪个                                   GPIO的编号,如果只有一个 GPIO 信息的话此参数为 0。

                  返回值: 正值,获取到的 GPIO 编号;负值,失败。

                 用法:

               

 3、常用gpio子系统函数,在include/asm-generic/gpio.h文件中: 

                                                                                                                                                       (1)gpio_direction_output:把某个GPIO设置输出高电平或者低电平:

            函数原型:

              

                gpio: GPIO 编号

                value:往GPIO要写的值;

             用法:

             

        (2)gpio_set_value:一般只是在这个GPIO口的寄存器上写上某个值,但不确定这个端口是否                设置为输出,为了提高运行效率;

              函数原型:

             

              gpio: GPIO 编号

              value:往GPIO要写的值;

              用法:

             

                 (1)和(2)一般会联合使用:初始化的时候用gpio_direction_output(),后面GPIO再输出操

         作的时候,可以使用gpio_set_value(),提高运行效率。

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值