分享

platform_driver_register与of_register_platform_driver分析

 langhuayipian 2011-05-06
在ARM体系结构中常见的是platform_driver_register
在powerpc中是of_register_platform_driver
下面通过具体的代码来分析其区别
platform_driver_register在driver/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);
}
EXPORT_SYMBOL_GPL(platform_driver_register);
——————————————————————————————————
而of_register_platform_driver在of_platform.c中定义
static inline int of_register_platform_driver(struct of_platform_driver *drv)
{
    return of_register_driver(drv, &of_platform_bus_type);
}
int of_register_driver()在driver/of/plateform.c中定义
int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
{
    drv->driver.bus = bus;

    /* register with core */
    return driver_register(&drv->driver);
}
而着最终都是调用的driver_register();
_____________________________________
这是由于二者结构获取硬件信息 的方式不同造成 的,在powerpc体系是通过dts
对比platform_driver和of_platform_driver
在include/linux/platform_device.h
struct platform_driver {
    int (*probe)(struct platform_device *);
    int (*remove)(struct platform_device *);
    void (*shutdown)(struct platform_device *);
    int (*suspend)(struct platform_device *, pm_message_t state);
    int (*resume)(struct platform_device *);
    struct device_driver driver;
    const struct platform_device_id *id_table;
};
在include/linux/of_platform_device.h
struct of_platform_driver
{
    int    (*probe)(struct of_device* dev,
             const struct of_device_id *match);
    int    (*remove)(struct of_device* dev);

    int    (*suspend)(struct of_device* dev, pm_message_t state);
    int    (*resume)(struct of_device* dev);
    int    (*shutdown)(struct of_device* dev);

    struct device_driver    driver;
};
#define    to_of_platform_driver(drv) \
    container_of(drv,struct of_platform_driver, driver)
of_device_id 和platform_device_id
可以看出 主要所区别在 of_device 和platform_device
***********************************************************
在arch/powerpc/include/asm/of_device.h定义了
/*
 * The of_device is a kind of "base class" that is a superset of
 * struct device for use by devices attached to an OF node and
 * probed using OF properties.
 */
struct of_device
{
    struct device        dev;        /* Generic device interface */
    struct pdev_archdata    archdata;
};

/*
 * Struct used for matching a device
 */
struct of_device_id
{
    char    name[32];
    char    type[32];
    char    compatible[128];  //dts中看到这个东东了哈。通过它的匹配获取硬件资源
#ifdef __KERNEL__
    void    *data;
#else
    kernel_ulong_t data;
#endif
};
——————————————————————————————————
在在include/linux/of_platform_device.h定义
struct platform_device {
    const char    * name;
    int        id;
    struct device    dev;//这个是通用的
    u32        num_resources;
    struct resource    * resource; //获取硬件资源

    const struct platform_device_id    *id_entry;

    /* arch specific additions */
    struct pdev_archdata    archdata;
};从上述定义的文件也可以发现powerpc 并不是一个通用的,和自己体系相关

struct platform_device_id {
    char name[PLATFORM_NAME_SIZE];
    kernel_ulong_t driver_data
            __attribute__((aligned(sizeof(kernel_ulong_t))));
};

*********************************
返回到我们的
int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
{
    drv->driver.bus = bus;

    /* register with core */
    return driver_register(&drv->driver);
}
bus 是从of_register_platform_driver中传入 of_platform_bus_type,是个全局变量在
arch/powerpc/kernel/of_platform.c中定义
struct bus_type of_platform_bus_type = {
       .uevent    = of_device_uevent,
};

of_device_uevent,在同上目录of_device.c定义
int of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
{
    struct of_device *ofdev;
    const char *compat;
    int seen = 0, cplen, sl;

    if (!dev)
        return -ENODEV;

    ofdev = to_of_device(dev);

    if (add_uevent_var(env, "OF_NAME=%s", ofdev->dev.of_node->name))
        return -ENOMEM;

    if (add_uevent_var(env, "OF_TYPE=%s", ofdev->dev.of_node->type))
        return -ENOMEM;

        /* Since the compatible field can contain pretty much anything
         * it's not really legal to split it out with commas. We split it
         * up using a number of environment variables instead. */

    compat = of_get_property(ofdev->dev.of_node, "compatible", &cplen);//根据compatible获取资源 具体看dts文件,在i2c学习中提过
    while (compat && *compat && cplen > 0) {
        if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat))
            return -ENOMEM;

        sl = strlen (compat) + 1;
        compat += sl;
        cplen -= sl;
        seen++;
    }

    if (add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen))
        return -ENOMEM;

    /* modalias is trickier, we add it in 2 steps */
    if (add_uevent_var(env, "MODALIAS="))
        return -ENOMEM;
    sl = of_device_get_modalias(ofdev, &env->buf[env->buflen-1],
                    sizeof(env->buf) - env->buflen);
    if (sl >= (sizeof(env->buf) - env->buflen))
        return -ENOMEM;
    env->buflen += sl;

    return 0;
}


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多