• 通过字符设备驱动分步注册方式编写LED驱动,完成设备文件和设备的绑定


    mychrdev.c

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include "head.h"
    10. char kbuf[128] = {0};
    11. gpio_t *vir_led1;
    12. gpio_t *vir_led2;
    13. gpio_t *vir_led3;
    14. unsigned int *vir_rcc;
    15. struct class *cls;
    16. struct device *dev;
    17. dev_t devno;
    18. struct cdev *cdev;
    19. unsigned int major;
    20. unsigned int minor;
    21. int mycdev_open(struct inode *inode, struct file *file)
    22. {
    23. int min = MINOR(inode->i_rdev);
    24. file->private_data = (void *)min;
    25. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    26. return 0;
    27. }
    28. long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    29. {
    30. int min = (int)file->private_data;
    31. switch (min)
    32. {
    33. case 0: // 控制LED1
    34. switch (cmd)
    35. {
    36. case LED_ON:
    37. // 开灯
    38. vir_led1->ODR |= 1 << 10;
    39. break;
    40. case LED_OFF:
    41. // 关灯
    42. vir_led1->ODR &= (~(1 << 10));
    43. break;
    44. }
    45. break;
    46. case 1: // 控制LED2
    47. switch (cmd)
    48. {
    49. case LED_ON:
    50. // 开灯
    51. vir_led2->ODR |= 1 << 10;
    52. break;
    53. case LED_OFF:
    54. // 关灯
    55. vir_led2->ODR &= (~(1 << 10));
    56. break;
    57. }
    58. break;
    59. case 2: // 控制LED3
    60. switch (cmd)
    61. {
    62. case LED_ON:
    63. // 开灯
    64. vir_led3->ODR |= 1 << 8;
    65. break;
    66. case LED_OFF:
    67. // 关灯
    68. vir_led3->ODR &= (~(1 << 8));
    69. break;
    70. }
    71. break;
    72. }
    73. return 0;
    74. }
    75. int mycdev_close(struct inode *inode, struct file *file)
    76. {
    77. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    78. return 0;
    79. }
    80. // 定义操作方法结构体变量并赋值
    81. struct file_operations fops = {
    82. .open = mycdev_open,
    83. .unlocked_ioctl = mycdev_ioctl,
    84. .release = mycdev_close,
    85. };
    86. int all_led_init(void)
    87. {
    88. // 寄存器地址的映射
    89. vir_led1 = ioremap(PHY_LED1_ADDR, sizeof(gpio_t));
    90. if (vir_led1 == NULL)
    91. {
    92. printk("ioremap filed:%d\n", __LINE__);
    93. return -ENOMEM;
    94. }
    95. vir_led2 = ioremap(PHY_LED2_ADDR, sizeof(gpio_t));
    96. if (vir_led2 == NULL)
    97. {
    98. printk("ioremap filed:%d\n", __LINE__);
    99. return -ENOMEM;
    100. }
    101. vir_led3 = vir_led1;
    102. vir_rcc = ioremap(PHY_RCC_ADDR, 4);
    103. if (vir_rcc == NULL)
    104. {
    105. printk("ioremap filed:%d\n", __LINE__);
    106. return -ENOMEM;
    107. }
    108. printk("物理地址映射成功\n");
    109. // 寄存器的初始化
    110. // rcc
    111. (*vir_rcc) |= (0X3 << 4);
    112. // led1
    113. vir_led1->MODER &= (~(3 << 20));
    114. vir_led1->MODER |= (1 << 20);
    115. vir_led1->ODR &= (~(1 << 10));
    116. // led2
    117. vir_led2->MODER &= (~(3 << 20));
    118. vir_led2->MODER |= (1 << 20);
    119. vir_led2->ODR &= (~(1 << 10));
    120. // led3
    121. vir_led3->MODER &= (~(3 << 16));
    122. vir_led1->MODER |= (1 << 16);
    123. vir_led1->ODR &= (~(1 << 8));
    124. printk("寄存器初始化成功\n");
    125. return 0;
    126. }
    127. static int __init mycdev_init(void)
    128. {
    129. int ret;
    130. // 为字符设备驱动对象申请空间
    131. cdev = cdev_alloc();
    132. if (cdev == NULL)
    133. {
    134. printk("字符设备驱动对象申请空间失败\n");
    135. ret = -EFAULT;
    136. goto out1;
    137. }
    138. printk("申请对象空间成功\n");
    139. // 初始化字符设备驱动对象
    140. cdev_init(cdev, &fops);
    141. // 申请设备号
    142. if (major > 0) // 静态指定设备号
    143. {
    144. ret = register_chrdev_region(MKDEV(major, minor), 3, "myled");
    145. if (ret)
    146. {
    147. printk("静态申请设备号失败\n");
    148. goto out2;
    149. }
    150. }
    151. else if (major == 0) // 动态申请设备号
    152. {
    153. ret = alloc_chrdev_region(&devno, minor, 3, "myled");
    154. if (ret)
    155. {
    156. printk("动态申请设备号失败\n");
    157. goto out2;
    158. }
    159. major = MAJOR(devno); // 获取主设备号
    160. minor = MINOR(devno); // 获取次设备号
    161. }
    162. printk("申请设备号成功\n");
    163. // 注册字符设备驱动对象
    164. ret = cdev_add(cdev, MKDEV(major, minor), 3);
    165. if (ret)
    166. {
    167. printk("注册字符设备驱动对象失败\n");
    168. goto out3;
    169. }
    170. printk("注册字符设备驱动对象成功\n");
    171. // 向上提交目录信息
    172. cls = class_create(THIS_MODULE, "myled");
    173. if (IS_ERR(cls))
    174. {
    175. printk("向上提交目录失败\n");
    176. ret = -PTR_ERR(cls);
    177. goto out4;
    178. }
    179. printk("向上提交目录成功\n");
    180. // 向上提交设备节点信息
    181. int i;
    182. for (i = 0; i < 3; i++)
    183. {
    184. dev = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i);
    185. if (IS_ERR(dev))
    186. {
    187. printk("向上提交设备节点信息失败\n");
    188. ret = -PTR_ERR(dev);
    189. goto out5;
    190. }
    191. }
    192. printk("向上提交设备信息成功\n");
    193. return 0;
    194. out5:
    195. // 释放前一次提交成功的设备信息
    196. for (--i; i >= 0; i--)
    197. {
    198. device_destroy(cls, MKDEV(major, i));
    199. }
    200. class_destroy(cls); // 释放目录
    201. out4:
    202. cdev_del(cdev);
    203. out3:
    204. unregister_chrdev_region(MKDEV(major, minor), 3);
    205. out2:
    206. kfree(cdev);
    207. out1:
    208. return ret;
    209. }
    210. static void __exit mycdev_exit(void)
    211. {
    212. // 释放节点信息
    213. int i;
    214. for (i = 0; i < 3; i++)
    215. {
    216. device_destroy(cls, MKDEV(major, i));
    217. }
    218. // 销毁目录
    219. class_destroy(cls);
    220. // 注销驱动对象
    221. cdev_del(cdev);
    222. // 释放设备号
    223. unregister_chrdev_region(MKDEV(major, minor), 3);
    224. // 释放对象空间
    225. kfree(cdev);
    226. // 取消地址映射
    227. iounmap(vir_led1);
    228. iounmap(vir_led2);
    229. iounmap(vir_rcc);
    230. // 注销字符设备驱动
    231. // unregister_chrdev(major, "mychrdev");
    232. }
    233. module_init(mycdev_init);
    234. module_exit(mycdev_exit);
    235. MODULE_LICENSE("GPL");

  • 相关阅读:
    基于 FastAPI 的房源租赁系统设计与实现
    汽车电子中的安森美深力科分享一款高性能车规级芯片NCV7520MWTXG
    GEE python:给矢量集合中的各个矢量添加属性信息和随机值
    你不知道的原生js广播频道接口
    K8S Pod控制器Deployment简介
    spark算子简单案例 - Python
    个人PC安装软件
    道教和道家的区别
    options.css 内容优化2 --chatPGT
    Linux chmod命令使用介绍
  • 原文地址:https://blog.csdn.net/weixin_47976606/article/details/132863515