jen_yimu 发表于 2011-12-23 02:09

linux设备驱动之总线、设备、驱动

<p><span style="font-size:13px">文章转载至多个地方,网上拼凑的一篇文章,说的好听一些的话那就叫自己总结的文章,只
是多次引用啊,哈哈,哎,不管了,反正这个有利用学习进步就好,这是重要的,文章转载过来要经过一篇大脑才能成为自己的,以后千万要注意这点,不要把大好
的文章转载放在博客里面不管了,等到那一天遇到同样的问题了上网一搜搜到自己博客里面来了,嘿嘿。转入正题,linux设备驱动的总线,设备和驱动。</span></p>
<p><span style="font-size:13px">linux设备驱动的难点在于复杂的,庞大的结构。理清楚结构和一个结构与另外结构的关系,以及linux设备驱动的层次性和层次封装抽象性。对于linux设备驱动的结构有点像C++中的类,而层次与抽象有点像继承的关系。</span></p>
<p><span style="font-size:13px">一、总线、设备、驱动的主要三个结构关系</span></p>
<p><span style="font-size:13px; color:#000000"><span style="color:#800000"><strong>struct<a href="http://hi.baidu.com/zengzhaonong/blog/item/b64f24c792ce21ded0006012.html" target="_blank" target="_blank">bus_type&nbsp;
</a></strong></span><br>
---------------------------------<br>
&nbsp;&nbsp;&nbsp; struct bus_type中为devices和drivers准备了两个链表:<br>
&nbsp;&nbsp;&nbsp; struct klist klist_devices<br>
&nbsp;&nbsp;&nbsp; struct klist klist_drivers<br>
<br>
<span style="color:#800000"><strong>struct <a href="http://hi.baidu.com/zengzhaonong/blog/item/097c0117c46360034b90a701.html" target="_blank" target="_blank">
device</a></strong></span><br>
---------------------------------<br>
&nbsp;&nbsp;&nbsp; struct device有两个成员<br>
&nbsp;&nbsp;&nbsp; struct bus_type&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *bus&nbsp;&nbsp;&nbsp;&nbsp; 记录的是这个设备连在哪条总线上<br>
&nbsp;&nbsp;&nbsp; struct device_driver *driver 记录的是这个设备用的是哪个驱动<br>
<br>
<span style="color:#800000"><strong>struct <a href="http://hi.baidu.com/zengzhaonong/blog/item/17936cf0b80c80ada40f52f5.html" target="_blank" target="_blank">
device_driver</a></strong></span><br>
---------------------------------<br>
&nbsp;&nbsp;&nbsp; struct device_driver同样有两个成员<br>
&nbsp;&nbsp;&nbsp; struct bus_type *bus&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 代表的是这个驱动属于哪条总线&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; struct klist&nbsp;&nbsp;&nbsp; klist_devices 记录的是这个驱动支持的那些设备,没错,是devices(复数),因为一个驱动程序可以支持一个或多个设备,反过来一个设备则只会绑定给一个驱动程序.</span><br>
</p>
<p>二、总线,设备,驱动的关联</p>
<p>总线将设备和驱动绑定。在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每 注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。一个现实的Linux设备和驱动通常都需要挂接在一种总线上。设备与驱动的关联通过总线的<span style="color:#FF0000">match()<span style="color:#333333">方法进行匹配,驱动挂载总线时与所有设备进行匹配,设备挂载总线时与所有的驱动进行匹配,所以驱动和设备的挂载无先后之分。匹配成功后会通过调用驱动的<span style="color:#FF0000">probo()<span style="color:#333333">方法来初始化设备。</span></span></span></span></p>
<p><span style="color:#FF0000"><span style="color:#333333"><span style="color:#FF0000"><span style="color:#333333">三、总线,设备,驱动的注册</span></span></span></span></p>
<p><span style="color:#FF0000"><span style="color:#333333"><span style="color:#FF0000"><span style="color:#333333"><span style="color:#000000">设备与驱动需要挂载在总线上,需要指明驱动与设备是属于哪条总线的,所以设备与驱动需要注册。而总线在linux系统中也是属于设备,所以总线也要注册,同时要先有总线而后才能注册设备和驱动,所以总线要先注册。</span></span></span></span></span></p>
<p><span style="color:#FF0000"><span style="color:#333333"><span style="color:#FF0000"><span style="color:#333333"><span style="color:#000000">总
线在linux系统中有俩种,一是实际存在的总线 pci&nbsp; usb 等等,还有一类是虚拟存在的总线 platform
,platform总线主要是用于集成在SoC系统的设备,使得每一个设备都属于一条总线,相应的设备称为platform_device,而驱动成为
platform_driver。<span style="color:#333333">linux驱动中platform总线用的非常多,以platform总线说明总线,设备,驱动的注册顺序,注意这里是以先调加设备为例。</span></span></span></span></span></span></p>
<p><span style="color:#FF0000"><span style="color:#333333"><span style="color:#FF0000"><span style="color:#333333"><span style="color:#000000"><span style="color:#333333">1. platform_bus_type -- 总线 先被kenrel 注册。<br>
<br>
2. 系统初始化过程中调用platform_add_devices 或者platform_device_register ,将平台设备(platform devices) 注册到平台总线中( platform_bus_type )<br>
3. 平台驱动(platform driver) 与平台设备(platform device) 的关联是在platform_driver_register 或者driver_register 中实现,一般这个函数在驱动的初始化过程调用。<br>
<br>
通过这三步,就将平台总线,设备,驱动关联起来。<br>
<br>
1. platform bus 先被kenrel 注册。<br>
------------------------------------------------------<br>
do_basic_setup() --&gt; - driver_init() --&gt; - platform_bus_init() --&gt;bus_register()<br>
<br>
<br>
2. 系统初始化过程中调用platform_add_devices 或者platform_device_register ,将平台设备(platform devices) 注册到平台总线中( platform_bus_type )<br>
------------------------------------------------------<br>
系统启动阶段,总线的驱动链表还是空的,所以启动阶段的platform_add_devices() 只负责将设备添加到总线的设备链表上。<br>
</span></span></span></span></span></span></p>
<p><span style="color:#FF0000"><span style="color:#333333"><span style="color:#FF0000"><span style="color:#333333"><span style="color:#000000"><span style="color:#333333">linux 2.6.26/drivers/base/platform.c<br>
int platform_add_devices(struct platform_device **devs, int num)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp; ...<br>
&nbsp;&nbsp;&nbsp;&nbsp; ret = platform_device_register (devs);<br>
&nbsp;&nbsp;&nbsp;&nbsp; ...<br>
}<br>
<br>
int platform_device_register(struct platform_device *pdev)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp; device_initialize(&amp;pdev &gt;dev);<br>
&nbsp;&nbsp;&nbsp;&nbsp; return platform_device_add (pdev);<br>
}<br>
<br>
int platform_device_add (struct platform_device *pdev)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp; ...<br>
&nbsp;&nbsp;&nbsp;&nbsp; pdev &gt;dev.bus = &amp;platform_bus_type;<br>
&nbsp;&nbsp;&nbsp;&nbsp; ...<br>
&nbsp;&nbsp;&nbsp;&nbsp; ret = device_add (&amp;pdev &gt;dev);<br>
&nbsp;&nbsp;&nbsp;&nbsp; ...<br>
}<br>
<br>
device_add()&nbsp;&nbsp; &gt;&nbsp;&nbsp; bus_attach_device()<br>
<br>
void bus_attach_device(struct device *dev)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp; struct bus_type *bus = dev &gt;bus;<br>
&nbsp;&nbsp;&nbsp;&nbsp; int ret = 0;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp; if (bus) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (bus &gt;p &gt;drivers_autoprobe)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = device_attach (dev);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WARN_ON(ret &lt; 0);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ret &gt;= 0)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; klist_add_tail (&amp;dev &gt;knode_bus, &amp;bus &gt;p &gt;klist_devices);<br>
&nbsp;&nbsp;&nbsp;&nbsp; }<br>
}<br>
<br>
device_attach() 的返回值:<br>
1 设备和驱动匹配成功<br>
0 设备已经注册,但是总线上没有与之相匹配的驱动( 系统启动阶段,由于总线上还没有驱动,所以设备在此匹配不到与之对应的驱动,只是将其添加到总线的设备链表)<br>
-ENODEV 设备没有注册(registered) -- 设备在哪里注册?<br>
<br>
如果设备和驱动匹配成功; 或者设备已经注册,但是总线上没有与之相匹配的驱动 ,bus_attach_device() 将调用klist_add_tail() 将设备添加到总线的设备链表尾部。<br>
</span></span></span></span></span></span></p>
<p><span style="color:#FF0000"><span style="color:#333333"><span style="color:#FF0000"><span style="color:#333333"><span style="color:#000000"><span style="color:#333333">四、附录linux内核中的platform的几个结构源代码<br>
</span></span></span></span></span></span></p>

