• platform驱动练习


    练习:

    驱动代码段

    1. #include "head.h"
    2. int major, minor = 0;
    3. struct cdev *cdev;
    4. struct class *cls;
    5. struct device *dev;
    6. //定义一个指向设备节点的指针
    7. struct device_node *node;
    8. struct device_node *node_led;
    9. struct device_node *node_irq;
    10. struct property *pr; //属性结构体指针
    11. int gpiono1;
    12. struct gpio_desc *desc_led1;
    13. int irqno;
    14. int number = 0;
    15. wait_queue_head_t wq_head; //定义等待对头
    16. int condition = 0;
    17. int chdev_open(struct inode *inode, struct file *file)
    18. {
    19. return 0;
    20. }
    21. int chdev_close(struct inode *inode, struct file *file)
    22. {
    23. return 0;
    24. }
    25. ssize_t chdev_read(struct file *file, char __user *ubuf, size_t size, loff_t *loff)
    26. {
    27. int ret;
    28. //阻塞
    29. ret = wait_event_interruptible(wq_head, condition);
    30. if (ret)
    31. {
    32. printk("接收阻塞休眠\n");
    33. return ret;
    34. }
    35. //把父进程拷贝到内核的数据再拷贝给子进程
    36. if (size > sizeof(number))
    37. size = sizeof(number);
    38. ret = copy_to_user(ubuf, &number, size);
    39. if (ret)
    40. {
    41. printk("数据从内核向用户拷贝失败\n");
    42. return -EIO;
    43. }
    44. condition = 0;
    45. return size;
    46. }
    47. ssize_t chdev_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff)
    48. {
    49. return 0;
    50. }
    51. long ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    52. {
    53. return 0;
    54. }
    55. //中断处理函数
    56. irqreturn_t irq_handler(int irq, void *dev)
    57. {
    58. gpiod_set_value(desc_led1, !gpiod_get_value(desc_led1));
    59. number ^= 1;
    60. //唤醒
    61. condition = 1;
    62. wake_up_interruptible(&wq_head);
    63. return IRQ_HANDLED;
    64. }
    65. struct file_operations fops = {
    66. .open = chdev_open,
    67. .read = chdev_read,
    68. .write = chdev_write,
    69. .release = chdev_close,
    70. .unlocked_ioctl = ioctl,
    71. };
    72. int pdrv_probe(struct platform_device *pdr)
    73. {
    74. //获取设备信息
    75. printk("%s:%d\n", __FILE__, __LINE__);
    76. irqno = platform_get_irq(pdr, 0);
    77. if (irqno < 0)
    78. {
    79. printk("获取资源失败\n");
    80. return irqno;
    81. }
    82. if (request_irq(irqno, irq_handler, IRQF_TRIGGER_FALLING, NULL, NULL))
    83. {
    84. printk("注册中断失败\n");
    85. return -1;
    86. }
    87. //获取GPIO编号
    88. desc_led1 = gpiod_get_from_of_node(pdr->dev.of_node, "led1", 0, GPIOD_OUT_LOW, NULL);
    89. if (IS_ERR(desc_led1))
    90. {
    91. printk("获取GPIO编号失败\n");
    92. return PTR_ERR(desc_led1);
    93. }
    94. return 0;
    95. }
    96. int pdrv_remove(struct platform_device *pdr)
    97. {
    98. printk("%s:%d\n", __FILE__, __LINE__);
    99. return 0;
    100. }
    101. //定义compatible表
    102. struct of_device_id oftable[] = {
    103. {.compatible = "hqyj,myplatform"},
    104. {},
    105. };
    106. //定义并初始化对象
    107. struct platform_driver pdrv = {
    108. .probe = pdrv_probe,
    109. .remove = pdrv_remove,
    110. .driver = {
    111. .name = "test",
    112. .of_match_table = oftable, //设备树匹配
    113. },
    114. };
    115. static int __init mycdev_init(void)
    116. {
    117. int ret;
    118. dev_t devno;
    119. cdev = cdev_alloc();
    120. if (NULL == cdev)
    121. {
    122. printk("初始化驱动设备对象失败\n");
    123. ret = -ENOMEM;
    124. goto ERR1;
    125. }
    126. cdev_init(cdev, &fops);
    127. ret = alloc_chrdev_region(&devno, minor, 1, "my_led");
    128. if (ret)
    129. {
    130. printk("申请设备号失败\n");
    131. goto ERR2;
    132. }
    133. major = MAJOR(devno);
    134. minor = MINOR(devno);
    135. ret = cdev_add(cdev, MKDEV(major, minor), 1);
    136. if (ret)
    137. {
    138. printk("字符设备驱动注册失败\n");
    139. goto ERR3;
    140. }
    141. cls = class_create(THIS_MODULE, "chdev_led");
    142. if (IS_ERR(cls))
    143. {
    144. printk("向上提交节点失败\n");
    145. goto ERR4;
    146. }
    147. dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "led");
    148. if (IS_ERR(dev))
    149. {
    150. printk("创建逻辑节点失败\n");
    151. ret = PTR_ERR(dev);
    152. goto ERR5;
    153. }
    154. //注册对象
    155. platform_driver_register(&pdrv);
    156. //初始化队列头
    157. init_waitqueue_head(&wq_head);
    158. return 0;
    159. ERR5:
    160. device_destroy(cls, MKDEV(major, 0));
    161. class_destroy(cls);
    162. ERR4:
    163. cdev_del(cdev);
    164. ERR3:
    165. unregister_chrdev_region(MKDEV(major, minor), 1);
    166. ERR2:
    167. kfree(cdev);
    168. ERR1:
    169. return ret;
    170. }
    171. static void __exit mycdev_exit(void)
    172. {
    173. //销毁设备节点
    174. device_destroy(cls, MKDEV(major, 0));
    175. class_destroy(cls);
    176. // 注销字符设备驱动
    177. cdev_del(cdev);
    178. // 释放设备号
    179. unregister_chrdev_region(MKDEV(major, minor), 1);
    180. // 释放动态申请的空间
    181. kfree(cdev);
    182. gpiod_set_value(desc_led1, 0);
    183. gpiod_put(desc_led1);
    184. //注销中断
    185. free_irq(irqno, NULL);
    186. //注销对象
    187. platform_driver_unregister(&pdrv);
    188. }
    189. module_init(mycdev_init);
    190. module_exit(mycdev_exit);
    191. MODULE_LICENSE("GPL");

    应用程序代码段

    1. #include <stdio.h>
    2. #include <sys/types.h>
    3. #include <sys/stat.h>
    4. #include <fcntl.h>
    5. #include <unistd.h>
    6. #include <stdlib.h>
    7. #include <string.h>
    8. #include <sys/wait.h>
    9. #include <sys/ioctl.h>
    10. #include <sys/select.h>
    11. #include <sys/time.h>
    12. int main(int argc, char const *argv[])
    13. {
    14. int fd;
    15. int number;
    16. char buf[128] = {};
    17. int which;
    18. fd = open("/dev/led", O_RDWR);
    19. if (fd < 0)
    20. {
    21. printf("打开文件失败\n");
    22. exit(-1);
    23. }
    24. while (1)
    25. {
    26. read(fd, &number, sizeof(number));
    27. printf("number = %d\n", number);
    28. }
    29. close(fd);
    30. return 0;
    31. }

    实验结果

  • 相关阅读:
    Linux终将取代Unix?富士通确认Unix系统和大型机的结束时间
    如何在 Endless OS 上安装 ONLYOFFICE 桌面编辑器 7.5
    Git 常用命令及其作用
    Ubuntu21.10升级22.04操作记录
    大三学生HTML期末作业,网页制作作业——HTML+CSS+JavaScript饮品饮料茶(7页)
    HittER: Hierarchical Transformers for Knowledge Graph Embeddings
    SQL实现模糊查询的四种方法总结
    职场经验:为什么要学习自动化测试?过来人告诉你答案
    yolov3学习笔记
    c语言结构体定义和结构体数组第一部分笔记
  • 原文地址:https://blog.csdn.net/m0_62707396/article/details/133100764