linux设备驱动模型

来源:互联网 发布:nodejs调用其它js文件 编辑:程序博客网 时间:2024/05/12 10:08

在驱动模型的基础上,就可以构建实际的设备驱动了,这里以platform总线来进行介绍,因为platform总线具有代表性,platform不是一个实际的总线,它是虚拟出来的,所以在设备上的任何硬件驱动都可以挂在这条总线上,最典型的就是设备上的控制器模块都是挂在platform总线上的

1. platform总线注册

1.1 platform_bus_type

struct bus_type platform_bus_type = {    .name       = "platform",    .dev_groups = platform_dev_groups,    .match      = platform_match,    .uevent     = platform_uevent,    .pm     = &platform_dev_pm_ops,};

1.2 platform总线注册

在系统初始化的时候会进行总线的注册

(drivers/base/platform.c)

int __init platform_bus_init(void){    int error;    early_platform_cleanup();    error = device_register(&platform_bus);-----------platform作为设备注册    if (error)        return error;    error =  bus_register(&platform_bus_type);--------platform总线注册    if (error)        device_unregister(&platform_bus);    of_platform_register_reconfig_notifier();    return error;}

2. platform设备注册

2.1 struct platform_device

(include/linux/platform_device.h)

struct platform_device {    const char  *name;---------------------设备名字    int     id;----------------------------设备ID    bool        id_auto;    struct device   dev;-------------------嵌入的device结构体    u32     num_resources;-----------------设备资源数    struct resource *resource;-------------设备资源    const struct platform_device_id *id_entry;    char *driver_override; /* Driver name to force a match */    /* MFD cell pointer */    struct mfd_cell *mfd_cell;    /* arch specific additions */    struct pdev_archdata    archdata;};

2.2 platform_device_register

platform设备注册的函数为:

(include/linux/platform_device.h)

extern int platform_device_register(struct platform_device *);

该函数首先把platform_device添加到/sys/device目录下,真正的注册在下面函数中:

(drivers/base/platform.c)

int platform_device_add(struct platform_device *pdev){    int i, ret;    if (!pdev)        return -EINVAL;    if (!pdev->dev.parent)        pdev->dev.parent = &platform_bus;---------设置父设备为platform_bus    pdev->dev.bus = &platform_bus_type;-----------所属总线为platform_bus    switch (pdev->id) {    default:        dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);        break;    case PLATFORM_DEVID_NONE:        dev_set_name(&pdev->dev, "%s", pdev->name);        break;    case PLATFORM_DEVID_AUTO:        /*         * Automatically allocated device ID. We mark it as such so         * that we remember it must be freed, and we append a suffix         * to avoid namespace collision with explicit IDs.         */        ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL);        if (ret < 0)            goto err_out;        pdev->id = ret;        pdev->id_auto = true;        dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id);        break;    }---------------------------------------------设置name    for (i = 0; i < pdev->num_resources; i++) {        struct resource *p, *r = &pdev->resource[i];        if (r->name == NULL)            r->name = dev_name(&pdev->dev);        p = r->parent;        if (!p) {            if (resource_type(r) == IORESOURCE_MEM)                p = &iomem_resource;            else if (resource_type(r) == IORESOURCE_IO)                p = &ioport_resource;        }        if (p && insert_resource(p, r)) {            dev_err(&pdev->dev, "failed to claim resource %d\n", i);            ret = -EBUSY;            goto failed;        }    }    pr_debug("Registering platform device '%s'. Parent at %s\n",         dev_name(&pdev->dev), dev_name(pdev->dev.parent));    ret = device_add(&pdev->dev);-------------------device注册    if (ret == 0)        return ret;......}

3. platform驱动注册

3.1 struct 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;---------------------嵌入的device_driver结构体    const struct platform_device_id *id_table;    bool prevent_deferred_probe;};

3.2 设备驱动注册

(include/linux/platform_device.h)

#define platform_driver_register(drv) \    __platform_driver_register(drv, THIS_MODULE)
int __platform_driver_register(struct platform_driver *drv,                struct module *owner){    drv->driver.owner = owner;    drv->driver.bus = &platform_bus_type;-------------所属总线为platform_bus    drv->driver.probe = platform_drv_probe;    drv->driver.remove = platform_drv_remove;    drv->driver.shutdown = platform_drv_shutdown;    return driver_register(&drv->driver);-------------驱动注册}

最主要的来看下驱动初始化函数platform_drv_probe

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);    int ret;    ret = of_clk_set_defaults(_dev->of_node, false);    if (ret < 0)        return ret;    ret = dev_pm_domain_attach(_dev, true);    if (ret != -EPROBE_DEFER) {        if (drv->probe) {            ret = drv->probe(dev);-----------------调用到具体设备的初始化函数probe            if (ret)                dev_pm_domain_detach(_dev, true);        } else {            /* don't fail if just dev_pm_domain_attach failed */            ret = 0;        }    }    if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) {        dev_warn(_dev, "probe deferral not supported\n");        ret = -ENXIO;    }    return ret;}
0 0