找回密码
 立即注册
首页 业界区 安全 10_linux dirver platform 框架

10_linux dirver platform 框架

嗅叽 2025-6-11 22:13:36
1. 概述  

硬件上修改gpio端口后,为了让linux driver 代码修改尽量少,可以使用linux driver 的platform框架。
该框架让硬件dev和软件driver 分离开,尽量保证driver编写完成后,不需要再修改。
如果采用platform机制实现驱动程序, 驱动工程师只需维护两个数据结构, 分别初始化和注册硬件节点和软件节点
    struct platform_device
    struct platform_driver
       
        内核会帮做四件事:
        1.帮你遍历dev或者drv链表
        2.帮你调用总线提供的match进行匹配
        3.如果匹配成功,内核还会帮你调用软件节点的probe函数
        4.如果匹配成功,内核还会给probe函数传递匹配成功的硬件节点首地址
2. dev 信息

详解struct platform_device
    struct platform_device {
                const char            *name;
                int                        id;
                struct device            dev;
                u32                        num_resources;  // 目前不使用
                struct resource        * resource;                // 目前不使用
        };       
        功能: 描述dev链表上每个纯硬件节点属性
        name: 指定一个硬件节点名称,用于匹配,必须初始化
        id:   指定一个硬件节点编号,如果dev链表上只有一个名称为name的硬件节点,id=-1;
              如果dev链表上有多个同名的硬件节点, 通过id进行标识:id=0,1,2,....
        dev:  只需关注其中的void *platform_data字段用于装载驱动工程师自定义的纯硬件信息
                  struct device {  void *platform_data; };
        num_resources:用于指示resource描述的硬件信息的个数,即:num_resources = ARRAY_SIZE(led_res)
                                   切记:num_resources只能和resource一起使用
                                  
        resource:用于装载resource描述的硬件信息, 此数据结构struct resource是内核声明的
       
        总结:装载硬件信息的方法有两种,目前采用第一种方法
                1.自定义描述
                2.resource描述
                两种方法可以同时使用,也可以单独使用
       
    配套函数:
        int platform_device_register(struct platform_device *pdev);
        功能:向内核dev链表添加硬件节点, 此时内核会帮你遍历,匹配,调用probe,传递参数
                  
    void platform_device_unregister(struct platform_device *pdev);
        功能:从内核dev链表删除硬件节点对象
       
        对应的头文件:
示例代码:
  1. $cat led.h
  2. #ifndef __LED_H_
  3. #define __LED_H_
  4. struct led_resource {
  5.     char *name;
  6.     int gpio;
  7. };
  8. struct led_platform_data {
  9.     struct led_resource *pres;
  10.     int numbs;
  11. };
  12. #endif
  13. $cat dev_led.c
  14. #include <linux/init.h>
  15. #include <linux/module.h>
  16. #include <linux/platform_device.h>
  17. #include <linux/gpio.h>
  18. #include <mach/platform.h>
  19. #include "led.h"
  20. // 定义
  21. struct led_resource led_res[] = {
  22.     {.name = "LED1",   .gpio = PAD_GPIO_C + 12},
  23.     {.name = "LED2",   .gpio = PAD_GPIO_C +  7},
  24.     {.name = "LED3",   .gpio = PAD_GPIO_C + 11},
  25.     {.name = "LED4",   .gpio = PAD_GPIO_B + 26},
  26. };
  27. struct led_platform_data led = {
  28.     .pres = led_res,
  29.     .numbs = ARRAY_SIZE(led_res)
  30. };
  31. void led_release(struct device *dev) {}
  32. struct platform_device led_dev = {
  33.     .name = "tarena_led",
  34.     .id = -1,
  35.     .dev = {
  36.         .platform_data = &led,
  37.         .release = led_release
  38.     }
  39. };
  40. int led_dev_init(void) {
  41.     int i;
  42.     printk("%s, dev=%p, platform_data=%p\n", __func__, &led_dev, led_dev.dev.platform_data);
  43.     for (i = 0; i < ARRAY_SIZE(led_res); i++) {
  44.         printk("%s, %p\n", led_res[i].name, &led_res[i]);
  45.     }
  46.     platform_device_register(&led_dev);
  47.     return 0;
  48. }
  49. void led_dev_exit(void) {
  50.     platform_device_unregister(&led_dev);
  51. }
  52. module_init(led_dev_init);
  53. module_exit(led_dev_exit);
  54. MODULE_LICENSE("GPL");
