• 华清远见嵌入式学习——驱动开发——day9


    目录

    作业要求:

    作业答案:

    代码效果:

    ​编辑

    Platform总线驱动代码:

    应用程序代码:

    设备树配置:


    作业要求:

    通过platform总线驱动框架编写LED灯的驱动,编写应用程序测试,发布到CSDN

    作业答案:

    代码效果:

    Platform总线驱动代码:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. //主设备号
    8. int major;
    9. //用于上传目录和设备节点信息
    10. struct class *cls;
    11. struct device *device;
    12. // led设备号
    13. struct gpio_desc *gpiono1;
    14. struct gpio_desc *gpiono2;
    15. struct gpio_desc *gpiono3;
    16. // 创建功能码
    17. #define LED_ON _IOW('l', 1, int)
    18. #define LED_OFF _IOW('l', 0, int)
    19. // ioctl函数,用于控制led设备
    20. long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    21. {
    22. switch (cmd)
    23. {
    24. case LED_ON:
    25. switch (arg)
    26. {
    27. case 1:
    28. gpiod_set_value(gpiono1, 1);
    29. break;
    30. case 2:
    31. gpiod_set_value(gpiono2, 1);
    32. break;
    33. case 3:
    34. gpiod_set_value(gpiono3, 1);
    35. break;
    36. }
    37. break;
    38. case LED_OFF:
    39. switch (arg)
    40. {
    41. case 1:
    42. gpiod_set_value(gpiono1, 0);
    43. break;
    44. case 2:
    45. gpiod_set_value(gpiono2, 0);
    46. break;
    47. case 3:
    48. gpiod_set_value(gpiono3, 0);
    49. break;
    50. }
    51. break;
    52. }
    53. return 0;
    54. }
    55. // 定义操作方法结构体变量并赋值
    56. struct file_operations fops = {
    57. .unlocked_ioctl = mycdev_ioctl,
    58. };
    59. // 封装probe函数,当设备和驱动匹配成功之后执行
    60. int pdrv_probe(struct platform_device *dev)
    61. {
    62. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    63. // 字符设备驱动注册
    64. major = register_chrdev(0, "mychrdev", &fops);
    65. if (major < 0)
    66. {
    67. printk("字符设备驱动注册失败\n");
    68. return major;
    69. }
    70. printk("字符设备驱动注册成功:major=%d\n", major);
    71. // 向上提交目录
    72. cls = class_create(THIS_MODULE, "mychrdev");
    73. if (IS_ERR(cls))
    74. {
    75. printk("向上提交目录失败\n");
    76. return -PTR_ERR(cls);
    77. }
    78. printk("向上提交目录成功\n");
    79. // 向上提交设备节点信息
    80. int i; // 向上提交三次设备节点信息
    81. for (i = 0; i < 3; i++)
    82. {
    83. device = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i);
    84. if (IS_ERR(dev))
    85. {
    86. printk("向上提交设备节点失败\n");
    87. return -PTR_ERR(dev);
    88. }
    89. }
    90. printk("向上提交设备节点成功\n");
    91. // 解析LED1的gpio编号
    92. gpiono1 = gpiod_get_from_of_node(dev->dev.of_node, "led1-gpio", 0, GPIOD_OUT_LOW, NULL);
    93. if (gpiono1 == NULL)
    94. {
    95. printk("解析led1对应gpio编号失败\n");
    96. return -ENXIO;
    97. }
    98. printk("解析led1对应gpio编号成功\n");
    99. // 解析LED1的gpio编号
    100. gpiono2 = gpiod_get_from_of_node(dev->dev.of_node, "led2-gpio", 0, GPIOD_OUT_LOW, NULL);
    101. if (gpiono2 == NULL)
    102. {
    103. printk("解析led2对应gpio编号失败\n");
    104. return -ENXIO;
    105. }
    106. printk("解析led2对应gpio编号成功\n");
    107. // 解析LED1的gpio编号
    108. gpiono3 = gpiod_get_from_of_node(dev->dev.of_node, "led3-gpio", 0, GPIOD_OUT_LOW, NULL);
    109. if (gpiono3 == NULL)
    110. {
    111. printk("解析led3对应gpio编号失败\n");
    112. return -ENXIO;
    113. }
    114. printk("解析led3对应gpio编号成功\n");
    115. return 0;
    116. }
    117. // 封装remove函数,用于驱动和设备卸载时执行
    118. int pdrv_remove(struct platform_device *dev)
    119. {
    120. // 销毁设备节点信息
    121. device_destroy(cls, MKDEV(major, 0));
    122. // 销毁设备节点信息
    123. int i;
    124. for (i = 0; i < 3; i++)
    125. {
    126. device_destroy(cls, MKDEV(major, i));
    127. }
    128. // 释放gpio编号
    129. gpiod_put(gpiono1);
    130. gpiod_put(gpiono2);
    131. gpiod_put(gpiono3);
    132. // 销毁目录
    133. class_destroy(cls);
    134. // 注销字符设备驱动
    135. unregister_chrdev(major, "mychrdev");
    136. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    137. return 0;
    138. }
    139. // 构建用于匹配的设备树表
    140. struct of_device_id oftable[] = {
    141. {
    142. .compatible = "hqyj,myplatform",
    143. },
    144. {/* end node */}, // 防止数组越界
    145. };
    146. // 分配驱动对象并初始化
    147. struct platform_driver pdrv = {
    148. .probe = pdrv_probe,
    149. .remove = pdrv_remove,
    150. .driver = {
    151. .name = "bbbbb",
    152. .of_match_table = oftable, // 设置设备树匹配
    153. },
    154. };
    155. // 一键注册宏
    156. module_platform_driver(pdrv);
    157. MODULE_LICENSE("GPL");

    应用程序代码:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. //创建功能码
    10. #define LED_ON _IOW('l',1,int)
    11. #define LED_OFF _IOW('l',0,int)
    12. int main(int argc, char const *argv[])
    13. {
    14. int a,b;
    15. int fd=open("/dev/myled0",O_RDWR);
    16. if(fd<0)
    17. {
    18. printf("打开设备文件失败\n");
    19. exit(-1);
    20. }
    21. while(1)
    22. {
    23. //从终端读取
    24. printf("请输入要实现的功能\n");
    25. printf("0(关灯) 1(开灯)\n");
    26. printf("请输入>");
    27. scanf("%d",&a);
    28. printf("请输入要控制的灯\n");
    29. printf("1(LED1) 2(LED2) 3(LED3)\n");
    30. printf("请输入>");
    31. scanf("%d",&b);
    32. switch(a)
    33. {
    34. case 1:
    35. ioctl(fd,LED_ON,b);
    36. break;
    37. case 0:
    38. ioctl(fd,LED_OFF,b);
    39. break;
    40. }
    41. }
    42. close(fd);
    43. return 0;
    44. }

    设备树配置:

    1. /dts-v1/;
    2. #include "stm32mp157.dtsi"
    3. #include "stm32mp15xa.dtsi"
    4. #include "stm32mp15-pinctrl.dtsi"
    5. #include "stm32mp15xxac-pinctrl.dtsi"
    6. #include "stm32mp15xx-fsmp1x.dtsi"
    7. / {
    8. model = "HQYJ STM32MP157 FSMP1A Discovery Board";
    9. compatible = "st,stm32mp157a-dk1", "st,stm32mp157";
    10. aliases {
    11. serial0 = &uart4;
    12. serial5 = &usart3;
    13. };
    14. chosen {
    15. stdout-path = "serial0:115200n8";
    16. };
    17. reserved-memory {
    18. gpu_reserved: gpu@d4000000 {
    19. reg = <0xd4000000 0x4000000>;
    20. no-map;
    21. };
    22. optee_memory: optee@0xde000000 {
    23. reg = <0xde000000 0x02000000>;
    24. no-map;
    25. };
    26. };
    27. mynode@0x12345678{
    28. compatible = "hqyj,mynode";
    29. astring="hello 23091";
    30. uint =<0xaabbccdd 0x11223344>;
    31. binarry=[00 0c 29 7b f9 be];
    32. mixed ="hello",[11 22],<0x12345678>;
    33. };
    34. myled
    35. {
    36. led1-gpio=<&gpioe 10 0>;
    37. led2-gpio=<&gpiof 10 0>;
    38. led3-gpio=<&gpioe 8 0>;
    39. };
    40. myirq{
    41. compatible = "hqyj,myirq";
    42. interrupt-parent = <&gpiof>;
    43. interrupts=<9 0>,<7 0>,<8 0>;
    44. };
    45. myplatform{
    46. compatible = "hqyj,myplatform";
    47. led1-gpio=<&gpioe 10 0>;
    48. led2-gpio=<&gpiof 10 0>;
    49. led3-gpio=<&gpioe 8 0>;
    50. interrupt-parent = <&gpiof>;
    51. interrupts=<9 0>;
    52. reg=<0X12345678 0X400>;
    53. };
    54. };

  • 相关阅读:
    【多服务场景化解决方案】AR虚拟技术助力智能家装
    软件设计师:数据库
    SpringBoot和MyBatis常见注解
    代码随想录算法训练营第三天|LeetCode 203.移除链表元素 、707.设计链表 、206.反转链表
    1111111
    函数柯里化的简单实现和应用
    VPP数据预取指令
    使用 PointNet 进行3D点集(即点云)的分类
    电脑重装系统后内存占用高怎么解决?
    8位ADC是256还是255?
  • 原文地址:https://blog.csdn.net/qq_54502935/article/details/136261633