一、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;
}
……
}
到这里,设备匹配和初始化完成。