复制代码
3. drv 信息

详解struct platform_driver
    struct platform_driver {
                struct device_driver driver;
                int (*probe)(struct platform_device *pdev);
                int (*remove)(struct platform_device *pdev);
        };       
        功能:描述软件节点信息
        driver:只关注其中的char *name字段,用于匹配
               struct device_driver {
                                const char *name;
                   }
    probe:硬件节点和软件节点匹配成功,内核调用
                  形参pdev指向匹配成功的硬件节点(&led_dev)
        remove:删除软件节点或者硬件节点,内核调用此函数
                  形参pdev指向匹配成功的硬件节点(&led_dev)
                  只调用一次
       
        配套函数:
        //向drv链表添加软件节点
        //内核帮你做遍历,匹配,调用probe,传递硬件节点的参数:platform_device
        int platform_driver_register(struct platform_driver *drv);
       
        //从drv链表删除软件节点
        void platform_driver_unregister(struct platform_driver *drv);
       
        对应的头文件:
  1. $cat drv_led.c
  2. // led_drv.c
  3. #include <linux/init.h>
  4. #include <linux/module.h>
  5. #include <linux/platform_device.h>
  6. #include <linux/gpio.h>
  7. #include <mach/platform.h>
  8. #include "led.h"
  9. struct led_platform_data* p_led;
  10. int led_probe(struct platform_device *pdev) {
  11.     int i = 0;
  12.     p_led = pdev->dev.platform_data;
  13.     printk("%s, dev=%p, platform_data=%p, p_led->pres=%p, numbs=%d\n",
  14.             __func__, pdev,  p_led, p_led->pres,  p_led->numbs);
  15.     for (i = 0; i < p_led->numbs; i++) {
  16.         printk("%s,  %p\n",  p_led->pres[i].name,  &p_led->pres[i]);
  17.     }
  18.     return 0;
  19. };
  20. int led_remove(struct platform_device *pdev) {
  21.     return 0;
  22. };
  23. struct platform_driver led_drv = {
  24.     .driver = { .name = "tarena_led"},
  25.     .probe = led_probe,
  26.     .remove = led_remove
  27. };
  28. int led_drv_init(void) {
  29.     platform_driver_register(&led_drv);
  30.     return 0;
  31. }
  32. void led_drv_exit(void) {
  33.     platform_driver_unregister(&led_drv);
  34. }
  35. module_init(led_drv_init);
  36. module_exit(led_drv_exit);
  37. MODULE_LICENSE("GPL");
复制代码
4. 编译测试
  1. $cat Makefile
  2. # 指定模块名称(最终生成的 .ko 文件名)
  3. obj-m += dev_led.o drv_led.o
  4. all:
  5.     make -C /opt/kernel SUBDIRS=$(PWD) modules
  6.     cp *.ko /opt/rootfs/home/driver
  7. clean:
  8.     make -C  /opt/kernel SUBDIRS=$(PWD) clean
复制代码
测试信息:
  1. /home/driver # insmod dev_led.ko
  2. [ 1834.902000] led_dev_init, dev=bf010110, platform_data=bf010300
  3. [ 1834.902000] LED1, bf0102e0
  4. [ 1834.903000] LED2, bf0102e8
  5. [ 1834.904000] LED3, bf0102f0
  6. [ 1834.907000] LED4, bf0102f8
  7. /home/driver #
  8. /home/driver # insmod drv_led.ko
  9. [ 1840.374000] led_probe, dev=bf010110, platform_data=bf010300, p_led->pres=bf0102e0, numbs=4
  10. [ 1840.375000] LED1,  bf0102e0
  11. [ 1840.376000] LED2,  bf0102e8
  12. [ 1840.378000] LED3,  bf0102f0
  13. [ 1840.379000] LED4,  bf0102f8
  14. /home/driver #
复制代码
从测试信息看,dev文件中定义的硬件资源,都可以在drv文件中获取到。如果之后修改gpio,在dev 中修改就可以。
如果要操作gpio,可以在drv 文件中 创建字符设备或混杂设备,从而操作gpio

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册