Linux设备模型

Linux设备模型(不涉及文件系统):
包括以下对象kref, kobject, subsystem, device,driver,bus_type

Kernel编译后,生成几个全局的subsystem对象,包括classes_subsys, bus_subsys, devices_subsys, 这些是顶层子系统,其他所

有总线注册,设备注册,驱动注册都挂靠在这几个子系统下

设备和驱动的注册都是在某一条总线上,所以我们首先分析总线结构,以下结构只跟踪结构中相关的特性。
struct bus_type {
 const char *name; 总线名称,总线对象的名字就被设定为该名字
 struct subsystem subsys; 总线也被认为是一种子系统,所以它继承子系统的特性
 struct kset devices; 是挂靠在该总线下设备对象的集合
 struct kset drivers; 是挂靠在该总线下驱动对象的集合
 struct klist klist_devices; 该总线下设备节点的knode_bus指向此字段
 struct klist klist_drivers; 该总线下驱动节点的knode_bus指向此字段
 
 在bus下加驱动及设备的时候,做匹配,通常比较驱动及设备的名字是否一致
 int (*match)(struct device *dev, struct device_driver *drv);
};
和总线相关的函数主要有4个:
int bus_register(struct bus_type *bus); 注册总线的时候,通常结构字段里面要对name和match赋初值,
以下是总线注册的流程
(1) bus->subsys.kset.kobj.kset = bus_subsys.kset 在bus_subsys下注册
(2) 注册2个kset,包括devices和drivers,使
bus->devices.subsys=&bus->subsys;
bus->devices.kobj.parent = &bus->subsys.kset.kobj;
(3) 初始化klist_devices和klist_drivers

注册完总线后,可以看到,相关字段devices,drivers,klist_devices,klist_drivers链表都还是空


接下来,我们开始分析驱动程序的注册
驱动程序注册的目的是将其注册在某一条总线下,总线的klist_drivers下含有该驱动节点,所以在注册驱动的时候,要指定注册在

哪条总线下,同时,驱动程序应该可以对某一类设备通用,所以需要有一个链表,链接所有使用这个驱动的设备klist_devices

struct device_driver {
 const char  * name;  驱动名
 struct bus_type * bus; 驱动属于哪条总线
 struct kobject  kobj; 驱动对象
 struct klist  klist_devices; 使用该驱动的设备链表头
 struct klist_node knode_bus; 指向总线下的klist_drivers

 驱动程序通用函数,注册的驱动可以重载这些函数
 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);
};

驱动注册,主要就是将驱动加到某条总线下,并且更新相关字段
(1) 首先将驱动对象的kset指向所属总线下的drivers
(2) 轮寻所属总线下的所有设备,对那些还没有指向驱动的设备,用bus下的match函数进行匹配,如果设备名和驱动名相同,则

将设备的驱动指针指向待添加的驱动程序,之后调用驱动程序的probe函数,完成封装device_drivers的驱动程序实例的初始化工作

,所以,在用户编写完驱动,调用module_init时候,该函数参数一般都是驱动程序的注册,会调用驱动程序的probe函数,之后会将

找到的设备的knode_driver添加进入注册的驱动程序的klist_devices列表
(3) 将驱动节点加入bus->klist_drivers,
(4) klist_add_tail(&drv->knode_bus, &bus->klist_drivers);

驱动的注销就是驱动注册的反安装

设备的注册:
首先要指定总线id,因为设备也是注册在某条总线下,

struct device {
 struct klist  klist_children; 链接所有子设备
 struct klist_node knode_parent;  对父设备的子节点 
 struct klist_node knode_driver; 链接到某驱动的klist_devices下
 struct klist_node knode_bus; 设备节点,总线链表是klist_devices
 struct device  * parent; 父设备
 struct kobject kobj; 设备对象
 char bus_id[BUS_ID_SIZE]; 注册前指点
 struct bus_type * bus; 所属总线
 struct device_driver *driver; 所属驱动,第一次没有,在probe下赋值
void  *driver_data; 可以由上层传入一些数据,在底层进行交换,编程的方法
void  *platform_data 同理
};

设备使用前要注册,调用device_register
(1) 将设备挂接在devices_subsys下,所有设备都挂在其下
(2) 用设备总线id给设备对象赋值
(3) 如果设备的驱动指针已经有值,则绑定dev->knode_driver到dev->driver->klist_devices
(4) 如果设备有驱动指针,则不会调用Probe
(5) 如果初次设备没有指定驱动程序,则所属总线会轮寻总线下所有驱动,调用驱动指向的总线下的Match函数,匹配名字字符

串相同的,如果找到,将这个驱动赋给设备的驱动指针,执行驱动的probe,绑定dev->knode_driver到dev->driver->klist_devices
(6) klist_add_tail(&dev->knode_bus, &bus->klist_devices);

在设计驱动模型的时候,主要要考虑抽象模型之间的关系。比如,Kobject是最基本的对象,在其中包含引用计数,对象名,链表节

点等基本信息,并且在Kobject层维护自身,
然后肯定是要在系统中,设定几个全局的变量,所以,定义了子系统的概念,,子系统有kset,可以将不同的对象链接在链表中,有

了全局的子系统的根,其他对象才能链接上去

在抽象模型中,总线是第一级,其他的设备和驱动,都挂接在某条总线下,设备对象是最下层的概念,设备挂接在devices_subsys和

总线下还有作为驱动的一个节点,驱动挂接在总线下,同时提供链表链接了符合该驱动的所有设备,这些都符合现实中的事物特征,

有了这些分析以后,就可以通过对象的注册方式,将不同的对象链接在一个系统中,
记住,系统中,肯定会有全局的对象,作为连接整个系统的根,在驱动模型中就是devices_subsys,bus_subsys,classes_subsys,

再例如,混杂设备,misc_list就是一个全局的变量,通过它其他混杂设备被连接在一起。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值