从RDA平台HX8357D屏驱动分析platform_driver_register、platform_device_register

来源:互联网 发布:远视 眼镜 知乎 编辑:程序博客网 时间:2024/06/09 16:03
 一、先看屏驱动里面
static struct platform_driver rda_fb_panel_HX8357D_mcu_driver = {
    .probe = rda_fb_panel_HX8357D_mcu_probe,
    .remove = rda_fb_panel_HX8357D_mcu_remove,
    .driver = {
        .name = HX8357D_MCU_PANEL_NAME}
};
static int __init rda_fb_panel_HX8357D_mcu_init(void)
{
    rda_fb_probe_panel(&HX8357D_mcu_info, &rda_fb_panel_HX8357D_mcu_driver);
    return platform_driver_register(&rda_fb_panel_HX8357D_mcu_driver);
}
module_init(rda_fb_panel_HX8357D_mcu_init);

如果要使platform_driver 里的probe函数正常执行,那么platform_driver_register的时候必须要match相同name的platform_device。

我们来找下相同name的platform_device。由于module_init()后执行了rda_fb_probe_panel(),这个函数做了自动检测不同型号LCD的操作,同时执行以下代码

    printk("lcd %s is selected\n", p_info->name);
    if (p_info->lcd.lcd_interface == GOUDA_LCD_IF_DBI) {
        struct platform_driver *plat_drv = (struct platform_driver *)p_driver;
        plat_drv->driver.name = RDA_DBI_PANEL_DRV_NAME;
    }
所以platform_driver name变为了RDA_DBI_PANEL_DRV_NAME
通过跟踪代码发现具有相同name的platform_device位于
Z:\rdadroid-4.2.2_r1-rel2.8\src\kernel\arch\arm\mach-rda\devices.c

static struct platform_device rda_fb_panel = {
    .name = RDA_DBI_PANEL_DRV_NAME,
    .id = -1,
    .dev = {
        .platform_data = NULL,
        },
};
二、系统是先注册的设备还是先注册的驱动?
1、Kernel启动
Z:\rdadroid-4.2.2_r1-rel2.8\src\kernel\init\main.c
start_kernel(void)->
rest_init();->
kernel_thread(kernel_init,…….);->
do_basic_setup()->
do_initcalls(void)->
do_initcall_level(int level)->
这里就会去调用不同级别的initcall

do_initcalls()函数
那些入口函数的调用由do_initcalls函数来完成。
do_initcall 函数通过for循环,由__initcall_start开始,直到__initcall_end结束,依次调用识别到的初始化函数。而位于 __initcall_start和__initcall_end之间的区域组成了.initcall.init节,其中保存了由 xxx_initcall形式的宏标记的函数地址,do_initcall函数可以很轻松的取得函数地址并执行其指向的函数。
.initcall.init节所保存的函数地址有一定的优先级,越前面的函数优先级越高,也会比位于后面的函数先被调用。

各initcall函数调用优先级别定义在
Z:\rdadroid-4.2.2_r1-rel2.8\src\kernel\include\linux\init.h
*/
#define pure_initcall(fn)        __define_initcall("0",fn,0)

#define core_initcall(fn)        __define_initcall("1",fn,1)
#define core_initcall_sync(fn)        __define_initcall("1s",fn,1s)
#define postcore_initcall(fn)        __define_initcall("2",fn,2)
#define postcore_initcall_sync(fn)    __define_initcall("2s",fn,2s)
#define arch_initcall(fn)        __define_initcall("3",fn,3)
#define arch_initcall_sync(fn)        __define_initcall("3s",fn,3s)
#define subsys_initcall(fn)        __define_initcall("4",fn,4)
#define subsys_initcall_sync(fn)    __define_initcall("4s",fn,4s)
#define fs_initcall(fn)            __define_initcall("5",fn,5)
#define fs_initcall_sync(fn)        __define_initcall("5s",fn,5s)
#define rootfs_initcall(fn)        __define_initcall("rootfs",fn,rootfs)
#define device_initcall(fn)        __define_initcall("6",fn,6)
#define device_initcall_sync(fn)    __define_initcall("6s",fn,6s)
#define late_initcall(fn)        __define_initcall("7",fn,7)
#define late_initcall_sync(fn)        __define_initcall("7s",fn,7s)
#define __initcall(fn) device_initcall(fn)
#define module_init(x)    __initcall(x);
2、RDA平台设备初始化
Z:\rdadroid-4.2.2_r1-rel2.8\src\kernel\arch\arm\mach-rda\devices.c

找到rda_init_devices()->
platform_add_devices(devices, ARRAY_SIZE(devices))->
int platform_add_devices(struct platform_device **devs, int num)
{
    int i, ret = 0;
    for (i = 0; i < num; i++) {
        ret = platform_device_register(devs[i]);
        if (ret) {
            while (--i >= 0)
                platform_device_unregister(devs[i]);
            break;
        }
    }
    return ret;
}

static struct platform_device *devices[] __initdata = {
&rda_fb_panel,
}

static struct platform_device rda_fb_panel = {
    .name = RDA_DBI_PANEL_DRV_NAME,// "rda-dbi-panel"
    .id = -1,
    .dev = {
        .platform_data = NULL,
        },
};
3、针对RDA_DBI_PANEL_DRV_NAME这个设备,是先注册的设备还是先注册的驱动?
通过跟踪代码发现rda_init_devices()调用流程如下
kernel/arch/arm/kernel/setup.c
static int __init customize_machine(void)
{
    /* customizes platform devices, or adds new ones */
    if (machine_desc->init_machine)
        machine_desc->init_machine();
    return 0;
}
arch_initcall(customize_machine);

