设备树()
转载:https://www.cnblogs.com/xiaojiang1025/p/6131381.html
https://www.cnblogs.com/targethero/tag/设备树/
https://www.cnblogs.com/kevinhwang/p/5667044.html
Linux设备树语法详解
概念
Linux内核从3.x开始引入设备树的概念,用于实现驱动代码与设备信息相分离。在设备树出现以前,所有关于设备的具体信息都要写在驱动里,一旦外围设备变化,驱动代码就要重写。引入了设备树之后,驱动代码只负责处理驱动的逻辑,而关于设备的具体信息存放到设备树文件中,这样,如果只是硬件接口信息的变化而没有驱动逻辑的变化,驱动开发者只需要修改设备树文件信息,不需要改写驱动代码。比如在ARM Linux内,一个.dts(device tree source)文件对应一个ARM的machine,一般放置在内核的"arch/arm/boot/dts/"目录内,比如exynos4412参考板的板级设备树文件就是"arch/arm/boot/dts/exynos4412-origen.dts"。这个文件可以通过$make dtbs
命令编译成二进制的.dtb文件供内核驱动使用。
基于同样的软件分层设计的思想,由于一个SoC可能对应多个machine,如果每个machine的设备树都写成一个完全独立的.dts文件,那么势必相当一些.dts文件有重复的部分,为了解决这个问题,Linux设备树目录把一个SoC公用的部分或者多个machine共同的部分提炼为相应的.dtsi文件。这样每个.dts就只有自己差异的部分,公有的部分只需要"include"相应的.dtsi文件, 这样就是整个设备树的管理更加有序。我这里用`Linux4.8.5源码自带的dm9000网卡为例来分析设备树的使用和移植。这个网卡的设备树节点信息在"Documentation/devicetree/bindings/net/davicom-dm9000.txt"有详细说明,其网卡驱动源码是"drivers/net/ethernet/davicom/dm9000.c"。
设备树框架
设备树用树状结构描述设备信息,它有以下几种特性
- 每个设备树文件都有一个根节点,每个设备都是一个节点。
- 节点间可以嵌套,形成父子关系,这样就可以方便的描述设备间的关系。
- 每个设备的属性都用一组key-value对(键值对)来描述。
- 每个属性的描述用
;
结束
所以,一个设备树的基本框架可以写成下面这个样子,一般来说,/表示板子,它的子节点node1表示SoC上的某个控制器,控制器中的子节点node2表示挂接在这个控制器上的设备(们)。
/{ //根节点
node1{ //node1是节点名,是/的子节点
key=value; //node1的属性
...
node2{ //node2是node1的子节点
key=value; //node2的属性
...
}
} //node1的描述到此为止
node3{
key=value;
...
}
}
节点名
理论个节点名只要是长度不超过31个字符的ASCII字符串即可,此外
Linux内核还约定设备名应写成形如<name>[@<unit_address>]
的形式,其中name就是设备名,最长可以是31个字符长度。unit_address一般是设备地址,用来唯一标识一个节点,下面就是典型节点名的写法
上面的节点名是firmware
,节点路径是/firmware@0203f000
,这点要注意,因为根据节点名查找节点的API的参数是不能有"@xxx"这部分的。
Linux中的设备树还包括几个特殊的节点,比如chosen,chosen节点不描述一个真实设备,而是用于firmware传递一些数据给OS,比如bootloader传递内核启动参数给内核
引用
当我们找一个节点的时候,我们必须书写完整的节点路径,这样当一个节点嵌套比较深的时候就不是很方便,所以,设备树允许我们用下面的形式为节点标注引用(起别名),借以省去冗长的路径。这样就可以实现类似函数调用的效果。编译设备树的时候,相同的节点的不同属性信息都会被合并,相同节点的相同的属性会被重写,使用引用可以避免移植者四处找节点,直接在板级.dts增改即可。
下面的例子中就是直接引用了dtsi中的一个节点,并向其中添加/修改新的属性信息
KEY
在设备树中,键值对是描述属性的方式,比如,Linux驱动中可以通过设备节点中的"compatible"这个属性查找设备节点。
Linux设备树语法中定义了一些具有规范意义的属性,包括:compatible, address, interrupt等,这些信息能够在内核初始化找到节点的时候,自动解析生成相应的设备信息。此外,还有一些Linux内核定义好的,一类设备通用的有默认意义的属性,这些属性一般不能被内核自动解析生成相应的设备信息,但是内核已经编写的相应的解析提取函数,常见的有 "mac_addr","gpio","clock","power"。"regulator" 等等。
compatible
设备节点中对应的节点信息已经被内核构造成struct platform_device。驱动可以通过相应的函数从中提取信息。compatible属性是用来查找节点的方法之一,另外还可以通过节点名或节点路径查找指定节点。dm9000驱动中就是使用下面这个函数通过设备节点中的"compatible"属性提取相应的信息,所以二者的字符串需要严格匹配。
在下面的这个dm9000的例子中,我们在相应的板级dts中找到了这样的代码块:
然后我们取内核源码中找到dm9000的网卡驱动,从中可以发现这个驱动是使用的设备树描述的设备信息(这不废话么,显然用设备树好处多多)。我们可以找到它用来描述设备信息的结构体,可以看出,驱动中用于匹配的结构使用的compatible和设备树中一模一样,否则就可能无法匹配,这里另外的一点是struct of_device_id数组的最后一个成员一定是空,因为相关的操作API会读取这个数组直到遇到一个空。
address
(几乎)所有的设备都需要与CPU的IO口相连,所以其IO端口信息就需要在设备节点节点中说明。常用的属性有
- #address-cells,用来描述子节点"reg"属性的地址表中用来描述首地址的cell的数量,
- #size-cells,用来描述子节点"reg"属性的地址表中用来描述地址长度的cell的数量。
有了这两个属性,子节点中的"reg"就可以描述一块连续的地址区域。下例中,父节点中指定了#address-cells = <2>;#size-cells = <1>,则子节点dev-bootscs0中的reg中的前两个数表示一个地址,即MBUS_ID(0xf0, 0x01)和0x1045C,最后一个数的表示地址跨度,即是0x4
interrupts
一个计算机系统中大量设备都是通过中断请求CPU服务的,所以设备节点中就需要在指定中断号。常用的属性有
- interrupt-controller 一个空属性用来声明这个node接收中断信号,即这个node是一个中断控制器。
- #interrupt-cells,是中断控制器节点的属性,用来标识这个控制器需要几个单位做中断描述符,用来描述子节点中"interrupts"属性使用了父节点中的interrupts属性的具体的哪个值。一般,如果父节点的该属性的值是3,则子节点的interrupts一个cell的三个32bits整数值分别为:<中断域 中断 触发方式>,如果父节点的该属性是2,则是<中断 触发方式>
- interrupt-parent,标识此设备节点属于哪一个中断控制器,如果没有设置这个属性,会自动依附父节点的
- interrupts,一个中断标识符列表,表示每一个中断输出信号
设备树中中断的部分涉及的部分比较多,interrupt-controller表示这个节点是一个中断控制器,需要注意的是,一个SoC中可能有不止一个中断控制器,这就会涉及到设备树中断组织的很多概念,下面是在文件"arch/arm/boot/dts/exynos4.dtsi"中对exynos4412的中断控制器(GIC)节点描述:
要说interrupt-parent,就得首先讲讲Linux设备管理中对中断的设计思路演变。随着linux kernel的发展,在内核中将interrupt controller抽象成irqchip这个概念越来越流行,甚至GPIO controller也可以被看出一个interrupt controller chip,这样,系统中至少有两个中断控制器了,另外,在硬件上,随着系统复杂度加大,外设中断数据增加,实际上系统可以需要多个中断控制器进行级联,形成事实上的硬件中断处理结构:
在这种趋势下,内核中原本的中断源直接到中断号的方式已经很难继续发展了,为了解决这些问题,linux kernel的大牛们就创造了irq domain(中断域)这个概念。domain在内核中有很多,除了irqdomain,还有power domain,clock domain等等,所谓domain,就是领域,范围的意思,也就是说,任何的定义出了这个范围就没有意义了。如上所述,系统中所有的interrupt controller会形成树状结构,对于每个interrupt controller都可以连接若干个外设的中断请求(interrupt source,中断源),interrupt controller会对连接其上的interrupt source(根据其在Interrupt controller中物理特性)进行编号(也就是HW interrupt ID了)。有了irq domain这个概念之后,这个编号仅仅限制在本interrupt controller范围内,有了这样的设计,CPU(Linux 内核)就可以根据级联的规则一级一级的找到想要访问的中断。当然,通常我们关心的只是内核中的中断号,具体这个中断号是怎么找到相应的中断源的,我们作为程序员往往不需要关心,除了在写设备树的时候,设备树就是要描述嵌入式软件开发中涉及的所有硬件信息,所以,设备树就需要准确的描述硬件上处理中断的这种树状结构,如此,就有了我们的interrupt-parant这样的概念:用来连接这样的树状结构的上下级,用于表示这个中断归属于哪个interrupt controller,比如,一个接在GPIO上的按键,它的组织形式就是:
中断源--interrupt parent-->GPIO--interrupt parent-->GIC1--interrupt parent-->GIC2--...-->CPU
有了parant,我们就可以使用一级一级的偏移量来最终获得当前中断的绝对编号,这里,可以看出,在我板子上的dm9000的的设备节点中,它的"interrupt-parent"引用了"exynos4x12-pinctrl.dtsi"(被板级设备树的exynos4412.dtsi包含)中的gpx0节点:
而在gpx0节点中,指定了"#interrupt-cells = <2>;",所以在dm9000中的属性"interrupts = <6 4>;"表示dm9000的的中断在作为irq parant的gpx0中的中断偏移量,即gpx0中的属性"interrupts"中的"<0 22 0>",通过查阅exynos4412的手册知道,对应的中断号是EINT[6]。
gpio
gpio也是最常见的IO口,常用的属性有
- "gpio-controller",用来说明该节点描述的是一个gpio控制器
- "#gpio-cells",用来描述gpio使用节点的属性一个cell的内容,即 `属性 = <&引用GPIO节点别名 GPIO标号 工作模式>
GPIO的设置同样采用了上述偏移量的思想,比如下面的这个led的设备书,表示使用GPX2组的第7个引脚:
驱动自定义key
针对具体的设备,有部分属性很难做到通用,需要驱动自己定义好,通过内核的属性提取解析函数进行值的获取,比如dm9000节点中的下面这句就是自定义的节点属性,用以表示配置EEPROM不可用。
VALUE
dts描述一个键的值有多种方式,当然,一个键也可以没有值
字符串信息
32bit无符号整型数组信息
二进制数数组
字符串哈希表
混合形式
上述几种的混合形式
设备树/驱动移植实例
设备树就是为驱动服务的,配置好设备树之后还需要配置相应的驱动才能检测配置是否正确。比如dm9000网卡,就需要首先将示例信息挂接到我们的板级设备树上,并根据芯片手册和电路原理图将相应的属性进行配置,再配置相应的驱动。需要注意的是,dm9000的地址线一般是接在片选线上的,所以设备树中就应该归属与相应片选线节点,我这里用的exynos4412,接在了bank1,所以是"<0x50000000 0x2 0x50000004 0x2>"
最终的配置结果是:
勾选相应的选项将dm9000的驱动编译进内核。
make menuconfig
[*] Networking support --->
Networking options --->
<*> Packet socket
<*>Unix domain sockets
[*] TCP/IP networking
[*] IP: kernel level autoconfiguration
Device Drivers --->
[*] Network device support --->
[*] Ethernet driver support (NEW) --->
<*> DM9000 support
File systems --->
[*] Network File Systems (NEW) --->
<*> NFS client support
[*] NFS client support for NFS version 3
[*] NFS client support for the NFSv3 ACL protocol extension
[*] Root file system on NFS
执行make uImage;make dtbs
,tftp下载,成功加载nfs根文件系统并进入系统,表示网卡移植成功
<body><div id="MathJax_Message" style="display: none;"></div><a name="top"></a>
<div id="home"><div id="header"><div id="blogTitle"><!--done--><div class="title"><a id="Header1_HeaderTitle" class="headermaintitle" href="https://www.cnblogs.com/xiaojiang1025/">ONE_Tech</a></div><div class="subtitle">Next Mile is My Destination</div>
</div><!--end: blogTitle 博客的标题和副标题 --><div id="navigator"><ul id="navList"><li id="nav_sitehome"></li><li id="nav_myhome"><a id="blog_nav_myhome" class="menu" href="https://www.cnblogs.com/xiaojiang1025/">首页</a></li><li id="nav_newpost"></li><li id="nav_contact"></li><li id="nav_rss"><!----></li><li id="nav_admin"><a id="blog_nav_admin" class="menu" rel="nofollow" href="https://i.cnblogs.com/">管理</a></li></ul>
<div class="blogStats"><div id="blog_stats"><!--done-->随笔-146 文章-0 评论-40 </div></div><!--end: blogStats --></div><!--end: navigator 博客导航栏 --></div><!--end: header 头部 --><div id="main"><div id="mainContent"><div class="forFlow"> <div id="post_detail"><!--done--><div id="topics"><div class="post"><h1 class="postTitle"><a id="cb_post_title_url" class="postTitle2" href="https://www.cnblogs.com/xiaojiang1025/p/6131381.html">Linux设备树语法详解</a></h1><div class="clear"></div><div class="postBody"><div id="cnblogs_post_body" class="blogpost-body cnblogs-markdown"><h2 id="概念">概念</h2><p>Linux内核从3.x开始引入设备树的概念,用于实现<u><strong>驱动代码与设备信息相分离</strong></u>。在设备树出现以前,所有关于设备的具体信息都要写在驱动里,一旦外围设备变化,驱动代码就要重写。引入了设备树之后,驱动代码只负责处理驱动的逻辑,而关于设备的具体信息存放到设备树文件中,这样,如果只是硬件接口信息的变化而没有驱动逻辑的变化,驱动开发者只需要修改设备树文件信息,不需要改写驱动代码。比如在ARM Linux内,一个<strong>.dts(device tree source)文件</strong>对应一个ARM的machine,一般放置在内核的<strong>"arch/arm/boot/dts/"</strong>目录内,比如exynos4412参考板的板级设备树文件就是<strong>"arch/arm/boot/dts/exynos4412-origen.dts"</strong>。这个文件可以通过<strong><code>$make dtbs</code>命令</strong>编译成二进制的<strong>.dtb文件</strong>供内核驱动使用。</p><p>基于同样的软件分层设计的思想,由于一个SoC可能对应多个machine,如果每个machine的设备树都写成一个完全独立的<strong>.dts文件</strong>,那么势必相当一些<strong>.dts</strong>文件有重复的部分,为了解决这个问题,Linux设备树目录把一个SoC公用的部分或者多个machine共同的部分提炼为相应的<strong>.dtsi文件</strong>。这样每个<strong>.dts</strong>就只有自己差异的部分,公有的部分只需要<strong>"include"相应的.dtsi文件</strong>, 这样就是整个设备树的管理更加有序。我这里用`Linux4.8.5源码自带的dm9000网卡为例来分析设备树的使用和移植。这个网卡的设备树节点信息在<strong>"Documentation/devicetree/bindings/net/davicom-dm9000.txt"</strong>有详细说明,其网卡驱动源码是<strong>"drivers/net/ethernet/davicom/dm9000.c"</strong>。</p><p><img src="https://images2015.cnblogs.com/blog/1022162/201612/1022162-20161228081245382-984713653.png"></p><h2 id="设备树框架">设备树框架</h2><p>设备树用树状结构描述设备信息,它有以下几种特性</p><ol><li>每个设备树文件都有一个根节点,每个设备都是一个节点。</li><li>节点间可以嵌套,形成父子关系,这样就可以方便的描述设备间的关系。</li><li>每个设备的属性都用一组key-value对(键值对)来描述。</li><li>每个属性的描述用<code>;</code>结束</li></ol><p>所以,一个设备树的基本框架可以写成下面这个样子,<strong>一般来说,/表示板子,它的子节点node1表示SoC上的某个控制器,控制器中的子节点node2表示挂接在这个控制器上的设备(们)</strong>。</p><pre><code class="hljs cs">/{ <span class="hljs-comment">//根节点</span> node1{ <span class="hljs-comment">//node1是节点名,是/的子节点</span> key=<span class="hljs-keyword">value</span>; <span class="hljs-comment">//node1的属性</span> ... node2{ <span class="hljs-comment">//node2是node1的子节点</span> key=<span class="hljs-keyword">value</span>; <span class="hljs-comment">//node2的属性</span> ... } } <span class="hljs-comment">//node1的描述到此为止</span> node3{ key=<span class="hljs-keyword">value</span>; ... }}</code></pre><h3 id="节点名">节点名</h3><p>理论个节点名只要是长度不超过31个字符的ASCII字符串即可,此外<br>Linux内核还约定设备名应写成形如<code><name>[@<unit_address>]</code>的形式,其中name就是设备名,最长可以是31个字符长度。unit_address一般是设备地址,用来唯一标识一个节点,下面就是典型节点名的写法</p><p><img src="https://images2015.cnblogs.com/blog/1022162/201612/1022162-20161228082232961-1663351901.png"></p><p>上面的节点名是<code>firmware</code>,节点路径是<code>/firmware@0203f000</code>,这点要注意,因为根据节点名查找节点的API的参数是不能有"@xxx"这部分的。</p><p>Linux中的设备树还包括几个特殊的节点,比如chosen,chosen节点不描述一个真实设备,而是用于firmware传递一些数据给OS,比如bootloader传递内核启动参数给内核</p><p><img src="https://images2015.cnblogs.com/blog/1022162/201612/1022162-20161228082239867-508348995.png"></p><h3 id="引用">引用</h3><p>当我们找一个节点的时候,我们必须书写<strong>完整的节点路径</strong>,这样当一个节点嵌套比较深的时候就不是很方便,所以,设备树允许我们用下面的形式为节点标注引用(起别名),借以省去冗长的路径。这样就可以实现类似函数调用的效果。编译设备树的时候,<strong><u>相同的节点的不同属性信息都会被合并,相同节点的相同的属性会被重写</u></strong>,使用引用可以避免移植者四处找节点,直接在板级.dts增改即可。<br><img src="https://images2015.cnblogs.com/blog/1022162/201612/1022162-20161228082650836-1587041920.png"></p><p>下面的例子中就是直接引用了dtsi中的一个节点,并向其中添加/修改新的属性信息<br><img src="https://images2015.cnblogs.com/blog/1022162/201612/1022162-20161228082913961-1212901788.png"></p><h2 id="key">KEY</h2><p>在设备树中,<strong>键值对</strong>是描述属性的方式,比如,Linux驱动中可以通过设备节点中的<strong>"compatible"</strong>这个属性查找设备节点。<br>Linux设备树语法中定义了一些具有规范意义的属性,包括:<strong>compatible</strong>, <strong>address</strong>, <strong>interrupt</strong>等,这些信息能够在内核初始化找到节点的时候,自动解析生成相应的设备信息。此外,还有一些Linux内核定义好的,一类设备通用的有默认意义的属性,这些属性一般不能被内核自动解析生成相应的设备信息,但是内核已经编写的相应的解析提取函数,常见的有 <strong>"mac_addr"</strong>,<strong>"gpio"</strong>,<strong>"clock"</strong>,<strong>"power"</strong>。<strong>"regulator"</strong> 等等。</p><h3 id="compatible">compatible</h3><p>设备节点中对应的节点信息已经被内核构造成<strong>struct platform_device</strong>。驱动可以通过相应的函数从中提取信息。<u>compatible属性是用来查找节点的方法之一,另外还可以通过节点名或节点路径查找指定节点</u>。dm9000驱动中就是使用下面这个函数通过设备节点中的<strong>"compatible"</strong>属性提取相应的信息,所以二者的字符串需要严格匹配。<br>在下面的这个dm9000的例子中,我们在相应的板级dts中找到了这样的代码块:<br><img src="https://images2015.cnblogs.com/blog/1022162/201612/1022162-20161228083547867-895420019.png"><br>然后我们取内核源码中找到dm9000的网卡驱动,从中可以发现这个驱动是使用的设备树描述的设备信息(这不废话么,显然用设备树好处多多)。我们可以找到它用来描述设备信息的结构体,可以看出,驱动中用于匹配的结构使用的<strong>compatible</strong>和设备树中一模一样,否则就可能无法匹配,这里另外的一点是<strong>struct of_device_id</strong>数组的最后一个成员一定是空,因为相关的操作API会读取这个数组直到遇到一个<strong>空</strong>。</p><p><img src="https://images2015.cnblogs.com/blog/1022162/201612/1022162-20161228083741070-1366149989.png"></p><h3 id="address">address</h3><p>(几乎)所有的设备都需要与CPU的IO口相连,所以其IO端口信息就需要在设备节点节点中说明。常用的属性有</p><ul><li><strong>#address-cells</strong>,用来描述<u>子节点<strong>"reg"</strong>属性的地址表中用来描述<u>首地址</u>的cell的数量</u>,</li><li><strong>#size-cells</strong>,用来描述<u>子节点<strong>"reg"</strong>属性的地址表中用来描述<u>地址长度</u>的cell的数量</u>。</li></ul><p>有了这两个属性,子节点中的<strong>"reg"</strong>就可以描述一块连续的地址区域。下例中,父节点中指定了<strong>#address-cells = <2>;#size-cells = <1></strong>,则子节点dev-bootscs0中的<strong>reg</strong>中的前两个数表示一个地址,即<strong>MBUS_ID(0xf0, 0x01)</strong>和<strong>0x1045C</strong>,最后一个数的表示地址跨度,即是<strong>0x4</strong></p><p><img src="https://images2015.cnblogs.com/blog/1022162/201612/1022162-20161228085036070-1357074559.png"></p><h3 id="interrupts">interrupts</h3><p>一个计算机系统中大量设备都是通过中断请求CPU服务的,所以设备节点中就需要在指定中断号。常用的属性有</p><ul><li><strong>interrupt-controller</strong> 一个空属性用来声明这个node接收中断信号,即这个node是一个中断控制器。</li><li><strong>#interrupt-cells</strong>,是中断控制器节点的属性,用来标识这个控制器需要几个单位做中断描述符,用来描述<u>子节点中<strong>"interrupts"</strong>属性使用了父节点中的<strong>interrupts</strong>属性的具体的哪个值</u>。一般,如果父节点的该属性的值是3,则子节点的interrupts一个cell的三个32bits整数值分别为:<中断域 中断 触发方式>,如果父节点的该属性是2,则是<中断 触发方式></li><li><strong>interrupt-parent</strong>,标识此设备节点属于哪一个中断控制器,如果没有设置这个属性,会自动依附父节点的</li><li><strong>interrupts</strong>,一个中断标识符列表,表示每一个中断输出信号</li></ul><p>设备树中中断的部分涉及的部分比较多,<strong>interrupt-controller</strong>表示这个节点是一个中断控制器,需要注意的是,一个SoC中可能有不止一个中断控制器,这就会涉及到设备树中断组织的很多概念,下面是在文件<strong>"arch/arm/boot/dts/exynos4.dtsi"</strong>中对exynos4412的中断控制器(GIC)节点描述:</p><p><img src="https://images2015.cnblogs.com/blog/1022162/201612/1022162-20161228121924539-418336592.png"></p><p>要说<strong>interrupt-parent</strong>,就得首先讲讲Linux设备管理中对中断的设计思路演变。随着linux kernel的发展,在内核中将interrupt controller抽象成<strong>irqchip</strong>这个概念越来越流行,甚至GPIO controller也可以被看出一个interrupt controller chip,这样,系统中至少有两个中断控制器了,另外,在硬件上,随着系统复杂度加大,外设中断数据增加,实际上系统可以需要多个中断控制器进行级联,形成事实上的硬件中断处理结构:</p><blockquote><p><img src="https://images2015.cnblogs.com/blog/1022162/201612/1022162-20161228121829367-918107508.png"></p></blockquote><p>在这种趋势下,内核中原本的中断源直接到中断号的方式已经很难继续发展了,为了解决这些问题,linux kernel的大牛们就创造了<strong>irq domain</strong>(中断域)这个概念。domain在内核中有很多,除了irqdomain,还有power domain,clock domain等等,所谓domain,就是领域,范围的意思,也就是说,任何的定义出了这个范围就没有意义了。如上所述,系统中所有的interrupt controller会形成树状结构,对于每个interrupt controller都可以连接若干个外设的中断请求(interrupt source,中断源),interrupt controller会对连接其上的interrupt source(根据其在Interrupt controller中物理特性)进行编号(也就是HW interrupt ID了)。<u>有了<strong>irq domain</strong>这个概念之后,这个编号仅仅限制在本interrupt controller范围内</u>,有了这样的设计,CPU(Linux 内核)就可以根据级联的规则一级一级的找到想要访问的中断。当然,通常我们关心的只是内核中的中断号,具体这个中断号是怎么找到相应的中断源的,我们作为程序员往往不需要关心,除了在写设备树的时候,设备树就是要描述嵌入式软件开发中涉及的所有硬件信息,所以,设备树就需要准确的描述硬件上处理中断的这种树状结构,如此,就有了我们的<strong>interrupt-parant</strong>这样的概念:用来连接这样的树状结构的上下级,用于表示这个中断归属于哪个interrupt controller,比如,一个接在GPIO上的按键,它的组织形式就是:</p><blockquote><p><strong>中断源</strong>--interrupt parent--><strong>GPIO</strong>--interrupt parent--><strong>GIC1</strong>--interrupt parent--><strong>GIC2</strong>--...--><strong>CPU</strong></p></blockquote><p>有了parant,我们就可以使用一级一级的<strong><u>偏移量</u></strong>来最终获得当前中断的绝对编号,这里,可以看出,在我板子上的dm9000的的设备节点中,它的<strong>"interrupt-parent"</strong>引用了<strong>"exynos4x12-pinctrl.dtsi"</strong>(被板级设备树的exynos4412.dtsi包含)中的gpx0节点:<br><img src="https://images2015.cnblogs.com/blog/1022162/201612/1022162-20161228104528976-1416799927.png"></p><p>而在gpx0节点中,指定了<strong>"#interrupt-cells = <2>;"</strong>,所以在dm9000中的属性<strong>"interrupts = <6 4>;"</strong>表示dm9000的的中断在作为irq parant的gpx0中的中断偏移量,即gpx0中的属性<strong>"interrupts"</strong>中的<strong>"<0 22 0>"</strong>,通过查阅exynos4412的手册知道,对应的中断号是EINT[6]。<br><img src="https://images2015.cnblogs.com/blog/1022162/201612/1022162-20161228104855117-961033999.png"></p><h3 id="gpio">gpio</h3><p>gpio也是最常见的IO口,常用的属性有</p><ul><li><strong>"gpio-controller"</strong>,用来说明该节点描述的是一个gpio控制器</li><li><strong>"#gpio-cells"</strong>,用来描述gpio使用节点的属性一个cell的内容,即 `属性 = <&引用GPIO节点别名 GPIO标号 工作模式></li></ul><p>GPIO的设置同样采用了上述<strong>偏移量</strong>的思想,比如下面的这个led的设备书,表示使用GPX2组的第7个引脚:<br><img src="https://images2015.cnblogs.com/blog/1022162/201612/1022162-20161228112857507-88695790.png"></p><h3 id="驱动自定义key">驱动自定义key</h3><p>针对具体的设备,有部分属性很难做到通用,需要驱动自己定义好,通过内核的属性提取解析函数进行值的获取,比如dm9000节点中的下面这句就是自定义的节点属性,用以表示配置EEPROM不可用。<br><img src="https://images2015.cnblogs.com/blog/1022162/201612/1022162-20161228113216211-1268631986.png"></p><h2 id="value"><strong>VALUE</strong></h2><p>dts描述一个键的值有多种方式,当然,一个键也可以没有值</p><h3 id="字符串信息">字符串信息</h3><p><img src="https://images2015.cnblogs.com/blog/1022162/201612/1022162-20161228113540382-882089.png"></p><h3 id="bit无符号整型数组信息">32bit无符号整型数组信息</h3><p><img src="https://images2015.cnblogs.com/blog/1022162/201612/1022162-20161228114624461-930044348.png"></p><h3 id="二进制数数组">二进制数数组</h3><p><img src="https://images2015.cnblogs.com/blog/1022162/201612/1022162-20161228114631195-225846067.png"></p><h3 id="字符串哈希表">字符串哈希表</h3><p><img src="https://images2015.cnblogs.com/blog/1022162/201612/1022162-20161228114203070-1518348205.png"></p><h3 id="混合形式">混合形式</h3><p>上述几种的混合形式</p><h2 id="设备树驱动移植实例">设备树/驱动移植实例</h2><p>设备树就是为驱动服务的,配置好设备树之后还需要配置相应的驱动才能检测配置是否正确。比如dm9000网卡,就需要首先将示例信息挂接到我们的板级设备树上,并根据芯片手册和电路原理图将相应的属性进行配置,再配置相应的驱动。需要注意的是,dm9000的地址线一般是接在片选线上的,所以设备树中就应该归属与相应片选线节点,我这里用的exynos4412,接在了bank1,所以是<strong>"<0x50000000 0x2 0x50000004 0x2>"</strong><br>最终的配置结果是:</p><p><img src="https://images2015.cnblogs.com/blog/1022162/201612/1022162-20161228114312961-683127554.png"></p><p>勾选相应的选项将dm9000的驱动编译进内核。</p><pre><code class="hljs vhdl">make menuconfig[*] Networking support <span class="hljs-comment">---></span> Networking options <span class="hljs-comment">---></span> <*> Packet socket <*>Unix domain sockets [*] TCP/IP networking [*] IP: kernel level autoconfigurationDevice Drivers <span class="hljs-comment">---></span> [*] Network device support <span class="hljs-comment">---></span> [*] Ethernet driver support (<span class="hljs-keyword">NEW</span>) <span class="hljs-comment">---></span> <*> DM9000 support<span class="hljs-keyword">File</span> systems <span class="hljs-comment">---></span> [*] Network <span class="hljs-keyword">File</span> Systems (<span class="hljs-keyword">NEW</span>) <span class="hljs-comment">---></span> <*> NFS client support [*] NFS client support <span class="hljs-keyword">for</span> NFS version <span class="hljs-number">3</span> [*] NFS client support <span class="hljs-keyword">for</span> the NFSv3 ACL protocol extension [*] Root <span class="hljs-keyword">file</span> system <span class="hljs-keyword">on</span> NFS</code></pre><p>执行<code>make uImage;make dtbs</code>,tftp下载,成功加载nfs根文件系统并进入系统,表示网卡移植成功<br><img src="https://images2015.cnblogs.com/blog/1022162/201612/1022162-20161204194015709-1927320659.png"></p></div><div id="MySignature"></div><div class="clear"></div><div id="blog_post_info_block"><div id="BlogPostCategory">分类: <a href="https://www.cnblogs.com/xiaojiang1025/category/918665.html" target="_blank">Linux驱动开发</a></div><div id="EntryTag">标签: <a href="https://www.cnblogs.com/xiaojiang1025/tag/Linux%E8%AE%BE%E5%A4%87%E6%A0%91%E8%AF%AD%E6%B3%95%E8%AF%A6%E8%A7%A3/">Linux设备树语法详解</a></div><div id="blog_post_info"><div id="green_channel"> <a href="javascript:void(0);" id="green_channel_digg" onclick="DiggIt(6131381,cb_blogId,1);green_channel_success(this,'谢谢推荐!');">好文要顶</a> <a id="green_channel_follow" onclick="follow('052846a7-4674-e611-9fc1-ac853d9f53cc');" href="javascript:void(0);">关注我</a> <a id="green_channel_favorite" onclick="AddToWz(cb_entryId);return false;" href="javascript:void(0);">收藏该文</a> <a id="green_channel_weibo" href="javascript:void(0);" title="分享至新浪微博" onclick="ShareToTsina()"><img src="//common.cnblogs.com/images/icon_weibo_24.png" alt=""></a> <a id="green_channel_wechat" href="javascript:void(0);" title="分享至微信" onclick="shareOnWechat()"><img src="//common.cnblogs.com/images/wechat.png" alt=""></a></div><div id="author_profile"> <div id="author_profile_info" class="author_profile_info"> <a href="http://home.cnblogs.com/u/xiaojiang1025/" target="_blank"><img src="//pic.cnblogs.com/face/1022162/20161215125946.png" class="author_avatar" alt=""></a> <div id="author_profile_detail" class="author_profile_info"> <a href="http://home.cnblogs.com/u/xiaojiang1025/">Abnor</a><br> <a href="http://home.cnblogs.com/u/xiaojiang1025/followees">关注 - 0</a><br> <a href="http://home.cnblogs.com/u/xiaojiang1025/followers">粉丝 - 153</a> </div> </div> <div class="clear"></div> <div id="author_profile_honor"></div> <div id="author_profile_follow"> <a href="javascript:void(0);" onclick="follow('052846a7-4674-e611-9fc1-ac853d9f53cc');return false;">+加关注</a> </div></div><div id="div_digg"> <div class="diggit" onclick="votePost(6131381,'Digg')"> <span class="diggnum" id="digg_count">5</span> </div> <div class="buryit" onclick="votePost(6131381,'Bury')"> <span class="burynum" id="bury_count">0</span> </div> <div class="clear"></div> <div class="diggword" id="digg_tips" style="color: red;">推荐成功</div></div><script type="text/javascript"> currentDiggType = 0;</script></div><div class="clear"></div><div id="post_next_prev"><a href="https://www.cnblogs.com/xiaojiang1025/p/6131131.html" class="p_n_p_prefix">« </a> 上一篇:<a href="https://www.cnblogs.com/xiaojiang1025/p/6131131.html" title="发布于2016-12-04 18:18">Linux源码Kconfig文件语法分析</a><br><a href="https://www.cnblogs.com/xiaojiang1025/p/6142548.html" class="p_n_p_prefix">» </a> 下一篇:<a href="https://www.cnblogs.com/xiaojiang1025/p/6142548.html" title="发布于2016-12-13 21:15">Linux模块编程框架</a><br></div></div>
</div><div class="postDesc">posted @ <span id="post-date">2016-12-06 11:40</span> <a href="https://www.cnblogs.com/xiaojiang1025/">Abnor</a> 阅读(<span id="post_view_count">30027</span>) 评论(<span id="post_comment_count">1</span>) <a href="https://i.cnblogs.com/EditPosts.aspx?postid=6131381" rel="nofollow">编辑</a> <a href="#" onclick="AddToWz(6131381);return false;">收藏</a></div></div><script src="//common.cnblogs.com/highlight/9.12.0/highlight.min.js"></script><script>markdown_highlight();</script><script type="text/javascript">var allowComments=false,cb_blogId=304099,cb_entryId=6131381,cb_blogApp=currentBlogApp,cb_blogUserGuid='052846a7-4674-e611-9fc1-ac853d9f53cc',cb_entryCreatedDate='2016/12/6 11:40:00';loadViewCount(cb_entryId);var cb_postType=1;var isMarkdown=true;</script></div><!--end: topics 文章、评论容器--></div><a name="!comments"></a><div id="blog-comments-placeholder"><div id="comments_pager_top"></div><!--done--><div class="feedback_area_title">评论列表</div><div class="feedbackNoItems"></div>
<div class="feedbackItem"><div class="feedbackListSubtitle"><div class="feedbackManage"> <span class="comment_actions"><a href="javascript:void(0);" onclick="return ReplyComment(3573444,'T6aD1Vc2atESnFRipRoQr3CfeP+N69Os6vSHqkjePwOvqQ924Oe+og==')">回复</a><a href="javascript:void(0);" onclick="return QuoteComment(3573444,'T6aD1Vc2atESnFRipRoQr3CfeP+N69Os6vSHqkjePwOvqQ924Oe+og==')">引用</a></span></div><a href="#3573444" class="layer">#1楼</a><a name="3573444" id="comment_anchor_3573444"></a><span id="comment-maxId" style="display:none;">3573444</span><span id="comment-maxDate" style="display:none;">2016/12/6 11:46:07</span> <span class="comment_date">2016-12-06 11:46</span> <a id="a_comment_author_3573444" href="https://www.cnblogs.com/CallMeUncle/" target="_blank">IT胡小帅</a> <a href="http://msg.cnblogs.com/send/IT%E8%83%A1%E5%B0%8F%E5%B8%85" title="发送站内短消息" class="sendMsg2This"> </a></div><div class="feedbackCon"><div id="comment_body_3573444" class="blog_comment_body">谢谢分享</div><div class="comment_vote"><a href="javascript:void(0);" class="comment_digg" onclick="return voteComment(3573444,'Digg',this)">支持(1)</a><a href="javascript:void(0);" class="comment_bury" onclick="return voteComment(3573444,'Bury',this)">反对(0)</a></div><span id="comment_3573444_avatar" style="display:none;">http://pic.cnblogs.com/face/534745/20140402152409.png</span></div></div><div id="comments_pager_bottom"></div></div><script type="text/javascript">var commentManager = new blogCommentManager();commentManager.renderComments(0);</script><div id="comment_form" class="commentform"><a name="commentform"></a><div id="divCommentShow"></div><div id="comment_nav"><span id="span_refresh_tips"></span><a href="javascript:void(0);" onclick="return RefreshCommentList();" id="lnk_RefreshComments" runat="server" clientidmode="Static">刷新评论</a><a href="#" onclick="return RefreshPage();">刷新页面</a><a href="#top">返回顶部</a></div><div id="comment_form_container">(评论功能已被禁用)</div><div class="ad_text_commentbox" id="ad_text_under_commentbox"></div><div id="ad_t2"><a href="http://www.ucancode.com/index.htm" target="_blank" onclick="ga('send', 'event', 'Link', 'click', 'T2-工控')">【推荐】超50万C++/C#源码: 大型实时仿真组态图形源码</a><br><a href="https://cloud.baidu.com/campaign/purchase-2019/index.html?track=cp:dsp|pf:pc|pp:chui-bokeyuan-huodong-19caigouji-BCC-neiyeCH-190410|pu:neiyeCH-wenzilian|ci:2019cgj|kw:2112847" target="_blank" onclick="ga('send', 'event', 'Link', 'click', 'T2-百度云')">【推荐】百度智能云品牌升级,云服务器福利低至0.5折</a><br><a href="https://gitee.com/enterprises?from=bky-2" target="_blank" onclick="ga('send', 'event', 'Link', 'click', 'T2-gitee')">【推荐】专业便捷的企业级代码托管服务 - Gitee 码云</a><br><a href="https://www.bagevent.com/event/2468856" target="_blank" onclick="ga('send', 'event', 'Link', 'click', 'T2-GAITC')">【活动】2019第四届全球人工技术大会解码“智能+时代”</a><br></div><div id="opt_under_post"></div><script async="async" src="https://www.googletagservices.com/tag/js/gpt.js"></script><script> var googletag = googletag || {}; googletag.cmd = googletag.cmd || [];</script><script> googletag.cmd.push(function() { googletag.defineSlot('/1090369/C1', [300, 250], 'div-gpt-ad-1546353474406-0').addService(googletag.pubads()); googletag.defineSlot('/1090369/C2', [468, 60], 'div-gpt-ad-1539008685004-0').addService(googletag.pubads()); googletag.pubads().enableSingleRequest(); googletag.enableServices(); });</script><div id="cnblogs_c1" class="c_ad_block"> <div id="div-gpt-ad-1546353474406-0" style="height:250px; width:300px;" data-google-query-id="CPDip5yLxeECFRWKwgodAlwPlA"><div id="google_ads_iframe_/1090369/C1_0__container__" style="border: 0pt none;"><iframe id="google_ads_iframe_/1090369/C1_0" title="3rd party ad content" name="google_ads_iframe_/1090369/C1_0" width="300" height="250" scrolling="no" marginwidth="0" marginheight="0" frameborder="0" srcdoc="" data-google-container-id="1" style="border: 0px; vertical-align: bottom;" data-load-complete="true"></iframe></div></div></div><div id="under_post_news"><div class="itnews c_ad_block"><b>相关博文:</b><br>· <a href="https://www.cnblogs.com/god-of-death/p/10270425.html" target="_blank" onclick="clickRecomItmem(10270425)">Linux设备树(一概述)</a><br>· <a href="https://www.cnblogs.com/kevinhwang/p/5647021.html" target="_blank" onclick="clickRecomItmem(5647021)">设备树实例(一)</a><br>· <a href="https://www.cnblogs.com/yixin-shenda/p/5486581.html" target="_blank" onclick="clickRecomItmem(5486581)">编写设备树DTS</a><br>· <a href="https://www.cnblogs.com/god-of-death/p/10270528.html" target="_blank" onclick="clickRecomItmem(10270528)">Linux设备树(三属性)</a><br>· <a href="https://www.cnblogs.com/embedded-linux/p/6102375.html" target="_blank" onclick="clickRecomItmem(6102375)">设备树概述</a><br></div></div><div id="cnblogs_c2" class="c_ad_block"> <div id="div-gpt-ad-1539008685004-0" style="height:60px; width:468px;" data-google-query-id="CPHip5yLxeECFRWKwgodAlwPlA"><div id="google_ads_iframe_/1090369/C2_0__container__" style="border: 0pt none;"><iframe id="google_ads_iframe_/1090369/C2_0" title="3rd party ad content" name="google_ads_iframe_/1090369/C2_0" width="468" height="60" scrolling="no" marginwidth="0" marginheight="0" frameborder="0" srcdoc="" data-google-container-id="2" style="border: 0px; vertical-align: bottom;" data-load-complete="true"></iframe></div></div></div><div id="under_post_kb"><div class="itnews c_ad_block"><b>最新新闻</b>:<br> · <a href="https://news.cnblogs.com/n/623583/" target="_blank">联想将推新3S战略 以5G和AI为技术基础</a><br> · <a href="https://news.cnblogs.com/n/623582/" target="_blank">反垄断案高通诉讼被驳回 10亿欧元巨额罚单必须交</a><br> · <a href="https://news.cnblogs.com/n/623581/" target="_blank">华为与中国铁塔完成5G能源方案联合创新测试</a><br> · <a href="https://news.cnblogs.com/n/623580/" target="_blank">美国有“996”吗?有,但是和“ICU”真没什么关系</a><br> · <a href="https://news.cnblogs.com/n/623579/" target="_blank">特斯拉公布Autopilot一季度报告:事故率低于人类驾驶</a><br>» <a href="http://news.cnblogs.com/" title="IT新闻" target="_blank">更多新闻...</a></div></div><div id="HistoryToday" class="c_ad_block"></div><script type="text/javascript"> if(enablePostBottom()) { codeHighlight(); fixPostBody(); setTimeout(function () { incrementViewCount(cb_entryId); }, 50); deliverT2(); deliverC1(); deliverC2(); loadNewsAndKb(); loadBlogSignature(); LoadPostInfoBlock(cb_blogId, cb_entryId, cb_blogApp, cb_blogUserGuid); GetPrevNextPost(cb_entryId, cb_blogId, cb_entryCreatedDate, cb_postType); loadOptUnderPost(); GetHistoryToday(cb_blogId, cb_blogApp, cb_entryCreatedDate); }</script></div>
</div><!--end: forFlow --></div><!--end: mainContent 主体内容容器-->
<div id="sideBar"><div id="sideBarMain"><!--done--><div class="newsItem"><h3 class="catListTitle">公告</h3><div id="blog-news"><div id="profile_block">昵称:<a href="https://home.cnblogs.com/u/xiaojiang1025/">Abnor</a><br>园龄:<a href="https://home.cnblogs.com/u/xiaojiang1025/" title="入园时间:2016-09-06">2年7个月</a><br>粉丝:<a href="https://home.cnblogs.com/u/xiaojiang1025/followers/">153</a><br>关注:<a href="https://home.cnblogs.com/u/xiaojiang1025/followees/">0</a><div id="p_b_follow"><a href="javascript:void(0);" onclick="follow('052846a7-4674-e611-9fc1-ac853d9f53cc')">+加关注</a></div><script>getFollowStatus('052846a7-4674-e611-9fc1-ac853d9f53cc')</script></div></div><script type="text/javascript">loadBlogNews();</script></div>
<div id="calendar"><div id="blog-calendar" style="display:none"></div><script type="text/javascript">loadBlogDefaultCalendar();</script></div><div id="leftcontentcontainer"><div id="blog-sidecolumn"><div id="sidebar_search" class="sidebar-block"><div id="sidebar_search" class="mySearch"><h3 class="catListTitle">搜索</h3><div id="sidebar_search_box"><div id="widget_my_zzk" class="div_my_zzk"><input type="text" id="q" onkeydown="return zzk_go_enter(event);" class="input_my_zzk"> <input onclick="zzk_go()" type="button" value="找找看" id="btnZzk" class="btn_my_zzk"></div>
</div></div>
</div><div id="sidebar_categories"><div class="catListPostCategory"><h3 class="catListTitle">随笔分类<span style="font-size:11px;font-weight:normal">(142)</span></h3>
<ul>
<li><a id="CatList_LinkList_0_Link_0" href="https://www.cnblogs.com/xiaojiang1025/category/881153.html">ARM汇编(6)</a> </li>
<li><a id="CatList_LinkList_0_Link_1" href="https://www.cnblogs.com/xiaojiang1025/category/879023.html">C上一层楼(9)</a> </li>
<li><a id="CatList_LinkList_0_Link_2" href="https://www.cnblogs.com/xiaojiang1025/category/879026.html">Linux环境编程(27)</a> </li>
<li><a id="CatList_LinkList_0_Link_3" href="https://www.cnblogs.com/xiaojiang1025/category/880101.html">Linux命令收集(42)</a> </li>
<li><a id="CatList_LinkList_0_Link_4" href="https://www.cnblogs.com/xiaojiang1025/category/918665.html">Linux驱动开发(35)</a> </li>
<li><a id="CatList_LinkList_0_Link_5" href="https://www.cnblogs.com/xiaojiang1025/category/894003.html">Makefile(6)</a> </li>
<li><a id="CatList_LinkList_0_Link_6" href="https://www.cnblogs.com/xiaojiang1025/category/883987.html">Shell脚本(5)</a> </li>
<li><a id="CatList_LinkList_0_Link_7" href="https://www.cnblogs.com/xiaojiang1025/category/879028.html">Ubuntu Tricks(5)</a> </li>
<li><a id="CatList_LinkList_0_Link_8" href="https://www.cnblogs.com/xiaojiang1025/category/1025415.html">存储VS虚拟化</a> </li>
<li><a id="CatList_LinkList_0_Link_9" href="https://www.cnblogs.com/xiaojiang1025/category/980142.html">设计模式(1)</a> </li>
<li><a id="CatList_LinkList_0_Link_10" href="https://www.cnblogs.com/xiaojiang1025/category/894006.html">算法VS数据结构</a> </li>
<li><a id="CatList_LinkList_0_Link_11" href="https://www.cnblogs.com/xiaojiang1025/category/915091.html">系统移植(6)</a> </li>
</ul>
</div>
</div><div id="sidebar_topviewedposts" class="sidebar-block"><div id="topview_posts_wrap"><div class="catListView"><h3 class="catListTitle">阅读排行榜</h3><div id="TopViewPostsBlock"><ul><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6131381.html">1. Linux设备树语法详解(30023)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/5863984.html">2. shell 脚本关键字&符号(13875)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6500540.html">3. Linux i2c子系统(一) _动手写一个i2c设备驱动(12682)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6106431.html">4. 从0移植uboot (一) _配置分析(9720)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6496704.html">5. 从0移植uboot (二) _uboot启动流程分析(8901)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/5958497.html">6. shell脚本变量(8886)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6193959.html">7. Linux设备管理(一)_kobject, kset,ktype分析(7475)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6500557.html">8. Linux块设备IO子系统(一) _驱动模型(7403)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6367910.html">9. Linux Platform驱动模型(二) _驱动方法(6706)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6181833.html">10. Linux字符设备驱动框架(6579)</a></li></ul></div></div></div></div><div id="sidebar_topcommentedposts" class="sidebar-block"><div id="topfeedback_posts_wrap"><div class="catListFeedback"><h3 class="catListTitle">评论排行榜</h3><div id="TopFeedbackPostsBlock"><ul><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6060604.html">1. Linux tcp黏包解决方案(7)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6193959.html">2. Linux设备管理(一)_kobject, kset,ktype分析(6)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/5950473.html">3. Linux 多线程信号量同步(2)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6500574.html">4. Linux usb子系统(一) _写一个usb鼠标驱动(2)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6413017.html">5. 跟着内核学框架-从misc子系统到3+2+1设备识别驱动框架(2)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6388605.html">6. Linux驱动技术(八) _并发控制技术(2)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6376561.html">7. Linux驱动技术(四) _异步通知技术(2)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6363626.html">8. Linux设备文件三大结构:inode,file,file_operations(2)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6202298.html">9. Linux设备管理(四)_从sysfs回到ktype(1)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6032316.html">10. Linux I/O多路复用(1)</a></li></ul></div></div></div></div><div id="sidebar_topdiggedposts" class="sidebar-block"><div id="topdigg_posts_wrap"><div class="catListView"><h3 class="catListTitle">推荐排行榜</h3><div id="TopDiggPostsBlock"><ul><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6506116.html">1. Linux usb子系统(二) _usb-skeleton.c精析(4)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6500540.html">2. Linux i2c子系统(一) _动手写一个i2c设备驱动(4)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6414746.html">3. Linux input子系统编程、分析与模板(4)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6367910.html">4. Linux Platform驱动模型(二) _驱动方法(4)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6131381.html">5. Linux设备树语法详解(4)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6181833.html">6. Linux字符设备驱动框架(3)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6106431.html">7. 从0移植uboot (一) _配置分析(3)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6367061.html">8. Linux Platform驱动模型(一) _设备信息(3)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6388604.html">9. Linux驱动技术(七) _内核定时器与延迟工作(3)</a></li><li><a href="https://www.cnblogs.com/xiaojiang1025/p/6020822.html">10. Linux 多线程可重入函数(3)</a></li></ul></div></div></div></div></div><script type="text/javascript">loadBlogSideColumn();</script></div></div><!--end: sideBarMain --></div><!--end: sideBar 侧边栏容器 --><div class="clear"></div></div><!--end: main --><div class="clear"></div><div id="footer"><!--done-->Copyright ©2019 Abnor</div><!--end: footer --></div><!--end: home 自定义的最大容器 -->
</body>