RK3568驱动指南|第九篇 设备模型-第110章 加载驱动和加载设备先后顺序分析实验

发布时间:2024年01月05日

瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568 支持安卓 11 和 linux 系统,主要面向物联网网关、NVR 存储、工控平板、工业检测、工控盒、卡拉 OK、云终端、车载中控等行业。

?
【公众号】迅为电子

【粉丝群】824412014(加群获取驱动文档+例程)

【视频观看】嵌入式学习之Linux驱动(第九期_设备模型_全新升级)_基于RK3568

【购买链接】迅为RK3568开发板瑞芯微Linux安卓鸿蒙ARM核心板人工智能AI主板???????


第110章?加载驱动和加载设备先后顺序分析实验

经过前面的实验章节,我们不管是先加载device.ko还是driver.ko,驱动和设备都可以匹配成功。所以我们可以猜测不管是device驱动还是driver驱动,都会有匹配操作。

在drivers/base/core.c文件中的device_ add 函数中调用了bus_ probe_ device 函数。如下图所示:

图110-1

bus_ probe_ device 函数,如下图所示,此函数中最重要的是device_initial_probe函数

图110-2

device_initial_probe函数,如下所示

图110-3

__device_attach函数如下所示:

static int __device_attach(struct device *dev, bool allow_async)
{
	int ret = 0;

	device_lock(dev);
	if (dev->p->dead) {
		goto out_unlock;
	} else if (dev->driver) {
		// 如果设备已经绑定了驱动程序,则返回1
		if (device_is_bound(dev)) {
			ret = 1;
			goto out_unlock;
		}
		// 尝试将设备与驱动程序进行绑定
		ret = device_bind_driver(dev);
		if (ret == 0)
			ret = 1;
		else {
			// 绑定失败,将设备的驱动程序指针置为NULL
			dev->driver = NULL;
			ret = 0;
		}
	} else {
		// 如果设备没有驱动程序,需要遍历总线上的驱动程序进行匹配
		struct device_attach_data data = {
			.dev = dev,
			.check_async = allow_async,
			.want_async = false,
		};

		// 如果设备有父设备,调用 pm_runtime_get_sync() 增加父设备的引用计数
		if (dev->parent)
			pm_runtime_get_sync(dev->parent);

		// 遍历总线上的驱动程序,调用 __device_attach_driver() 进行匹配
		ret = bus_for_each_drv(dev->bus, NULL, &data,
					__device_attach_driver);
		if (!ret && allow_async && data.have_async) {
			/*
			 * 如果无法同步找到适合的驱动程序,并且允许异步探测以及有驱动程序要求异步探测,
			 * 则尝试进行异步探测。
			 */
			dev_dbg(dev, "scheduling asynchronous probe\n");
			// 增加设备的引用计数,以确保在异步探测期间设备不会被释放
			get_device(dev);
			// 调度异步任务 __device_attach_async_helper() 进行异步探测
			async_schedule(__device_attach_async_helper, dev);
		} else {
			// 如果无法异步探测或者没有驱动程序要求异步探测,则调用 pm_request_idle() 进入空闲状态
			pm_request_idle(dev);
		}

		// 如果设备有父设备,调用 pm_runtime_put() 减少父设备的引用计数
		if (dev->parent)
			pm_runtime_put(dev->parent);
	}
out_unlock:
	// 解锁设备
	device_unlock(dev);
	return ret;
}

__device_attach函数的主要逻辑如下:

首先,通过调用 device_lock(dev) 锁定设备,确保在进行设备附加操作时不会被其他线程干扰。接下来,检查设备的状态。如果设备已经被标记为死亡,那么直接跳转到解锁设备的位置,并返回0。

如果设备已经绑定了驱动程序,则返回1。如果设备没有绑定驱动程序,则尝试将设备与驱动程序进行绑定。如果绑定成功,返回1;否则,将设备的驱动程序指针置为NULL,并返回0。

如果设备既没有绑定驱动程序,也没有被标记为死亡,那么需要遍历总线上的驱动程序进行匹配。为此,定义了一个结构体 struct device_attach_data,其中包含了设备、是否允许异步探测以及是否有驱动程序要求异步探测的信息。

如果设备有父设备,调用 pm_runtime_get_sync(dev->parent) 增加父设备的引用计数。

调用 bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver) 遍历总线上的驱动程序,并调用 __device_attach_driver 进行匹配。__device_attach_driver 是一个回调函数,用于判断驱动程序是否适配当前设备。

如果无法同步找到适合的驱动程序,并且允许异步探测以及有驱动程序要求异步探测,则调度异步任务 __device_attach_async_helper 进行异步探测。在异步探测之前,会增加设备的引用计数以确保设备在异步探测期间不会被释放。异步探测会在后台进行,不会阻塞当前线程。

如果无法异步探测或者没有驱动程序要求异步探测,则调用 pm_request_idle(dev) 进入空闲状态,让设备进入省电模式。

在上述函数中,使用device_bind_driver函数将设备与驱动程序进行绑定,如下所示:

图110-4

driver_bound函数如下所示,用于将驱动程序绑定到设备上。

static void driver_bound(struct device *dev)
{
	if (device_is_bound(dev)) {
		// 如果设备已经绑定了驱动程序,则输出警告信息并返回
		printk(KERN_WARNING "%s: device %s already bound\n",
			__func__, kobject_name(&dev->kobj));
		return;
	}

	// 输出绑定信息
	pr_debug("driver: '%s': %s: bound to device '%s'\n", dev->driver->name,
		 __func__, dev_name(dev));

	// 将设备添加到驱动程序的设备链表中
	klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);

	// 更新设备的驱动程序链接状态
	device_links_driver_bound(dev);

	// 检查设备的电源管理回调函数
	device_pm_check_callbacks(dev);

	/*
	 * 确保设备不再位于延迟探测列表中,并启动重试所有待处理设备
	 */
	driver_deferred_probe_del(dev);
	driver_deferred_probe_trigger();

	// 如果设备有总线,调用总线通知链进行通知
	if (dev->bus)
		blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
					     BUS_NOTIFY_BOUND_DRIVER, dev);

	// 发送内核对象事件通知
	kobject_uevent(&dev->kobj, KOBJ_BIND);
}

上述代码的作用是将驱动和设备进行绑定,首先,通过调用 device_is_bound(dev) 检查设备是否已经绑定了驱动程序。如果设备已经绑定了驱动程序,则输出警告信息并返回。如果设备未绑定驱动程序,将输出绑定信息,其中包括驱动程序的名称、函数名和设备的名称。接下来,通过调用 klist_add_tail() 将设备添加到驱动程序的设备链表中。这样,驱动程序可以通过遍历该链表来访问所有已绑定的设备。

然后,调用 device_links_driver_bound() 更新设备的驱动程序链接状态。这个函数会确保设备和驱动程序之间的链接关系是正确的。

至此,加载驱动和加载设备先后顺序分析完毕。


文章来源:https://blog.csdn.net/BeiJingXunWei/article/details/135392337
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。