0
点赞
收藏
分享

微信扫一扫

ldd3学习之十一(3):Linux设备模型---platform总线分析


platform机制由两部分组成,platform_device和platform_driver。

Platform驱动与传统的设备驱动模型(即通过driver_register函数进行注册)相比,优势在于platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序使用这些资源时使用统一的接口(即通过platform device提供的标准接口),这样提高了程序可移植性。

platform 是一个虚拟的地址总线,相比 PCI、USB、I2C,它主要用于描述 SOC 上的片上资源。比如 S3C2410 上集成的控制器( LCD、Watchdog、RTC等),platform 所描述的资源有一个共同点:在 CPU 的总线上直接取址。

用platform


1.平台设备

(1)描述

  1. struct platform_device {
  2. const char    * name;//设备名字
  3. int        id;       //设备编号
  4. ;
  5. ;
  6. * resource;//设备资源

  7. *id_entry;

  8. /* arch specific additions */
  9. ;
  10. };

(2)分配

  1. struct platform_device *platform_device_alloc(const char *name, unsigned int id)
  2. name:设备名
  3. id:一般为-1

(3)注册

  1. int platform_device_add(struct platform_device *pdev)
  2. {
  3. //增加的platform设备,都以platform_bus(platform设备)为父节点
  4. if (!pdev->dev.parent) pdev->dev.parent = &platform_bus;

  5. //platform类型设备都挂接在platform总线上 /sys/bus/platform/
  6. pdev->dev.bus = &platform_bus_type;
  7. .
  8. .
  9. .
  10. }

(4)资源描述

  1. /*
  2. * Resources are tree-like, allowing
  3. * nesting etc..
  4. */
  5. {
  6. ;//资源的起始物理地址
  7. end;  //资源的结束物理地址
  8. const char *name;     //资源名称
  9. ;  //资源类型,MEM,IO,IRQ
  10. *parent, *sibling, *child; //资源链表指针
  11. };

比如linux-2.6.32内核自带的s3c2410-wdt设备加载过程如下

  1. /* Watchdog */
  2. #define S3C24XX_VA_WATCHDOG S3C_VA_WATCHDOG
  3. #define S3C2410_PA_WATCHDOG (0x53000000)
  4. #define S3C24XX_SZ_WATCHDOG SZ_1M

  5. #define S3C24XX_PA_WATCHDOG S3C2410_PA_WATCHDOG

  6. [] = {
  7. [0] = {//硬件寄存器资源
  8. .start = S3C24XX_PA_WATCHDOG, //0x53000000
  9. .end = S3C24XX_PA_WATCHDOG + S3C24XX_SZ_WATCHDOG - 1,
  10. .flags = IORESOURCE_MEM,
  11. },
  12. [1] = {//中断资源
  13. .start = IRQ_WDT,
  14. .end = IRQ_WDT,
  15. .flags = IORESOURCE_IRQ,
  16. }

  17. };

  18. = {
  19. .name         = "s3c2410-wdt",//name要与platform_driver中的name一致
  20. .id         = -1,
  21. .num_resources     = ARRAY_SIZE(s3c_wdt_resource),
  22. .resource     = s3c_wdt_resource,
  23. };
  24. static struct platform_device *smdk2440_devices[] __initdata = {
  25. &s3c_device_usb,
  26. &s3c_device_lcd,
  27. &s3c_device_wdt,//platform_device指针
  28. &s3c_device_i2c0,
  29. &s3c_device_iis,
  30. };
  31. static void __init smdk2440_machine_init(void)
  32. {
  33. s3c24xx_fb_set_platdata(&smdk2440_fb_info);
  34. s3c_i2c0_set_platdata(NULL);

//添加所有platform设备


  1. platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
  2. smdk_machine_init();
  3. }

  4. MACHINE_START(S3C2440, "SMDK2440")
  5. /* Maintainer: Ben Dooks */
  6. .phys_io = S3C2410_PA_UART,
  7. .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
  8. .boot_params = S3C2410_SDRAM_PA + 0x100,

  9. .init_irq = s3c24xx_init_irq,
  10. .map_io = smdk2440_map_io,
  11. .init_machine = smdk2440_machine_init,
  12. .timer = &s3c24xx_timer,
  13. MACHINE_END


(5)获取资源方法

  1. /**
  2. * platform_get_resource - get a resource for a device
  3. * @dev: platform device
  4. * @type: resource type
  5. * @num: resource index
  6. */
  7. *platform_get_resource(struct platform_device *dev,
  8. int type, unsigned int num)
  9. dev:资源所属设备
  10. type:获取资源类型
  11. num:获取的资源index
  12. 比如:
  13. platform_get_resource(pdev,IORESOURCE_IRQ,0)//获取中断号
  14. platform_get_resource(pdev,IORESOURCE_MEM,0)//获取第0个资源

2.平台驱动

(1)描述

  1. struct platform_driver {
  2. int (*probe)(struct platform_device *);
  3. int (*remove)(struct platform_device *);
  4. (*shutdown)(struct platform_device *);
  5. int (*suspend)(struct platform_device *, pm_message_t state);
  6. int (*resume)(struct platform_device *);
  7. ;
  8. *id_table;
  9. };

(2)注册

  1. /**
  2. * platform_driver_register
  3. * @drv: platform driver structure
  4. */
  5. int platform_driver_register(struct platform_driver *drv)

