Chinaunix首页 | 论坛 | 博客
  • 博客访问: 478520
  • 博文数量: 285
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 629
  • 用 户 组: 普通用户
  • 注册时间: 2013-10-14 17:53
个人简介

相信自己,快乐每一天

文章分类

全部博文(285)

分类: LINUX

2013-10-26 10:50:49

原文地址:Linux设备模型--platform 作者:mutes

http://blog.csdn.net/woshixingaaa/archive/2011/05/21/6436172.aspx

首先看一下我的系统中都有什么设备挂在了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.   
  48. 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.   
  10. int __init platform_bus_init(void)  
  11. {  
  12.     int error;  
  13.   
  14.     early_platform_cleanup();  
  15.   
  16.     error = device_register(&platform_bus);  
  17.     if (error)  
  18.         return error;  
  19.     error =  bus_register(&platform_bus_type);  
  20.     if (error)  
  21.         device_unregister(&platform_bus);  
  22.     return error;  
  23. }  
记住总线也是一种设备,所以首先注册总线设备,然后注册总线。
  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.   
  9. struct platform_device {  
  10.     const char  * name;          /*设备名*/  
  11.     int     id;              /*设备编号,配合设备名使用*/   
  12.     struct device   dev;  
  13.     u32     num_resources;  
  14.     struct resource * resource;      /*设备资源*/  
  15.   
  16.     struct platform_device_id   *id_entry;  
  17. };  
  18.   
  19. struct platform_driver {  
  20.     int (*probe)(struct platform_device *);  
  21.     int (*remove)(struct platform_device *);  
  22.     void (*shutdown)(struct platform_device *);  
  23.     int (*suspend)(struct platform_device *, pm_message_t state);  
  24.     int (*suspend_late)(struct platform_device *, pm_message_t state);  
  25.     int (*resume_early)(struct platform_device *);  
  26.     int (*resume)(struct platform_device *);  
  27.     struct device_driver driver;  
  28.     struct platform_device_id *id_table;  
  29. };  
设备的分配:
struct platform_device *platform_device_alloc(const char *name, int id);  //name:设备名,id:设备id,一般为-1  
设备的注册:
int platform_device_add(struct platform_device *pdev);  
获取资源:
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.     /* 
  6.      * Lock device and try to bind to it. We drop the error 
  7.      * here and always return 0, because we need to keep trying 
  8.      * to bind to devices and some drivers will return an error 
  9.      * simply if it didn't support the device. 
  10.      * 
  11.      * driver_probe_device() will spit a warning if there 
  12.      * is an error. 
  13.      */  
  14.   
  15.     if (!driver_match_device(drv, dev))  
  16.         return 0;  
  17.   
  18.     if (dev->parent) /* Needed for USB */  
  19.         down(&dev->parent->sem);  
  20.     down(&dev->sem);  
  21.     if (!dev->driver)  
  22.         driver_probe_device(drv, dev);  
  23.     up(&dev->sem);  
  24.     if (dev->parent)  
  25.         up(&dev->parent->sem);  
  26.   
  27.     return 0;  
  28. }  
匹配的时候调用的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.   
  6.     /* match against the id table first */  
  7.     if (pdrv->id_table)  
  8.         return platform_match_id(pdrv->id_table, pdev) != NULL;  
  9.   
  10.     /* fall-back to driver name match */  
  11.     return (strcmp(pdev->name, drv->name) == 0);  
  12. }  
最后一行可以看到通过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   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include   
  7.   
  8. static struct platform_device *my_device;  
  9.   
  10. static int __init platform_dev_init(void) {  
  11.     int ret;  
  12.       
  13.     //分配结构  
  14.     my_device = platform_device_alloc("my_dev", -1);  
  15.     //注册设备  
  16.     ret = platform_device_add(my_device);  
  17.       
  18.     if(ret)  
  19.         printk("platform_device_add failed!/n");  
  20.           
  21.     return ret;  
  22. }  
  23.   
  24. static void __exit platform_dev_exit(void) {  
  25.     platform_device_unregister(my_device);//卸载设备  
  26. }  
  27.   
  28. module_init(platform_dev_init);  
  29. module_exit(platform_dev_exit);  
  30. MODULE_LICENSE("GPL");  
driver.c
  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include   
  7. #include   
  8.   
  9. static int my_probe(struct device *dev) {  
  10.     printk("Driver found device!/n");  
  11.     return 0;  
  12. }  
  13.   
  14. static int my_remove(struct device *dev) {  
  15.     printk("Driver found device unpluged!/n");  
  16.     return 0;  
  17. }  
  18. //定义platform_driver结构体  
  19. static struct platform_driver my_driver = {  
  20.     .probe  = my_probe,  
  21.     .remove = my_remove,      
  22.     .driver = {  
  23.         .owner = THIS_MODULE,  
  24.         .name = "my_dev",  
  25.     },  
  26. };  
  27.   
  28. static int __init my_driver_init(void) {  
  29.     return platform_driver_register(&my_driver);  
  30. }  
  31.   
  32. static void __exit my_driver_exit(void) {  
  33.     platform_driver_unregister(&my_driver);  
  34. }  
  35.   
  36. module_init(my_driver_init);  
  37. module_exit(my_driver_exit);  
  38. 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 device!  
  5. root@hacker:/home/hacker/platform# rmmod driver.ko  
  6. root@hacker:/home/hacker/platform# dmesg  
  7. [ 4499.724439] Driver found device!  
  8. [ 4513.368712] Driver found device unpluged!  
  9. root@hacker:/home/hacker/platform# rmmod device.ko  
  10.   
  11. root@hacker:/home/hacker/platform# insmod device.ko  
  12. root@hacker:/home/hacker/platform# insmod driver.ko  
  13. root@hacker:/home/hacker/platform# dmesg  
  14. [ 4540.509227] Driver found device!  
  15. root@hacker:/home/hacker/platform# rmmod device.ko  
  16. root@hacker:/home/hacker/platform# dmesg  
  17. [ 4540.509227] Driver found device!  
  18. [ 4545.786076] Driver found device unpluged!  
  19. root@hacker:/home/hacker/platform# rmmod driver.ko  
  20. root@hacker:/home/hacker/platform# dmesg  
  21. [ 4540.509227] Driver found device!  
  22. [ 4545.786076] Driver found device unpluged!  

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