Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1156277
  • 博文数量: 241
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 2279
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-27 19:53
个人简介

JustForFun

文章分类

全部博文(241)

文章存档

2023年(8)

2022年(2)

2021年(3)

2020年(30)

2019年(11)

2018年(27)

2017年(54)

2016年(83)

2015年(23)

我的朋友

分类: LINUX

2016-10-05 17:36:16

 那什么情况可以使用platform driver机制编写驱动呢?
我的理解是只要和内核本身运行依赖性不大的外围设备(换句话说只要不在内核 运行所需的一个最小系统之内的设备),相对独立的,拥有各自独自的资源(addresses and IRQs),都可以用platform_driver实现。如:lcd,usb,uart等,都可以用platfrom_driver写,而 timer,irq等最小系统之内的设备则最好不用platfrom_driver机制,实际上内核实现也是这样的。


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static int __init kernel_init(void * unused) ->do_basic_setup()函数->driver_init();

//这个函数的各个init倒是很有意思,是窥探内核设备和驱动的好切入点。
/**
 * driver_init - initialize driver model.
 *
 * Call the driver model init functions to initialize their
 * subsystems. Called early from init/main.c.
 */
void __init driver_init(void)
{
    /* These are the core pieces */
    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();
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
platform bus的注册platform bus注册是通过platform_bus_init函数完成的,该函数定义在drivers/base/platform.c文件中,其内容如下:


int __init platform_bus_init(void)
{
    int error;
//调用device_register注册了一个“platform”的device,以后注册的所有platform设备均以这个“platform”设备为父设备
    error = device_register(&platform_bus);
    if (error)
        return error;
//调用bus_register注册总线platform_bus_type。
    error =  bus_register(&platform_bus_type);
    if (error)
        device_unregister(&platform_bus);
    return error;
}
//////////////////////////////////////////////////////////////////
platform_bus定义在drivers/base/platform.c文件中,其内容如下:
struct device platform_bus = {
    .bus_id        = "platform",
};

platform_bus_type定义在drivers/base/platform.c文件中,其内容如下:
struct bus_type platform_bus_type = {
    .name        = "platform",
    .dev_attrs    = platform_dev_attrs,
    .match        = platform_match,
    .uevent        = platform_uevent,
    .pm        = PLATFORM_PM_OPS_PTR,
};

////////////////////////////////////////////////////////////////////////////
platform_match函数定义在drivers/base/platform.c文件中,其内容如下:

2.6.28内核如下:
/**
 * platform_match - bind platform device to platform driver.
 * @dev: device.
 * @drv: driver.
 *
 * Platform device IDs are assumed to be encoded like this:
 * "", where is a short description of the type of
 * device, like "pci" or "floppy", and is the enumerated
 * instance of the device, like '0' or '42'.  Driver IDs are simply
 * "".  So, extract the from the platform_device structure,
 * and compare it against the name of the driver. Return whether they match
 * or not.
 */
static int platform_match(struct device *dev, struct device_driver *drv)
{
    struct platform_device *pdev;

    pdev = container_of(dev, struct platform_device, dev);
    return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
}


Linux kernel release 3.x
/**
 * platform_match - bind platform device to platform driver.
 * @dev: device.
 * @drv: driver.
 *
 * Platform device IDs are assumed to be encoded like this:
 * "", where is a short description of the type of
 * device, like "pci" or "floppy", and is the enumerated
 * instance of the device, like '0' or '42'.  Driver IDs are simply
 * "".  So, extract the from the platform_device structure,
 * and compare it against the name of the driver. Return whether they match
 * or not.
 */
static int platform_match(struct device *dev, struct device_driver *drv)
{
    struct platform_device *pdev = to_platform_device(dev);
    struct platform_driver *pdrv = to_platform_driver(drv);

    /* When driver_override is set, only bind to the matching driver */
    if (pdev->driver_override)
        return !strcmp(pdev->driver_override, drv->name);

    /* Attempt an OF style match first */
    if (of_driver_match_device(dev, drv))
        return 1;

    /* Then try ACPI style match */
    if (acpi_driver_match_device(dev, drv))
        return 1;

    /* Then try to match against the id table */
    if (pdrv->id_table)
        return platform_match_id(pdrv->id_table, pdev) != NULL;
//后退或撤退 到驱动名字匹配
    /* fall-back to driver name match */
    return (strcmp(pdev->name, drv->name) == 0);
}


注册一个paltform_device通过调用platform_device_register函数完成,该函数定义在drivers/base/platform.c文件中,其内容如下:
/**
 * platform_device_register - add a platform-level device
 * @pdev: platform device we're adding
 */
int platform_device_register(struct platform_device *pdev)
{
//调用device_initialize初始化platform_device.dev。
    device_initialize(&pdev->dev);
//调用platform_device_add函数,该函数定义在drivers/base/platform.c文件中
    return platform_device_add(pdev);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
platform_device_add函数,该函数定义在drivers/base/platform.c文件中

/**
 * platform_device_add - add a platform device to device hierarchy
 * @pdev: platform device we're adding
 *
 * This is part 2 of platform_device_register(), though may be called
 * separately _iff_ pdev was allocated by platform_device_alloc().
 */
int platform_device_add(struct platform_device *pdev)
{
    int i, ret;

    if (!pdev)
        return -EINVAL;
//如果platform_device没有指定父设备,则设置pdev->dev.parent为platform_bus,即“platform”设备。
    if (!pdev->dev.parent)
        pdev->dev.parent = &platform_bus;
//指定bus类型为platform_bus_type。
    pdev->dev.bus = &platform_bus_type;
//根据不同情况设置设备名
    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;
    }
//调用insert_resource函数将platform_device的资源插入到资源树中。
    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));
//调用device_add将platform_device对应的device注册到sysfs系统中。
    ret = device_add(&pdev->dev);
    if (ret == 0)
        return ret;

 failed:
    if (pdev->id_auto) {
        ida_simple_remove(&platform_devid_ida, pdev->id);
        pdev->id = PLATFORM_DEVID_AUTO;
    }

    while (--i >= 0) {
        struct resource *r = &pdev->resource[i];
        unsigned long type = resource_type(r);

        if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
            release_resource(r);
    }

 err_out:
    return ret;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
platform driver的注册platform driver是通过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;
    const struct platform_device_id *id_table;
    bool prevent_deferred_probe;
};
 


/////////////////////////////////////////////////////////////////////////////////////////////
platform_driver的注册是通过调用platform_driver_register函数完成的,该函数定义在drivers/base/platform.c文件中,其内容如下:
/**
 * 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;
//调用driver_register注册platform_driver.driver
    return driver_register(&drv->driver);
}


阅读(1011) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~