• 驱动开发 作业 day9 9/20


    基于platform实现

    head.h

    1. #ifndef __HEAD_H__
    2. #define __HEAD_H__
    3. //构建LED开关的功能码,不添加ioctl第三个参数
    4. #define LED_ON _IO('l',1)
    5. #define LED_OFF _IO('l',0)
    6. #endif

    test.c

    1. #include <stdlib.h>
    2. #include <stdio.h>
    3. #include <sys/types.h>
    4. #include <sys/stat.h>
    5. #include <fcntl.h>
    6. #include <unistd.h>
    7. #include <string.h>
    8. #include <sys/ioctl.h>
    9. #include "head.h"
    10. int main(int argc, char const *argv[])
    11. {
    12. int a;
    13. char buf[128] = {0};
    14. int fd = open("/dev/myplatform0", O_RDWR);
    15. if (fd < 0)
    16. {
    17. printf("打开设备文件失败\n");
    18. exit(-1);
    19. }
    20. while (1)
    21. {
    22. read(fd, buf, 1);
    23. switch (buf[0])
    24. {
    25. case 1:
    26. ioctl(fd, LED_ON); // 开灯
    27. break;
    28. case 0:
    29. ioctl(fd, LED_OFF); // 关灯
    30. }
    31. }
    32. close(fd);
    33. return 0;
    34. }

    pdr.c

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

  • 相关阅读:
    Apache Hadoop 输入格式示例
    C++ 语言学习 day15 复习 (7)
    五个与iOS基础开发相关的案例:
    刘知远:大模型值得探索的十个研究方向
    【C++笔试强训】第二十天
    前后端分离-图书价格排序案例、后端返回图片地址显示在组件上(打印图片地址)
    Mybatis学习笔记1 Mybatis入门
    闪马智能完成4亿元第四轮融资 国产自主可控AI平台加速赋能城市升级
    三大缓存技术--localStorage、sessionStorage、Cookie
    使用SpringBoot发送异步事件的方式解决前端接口调用超时问题
  • 原文地址:https://blog.csdn.net/qq_56558010/article/details/133099178