作者:刘昊昱
博客: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 * "<name><instance>", where <name> is a short description of the type of 717 * device, like "pci" or "floppy", and <instance> is the enumerated 718 * instance of the device, like '0' or '42'. Driver IDs are simply 719 * "<name>". So, extract the <name> 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内核)》一文中已经分析过,这里不再重复。