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
</a></strong></span><br>
---------------------------------<br>
struct bus_type中为devices和drivers准备了两个链表:<br>
struct klist klist_devices<br>
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>
struct device有两个成员<br>
struct bus_type *bus 记录的是这个设备连在哪条总线上<br>
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>
struct device_driver同样有两个成员<br>
struct bus_type *bus 代表的是这个驱动属于哪条总线 <br>
struct klist 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 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() --> - driver_init() --> - platform_bus_init() -->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>
...<br>
ret = platform_device_register (devs);<br>
...<br>
}<br>
<br>
int platform_device_register(struct platform_device *pdev)<br>
{<br>
device_initialize(&pdev >dev);<br>
return platform_device_add (pdev);<br>
}<br>
<br>
int platform_device_add (struct platform_device *pdev)<br>
{<br>
...<br>
pdev >dev.bus = &platform_bus_type;<br>
...<br>
ret = device_add (&pdev >dev);<br>
...<br>
}<br>
<br>
device_add() > bus_attach_device()<br>
<br>
void bus_attach_device(struct device *dev)<br>
{<br>
struct bus_type *bus = dev >bus;<br>
int ret = 0;<br>
<br>
if (bus) {<br>
if (bus >p >drivers_autoprobe)<br>
ret = device_attach (dev);<br>
WARN_ON(ret < 0);<br>
if (ret >= 0)<br>
klist_add_tail (&dev >knode_bus, &bus >p >klist_devices);<br>
}<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> </span><span class="comment">// 所在目录:kernel/include/linux/platform_device.h </span><span> </span></span></li><li class=""><span> <span class="keyword">struct</span><span> platform_device </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">const</span><span> </span><span class="datatypes">char</span><span> * name;</span><span class="comment">/* 设备名 */</span><span> </span></span></li><li class="alt"><span> u32 id; </span></li><li class=""><span> <span class="keyword">struct</span><span> device dev; </span></span></li><li class="alt"><span> u32 num_resources;<span class="comment">/* 设备所使用各类资源数量 */</span><span> </span></span></li><li class=""><span> <span class="keyword">struct</span><span> resource * resource;</span><span class="comment">/* 资源 */</span><span> </span></span></li><li class="alt"><span>}; </span></li><li class=""><span> <span class="comment">// 所在目录:include/linux/ioport.h </span><span> </span></span></li><li class="alt"><span><span class="keyword">struct</span><span> resource </span></span></li><li class=""><span>{ </span></li><li class="alt"><span> resource_size_t start; <span class="comment">/* 资源的开始值 */</span><span> </span></span></li><li class=""><span> resource_size_t end; <span class="comment">/* 资源的结束值 */</span><span> </span></span></li><li class="alt"><span> <span class="keyword">const</span><span> </span><span class="datatypes">char</span><span> *name; </span><span class="comment">/* 资源的名字 */</span><span> </span></span></li><li class=""><span> unsigned <span class="datatypes">long</span><span> flags; </span><span class="comment">/* 资源的类型值,如可以是:mem,io,irq,dma等等 */</span><span> </span></span></li><li class="alt"><span> <span class="keyword">struct</span><span> resource *parent, *sibling, *child; </span></span></li><li class=""><span>}; </span></li><li class="alt"><span><span class="comment">// 所在目录:kernel/include/linux/ioport.h </span><span> </span></span></li><li class=""><span><span class="keyword">struct</span><span> platform_driver </span></span></li><li class="alt"><span>{ </span></li><li class=""><span> <span class="datatypes">int</span><span> (*probe)(</span><span class="keyword">struct</span><span> platform_device *); </span></span></li><li class="alt"><span> <span class="datatypes">int</span><span> (*remove)(</span><span class="keyword">struct</span><span> platform_device *); </span></span></li><li class=""><span> <span class="keyword">void</span><span> (*shutdown)(</span><span class="keyword">struct</span><span> platform_device *); </span></span></li><li class="alt"><span> <span class="datatypes">int</span><span> (*suspend)(</span><span class="keyword">struct</span><span> platform_device *, pm_message_t state); </span></span></li><li class=""><span> <span class="datatypes">int</span><span> (*suspend_late)(</span><span class="keyword">struct</span><span> platform_device *, pm_message_t state); </span></span></li><li class="alt"><span> <span class="datatypes">int</span><span> (*resume_early)(</span><span class="keyword">struct</span><span> platform_device *); </span></span></li><li class=""><span> <span class="datatypes">int</span><span> (*resume)(</span><span class="keyword">struct</span><span> platform_device *); </span></span></li><li class="alt"><span> <span class="keyword">struct</span><span> pm_ext_ops *pm; </span></span></li><li class=""><span> <span class="keyword">struct</span><span> device_driver driver; </span></span></li><li class="alt"><span>}; </span></li><li class=""><span><span class="comment">// 所在目录:include/linux/device.h </span><span> </span></span></li><li class="alt"><span><span class="keyword">struct</span><span> device_driver </span></span></li><li class=""><span>{ </span></li><li class="alt"><span> <span class="datatypes">char</span><span> * name; </span></span></li><li class=""><span> <span class="keyword">struct</span><span> bus_type * bus; </span></span></li><li class="alt"><span> rwlock_t lock; </span></li><li class=""><span> atomic_t refcount; </span></li><li class="alt"><span> list_t bus_list; </span></li><li class=""><span> list_t devices; </span></li><li class="alt"><span> <span class="keyword">struct</span><span> driver_dir_entry dir; </span></span></li><li class=""><span> <span class="datatypes">int</span><span> (*probe) (</span><span class="keyword">struct</span><span> device * dev); </span></span></li><li class="alt"><span> <span class="datatypes">int</span><span> (*remove) (</span><span class="keyword">struct</span><span> device * dev); </span></span></li><li class=""><span> <span class="datatypes">int</span><span> (*suspend) (</span><span class="keyword">struct</span><span> device * dev, u32 state, u32 level); </span></span></li><li class="alt"><span> <span class="datatypes">int</span><span> (*resume) (</span><span class="keyword">struct</span><span> device * dev, u32 level); </span></span></li><li class=""><span> <span class="keyword">void</span><span> (*release) (</span><span class="keyword">struct</span><span> device_driver * drv); </span></span></li><li class="alt"><span>}; </span></li></ol></div><br>
文章内容多为转载,但是也经过我一番整理,发现其实整理一下自己也学到了很多。 看看大家的文章,再自己想想!谢谢! mark 一下啊:curse:
页:
[1]