您的位置:首页 > 其它

平台总线设备模型

2012-01-19 15:23 211 查看
平台总线是内核实现的一条虚拟总线,Linux设备模型包含三个重要的元素,总线、设备和驱动,那看看平台总线又是怎样去实现的。
首先看平台总线的定义:
946 struct bus_type platform_bus_type = { 
 947         .name           = "platform", 
 948         .dev_attrs      = platform_dev_attrs, 
 949         .match          = platform_match, 
 950         .uevent         = platform_uevent, 
 951         .pm             = &platform_dev_pm_ops, 
 952 };

我们知道总线匹配设备和驱动是通过它的match函数,那具体看看这个函数是怎样实现的。
606 static int platform_match(struct device *dev, struct device_driver *drv) 
 607 { 
 608         struct platform_device *pdev = to_platform_device(dev); 
 609         struct platform_driver *pdrv = to_platform_driver(drv); 
 610 
 611         /* match against the id table first */ 
 612         if (pdrv->id_table) 
 613                 return platform_match_id(pdrv->id_table, pdev) != NULL; 
 614 
 615         /* fall-back to driver name match */ 
 616         return (strcmp(pdev->name, drv->name) == 0); 
 617 }

我们看,如果平台驱动有一个id_table,那就通过函数platform_match_id去匹配,如果没有就比较平台设备的name字段和平台驱动的name字段是否相同,这也就是平台总线的匹配规则。再来看平台总线的注册。

955 int __init platform_bus_init(void) 
 956 { 
 957         int error; 
 958 
 959         early_platform_cleanup(); 
 960 
 961         error = device_register(&platform_bus); 
 962         if (error) 
 963                 return error; 
 964         error =  bus_register(&platform_bus_type); 
 965         if (error) 
 966                 device_unregister(&platform_bus); 
 967         return error; 
 968 }


我们看平台总线注册就是采用的bus_register函数,再看在注册平台总线之前,还调用了
device_register去注册了一个设备,因为总线它也是一个设备,也要被注册进内核。那就具体来看这个设备是怎么定义的。
28 struct device platform_bus = { 
  29         .init_name      = "platform", 
  30 }; 
  31 EXPORT_SYMBOL_GPL(platform_bus);

我们看就给了一个名字。看完了总线,又来看看平台设备又是怎样定义怎样去注册。
17 struct platform_device { 
 18         const char      * name; 
 19         int             id; 
 20         struct device   dev; 
 21         u32             num_resources; 
 22         struct resource * resource; 
 23 
 24         struct platform_device_id       *id_entry; 
 25 
 26         /* arch specific additions */ 
 27         struct pdev_archdata    archdata; 
 28 };

其中有个重要的元素resource,该元素存入的最重要的设备资源信息,比如I/O基地址,中断号等等。structresource结构定义在include/linux/ioport.h中
18 struct resource { 
 19         resource_size_t start; 
 20         resource_size_t end; 
 21         const char *name; 
 22         unsigned long flags; 
 23         struct resource *parent, *sibling, *child; 
 24 };

有可能设备的资源不只一个,定义资源时定义成一个数组的形式,那就使用函数去获取,
platform_get_resource就是用来获取设备的资源信息,去看看这个函数
33 /** 
  34  * platform_get_resource - get a resource for a device 
  35  * @dev: platform device 
  36  * @type: resource type 
  37  * @num: resource index 
  38  */ 
  39 struct resource *platform_get_resource(struct platform_device *dev, 
  40                                        unsigned int type, unsigned int num) 
  41 { 
  42         int i; 
  43 
  44         for (i = 0; i < dev->num_resources; i++) { 
  45                 struct resource *r = &dev->resource[i]; 
  46 
  47                 if (type == resource_type(r) && num-- == 0) 
  48                         return r; 
  49         } 
  50         return NULL; 
  51 } 
  52 EXPORT_SYMBOL_GPL(platform_get_resource);

这个函数的第一个参数为要获取资源的平台设备,第二个参数为资源类型,比如IORESOURCE_MEM,第三个参数为资源在数组中的一个号。如果是获取中断号,还可以使用函数platform_get_irq
54 /** 
  55  * platform_get_irq - get an IRQ for a device 
  56  * @dev: platform device 
  57  * @num: IRQ number index 
  58  */ 
  59 int platform_get_irq(struct platform_device *dev, unsigned int num) 
  60 { 
  61         struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num); 
  62 
  63         return r ? r->start : -ENXIO; 
  64 } 
  65 EXPORT_SYMBOL_GPL(platform_get_irq);

