• 【无标题】


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

    用户层程序app

    1. #include <stdio.h>
    2. #include <sys/types.h>
    3. #include <sys/stat.h>
    4. #include <fcntl.h>
    5. #include <unistd.h>
    6. #include <stdlib.h>
    7. #include <string.h>
    8. #include <sys/ioctl.h>
    9. #include "head.h"
    10. int main(int argc, const char *argv[])
    11. {
    12. char buf[128] = "";
    13. int a;
    14. int fd;
    15. while (1)
    16. {
    17. printf("请选择要打开的灯(1,2,3)\n");
    18. scanf(" %d", &a);
    19. switch (a)
    20. {
    21. case 1:
    22. fd = open("/dev/myled0", O_RDWR);
    23. if (fd < 0)
    24. {
    25. printf("设备文件打开失败\n");
    26. exit(-1);
    27. }
    28. printf("打开文件%d成功\n",a-1);
    29. break;
    30. case 2:
    31. fd = open("/dev/myled1", O_RDWR);
    32. if (fd < 0)
    33. {
    34. printf("设备文件打开失败\n");
    35. exit(-1);
    36. }
    37. printf("打开文件%d成功\n",a-1);
    38. break;
    39. case 3:
    40. fd = open("/dev/myled2", O_RDWR);
    41. if (fd < 0)
    42. {
    43. printf("设备文件打开失败\n");
    44. exit(-1);
    45. }
    46. printf("打开文件%d成功\n",a-1);
    47. break;
    48. default:
    49. printf("请输入范围内的数\n");
    50. }
    51. int b;
    52. printf("请开灯关灯(0/1)\n");
    53. scanf(" %d",&b);
    54. switch(b)
    55. {
    56. case 1:
    57. ioctl(fd,LED_ON);
    58. break;
    59. case 0:
    60. ioctl(fd,LED_OF);
    61. break;
    62. default:
    63. printf("请输入'0'或'1'\n");
    64. }
    65. close(fd);
    66. printf("关闭文件%d\n",a-1);
    67. }
    68. return 0;
    69. }

    驱动程序

    1. #include <linux/init.h>
    2. #include <linux/module.h>
    3. #include <linux/fs.h>
    4. #include <linux/uaccess.h>
    5. #include <linux/compiler.h>
    6. #include <linux/io.h>
    7. #include <linux/device.h>
    8. #include <linux/slab.h>
    9. #include <linux/cdev.h>
    10. #include "head.h"
    11. unsigned int major;
    12. struct class *cls;
    13. struct device *dev;
    14. char kbuf[128] = "";
    15. unsigned int *vir_modere;
    16. unsigned int *vir_moderf;
    17. unsigned int *vir_rcc;
    18. unsigned int *vir_odre;
    19. unsigned int *vir_odrf;
    20. struct cdev *cdev;
    21. unsigned int major = 240;
    22. unsigned int minor = 0;
    23. struct class *cls;
    24. struct device *dev;
    25. int ret;
    26. dev_t devno;
    27. int mycdev_open(struct inode *inode, struct file *file)
    28. {
    29. int num=MINOR(inode->i_rdev);
    30. file->private_data=(void*)num;
    31. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    32. return 0;
    33. }
    34. ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
    35. {
    36. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    37. return 0;
    38. }
    39. ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
    40. {
    41. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    42. return 0;
    43. }
    44. int mycdev_close(struct inode *inode, struct file *file)
    45. {
    46. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    47. return 0;
    48. }
    49. long myled_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    50. {
    51. int num=(int)file->private_data;
    52. switch(num)
    53. {
    54. case 0://控制LED1
    55. switch(cmd)
    56. {
    57. case LED_ON:
    58. (*vir_odre) |= (0x1 << 10);
    59. break;
    60. case LED_OF:
    61. (*vir_odre) &= (~(0x1 << 10));
    62. }
    63. break;
    64. case 1://控制LED2
    65. switch(cmd)
    66. {
    67. case LED_ON:
    68. (*vir_odrf) |= (0x1 << 10);
    69. break;
    70. case LED_OF:
    71. (*vir_odrf) &= (~(0x1 << 10));
    72. }
    73. break;
    74. case 2://控制LED3
    75. switch(cmd)
    76. {
    77. case LED_ON:
    78. (*vir_odre) |= (0x1 << 8);
    79. break;
    80. case LED_OF:
    81. (*vir_odre) &= (~(0x1 << 8));
    82. }
    83. }
    84. return 0;
    85. }
    86. struct file_operations fops = {
    87. .open = mycdev_open,
    88. .read = mycdev_read,
    89. .write = mycdev_write,
    90. .release = mycdev_close,
    91. .unlocked_ioctl=myled_ioctl,
    92. };
    93. int led_init(void)
    94. {
    95. vir_rcc = ioremap(LED_RCC, 4);
    96. if (vir_rcc == NULL)
    97. {
    98. printk("物理映射失败%d\n", __LINE__);
    99. }
    100. vir_modere = ioremap(LED_MODERE, 4);
    101. if (vir_rcc == NULL)
    102. {
    103. printk("物理映射失败%d\n", __LINE__);
    104. }
    105. vir_moderf = ioremap(LED_MODERF, 4);
    106. if (vir_rcc == NULL)
    107. {
    108. printk("物理映射失败%d\n", __LINE__);
    109. }
    110. vir_odre = ioremap(LED_ODRE, 4);
    111. if (vir_rcc == NULL)
    112. {
    113. printk("物理映射失败%d\n", __LINE__);
    114. }
    115. vir_odrf = ioremap(LED_ODRF, 4);
    116. if (vir_rcc == NULL)
    117. {
    118. printk("物理映射失败%d\n", __LINE__);
    119. }
    120. // rcc使能
    121. (*vir_rcc) |= (0x1 << 4);
    122. (*vir_rcc) |= (0x1 << 5);
    123. // moder设置输出模式
    124. // led1,PE10
    125. (*vir_modere) &= (~(0x3 << 20));
    126. (*vir_modere) |= (0x1 << 20);
    127. // led2PF10
    128. (*vir_moderf) &= (~(0x3 << 20));
    129. (*vir_moderf) |= (0x1 << 20);
    130. // led3,PE8
    131. (*vir_modere) &= (~(0x3 << 16));
    132. (*vir_modere) |= (0x1 << 16);
    133. // 设置默认为关灯
    134. (*vir_odre) &= (~(0x1 << 10));
    135. (*vir_odrf) &= (~(0x1 << 10));
    136. (*vir_odre) &= (~(0x1 << 8));
    137. return 0;
    138. }
    139. static int __init mycdev_init(void)
    140. {
    141. // 字符设备驱动注册
    142. /* major = register_chrdev(0,"mychrdev",&fops);
    143. if(major < 0)
    144. {
    145. printk("字符设备驱动注册失败\n");
    146. return major;
    147. }
    148. printk("字符设备驱动注册成功%d\n",major);
    149. */
    150. // 申请空间
    151. cdev = cdev_alloc();
    152. if (cdev == NULL)
    153. {
    154. printk("空间申请失败\n");
    155. ret = -EFAULT;
    156. goto out1;
    157. }
    158. printk("申请空间成功\n");
    159. // 字符设备初始化
    160. cdev_init(cdev, &fops);
    161. if (major > 0)
    162. {
    163. // 静态申请设备号
    164. ret = register_chrdev_region(MKDEV(major,minor), 3, "myled");
    165. if (ret)
    166. {
    167. printk("静态指定设备号失败\n");
    168. goto out2;
    169. }
    170. }
    171. else
    172. {
    173. // 动态申请设备号
    174. ret = alloc_chrdev_region(&devno, minor, 3, "myled");
    175. if (ret)
    176. {
    177. printk("动态申请设备号失败\n");
    178. // 释放空间
    179. goto out2;
    180. }
    181. // 获取主次设备号,因为静态动态申请不一样,在下面注册中要用到设备号
    182. major = MAJOR(devno); // 主设备号
    183. minor = MINOR(devno); // 次设备号
    184. }
    185. printk("申请设备号成功\n");
    186. // 注册驱动
    187. ret = cdev_add(cdev, MKDEV(major, minor), 3);
    188. if (ret)
    189. {
    190. printk("注册字符设备驱动对象\n");
    191. goto out3;
    192. }
    193. printk("注册字符设备驱动对象成功");
    194. // 进行映射
    195. led_init();
    196. // 向上提交目录信息
    197. cls = class_create(THIS_MODULE, "myled");
    198. if (IS_ERR(cls))
    199. {
    200. printk("向上提供目录\n");
    201. ret = -PTR_ERR(cls);
    202. goto out4;
    203. }
    204. printk("向上提交目录成功\n");
    205. //向上提交节点信息
    206. int i;
    207. for (i = 0; i < 3; i++)
    208. {
    209. dev = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i);
    210. if (IS_ERR(dev))
    211. {
    212. printk("向上提交设备节点信息失败\n");
    213. ret = -PTR_ERR(dev);
    214. goto out5;
    215. }
    216. printk("向上提交设备节点信息成功\n");
    217. }
    218. return 0;
    219. out5:
    220. for(--i;i>=0;i--)
    221. {
    222. device_destroy(cls, MKDEV(major, i));
    223. }
    224. class_destroy(cls);
    225. out4:
    226. cdev_del(cdev);
    227. out3:
    228. unregister_chrdev_region(MKDEV(major, minor), 3);
    229. out2:
    230. kfree(cdev);
    231. out1: return ret;
    232. }
    233. static void __exit mycdev_exit(void)
    234. {
    235. // unregister_chrdev(major,"mychrdev");
    236. int i;
    237. for(i=0;i<3;i++)
    238. {
    239. device_destroy(cls,MKDEV(major,i));
    240. }
    241. class_destroy(cls);
    242. cdev_del(cdev);
    243. unregister_chrdev_region(MKDEV(major,minor),3);
    244. kfree(cdev);
    245. iounmap(vir_rcc);
    246. iounmap(vir_modere);
    247. iounmap(vir_moderf);
    248. iounmap(vir_odre);
    249. iounmap(vir_odrf);
    250. }
    251. module_init(mycdev_init);
    252. module_exit(mycdev_exit);
    253. MODULE_LICENSE("GPL");

    头文件

    1. #ifndef __H__
    2. #define __H__
    3. #define LED_MODERE 0X50006000
    4. #define LED_MODERF 0X50007000
    5. #define LED_ODRE 0X50006014
    6. #define LED_ODRF 0X50007014
    7. #define LED_RCC 0X50000A28
    8. #define LED_ON _IO('l',1)
    9. #define LED_OF _IO('l',0)
    10. #endif

  • 相关阅读:
    【juc】countdownlatch实现并发网络请求
    100106. 元素和最小的山形三元组 I
    Babylonjs学习笔记(六)——贴图的使用
    精益求精:Android应用体积优化的终极指南
    可视化业务流程监控,是解决方案更是运维之道!
    Python循环控制
    前端技能树,面试复习—— 模拟题+真题系列(2): 单例模式 | 大文件上传 | SSR 原理 | 收集依赖 | HOOK 原理 | Worker 等等
    05【原型设计模式】
    发现一个舔狗神器,Python真的太厉害了,自动下载妹子视频...
    TCP的三次握手和四次挥手
  • 原文地址:https://blog.csdn.net/Kukuderener/article/details/132863881