kernel/arch/arm/mach-rda/board-rda8810.c
.init_machine    = rda8810_init,
rda8810_init()->
 rda_init_devices()->

arch_initcall()调用优先级高于module_init(),所以系统会先去platform_device_register将设备添加到设备链表

三、驱动是如何probe到设备的,以及设备是如何probe到驱动的?
由二知道系统优先执行了arch_initcall(customize_machine)–>platform_device_register将设备登记到设备链表
随后module_init(rda_fb_panel_HX8357D_mcu_init);->platform_driver_register()
 
int platform_driver_register(struct platform_driver *drv)
{
    return driver_register(&drv->driver);
}

int driver_register(struct device_driver *drv)
{
    ret = bus_add_driver(drv);
}

int bus_add_driver(struct device_driver *drv)
{
    if (drv->bus->p->drivers_autoprobe) {
        error = driver_attach(drv);
        if (error)
            goto out_unregister;
    }

}

int driver_attach(struct device_driver *drv)
{
    return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
//到这里遍历总线上的设备并掉用__driver_attach
}



static int __driver_attach(struct device *dev, void *data)
{
    struct device_driver *drv = data;
    /*
     * Lock device and try to bind to it. We drop the error
     * here and always return 0, because we need to keep trying
     * to bind to devices and some drivers will return an error
     * simply if it didn't support the device.
     *
     * driver_probe_device() will spit a warning if there
     * is an error.
     */
    if (!driver_match_device(drv, dev))
        return 0;
//调用的驱动的总线上的match函数。如果返回1,则可以继续,否则就Done了。
    if (dev->parent)    /* Needed for USB */
        device_lock(dev->parent);
    device_lock(dev);
    if (!dev->driver)
        driver_probe_device(drv, dev);//
    device_unlock(dev);
    if (dev->parent)
        device_unlock(dev->parent);

    return 0;
}

int driver_probe_device(struct device_driver *drv, struct device *dev)
{
    ret = really_probe(dev, drv);
}

static int really_probe(struct device *dev, struct device_driver *drv)
{
    if (dev->bus->probe) {
        ret = dev->bus->probe(dev);
        if (ret)
            goto probe_failed;
    } else if (drv->probe) {
        ret = drv->probe(dev);//如果probe非空则调用probe
        if (ret)
            goto probe_failed;
    }

}

rda_fb_panel_HX8357D_mcu_driver注册成功并探测匹配到设备后执行probe函数
Probe函数执行会去登记"rda-fb"的设备,然后设备去探测名为rda-fb的驱动,匹配成功后执行rda_fb_probe函数。
为什么说是设备去找驱动?因为注册设备之前rda-fb的驱动已添加到driver链表
设备probe驱动分析如下:
.probe = rda_fb_panel_HX8357D_mcu_probe,
static int rda_fb_panel_HX8357D_mcu_probe(struct platform_device *pdev)
{
    rda_fb_register_panel(&HX8357D_mcu_info);

    dev_info(&pdev->dev, "rda panel HX8357D_mcu registered\n");

    return 0;
}
int platform_device_register(struct platform_device *pdev)
{
    return platform_device_add(pdev);
}
int platform_device_add(struct platform_device *pdev)
{
    ret = device_add(&pdev->dev);
    if (ret == 0)
        return ret;
}

int device_add(struct device *dev)
{
    error = bus_add_device(dev);
    if (error)
        goto BusError;

bus_probe_device(dev);
}

void bus_probe_device(struct device *dev)
{

    if (bus->p->drivers_autoprobe) {
        ret = device_attach(dev);
        WARN_ON(ret < 0);
    }
}

int device_attach(struct device *dev)
{
        ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
}

static int __device_attach(struct device_driver *drv, void *data)
{
    struct device *dev = data;

    if (!driver_match_device(drv, dev))
        return 0;
//调用的驱动的总线上的match函数。如果返回1,则可以继续,否则就Done了。
    return driver_probe_device(drv, dev);
}

int driver_probe_device(struct device_driver *drv, struct device *dev)
{
    ret = really_probe(dev, drv);
}

static int really_probe(struct device *dev, struct device_driver *drv)
{
    if (dev->bus->probe) {
        ret = dev->bus->probe(dev);
        if (ret)
            goto probe_failed;
    } else if (drv->probe) {
        ret = drv->probe(dev);//如果probe非空则被调用
        if (ret)
            goto probe_failed;
    }

}
疑问:
if (drv->probe) 的drv类型为struct device_driver * 为何最终调用到了struct platform_driver里的probe?

rda_fb_panel_HX8357D_mcu_probe指定的参数类型为struct platform_device *,而最终传递给drv->probe()的dev类型为struct device *?

因为注册驱动前程序给drv->driver.probe赋值了platform_drv_probe;的函数指针
int platform_driver_register(struct platform_driver *drv)
{
    if (drv->probe)
        drv->driver.probe = platform_drv_probe;
}
所以每当跑到relly_probe()执行ret = drv->probe(dev)的时候就会实际调用到platform_drv_probe(struct device *_dev)

函数原型如下:
static int platform_drv_probe(struct device *_dev)
{
    struct platform_driver *drv = to_platform_driver(_dev->driver);
    struct platform_device *dev = to_platform_device(_dev);

    return drv->probe(dev);
}

#define to_platform_driver(drv)    (container_of((drv), struct platform_driver,  driver))
#define to_platform_device(x) container_of((x), struct platform_device, dev)

通过struct device *_dev找到所在结构体的首地址,最终调用到platform_driver结构体里面probe所指向的函数





0 0
原创粉丝点击