• platform总线


    1、什么是platform总线?

    platform是Linux内核抽象出来的软件代码,用于设备与驱动的连接,设备与驱动通过总线进行匹配;匹配成功后会执行驱动中的probe函数,在probe函数中可以获取到设备的信息;

    设备与驱动的信息分别通过链表进行管理。

    2、如何运用platform

    编写驱动和设备端的代码----搭建platform框架

    设备与硬件有三种匹配方式:名字匹配,id_table匹配,设备树匹配

    名字匹配,设备树匹配都在设备结构体pdrv里的driver结构体里面,

    首先定义一个驱动结构体并赋值,。probe函数,.remove函数,.driver匹配选项设置有两种,使用一键注册函数module_platform_driver(结构体名)

    名字匹配:

    驱动代码

    1. #include <linux/init.h>
    2. #include <linux/module.h>
    3. #include <linux/platform_device.h>
    4. struct resource *res;
    5. int irqno;
    6. //定义一个probe函数
    7. int pdrv_probe(struct platform_device *pdev)
    8. {
    9. //获取MEM类型的资源
    10. res=platform_get_resource(pdev,IORESOURCE_MEM,0);
    11. if(res==NULL)
    12. {
    13. printk("获取MEM资源失败\n");
    14. return ENODATA;
    15. }
    16. //获取中断类型的资源
    17. irqno=platform_get_irq(pdev,0);
    18. if(irqno<0)
    19. {
    20. printk("获取中断资源失败\n");
    21. return ENODATA;
    22. }
    23. printk("addr:%#llx ,irqno:%d\n",res->start,irqno);
    24. return 0;
    25. }
    26. int pdrv_remove(struct platform_device *pdev)
    27. {
    28. printk("%s:%d\n",__func__,__LINE__);
    29. return 0;
    30. }
    31. //热插拔宏,可以在插入硬件时,自动安装驱动
    32. MODULE_DEVICE_TABLE(platform,idtable);
    33. //对象初始化
    34. struct platform_driver pdrv={
    35. .probe=pdrv_probe,
    36. .remove=pdrv_remove,
    37. .driver={
    38. .name="aaaaa", //按名字匹配,只能匹配一个设备
    39. },
    40. };
    41. module_platform_driver(pdrv); //一键注册驱动
    42. MODULE_LICENSE("GPL");

    设备代码

    1.定义一个设备结构体并赋值,struct platform_driver pdrv;

    2.

     

    1. #include <linux/init.h>
    2. #include <linux/module.h>
    3. #include <linux/platform_device.h>
    4. //对设备信息进行填充
    5. struct resource res[]={
    6. [0]={
    7. .start=0x12345678,
    8. .end=0x12345678+49,
    9. .flags= IORESOURCE_MEM,
    10. },
    11. [1]={
    12. .start=71,
    13. .end=71,
    14. .flags= IORESOURCE_IRQ,
    15. },
    16. };
    17. //定义一个relese函数
    18. void pdev_release(struct device *dev)
    19. {
    20. printk("%s:%d\n",__func__,__LINE__);
    21. }
    22. //给对象赋值
    23. struct platform_device pdev={
    24. .name="aaaaa",
    25. .id=PLATFORM_DEVID_AUTO,
    26. .dev={
    27. .release=pdev_release,
    28. },
    29. .resource=res,
    30. .num_resources=ARRAY_SIZE(res),
    31. };
    32. static int __init mycdev_init(void)
    33. {
    34. //注册device
    35. return platform_device_register(&pdev);
    36. }
    37. static void __exit mycdev_exit(void)
    38. {
    39. //注销device
    40. platform_device_unregister(&pdev);
    41. }
    42. module_init(mycdev_init);
    43. module_exit(mycdev_exit);
    44. MODULE_LICENSE("GPL");

    id_table匹配:一个驱动匹配多款硬件设备,如不同品牌的U盘

    1. #include <linux/init.h>
    2. #include <linux/module.h>
    3. #include <linux/platform_device.h>
    4. #include <linux/mod_devicetable.h>
    5. struct resource *res;
    6. int irqno;
    7. //定义一个probe函数
    8. int pdrv_probe(struct platform_device *pdev)
    9. {
    10. //获取MEM类型的资源
    11. res=platform_get_resource(pdev,IORESOURCE_MEM,0);
    12. if(res==NULL)
    13. {
    14. printk("获取MEM资源失败\n");
    15. return ENODATA;
    16. }
    17. //获取中断类型的资源
    18. irqno=platform_get_irq(pdev,0);
    19. if(irqno<0)
    20. {
    21. printk("获取中断资源失败\n");
    22. return ENODATA;
    23. }
    24. printk("addr:%#llx ,irqno:%d\n",res->start,irqno);
    25. return 0;
    26. }
    27. int pdrv_remove(struct platform_device *pdev)
    28. {
    29. printk("%s:%d\n",__func__,__LINE__);
    30. return 0;
    31. }
    32. //id_table创建
    33. struct platform_device_id idtable[]={
    34. {"hi1",0},
    35. {"hi2",1},
    36. {"hi3",2},
    37. {},//防止越界
    38. };
    39. //热插拔宏,可以在插入硬件时,自动安装驱动
    40. MODULE_DEVICE_TABLE(platform,idtable);
    41. //对象初始化
    42. struct platform_driver pdrv={
    43. .probe=pdrv_probe,
    44. .remove=pdrv_remove,
    45. .driver={
    46. .name="aaaaa", //按名字匹配,只能匹配一个设备
    47. },
    48. .id_table=idtable, //设置名字表匹配,可以匹配多个硬件设备
    49. };
    50. module_platform_driver(pdrv);
    51. MODULE_LICENSE("GPL");

    设备树匹配:

    1、编写自己的设备树节点---编译设备树,开发板上电加载
    2、驱动对象中,匹配方式-----设备树匹配
    3、构建comptible表
    struct of_device_id oftable[]={
    {.compatible="hqyj,platform",},
    };设备初始化结构体中,添加设备树匹配
    .of_match_table=oftable,

     驱动编译后拷贝到~/nfs/rootfs

    1. #include <linux/init.h>
    2. #include <linux/module.h>
    3. #include <linux/platform_device.h>
    4. #include <linux/mod_devicetable.h>
    5. #include <linux/of.h>
    6. #include <linux/of_gpio.h>
    7. struct resource *res;
    8. int irqno;
    9. struct gpio_desc *gpiono; //存放gpio编号
    10. //定义一个probe函数
    11. int pdrv_probe(struct platform_device *pdev)
    12. {
    13. //获取MEM类型的资源
    14. res=platform_get_resource(pdev,IORESOURCE_MEM,0);
    15. if(res==NULL)
    16. {
    17. printk("获取MEM资源失败\n");
    18. return ENODATA;
    19. }
    20. //获取中断类型的资源
    21. irqno=platform_get_irq(pdev,0);
    22. if(irqno<0)
    23. {
    24. printk("获取中断资源失败\n");
    25. return ENODATA;
    26. }
    27. printk("addr:%#x ,irqno:%d\n",res->start,irqno);
    28. //解析设备树节点信息
    29. gpiono=gpiod_get_from_of_node(pdev->dev.of_node,"myled1",0,GPIOD_OUT_HIGH,NULL);
    30. if(IS_ERR(gpiono))
    31. {
    32. printk("获取gpio编号失败\n");
    33. return PTR_ERR(gpiono);
    34. }
    35. printk("点亮led1\n");
    36. gpiod_set_value(gpiono,1);
    37. return 0;
    38. }
    39. int pdrv_remove(struct platform_device *pdev)
    40. {
    41. gpiod_set_value(gpiono,0);
    42. gpiod_put(gpiono);
    43. return 0;
    44. }
    45. struct of_device_id oftable[]={
    46. {
    47. .compatible="hqyj,platform",
    48. },
    49. {},
    50. };
    51. //热插拔宏,可以在插入硬件时,自动安装驱动
    52. MODULE_DEVICE_TABLE(of,oftable);
    53. //对象初始化
    54. struct platform_driver pdrv={
    55. .probe=pdrv_probe,
    56. .remove=pdrv_remove,
    57. .driver={
    58. .name="aaaaa", //按名字匹配,只能匹配一个设备
    59. .of_match_table=oftable,//设备树匹配
    60. },
    61. };
    62. module_platform_driver(pdrv);
    63. MODULE_LICENSE("GPL");

     现象:

    如何让设备安装时,驱动自动加载,就像插入u盘,系统会自动识别硬件安装驱动

    MODULE_DEVICE_TABLE(platform,idtable);添加此行即可

  • 相关阅读:
    封装自定义表格组件
    2023届C/C++软件开发工程师校招面试常问知识点复盘Part 6
    ​LeetCode解法汇总2342. 数位和相等数对的最大和
    LDA算法实现鸢尾花数据集降维
    HCIA4.26-5.10
    Go语言 String 简介
    课程29:.Net Core API限流
    《现代命令行工具指南》9. 删除文件:让删除文件变得安全可控 - trash-cli
    蜜雪冰城涨价怒赞无数 雪王张红超卷出一条阳道
    加拿大海运专线怎么选?加拿大海运专线有哪些费用
  • 原文地址:https://blog.csdn.net/m0_68004652/article/details/128104905