LINUX设备驱动模型分析之五 总线-设备-驱动模块总结

前面几篇文章我们对bus-device-driver模型进行了单独介绍,本篇文章我们对这三部分进行总结,同时对之前文章中未细化的部分进行详细说明。

bus-device-driver相关结构体关联

如下图是包含bus-device-driver的关联图,我们根据该流程图再次进行一下说明。

1.devices_kset集合说明

内核系统中在device模块的初始化接口中,创建了一个kset类型的全局变量devices_kset

该kset类型的全局变量,通过list成员集合了所有系统中已创建的device类型对应的kobject变量,

系统中依附在所有类型总线上的device,均会通过其对应的kobject变量,链接至devices_kset链表上。即通过devices_kset可找到系统中所有已创建的device。这一层关系和具体的bus-device-driver绑定没有关联。

2.bus_kset集合说明

内核系统中在bus模块初始化接口中,创建了一个kset类型的全局变量bus_kset。该全局变量

会将系统中所有已注册的总线类型对应的kobject链接在一起,通过该系统变量可以查看系统中所有已注册的总线类型。

3.bus->p->driver_kset集合说明

该变量和以上两个全局变量略有不同,该变量依附于具体的总线类型,仅在具体的总线变量创建时,方会创建该变量,该变量会将所有注册进其依附总线的驱动对应的kobject链接在一起。

4.bus->p->device_kset集合说明

该变量主要是总线变量的成员变量,系统中主要使用该kset对应的kobject以及与具体设备变量对应的kobject,这两个kobject相互创建链接子目录。(针对bus->p->device_kset与device类型变量对应的kobject的链接关系,没有在上面图中画出)

5.bus->p->klist_devices

该变量主要用于将所有注册至该总线上的device类型变量链接在一起,通过该变量可以查看该总线上当前已注册的设备。

6.bus->p->klist_drivers

该变量主要用于将所有注册至该总线上的device_driver类型变量链接在一起,通过该变量可以查看该总线上当前已注册的驱动。

总线类型通过klist_devices、klist_drivers,可以找到该总线上所有已注册的设备与驱动

7.device_driver->p->klist_devices

该变量主要用于链接所有已和该驱动绑定的设备,当进行设备与驱动的绑定或者解绑前,可通过遍历该链表确认执行操作的设备是否已在绑定列表中。

bus-device-driver的一些说明

下面我们主要是针对bus-device-driver再进行一些补充说明。

bus-device-driver的绑定操作

  1. 当系统中完成一个device的注册时,当完成device-bus相关的绑定(包括device、bus_type、kobject等绑定),会遍历该总线上所有已注册的驱动(通过遍历链表bus->p->klist_drivers实现),若该device与已注册的驱动匹配(如设备名称与驱动名称匹配等,匹配函数一般由总线类型变量中的match函数指针提供,如platform总线的match函数为platform_match),则再完成device-driver的绑定操作,并调用驱动的probe函数,完成对device的探测。对应函数为bus_probe_device、device_attach、__device_attach、driver_bound等。
  2. 当系统中完成一个driver的注册时,在完成driver-bus相关的绑定后,也会遍历该总线上所有已注册的设备(通过遍历链表bus->p->klist_devices实现),针对未进行device-driver绑定的设备,若device与该driver匹配,则完成device-driver的绑定操作,并调用驱动的probe函数,完成对device的探测。对应函数为driver_attach、__driver_attach、driver_probe_device、driver_bound等。

这也是总线变量中的klist_drivers、klist_devices变量的作用。

  1. 针对device结构体、driver结构体,一般会被嵌入更大的结构体中,用以实现具体总线类型的设备与驱动,如platform总线(platform_device、platform_driver)、i2c总线(i2c_client、i2c_driver、i2c_adapter)、pci总线(pci_dev、pci_driver)等。

而针对总线注册与注销接口、设备注册与注销接口、驱动注册与注销接口,也就是实现上面所说的关联罢了。

设备与驱动绑定时的探测接口调用

    当设备与驱动完成绑定时,会调用对应的探测接口,进行设备的初始化操作,如下即为探测接口的调用关系以及与bus、driver的关系。

      如下图所示,当调用device_register、driver_register接口进行设备与驱动的注册时,若设备与驱动匹配后,则调用总线的probe接口或者driver的probe接口进行探测。

通过总线的probe接口,最终也是调用driver->probe接口进行探测。而针对driver->probe

接口,最终会调用具体driver->probe(如platform_driver->probe、i2c_driver->probe、sp_driver->probe等),从driver->probe到xxx_driver->probe接口的调用,其实就是面向对象中的通过调用基类的接口,从而实现调用子类的接口。

设备与驱动解绑时的去除接口调用

当设备与驱动完成解绑时,会调用对应的remove接口,进行设备的移除时的处理操作,如下即为remove接口的调用关系以及与bus、driver的关系。

      如下图所示,当调用device_unregister、driverun_register接口进行设备的移除操作,通过调用总线的probe接口或者driver的probe接口进行移除操作。remove的流程与上面的probe流程类似,这个也是内核面向对象实现的一种。

 

对象的生命周期

我们知道kset、device、driver、bus_type类型的变量,均使用kobject->kref作为引用计数

使用,而针对kobject的释放也是通过该引用计数实现,当引用计数为0时,则释放该kobject,同时也会根据kobject->kobj_type->sysfs_ops->release接口,实现对kobject所嵌入的内存的释放操作。其处理流程如下所示

而针对kobject->kobj_type而言,针对bus_type,其定义如下,release接口为device_release;针对bus_type,其对应kobj_type定义如下,并没有为bus_type创建特定的release接口。

static void device_release(struct kobject *kobj)
{
	struct device *dev = kobj_to_dev(kobj);
	struct device_private *p = dev->p;

	/*
	 * Some platform devices are driven without driver attached
	 * and managed resources may have been acquired.  Make sure
	 * all resources are released.
	 *
	 * Drivers still can add resources into device after device
	 * is deleted but alive, so release devres here to avoid
	 * possible memory leak.
	 */
	devres_release_all(dev);

	if (dev->release)
		dev->release(dev);
	else if (dev->type && dev->type->release)
		dev->type->release(dev);
	else if (dev->class && dev->class->dev_release)
		dev->class->dev_release(dev);
	else
		WARN(1, KERN_ERR "Device '%s' does not have a release() "
			"function, it is broken and must be fixed.\n",
			dev_name(dev));
	kfree(p);
}

static const void *device_namespace(struct kobject *kobj)
{
	struct device *dev = kobj_to_dev(kobj);
	const void *ns = NULL;

	if (dev->class && dev->class->ns_type)
		ns = dev->class->namespace(dev);

	return ns;
}

static struct kobj_type device_ktype = {
	.release	= device_release,
	.sysfs_ops	= &dev_sysfs_ops,
	.namespace	= device_namespace,
};

static struct kobj_type bus_ktype = {
	.sysfs_ops	= &bus_sysfs_ops,
};

至此我们完成了设备驱动模型(bus-device-driver)的分析,下一篇文章我们将以platform总线为主介绍具体的总线及其设备与驱动的实现。

发布了140 篇原创文章 · 获赞 30 · 访问量 45万+

猜你喜欢

转载自blog.csdn.net/lickylin/article/details/102825859
今日推荐