zoukankan      html  css  js  c++  java
  • 翻译:A Tutorial on the Device Tree (Zynq) -- Part III

    [A Tutorial on the Device Tree (Zynq) -- Part III](A Tutorial on the Device Tree (Zynq) -- Part III)

    定义外设

    可能你读本文是为了给你的设备写一个Linux驱动,在这方面要推荐著名的《Linux Device Driver》。但是在写一个设备驱动之前,允许我分享写Linux驱动的第一诫:永远不要为Linux写设备驱动

    更好的办法是找一个维护状态良好的类似功能的设备驱动,然后修改它。这不仅仅意味着更容易,更可能帮我们避免我们一些未意识到的问题。从其他驱动移植过来可以让这份驱动更容易被理解,可移植,更可能被内核树接受。

    所以现在的重点变为理解其他驱动,然后做一点调整。有疑问的地方就照着别人的做法做。创新和个人风格在这里没什么用。

    现在,回到设备树。让我们来看看第二部分省略的内容:

      ps7_axi_interconnect_0: axi@0 {
        #address-cells = <1>;
        #size-cells = <1>;
        compatible = "xlnx,ps7-axi-interconnect-1.00.a", "simple-bus";
        ranges ;
        gic: interrupt-controller@f8f01000 {
          #interrupt-cells = < 3 >;
          compatible = "arm,cortex-a9-gic";
          interrupt-controller ;
          reg = < 0xf8f01000 0x1000  >,< 0xf8f00100 0x100  >;
        } ;
        pl310: pl310-controller@f8f02000 {
          arm,data-latency = < 3 2 2 >;
          arm,tag-latency = < 2 2 2 >;
          cache-level = < 2 >;
          cache-unified ;
          compatible = "arm,pl310-cache";
          interrupts = < 0 34 4 >;
          reg = < 0xf8f02000 0x1000 >;
        } ;
    
          [ ... more items ... ]
    
        xillybus_0: xillybus@50000000 {
          compatible = "xlnx,xillybus-1.00.a";
          reg = < 0x50000000 0x1000 >;
          interrupts = < 0 59 1 >;
          interrupt-parent = <&gic>;
          xlnx,max-burst-len = <0x10>;
          xlnx,native-data-width = <0x20>;
          xlnx,slv-awidth = <0x20>;
          xlnx,slv-dwidth = <0x20>;
          xlnx,use-wstrb = <0x1>;
        } ;
      } ;
    

    这里只列出原始DTS文件中的两个设备。

    第一个条目:Zynq处理器的中断控制器。这个条目确保中断控制器被加载。注意它的标签是“gic"。这个标签被每个使用中断的设备引用。

    终于可以讲述最有趣的部分了:以上说的这些如何与内核代码配合工作。

    关于内核驱动

    设备驱动加载和卸载时有四件事情会发生:

    • 硬件存在时(比如在设备树中声明),内核代码加载相应驱动
    • 驱动需要了解设备的物理地址
    • 驱动需要了解设备触发的中断号,用来注册中断处理函数。
    • 一些特殊信息需要被获取

    内核中有直接访问设备树的API,但是设备驱动使用专用接口更方便,这些专用接口受PCI/PCIe驱动的API影响。来看下xillybus_0条目,这是一个挂载于AXI总线上的典型逻辑设备。

    标签和节点名

    首先,标签("xillybus")和条目名("xillybus@50000000")。标签可以省略,条目节点名的格式为(some-name@address),最后在/sys下产生一个标准的条目(/sys/devices/axi.0/50000000.xillybus/)。这个设备树的数据位于/proc/device-tree/axi@0/xillybus@50000000/,不过内核肯定不是从这里访问设备树的。

    驱动自动加载

    节点中的第一个赋值语句compatible = “xlnx,xillybus-1.00.a”是最重要的一句:它连接硬件和驱动。当内核在总线上扫描设备时(设备节点在设备树里挂在一个总线节点下),内核检索"compatible"字段,然后将其字符串与一些已知的字符串比较。这个过程会在启动时自动发生两次:

    • 内核启动时,编译进内核的驱动与设备树中某个"compatible"条目匹配
    • 之后加载内核模块时,再触发一次匹配操作

    内核驱动和"compatible"条目的连接由驱动代码中的一小段完成:

    static struct of_device_id xillybus_of_match[] __devinitdata = {
      { .compatible = "xlnx,xillybus-1.00.a", },
      {}
    };
    
    MODULE_DEVICE_TABLE(of, xillybus_of_match);
    

    这段代码使得驱动与某一个"compatible"条目匹配。注意上面的id表中有一个空结构,用这个空意绪标志id表的结束。

    在上段代码之后,一定有类似如下的一段代码:

    static struct platform_driver xillybus_platform_driver = {
      .probe = xilly_drv_probe,
      .remove = xilly_drv_remove,
      .driver = {
        .name = "xillybus",
        .owner = THIS_MODULE,
        .of_match_table = xillybus_of_match,
      },
    };
    

    platform_driver_register(&xillybus_platform_driver)在模块初始化里被调用。这个结构告诉内核,当驱动与某个硬件匹配时,xilly_drv_probe 被调用。

    对内核来说,"compatible"字串需要与某个驱动名相同。”xlnx"前缀用于防止名字冲突。

    另外,一个设备可以有多个"compatible"。因为一个设备可以有多个模块对应多个驱动。

    可能会需要匹配硬件的名字和类型,但这不常用。

    写内核模块时需要特别注意,自动加载机制依赖于/lib/modules/{kernel version}/modules.ofmap文件中的"compatible"字串,其他定义文件也在这个目录下。正确的方式是把*.ko文件复制到/lib/modules/{kernel version}/kernel/drivers/下的相关目录中,然后:

    depmod -a
    
  • 相关阅读:
    Spark在MaxCompute的运行方式
    新功能初探 | MySQL 8.0 Multi-Valued Indexes功能简述
    吐血整理 | 1000行MySQL学习笔记,不怕你不会,就怕你不学!
    阿里巴巴架构师:十问业务中台和我的答案
    C# int?
    页面后退清空缓存
    oracle 中 创建序列sequence
    sql 与 oracle 几个简单语法差别
    oracle 中用法dual
    将DataTable进行分页并生成新的DataTable
  • 原文地址:https://www.cnblogs.com/sammei/p/3978655.html
Copyright © 2011-2022 走看看