• 华清远见上海中心22071班--11.19作业


    题目:实现开发板点灯操作

    程序要求:

            1)分部实现注册字符设备驱动

            2)自动创建设备节点

            3)通过结构体对led灯地址进行映射

            4)次设备号完成私有数据传参

            5)在open函数中获取到次设备号,用私有数据传参,传递给write函数

            6)在write函数,判断次设备号,就知道操作的是哪盏灯

    操作方法:

    在串口工具进行输入:

            echo 1 > /dev/myled0 ---->led1灯点亮

            echo 0 > /dev/myled0 ---->led1灯熄灭

            echo 1 > /dev/myled1 ---->led1灯点亮

            echo 0 > /dev/myled1 ---->led1灯熄灭

    程序:

    1. #ifndef __LED_H__
    2. #define __LED_H__
    3. typedef struct{
    4. volatile unsigned int MODER;
    5. volatile unsigned int OPTYPER;
    6. volatile unsigned int OSPEEDR;
    7. volatile unsigned int PUPDR;
    8. volatile unsigned int IDR;
    9. volatile unsigned int ODR;
    10. }gpio_t;
    11. typedef enum{
    12. LED1,
    13. LED2,
    14. LED3
    15. }led_t;
    16. #define GPIOE 0x50006000
    17. #define GPIOF 0x50007000
    18. #define PHY_RCC 0x50000A28
    19. #endif

    ​​​​​​​

    1. #include <linux/module.h>
    2. #include <linux/init.h>
    3. #include <linux/fs.h>
    4. #include <linux/slab.h>
    5. #include <linux/cdev.h>
    6. #include <linux/device.h>
    7. #include "led.h"
    8. #include <linux/uaccess.h>
    9. #include <linux/io.h>
    10. #define CNAME "myled"
    11. struct class *cls;
    12. struct device *dev;
    13. struct cdev *mycdev;
    14. #if 1
    15. unsigned int major = 0;
    16. #else
    17. unsigned int major = 500;
    18. #endif
    19. int minor =0;
    20. const int count = 3;
    21. volatile unsigned int* virt_rcc;
    22. gpio_t *virt_gpioe;
    23. gpio_t *virt_gpiof;
    24. int mycdev_open(struct inode *inode,struct file *file)
    25. {
    26. int pos = MINOR(inode->i_rdev);
    27. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    28. file->private_data = (void*)pos;
    29. return 0;
    30. }
    31. ssize_t mycdev_read(struct file* file,char __user *ubuf,size_t size,loff_t *loffs)
    32. {
    33. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    34. return 0;
    35. }
    36. ssize_t mycdev_write(struct file* file,const char __user *ubuf,size_t size,loff_t *loffs)
    37. {
    38. int pos;
    39. int ret = 0;
    40. char kbuf[5]={0};
    41. if(size > 5) size=5;
    42. ret = copy_from_user(kbuf,ubuf,size);
    43. if(ret)
    44. {
    45. printk("copy from user error\n");
    46. return -EIO;
    47. }
    48. //判断是点灯还是熄灭
    49. pos =(int)file->private_data;
    50. if('1' == kbuf[0])
    51. {
    52. //通过次设备号判断是哪个灯需要亮
    53. switch (pos)
    54. {
    55. case 0:
    56. virt_gpioe->ODR |= (0x1 << 10); //led1输出高电平
    57. break;
    58. case 1:
    59. virt_gpiof->ODR |= (0x1 << 10); //led2输出高电平
    60. break;
    61. case 2:
    62. virt_gpioe->ODR |= (0x1 << 8); //led3输出高电平
    63. break;
    64. }
    65. }
    66. if('0' == kbuf[0])
    67. {
    68. //通过次设备号判断是哪个灯需要灭
    69. switch (pos)
    70. {
    71. case 0:
    72. virt_gpioe->ODR &= ~(0x1 << 10); //led1输出低电平
    73. break;
    74. case 1:
    75. virt_gpiof->ODR &= ~(0x1 << 10); //led2输出低电平
    76. break;
    77. case 2:
    78. virt_gpioe->ODR &= ~(0x1 << 8); //led3输出低电平
    79. break;
    80. }
    81. }
    82. printk("kbuf=%s\n",kbuf);
    83. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    84. return size;
    85. }
    86. int mycdev_close(struct inode *inode,struct file *file)
    87. {
    88. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    89. return 0;
    90. }
    91. const struct file_operations fops ={
    92. .open = mycdev_open,
    93. .read = mycdev_read,
    94. .write = mycdev_write,
    95. .release = mycdev_close,
    96. };
    97. static int __init demo_init(void)
    98. {
    99. int ret = 0;
    100. dev_t devno;
    101. int i;
    102. //分配cdev结构体空间
    103. mycdev = cdev_alloc();
    104. if(NULL == mycdev)
    105. {
    106. printk("cdev alloc error\n");
    107. ret = -EIO;
    108. goto ERR1;
    109. }
    110. //初始化结构体
    111. cdev_init(mycdev,&fops);
    112. //申请设备号
    113. if(major >0)
    114. {
    115. //静态申请设备号
    116. ret = register_chrdev_region(MKDEV(major,minor),count,CNAME);
    117. if(ret)
    118. {
    119. printk("register chrdev regin error\n");
    120. ret = -ENOMEM;
    121. goto ERR2;
    122. }
    123. }
    124. else
    125. {
    126. //动态申请设备号
    127. ret = alloc_chrdev_region(&devno,0,count,CNAME);
    128. if(ret)
    129. {
    130. printk("alloc_chrdev error\n");
    131. ret = -ENOMEM;
    132. goto ERR2;
    133. }
    134. major = MAJOR(devno);
    135. minor = MINOR(devno);
    136. }
    137. //驱动注册
    138. ret = cdev_add(mycdev,MKDEV(major,minor),count);
    139. if(ret)
    140. {
    141. printk("cdev add error\n");
    142. ret = -EIO;
    143. goto ERR3;
    144. }
    145. //自动创建设备节点
    146. //提交目录信息
    147. cls = class_create(THIS_MODULE,CNAME);
    148. if(IS_ERR(cls))
    149. {
    150. printk("class create error\n");
    151. ret = PTR_ERR(cls);
    152. goto ERR4;
    153. }
    154. //提交设备节点信息
    155. for(i=0;i<count;i++)
    156. {
    157. dev = device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);
    158. if(IS_ERR(dev))
    159. {
    160. printk("device create error\n");
    161. ret = PTR_ERR(dev);
    162. goto ERR5;
    163. }
    164. }
    165. //对灯的物理地址进行映射
    166. virt_rcc = ioremap(PHY_RCC,4);
    167. if(NULL == virt_rcc)
    168. {
    169. printk("rcc ioremap is error\n");
    170. return -ENOMEM;
    171. }
    172. virt_gpioe = ioremap(GPIOE,sizeof(GPIOE));
    173. if(NULL == virt_gpioe)
    174. {
    175. printk("gpio moder ioremap is error\n");
    176. return -ENOMEM;
    177. }
    178. virt_gpiof = ioremap(GPIOF,sizeof(GPIOF));
    179. if(NULL == virt_gpiof)
    180. {
    181. printk("gpio odr ioremap is error\n");
    182. return -ENOMEM;
    183. }
    184. //将rcc、gpio初始化 PE10\PF10\PE8
    185. *virt_rcc |= (0x3<<4);
    186. //PE10初始化
    187. virt_gpioe->MODER &= (~(0x3<<20));
    188. virt_gpioe->MODER |= 0x1<<20;
    189. virt_gpioe->ODR &= (~(0x1<<10));
    190. //PE8初始化
    191. virt_gpioe->MODER &= (~(0x3<<16));
    192. virt_gpioe->MODER |= 0x1<<16;
    193. virt_gpioe->ODR &= (~(0x1<<8));
    194. //PF10初始化
    195. virt_gpiof->MODER &= (~(0x3<<20));
    196. virt_gpiof->MODER |= 0x1<<20;
    197. virt_gpiof->ODR &= (~(0x1<<10));
    198. return 0;
    199. ERR5:
    200. for(--i;i>=0;i--)
    201. {
    202. device_destroy(cls,MKDEV(major,i));
    203. }
    204. class_destroy(cls);
    205. ERR4:
    206. cdev_del(mycdev);
    207. ERR3:
    208. unregister_chrdev_region(MKDEV(major,minor),count);
    209. ERR2:
    210. kfree(mycdev);
    211. ERR1:
    212. return -EIO;
    213. }
    214. static void __exit demo_exit(void)
    215. {
    216. int i = 0;
    217. //销毁设备节点信息
    218. for(i=0;i<count;i++)
    219. {
    220. device_destroy(cls,MKDEV(major,i));
    221. }
    222. //销毁目录信息
    223. class_destroy(cls);
    224. //驱动注销
    225. cdev_del(mycdev);
    226. //注销设备号
    227. unregister_chrdev_region(MKDEV(major,minor),count);
    228. //释放结构体指针
    229. kfree(mycdev);
    230. }
    231. module_init(demo_init);
    232. module_exit(demo_exit);
    233. MODULE_LICENSE("GPL");

    测试命令

            在串口工具依次输入命令,点亮LED1\LED2\LED3,然后依次熄灭LED1\LED2\LED3,如下图

    测试结果:

    LED1亮:

    LED1\LED2亮:

    LED1\LED2\LED3亮:

     LED1熄灭:

    LED1\LED2熄灭:

    LED1\LED2\LED3熄灭:

  • 相关阅读:
    最全最简洁的gitlab代码提交流程
    数组指针的使用
    谷歌JAX快速入门笔记详解和案例
    php的短信验证的流程,如何实现前端js加后端php
    二、什么是寄存器
    vite和webpack的区别
    elasticSearch配置
    VR虚拟现实:VR技术如何进行原型制作
    Composition API(常用部分)
    你的Web3域名 价值究竟何在?
  • 原文地址:https://blog.csdn.net/guangyinAA/article/details/127937623