Device_driver_model 设备驱动模型

本文详细介绍了Linux内核的设备驱动模型,包括kobject和kset的概念,sysfs文件系统与设备模型的关系,以及设备注册、驱动注册的过程。重点讲解了设备驱动probe的时机和相关函数调用,阐述了设备与驱动的匹配、初始化以及在sysfs中的表示。
摘要由CSDN通过智能技术生成

设备驱动模型

相关介绍

简单理解起来,设备驱动模型主要作用有两点:

  1. 在sysfs下形成树状层次结构,然后由sysfs文件系统作为设备入口。(以Kobject/Kset为主)
  2. 实现device、bus、driver的统一管理,方便设备与驱动的match和probe

框架大概是这样的:

Sysfs
Kobject/Kset
device–bus–driver
platform … SPI I2C

/sys 文件系统下的目录结构

/sys/devices 对所有设备的分层次表达
/sys/dev 维护一个按字符设备和块设备的主次号码(major:minor)链接到真实的设备(/sys/devices下)的符号链接文件
/sys/bus 这是内核设备按总线类型分层放置的目录结构, devices 中的所有设备都是连接于某种总线之下,在这里的每一种具体总线之下可以找到每一个具体设备的符号链接,它也是构成 Linux 统一设备模型的一部分;
/sys/class 这是按照设备功能分类的设备模型,如系统所有输入设备都会出现在 /sys/class/input 之下,而不论它们是以何种总线连接到系统。
/sys/block 这里是系统中当前所有的块设备所在 ,由于历史遗留问题一直存在,但在2.6.22开始已经被标记过时,为了向后兼容才保留着,但其内容已经链接到 /sys/devices/ 中真实设备的符号链接文件 。
/sys/firmware 这里是系统加载固件机制的对用户空间的接口,关于固件有专用于固件加载的一套API,在附录 LDD3 一书中有关于内核支持固件加载机制的更详细的介绍;
/sys/fs 这里按照设计是用于描述系统中所有文件系统,包括文件系统本身和按文件系统分类存放的已挂载点
/sys/module 这里有系统中所有模块的信息,不论这些模块是以内联(inlined)方式编译到内核映像文件(vmlinuz)中还是编译为外部模块(ko文件),都可能会出现在 /sys/module
/sys/power 这里是系统中电源选项,这个目录下有几个属性文件可以用于控制整个机器的电源状态,如可以向其中写入控制命令让机器关机、重启等。

不同的硬件平台上的设备是多种多样的,为了使设备都能抽象出来进行统一管理,Linux内核定义了一个kobject结构体,/sys下的每个目录都是通过kobject来抽象的,而kset即是一个特殊的kobject,也是同类型的kobject的一个集合,kobject和sysfs自然的绑定在一起,这样能方便组织驱动中的各种联系。

在Linux设备驱动模型中,主要需要的基本结构为

类型 内容 数据结构 /sys目录
设备(Devices) 设备是此模型中最基本的类型,以设备本身的连接按层次组织 strust device /sys/devices/*
设备驱动(Device Drivers) 在一个系统中安装多个相同设备,只需要一份驱动程序的支持 struct device_driver /sys/bus/pci/drivers/*
总线(Bus) 在整个总线级别对此总线上连接的所有设备进行管理 struct bus_type /sys/bus/*
设备类别(Device Classes) 这是按照功能进行分类组织的设备层次树;如 USB 接口和 PS/2 接口的鼠标都是输入设备,都会出现在 /sys/class/input/ 下 struct class /sys/class/*

kobject/kset

从内核实现sysfs层次结构时所使用的数据结构角度来入手分析,Linux 统一设备模型又是以两种基本数据结构(Kobject/Kset)进行树型和链表型结构组织的。

/******************************************************************************
* Kobject是基本的数据类型,每个Kobject都会在"/sys/“文件系统中以目录的形式出现。
* struct kref 内含一个 atomic_t 类型用于引用计数, parent 是单个指向父节点的指针, entry 
* 用于父 kset 以链表头结构将 kobject 结构维护成双向链表;
*******************************************************************************/
struct kobject {
   
	const  char			*name;  //Kobject名字
	struct list_head	entry;	//用于把kobject添加到Kset中的list_head
	struct kobject		*parent;//指向parent kobject,以此形成结构
	struct kset			*kset;  //该kobject属于的kset,可以设置为NULL。如果存在,且还未制定parent,会默认kset为parent
	struct kobj_type	*ktype; //该Kobject属于的kobj_type,每个Kobject必须有一个ktype。
	struct kernfs_node	 *sd; /* sysfs directory entry */
	struct kref		kref;	    //用于原子操作的引用计数。
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
	struct delayed_work	release; 
#endif
	unsigned int state_initialized:1;//表示是否初始化
	unsigned int state_in_sysfs:1;	 //指示该Kobject是否已在sysfs中呈现,以便在自动注销时从sysfs中移除。 
	unsigned int state_add_uevent_sent:1;
	unsigned int state_remove_uevent_sent:1;
	unsigned int uevent_suppress:1;  //如果该字段为1,则表示忽略所有上报的uevent事件。
};
/******************************************************************************
* kset类型是属于特定子系统的一组特定类型的kobjects。
* KSET定义了一组Kobjects。它们可以是不同的“类型”,但总体上,这些Kobjects都希望被分组在一
* 起,并以相同的方式操作。KSET用于定义Kobjects中发生的属性回调和其他常见事件。
*******************************************************************************/
struct kset {
   
