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


    head.h

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

    cdev.c

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

    test.c

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

  • 相关阅读:
    推荐计划为什么有效?需要推荐计划的10个原因
    图解|从根上彻底理解MySQL的索引
    JSON和全局异常处理
    笔记-Python编码问题整理
    【探索Linux】—— 强大的命令行工具 P.26(网络编程套接字基本概念—— socket编程接口 | socket编程接口相关函数详细介绍 )
    [AI]Python中的Restful
    【C语言】【排序算法】----- 归并排序
    哈工大机器人竞技队成立22年来4次获国际冠军
    IDE相关设置和插件
    实时即未来,大数据项目车联网之原始数据实时ETL任务消费数据策略【三】
  • 原文地址:https://blog.csdn.net/m0_59343476/article/details/132865832