http://blog.csdn.net/mcgrady_tracy/article/details/7210915
平台总线是内核实现的一条虚拟总线,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);