我们看这个函数也是调用platform_get_resource去获取资源,只是它获取资源的类型为IORESOURCE_IRQ,最后返回中断号。
再来看平台设备的注册,平台设备注册采用platform_device_register函数
54 /** 
  55  * platform_get_irq - get an IRQ for a device 
  56  * @dev: platform device 
  57  * @num: IRQ number index 
  58  */ 
  59 int platform_get_irq(struct platform_device *dev, unsigned int num) 
  60 { 
  61         struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num); 
  62 
  63         return r ? r->start : -ENXIO; 
  64 } 
  65 EXPORT_SYMBOL_GPL(platform_get_irq);

device_initialize就是device_register那的函数,那就看platform_device_add
227 /** 
 228  * platform_device_add - add a platform device to device hierarchy 
 229  * @pdev: platform device we're adding 
 230  * 
 231  * This is part 2 of platform_device_register(), though may be called 
 232  * separately _iff_ pdev was allocated by platform_device_alloc(). 
 233  */ 
 234 int platform_device_add(struct platform_device *pdev) 
 235 { 
 236         int i, ret = 0; 
 237 
 238         if (!pdev) 
 239                 return -EINVAL; 
 240 
 241         if (!pdev->dev.parent) 
 242                 pdev->dev.parent = &platform_bus; 
 243 
 244         pdev->dev.bus = &platform_bus_type; 
 245 
 246         if (pdev->id != -1) 
 247                 dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id); 
 248         else 
 249                 dev_set_name(&pdev->dev, "%s", pdev->name); 
 250 
 251         for (i = 0; i < pdev->num_resources; i++) { 
 252                 struct resource *p, *r = &pdev->resource[i]; 
 253 
 254                 if (r->name == NULL) 
 255                         r->name = dev_name(&pdev->dev); 
 256 
 257                 p = r->parent; 
 258                 if (!p) { 
 259                         if (resource_type(r) == IORESOURCE_MEM) 
 260                                 p = &iomem_resource; 
 261                         else if (resource_type(r) == IORESOURCE_IO) 
 262                                 p = &ioport_resource; 
 263                 } 
 264 
 265                 if (p && insert_resource(p, r)) { 
 266                         printk(KERN_ERR 
 267                                "%s: failed to claim resource %d\n", 
 268                                dev_name(&pdev->dev), i); 
 269                         ret = -EBUSY; 
 270                         goto failed; 
 271                 } 
 272         } 
 273 
 274         pr_debug("Registering platform device '%s'. Parent at %s\n", 
 275                  dev_name(&pdev->dev), dev_name(pdev->dev.parent)); 
 276 
 277         ret = device_add(&pdev->dev); 
 278         if (ret == 0) 
 279                 return ret; 
 280 
 281  failed: 
 282         while (--i >= 0) { 
 283                 struct resource *r = &pdev->resource[i]; 
 284                 unsigned long type = resource_type(r); 
 285 
 286                 if (type == IORESOURCE_MEM || type == IORESOURCE_IO) 
 287                         release_resource(r); 
 288         } 
 289 
 290         return ret; 
 291 } 
 292 EXPORT_SYMBOL_GPL(platform_device_add);

最终调用device_register那的device_add完成平台设备的注册。
我们也可以使用platform_add_devices去注册一组平台设备
103 /** 
 104  * platform_add_devices - add a numbers of platform devices 
 105  * @devs: array of platform devices to add 
 106  * @num: number of platform devices in array 
 107  */ 
 108 int platform_add_devices(struct platform_device **devs, int num) 
 109 { 
 110         int i, ret = 0; 
 111 
 112         for (i = 0; i < num; i++) { 
 113                 ret = platform_device_register(devs[i]); 
 114                 if (ret) { 
 115                         while (--i >= 0) 
 116                                 platform_device_unregister(devs[i]); 
 117                         break; 
 118                 } 
 119         } 
 120 
 121         return ret; 
 122 } 
 123 EXPORT_SYMBOL_GPL(platform_add_devices);

