platform_driver_register,什么时候调用PROBE函数 注册后如何找到驱动匹配的设备【转】

简介:
kernel_init中do_basic_setup()->driver_init()->platform_bus_init()->...初始化platform bus(虚拟总线)
设备向内核注册的时候platform_device_register()->platform_device_add()->...内核把设备挂在虚拟的platform bus下
驱动注册的时候platform_driver_register()->driver_register()->bus_add_driver()->driver_attach()->bus_for_each_dev()
对每个挂在虚拟的platform bus的设备作__driver_attach()->driver_probe_device()->drv->bus->match()==platform_match()->比较strncmp(pdev->name, drv->name, BUS_ID_SIZE),
如果相符就调用platform_drv_probe()->driver->probe(),如果probe成功则绑定该设备到该驱动.
kernel/init/main.c 
 
static int __init kernel_init(void * unused)
{
/*
 * Wait until kthreadd is all set-up.
 */
wait_for_completion(&kthreadd_done);
/*
 * init can allocate pages on any node
 */
set_mems_allowed(node_states[N_HIGH_MEMORY]);
/*
 * init can run on any cpu.
 */
set_cpus_allowed_ptr(current, cpu_all_mask);
 
cad_pid = task_pid(current);
 
smp_prepare_cpus(setup_max_cpus);
 
do_pre_smp_initcalls();
lockup_detector_init();
 
smp_init();
sched_init_smp();
 
do_basic_setup();
 
/* Open the /dev/console on the rootfs, this should never fail */
if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
printk(KERN_WARNING "Warning: unable to open an initial console.\n");
 
(void) sys_dup(0);
(void) sys_dup(0);
/*
 * check if there is an early userspace init.  If yes, let it do all
 * the work
 */
 
if (!ramdisk_execute_command)
ramdisk_execute_command = "/init";
 
if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
ramdisk_execute_command = NULL;
prepare_namespace();
}
 
/*
 * Ok, we have completed the initial bootup, and
 * we're essentially up and running. Get rid of the
 * initmem segments and start the user-mode stuff..
 */
 
init_post();
return 0;
}
 
 
static void __init do_basic_setup(void)
{
cpuset_init_smp();
usermodehelper_init();
init_tmpfs();
driver_init();
init_irq_proc();
do_ctors();
do_initcalls();
}
 
kernel/drivers/base/init.c
 
void __init driver_init(void)
{
/* These are the core pieces */
devtmpfs_init();
devices_init();
buses_init();
classes_init();
firmware_init();
hypervisor_init();
 
/* These are also core pieces, but must come after the
 * core core pieces.
 */
platform_bus_init();
system_bus_init();
cpu_dev_init();
memory_dev_init();
}
 
kernel/drivers/base/platform.c
注册虚拟总线
int __init platform_bus_init(void)
{
int error;
 
early_platform_cleanup();
 
error = device_register(&platform_bus);
if (error)
return error;
error =  bus_register(&platform_bus_type);
if (error)
device_unregister(&platform_bus);
return error;
}
 
 
kernel/drivers/base/platform.c
 
int platform_device_register(struct platform_device *pdev)
{
device_initialize(&pdev->dev);
return platform_device_add(pdev);
}
 
 
kernel/drivers/base/platform.c
 
int platform_driver_register(struct platform_driver *drv)
{
drv->driver.bus = &platform_bus_type;
if (drv->probe)
drv->driver.probe = platform_drv_probe;
if (drv->remove)
drv->driver.remove = platform_drv_remove;
if (drv->shutdown)
drv->driver.shutdown = platform_drv_shutdown;
 
return driver_register(&drv->driver);
}
 
kernel/drivers/base/driver.c
 
int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;
 
BUG_ON(!drv->bus->p);
 
if ((drv->bus->probe && drv->probe) ||
    (drv->bus->remove && drv->remove) ||
    (drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use "
"bus_type methods\n", drv->name);
 
other = driver_find(drv->name, drv->bus);
if (other) {
put_driver(other);
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n", drv->name);
return -EBUSY;
}
 
ret = bus_add_driver(drv);
if (ret)
return ret;
ret = driver_add_groups(drv, drv->groups);
if (ret)
bus_remove_driver(drv);
return ret;
}
 
kernel/drivers/base/bus.c
 
int bus_add_driver(struct device_driver *drv)
{
struct bus_type *bus;
struct driver_private *priv;
int error = 0;
 
bus = bus_get(drv->bus);
if (!bus)
return -EINVAL;
 
pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
 
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
error = -ENOMEM;
goto out_put_bus;
}
klist_init(&priv->klist_devices, NULL, NULL);
priv->driver = drv;
drv->p = priv;
priv->kobj.kset = bus->p->drivers_kset;
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
     "%s", drv->name);
if (error)
goto out_unregister;
 
if (drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv);
if (error)
goto out_unregister;
}
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
module_add_driver(drv->owner, drv);
 
