• 驱动 私有数据传参点灯


    1.在串口工具进行输入:   
        echo 1 > /dev/myled0 ---->led1灯点亮
        echo 0 > /dev/myled0 ---->led1灯熄灭
        echo 1 > /dev/myled1 ---->led1灯点亮
        echo 0 > /dev/myled1 ---->led1灯熄灭
        echo 1 > /dev/myled2 ---->led1灯点亮
        echo 0 > /dev/myled2 ---->led1灯熄灭
    linux@ubuntu:/sys/class/myled$ ls /dev/myled* -ll
        
    crw------- 1 root root 236, 0 Nov 18 14:55 /dev/myled0 ----->控制PE10(LED1)
        crw------- 1 root root 236, 1 Nov 18 14:55 /dev/myled1----->控制PF10(LED2)
        crw------- 1 root root 236, 2 Nov 18 14:55 /dev/myled2----->控制PE8(LED3)

    2.驱动:
        open:在open函数中获取到次设备号,用私有数据传参,传递给write函数
        write:在write函数,判断次设备号,就知道操作的是哪盏灯

    3.要求:
        1)分部实现注册字符设备驱动
        2)自动创建设备节点
        3)通过结构体对led灯地址进行映射
        4)次设备号完成私有数据传参

    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/ioctl.h>
    8. #include <linux/cdev.h>
    9. #include <linux/mm.h>
    10. #include <linux/slab.h>
    11. #include <linux/kernel.h>
    12. #include <uapi/linux/kdev_t.h>
    13. #include "myled.h"
    14. #define CNAME "myled"
    15. char kbuf[128] = {0};
    16. struct class *cls;
    17. struct device *dev;
    18. //虚拟地址
    19. gpio_t *virt_gpioe; //PE
    20. gpio_t *virt_gpiof; //PF
    21. volatile unsigned int *virt_rcc; //RCC
    22. //cdev结构体指针
    23. struct cdev *cdev;
    24. #if 1
    25. unsigned int major=0; //动态申请设备号
    26. #else
    27. unsigned int major=500; //静态申请设备号
    28. #endif
    29. int minor = 0;
    30. const int count=3;
    31. int mycdev_open(struct inode *inode, struct file *file)
    32. {
    33. int minor;
    34. minor=MINOR(inode->i_rdev);
    35. file->private_data=(void*)minor;
    36. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    37. return 0;
    38. }
    39. ssize_t mycdev_read(struct file *file, char __user *ubuf, size_t size, loff_t *loff)
    40. {
    41. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    42. return size;
    43. }
    44. ssize_t mycdev_write (struct file *file, const char __user *ubuf, size_t size, loff_t *loff)
    45. {
    46. int minor;
    47. int ret;
    48. minor=(int)file->private_data;
    49. switch(minor)
    50. {
    51. case 0: //LED1---->PE10
    52. if(size > sizeof(kbuf))
    53. {
    54. size=sizeof(kbuf);
    55. }
    56. ret=copy_from_user(kbuf,ubuf,size);
    57. if(ret)
    58. {
    59. printk("传递数据失败\n");
    60. return -EIO;
    61. }
    62. if('0'==kbuf[0])
    63. {
    64. virt_gpioe->ODR &= (~(0x1<<10));
    65. }
    66. else
    67. {
    68. virt_gpioe->ODR |=(0x1<<10);
    69. }
    70. break;
    71. case 1: //LED2---->PF10
    72. if(size > sizeof(kbuf))
    73. {
    74. size=sizeof(kbuf);
    75. }
    76. ret=copy_from_user(kbuf,ubuf,size);
    77. if(ret)
    78. {
    79. printk("传递数据失败\n");
    80. return -EIO;
    81. }
    82. if('0'==kbuf[0])
    83. {
    84. virt_gpiof->ODR &= (~(0x1<<10));
    85. }
    86. else
    87. {
    88. virt_gpiof->ODR |=(0x1<<10);
    89. }
    90. break;
    91. case 2: //LED3---->PE8
    92. if(size > sizeof(kbuf))
    93. {
    94. size=sizeof(kbuf);
    95. }
    96. ret=copy_from_user(kbuf,ubuf,size);
    97. if(ret)
    98. {
    99. printk("传递数据失败\n");
    100. return -EIO;
    101. }
    102. if('0'==kbuf[0])
    103. {
    104. virt_gpioe->ODR &= (~(0x1<<8));
    105. }
    106. else
    107. {
    108. virt_gpioe->ODR |=(0x1<<8);
    109. }
    110. break;
    111. }
    112. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    113. return size;
    114. }
    115. long mycdev_ioctl(struct file *file,unsigned int cmd,unsigned long arg)
    116. {
    117. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    118. return 0;
    119. }
    120. int mycdev_close(struct inode *inode, struct file *file)
    121. {
    122. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    123. return 0;
    124. }
    125. //操作方法结构体
    126. const struct file_operations fops =
    127. {
    128. .open = mycdev_open,
    129. .read = mycdev_read,
    130. .write = mycdev_write,
    131. .unlocked_ioctl = mycdev_ioctl,
    132. .release = mycdev_close,
    133. };
    134. //入口
    135. static int __init mycdev_init(void)
    136. {
    137. int i;
    138. int ret;
    139. dev_t devno; //动态分配的设备号
    140. //1.分配cdev结构体
    141. cdev=cdev_alloc();
    142. if(NULL==cdev)
    143. {
    144. printk("cdev_alloc fail\n");
    145. goto ERR1;
    146. return -EIO;
    147. }
    148. //2.初始化结构体
    149. cdev_init(cdev,&fops);
    150. //3.申请设备号
    151. if(major>0)
    152. {
    153. //静态
    154. ret=register_chrdev_region(MKDEV(major,minor),count,CNAME);
    155. if(ret)
    156. {
    157. printk("静态申请设备号失败\n");
    158. ret=-ENOMEM;
    159. goto ERR2;
    160. }
    161. }
    162. else
    163. {
    164. //动态申请设备号
    165. ret=alloc_chrdev_region(&devno,0,count,CNAME);
    166. if(ret)
    167. {
    168. printk("动态申请设备失败\n");
    169. ret=-ENOMEM;
    170. goto ERR2;
    171. }
    172. major=MAJOR(devno);
    173. minor=MINOR(devno);
    174. }
    175. //4.驱动的注册
    176. ret=cdev_add(cdev,MKDEV(major,minor),count);
    177. if(ret)
    178. {
    179. printk("驱动注册失败\n");
    180. return -EIO;
    181. goto ERR3;
    182. }
    183. //5.自动创建设备节点
    184. cls=class_create(THIS_MODULE,CNAME);
    185. if(IS_ERR(cls))
    186. {
    187. printk("向上层提交目录信息失败\n");
    188. ret=PTR_ERR(cls);
    189. goto ERR4;
    190. }
    191. //提交设备结点信息
    192. for(i=0;i<count;i++)
    193. {
    194. dev=device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);
    195. if(IS_ERR(dev))
    196. {
    197. printk("提交设备结点信息失败\n");
    198. ret=PTR_ERR(dev);
    199. goto ERR5;
    200. }
    201. }
    202. //对灯地址进行映射
    203. virt_rcc=ioremap(PHY_RCC,4);
    204. if(NULL==virt_rcc)
    205. {
    206. printk("RCC映射失败\n");
    207. return -ENOMEM;
    208. }
    209. virt_gpioe=ioremap(PHY_GPIOE,sizeof(gpio_t));
    210. if(NULL==virt_gpioe)
    211. {
    212. printk("GPIOE映射失败");
    213. return -ENOMEM;
    214. }
    215. virt_gpiof=ioremap(PHY_GPIOF,sizeof(gpio_t));
    216. if(NULL==virt_gpiof)
    217. {
    218. printk("GPIOF映射失败\n");
    219. return -ENOMEM;
    220. }
    221. //对灯进行初始化
    222. //RCC使能
    223. *virt_rcc |= (0x3 << 4);
    224. //1.对LED1--->PE10初始化
    225. //设置PE10引脚为输出模式
    226. virt_gpioe->MODER &= (~(0x3 << 20));
    227. virt_gpioe->MODER |= (0x1 << 20);
    228. //设置PE10引脚默认为低电平
    229. virt_gpioe->ODR &= (~(0x1 << 10));
    230. //2.对LED2--->PF10初始化
    231. //设置PF10引脚为输出模式
    232. virt_gpiof->MODER &= (~(0x3 << 20));
    233. virt_gpiof->MODER |= (0x1 << 20);
    234. //设置PF10引脚默认为低电平
    235. virt_gpiof->ODR &= (~(0x1 << 10));
    236. //3.对LED3--->PE8初始化
    237. //设置PE8引脚为输出模式
    238. virt_gpioe->MODER &= (~(0x3 << 16));
    239. virt_gpioe->MODER |= (0x1 << 16);
    240. //设置PE8引脚默认为低电平
    241. virt_gpioe->ODR &= (~(0x1 << 8));
    242. return 0;
    243. ERR5:
    244. for(--i;i>0;i--)
    245. {
    246. device_destroy(cls,MKDEV(major,i));
    247. }
    248. class_destroy(cls);
    249. ERR4:
    250. cdev_del(cdev);
    251. ERR3:
    252. unregister_chrdev_region(MKDEV(major,minor),count);
    253. ERR2:
    254. kfree(cdev);
    255. ERR1:
    256. //返回错误码
    257. return -EIO;
    258. }
    259. //出口
    260. static void __exit mycdev_exit(void)
    261. {
    262. int i;
    263. //1。销毁设备节点信息
    264. for(i=0;i<count;i++)
    265. {
    266. device_destroy(cls,MKDEV(major,i));
    267. }
    268. //2.销毁目录信息
    269. class_destroy(cls);
    270. //3.驱动的注销
    271. cdev_del(cdev);
    272. //4.销毁设备号
    273. unregister_chrdev_region(MKDEV(major,minor),count);
    274. //5.释放cdev结构体
    275. kfree(cdev);
    276. }
    277. //指定入口地址
    278. module_init(mycdev_init);
    279. module_exit(mycdev_exit);
    280. //指定出口地址
    281. //许可证
    282. MODULE_LICENSE("GPL");

     

     

     

     

     

  • 相关阅读:
    创建vue3工程
    java计算机毕业设计桂林恒保健康防护有限公司官网MyBatis+系统+LW文档+源码+调试部署
    深度学习模型部署全流程-模型部署
    155. RESTframe的请求和响应
    mybatis的使用技巧8——联合查询union和union all的区别和用法
    MySQL学习指南&笔记&经典案例句
    DTC 2024,Databend 数据汇聚平台的建设与挑战
    关于公司后端技术团队的建设
    组件封装使用?
    Python 对 split函数的理解
  • 原文地址:https://blog.csdn.net/weixin_47202678/article/details/127938278