看完了注册来看注销函数,注销函数就是platform_device_unregister。
331 /** 
 332  * platform_device_unregister - unregister a platform-level device 
 333  * @pdev: platform device we're unregistering 
 334  * 
 335  * Unregistration is done in 2 steps. First we release all resources 
 336  * and remove it from the subsystem, then we drop reference count by 
 337  * calling platform_device_put(). 
 338  */ 
 339 void platform_device_unregister(struct platform_device *pdev) 
 340 { 
 341         platform_device_del(pdev); 
 342         platform_device_put(pdev); 
 343 } 
 344 EXPORT_SYMBOL_GPL(platform_device_unregister); 
 294 /** 
 295  * platform_device_del - remove a platform-level device 
 296  * @pdev: platform device we're removing 
 297  * 
 298  * Note that this function will also release all memory- and port-based 
 299  * resources owned by the device (@dev->resource).  This function must 
 300  * _only_ be externally called in error cases.  All other usage is a bug. 
 301  */ 
 302 void platform_device_del(struct platform_device *pdev) 
 303 { 
 304         int i; 
 305 
 306         if (pdev) { 
 307                 device_del(&pdev->dev); 
 308 
 309                 for (i = 0; i < pdev->num_resources; i++) { 
 310                         struct resource *r = &pdev->resource[i]; 
 311                         unsigned long type = resource_type(r); 
 312 
 313                         if (type == IORESOURCE_MEM || type == IORESOURCE_IO) 
 314                                 release_resource(r); 
 315                 } 
 316         } 
 317 } 
 318 EXPORT_SYMBOL_GPL(platform_device_del);

device_del就是device_unregister那的函数
再来看驱动,平台设备驱动结构定义
58 struct platform_driver { 
 59         int (*probe)(struct platform_device *); 
 60         int (*remove)(struct platform_device *); 
 61         void (*shutdown)(struct platform_device *); 
 62         int (*suspend)(struct platform_device *, pm_message_t state); 
 63         int (*resume)(struct platform_device *); 
 64         struct device_driver driver; 
 65         struct platform_device_id *id_table; 
 66 };

驱动注册
474 /** 
 475  * platform_driver_register 
 476  * @drv: platform driver structure 
 477  */ 
 478 int platform_driver_register(struct platform_driver *drv) 
 479 { 
 480         drv->driver.bus = &platform_bus_type; 
 481         if (drv->probe) 
 482                 drv->driver.probe = platform_drv_probe; 
 483         if (drv->remove) 
 484                 drv->driver.remove = platform_drv_remove; 
 485         if (drv->shutdown) 
 486                 drv->driver.shutdown = platform_drv_shutdown; 
 487 
 488         return driver_register(&drv->driver); 
 489 } 
 490 EXPORT_SYMBOL_GPL(platform_driver_register);

平台驱动结构里面有个成员driver,它是device_driver结构类型,它的probe函数指针赋值了这里的platform_drv_probe,也就是平台总线匹配设备和驱动成功后,将调用这里的
platform_drv_probe函数,那就在去看看这个函数。
445 static int platform_drv_probe(struct device *_dev) 
 446 { 
 447         struct platform_driver *drv = to_platform_driver(_dev->driver); 
 448         struct platform_device *dev = to_platform_device(_dev); 
 449 
 450         return drv->probe(dev); 
 451 }

还有一点的是它的remove函数为这里的platform_drv_remove,不管是设备注销还是驱动注销都是先调用这个函数,然后才调用平台驱动的remove函数。
458 static int platform_drv_remove(struct device *_dev) 
 459 { 
 460         struct platform_driver *drv = to_platform_driver(_dev->driver); 
 461         struct platform_device *dev = to_platform_device(_dev); 
 462 
 463         return drv->remove(dev); 
 464 }

也就是最后调用platform_driver的probe函数,它的参数dev是platform_device结构类型。注意这里有两个probe,一个是platform_driver的probe,它是要求我们在编写平台设备驱动时自己去定义,另一个是device_driver的probe,它供总线匹配设备和驱动成功后调用,probe为这里的platform_drv_probe,这个函数的功能就是调用platform_driver的probe。
平台设备驱动注册最后调用的就是driver_register,只不过这里的总线是平台总线。
驱动注销
492 /** 
 493  * platform_driver_unregister 
 494  * @drv: platform driver structure 
 495  */ 
 496 void platform_driver_unregister(struct platform_driver *drv) 
 497 { 
 498         driver_unregister(&drv->driver); 
 499 } 
 500 EXPORT_SYMBOL_GPL(platform_driver_unregister);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: