linux 下面对 driver 的定义:
struct device_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 提供接口;
这个应该是很好理解的,不可能让每个上层软件的作者自己写驱动来访问硬件;所以必须要抽象出一套接口,但是需要哪些接口呢?
Linux 的 driver 实现很有意思,把任何东西都抽象成文件,包括硬件,这样对硬件的操作也就只需提供 vfs 所需的一套接口,当然其实这些接口的类型在很大程度上划分了 driver 的类型,而这些接口也可以提供其它的形式,比如网卡就不提供这些接口;
Open :打开,也就是打开这个设备,这只是抽象的概念,很多硬件设备不存在这样的物理动作,比如门,我们才说打开,当然如果理解所谓“打开心扉”也就很好理解这里的 driver 所抽象出的打开了;先前所说硬件的初始化可以在 probe 函数里面做,当然我想有些动作放在 open 里面做也可以的,但是必须要考虑的是, open 是可能出现许多个进程来访问的,或者你自己要上锁或者你就要考虑可重入性,也就是说如果一些动作只能做一次,那么显然放在 open 里面来做就不合适了。
Close :这个和 open 相反的动作,但是这个 close 是上层才有的一个概念,在驱动里面用来一个叫 release 的接口实现,至于 close 到 release 之间的转换就需要去看看文件系统这层的实现了。
Read :这就是读取数据了,没什么好说,比如串口,比如 touch panel ;
Write :这就是写了,也就是往设备里面写数据;
其它的一些对上的接口 …. 就不讨论了;