• 通过字符设备驱动的分步实现编写LED驱动,另外实现特备文件和设备的绑定


    头文件.h文件

    1. #ifndef __HEAD_H__
    2. #define __HEAD_H__
    3. typedef struct
    4. {
    5. unsigned int MODER;
    6. unsigned int OTYPER;
    7. unsigned int OSPEEDR;
    8. unsigned int PUPDR;
    9. unsigned int IDR;
    10. unsigned int ODR;
    11. } gpio_t;
    12. #define PHY_LED1_ADDR 0X50006000
    13. #define PHY_LED2_ADDR 0X50007000
    14. #define PHY_LED3_ADDR 0X50006000
    15. #define PHY_RCC_ADDR 0X50000A28
    16. // 构建开灯关灯的功能码
    17. #define LED_ON _IO('l', 1)
    18. #define LED_OFF _IO('l', 0)
    19. #endif

    驱动文件

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

    应用程序

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include "head.h"
    10. int fd1=0, fd2=0, fd3=0;
    11. int main(int argc, char const *argv[])
    12. {
    13. char buf[128] = {0};
    14. int a, b;
    15. while (1)
    16. {
    17. // 从终端读取
    18. printf("myled0控制led1,myled0控制led1,myled0控制led1\n");
    19. printf("请选择要控制的灯:1 2 3\n");
    20. printf("请输入>");
    21. scanf("%d", &a);
    22. printf("请输入要实现的功能 ");
    23. printf("0(关灯) 1(开灯)\n");
    24. printf("请输入>");
    25. scanf("%d", &b);
    26. switch (a)
    27. {
    28. case 1:
    29. if (fd2 > 0)
    30. close(fd2);
    31. if (fd3 > 0)
    32. close(fd3);
    33. fd1 = open("/dev/myled0", O_RDWR);
    34. if (fd1 < 0)
    35. {
    36. printf("打开设备文件失败\n");
    37. exit(-1);
    38. }
    39. ioctl(fd1, 1, b);
    40. break;
    41. case 2:
    42. if (fd2 > 0)
    43. close(fd2);
    44. if (fd2 > 0)
    45. close(fd2);
    46. fd1 = open("/dev/myled1", O_RDWR);
    47. if (fd1 < 0)
    48. {
    49. printf("打开设备文件失败\n");
    50. exit(-1);
    51. }
    52. ioctl(fd1, 2, b);
    53. break;
    54. case 3:
    55. if (fd1 > 0)
    56. close(fd1);
    57. if (fd2 > 0)
    58. close(fd2);
    59. fd3 = open("/dev/myled2", O_RDWR);
    60. if (fd3 < 0)
    61. {
    62. printf("打开设备文件失败\n");
    63. exit(-1);
    64. }
    65. ioctl(fd3, 3, b);
    66. break;
    67. default:
    68. break;
    69. }
    70. }
    71. if (fd1 > 0)
    72. close(fd1);
    73. if (fd2 > 0)
    74. close(fd2);
    75. if (fd3 > 0)
    76. close(fd3);
    77. return 0;
    78. }

     

     

     

     

  • 相关阅读:
    软件测试高频面试题真实分享/网上银行转账是怎么测的,设计一下测试用例。
    分类预测 | Matlab实现PSO-LSTM-Attention粒子群算法优化长短期记忆神经网络融合注意力机制多特征分类预测
    多文件上传
    基于stm32单片机的水位检测自动抽水系统
    nexus搭建npm私有镜像
    如何飞速成为开源贡献者(Contributor)
    沃尔玛、阿里国际该如何做测评自养号?
    [附源码]计算机毕业设计社区住户信息管理系统Springboot程序
    golang jwt-go 一个案例搞懂jwt鉴权
    二分查找,求方程多解
  • 原文地址:https://blog.csdn.net/ck0056/article/details/133999652