一文看懂Linux内核Device和Driver匹配原理

一、Driver初始化

每个驱动程序都有自己的init函数,但是这些init函数是如何初始化的?
两种假设:
1、放到一个总的init函数,我们把init函数填入这个函数?
2、放到一个专用的init文件,我们把init函数填入这个头文件?
Linux处理方式:
—在编译的镜像文件中定义一个INIT_CALL段(section),存放init函数的指针
—用module_init等宏定义将init函数填入对应INIT_CALL段中;
—用不同的init level实现初始化先后顺序的分级;

1、INIT_CALL段的定义

源码位置:
Kernel/include/asm-generic/vmlinux.lds.h

1.1、添加INIT_CALLS到initdata段

#define INIT_DATA_SECTION(initsetup_align)				\
	.init.data : AT(ADDR(.init.data) - LOAD_OFFSET) {		\
		INIT_DATA						\
		INIT_SETUP(initsetup_align)				\
		INIT_CALLS						\
		CON_INITCALL						\
		INIT_RAM_FS						\
	}

1.2、定义INIT_CALLS

#define INIT_CALLS							\
		__initcall_start = .;					\
		KEEP(*(.initcallearly.init))				\
		INIT_CALLS_LEVEL(0)					\
		INIT_CALLS_LEVEL(1)					\
		INIT_CALLS_LEVEL(2)					\
		INIT_CALLS_LEVEL(3)					\
		INIT_CALLS_LEVEL(4)					\
		INIT_CALLS_LEVEL(5)					\
		INIT_CALLS_LEVEL(rootfs)				\
		INIT_CALLS_LEVEL(6)					\
		INIT_CALLS_LEVEL(7)					\
		__initcall_end = .;

1.3、定义INIT_CALLS_LEVEL

