首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

platform bus平台总线详解

  • 25-03-04 14:02
  • 3374
  • 12560
blog.csdn.net

往期内容

  1. 驱动中的device和device_driver结构体-CSDN博客
  2. bus总线的相关结构体和注册逻辑-CSDN博客
  3. bus中设备驱动的probe触发逻辑和device、driver的添加逻辑-CSDN博客

前言

注:以下的代码皆摘自于linux 4.9.88版本的内核源码,不同版本可能有所出入。

之前的章节驱动中的device和device_driver结构体-CSDN博客讲过:Linux驱动开发很少直接使用device和device_driver,因为内核在它们之上又封装了一层,如platform device。内核在设备模型的基础上(device和device_driver),对这些设备进行了更进一步的**封装**,抽象出paltform bus、platform device和platform driver,以便驱动开发人员可以方便的开发这类设备的驱动。

画板

Platform Bus,基于底层bus模块,抽象出一个虚拟的Platform bus,用于挂载Platform设备;

Platform Device,基于底层device模块,抽象出Platform Device,用于表示Platform设备;

Platform Driver,基于底层device_driver模块,抽象出Platform Driver,用于驱动Platform设备。

1. struct platform_device

/*include/linux/platform_device.h*/
struct platform_device {
	const char	*name;
	int		id;
	bool		id_auto;
	struct device	dev;
	u32		num_resources;
	struct resource	*resource;

	const struct platform_device_id	*id_entry;
	char *driver_override; /* Driver name to force a match */

	/* MFD cell pointer */
	struct mfd_cell *mfd_cell;

