Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2150693
  • 博文数量: 438
  • 博客积分: 3871
  • 博客等级: 中校
  • 技术积分: 6075
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-10 00:11
个人简介

邮箱: wangcong02345@163.com

文章分类

全部博文(438)

文章存档

2017年(15)

2016年(119)

2015年(91)

2014年(62)

2013年(56)

2012年(79)

2011年(16)

分类: LINUX

2013-09-12 16:24:19

一、平台设备platform_device的添加过程
1. 定义dm9000的platform_device结构体,并初始化
在arch/arm/mach-s3c64xx/mach-smdk6410.c中定义了dm9000的platform_device
  1. static struct platform_device smdk6410_device_eth = {
  2.     .name    = "dm9000",
  3.     .id    = -1,
  4.     .num_resources    = ARRAY_SIZE(smdk6410_dm9000_resource),
  5.     .resource    = smdk6410_dm9000_resource,
  6.     .dev    = {
  7.         .platform_data = &smdk6410_dm9000_pdata,
  8.     },
  9. };
2. 设备的注册过程
将dm9000的platform_device结构体添加到数组中
在arch/arm/mach-s3c64xx/mach-smdk6410.c中

  1. static struct platform_device *smdk6410_devices[] __initdata = {
  2.     &smdk6410_device_eth,                    //把dm9000添加到device数组中
  3. };

  4. static void __init smdk6410_machine_init(void)
  5. {
  6.     platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices));
  7. }
在driver/bash/platform.c中
  1. int platform_add_devices(struct platform_device **devs, int num)
  2. {
  3.     for (i = 0; i < num; i++)
  4.         ret = platform_device_register(devs[i]);
  5. }
platform_add_devices               ;add多个devices
    --> platform_device_add      ;add单个devices
  1. int platform_device_add(struct platform_device *pdev)
  2. {
  3.     //如果platform_device没有parent的话,默认把parent设为platform_bus
  4.     if (!pdev->dev.parent)
  5.         pdev->dev.parent = &platform_bus;   
  6.     //设定总线的match uevent函数指针
  7.     pdev->dev.bus = &platform_bus_type;

  8.     if (pdev->id != -1)
  9.         dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
  10.     else
  11.         dev_set_name(&pdev->dev, "%s", pdev->name);
  12.     //下面这部分是配置resource
  13.     for (i = 0; i < pdev->num_resources; i++) {
  14.         struct resource *p, *r = &pdev->resource[i];
  15.         if (r->name == NULL)
  16.             r->name = dev_name(&pdev->dev);
  17.         p = r->parent;
  18.         if (!p) {
  19.             if (resource_type(r) == IORESOURCE_MEM)
  20.                 p = &iomem_resource;
  21.             else if (resource_type(r) == IORESOURCE_IO)
  22.                 p = &ioport_resource;
  23.         }
  24.         if (p && insert_resource(p, r)) {
  25.             ret = -EBUSY;
  26.             goto failed;
  27.         }
  28.     }
  29.     ret = device_add(&pdev->dev);     //2.1
  30. }
2.1 device_add
platform_add_devices               ;add多个devices
    --> platform_device_add      ;add单个devices
    --> device_add
  1. int device_add(struct device *dev)
  2. {
  3.     struct class_interface *class_intf;
  4.     if (!dev->p) {
  5.         error = device_private_init(dev);
  6.     }
  7.     if (dev->init_name) {
  8.         dev_set_name(dev, "%s", dev->init_name);
  9.         dev->init_name = NULL;
  10.     }
  11.     parent = get_device(dev->parent);
  12.     setup_parent(dev, parent);
  13.     if (parent)
  14.         set_dev_node(dev, dev_to_node(parent));

  15.     error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);   
  16.     if (platform_notify)
  17.         platform_notify(dev);
  18.     //在sysfs目录下为device创建文件
  19.     error = device_create_file(dev, &uevent_attr);

  20.     if (MAJOR(dev->devt)) {
  21.         device_create_file(dev, &devt_attr);
  22.         device_create_sys_dev_entry(dev);
  23.         devtmpfs_create_node(dev);
  24.     }
  25.     device_add_class_symlinks(dev);
  26.     device_add_attrs(dev);   
  27.     bus_add_device(dev);               //将设备添加到总线下,说白了就是在链表里面加个值klist_add_tail
  28.     dpm_sysfs_add(dev);  
  29.     device_pm_add(dev);
  30.     if (dev->bus)
  31.         blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_ADD_DEVICE, dev);
  32.     kobject_uevent(&dev->kobj, KOBJ_ADD);
  33.     bus_probe_device(dev);              //最关心的部分:匹配驱动
  34.     if (parent)
  35.         klist_add_tail(&dev->p->knode_parent,&parent->p->klist_children);

  36.     if (dev->class) {
  37.         mutex_lock(&dev->class->p->class_mutex);
  38.         klist_add_tail(&dev->knode_class,  &dev->class->p->klist_devices);
  39.         list_for_each_entry(class_intf,  &dev->class->p->class_interfaces, node)
  40.             if (class_intf->add_dev)
  41.                 class_intf->add_dev(dev, class_intf);
  42.         mutex_unlock(&dev->class->p->class_mutex);
  43.     }
  44. }
