试着总结一下,学习一下,至少现在的我对于设备模型这个概念,几乎完全不懂。
Linux设备模型中三个很重要的概念就是总线、设备和驱动,即bus、device、driver,而实际上内核中也定义了这么一些数据结构,分别为struct bus_type,struct device,struct device_driver,
原型定义均在include/linux/device.h中。而struct bus_type结构中两个非常重要的成员就是kset和kobject这两个结构体。
于是乎,Linux设备模型概念中重要的5个概念都引出来了,即设备模型
在具体实现方面分两个层次:
一是底层数据结构来实现基本对象及其层次关系:kobjects和ksets。
二是基于这两个底层数据结构上实现的设备模型:总线,设备,驱动。
一、底层数据结构:kobject,kset
kobject
结合面向对象的思维。这个kobject属于最基础的结构,也就是最高抽象层(有点像java中的Cobject类)。任何一个设备模型如总线,设备,驱动都属于一个kobject 。在实现上这种派生关系就是在结构体中包含一个kobject的变量。
这个在层次上处理最顶层的kobject结构提供了所有模型需要的最基本的功能:
1 引用计数 用于内核维护其存在与消亡
2 sysfs表示 每个sys/下的对象对应着一个kobject。
3 热拔插事件处理 处理设备的热拔插事件。
Kobjects 在内核中对应有一套申请,初始化,添加,注册,计数操作,释放等函数
//2.6.10
struct kobject {
char * k_name; //名称
char name[KOBJ_NAME_LEN];
struct kref kref; //计数
struct list_head entry;//用于连接到同类kobjects的链表
struct kobjectn * parent;//用于实现层次,指向其父对象
struct kset * kset; //用于实现层次,所属的集合
struct kobj_typen * ktype;//指向对象的类型
struct dentry * dentry; //指示在sysfs中的目录项
};
Kset和kobj_type
Kset在概念上是一个集合或者叫容器。实现了对象的层次。所有属于一个ksets的对象(kobject)的parent都指向该ksets的kobj.同时这个对象都连接到kset 的list表上。同时位于ksets层次之上的是subsys,在最新的内核中已经取消subsys,因为它本质上也就是一个ksets。Kset有一套类似kobject的操作,实现上只是进一步调用其自身kobj的相应操作,毕竟ksets本质上也是一个kobject。
//2.6.10
struct kset {
struct subsystem * subsys; //在新内核中已经没有subsys概念了,统一用kests
struct kobj_type * ktype; //类型
struct list_head list; //同一kset的链表
struct kobject kobj; //自身的kobjects
struct kset_hotplug_ops * hotplug_ops;
};
最后 属于同一个集合的对象可以拥有共同的属性:ktype 。
struct kobj_type {
void (*release)(struct kobject *);
struct sysfs_ops * sysfs_ops;
struct attribute ** default_attrs;
};
所谓的属性更具体一点说就是一些键值对。并且在sysfs_ops中的show函数被文件系统调用来显示sys/下面对应入口各属性的值。
如此 ,kobjects与ksets实现层次树的底层骨架。
进一步地,通过封装这些底层结构来实现上层的设备驱动模型。
二、总线 设备 驱动
关于bus,关于device,关于driver,他们是如何建立联系的呢?
基本关系简要的概括如下:
驱动核心可以注册多种类型的总线。
每种总线下面可以挂载许多设备。(通过kset devices)
每种总线下可以用很多设备驱动。(通过包含一个kset drivers)}
每个驱动可以处理一组设备。
这种基本关系的建立源于实际系统中各种总线,设备,驱动结构的抽象。
具体到usb设备就是usb core的代码会进行整个usb系统的初始化,比如申请struct bus_type usb_bus_type,然后扫描usb总线,看线上连接了哪些usb设备,或者说root hub上连了哪些usb设备
,比如说连了一个usb键盘,那么就为它准备一个struct device,根据它的实际情况,为这个struct device赋值,并插入devices链表中来。又比如root hub上连了一个普通的hub,那么除了要为这个hub本身准备一个struct device以外,还得继续扫描这个hub上是否又连了别的设备,有的话继续重复之前的事情,这样一直进行下去,直到完成整个扫描,最终就把usb_bus_type中的devices链表给建立了起来。
那么drivers链表呢?这个就不用bus方面主动了,而该由每一个driver本身去bus上面登记,或者说挂牌。具体到usb系统,每一个usb设备的驱动程序都会有一个struct usb_driver结构体,其代
码如下,来自include/linux/usb.h
//2.6.10
struct usb_driver {
struct module *owner;
const char *name;
int (*probe) (struct usb_interface *intf,
const struct usb_device_id *id);
void (*disconnect) (struct usb_interface *intf);
int (*ioctl) (struct usb_interface *intf, unsigned int code, void *buf);
int (*suspend) (struct usb_interface *intf, u32 state);
int (*resume) (struct usb_interface *intf);
const struct usb_device_id *id_table;
struct device_driver driver;
};
bus和device之间是如何建立联系的?
看似很长一段,实际上也就是注释为主.而此刻我们只需注意到其中的struct device_driver driver这个成员,usb core为每一个设备驱动准备了一个函数,让它把自己的这个
struct device_driver driver插入到usb_bus_type中的drivers链表中去.而这个函数正是我们此前看到的usb_register.而与之对应的 usb_deregister所从事的正是与之相反的工作,把这个结构
体从drivers链表中删除.可以说,usb core的确是用心良苦,为每一个usb设备驱动做足了功课,正因为如此,作为一个实际的usb设备驱动,它在初始化阶段所要做的事情就很少,很简单了, 直接调用
usb_register即可.事实上,没有人是理所当然应该为你做什么的,但usb core这么做了.所以每一个写usb设备驱动的人应该铭记,usb device driver绝不是一个人在工作,在他身后,是usb core所提
供的默默无闻又不可或缺的支持。
device和driver之间是如何建立联系的呢?
因为有了热插拔,device可以在计算机启动以后在插入或者拔出计算机了.因此,很难再说是先有device还是先有driver了.因为都有可能.device可以在任何时刻出现,而driver也可以在任何时刻被加载,所以,出现的情况就是,每当一个struct device诞生,它就会去bus的drivers链表中寻找自己的另一半,反之,每当一个一个struct device_driver诞生,它就去bus的devices链表中寻找它的那些设备.如果找到了合适的,那么ok,调用 device_bind_driver绑定好.如果找不到,没有关系,等待吧。
还记得初始化的那几行代码吗?回到usb_register中来,看一下传给他的参数是什么?
我们注意到,那句调用是这样子的,
/* register the driver, return usb_register return code if error */
retval = usb_register(&usb_storage_driver);
是的,传递了一个叫做usb_storage_driver的家伙,这是什么?同一文件中,drivers/usb/storage/usb.c:
struct usb_driver usb_storage_driver = {
.owner = THIS_MODULE,
.name = "usb-storage",
.probe = storage_probe,
.disconnect = storage_disconnect,
.id_table = storage_usb_ids,
};
可以看到这里定义了一个struct usb_driver的结构体变量,usb_storage_driver,关于usb_driver我们上节已经说过了,当时主要说的是其中的成员driver,而眼下要讲的则是另外几个成员.首先,.owner
和.name这两个没啥好多说的,owner这玩艺是用来给模块计数的,每个模块都这么用,赋值总是THIS_MODULE,而name就是这个模块的名字,usb core会处理它,所以如果这个模块正常被加载了的话,使用lsmod命令能看到一个叫做usb-storage的模块名。
------------------------------------------------------------------------------------------------------------------
作者:庞辉
出处:http://www.cnblogs.com/pang123hui/
本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名庞辉(包含链接).