error = driver_create_file(drv, &driver_attr_uevent);
if (error) {
printk(KERN_ERR "%s: uevent attr (%s) failed\n",
__func__, drv->name);
}
error = driver_add_attrs(bus, drv);
if (error) {
/* How the hell do we get out of this pickle? Give up */
printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
__func__, drv->name);
}
 
if (!drv->suppress_bind_attrs) {
error = add_bind_files(drv);
if (error) {
/* Ditto */
printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
__func__, drv->name);
}
}
 
kobject_uevent(&priv->kobj, KOBJ_ADD);
return 0;
 
out_unregister:
kobject_put(&priv->kobj);
kfree(drv->p);
drv->p = NULL;
out_put_bus:
bus_put(bus);
return error;
}
 
kernel/drivers/base/Dd.c
 
int driver_attach(struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
EXPORT_SYMBOL_GPL(driver_attach);
 
kernel/drivers/base/bus.c
 
int bus_for_each_dev(struct bus_type *bus, struct device *start,
     void *data, int (*fn)(struct device *, void *))
{
struct klist_iter i;
struct device *dev;
int error = 0;
 
if (!bus)
return -EINVAL;
 
klist_iter_init_node(&bus->p->klist_devices, &i,
     (start ? &start->p->knode_bus : NULL));
while ((dev = next_device(&i)) && !error)
error = fn(dev, data);
klist_iter_exit(&i);
return error;
}
EXPORT_SYMBOL_GPL(bus_for_each_dev);












本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/sky-heaven/p/5526309.html ,如需转载请自行联系原作者


相关文章
|
15天前
|
存储 Java Android开发
Rockchip系列之UART 新增framework系统jni+service接口访问(2)
Rockchip系列之UART 新增framework系统jni+service接口访问(2)
25 1
|
4月前
|
Go 开发工具 C++
2023驱动保护学习 -- 创建第一个驱动程序
2023驱动保护学习 -- 创建第一个驱动程序
31 0
|
5月前
|
运维 监控 安全
ops有多个,ops1或2等等,这些ops作用和定义是什么,只是跳转用的么?上限有多少个?
ops有多个,ops1或2等等,这些ops作用和定义是什么,只是跳转用的么?上限有多少个?
105 0
|
5月前
|
监控 安全 API
7.5 Windows驱动开发:监控Register注册表回调
在笔者前一篇文章`《内核枚举Registry注册表回调》`中实现了对注册表的枚举,本章将实现对注册表的监控,不同于32位系统在64位系统中,微软为我们提供了两个针对注册表的专用内核监控函数,通过这两个函数可以在不劫持内核API的前提下实现对注册表增加,删除,创建等事件的有效监控,注册表监视通常会通过`CmRegisterCallback`创建监控事件并传入自己的回调函数,与该创建对应的是`CmUnRegisterCallback`当注册表监控结束后可用于注销回调。
46 0
7.5 Windows驱动开发:监控Register注册表回调
|
10月前
|
存储 算法 芯片
IMX6ULL的I2C驱动详细分析
IMX6ULL的I2C驱动详细分析
170 0
IMX6ULL的I2C驱动详细分析
|
网络协议 流计算 Windows
驱动开发:探索DRIVER_OBJECT驱动对象
本章将探索驱动程序开发的基础部分,了解驱动对象`DRIVER_OBJECT`结构体的定义,一般来说驱动程序`DriverEntry`入口处都会存在这样一个驱动对象,该对象内所包含的就是当前所加载驱动自身的一些详细参数,例如驱动大小,驱动标志,驱动名,驱动节等等,每一个驱动程序都会存在这样的一个结构。
60360 0
驱动开发:探索DRIVER_OBJECT驱动对象
RK3399平台开发系列讲解(USB设备驱动)5.41、ECM Function Driver代码分析
RK3399平台开发系列讲解(USB设备驱动)5.41、ECM Function Driver代码分析
119 0
RK3399平台开发系列讲解(USB设备驱动)5.41、ECM Function Driver代码分析
|
监控 API
驱动开发:内核监控Register注册表回调
在笔者前一篇文章`《驱动开发:内核枚举Registry注册表回调》`中实现了对注册表的枚举,本章将实现对注册表的监控,不同于32位系统在64位系统中,微软为我们提供了两个针对注册表的专用内核监控函数,通过这两个函数可以在不劫持内核API的前提下实现对注册表增加,删除,创建等事件的有效监控,注册表监视通常会通过`CmRegisterCallback`创建监控事件并传入自己的回调函数,与该创建对应的是`CmUnRegisterCallback`当注册表监控结束后可用于注销回调。
367 0
驱动开发:内核监控Register注册表回调
|
消息中间件
RT-Thread记录(十一、I/O 设备模型之UART设备 — 源码解析)
深入理解 RT-Thread I/O 设备模型 — 分析 UART设备源码。
297 4
RT-Thread记录(十一、I/O 设备模型之UART设备 — 源码解析)