• 驱动 11/24


    要求:设备树点亮板子上的所有灯

    测试代码:

    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. char buf[128] = "";
    9. char ubuf[128] = {0};
    10. int main(int argc, char const *argv[])
    11. {
    12. int fd = -1;
    13. fd = open("/dev/myled0",O_RDWR);
    14. if(-1 == fd)
    15. {
    16. perror("open is error");
    17. exit(1);
    18. }
    19. while(1)
    20. {
    21. printf("请输入你想操控的位置>>0:内核板 1:拓展板\n");
    22. fgets(buf,sizeof(buf),stdin);
    23. buf[strlen(buf)-1]='\0'; //去除换行
    24. printf("请输入你想开灯还是关灯>>0:关灯 1:开灯\n");
    25. fgets(buf+1,sizeof(buf),stdin);
    26. buf[strlen(buf)-1]='\0'; //去除换行
    27. printf("请输入你想操控的灯>>1:LED1 2:LED2 3:LED3\n");
    28. fgets(buf+2,sizeof(buf),stdin);
    29. buf[strlen(buf)-1]='\0'; //去除换行
    30. printf("最后的操作码为:%s\n",buf);
    31. write(fd,buf,sizeof(buf));
    32. }
    33. close(fd);
    34. return 0;
    35. }

    驱动代码

    1. #include <linux/init.h>
    2. #include <linux/module.h>
    3. #include <linux/cdev.h>
    4. #include <linux/fs.h>
    5. #include <linux/device.h>
    6. #include <linux/slab.h>
    7. #include <linux/io.h>
    8. #include <linux/uaccess.h>
    9. #include <linux/of.h>
    10. #include<linux/of_gpio.h>
    11. #include<linux/gpio.h>
    12. #define CNAME "myled"
    13. struct cdev *cdev;
    14. struct class * cls;
    15. struct device * dev;
    16. #if 1
    17. unsigned int major = 0;//动态申请设备号
    18. #else
    19. unsigned int major = 500; //静态指定设备号
    20. #endif
    21. int minor = 0;
    22. const int count = 1;
    23. char kbuf[128] = "";
    24. //定义指针指向获取到的设备节点信息
    25. struct device_node *nhb_node;
    26. struct device_node *tzb_node;
    27. //用于接收到的gpio编号
    28. struct gpio_desc * tzb_gpiono1,* tzb_gpiono2,* tzb_gpiono3;
    29. struct gpio_desc * nhb_gpiono1,* nhb_gpiono2,* nhb_gpiono3;
    30. int mycdev_open(struct inode *inode, struct file *file)
    31. {
    32. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    33. return 0;
    34. }
    35. ssize_t mycdev_read(struct file *file, char __user *ubuf, size_t size, loff_t *loff)
    36. {
    37. int ret;
    38. printk("read:%s:%s:%d\n",__FILE__,__func__,__LINE__);
    39. if(size > sizeof(kbuf)) size = sizeof(kbuf);
    40. ret = copy_to_user(ubuf,kbuf,size);
    41. if(ret)
    42. {
    43. printk("copy to user is error\n");
    44. return -EIO;
    45. }
    46. return size;
    47. return 0;
    48. }
    49. ssize_t mycdev_write (struct file *file, const char __user *ubuf, size_t size, loff_t *loff)
    50. {
    51. int ret;
    52. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    53. //校验传输数据大小,如果用户空间传输数据的大小大于内核空间,需要更正传输数据大小
    54. if(size > sizeof(kbuf)) size = sizeof(kbuf);
    55. ret = copy_from_user(kbuf,ubuf,size);
    56. if(ret)
    57. {
    58. printk("copy from user is error\n");
    59. return -EIO;
    60. }
    61. printk("传递过来的命令为:kbuf=%s\n",kbuf);
    62. /*kbuf[0]:控制内核板还是拓展板
    63. kbuf[1]:开灯还是关灯
    64. kbuf[2]:具体的哪一盏灯
    65. */
    66. switch(kbuf[0])
    67. {
    68. case '0'://内核
    69. switch (kbuf[1])
    70. {
    71. case '0'://关灯
    72. switch (kbuf[2])
    73. {
    74. case '1': //led1
    75. gpiod_set_value(nhb_gpiono1,0);
    76. break;
    77. case '2': //led2
    78. gpiod_set_value(nhb_gpiono2,0);
    79. break;
    80. case '3': //led3
    81. gpiod_set_value(nhb_gpiono3,0);
    82. break;
    83. default:
    84. break;
    85. }
    86. break;
    87. case '1'://开灯
    88. switch (kbuf[2])
    89. {
    90. case '1': //led1
    91. gpiod_set_value(nhb_gpiono1,1);
    92. break;
    93. case '2': //led2
    94. gpiod_set_value(nhb_gpiono2,1);
    95. break;
    96. case '3': //led3
    97. gpiod_set_value(nhb_gpiono3,1);
    98. break;
    99. default:
    100. break;
    101. }
    102. break;
    103. default:
    104. break;
    105. }
    106. case '1'://拓展板
    107. switch (kbuf[1])
    108. {
    109. case '0'://关灯
    110. switch (kbuf[2])
    111. {
    112. case '1': //led1
    113. gpiod_set_value(tzb_gpiono1,0);
    114. break;
    115. case '2': //led2
    116. gpiod_set_value(tzb_gpiono2,0);
    117. break;
    118. case '3': //led3
    119. gpiod_set_value(tzb_gpiono3,0);
    120. break;
    121. default:
    122. break;
    123. }
    124. break;
    125. case '1'://开灯
    126. switch (kbuf[2])
    127. {
    128. case '1': //led1
    129. gpiod_set_value(tzb_gpiono1,1);
    130. break;
    131. case '2': //led2
    132. gpiod_set_value(tzb_gpiono2,1);
    133. break;
    134. case '3': //led3
    135. gpiod_set_value(tzb_gpiono3,1);
    136. break;
    137. default:
    138. break;
    139. }
    140. break;
    141. default:
    142. break;
    143. }
    144. break;
    145. }
    146. return size;
    147. }
    148. int mycdev_close (struct inode *inode, struct file *file)
    149. {
    150. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    151. return 0;
    152. }
    153. const struct file_operations fops = {
    154. .open = mycdev_open,
    155. .read = mycdev_read,
    156. .write = mycdev_write,
    157. .release = mycdev_close,
    158. };
    159. //入口
    160. static int __init mycdev_init(void)
    161. {
    162. int ret;
    163. int i;
    164. dev_t devno;
    165. //1.分配cdev结构体
    166. cdev=cdev_alloc();
    167. if(NULL==cdev)
    168. {
    169. printk("分配结构体失败\n");
    170. ret = -EIO;
    171. goto ERR1;
    172. }
    173. //2.初始化结构体
    174. cdev_init(cdev,&fops);
    175. //3.申请设备号
    176. if(major>0)
    177. {
    178. //静态指定设备号
    179. ret=register_chrdev_region(MKDEV(major,minor),count,CNAME);
    180. if(ret)
    181. {
    182. printk("静态指定设备号失败\n");
    183. ret= -ENOMEM;
    184. goto ERR2;
    185. }
    186. }
    187. else
    188. {
    189. //动态申请设备号
    190. ret=alloc_chrdev_region(&devno,0,count,CNAME);
    191. if(ret)
    192. {
    193. printk("动态指定设备号失败\n");
    194. ret= -ENOMEM;
    195. goto ERR2;
    196. }
    197. //获取主设备号
    198. major=MAJOR(devno);
    199. //获取次设备号
    200. minor=MINOR(devno);
    201. printk("动态指定设备号成功\n");
    202. }
    203. //4.驱动的注册
    204. ret=cdev_add(cdev,MKDEV(major,minor),count);
    205. if(ret)
    206. {
    207. printk("驱动注册失败\n");
    208. ret=-EIO;
    209. goto ERR3;
    210. }
    211. printk("驱动注册成功\n");
    212. //5.自动创建设备节点
    213. //1)向上层提交目录信息
    214. cls=class_create(THIS_MODULE,CNAME);
    215. if(IS_ERR(cls))
    216. {
    217. printk("向上层提交目录信息失败\n");
    218. ret=PTR_ERR(cls);
    219. goto ERR4;
    220. }
    221. //2)向上层提交设备节点信息
    222. printk("向上层提交设备节点信息成功\n");
    223. for(i=0;i<count;i++)
    224. {
    225. dev=device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);
    226. if(IS_ERR(dev))
    227. {
    228. printk("向上层提交设备节点信息失败\n");
    229. ret=PTR_ERR(dev);
    230. goto ERR5;
    231. }
    232. }
    233. printk("向上层提交设备节点信息成功\n");
    234. //灯的初始化
    235. /*
    236. nhb-leds{
    237. led1=<&gpioz 5 0>;
    238. led2=<&gpioz 6 0>;
    239. led3=<&gpioz 7 0>;
    240. };
    241. tzb-leds{
    242. led1=<&gpioe 10 0>;
    243. led2=<&gpiof 10 0>;
    244. led3=<&gpioe 8 0>;
    245. }; */
    246. //通过名字获取设备树结点信息
    247. //拓展板
    248. tzb_node=of_find_node_by_name(NULL,"tzb-leds");
    249. if(tzb_node==NULL)
    250. {
    251. printk("通过名字解析设备树失败\n");
    252. return -EFAULT;
    253. }
    254. printk("通过名字解析设备树成功\n");
    255. //获取并申请gpio编号
    256. tzb_gpiono1=gpiod_get_from_of_node(tzb_node,"led1",0,GPIOD_OUT_LOW,NULL);
    257. if(IS_ERR(tzb_gpiono1))
    258. {
    259. printk("获取并申请gpio编号失败\n");
    260. return PTR_ERR(tzb_gpiono1);
    261. }
    262. tzb_gpiono2=gpiod_get_from_of_node(tzb_node,"led2",0,GPIOD_OUT_LOW,NULL);
    263. if(IS_ERR(tzb_gpiono2))
    264. {
    265. printk("获取并申请gpio编号失败\n");
    266. return PTR_ERR(tzb_gpiono2);
    267. }
    268. tzb_gpiono3=gpiod_get_from_of_node(tzb_node,"led3",0,GPIOD_OUT_LOW,NULL);
    269. if(IS_ERR(tzb_gpiono3))
    270. {
    271. printk("获取并申请gpio编号失败\n");
    272. return PTR_ERR(tzb_gpiono3);
    273. }
    274. printk("获取gpio编号成功\n");
    275. /*
    276. //点亮拓展板led1
    277. gpiod_set_value(tzb_gpiono1,1);
    278. gpiod_set_value(tzb_gpiono2,1);
    279. gpiod_set_value(tzb_gpiono3,1);
    280. */
    281. /*****************************************************************************/
    282. //内核板
    283. nhb_node=of_find_node_by_name(NULL,"nhb-leds");
    284. if(nhb_node==NULL)
    285. {
    286. printk("通过名字解析设备树失败\n");
    287. return -EFAULT;
    288. }
    289. printk("通过名字解析设备树成功\n");
    290. //获取并申请gpio编号
    291. nhb_gpiono1=gpiod_get_from_of_node(nhb_node,"led1",0,GPIOD_OUT_LOW,NULL);
    292. if(IS_ERR(nhb_gpiono1))
    293. {
    294. printk("获取并申请gpio编号失败\n");
    295. return PTR_ERR(nhb_gpiono1);
    296. }
    297. nhb_gpiono2=gpiod_get_from_of_node(nhb_node,"led2",0,GPIOD_OUT_LOW,NULL);
    298. if(IS_ERR(nhb_gpiono2))
    299. {
    300. printk("获取并申请gpio编号失败\n");
    301. return PTR_ERR(nhb_gpiono2);
    302. }
    303. nhb_gpiono3=gpiod_get_from_of_node(nhb_node,"led3",0,GPIOD_OUT_LOW,NULL);
    304. if(IS_ERR(nhb_gpiono3))
    305. {
    306. printk("获取并申请gpio编号失败\n");
    307. return PTR_ERR(nhb_gpiono3);
    308. }
    309. printk("获取gpio编号成功\n");
    310. /*
    311. //点亮内核板led1
    312. gpiod_set_value(nhb_gpiono1,1);
    313. gpiod_set_value(nhb_gpiono2,1);
    314. gpiod_set_value(nhb_gpiono3,1);
    315. */
    316. return 0;
    317. ERR5:
    318. for(--i;i>0;i--)
    319. {
    320. device_destroy(cls,MKDEV(major,i));
    321. }
    322. ERR4:
    323. cdev_del(cdev);
    324. ERR3:
    325. unregister_chrdev_region(MKDEV(major,minor),count);
    326. ERR2:
    327. kfree(cdev);
    328. ERR1:
    329. return -EIO;
    330. }
    331. //出口
    332. static void __exit mycdev_exit(void)
    333. {
    334. int i;
    335. //1。销毁设备节点信息
    336. for(i=0;i<count;i++)
    337. {
    338. device_destroy(cls,MKDEV(major,i));
    339. }
    340. //2.销毁目录信息
    341. class_destroy(cls);
    342. //3.驱动的注销
    343. cdev_del(cdev);
    344. //4.销毁设备号
    345. unregister_chrdev_region(MKDEV(major,minor),count);
    346. //5.释放cdev结构体
    347. kfree(cdev);
    348. //卸载驱动前熄灭灯
    349. gpiod_set_value(tzb_gpiono1,0);
    350. gpiod_set_value(tzb_gpiono2,0);
    351. gpiod_set_value(tzb_gpiono3,0);
    352. gpiod_set_value(nhb_gpiono1,0);
    353. gpiod_set_value(nhb_gpiono2,0);
    354. gpiod_set_value(nhb_gpiono3,0);
    355. //释放申请得到的gpio编号
    356. gpiod_put(tzb_gpiono1);
    357. gpiod_put(tzb_gpiono2);
    358. gpiod_put(tzb_gpiono3);
    359. gpiod_put(nhb_gpiono1);
    360. gpiod_put(nhb_gpiono2);
    361. gpiod_put(nhb_gpiono3);
    362. }
    363. //指定入口地址
    364. module_init(mycdev_init);
    365. module_exit(mycdev_exit);
    366. //指定出口地址
    367. //许可证
    368. MODULE_LICENSE("GPL");

    设备树

     现象:

     

  • 相关阅读:
    Gateway 接口参数加解密
    vector 用法 说明
    spring整合SpringCache
    盘点5个C#开发的、可用于个人博客的系统
    BM1684X搭建sophon sail环境
    [推荐]Linux安装与配置虚拟机之虚拟机服务器坏境配置
    Java面试题之synchronized平台级锁和Lock实现的锁区别
    小红书多账号管理平台哪个好用?可以快速监测多个小红书账号的数据吗?
    五、【React-Router6】路由表 useRoutes() + Outlet
    Golang 变量作用域陷阱 误用短声明导致变量覆盖
  • 原文地址:https://blog.csdn.net/weixin_47202678/article/details/128022374