Linux设备驱动程序架构分析之platform(基于3.10.1内核)

作者:刘昊昱 

博客:http://blog.csdn.net/liuhaoyutz

内核版本:3.10.1

 
一、platform bus的注册
platform bus注册是通过platform_bus_init函数完成的,该函数定义在drivers/base/platform.c文件中,其内容如下:
 
  
 904int __init platform_bus_init(void)
 905{
 906    int error;
 907
 908    early_platform_cleanup();
 909
 910    error = device_register(&platform_bus);
 911    if (error)
 912        return error;
 913    error =  bus_register(&platform_bus_type);
 914    if (error)
 915        device_unregister(&platform_bus);
 916    return error;
 917}


908行,调用early_platform_cleanup作一些清理工作。
910行,调用device_register注册了一个“platform”的device,以后注册的所有platform设备均以这个“platform”设备为父设备。platform_bus定义在drivers/base/platform.c文件中,其内容如下:
 
  
  35struct device platform_bus = {
  36    .init_name  = "platform",
  37};


913行,调用bus_register注册总线platform_bus_type。bus_register函数的执行过程我们在《Linux设备模型分析之bus(基于3.10.1内核)》一文中已经分析过,这里就不再重复了。platform_bus_type定义在drivers/base/platform.c文件中,其内容如下:
 
  
 895struct bus_type platform_bus_type = {
 896    .name       = "platform",
 897    .dev_attrs  = platform_dev_attrs,
 898    .match      = platform_match,
 899    .uevent     = platform_uevent,
 900    .pm     = &platform_dev_pm_ops,
 901};


platform_match函数定义在drivers/base/platform.c文件中,其内容如下:
 
  
 710/**
 711 * platform_match - bind platform device to platform driver.
 712 * @dev: device.
 713 * @drv: driver.
 714 *
 715 * Platform device IDs are assumed to be encoded like this:
 716 * "", where  is a short description of the type of
 717 * device, like "pci" or "floppy", and  is the enumerated
 718 * instance of the device, like '0' or '42'.  Driver IDs are simply
 719 * "".  So, extract the  from the platform_device structure,
 720 * and compare it against the name of the driver. Return whether they match
 721 * or not.
 722 */
 723static int platform_match(struct device *dev, struct device_driver *drv)
 724{
 725    struct platform_device *pdev = to_platform_device(dev);
 726    struct platform_driver *pdrv = to_platform_driver(drv);
 727
 728    /* Attempt an OF style match first */
 729    if (of_driver_match_device(dev, drv))
 730        return 1;
 731
 732    /* Then try ACPI style match */
 733    if (acpi_driver_match_device(dev, drv))
 734        return 1;
 735
 736    /* Then try to match against the id table */
 737    if (pdrv->id_table)
 738        return platform_match_id(pdrv->id_table, pdev) != NULL;
 739
 740    /* fall-back to driver name match */
 741    return (strcmp(pdev->name, drv->name) == 0);
 742}


 
二、platform device的注册
platform device通过struct platform_device结构体来描述,这个结构体定义在include/linux/platform_device.h文件中,其内容如下:
 
  
 22struct platform_device {
 23    const char  *name;
 24    int     id;
 25    bool        id_auto;
 26    struct device   dev;
 27    u32     num_resources;
 28    struct resource *resource;
 29
 30    const struct platform_device_id *id_entry;
 31
 32    /* MFD cell pointer */
 33    struct mfd_cell *mfd_cell;
 34
 35    /* arch specific additions */
 36    struct pdev_archdata    archdata;
 37};


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


