• 通过platform实现


    drv.c

    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. //获取资源结构体
    17. struct resource *res;
    18. //中断号
    19. unsigned int irqno;
    20. //gpio信息结构体
    21. struct gpio_desc *gpiono;
    22. //字符设备驱动对象空间首地址
    23. struct cdev *cdev;
    24. char kbuf[128] = {0};
    25. //主设备号
    26. unsigned int major = 0;
    27. //次设备号
    28. unsigned int minor = 0;
    29. //设备号
    30. dev_t devno;
    31. module_param(major,uint,0664); //方便在命令行传递major的值
    32. //用于保存目录信息
    33. struct class *cls;
    34. //用于保存设备节点信息
    35. struct device *dev;
    36. int number = 0;
    37. unsigned int condition = 0;
    38. wait_queue_head_t wq_head;
    39. //中断处理函数
    40. irqreturn_t key_handler(int irq,void *dev)
    41. {
    42. gpiod_set_value(gpiono,!(gpiod_get_value(gpiono)));
    43. number = !number;
    44. condition = 1;
    45. wake_up_interruptible(&wq_head);
    46. return IRQ_HANDLED;
    47. }
    48. int mycdev_open(struct inode *inode, struct file *file)
    49. {
    50. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    51. return 0;
    52. }
    53. ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
    54. {
    55. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    56. int ret;
    57. //向用户空间读取拷贝
    58. if(size>sizeof(number))//用户空间期待读取的大小内核满足不了,那就给内核支持的最大大小
    59. size=sizeof(number);
    60. //切换进程为休眠态
    61. wait_event_interruptible(wq_head,condition);
    62. ret=copy_to_user(ubuf,&number,size);
    63. if(ret)//拷贝失败
    64. {
    65. printk("copy_to_user filed\n");
    66. return ret;
    67. }
    68. condition = 0;
    69. return 0;
    70. }
    71. int mycdev_close(struct inode *inode, struct file *file)
    72. {
    73. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    74. return 0;
    75. }
    76. //定义操作方法结构体变量并赋值
    77. struct file_operations fops={
    78. .open=mycdev_open,
    79. .read=mycdev_read,
    80. .release=mycdev_close,
    81. };
    82. //封装probe函数
    83. int pdrv_probe(struct platform_device *pdev)
    84. {
    85. int ret;
    86. // 为字符设备驱动对象申请空间
    87. cdev = cdev_alloc();
    88. if (cdev == NULL)
    89. {
    90. printk("字符设备驱动对象申请空间失败\n");
    91. ret = -EFAULT;
    92. goto out1;
    93. }
    94. printk("申请对象空间成功\n");
    95. // 初始化字符设备驱动对象
    96. cdev_init(cdev, &fops);
    97. // 申请设备号
    98. if (major > 0) // 静态指定设备号
    99. {
    100. ret = register_chrdev_region(MKDEV(major, minor), 3, "myplatform");
    101. if (ret)
    102. {
    103. printk("静态申请设备号失败\n");
    104. goto out2;
    105. }
    106. }
    107. else if (major == 0) // 动态申请设备号
    108. {
    109. ret = alloc_chrdev_region(&devno, minor, 3, "myplatform");
    110. if (ret)
    111. {
    112. printk("动态申请设备号失败\n");
    113. goto out2;
    114. }
    115. major = MAJOR(devno); // 获取主设备号
    116. minor = MINOR(devno); // 获取次设备号
    117. }
    118. printk("申请设备号成功\n");
    119. // 注册字符设备驱动对象
    120. ret = cdev_add(cdev, MKDEV(major, minor), 3);
    121. if (ret)
    122. {
    123. printk("注册字符设备驱动对象失败\n");
    124. goto out3;
    125. }
    126. printk("注册字符设备驱动对象成功\n");
    127. // 向上提交目录信息
    128. cls = class_create(THIS_MODULE, "myplatform");
    129. if (IS_ERR(cls))
    130. {
    131. printk("向上提交目录失败\n");
    132. ret = -PTR_ERR(cls);
    133. goto out4;
    134. }
    135. printk("向上提交目录成功\n");
    136. // 向上提交设备节点信息
    137. int i;
    138. for (i = 0; i < 3; i++)
    139. {
    140. dev = device_create(cls, NULL, MKDEV(major, i), NULL, "myplatform%d", i);
    141. if (IS_ERR(dev))
    142. {
    143. printk("向上提交设备节点信息失败\n");
    144. ret = -PTR_ERR(dev);
    145. goto out5;
    146. }
    147. }
    148. printk("向上提交设备信息成功\n");
    149. //初始化等待队列头
    150. init_waitqueue_head(&wq_head);
    151. //获取MEM类型的资源
    152. res = platform_get_resource(pdev,IORESOURCE_MEM,0);
    153. if(res == NULL)
    154. {
    155. printk("获取MEM类型资源失败\n");
    156. return -ENXIO;
    157. }
    158. //获取中断类型的资源
    159. irqno = platform_get_irq(pdev,0);
    160. if(irqno < 0)
    161. {
    162. printk("获取中断类型资源失败\n");
    163. return -ENXIO;
    164. }
    165. //注册中断
    166. int ret1 = request_irq(irqno,key_handler,IRQF_TRIGGER_FALLING,"key_int",NULL);
    167. if(ret1<0)
    168. {
    169. printk("注册按键1中断失败\n");
    170. return ret1;
    171. }
    172. printk("注册按键1中断成功\n");
    173. printk("mem资源%llx\n",res->start);
    174. printk("irq资源%d\n",irqno);
    175. printk("%s;%s:%d\n",__FILE__,__func__,__LINE__);
    176. //设备树匹配成功后,设备树节点指针可以通过pdev->dev.of_node获取
    177. //基于设备树节点信息获取gpio_desc对象指针
    178. gpiono = gpiod_get_from_of_node(pdev->dev.of_node,"led3-gpio",0,GPIOD_OUT_LOW,NULL);
    179. if(IS_ERR(gpiono))
    180. {
    181. printk("解析GPIO管脚信息失败\n");
    182. return -ENXIO;
    183. }
    184. printk("解析GPIO管脚信息成功\n");
    185. return 0;
    186. out5:
    187. // 释放前一次提交成功的设备信息
    188. for (--i; i >= 0; i--)
    189. {
    190. device_destroy(cls, MKDEV(major, i));
    191. }
    192. class_destroy(cls); // 释放目录
    193. out4:
    194. cdev_del(cdev);
    195. out3:
    196. unregister_chrdev_region(MKDEV(major, minor), 3);
    197. out2:
    198. kfree(cdev);
    199. out1:
    200. return ret;
    201. }
    202. //封装remove函数
    203. int pdrv_remove(struct platform_device *pdev)
    204. {
    205. //关灯
    206. gpiod_set_value(gpiono,0);
    207. //释放GPIO信息
    208. gpiod_put(gpiono);
    209. //注销中断
    210. free_irq(irqno,NULL);
    211. // 释放节点信息
    212. int i;
    213. for (i = 0; i < 3; i++)
    214. {
    215. device_destroy(cls, MKDEV(major, i));
    216. }
    217. // 销毁目录
    218. class_destroy(cls);
    219. // 注销驱动对象
    220. cdev_del(cdev);
    221. // 释放设备号
    222. unregister_chrdev_region(MKDEV(major, minor), 3);
    223. // 释放对象空间
    224. kfree(cdev);
    225. printk("%s;%s:%d\n",__FILE__,__func__,__LINE__);
    226. return 0;
    227. }
    228. //构建设备树匹配表
    229. struct of_device_id oftable[] = {
    230. { .compatible = "hqyj,myplatform"},
    231. { /* end node */ },//防止数组越界
    232. };
    233. //定义驱动信息对象并初始化
    234. struct platform_driver pdrv = {
    235. .probe = pdrv_probe,
    236. .remove = pdrv_remove,
    237. .driver = {
    238. .name = "bbbbb",
    239. .of_match_table=oftable,//用于设备树匹配
    240. },
    241. };
    242. //一键注册宏
    243. module_platform_driver(pdrv);
    244. MODULE_LICENSE("GPL");

    app.c

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. int main(int argc, const char *argv[])
    10. {
    11. int buf[128] = {0};
    12. int fd;
    13. // 打开设备节点
    14. 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,sizeof(buf));
    23. printf("number=%d\n",buf);
    24. }
    25. close(fd);
    26. return 0;
    27. }

  • 相关阅读:
    mysql服务器参数设置
    Spring Boot 检索&定时任务
    可以用商城源码做什么?
    元数据概述
    02129 信息资源建设《信息资源管理(第2版) 电子工业出版社 肖明著》考点整理
    【python】python实现杨辉三角的三种方法
    python 线程池ThreadPoolExecutor
    Jenkins学习笔记
    大数据中的小文件问题
    [EIS 2019]EzPOP
  • 原文地址:https://blog.csdn.net/m0_59343476/article/details/133105342