	/* arch specific additions */
	struct pdev_archdata	archdata;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  1. const char *name:
    • 设备的名称。这个名称在设备注册时会被复制到其 struct device 中的 init_name 字段。它用于唯一标识设备,并且在设备和驱动的匹配过程中扮演着关键角色。多个设备可以具有相同的名称,但内核会利用其他属性(如 ID)来区分它们。
  2. **int id:
    • 设备的唯一标识符。它用于区分同一总线上的不同设备。在驱动的 probe 函数中,通过 ID 可以判断设备的具体信息,尤其是在多个同名设备的情况下。
    • 内核允许存在多个名称相同的设备。而设备驱动的probe,依赖于名称,Linux采取的策略是:在bus的设备链表中查找device,和对应的device_driver比对name,如果相同,则查看该设备是否已经绑定了driver(查看其dev->driver指针是否为空),如果已绑定,则不会执行probe动作,如果没有绑定,则以该device的指针为参数,调用driver的probe接口。因此,在driver的probe接口中,通过判断设备的ID,可以知道此次驱动的设备是哪个。
  3. bool id_auto:
    • 指示该设备的 ID 是否由内核自动分配。如果为 true,则在设备注册时无需手动指定 ID,内核会为其分配一个唯一的 ID。这使得开发者在注册设备时更为方便。
  4. struct device dev:
    • 这是一个通用的设备结构,包含了设备的所有基础属性和操作方法。platform_device 是一个特殊的设备,因此它继承了 struct device 的所有功能。这个字段用于与内核的设备模型集成。
  5. u32 num_resources:
    • 设备使用的资源数量。这个字段指明了设备在使用的资源(如中断、内存地址等)的个数。
  6. struct resource *resource:
    • 指向设备使用的资源的指针。资源由 struct resource 描述,它抽象了设备所需的硬件资源,如 I/O 地址、内存地址、IRQ 号等。通过这个结构,内核可以管理这些资源的分配和释放,确保没有两个设备同时占用同一资源。
    • 在Linux中,系统资源包括I/O、Memory、Register、IRQ、DMA、Bus等多种类型。这些资源大多具有独占性,不允许多个设备同时使用,因此Linux内核提供了一些API,用于分配、管理这些资源。当某个设备需要使用某些资源时,只需利用struct resource组织这些资源(如名称、类型、起始、结束地址等),并保存在该设备的resource指针中即可。然后在设备probe时,设备需求会调用资源管理接口,分配、使用这些资源。而内核的资源管理逻辑,可以判断这些资源是否已被使用、是否可被使用等等。
  7. const struct platform_device_id *id_entry:
    • 指向与该平台设备相关的设备 ID 匹配表。该表定义了哪些驱动程序可以与此设备匹配。驱动程序在加载时会检查其 ID 列表,以便找到适合的设备。
  8. char *driver_override:
    • 用于强制设备与特定驱动匹配的驱动名称。如果某个设备需要特定的驱动而不想由内核自动选择,开发者可以在此字段中设置驱动名称。
  9. struct mfd_cell *mfd_cell:
    • 指向多功能设备(MFD)单元的指针。MFD 设备允许多个子设备通过同一个驱动进行管理,适用于复杂的硬件结构。
  10. struct pdev_archdata archdata:
    • 存储架构特定的附加数据。由于不同的硬件平台有不同的需求和实现,该字段允许每种架构定义自己特有的数据结构和成员。虽然这个设计可能显得灵活,但也让代码的可维护性和清晰性受到了挑战。

struct platform_device 结构体是 Linux 内核设备模型中处理平台设备的核心数据结构。它不仅存储了设备的基本信息,如名称和 ID,还管理了设备所需的硬件资源,并提供了与驱动程序匹配的必要信息。通过这个结构,内核能够有效地管理和控制平台设备的生命周期和资源使用。

2. struct platform_driver

struct platform_driver {
	int (*probe)(struct platform_device *);
	int (*remove)(struct platform_device *);
	void (*shutdown)(struct platform_device *);
	int (*suspend)(struct platform_device *, pm_message_t state);
	int (*resume)(struct platform_device *);
	struct device_driver driver;
	const struct platform_device_id *id_table;
	bool prevent_deferred_probe;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  1. int (*probe)(struct platform_device *);:
    • 指向一个函数,该函数在驱动程序与设备匹配时被调用。probe 函数的主要作用是初始化设备、分配资源、注册字符设备等。它是设备驱动的入口点,执行设备的设置和配置操作。
  2. int (*remove)(struct platform_device *);:
    • 指向一个函数,该函数在设备被移除时被调用。通常,这个函数负责释放 probe 中分配的资源,注销字符设备等。它确保在设备被卸载时正确清理和释放所有相关资源。
  3. void (*shutdown)(struct platform_device *);:
    • 指向一个函数,在系统关闭或设备驱动被卸载时调用。这个函数通常用于保存设备状态和进行最后的清理,以确保设备可以安全关闭。
  4. int (*suspend)(struct platform_device *, pm_message_t state);:
    • 指向一个函数,在设备进入低功耗状态时被调用。该函数会处理设备的挂起逻辑,如关闭某些功能、保存设备状态等。pm_message_t 参数用于指示挂起的类型(如休眠、待机等)。
  5. **int (*resume)(struct platform_device *);**:
    • 指向一个函数,在设备从挂起状态恢复时调用。该函数负责重新初始化设备并恢复其之前的状态,以便设备可以继续正常操作。
  6. struct device_driver driver;:
    • 这是一个基础的设备驱动结构,包含了设备驱动的通用属性和功能。通过这个字段,platform_driver 继承了设备驱动的基本功能,包括驱动的名称、所属总线等。
  7. const struct platform_device_id *id_table;:
    • 指向与该平台驱动匹配的设备 ID 表。它的功能与 of_match_table 和 acpi_match_table 类似,为驱动提供其他匹配设备的方式。通过这个表,内核可以根据设备 ID 来判断驱动是否适用于特定设备,而不仅仅依赖于设备名称。
  8. bool prevent_deferred_probe;:
    • 这个字段用于控制是否阻止延迟探测。延迟探测是指在设备驱动无法立即匹配设备时,内核将其推迟到稍后的时间来进行匹配。如果将此字段设置为 true,则驱动在匹配时会立即进行,而不会被延迟处理。

struct platform_driver 提供了一种描述平台设备驱动的机制,包含了多种操作的回调函数,以支持设备的生命周期管理,如初始化、移除、挂起和恢复等。此外,它通过 id_table 提供了更灵活的设备匹配方式,允许驱动在不同的条件下识别和管理多个设备。这使得平台驱动可以更有效地与硬件交互,提供稳定和高效的设备支持。

3. API

3.1 Platform Device

Platform Device主要提供设备的分配、注册等接口,供其它driver使用。在 Linux 内核中,platform_device 代表平台设备,include/linux/platform_device.h 中提供了一系列 API 来注册、管理和使用这些设备。具体包括:

1. 设备注册与注销

int platform_device_register(struct platform_device *);
● 功能: 注册一个平台设备,使其在内核中可用。
● 参数: struct platform_device *pdev,指向要注册的设备结构体。
● 返回值: 返回 0 表示成功,负值表示错误。

void platform_device_unregister(struct platform_device *);
● 功能: 注销一个已注册的平台设备。
● 参数: struct platform_device *pdev,指向要注销的设备结构体。
● 注意: 注销后设备将不再可用。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

2. 设备资源和 IRQ 管理

struct resource *platform_get_resource(struct platform_device *, unsigned int, unsigned int);
● 功能: 获取与设备关联的资源。
● 参数:
  ○ struct platform_device *pdev:目标设备。
  ○ unsigned int type:资源类型(如 I/O、内存等)。
  ○ unsigned int num:资源的索引。
● 返回值: 返回指向资源结构的指针,或返回 NULL 如果没有找到。

int platform_get_irq(struct platform_device *, unsigned int);
● 功能: 获取与设备关联的 IRQ。
● 参数: 
  ○ struct platform_device *pdev:目标设备。
  ○ unsigned int num:IRQ 的索引。
● 返回值: 返回 IRQ 号,或负值表示错误。

struct resource *platform_get_resource_byname(struct platform_device *, unsigned int, const char *);
● 功能: 根据资源名称获取资源。
● 参数: 
  ○ struct platform_device *pdev:目标设备。
  ○ unsigned int type:资源类型。
  ○ const char *name:资源名称。
● 返回值: 返回指向资源结构的指针,或返回 NULL 如果没有找到。

int platform_get_irq_byname(struct platform_device *, const char *);
● 功能: 根据名称获取 IRQ。
● 参数: 
  ○ struct platform_device *pdev:目标设备。
  ○ const char *name:IRQ 名称。
● 返回值: 返回 IRQ 号,或负值表示错误。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

3. 设备数组管理

int platform_add_devices(struct platform_device **, int);
● 功能: 注册一个平台设备数组。
● 参数: 
  ○ struct platform_device **pdevs:指向设备指针数组。
  ○ int count:数组中的设备数量。
● 返回值: 返回 0 表示成功,负值表示错误。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

4. 设备注册的简化接口

struct platform_device *platform_device_register_full(const struct platform_device_info *pdevinfo);
● 功能: 完整注册平台设备,使用 platform_device_info 结构提供的详细信息。
● 参数: const struct platform_device_info *pdevinfo:设备信息结构体。
● 返回值: 返回指向已注册设备的指针,或返回 NULL 如果失败。

struct platform_device *platform_device_register_resndata(struct device *parent, const char *name, int id, const struct resource *res, unsigned int num, const void *data, size_t size);
● 功能: 注册一个带资源和数据的平台设备。
● 参数: 
  ○ struct device *parent:设备父级。
  ○ const char *name:设备名称。
  ○ int id:设备 ID。
  ○ const struct resource *res:资源数组。
  ○ unsigned int num:资源数量。
  ○ const void *data:附加数据。
  ○ size_t size:数据大小。
● 返回值: 返回指向已注册设备的指针,或返回 NULL 如果失败。

struct platform_device *platform_device_register_simple(const char *name, int id, const struct resource *res, unsigned int num);
● 功能: 简单注册一个平台设备,提供名称、ID 和资源。
● 参数: 
  ○ const char *name:设备名称。
  ○ int id:设备 ID。
  ○ const struct resource *res:资源数组。
  ○ unsigned int num:资源数量。
● 返回值: 返回指向已注册设备的指针,或返回 NULL 如果失败。

struct platform_device *platform_device_register_data(struct device *parent, const char *name, int id, const void *data, size_t size);
● 功能: 注册一个带数据的平台设备。
● 参数: 
  ○ struct device *parent:设备父级。
  ○ const char *name:设备名称。
  ○ int id:设备 ID。
  ○ const void *data:附加数据。
  ○ size_t size:数据大小。
● 返回值: 返回指向已注册设备的指针,或返回 NULL 如果失败。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

5. 设备内存和资源管理

struct platform_device *platform_device_alloc(const char *name, int id);
● 功能: 分配内存用于一个平台设备,但不注册。
● 参数: 
  ○ const char *name:设备名称。
  ○ int id:设备 ID。
● 返回值: 返回指向分配的设备的指针,或返回 NULL 如果失败。

int platform_device_add_resources(struct platform_device *pdev, const struct resource *res, unsigned int num);
● 功能: 向平台设备添加资源。
● 参数: 
  ○ struct platform_device *pdev:目标设备。
  ○ const struct resource *res:资源数组。
  ○ unsigned int num:资源数量。
● 返回值: 返回 0 表示成功,负值表示错误。

int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size);
● 功能: 向平台设备添加附加数据。
● 参数: 
  ○ struct platform_device *pdev:目标设备。
  ○ const void *data:附加数据。
  ○ size_t size:数据大小。
● 返回值: 返回 0 表示成功,负值表示错误。

int platform_device_add(struct platform_device *pdev);
● 功能: 注册一个已分配的设备。
● 参数: struct platform_device *pdev:目标设备。
● 返回值: 返回 0 表示成功,负值表示错误。

void platform_device_del(struct platform_device *pdev);
● 功能: 删除并注销设备,但不释放内存。
● 参数: struct platform_device *pdev:目标设备。

void platform_device_put(struct platform_device *pdev);
● 功能: 释放对设备的引用。 
● 参数: struct platform_device *pdev:目标设备。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

3.2 Platform Driver

在 Linux 内核中,platform_driver 结构体与 platform_device 结构体配合使用,提供了对平台设备驱动的管理和操作。这部分代码主要定义了与平台驱动相关的 API。以下是对这些 API 的详细说明:

1. 驱动注册与注销

int platform_driver_register(struct platform_driver *);
● 功能: 注册一个平台驱动,使其在内核中可用。
● 参数: 
  ○ struct platform_driver *driver:指向要注册的驱动结构体。
● 返回值: 返回 0 表示成功,负值表示错误。成功注册后,内核会在适当的时候调用该驱动的 probe 函数。

void platform_driver_unregister(struct platform_driver *);
● 功能: 注销一个已注册的平台驱动。
● 参数: 
  ○ struct platform_driver *driver:指向要注销的驱动结构体。
● 注意: 注销后驱动将不再可用,内核会停止调用该驱动的相关回调函数。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

2. 驱动探测

int platform_driver_probe(struct platform_driver *driver, int (*probe)(struct platform_device *));
● 功能: 手动执行驱动的 probe 函数。
● 参数: 
  ○ struct platform_driver *driver:指向要探测的驱动结构体。
  ○ int (*probe)(struct platform_device *):指向 probe 函数的指针,probe 函数的作用是初始化设备。
● 返回值: 返回 0 表示成功,负值表示错误。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

3. 驱动数据管理

static inline void *platform_get_drvdata(const struct platform_device *pdev);
● 功能: 获取与平台设备关联的驱动数据。
● 参数: 
  ○ const struct platform_device *pdev:指向目标设备的指针。
● 返回值: 返回指向设备关联数据的指针。如果没有数据,则返回 NULL。

static inline void platform_set_drvdata(struct platform_device *pdev, void *data);
● 功能: 设置与平台设备关联的驱动数据。
● 参数: 
  ○ struct platform_device *pdev:指向目标设备的指针。
  ○ void *data:要与设备关联的数据指针。
● 注意: 通过 set_drvdata 函数,驱动可以存储与设备相关的上下文数据,以便后续在 probe、remove 或其他回调函数中使用。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

这些 API 提供了对平台驱动的管理和操作,包括驱动的注册、注销、探测以及与设备关联的数据的设置和获取。通过这些函数,开发者能够有效地控制平台驱动的生命周期和与之相关的状态信息,增强了内核对硬件设备的支持能力。

4. platform device和platform driver的注册

在 Linux 内核中,platform_device 和 platform_driver 的注册过程是通过 platform_device_add 和 platform_driver_register 这两个接口实现的。以下是对这两个接口的详细内部动作的解析。

4.1 platform_device_add 的内部动作

Linux-4.9.88\drivers\base\platform.c:
**
 * platform_device_add - add a platform device to device hierarchy
 * @pdev: platform device we're adding
 *
 * This is part 2 of platform_device_register(), though may be called
 * separately _iff_ pdev was allocated by platform_device_alloc().
 */
int platform_device_add(struct platform_device *pdev)
{
	int i, ret;

	if (!pdev)
		return -EINVAL;

	if (!pdev->dev.parent)
		pdev->dev.parent = &platform_bus;

	pdev->dev.bus = &platform_bus_type;

	switch (pdev->id) {
	default:
		dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
		break;
	case PLATFORM_DEVID_NONE:
		dev_set_name(&pdev->dev, "%s", pdev->name);
		break;
	case PLATFORM_DEVID_AUTO:
		/*
		 * Automatically allocated device ID. We mark it as such so
		 * that we remember it must be freed, and we append a suffix
		 * to avoid namespace collision with explicit IDs.
		 */
		ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL);
		if (ret < 0)
			goto err_out;
		pdev->id = ret;
		pdev->id_auto = true;
		dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id);
		break;
	}

	for (i = 0; i < pdev->num_resources; i++) {
		struct resource *p, *r = &pdev->resource[i];

		if (r->name == NULL)
			r->name = dev_name(&pdev->dev);

		p = r->parent;
		if (!p) {
			if (resource_type(r) == IORESOURCE_MEM)
				p = &iomem_resource;
			else if (resource_type(r) == IORESOURCE_IO)
				p = &ioport_resource;
		}

		if (p && insert_resource(p, r)) {
			dev_err(&pdev->dev, "failed to claim resource %d\n", i);
			ret = -EBUSY;
			goto failed;
		}
	}

	pr_debug("Registering platform device '%s'. Parent at %s\n",
		 dev_name(&pdev->dev), dev_name(pdev->dev.parent));

	ret = device_add(&pdev->dev);
	if (ret == 0)
		return ret;

 failed:
	if (pdev->id_auto) {
		ida_simple_remove(&platform_devid_ida, pdev->id);
		pdev->id = PLATFORM_DEVID_AUTO;
	}

	while (--i >= 0) {
		struct resource *r = &pdev->resource[i];
		if (r->parent)
			release_resource(r);
	}

 err_out:
	return ret;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  1. 父设备设置:
    • 如果设备没有指定父设备,则将其父设备设置为 platform_bus,即 /sys/devices/platform/ 代表的设备。
    • 这意味着设备的 sysfs 目录会被创建为 /sys/devices/platform/xxx_device。
  2. 设置设备总线:
    • 将设备的 bus 指针指定为 platform_bus_type:
