• 驱动开发练习,platform实现如下功能


    实验要求

     驱动代码

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include
    16. #include
    17. int i;
    18. struct resource *res;
    19. struct device_node *dnode;
    20. unsigned int irqno[3];
    21. unsigned int irqflag;
    22. struct gpio_desc *gpiono[3];
    23. unsigned char number;
    24. struct cdev *cdev;
    25. char kbuf[128] = {0};
    26. unsigned int major = 0;
    27. unsigned int minor = 0;
    28. dev_t devno;
    29. module_param(major, uint, 0664); // 方便在命令行传递major的值
    30. struct class *cls;
    31. struct device *dev;
    32. unsigned int condition = 0;
    33. // 定义一个等待队列头
    34. wait_queue_head_t wq_head;
    35. // 定义中断处理函数
    36. irqreturn_t key_handler(int irq, void *dev)
    37. {
    38. int which = (int)dev;
    39. if(number==0)
    40. {
    41. number=1;
    42. kbuf[0]='1';
    43. }else
    44. {
    45. number=0;
    46. kbuf[0]='0';
    47. }
    48. switch (which)
    49. {
    50. case 0:
    51. gpiod_set_value(gpiono[0], number);
    52. break;
    53. case 1:
    54. gpiod_set_value(gpiono[1], number);
    55. break;
    56. case 2:
    57. gpiod_set_value(gpiono[2], number);
    58. break;
    59. }
    60. condition = 1; // 表示硬件数据就绪
    61. wake_up_interruptible(&wq_head);
    62. return IRQ_HANDLED;
    63. }
    64. // 封装probe函数
    65. int pdrv_probe(struct platform_device *pdev)
    66. {
    67. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    68. if (res == NULL)
    69. {
    70. printk("获取men资源失败\n");
    71. return -ENXIO;
    72. }
    73. printk("mem资源%x\n", res->start);
    74. for (i = 0; i < 3; i++)
    75. {
    76. irqno[0] = platform_get_irq(pdev, 0);
    77. }
    78. if (irqno[0] < 0)
    79. {
    80. printk("获取中断类型资源失败\n");
    81. return -ENXIO;
    82. }
    83. printk("irq资源%d\n", irqno[0]);
    84. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    85. // 设备树匹配成功后,设备树节点指针可以通过pdev->dev.of_node获取
    86. // 基于设备树节点信息获取gpio_desc对象指针
    87. gpiono[0] = gpiod_get_from_of_node(pdev->dev.of_node, "led1-gpio", 0, GPIOD_OUT_LOW, NULL);
    88. if (IS_ERR(gpiono))
    89. {
    90. printk("解析GPIO管脚信息失败\n");
    91. return -ENXIO;
    92. }
    93. gpiono[1] = gpiod_get_from_of_node(pdev->dev.of_node, "led2-gpio", 0, GPIOD_OUT_LOW, NULL);
    94. if (IS_ERR(gpiono))
    95. {
    96. printk("解析GPIO管脚信息失败\n");
    97. return -ENXIO;
    98. }
    99. gpiono[2] = gpiod_get_from_of_node(pdev->dev.of_node, "led3-gpio", 0, GPIOD_OUT_LOW, NULL);
    100. if (IS_ERR(gpiono))
    101. {
    102. printk("解析GPIO管脚信息失败\n");
    103. return -ENXIO;
    104. }
    105. return 0;
    106. }
    107. // 封装操作方法
    108. int mycdev_open(struct inode *inode, struct file *file)
    109. {
    110. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    111. return 0;
    112. }
    113. int mycdev_close(struct inode *inode, struct file *file)
    114. {
    115. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    116. return 0;
    117. }
    118. ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
    119. {
    120. int ret;
    121. // 判断IO方式
    122. if (file->f_flags & O_NONBLOCK) // 非阻塞
    123. {
    124. }
    125. else // 阻塞
    126. {
    127. wait_event_interruptible(wq_head, condition); // 先检查condition再将进程休眠
    128. }
    129. ret = copy_to_user(ubuf, kbuf, size);
    130. if (ret)
    131. {
    132. printk("copy_to_user err\n");
    133. return -EIO;
    134. }
    135. condition = 0; // 下一次硬件数据没有就绪
    136. return 0;
    137. }
    138. // 定义操作方法结构体变量并赋值
    139. struct file_operations fops = {
    140. .open = mycdev_open,
    141. .release = mycdev_close,
    142. .read = mycdev_read,
    143. };
    144. // 封装remvoe函数
    145. int pdrv_remove(struct platform_device *pdev)
    146. {
    147. // 释放GPIO信息
    148. for (i = 0; i < 3; i++)
    149. {
    150. gpiod_put(gpiono[i]);
    151. }
    152. int i;
    153. for (i = 0; i < 3; i++)
    154. {
    155. free_irq(irqno[i], (void *)i);
    156. }
    157. // 销毁设备文件
    158. // 注销驱动
    159. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    160. return 0;
    161. }
    162. // 构建设备树匹配表
    163. struct of_device_id oftable[] = {
    164. {.compatible = "hqyj,myplatform"},
    165. {},
    166. };
    167. // 定义驱动信息对象并初始化
    168. struct platform_driver pdrv = {
    169. .probe = pdrv_probe,
    170. .remove = pdrv_remove,
    171. .driver = {
    172. .name = "ccccc",
    173. .of_match_table = oftable, // 用来设备树匹配
    174. },
    175. };
    176. static int __init mycdev_init(void)
    177. {
    178. // 注册
    179. platform_driver_register(&pdrv);
    180. // 解析按键的设备树节点
    181. dnode = of_find_compatible_node(NULL, NULL, "hqyj,myirq");
    182. if (dnode == NULL)
    183. {
    184. printk("解析设备树节点失败\n");
    185. return -ENXIO;
    186. }
    187. printk("解析设备树节点成功\n");
    188. // 解析按键的软中断号
    189. int i;
    190. for (i = 0; i < 3; i++)
    191. {
    192. irqno[i] = irq_of_parse_and_map(dnode, i);
    193. if (!irqno[i])
    194. {
    195. printk("解析按键1软中断号失败\n");
    196. return -ENXIO;
    197. }
    198. printk("解析按键软中断号成功%d\n", irqno[i]);
    199. // 注册 按键中断
    200. int ret = request_irq(irqno[i], key_handler, IRQF_TRIGGER_FALLING, "key_int", (void *)i);
    201. if (ret < 0)
    202. {
    203. printk("注册按键中断失败\n");
    204. return ret;
    205. }
    206. }
    207. printk("注册按键中断成功\n");
    208. init_waitqueue_head(&wq_head);
    209. int ret;
    210. // 为字符设备驱动对象申请空间
    211. cdev = cdev_alloc();
    212. if (cdev == NULL)
    213. {
    214. printk("字符设备驱动对象申请空间失败\n");
    215. ret = -EFAULT;
    216. goto out1;
    217. }
    218. printk("申请对象空间成功\n");
    219. // 初始化字符设备驱动对象
    220. cdev_init(cdev, &fops);
    221. // 申请设备号
    222. if (major > 0) // 静态指定设备号
    223. {
    224. ret = register_chrdev_region(MKDEV(major, minor), 3, "myled");
    225. if (ret)
    226. {
    227. printk("静态申请设备号失败\n");
    228. goto out2;
    229. }
    230. }
    231. else if (major == 0) // 动态申请设备号
    232. {
    233. ret = alloc_chrdev_region(&devno, minor, 3, "myled");
    234. if (ret)
    235. {
    236. printk("动态申请设备号失败\n");
    237. goto out2;
    238. }
    239. major = MAJOR(devno); // 获取主设备号
    240. minor = MINOR(devno); // 获取次设备号
    241. }
    242. printk("申请设备号成功\n");
    243. // 注册字符设备驱动对象
    244. ret = cdev_add(cdev, MKDEV(major, minor), 3);
    245. if (ret)
    246. {
    247. printk("注册字符设备驱动对象失败\n");
    248. goto out3;
    249. }
    250. printk("注册字符设备驱动对象成功\n");
    251. // 向上提交目录信息
    252. cls = class_create(THIS_MODULE, "myled");
    253. if (IS_ERR(cls))
    254. {
    255. printk("向上提交目录失败\n");
    256. ret = -PTR_ERR(cls);
    257. goto out4;
    258. }
    259. printk("向上提交目录成功\n");
    260. // 向上提交设备节点信息
    261. for (i = 0; i < 3; i++)
    262. {
    263. dev = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i);
    264. if (IS_ERR(dev))
    265. {
    266. printk("向上提交设备节点信息失败\n");
    267. ret = -PTR_ERR(dev);
    268. goto out5;
    269. }
    270. }
    271. printk("向上提交设备信息成功\n");
    272. return 0;
    273. out5:
    274. // 释放前一次提交成功的设备信息
    275. for (--i; i >= 0; i--)
    276. {
    277. device_destroy(cls, MKDEV(major, i));
    278. }
    279. class_destroy(cls); // 释放目录
    280. out4:
    281. cdev_del(cdev);
    282. out3:
    283. unregister_chrdev_region(MKDEV(major, minor), 3);
    284. out2:
    285. kfree(cdev);
    286. out1:
    287. return ret;
    288. return 0;
    289. }
    290. static void __exit mycdev_exit(void)
    291. {
    292. // 注册
    293. platform_driver_unregister(&pdrv);
    294. }
    295. module_init(mycdev_init);
    296. module_exit(mycdev_exit);
    297. MODULE_LICENSE("GPL");

     应用程序代码

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. int main(int argc, char const *argv[])
    10. {
    11. char buf[128] = {0};
    12. int fd = open("/dev/myled0", O_RDWR);
    13. if (fd < 0)
    14. {
    15. printf("打开设备文件失败\n");
    16. exit(-1);
    17. }
    18. while (1)
    19. {
    20. read(fd,buf,sizeof(buf));
    21. printf("%s\n",buf);
    22. }
    23. return 0;
    24. }

    实验现象

     

  • 相关阅读:
    财务领域的数字助手,银企对账与到账通知软件机器人
    四、JavaScript任务管理[同步与异步、宏任务、微任务]
    大语言模型LLM微调技术深度解析:Fine-tuning、Adapter-Tuning与Prompt Tuning的作用机制、流程及实践应用(LLM系列08)
    UEC++ day7
    MIPS汇编入门
    从 C 到 C++ 编程 — 面向对象编程
    NSSCTF第11页(3)
    竞赛 深度学习+opencv+python实现车道线检测 - 自动驾驶
    final关键字
    Latex如何隐藏图片
  • 原文地址:https://blog.csdn.net/weixin_60039521/article/details/133101475