2.2 bus_probe_device
platform_add_devices               ;add多个devices
    --> platform_device_add      ;add单个devices
    --> device_add
   --> bus_probe_device          ;匹配驱动
  1. void bus_probe_device(struct device *dev)
  2. {
  3.     struct bus_type *bus = dev->bus;
  4.     if (bus && bus->p->drivers_autoprobe) {
  5.         device_attach(dev);       
  6.     }
  7. }
2.3 device_attach
platform_add_devices               ;add多个devices
    --> platform_device_add      ;add单个devices
    --> device_add
   --> bus_probe_device          ;匹配驱动
   --> device_attach           
如果己经指定了驱动就直接device_bind_driver
如果没有指定驱动,对bus上所有的驱动查找并匹配驱动
  1. int device_attach(struct device *dev)
  2. {
  3.     device_lock(dev);
  4.     if (dev->driver) {
  5.         if (klist_node_attached(&dev->p->knode_driver)) {
  6.             ret = 1;
  7.             goto out_unlock;
  8.         }
  9.         ret = device_bind_driver(dev);
  10.         if (ret == 0)
  11.             ret = 1;
  12.         else {
  13.             dev->driver = NULL;
  14.             ret = 0;
  15.         }
  16.     } else {
  17.         pm_runtime_get_noresume(dev);
  18.         //对注册进bus的所有驱动匹配device,会调用bus的platform_match
  19.         //匹配过程很简单比较name-->strcmp(pdev->name, drv->name) == 0,说明匹配成功.
  20.         ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
  21.         pm_runtime_put_sync(dev);
  22.     }
  23. out_unlock:
  24.     device_unlock(dev);
  25.     return ret;
  26. }

二. platform_driver_register的过程
1. 在驱动中调用platform_driver_register注册驱动
以dm9000的注册为例,在driver/net/dm9000.c中
  1. static struct platform_driver dm9000_driver = {
  2.     .driver    = {
  3.         .name = "dm9000",
  4.         .owner     = THIS_MODULE,
  5.         .pm     = &dm9000_drv_pm_ops,
  6.     },
  7.     .probe = dm9000_probe,
  8.     .remove = __devexit_p(dm9000_drv_remove),
  9. };

  10. static int __init dm9000_init(void)
  11. {
  12.     return platform_driver_register(&dm9000_driver);
  13. }
2. platform_driver的注册过程
在driver/base/platform.c中
  1. int platform_driver_register(struct platform_driver *drv)
  2. {
  3.     drv->driver.bus = &platform_bus_type;
  4.     if (drv->probe)
  5.         drv->driver.probe = platform_drv_probe;
  6.     if (drv->remove)
  7.         drv->driver.remove = platform_drv_remove;
  8.     if (drv->shutdown)
  9.         drv->driver.shutdown = platform_drv_shutdown;

  10.     return driver_register(&drv->driver);
  11. }
platform_driver_register
    --> driver_register
在drivers/base/driver.c中
  1. int driver_register(struct device_driver *drv)
  2. {
  3.     struct device_driver *other;
  4.     //看一下驱动是否己被加载过,如果有,打钱"Driver name is already registered"
  5.     other = driver_find(drv->name, drv->bus);
  6.     bus_add_driver(drv);                       //向总线中添加驱动
  7.     driver_add_groups(drv, drv->groups);
  8. }

platform_driver_register
    --> driver_register
    --> bus_add_driver
在drivers/base/bus.c中
  1. int bus_add_driver(struct device_driver *drv)
  2. {
  3.     struct bus_type *bus;
  4.     struct driver_private * priv = kzalloc(sizeof(*priv), GFP_KERNEL);
  5.     klist_init(&priv->klist_devices, NULL, NULL);
  6.     priv->driver = drv;
  7.     drv->p = priv;
  8.     priv->kobj.kset = bus->p->drivers_kset;
  9.     kobject_init_and_add(&priv->kobj, &driver_ktype, NULL, "%s", drv->name);
  10.     if (drv->bus->p->drivers_autoprobe)
  11.         driver_attach(drv);                  //向总线中添加驱动   
  12.     klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
  13.     module_add_driver(drv->owner, drv);
  14.     error = driver_create_file(drv, &driver_attr_uevent);   
  15.     error = driver_add_attrs(bus, drv);   
  16.     if (!drv->suppress_bind_attrs) {
  17.         add_bind_files(drv);      
  18.     }

  19.     kobject_uevent(&priv->kobj, KOBJ_ADD);
  20.     return 0;
  21. }