	struct list_head list;  //该kset所有kobjects的list
	spinlock_t list_lock;	//
	struct kobject kobj;	//嵌入的kobject
	const struct kset_uevent_ops *uevent_ops; //kset操作函数
} ;

这里写图片描述

这三个kobjects同属于一个kset,在没有指定parent的情况下,默认为它们的parent为kset内嵌的kobject。

kobj_type

有一些kobject下会有一些属性,在 /sys 下表现形式就是文件,通过这些文件可以向用户提供一些接口操作。

/* /include/linux/kobject.h */
struct kobj_type {
   
	void (*release)(struct kobject *kobj); //释放kobject函数接口
	const struct sysfs_ops *sysfs_ops;	   //属性操作函数实现接口
	struct attribute **default_attrs;	   //属性定义
	const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
	const void *(*namespace)(struct kobject *kobj);
};

/* /include/linux/sysfs.h */
struct attribute {
   
	const char		*name;
	umode_t			mode;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
	bool			ignore_lockdep:1;
	struct lock_class_key	*key;
	struct lock_class_key	skey;
#endif
};

attribute, 属性。它以文件的形式输出到sysfs的目录当中。在kobject对应的目录下面。文件名就是name。文件读写的方法对应于kobj type中的sysfs ops。

小结

在Linux统一设备模型中,核心内容就是使用Bus、Class、Device、Driver四个核心数据结构,将大量不同功能的硬件设备以及驱动,以树状结构进行归纳、抽象,从而进行统一管理这也是kobject产生的原因。

目前为止,Kobject在设备模型中主要提供的功能为:

  1. 通过parent指针,可以将所有Kobject以层次结构的形式组合起来。
  2. 使用一个引用计数 kref,来记录Kobject被引用的次数,并在引用次数变为0时把它释放(这是Kobject诞生时的唯一功能)。
  3. 和sysfs虚拟文件系统配合,将每一个Kobject及其特性,以文件的形式,开放到用户空间。

由于kobject可以自动释放,使得kobject必须是动态分配的。而kobject大多数时候是内嵌在大型的数据结构中(如Kset、device_driver等),因此这些大型数据结构也是需要动态分配、动态释放的,释放的时机是内嵌的Kobject释放的时候。但是Kobject的释放是由Kobject模块自动完成的(在引用计数为0时),那么怎么一并释放包含自己的大型数据结构呢?

这时Kobj_type就派上用场了。我们知道,Kobj_type中的release回调函数负责释放Kobject(甚至是包含Kobject的数据结构)的内存空间,那么Kobj_type及其内部函数,是由谁实现呢?是由上层数据结构所在的模块!因为只有它,才清楚Kobject嵌在哪个数据结构中,并通过Kobject指针以及自身的数据结构类型,找到需要释放的上层数据结构的指针,然后释放它。

由此可知,每一个内嵌Kobject的数据结构,例如kset、device、device_driver等等,都要实现一个Ktype,并定义其中的回调函数。同理,sysfs相关的操作也一样,必须经过ktype的中转,因为sysfs看到的是Kobject,而真正的文件操作的主体,是内嵌Kobject的上层数据结构!

bus、device和driver的数据类型

/******************************************************************************
* bus_type 设备总线类型
*******************************************************************************/
struct bus_type {
   
	const char		*name; // 总线名称
	const char		*dev_name; // 用于子系统枚举像("foo%d",dev->id)这样的的设备
	struct device		*dev_root; // 用作父级的默认设备
	const struct attribute_group **bus_groups; //默认总线属性
	const struct attribute_group **dev_groups; //默认挂在在总线上设备的属性
	const struct attribute_group **drv_groups; //默认挂在在总线上设备的驱动属性

	int (*match)(struct device *dev, struct device_driver *drv);
    	// 回调函数,用于匹配 device和driver
	int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
    	// 回调函数,在device发生添加、移除或者其他动作时候调用,用来修改环境变量
	int (*probe)(struct device *dev); //初始化
	int (*remove)(struct device *dev);//移除设备
	void (*shutdown)(struct device *dev);

	int (*online)(struct device *dev);
	int (*offline)(struct device *dev);

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

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

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

	const struct dev_pm_ops *pm;

	const struct iommu_ops *iommu_ops;

	struct subsys_private *p; //私有数据,内有kset、klist
	struct lock_class_key lock_key;

	bool need_parent_lock;
};

/* /drivers/base/base.h */
struct subsys_private {
   
	struct kset subsys;  //在bus_type中代表bus本身,它下面可以包含其它的kset或者其它的kobject;
	struct kset *devices_kset; //bus下面所有的device
	struct list_head interfaces; //用于保存该bus下所有的interface。
	struct mutex mutex
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值