Chinaunix首页 | 论坛 | 博客
  • 博客访问: 411221
  • 博文数量: 118
  • 博客积分: 294
  • 博客等级: 二等列兵
  • 技术积分: 667
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-16 20:31
文章分类

全部博文(118)

文章存档

2014年(3)

2012年(25)

2011年(90)

分类:

2012-02-02 23:01:20

原文地址:Linux驱动修炼之道-platform 作者:TerryJk

首先看一下我的系统中都有什么设备挂在了platform虚拟总线上:

  1. hacker@hacker:~/linux-2.6.30.4$ cd /sys/bus/platform/
  2. hacker@hacker:/sys/bus/platform$ tree
  3. .
  4. |-- devices
  5. | |-- Fixed MDIO bus.0 -> ../../../devices/platform/Fixed MDIO bus.0
  6. | |-- eisa.0 -> ../../../devices/platform/eisa.0
  7. | |-- i8042 -> ../../../devices/platform/i8042
  8. | |-- pcspkr -> ../../../devices/platform/pcspkr
  9. | |-- rtc_cmos -> ../../../devices/platform/rtc_cmos
  10. | `-- serial8250 -> ../../../devices/platform/serial8250
  11. |-- drivers
  12. | |-- dsa
  13. | | |-- bind
  14. | | |-- uevent
  15. | | `-- unbind
  16. | |-- i8042
  17. | | |-- bind
  18. | | |-- i8042 -> ../../../../devices/platform/i8042
  19. | | |-- uevent
  20. | | `-- unbind
  21. | |-- mdio-gpio
  22. | | |-- bind
  23. | | |-- uevent
  24. | | `-- unbind
  25. | |-- parport_pc
  26. | | |-- bind
  27. | | |-- module -> ../../../../module/parport_pc
  28. | | |-- uevent
  29. | | `-- unbind
  30. | |-- rtc_cmos
  31. | | |-- bind
  32. | | |-- rtc_cmos -> ../../../../devices/platform/rtc_cmos
  33. | | |-- uevent
  34. | | `-- unbind
  35. | |-- serial8250
  36. | | |-- bind
  37. | | |-- serial8250 -> ../../../../devices/platform/serial8250
  38. | | |-- uevent
  39. | | `-- unbind
  40. | `-- twl4030_reg
  41. | |-- bind
  42. | |-- uevent
  43. | `-- unbind
  44. |-- drivers_autoprobe
  45. |-- drivers_probe
  46. `-- uevent

  47. 19 directories, 24 files

platform的初始化:首先系统启动的时候会调用platform_bus_init来初始化这个虚拟总线,让后向虚拟总线注册即将挂载这条总线上的设备。platform_bus_type部分是内核为我们实现好的,我们只关系platform_device与platform_driver就行了。

  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_PM_OPS_PTR,
  7. };
  8. EXPORT_SYMBOL_GPL(platform_bus_type);

  9. int __init platform_bus_init(void)
  10. {
  11.     int error;

  12.     early_platform_cleanup();

  13.     error = device_register(&platform_bus);
  14.     if (error)
  15.         return error;
  16.     error = bus_register(&platform_bus_type);
  17.     if (error)
  18.         device_unregister(&platform_bus);
  19.     return error;
  20. }

记住总线也是一种设备,所以首先注册总线设备,然后注册总线。

  1. static struct platform_device *smdk2410_devices[] __initdata = {
  2.     &s3c_device_usb,
  3.     &s3c_device_lcd,
  4.     &s3c_device_wdt,
  5.     &s3c_device_i2c0,
  6.     &s3c_device_iis,
  7. };

把设备挂到platform总线上:

  1. static void __init smdk2410_init(void)
  2. {
  3.     s3c_i2c0_set_platdata(NULL);
  4.     platform_add_devices(smdk2410_devices, ARRAY_SIZE(smdk2410_devices));
  5.     smdk_machine_init();
  6. }
