zoukankan      html  css  js  c++  java
  • 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. ");
     
    (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 ", drv->name);
     
    other = driver_find(drv->name, drv->bus);
    if (other) {
    put_driver(other);
    printk(KERN_ERR "Error: Driver '%s' is already registered, "
    "aborting... ", 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 ", 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 ",
    __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 ",
    __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 ",
    __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);
  • 相关阅读:
    Android开发 使用 adb logcat 显示 Android 日志
    【嵌入式开发】向开发板中烧写Linux系统-型号S3C6410
    C语言 结构体相关 函数 指针 数组
    C语言 命令行参数 函数指针 gdb调试
    C语言 指针数组 多维数组
    Ubuntu 基础操作 基础命令 热键 man手册使用 关机 重启等命令使用
    C语言 内存分配 地址 指针 数组 参数 实例解析
    CRT 环境变量注意事项
    hadoop 输出文件 key val 分隔符
    com.mysql.jdbc.exceptions.MySQLNonTransientConnectionException: Too many connections
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/5526309.html
Copyright © 2011-2022 走看看