platform_driver_register
    --> driver_register
    --> bus_add_driver
            --> driver_attach
在drivers/base/dd.c中
  1. int driver_attach(struct device_driver *drv)
  2. {
  3.     //遍历总线上的所有设备,调用__driver_attachdriver
  4.     return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); 
  5. }
platform_driver_register
    --> driver_register
    --> bus_add_driver
            --> driver_attach
                --> __driver_attach
这个函数很关键,即有驱动与设备的匹配过程,又调用了驱动的probe函数
  1. static int __driver_attach(struct device *dev, void *data)
  2. {
  3.     struct device_driver *drv = data;
  4.     //如果drv->bus->match存在就调用来匹配drv与dev,匹配不成功则返回
  5.     //注意这个返回值(strcmp(a,b)==0),匹配成功返回1,不成功返回0
  6.     if (!driver_match_device(drv, dev))
  7.         return 0;
  8.     if (dev->parent)    
  9.         device_lock(dev->parent);
  10.     device_lock(dev);
  11.     if (!dev->driver)
  12.         driver_probe_device(drv, dev);  //驱动与设备匹配成功后就会调用驱动的probe函数
  13.     device_unlock(dev);
  14.     if (dev->parent)
  15.         device_unlock(dev->parent);
  16.     return 0;
  17. }
2.1 驱动匹配设备的过程
platform_driver_register

    --> driver_register
    --> bus_add_driver
            --> driver_attach
             --> __driver_attach
                  --> drvier_match_device
  1. static inline int driver_match_device(struct device_driver *drv, struct device *dev)
  2. {
  3.     return drv->bus->match ? drv->bus->match(dev, drv) : 1;
  4. }
platform_driver_register函数中有
    drv->driver.bus = &platform_bus_type;
  1. struct bus_type platform_bus_type = {
  2.     .name = "platform",
  3.     .dev_attrs = platform_dev_attrs,
  4.     .match = platform_match,
  5.     .uevent = platform_uevent,
  6.     .pm = &platform_dev_pm_ops,
  7. };
在driver/base/platform.c中
  1. static int platform_match(struct device *dev, struct device_driver *drv)
  2. {
  3.     struct platform_device *pdev = to_platform_device(dev);
  4.     struct platform_driver *pdrv = to_platform_driver(drv);

  5.     if (of_driver_match_device(dev, drv))
  6.         return 1;
  7.     if (pdrv->id_table)   //如果有id_table,驱动可以支持多个设备
  8.         return platform_match_id(pdrv->id_table, pdev) != NULL;

  9.     return (strcmp(pdev->name, drv->name) == 0);   //还是strcmp
  10. }
id_table的解析过程
  1. static const struct platform_device_id *platform_match_id(
  2.             const struct platform_device_id *id,
  3.             struct platform_device *pdev)
  4. {
  5.     while (id->name[0]) {
  6.         if (strcmp(pdev->name, id->name) == 0) {   //还是strcmp
  7.             pdev->id_entry = id;
  8.             return id;
  9.         }
  10.         id++;
  11.     }
  12.     return NULL;
  13. }
2.2 调用驱动程序probe的过程
platform_driver_register
    --> driver_register
    --> bus_add_driver
            --> driver_attach
                --> __driver_attach
其中的参数drv与dev是匹配成功的两个drv与dev
在drivers/base/dd.c中
  1. int driver_probe_device(struct device_driver *drv, struct device *dev)
  2. {
  3.     int ret = 0;
  4.     if (!device_is_registered(dev))
  5.         return -ENODEV;

  6.     pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
  7.          drv->bus->name, __func__, dev_name(dev), drv->name);

  8.     pm_runtime_get_noresume(dev);
  9.     pm_runtime_barrier(dev);
  10.     ret = really_probe(dev, drv);        //really_probe,这名字起得,莫非以前都在玩我吗?
  11.     pm_runtime_put_sync(dev);

  12.     return ret;
  13. }
真的要调用probe了
在drivers/base/dd.c中
  1. static int really_probe(struct device *dev, struct device_driver *drv)
  2. {
  3.     atomic_inc(&probe_count);
  4.     dev->driver = drv;
  5.     driver_sysfs_add(dev);   
  6.     if (dev->bus->probe)             
  7.         ret = dev->bus->probe(dev);       
  8.     else if (drv->probe)
  9.         ret = drv->probe(dev);    //终于要调用驱动的probe了,传给probe的参数是匹配的设备
  10.     driver_bound(dev);   
  11. }

三. 总结

    1. 不论注册device还是注册driver都会遍历bus对其中的driver或device进行匹配
    2. 驱动调用了platform_device_register之后会调用驱动的probe函数.

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