首先来看一个重要的数据结构
  1. struct resource {
  2.     resource_size_t start; /*资源的起始物理地址*/
  3.     resource_size_t end; /*资源的结束物理地址*/
  4.     const char *name; /*资源的名称*/
  5.     unsigned long flags; /*资源的类型*/
  6.     struct resource *parent, *sibling, *child; /*资源的链表指针*/
  7. };

  8. struct platform_device {
  9.     const char    * name; /*设备名*/
  10.     int        id; /*设备编号,配合设备名使用*/
  11.     struct device    dev;
  12.     u32        num_resources;
  13.     struct resource    * resource; /*设备资源*/

  14.     struct platform_device_id    *id_entry;
  15. };

  16. struct platform_driver {
  17.     int (*probe)(struct platform_device *);
  18.     int (*remove)(struct platform_device *);
  19.     void (*shutdown)(struct platform_device *);
  20.     int (*suspend)(struct platform_device *, pm_message_t state);
  21.     int (*suspend_late)(struct platform_device *, pm_message_t state);
  22.     int (*resume_early)(struct platform_device *);
  23.     int (*resume)(struct platform_device *);
  24.     struct device_driver driver;
  25.     struct platform_device_id *id_table;
  26. };

设备的分配:

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

设备的注册:

  1. int platform_device_add(struct platform_device *pdev)

获取资源:

  1. struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num);

/*dev:资源所属的设备,type:获取的资源类型,num:获取的资源数*/
这里详述platform_device与platform_driver是怎样匹配上的,这里跟踪函数的执行过程,首先是platform_driver_register:

  1. int platform_driver_register(struct platform_driver *drv)
  2. {
  3.     。。。。。。。。。。
  4.     return driver_register(&drv->driver);
  5. }
  6. int driver_register(struct device_driver *drv)
  7. {
  8.     。。。。。。。。。。。
  9.     ret = bus_add_driver(drv);
  10.     。。。。。。。。。。。
  11. }
  12. int bus_add_driver(struct device_driver *drv)
  13. {
  14.     。。。。。。。。。。。。
  15.     if (drv->bus->p->drivers_autoprobe) {
  16.         error = driver_attach(drv);
  17.         if (error)
  18.             goto out_unregister;
  19.     }
  20.     。。。。。。。。。。。。    
  21. }
  22. int driver_attach(struct device_driver *drv)
  23. {
  24.     return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
  25. }
这里来看__driver_attach这个函数,其中分别调用了driver_match_device,driver_probe_device函数。如果匹配成果调用probe函数,否则返回。
  1. static int __driver_attach(struct device *dev, void *data)
  2. {
  3.     struct device_driver *drv = data;

  4.     /*
  5.      * Lock device and try to bind to it. We drop the error
  6.      * here and always return 0, because we need to keep trying
  7.      * to bind to devices and some drivers will return an error
  8.      * simply if it didn't support the device.
  9.      *
  10.      * driver_probe_device() will spit a warning if there
  11.      * is an error.
  12.      */

  13.     if (!driver_match_device(drv, dev))
  14.         return 0;

  15.     if (dev->parent)    /* Needed for USB */
  16.         down(&dev->parent->sem);
  17.     down(&dev->sem);
  18.     if (!dev->driver)
  19.         driver_probe_device(drv, dev);
  20.     up(&dev->sem);
  21.     if (dev->parent)
  22.         up(&dev->parent->sem);

  23.     return 0;
  24. }

匹配的时候调用的bus的match函数。

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

找到platform_match:

  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.     /* match against the id table first */
  6.     if (pdrv->id_table)
  7.         return platform_match_id(pdrv->id_table, pdev) != NULL;

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

