Linux driver编写思考

来源:互联网 发布:英雄联盟mac版怎么下 编辑:程序博客网 时间:2024/05/18 02:06

 

<!-- /* Font Definitions */ @font-face{font-family:宋体;panose-1:2 1 6 0 3 1 1 1 1 1;mso-font-alt:SimSun;mso-font-charset:134;mso-generic-font-family:auto;mso-font-pitch:variable;mso-font-signature:3 135135232 16 0 262145 0;}@font-face{font-family:"/@宋体";panose-1:2 1 6 0 3 1 1 1 1 1;mso-font-charset:134;mso-generic-font-family:auto;mso-font-pitch:variable;mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal{mso-style-parent:"";margin:0cm;margin-bottom:.0001pt;text-align:justify;text-justify:inter-ideograph;mso-pagination:none;font-size:10.5pt;mso-bidi-font-size:12.0pt;font-family:"Times New Roman";mso-fareast-font-family:宋体;mso-font-kerning:1.0pt;}h1{mso-style-next:正文;margin-top:17.0pt;margin-right:0cm;margin-bottom:16.5pt;margin-left:0cm;text-align:justify;text-justify:inter-ideograph;line-height:240%;mso-pagination:lines-together;page-break-after:avoid;mso-outline-level:1;font-size:22.0pt;font-family:"Times New Roman";mso-font-kerning:22.0pt;} /* Page Definitions */ @page{mso-page-border-surround-header:no;mso-page-border-surround-footer:no;}@page Section1{size:595.3pt 841.9pt;margin:72.0pt 90.0pt 72.0pt 90.0pt;mso-header-margin:42.55pt;mso-footer-margin:49.6pt;mso-paper-source:0;layout-grid:15.6pt;}div.Section1{page:Section1;} /* List Definitions */ @list l0{mso-list-id:784233325;mso-list-type:hybrid;mso-list-template-ids:-1427321556 -1863033830 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}@list l0:level1{mso-level-text:%1,;mso-level-tab-stop:18.0pt;mso-level-number-position:left;margin-left:18.0pt;text-indent:-18.0pt;}@list l1{mso-list-id:1376807113;mso-list-type:hybrid;mso-list-template-ids:-1341603798 2127586910 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}@list l1:level1{mso-level-text:%1,;mso-level-tab-stop:18.0pt;mso-level-number-position:left;margin-left:18.0pt;text-indent:-18.0pt;}ol{margin-bottom:0cm;}ul{margin-bottom:0cm;}-->

 

                                   Linuxdriver编写思考

linux下面对driver的定义:

structdevice_driver {

const char              *name;

struct bus_type              *bus;

struct completion    unloaded;

struct kobject         kobj;

struct klist             klist_devices;

struct klist_node     knode_bus;

struct module         *owner;

const char             *mod_name;  /* used for built-in modules */

struct module_kobject    * mkobj;

 

int   (*probe)  (struct device * dev);

int   (*remove)      (struct device * dev);

void (*shutdown)   (struct device * dev);

int   (*suspend)      (struct device * dev, pm_message_t state);

int   (*resume)       (struct device * dev);

 

unsigned int multithread_probe:1;

};

我们一个个来看,

 Name:就是这个driver的名字;

 Bus:就是这个driver是挂在上面bus上面的;

 Unloaded:这个以后再讨论;

 Kobj:这个可以理解为driver结构的父亲,如果从面向对象的角度来看的话;

 Klist_devices:这个就是由此driver驱动的设备列表;

 Knode_bus:这个就是用来挂在它说属的bus链表上的节点,顺着这个链表就可以找到所有的挂在这个bus上的所有的driver

 Owner:这个driver所属的模块;

Mod_name:模块名字;

 mkobj:模块的顶层描述;

 probe:这个是很关键的函数,用来初始化此driver驱动的硬件,还有其它能够正常为应用层提供服务说需要提前做的事都需要在这里做;

 remove:这个就是移除的时候做的事情;

 suspend:这个应该是睡眠的时候做的事情,也就是说上层通过这个函数实现对硬件的电源策略控制;

resume:这个就是从睡眠中醒来需要对硬件所做的事都需要在这里做;

multithread_probe:是否启用多线程probe

 

分析完了driver的结构,我们看看为什么需要这样的设计,也就是说,如果我们自己需要实现一套架构用来实现同样的功能,我们需要做什么呢?

Driver应该提供的功能

driver应该提供哪些功能呢?

1, 为应用层使用driver提供接口;

这个应该是很好理解的,不可能让每个上层软件的作者自己写驱动来访问硬件;所以必须要抽象出一套接口,但是需要哪些接口呢?

Linuxdriver实现很有意思,把任何东西都抽象成文件,包括硬件,这样对硬件的操作也就只需提供vfs所需的一套接口,当然其实这些接口的类型在很大程度上划分了driver的类型,而这些接口也可以提供其它的形式,比如网卡就不提供这些接口;

Open:打开,也就是打开这个设备,这只是抽象的概念,很多硬件设备不存在这样的物理动作,比如门,我们才说打开,当然如果理解所谓“打开心扉”也就很好理解这里的driver所抽象出的打开了;先前所说硬件的初始化可以在probe函数里面做,当然我想有些动作放在open里面做也可以的,但是必须要考虑的是,open是可能出现许多个进程来访问的,或者你自己要上锁或者你就要考虑可重入性,也就是说如果一些动作只能做一次,那么显然放在open里面来做就不合适了。

Close:这个和open相反的动作,但是这个close是上层才有的一个概念,在驱动里面用来一个叫release的接口实现,至于closerelease之间的转换就需要去看看文件系统这层的实现了。

Read:这就是读取数据了,没什么好说,比如串口,比如touch panel

Write:这就是写了,也就是往设备里面写数据;

其它的一些对上的接口….就不讨论了;

driver还必须要提供其它的接口:那就是做为linux driver本身说必须要提供的接口,这些接口通常是内核自身所调用的;

那就是

Probe:这个函数很关键,它作为一个桥梁连接设备和driver,并且必须要对硬件进行初始化,以便在以后的用户接口调用的时候设备能正常工作;从软件的角度说,许多空间的分配等都在这里做,通过dev_set_drvdatadev_get_drvdata设置和获取相应的数据;

Remove:这个函数和上面这个函数是相反的,也就是负责清理扫尾的工作,负责释放数据结构,停止硬件等;

Suspend:这个是在睡眠的时候调用的,在这里就必须要进行功耗控制;

Resume:这个就是唤醒的时候调用的,它需要执行相应的恢复动作,以便硬件能正常工作;

2, 实现对硬件设备的访问控制;

只提供接口不负责实现,就是所谓的“银样蜡枪头,所以驱动最复杂的地方在于如何控制硬件实现我们想实现的功能;而这些具体的实现通常就包含在给上层提供的接口中;而另外一方面一个驱动要实现某项功能很多时候不是自己独立实现的,而是依赖于其它的模块,比如WIFI驱动,在我们的平台上,是通过sdio口连接的,而sdio口是mmc controller提供的,而mmc本身又是通过gpio口实现的,换句话说,如果要wifi能正常工作,就必须要mmc这一套能正常工作;那么就需要先配置gpio口,再移植mmc驱动,最后才是wifi驱动,而wifi芯片本身说不定还需要其它的动作才能正常,比如上电等等;

Driver和设备之间的连接

如果说driver就是由struct device_driver来描述,而设备也是有struct device来描述的话,那么如何描述driverdriver所驱动的设备这种关系呢?也就是说如果是父子,或夫妻关系的话,他们是如何相认的,又是如何维持这种纽带的?一个设备通常由一个driver驱动,而一个driver有时候可以驱动多个设备(这也许是在美好的一夫多妻制时代)

1, 家族的概念

每个人都诞生于一个家庭,而由一系列有血缘关系的家庭又组成家族,我想bus的概念有点类似家族;

2, 设备的诞生

当一个设备通过device_add的方式调用的话,对它所属的家族来说意味着一个新的小孩诞生了;如果这时候它的配偶已经由上帝指定的话,意味着它的配偶已经住进了它们的家族(挂在了bus上),那么上帝就会把它的配偶driver指向这个device完成婚姻,通常这时候就会调用driver提供的probe函数进行一系列的初始化操作,这就像丈夫对妻子进行思想教育一样;

3, driver的诞生

当一个driver调用driver_register的时候,也就宣布着新的孩子诞生了,如果它的配偶已经住进他们的家族,也就是说如果驱动的设备已经挂在了总线上,那么就可以结婚了(估计他们是属于一出生就比较成熟的类型),同样这时候就要调用driverprobe函数进行初始化工作了;

4, 人口登记

不管是男孩还是女孩,对政府来说都是kobject,所以一旦有孩子诞生不管是男是女都会调用kobject_add登记在案,这样政府就可以完全掌控所有的信息;

5, 配偶的寻找

如果是先有device,那么匹配就是通过遍历bus上的driver来进行的,反之就是通过遍历bus上的设备进行的,而匹配的前提就是设备已经注册,并且符合这个家族的族规,而族规通常是由busmatch函数来控制,而很多时候都是比较设备的名字和driver的名字是否相同(这个比结婚要比的东西简朴许多啊,现在结婚比的是money)当然还有其它许多的匹配方式,如果通过这个测试就可以调用driver提供的probe函数进行初始化了;

 

这样的话,设备和driver就可以连接起来了,有了这样的人口登记和家族联系,就可以实现诸如睡眠唤醒这样的功能了。

原创粉丝点击