#define INIT_CALLS_LEVEL(level)						\
		__initcall##level##_start = .;				\
		KEEP(*(.initcall##level##.init))			\
		KEEP(*(.initcall##level##s.init))			\

举例展开后level=6

#define INIT_CALLS_LEVEL(6)						\
		__initcall6_start = .;				\
		KEEP(*(.initcall6.init))			\
		KEEP(*(.initcall6s.init))
#define INIT_CALLS							\
		__initcall_start = .;					\
		KEEP(*(.initcallearly.init))    \
        __initcall0_start                   \
        KEEP(*(.initcall0.init))			\
		KEEP(*(.initcall0s.init))        \
		 __initcall1_start                   \
        KEEP(*(.initcall1.init))			\
		KEEP(*(.initcall1s.init))        \
		 __initcall2_start                   \
        KEEP(*(.initcall2.init))			\
		KEEP(*(.initcall2s.init))        \
		 __initcall3_start                   \
        KEEP(*(.initcall3.init))			\
		KEEP(*(.initcall3s.init))        \
		 __initcall4_start                   \
        KEEP(*(.initcall4.init))			\
		KEEP(*(.initcall4s.init))        \
		 __initcall5_start                   \
        KEEP(*(.initcall5.init))			\
		KEEP(*(.initcall5s.init))        \
		 __initcall6_start                   \
        KEEP(*(.initcall6.init))			\
		KEEP(*(.initcall6s.init))        \
		 __initcall7_start                   \
        KEEP(*(.initcall7.init))			\
		KEEP(*(.initcall7s.init))        \
		__initcall_end = .;

2、init宏的展开

2.1、源码解析

源码位置:
#include <linux/module.h>

#ifndef MODULE
/**
 * module_init() - driver initialization entry point
 * @x: function to be run at kernel boot time or module insertion
 *
 * module_init() will either be called during do_initcalls() (if
 * builtin) or at module insertion time (if a module).  There can only
 * be one per module.
 */
#define module_init(x)	__initcall(x);

/**
 * module_exit() - driver exit entry point
 * @x: function to be run when driver is removed
 *
 * module_exit() will wrap the driver clean-up code
 * with cleanup_module() when used with rmmod when
 * the driver is a module.  If the driver is statically
 * compiled into the kernel, module_exit() has no effect.
 * There can only be one per module.
 */
#define module_exit(x)	__exitcall(x);

#else /* MODULE */

/*
 * In most cases loadable modules do not need custom
 * initcall levels. There are still some valid cases where
 * a driver may be needed early if built in, and does not
 * matter when built as a loadable module. Like bus
 * snooping debug drivers.
 */
#define early_initcall(fn)		module_init(fn)
#define core_initcall(fn)		module_init(fn)
#define core_initcall_sync(fn)		module_init(fn)
#define postcore_initcall(fn)		module_init(fn)
#define postcore_initcall_sync(fn)	module_init(fn)
#define arch_initcall(fn)		module_init(fn)
#define subsys_initcall(fn)		module_init(fn)
#define subsys_initcall_sync(fn)	module_init(fn)
#define fs_initcall(fn)			module_init(fn)
#define fs_initcall_sync(fn)		module_init(fn)
#define rootfs_initcall(fn)		module_init(fn)
#define device_initcall(fn)		module_init(fn)
#define device_initcall_sync(fn)	module_init(fn)
#define late_initcall(fn)		module_init(fn)
#define late_initcall_sync(fn)		module_init(fn)

#define console_initcall(fn)		module_init(fn)

/* Each module must use one module_init(). */
#define module_init(initfn)					\
	static inline initcall_t __maybe_unused __inittest(void)		\
	{ return initfn; }					\
	int init_module(void) __copy(initfn) __attribute__((alias(#initfn)));

/* This is only required if you want to be unloadable. */
#define module_exit(exitfn)					\
	static inline exitcall_t __maybe_unused __exittest(void)		\
	{ return exitfn; }					\
	void cleanup_module(void) __copy(exitfn) __attribute__((alias(#exitfn)));

#endif

源码位置:
#include <linux/init.h>

/*
 * A "pure" initcall has no dependencies on anything else, and purely
 * initializes variables that couldn't be statically initialized.
 *
 * This only exists for built-in code, not for modules.
 * Keep main.c:initcall_level_names[] in sync.
 */
#define pure_initcall(fn)		__define_initcall(fn, 0)

#define core_initcall(fn)		__define_initcall(fn, 1)
#define core_initcall_sync(fn)		__define_initcall(fn, 1s)
#define postcore_initcall(fn)		__define_initcall(fn, 2)
#define postcore_initcall_sync(fn)	__define_initcall(fn, 2s)
#define arch_initcall(fn)		__define_initcall(fn, 3)
#define arch_initcall_sync(fn)		__define_initcall(fn, 3s)
#define subsys_initcall(fn)		__define_initcall(fn, 4)
#define subsys_initcall_sync(fn)	__define_initcall(fn, 4s)
#define fs_initcall(fn)			__define_initcall(fn, 5)
#define fs_initcall_sync(fn)		__define_initcall(fn, 5s)
#define rootfs_initcall(fn)		__define_initcall(fn, rootfs)
#define device_initcall(fn)		__define_initcall(fn, 6)
#define device_initcall_sync(fn)	__define_initcall(fn, 6s)
#define late_initcall(fn)		__define_initcall(fn, 7)
#define late_initcall_sync(fn)		__define_initcall(fn, 7s)

#define __initcall(fn) device_initcall(fn)

#define __exitcall(fn)						\
	static exitcall_t __exitcall_##fn __exit_call = fn

#define console_initcall(fn)	___define_initcall(fn,, .con_initcall)
#define ___define_initcall(fn, id, __sec) \
	static initcall_t __initcall_##fn##id __used \
		__attribute__((__section__(#__sec ".init"))) = fn;

__used:编译参数,告诉编译器这个变量是使用的,不是定义了未使用的变量,避免编译warning和error

attribute((section(“.initcall” #id “.init”)))编译参数,通知编译器把__initcall_fnid写入section initcallid.init中

module_init()初始化过程:
Module_init()–>__initcall–>device_initcall–>level6

2.2、module_init展开

1 定义了一个函数指针:__initcall_fnid
2 函数指针指向:fn
3 函数指针写入固定的section:.initcallid.init

展开后:
static initcall_t __initcall_fnid = fn

2.3、System.map中INIT_CALL段:

ffffffc0017dad78 T __initcall_start

ffffffc0017daf38 T __initcall0_start

ffffffc0017daf68 T __initcall1_start

ffffffc0017dafa0 t __initcall_pm_init1
ffffffc0017db000 t __initcall_debugfs_init1
ffffffc0017db018 t __initcall_pinctrl_init1

ffffffc0017db078 T __initcall2_start

ffffffc0017db078 T __initcall2_start

ffffffc0017db148 T __initcall3_start

ffffffc0017db2d0 T __initcall4_start

ffffffc0017db5e8 T __initcall5_start

ffffffc0017db730 T __initcall6_start

ffffffc0017dc3d0 t __initcall_qpnp_led_init6
ffffffc0017dc3d8 t __initcall_qpnp_wled_init6
ffffffc0017dc3e0 t __initcall_switch_class_init6
ffffffc0017dc3e8 t __initcall_gpio_switch_init6
ffffffc0017dc3f0 t __initcall_tz_log_init6
ffffffc0017dc3f8 t __initcall_hid_init6
ffffffc0017dc400 t __initcall_uhid_init6

ffffffc0017dcbe8 T __initcall7_start

3、__initcall_fnid的执行

源码位置:
kernel/init/main.c
执行顺序:
start_kernel --> rest_init -->kernel_init --> kernel_init_freeable -->do_basic_setup -->do_initcalls -->do_initcall_level --> do_one_initcall --> fn();

3.1、遍历所有初始化level

do_initcalls按照level来遍历执行所有level的init函数,level从0到7,依次执行,0的优先级最高,7的最低;

static void __init do_initcalls(void)
{
	int level;

	for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
		do_initcall_level(level);
}

3.2、遍历每个level的所有初始化函数

do_initcall_level对每个initlevel中的函数指针遍历,从一个level的start,执行到下一个level的start,比如:从level6,从__initcall6_start开始,每个函数指针执行,执行到__initcall7_start,level6初始化完成,用这种方式完成__initcall_start到__initcall_end中间所有函数指针对应初始化化函数的执行。

static void __init do_initcall_level(int level)
{
	initcall_entry_t *fn;

	strcpy(initcall_command_line, saved_command_line);
	parse_args(initcall_level_names[level],
		   initcall_command_line, __start___param,
		   __stop___param - __start___param,
		   level, level,
		   NULL, &repair_env_string);

	trace_initcall_level(initcall_level_names[level]);
	for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
		do_one_initcall(initcall_from_entry(fn));
}

3.3、每个初始化函数的执行

do_one_initcall执行对应的初始化函数fn。


```dart
int __init_or_module do_one_initcall(initcall_t fn)
{
	int count = preempt_count();
	char msgbuf[64];
	int ret;

	if (initcall_blacklisted(fn))
		return -EPERM;

	do_trace_initcall_start(fn);
	ret = fn();
	do_trace_initcall_finish(fn, ret);

	msgbuf[0] = 0;

	if (preempt_count() != count) {
		sprintf(msgbuf, "preemption imbalance ");
		preempt_count_set(count);
	}
	if (irqs_disabled()) {
		strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf));
		local_irq_enable();
	}
	WARN(msgbuf[0], "initcall %pS returned with %s\n", fn, msgbuf);

	add_latent_entropy();
	return ret;
}

3.4、fn指针

fn = initcall_levels[level]

extern initcall_t __initcall_start[];
extern initcall_t __initcall0_start[];
extern initcall_t __initcall1_start[];
extern initcall_t __initcall2_start[];
extern initcall_t __initcall3_start[];
extern initcall_t __initcall4_start[];
extern initcall_t __initcall5_start[];
extern initcall_t __initcall6_start[];
extern initcall_t __initcall7_start[];
extern initcall_t __initcall_end[];

static initcall_t *initcall_levels[] __initdata = {
	__initcall0_start,
	__initcall1_start,
	__initcall2_start,
	__initcall3_start,
	__initcall4_start,
	__initcall5_start,
	__initcall6_start,
	__initcall7_start,
	__initcall_end,
};

关于rootfs的initcall另外,从system.map中可以看出,rootfs仅有一个初始化__initcall_populate_rootfsrootfs,其他并没有使用。
ffffffc0017db718 t __initcall_deferred_probe_initcall5s
ffffffc0017db720 t __initcall_msm_gcc_mdss_init5s
ffffffc0017db728 t __initcall_populate_rootfsrootfs
ffffffc0017db728 T __initcallrootfs_start
ffffffc0017db730 T __initcall6_start
ffffffc0017db730 t __initcall_register_pmu_driver6

关于rootfs的initcall,从代码来看,代码并没有显示的遍历rootfs的init,那么rootfs的init是否执行,如何执行?
–是,rootfs init会执行;
–在遍历level5时,level5s结束后,并没有结束,结束的标志是__initcall6_start,所以level5s结束后继续执行rootfs,直到__initcall6_start,综上rootfs是跟着level5一起初始化的,优先级低于level5s,高于level6。

总结:
—module_init宏将init的函数指针放到__initcall_id的段中;
—start kernel一系列调用到do initcall遍历整个section中的指针逐个调用初始化;
—初始化顺序先依赖于level,level越低优先级越高,同level依赖于编译顺序;

4、init函数中的register

驱动的init函数的主要任务是注册driver,一般调用xxbus的driver注册函数,例如:
–ret = platform_driver_register(&gpio_switch_drv);
–return i2c_add_driver(&aw2013_led_driver);
–retval = spi_register_driver(&wk2xxx_driver);
在这里插入图片描述
至此,driver的init和register完成。

二、Device的创建

1、platform dev的创建

源码位置:
kernel\arch\arm64\kernel\setup.c
kernel\drivers\of\platform.c

入口:
arch_initcall_sync(arm64_device_init);
Platform设备注册流程:
arm64_device_init --> of_platform_populate --> of_platform_bus_create --> of_platform_device_create_pdata --> of_device_add --> device_add --> bus_add_device & bus_probe_device
关键函数解析:

int of_platform_populate(struct device_node *root,
			const struct of_device_id *matches,
			const struct of_dev_auxdata *lookup,
			struct device *parent)
{
	struct device_node *child;
	int rc = 0;

	root = root ? of_node_get(root) : of_find_node_by_path("/");
	if (!root)
		return -EINVAL;

	pr_debug("%s()\n", __func__);
	pr_debug(" starting at: %pOF\n", root);

   /* 遍历根节点的每个子节点,创建platformdev */
	for_each_child_of_node(root, child) {
		rc = of_platform_bus_create(child, matches, lookup, parent, true);
		if (rc) {
			of_node_put(child);
			break;
		}
	}
	of_node_set_flag(root, OF_POPULATED_BUS);

	of_node_put(root);
	return rc;
}
EXPORT_SYMBOL_GPL(of_platform_populate);
static int of_platform_bus_create(struct device_node *bus,
				  const struct of_device_id *matches,
				  const struct of_dev_auxdata *lookup,
				  struct device *parent, bool strict)
{
	const struct of_dev_auxdata *auxdata;
	struct device_node *child;
	struct platform_device *dev;
	const char *bus_id = NULL;
	void *platform_data = NULL;
	int rc = 0;
    /* compatiable属性是必要条件,否则退出,不创建 */
	/* Make sure it has a compatible property */
	if (strict && (!of_get_property(bus, "compatible", NULL))) {
		pr_debug("%s() - skipping %pOF, no compatible prop\n",
			 __func__, bus);
		return 0;
	}

	/* Skip nodes for which we don't want to create devices */
	if (unlikely(of_match_node(of_skipped_node_table, bus))) {
		pr_debug("%s() - skipping %pOF node\n", __func__, bus);
		return 0;
	}

	if (of_node_check_flag(bus, OF_POPULATED_BUS)) {
		pr_debug("%s() - skipping %pOF, already populated\n",
			__func__, bus);
		return 0;
	}

	auxdata = of_dev_lookup(lookup, bus);
	if (auxdata) {
		bus_id = auxdata->name;
		platform_data = auxdata->platform_data;
	}

	if (of_device_is_compatible(bus, "arm,primecell")) {
		/*
		 * Don't return an error here to keep compatibility with older
		 * device tree files.
		 */
		of_amba_device_create(bus, bus_id, platform_data, parent);
		return 0;
	}
    /* 继续创建Platform dev */
	dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);
	if (!dev || !of_match_node(matches, bus))
		return 0;
    /* 如果创建成功,并且这个设备的compatible是匹配matches的,则对其所有子节点递归创建platformdev */
	for_each_child_of_node(bus, child) {
		pr_debug("   create child: %pOF\n", child);
		rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict);
		if (rc) {
			of_node_put(child);
			break;
		}
	}
	of_node_set_flag(bus, OF_POPULATED_BUS);
	return rc;
}

允许递归创建子节点的compatible的matchs列表如下:

const struct of_device_id of_default_bus_match_table[] = {
	{ .compatible = "simple-bus", },
	{ .compatible = "simple-mfd", },
	{ .compatible = "isa", },
#ifdef CONFIG_ARM_AMBA
	{ .compatible = "arm,amba-bus", },
#endif /* CONFIG_ARM_AMBA */
	{} /* Empty terminated list */
};
static struct platform_device *of_platform_device_create_pdata(
					struct device_node *np,
					const char *bus_id,
					void *platform_data,
					struct device *parent)
{
	struct platform_device *dev;
    /* 检查status是否是ok,没有和ok都通过 */
	if (!of_device_is_available(np) ||
	    of_node_test_and_set_flag(np, OF_POPULATED))
		return NULL;
    /* 分配irq,reg资源 */
	dev = of_device_alloc(np, bus_id, parent);
	if (!dev)
		goto err_clear_flag;

	dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
	if (!dev->dev.dma_mask)
		dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
	dev->dev.bus = &platform_bus_type;
	dev->dev.platform_data = platform_data;
	of_msi_configure(&dev->dev, dev->dev.of_node);
    /* 继续创建Platform dev */
	if (of_device_add(dev) != 0) {
		platform_device_put(dev);
		goto err_clear_flag;
	}

	return dev;

err_clear_flag:
	of_node_clear_flag(np, OF_POPULATED);
	return NULL;
}
int of_device_add(struct platform_device *ofdev)
{
	BUG_ON(ofdev->dev.of_node == NULL);

	/* name and id have to be set so that the platform bus doesn't get
	 * confused on matching */
	ofdev->name = dev_name(&ofdev->dev);
	ofdev->id = PLATFORM_DEVID_NONE;

	/*
	 * If this device has not binding numa node in devicetree, that is
	 * of_node_to_nid returns NUMA_NO_NODE. device_add will assume that this
	 * device is on the same node as the parent.
	 */
	set_dev_node(&ofdev->dev, of_node_to_nid(ofdev->dev.of_node));

	return device_add(&ofdev->dev);
}

2、其他总线设备的创建

以i2c为例

2.1、注册sys/bus/i2c/i2c-%d设备

此处注册的为i2c bus Device
i2c_register_adapter–> device_register(&adap->dev) --> device_add --> bus_add_device & bus_probe_device

2.2、注册sys/bus/i2c/i2c-%d/%d-addr设备

此处注册为挂在i2c bus下的设备
i2c_register_adapter–> of_i2c_register_devices --> i2c_new_device --> device_register(&client->dev)–> device_add --> bus_add_device & bus_probe_device

2.3、代码解析

static void of_i2c_register_devices(struct i2c_adapter *adap)
{
……
	//遍历adap下子节点,给每个子节点注册dev
	for_each_available_child_of_node(adap->dev.of_node, node) {
	
		//没有compatible不注册
		if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
			dev_err(&adap->dev, "of_i2c: modalias failure on %s\n",
				node->full_name);
			continue;
		}
		//没有addr不注册
		addr = of_get_property(node, "reg", &len);
		if (!addr || (len < sizeof(int))) {
			dev_err(&adap->dev, "of_i2c: invalid reg on %s\n",
				node->full_name);
			continue;
		}
		//第一次检查addr,不能大于0x3ff(10位地址的最大值为0x3FF)
		info.addr = be32_to_cpup(addr);
		if (info.addr > (1 << 10) - 1) {
			dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n",
				info.addr, node->full_name);
			continue;
		}
……
		//注册i2c dev
		result = i2c_new_device(adap, &info);
}

i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
{
……
	//第2次检查i2c地址,本次是10位和7位分开检查
	status = i2c_check_client_addr_validity(client);
	if (status) {
		dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n",
			client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr);
		goto out_err_silent;
	}

	// 检查地址是否重复
	status = i2c_check_addr_busy(adap, client->addr);
	if (status)
		goto out_err;

	client->dev.parent = &client->adapter->dev;
	//配置总线为i2c总线
	client->dev.bus = &i2c_bus_type;
	client->dev.type = &i2c_client_type;
	client->dev.of_node = info->of_node;
	ACPI_COMPANION_SET(&client->dev, info->acpi_node.companion);
	//配置设备名字为i2c%d-addr
	i2c_dev_set_name(adap, client);
	//注册i2c设备
	status = device_register(&client->dev);
	
}

注册驱动时,可以直接调用platform_driver_register直接注册.

三、dev和driver的匹配

1、dev和driver的match

注册driver时:
bus_add_driver --> driver_attach --> bus_for_each_dev(drv->bus, NULL, drv, __driver_attach) --> __driver_attach --> driver_match_device --> drv->bus->match(dev, drv);
增加Device时:
bus_probe_device --> device_initial_probe --> __device_attach --> bus_for_each_drv(dev->bus, NULL, &data,__device_attach_driver) --> __device_attach_driver --> driver_match_device --> drv->bus->match(dev, drv)
在这里插入图片描述

struct bus_type platform_bus_type = {
	.name		= "platform",
	.dev_groups	= platform_dev_groups,
	.match		= platform_match,
	.uevent		= platform_uevent,
	.pm		= &platform_dev_pm_ops,
};
struct bus_type i2c_bus_type = {
	.name		= "i2c",
	.match		= i2c_device_match,
	.probe		= i2c_device_probe,
	.remove		= i2c_device_remove,
	.shutdown	= i2c_device_shutdown,
	.pm		= &i2c_device_pm_ops,
};
struct bus_type spi_bus_type = {
	.name		= "spi",
	.dev_groups	= spi_dev_groups,
	.match		= spi_match_device,
	.uevent		= spi_uevent,
	.pm		= &spi_pm,
};
static int platform_match(struct device *dev, struct device_driver *drv)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct platform_driver *pdrv = to_platform_driver(drv);

	/* When driver_override is set, only bind to the matching driver */
	if (pdev->driver_override)
		return !strcmp(pdev->driver_override, drv->name);

	/* Attempt an OF style match first */
	if (of_driver_match_device(dev, drv))
		return 1;

	/* Then try ACPI style match */
	if (acpi_driver_match_device(dev, drv))
		return 1;

	/* Then try to match against the id table */
	if (pdrv->id_table)
		return platform_match_id(pdrv->id_table, pdev) != NULL;

	/* fall-back to driver name match */
	return (strcmp(pdev->name, drv->name) == 0);
}

of_driver_match_device --> of_match_device --> of_match_node --> __of_match_node --> __of_device_is_compatible
其中of_match_node所对driver中matches的结果做了遍历,driver中也允许存在多个match数组,即多个compatible,在向下调用都是一个driver的match结构去对可能存在的多个devtree的compatible来匹配;

static int __of_device_is_compatible(const struct device_node *device,
				     const char *compat, const char *type, const char *name)
{
	struct property *prop;
	const char *cp;
	int index = 0, score = 0;

	/* Compatible match has highest priority */
	if (compat && compat[0]) {
		prop = __of_find_property(device, "compatible", NULL);
		for (cp = of_prop_next_string(prop, NULL); cp;
		     cp = of_prop_next_string(prop, cp), index++) {
			if (of_compat_cmp(cp, compat, strlen(compat)) == 0) {
				score = INT_MAX/2 - (index << 2);
				break;
			}
		}
		if (!score)
			return 0;
	}

	/* Matching type is better than matching name */
	if (type && type[0]) {
		if (!__of_node_is_type(device, type))
			return 0;
		score += 2;
	}

	/* Matching name is a bit better than not */
	if (name && name[0]) {
		if (!of_node_name_eq(device, name))
			return 0;
		score++;
	}

	return score;
}

实际匹配过程是积分匹配,积分越高,匹配程度越高,最终选择积分最高的dev来作为最终匹配结果;
积分中,compatiable积分最高,type是2,name是1;
Devtee的compatiable允许有多个,index越小优先级越高;
Index为0时优先级最高,
16位INT,campatiable积分是INT_MAX/2 = 2^14-1 = 0x3fff-1 = 16383
32位INT,campatiable积分是INT_MAX/2 = 2^30-1 = 0x3fffffff-1 = 1073741824

2、driver probe的执行

dev和drv在match通过这执行,失败不执行。
Driver开始的路径:
bus_add_driver --> driver_attach --> bus_for_each_dev(drv->bus, NULL, drv, __driver_attach) --> __driver_attach --> driver_match_device成功则driver_probe_device
Device开始的路径:
bus_probe_device --> device_initial_probe --> __device_attach --> bus_for_each_drv(dev->bus, NULL, &data,__device_attach_driver) --> __device_attach_driver --> driver_match_device成功则driver_probe_device
probe的执行:
driver_probe_device --> really_probe --> drv->probe(dev)

static int really_probe(struct device *dev, struct device_driver *drv)
{
	……
	//如果有pinctrl,先绑定pinctrl,并配置default pinctrl
	ret = pinctrl_bind_pins(dev);
    ……
   //执行bus probe和driver probe
	if (dev->bus->probe) {
		ret = dev->bus->probe(dev);
		if (ret)
			goto probe_failed;
	} else if (drv->probe) {
		ret = drv->probe(dev);
		if (ret)
			goto probe_failed;
	}
	……
}

到这里,设备匹配和初始化完成。

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Linux内核是一种开源的操作系统内核,是Linux操作系统的核心组成部分。它提供了操作系统与硬件之间的抽象层,负责管理系统的资源、调度任务、提供驱动程序等功能。 Linux内核采用分层的架构,包括硬件抽象层、系统调用层、进程管理层、文件系统层和网络层等。硬件抽象层负责将不同硬件设备的接口统一起来,使得上层的软件可以方便地与硬件进行通信。系统调用层提供了一组API供用户进程调用,如文件操作、网络通信等。进程管理层负责进程的创建、销毁以及调度等任务。文件系统层负责文件的管理和存储。网络层负责网络协议的实现和网络通信。 Linux内核的工作原理可以简单概括为以下几个关键步骤。首先,当一台计算机启动时,BIOS会加载内核映像到内存中,并执行启动代码。然后,内核初始化各种数据结构、驱动程序和关键服务。接下来,内核创建一个初始的用户空间进程,称为init进程。init进程是所有其他进程的祖先进程。在此之后,内核根据调度算法来决定哪个进程可以使用CPU,并依次执行。同时,内核会提供一个中断机制,以便处理硬件事件的优先级。 内核还提供了许多系统调用供用户进程调用,以实现对各种功能的访问。当用户进程需要操作文件、创建进程或进行网络通信时,会通过系统调用将请求传递给内核,由内核代表用户进程执行相应的操作。内核通过调度算法来分配CPU时间片,并通过虚拟内存管理来管理内存资源的分配和回收。 总而言之,Linux内核是一个高度可配置和模块化的操作系统内核,通过分层架构和系统调用机制实现了对硬件的抽象和对用户进程的管理。了解Linux内核的架构和工作原理,有助于深入理解Linux操作系统以及开发和调试相关应用程序。 ### 回答2: Linux是一种开源的操作系统内核,其设计目标是为了在不同的计算机硬件平台上提供高效的、稳定的和安全的操作系统服务。 Linux内核的架构可以分为三个主要部分:进程管理、内存管理和文件系统管理。 在进程管理方面,Linux内核使用了多任务处理技术,可以同时运行多个进程。每个进程都有独立的地址空间和资源,通过调度算法可以合理分配CPU时间片,优化系统的响应速度和资源利用率。 在内存管理方面,Linux内核使用了虚拟内存技术,将物理内存和逻辑内存进行了映射,使得每个进程都有独立的地址空间。当物理内存不足时,Linux内核会通过页面置换算法将暂时不使用的页写入磁盘交换空间,以释放物理内存供其他进程使用。 在文件系统管理方面,Linux内核支持多种文件系统,包括传统的ext3和ext4文件系统,以及现代的Btrfs和XFS文件系统。它负责文件的读写操作,以及文件的权限控制和磁盘空间的管理。 Linux内核的工作原理可以简单概括为以下几个步骤:首先,启动引导程序将内核加载到内存中,并进行初始化。然后,内核分配一部分内存作为内核空间,用于存放内核代码和数据结构。接着,内核根据系统的硬件配置进行设备的初始化和驱动程序的加载。之后,内核根据系统的启动参数和配置文件进行一系列的初始化工作,包括启动系统服务和加载用户程序。最后,内核进入主循环,不断地处理中断、调度进程、管理内存和文件系统,以提供稳定的操作系统服务。 总之,Linux内核是一个复杂而高效的软件系统,它通过进程管理、内存管理和文件系统管理等功能,实现了操作系统的基本功能。了解Linux内核的架构和工作原理,有助于我们更好地理解和使用这个优秀的开源操作系统。 ### 回答3: Linux内核是一个开放源代码的操作系统内核,由一个核心程序和一组通用的系统工具组成。它是Linux操作系统的核心,负责处理硬件设备、管理系统资源、实现进程管理、文件系统和网络功能等。 Linux内核的架构可以分为两个层次:用户空间和内核空间。用户空间包括用户应用程序,如图形界面、终端程序等,它们通过系统调用接口与内核进行通信。内核空间包括内核核心的数据结构和程序,用于管理和控制硬件资源。 Linux内核的工作原理可以概括为以下几个方面: 1. 进程管理:内核负责创建、调度和终止进程。它使用进程描述符(task_struct)来跟踪进程的状态和资源使用情况,并根据调度算法分配CPU时间片给不同的进程。 2. 内存管理:内核负责管理系统的物理内存和虚拟内存。物理内存管理包括内存分配和释放,虚拟内存管理包括页面置换和页面回写等策略,以优化内存的使用效率。 3. 文件系统:内核提供文件系统接口,管理文件和目录的创建、读写和删除等操作。它通过虚拟文件系统层(VFS)将不同的文件系统统一管理,如ext4、NTFS等。 4. 设备驱动:内核提供了访问硬件设备的接口,通过设备驱动程序与硬件交互。不同的硬件设备需要不同的驱动程序,如网卡、显卡、声卡等。 5. 网络功能:内核提供TCP/IP协议栈和网络设备驱动程序,用于实现网络通信功能。它提供网络连接的建立、数据传输和断开等功能,支持各种网络协议,如HTTP、FTP、SSH等。 总的来说,Linux内核是一个非常复杂且功能强大的软件,它负责管理计算机的各种资源和提供操作系统的各种功能。通过深入理解其架构和工作原理,我们可以更好地理解和使用Linux操作系统。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值