最后一行可以看到通过pdev->name与drv->name进行匹配,也就是说是通过设备与驱动的名字进行匹配。匹配成功后调用驱动的probe函数。

  1. int driver_probe_device(struct device_driver *drv, struct device *dev)
  2. {
  3.     。。。。。。。。。
  4.     ret = really_probe(dev, drv);
  5.     。。。。。。。。
  6. }
  7. static int really_probe(struct device *dev, struct device_driver *drv)
  8. {
  9.     。。。。。。。。
  10.     if (dev->bus->probe) {
  11.         ret = dev->bus->probe(dev);
  12.         if (ret)
  13.             goto probe_failed;
  14.     } else if (drv->probe) {
  15.         ret = drv->probe(dev);
  16.         if (ret)
  17.             goto probe_failed;
  18.     }
  19.     。。。。。。。。
  20. }

由relly_probe函数可以看出,如果bus定义了probe函数,则调用bus的probe函数;如果bus,没有定义而driver定义了probe函数,则调用driver的probe函数。由上边的platform_bus_type可以看出bus并没有定义probe函数,所以调用driver的probe函数。

测试程序:

device.c

  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/device.h>
  4. #include <linux/string.h>
  5. #include <linux/module.h>
  6. #include <linux/platform_device.h>

  7. static struct platform_device *my_device;

  8. static int __init platform_dev_init(void) {
  9.     int ret;
  10.     
  11.     //分配结构
  12.     my_device = platform_device_alloc("my_dev", -1);
  13.     //注册设备
  14.     ret = platform_device_add(my_device);
  15.     
  16.     if(ret)
  17.         printk("platform_device_add failed!/n");
  18.         
  19.     return ret;
  20. }

  21. static void __exit platform_dev_exit(void) {
  22.     platform_device_unregister(my_device);//卸载设备
  23. }

  24. module_init(platform_dev_init);
  25. module_exit(platform_dev_exit);
  26. MODULE_LICENSE("GPL");

driver.c

  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/init.h>
  4. #include <linux/device.h>
  5. #include <linux/string.h>
  6. #include <linux/module.h>
  7. #include <linux/platform_device.h>

  8. static int my_probe(struct device *dev) {
  9.     printk("Driver found device!/n");
  10.     return 0;
  11. }

  12. static int my_remove(struct device *dev) {
  13.     printk("Driver found device unpluged!/n");
  14.     return 0;
  15. }
  16. //定义platform_driver结构体
  17. static struct platform_driver my_driver = {
  18.     .probe    = my_probe,
  19.     .remove = my_remove,    
  20.     .driver = {
  21.         .owner = THIS_MODULE,
  22.         .name = "my_dev",
  23.     },
  24. };

  25. static int __init my_driver_init(void) {
  26.     return platform_driver_register(&my_driver);
  27. }

  28. static void __exit my_driver_exit(void) {
  29.     platform_driver_unregister(&my_driver);
  30. }

  31. module_init(my_driver_init);
  32. module_exit(my_driver_exit);
  33. MODULE_LICENSE("GPL");

测试效果:

  1. root@hacker:/home/hacker/platform# insmod driver.ko
  2. root@hacker:/home/hacker/platform# insmod device.ko
  3. root@hacker:/home/hacker/platform# dmesg
  4. [ 4499.724439] Driver found
  5. root@hacker:/home/hacker/platform# rmmod driver.ko
  6. root@hacker:/home/hacker/platform# dmesg
  7. [ 4499.724439] Driver found
  8. [ 4513.368712] Driver found device
  9. root@hacker:/home/hacker/platform# rmmod device.ko

  10. root@hacker:/home/hacker/platform# insmod device.ko
  11. root@hacker:/home/hacker/platform# insmod driver.ko
  12. root@hacker:/home/hacker/platform# dmesg
  13. [ 4540.509227] Driver found
  14. root@hacker:/home/hacker/platform# rmmod device.ko
  15. root@hacker:/home/hacker/platform# dmesg
  16. [ 4540.509227] Driver found
  17. [ 4545.786076] Driver found device
  18. root@hacker:/home/hacker/platform# rmmod driver.ko
  19. root@hacker:/home/hacker/platform# dmesg
  20. [ 4540.509227] Driver found
  21. [ 4545.786076] Driver found device

 

 

转自:http://blog.csdn.net/woshixingaaa/article/details/6436172

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