platform总线架构

Linux驱动下的platform总线架构

    从 Linux 2.6 内核起,引入一套新的驱动管理和注册机制:platform_device和 platform_driver 。Linux 中大部分的设备驱动,都可以使用这套机制,设备用 platform_device表示;驱动用 platform_driver 进行注册。
    
    Linux platform driver 机制和传统的 device driver机制(即:通过 driver_register 函数进行注册)相比,一个十分明显的优势在于 platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序中用使用这些资源时,通过 platform device提供的标准接口进行申请并使用。

    platform 是一个虚拟的地址总线,相比 PCI、USB,它主要用于描述 SOC上的片上资源。比如 S3C2410 上集成的控制器( LCD、Watchdog、RTC等),platform所描述的资源有一个共同点:在 CPU 的总线上直接取址。

    平台设备会分到一个名称(用在驱动绑定中)以及一系列诸如地址和中断请求号(IRQ)之类的资源。
struct platform_device{              // include/linux/platform_device.h
    const char    * name;
    int        id;
    struct device    dev;
    u32       num_resources;
    struct resource    * resource;
};
***************************************************************************
/*
*  主要用于定义具体设备占用的硬件资源(如:地址空间、中断号等)。
*/
struct resource {
    resource_size_t start;
    resource_size_t end;
    const char *name;
    unsigned long flags;
    struct resource *parent, *sibling, *child;
};
***************************************************************************
platform 总线下驱动的开发步骤是:
   1、设备
  设备注册中,需要实现的机构体是:platform_device 。
1)初始化 resource 结构变量
2)初始化 platform_device 结构变量
3)向系统注册设备:platform_device_register。(以上三步,必须在设备驱动加载前完成,所以,AT91RM9200 的内核下,该三步是放在 arch/arm/mach-at91/board-dk.c中)
   2、驱动
  驱动注册中,需要实现的结构体是:platform_driver 。
struct platform_driver{                          // include/linux/platform_device.h
    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 (*suspend_late)(struct platform_device *,pm_message_t state);
    int (*resume_early)(struct platform_device *);
    int (*resume)(struct platform_device *);
    struct pm_ext_ops *pm;
    struct device_driver driver;
};
在驱动程序的初始化函数中,调用了 platform_driver_register() 注册 platform_driver 。
需要注意的是:platform_driver 和 platform_device 中的 name 变量的值必须是相同的 。这样在
platform_driver_register() 注册时,会将当前注册的 platform_driver 中的 name变量的值和已注册的所有 platform_device 中的 name 变量的值进行比较,只有找到具有相同名称的platform_device 才能注册成功。当注册成功时,会调用 platform_driver 结构元素 probe 函数指针。

rtc-ds1302.c 中,驱动首先执行:
********************************************************************
static int __init ds1302_rtc_init(void)
{
    returnplatform_driver_register(&ds1302_platform_driver);
}
********************************************************************
然后,进入:drivers/base/platform.c:platform_driver_register()
********************************************************************
/**
 * platform_driver_register
 * @drv: platform driver structure
 */
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;
    if (drv->suspend)
        drv->driver.suspend =platform_drv_suspend;
    if (drv->resume)
        drv->driver.resume =platform_drv_resume;
    if (drv->pm)
        drv->driver.pm =&drv->pm->base;
    return driver_register(&drv->driver);
}
此处,对drv->driver 结构体中的几个函数指针进行初始化设置。最后,调用 driver_register 注册driver 成员。
drv->driver 的类型是:
struct platform_driver{                    // include/linux/platform_device.h
    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 (*suspend_late)(struct platform_device *,pm_message_t state);
    int (*resume_early)(struct platform_device *);
    int (*resume)(struct platform_device *);
    struct pm_ext_ops *pm;
    struct device_driverdriver;          //drv->driver
};

struct device_driver{                     // include/linux/device.h
    const char       *name;
    struct bus_type       *bus;

    struct module       *owner;
    const char        *mod_name;    /* used for built-in modules */

    int (*probe) (struct device *dev);
    int (*remove) (struct device *dev);
    void (*shutdown) (struct device *dev);
    int (*suspend) (struct device *dev, pm_message_tstate);
    int (*resume) (struct device *dev);
    struct attribute_group **groups;

    struct pm_ops *pm;

    struct driver_private *p;
};
********************************************************************
然后,进入:drivers/base/driver.c:driver_register
********************************************************************
/**
 * driver_register - register driver with bus
 * @drv: driver to register
 *
 * We pass off most of the work to the bus_add_driver() call,
 * since most of the things we have to do deal with the bus
 * structures.
 */
int driver_register(struct device_driver *drv)
{
    int ret;
    struct device_driver *other;

    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_typemethods\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 -EEXIST;
    }

    ret =bus_add_driver(drv);              // 调用:bus_add_driver(),执行到此处,drv->bus 指向的是 platform_bus_type这一全局变量。
    if (ret)
        return ret;
    ret = driver_add_groups(drv, drv->groups);
    if (ret)
        bus_remove_driver(drv);
    return ret;
}
********************************************************************
然后,进入:drivers/base/bus.c:bus_add_driver
********************************************************************
/**
 * bus_add_driver - Add a driver to the bus.
 * @drv: driver.
 */
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)
            gotoout_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: ueventattr (%s) failed\n",
            __func__,drv->name);
    }
    error = driver_add_attrs(bus, drv);
    if (error) {
        /* How the hell do we get outof this pickle? Give up */
        printk(KERN_ERR "%s:driver_add_attrs(%s) failed\n",
            __func__,drv->name);
    }
    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 error;
out_unregister:
    kobject_put(&priv->kobj);
out_put_bus:
    bus_put(bus);
    return error;
}

你可能感兴趣的:(linux,struct,Module,null,resources,structure)