<div class="dp-highlighter bg_cpp"><div class="bar"><div class="tools"><a href="http://blog.csdn.net/yimu13/article/details/6762964#" class="ViewSource" title="view plain" target="_blank" target="_blank">view plain</a></div></div><ol class="dp-cpp" start="1"><li class="alt"><span><span>&nbsp;</span><span class="comment">//&nbsp;所在目录:kernel/include/linux/platform_device.h&nbsp;&nbsp;</span><span>&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;<span class="keyword">struct</span><span>&nbsp;platform_device&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">const</span><span>&nbsp;</span><span class="datatypes">char</span><span>&nbsp;&nbsp;*&nbsp;name;</span><span class="comment">/*&nbsp;设备名&nbsp;*/</span><span>&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;u32&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;id;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">struct</span><span>&nbsp;device&nbsp;dev;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;u32&nbsp;&nbsp;num_resources;<span class="comment">/*&nbsp;设备所使用各类资源数量&nbsp;*/</span><span>&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">struct</span><span>&nbsp;resource&nbsp;*&nbsp;resource;</span><span class="comment">/*&nbsp;资源&nbsp;*/</span><span>&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt"><span>};&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;<span class="comment">//&nbsp;所在目录:include/linux/ioport.h&nbsp;&nbsp;</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span><span class="keyword">struct</span><span>&nbsp;resource&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class=""><span>{&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;resource_size_t&nbsp;start;&nbsp;&nbsp;<span class="comment">/*&nbsp;&nbsp;资源的开始值&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;resource_size_t&nbsp;end;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">/*&nbsp;&nbsp;资源的结束值&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">const</span><span>&nbsp;</span><span class="datatypes">char</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*name;&nbsp;&nbsp;</span><span class="comment">/*&nbsp;&nbsp;资源的名字&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="datatypes">long</span><span>&nbsp;&nbsp;&nbsp;flags;&nbsp;&nbsp;</span><span class="comment">/*&nbsp;&nbsp;资源的类型值,如可以是:mem,io,irq,dma等等&nbsp;*/</span><span>&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">struct</span><span>&nbsp;resource&nbsp;*parent,&nbsp;*sibling,&nbsp;*child;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class=""><span>};&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span><span class="comment">//&nbsp;所在目录:kernel/include/linux/ioport.h&nbsp;&nbsp;</span><span>&nbsp;&nbsp;</span></span></li><li class=""><span><span class="keyword">struct</span><span>&nbsp;platform_driver&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt"><span>{&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;&nbsp;<span class="datatypes">int</span><span>&nbsp;(*probe)(</span><span class="keyword">struct</span><span>&nbsp;platform_device&nbsp;*);&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;<span class="datatypes">int</span><span>&nbsp;(*remove)(</span><span class="keyword">struct</span><span>&nbsp;platform_device&nbsp;*);&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;<span class="keyword">void</span><span>&nbsp;(*shutdown)(</span><span class="keyword">struct</span><span>&nbsp;platform_device&nbsp;*);&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;<span class="datatypes">int</span><span>&nbsp;(*suspend)(</span><span class="keyword">struct</span><span>&nbsp;platform_device&nbsp;*,&nbsp;pm_message_t&nbsp;state);&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;<span class="datatypes">int</span><span>&nbsp;(*suspend_late)(</span><span class="keyword">struct</span><span>&nbsp;platform_device&nbsp;*,&nbsp;pm_message_t&nbsp;state);&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;<span class="datatypes">int</span><span>&nbsp;(*resume_early)(</span><span class="keyword">struct</span><span>&nbsp;platform_device&nbsp;*);&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;<span class="datatypes">int</span><span>&nbsp;(*resume)(</span><span class="keyword">struct</span><span>&nbsp;platform_device&nbsp;*);&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;<span class="keyword">struct</span><span>&nbsp;pm_ext_ops&nbsp;*pm;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;<span class="keyword">struct</span><span>&nbsp;device_driver&nbsp;driver;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt"><span>};&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class=""><span><span class="comment">//&nbsp;所在目录:include/linux/device.h&nbsp;&nbsp;</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span><span class="keyword">struct</span><span>&nbsp;device_driver&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class=""><span>{&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">char</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;name;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">struct</span><span>&nbsp;bus_type&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;bus;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rwlock_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lock;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;atomic_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;refcount;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;list_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bus_list;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;list_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;devices;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">struct</span><span>&nbsp;driver_dir_entry&nbsp;dir;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">int</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(*probe)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span class="keyword">struct</span><span>&nbsp;device&nbsp;*&nbsp;dev);&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">int</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(*remove)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span class="keyword">struct</span><span>&nbsp;device&nbsp;*&nbsp;dev);&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">int</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(*suspend)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span class="keyword">struct</span><span>&nbsp;device&nbsp;*&nbsp;dev,&nbsp;u32&nbsp;state,&nbsp;u32&nbsp;level);&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">int</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(*resume)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span class="keyword">struct</span><span>&nbsp;device&nbsp;*&nbsp;dev,&nbsp;u32&nbsp;level);&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">void</span><span>&nbsp;&nbsp;&nbsp;&nbsp;(*release)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span class="keyword">struct</span><span>&nbsp;device_driver&nbsp;*&nbsp;drv);&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt"><span>};&nbsp;&nbsp;&nbsp;&nbsp;</span></li></ol></div><br>
文章内容多为转载,但是也经过我一番整理,发现其实整理一下自己也学到了很多。

hustsean 发表于 2012-08-15 22:07

看看大家的文章,再自己想想!谢谢!

willinux 发表于 2014-07-01 11:23

mark 一下啊:curse:
页: [1]
查看完整版本: linux设备驱动之总线、设备、驱动