398行,调用device_initialize初始化platform_device.dev。
399行,arch_setup_pdev_archdata是一个空函数,忽略。
400行,调用platform_device_add函数,该函数定义在drivers/base/platform.c文件中,其内容如下:
 
  
 273/**
 274 * platform_device_add - add a platform device to device hierarchy
 275 * @pdev: platform device we're adding
 276 *
 277 * This is part 2 of platform_device_register(), though may be called
 278 * separately _iff_ pdev was allocated by platform_device_alloc().
 279 */
 280int platform_device_add(struct platform_device *pdev)
 281{
 282    int i, ret;
 283
 284    if (!pdev)
 285        return -EINVAL;
 286
 287    if (!pdev->dev.parent)
 288        pdev->dev.parent = &platform_bus;
 289
 290    pdev->dev.bus = &platform_bus_type;
 291
 292    switch (pdev->id) {
 293    default:
 294        dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
 295        break;
 296    case PLATFORM_DEVID_NONE:
 297        dev_set_name(&pdev->dev, "%s", pdev->name);
 298        break;
 299    case PLATFORM_DEVID_AUTO:
 300        /*
 301         * Automatically allocated device ID. We mark it as such so
 302         * that we remember it must be freed, and we append a suffix
 303         * to avoid namespace collision with explicit IDs.
 304         */
 305        ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL);
 306        if (ret < 0)
 307            goto err_out;
 308        pdev->id = ret;
 309        pdev->id_auto = true;
 310        dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id);
 311        break;
 312    }
 313
 314    for (i = 0; i < pdev->num_resources; i++) {
 315        struct resource *p, *r = &pdev->resource[i];
 316
 317        if (r->name == NULL)
 318            r->name = dev_name(&pdev->dev);
 319
 320        p = r->parent;
 321        if (!p) {
 322            if (resource_type(r) == IORESOURCE_MEM)
 323                p = &iomem_resource;
 324            else if (resource_type(r) == IORESOURCE_IO)
 325                p = &ioport_resource;
 326        }
 327
 328        if (p && insert_resource(p, r)) {
 329            dev_err(&pdev->dev, "failed to claim resource %d\n", i);
 330            ret = -EBUSY;
 331            goto failed;
 332        }
 333    }
 334
 335    pr_debug("Registering platform device '%s'. Parent at %s\n",
 336         dev_name(&pdev->dev), dev_name(pdev->dev.parent));
 337
 338    ret = device_add(&pdev->dev);
 339    if (ret == 0)
 340        return ret;
 341
 342 failed:
 343    if (pdev->id_auto) {
 344        ida_simple_remove(&platform_devid_ida, pdev->id);
 345        pdev->id = PLATFORM_DEVID_AUTO;
 346    }
 347
 348    while (--i >= 0) {
 349        struct resource *r = &pdev->resource[i];
 350        unsigned long type = resource_type(r);
 351
 352        if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
 353            release_resource(r);
 354    }
 355
 356 err_out:
 357    return ret;
 358}


287-288行,如果platform_device没有指定父设备,则设置pdev->dev.parent为platform_bus,即“platform”设备。
290行,指定bus类型为platform_bus_type。
292-312行,根据不同情况设置设备名。
314-333行,调用insert_resource函数将platform_device的资源插入到资源树中。
338行,调用device_add将platform_device对应的device注册到sysfs系统中。这个函数我们在《Linux设备模型分析之device(基于3.10.1内核)》一文中已经分析过,这里不再重复了。
 
三、platform driver的注册
platform driver是通过struct platform_driver结构体来描述的,该结构体定义在include/linux/platform_device.h文件中,其内容如下:
 
  
173struct platform_driver {
174    int (*probe)(struct platform_device *);
175    int (*remove)(struct platform_device *);
176    void (*shutdown)(struct platform_device *);
177    int (*suspend)(struct platform_device *, pm_message_t state);
178    int (*resume)(struct platform_device *);
179    struct device_driver driver;
180    const struct platform_device_id *id_table;
181};


platform_driver的注册是通过调用platform_driver_register函数完成的,该函数定义在drivers/base/platform.c文件中,其内容如下:
 
  
 525/**
 526 * platform_driver_register - register a driver for platform-level devices
 527 * @drv: platform driver structure
 528 */
 529int platform_driver_register(struct platform_driver *drv)
 530{
 531    drv->driver.bus = &platform_bus_type;
 532    if (drv->probe)
 533        drv->driver.probe = platform_drv_probe;
 534    if (drv->remove)
 535        drv->driver.remove = platform_drv_remove;
 536    if (drv->shutdown)
 537        drv->driver.shutdown = platform_drv_shutdown;
 538
 539    return driver_register(&drv->driver);
 540}


531-537行,完成一些初始化工作。

539行,调用driver_register注册platform_driver.driver,该函数我们在《Linux设备模型分析之device_driver(基于3.10.1内核)》一文中已经分析过,这里不再重复。

你可能感兴趣的:(Linux设备驱动程序架构分析)