pdev->dev.bus = &platform_bus_type;
  • 1
  1. 名称和 ID 处理:
    • 根据设备的 ID 修改或设置设备的名称。对于多个同名的设备,通过 ID 区分设备。在这里,将实际名称修改为 name.id 的形式,例如:
spi_device1
  • 1
  1. 资源管理:
    • 调用 resource 模块的 insert_resource 接口,将该设备需要使用的资源统一管理起来。此时,资源模块会知道该设备所需的资源,这样它就可以进行相应的管理。
  2. 添加设备到内核:
    • 调用 device_add 接口,将内嵌的 struct device 变量添加到内核中,使设备在内核中可用。

4.2 platform_driver_register 的内部动作

Linux-4.9.88\include\linux\platform_device.h
#define platform_driver_register(drv) \
	__platform_driver_register(drv, THIS_MODULE)

/**
 * __platform_driver_register - register a driver for platform-level devices
 * @drv: platform driver structure
 * @owner: owning module/driver
 */
int __platform_driver_register(struct platform_driver *drv,
				struct module *owner)
{
	drv->driver.owner = owner;
	drv->driver.bus = &platform_bus_type;
	drv->driver.probe = platform_drv_probe;
	drv->driver.remove = platform_drv_remove;
	drv->driver.shutdown = platform_drv_shutdown;