在2.6.32内核s3c2410_wdt.c中实例注册过程


  1. static struct platform_driver s3c2410wdt_driver = {
  2. .probe        = s3c2410wdt_probe,
  3. .remove        = __devexit_p(s3c2410wdt_remove),
  4. .shutdown    = s3c2410wdt_shutdown,
  5. .suspend    = s3c2410wdt_suspend,
  6. .resume        = s3c2410wdt_resume,
  7. .driver        = {
  8. .owner    = THIS_MODULE,
  9. //名字与platform_device中的name一致
  10. },
  11. };
  12. static int __init watchdog_init(void)
  13. {
  14. printk(banner);
  15. return platform_driver_register(&s3c2410wdt_driver);
  16. }

  17. static void __exit watchdog_exit(void)
  18. {
  19. platform_driver_unregister(&s3c2410wdt_driver);
  20. }
  21. module_init(watchdog_init);
  22. module_exit(watchdog_exit);

(3)probe函数

执行时机:当所加载驱动与相应设备匹配成功

功能:获得设备资源,完成一个设备驱动所有的操作接口

(4)remove函数

执行:设备或驱动移除时

功能:释放probe申请的一切资源

比如s3c2410_wdt.c
1. /* device interface */
2.
3. int __devinit s3c2410wdt_probe(struct platform_device *pdev)
4. {
5. *res;
6. *dev;
7. int wtcon;
8. int started = 0;
9. int ret;
10. int size;
11.
12. ("%s: probe=%p\n", __func__, pdev);
13.
14. = &pdev->dev;
15. = &pdev->dev;
16.
17. /* get the memory region for the watchdog timer */
18.
19. = platform_get_resource(pdev, IORESOURCE_MEM, 0);//获得资源,物理地址
20. if (res == NULL) {
21. (dev, "no memory resource specified\n");
22. -ENOENT;
23. }
24.
25. = (res->end - res->start) + 1;
26. = request_mem_region(res->start, size, pdev->name);
27. if (wdt_mem == NULL) {
28. (dev, "failed to get memory region\n");
29. = -ENOENT;
30. ;
31. }
32.
33. = ioremap(res->start, size);
34. if (wdt_base == NULL) {
35. (dev, "failed to ioremap() region\n");
36. = -EINVAL;
37. ;
38. }
39.
40. ("probe: mapped wdt_base=%p\n", wdt_base);
41.
42. = platform_get_resource(pdev, IORESOURCE_IRQ, 0);//获得中断号
43. if (wdt_irq == NULL) {
44. (dev, "no irq resource specified\n");
45. = -ENOENT;
46. ;
47. }
48.
49. = request_irq(wdt_irq->start, s3c2410wdt_irq, 0, pdev->name, pdev);//注册中断
50. if (ret != 0) {
51. (dev, "failed to install irq (%d)\n", ret);
52. ;
53. }
54.
55. = clk_get(&pdev->dev, "watchdog");
56. if (IS_ERR(wdt_clock)) {
57. (dev, "failed to find watchdog clock source\n");
58. = PTR_ERR(wdt_clock);
59. ;
60. }
61.
62. (wdt_clock);
63.
64. /* see if we can actually set the requested timer margin, and if
65. * not, try the default value */
66.
67. if (s3c2410wdt_set_heartbeat(tmr_margin)) {
68. = s3c2410wdt_set_heartbeat(
69. );
70.
71. if (started == 0)
72. (dev,
73. "tmr_margin value out of range, default %d used\n",
74. );
75. else
76. (dev, "default timer value is out of range, "
77. "cannot start\n");
78. }
79.
80. = misc_register(&s3c2410wdt_miscdev);
81. if (ret) {
82. (dev, "cannot register miscdev on minor=%d (%d)\n",
83. , ret);
84. ;
85. }
86.
87. if (tmr_atboot && started == 0) {
88. (dev, "starting watchdog timer\n");
89. ();
90. } else if (!tmr_atboot) {
91. /* if we're not enabling the watchdog, then ensure it is
92. * disabled if it has been left running from the bootloader
93. * or other source */
94.
95. ();
96. }
97.
98. /* print out a statement of readiness */
99.
100. = readl(wdt_base + S3C2410_WTCON);
101.
102. (dev, "watchdog %sactive, reset %sabled, irq %sabled\n",
103. (wtcon & S3C2410_WTCON_ENABLE) ? "" : "in",
104. (wtcon & S3C2410_WTCON_RSTEN) ? "" : "dis",
105. (wtcon & S3C2410_WTCON_INTEN) ? "" : "en");
106.
107. ;
108.
109. :
110. (wdt_clock);
111. (wdt_clock);
112.
113. :
114. (wdt_irq->start, pdev);
115.
116. :
117. (wdt_base);
118.
119. :
120. (wdt_mem);
121. (wdt_mem);
122.
123. ;
124. }

3.平台总线

(1)描述

  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. };

(2)match方法:当platform总线上有设备或驱动变化时执行一次或多次

  1. static int platform_match(struct device *dev, struct device_driver *drv)
  2. {
  3. *pdev = to_platform_device(dev);
  4. *pdrv = to_platform_driver(drv);

  5. /* match against the id table first */
  6. if (pdrv->id_table)
  7. (pdrv->id_table, pdev) != NULL;

  8. /* fall-back to driver name match */
  9. (strcmp(pdev->name, drv->name) == 0); //比较name成员
  10. }

4.小结:

(1)当platform总线上有设备或驱动加入时,platform总线的match方法被调用一次或多次,遍历所有设备,一旦name成员与driver匹配成功,调用driver的probe方法,移除时调用remove方法。

(2)platform总线只是提供了一个管理硬件资源与设备的机制,驱动接口真正的实现在probe()函数内完成。

一个简单的platform机制测试代码:​​ platform.rar ​​  

实验结果:​​​​


举报

相关推荐

0 条评论