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


    text.c

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include"head.h"
    9. #include
    10. int main(int argc, char const *argv[])
    11. {
    12. int a,b;
    13. while(1)
    14. {
    15. char buf[128]="/dev/mycdev";
    16. //从终端读取
    17. printf("请输入两个字符\n");
    18. printf("第一个字符:0(LED1) 1(LED2) 2(LED3)\n");
    19. scanf("%d",&b);
    20. sprintf(buf,"%s%d",buf,b);
    21. int fd=open(buf,O_RDWR);
    22. if(fd<0)
    23. {
    24. printf("打开设备文件失败\n");
    25. exit(-1);
    26. }
    27. printf("第二个字符:0(关灯) 1(开灯)\n");
    28. printf("请输入>");
    29. scanf("%d",&a);
    30. switch(a)
    31. {
    32. case 1:
    33. ioctl(fd,LED_ON);
    34. break;
    35. case 0:
    36. ioctl(fd,LED_OFF);
    37. break;
    38. }
    39. close(fd);
    40. }
    41. return 0;
    42. }

    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. #define LED_ON _IO('l', 1)
    16. #define LED_OFF _IO('l', 0)
    17. #endif

    dome.c

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

  • 相关阅读:
    前端开发:JS相关的核心知识点
    [贪心算法]Leetcode738. 单调递增的数字
    003-JavaSE基础巩固练习:if语句练习
    Google单元测试sample分析(二)
    陈奂仁音乐狂欢节:怪异的多色吉他 NFT 系列来袭!
    C# 颜色与坐标
    硬核!一个基于SpringBoot+Vue前后端分离低代码项目
    博客的评论与回复功能的实现
    创建第一个MyBatis框架--保姆级教学
    Python算法——树的最大深度和最小深度
  • 原文地址:https://blog.csdn.net/m0_73775266/article/details/133998657