	return driver_register(&drv->driver);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  1. 设置驱动总线:
    • 将驱动的 bus 指针指定为 platform_bus_type:
drv->driver.bus = &platform_bus_type;
  • 1
  1. 回调函数指针设置:
    • 如果该平台驱动提供了 probe、remove、shutdown 等回调函数,则将它内嵌的 struct driver 变量的这些指针设置为平台模块提供的函数,例如:
      • probe 函数指针设置为 platform_drv_probe
      • remove 函数指针设置为 platform_drv_remove
      • shutdown 函数指针设置为 platform_drv_shutdown
    • 通过这种方式,probe 等动作将从 struct driver 变量开始,经过 platform_drv_xxx 等接口的转接,最终调用到平台驱动自身的回调函数中。
  2. 驱动注册到内核:
    • 调用 driver_register 接口,将内嵌的 struct driver 变量添加到内核中,使驱动在内核中可用。

诶?最后不还是调用到了driver_register,而driver_register最后还是会去调用bus_add_driver函数,所以说这玩意其实就是嵌套的。

5. 平台设备的probe

在Bus中讲过设备驱动的probe的触发逻辑,其实在platform中也差不多,注册添加platform_driver时会触发probe,只不过包装了一下而已

bus中设备驱动的probe触发逻辑和device、driver的添加逻辑-CSDN博客

6. 联系

drivers/base/platform.c、dd.c

其实看一个图,兴许就能明白bus、driver/device、platform_deivce/platform_driver之间的关系:

画板

可以很清楚的看出,最后时调用了driver_attach操作,去进行遍历是否有匹配的device(主要依靠下面的_driver_attach,后面会讲到):

如果找到了最后肯定会调用到driver中的probe函数,其probe函数也在__driver_attach中体现:

最后就调用了自己驱动定义的probe函数。

7. 匹配规则

drivers/base/platform.c、dd.c

最后简单讲一下platform_device和platform_driver之间的匹配方式:

下面该函数在上面也讲到了,会去遍历是否有匹配的device,匹配就调用参四__driver_attach函数,里面会去调用bus_probe_device函数去调用驱动程序的probe

dd.c

匹配主要发生在__driver_attach中:

最后通过这张图就可以简单了解到匹配的四种方式

文章知识点与官方知识档案匹配,可进一步学习相关知识
C技能树首页概览220410 人正在系统学习中
注:本文转载自blog.csdn.net的憧憬一下的文章"https://blog.csdn.net/caiji0169/article/details/142747461"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top