• 驱动开发--自动创建设备节点udev机制的实现过程


    一、udev的认识

    udev:自动创建设备节点的机制,创建设备节点的逻辑在用户空间

    二、udev机制创建设备节点的过程分析

    三、目录信息创建和删除类函数

    1. #include
    2. 1.向上提交目录信息
    3. struct class * class_create(struct module *owner,const char *name );
    4. 功能:申请一个设备类并初始化,向上提交目录信息
    5. 参数:
    6. 参数1:owner:指向当前内核模块自身的一个模块指针,填写THIS_MODULE
    7. 参数2:name:向上提交的目录名
    8. 返回值:成功返回申请的struct class对象空间首地址,失败返回错误码指针
    9. /*
    10. 在内核空间最顶层会预留4K空间,当struct class函数调用失败后函数会返回一个指向这4K空间的指针
    11. bool __must_check IS_ERR(__force const void *ptr)
    12. 功能:判断指针是否指向4K预留空间
    13. 参数:要判断的指针
    14. 返回值:如果指着指向4K预留空间返回逻辑真,否则返回逻辑假
    15. long __must_check PTR_ERR(__force const void *ptr)
    16. 功能:通过错误码指针得到错误码
    17. ex:struct class_create *cls=struct class_create(THIS_MODULE,"mycdev");
    18. if(IS_ERR(cls))
    19. {
    20. printk("向上提交目录失败\n");
    21. return -PRT_ERR(cls);
    22. }
    23. */
    24. 2.销毁目录
    25. void class_destroy(struct class *cls)
    26. 功能:销毁目录信息
    27. 参数:cls:指向class对象的指针
    28. 返回值:无

    四、节点信息创建和删除类函数

    1. 1.向上提交节点信息
    2. struct device *device_create(struct class *class, struct device *parent,
    3. dev_t devt, void *drvdata, const char *fmt, ...)
    4. 功能:创建一个设备对象,向上提交设备节点信息
    5. 参数:
    6. 参数1:cls:向上提交目录时的到的类对象指针
    7. 参数2:parent:当前申请的对象前一个节点的地址,不知道就填 NULL
    8. 参数3:devt:设备号 主设备号<<20|次设备号
    9. /*
    10. MKDEV(主设备号,次设备号):根据主设备号和次设备号得到设备号
    11. MAJOR(dev):根据设备号获取主设备号
    12. MINOR(dev):根据设备号获取次设备号
    13. */
    14. 参数4:dridata:申请的device对象的私有数据,填写NULL
    15. 参数5:fmt:向上提交的设备节点名
    16. ...:不定长参数
    17. 返回值:成功返回申请到的device对象首地址,失败返回错误码指针,指向4K预留空间
    18. 2.销毁设备节点信息
    19. void device_destroy(struct class *class, dev_t devt)
    20. 功能:销毁设备节点信息
    21. 参数:
    22. class:向上提交目录时得到的类对象指针
    23. devt:向上提交设备节点信息时提交的设备号
    24. 返回值:无

    五、自动创建设备节点实例

    1.驱动程序

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include"head.h"
    7. int major;
    8. char kbuf[128]={0};
    9. gpio_t *vir_led1;
    10. gpio_t *vir_led2;
    11. gpio_t *vir_led3;
    12. unsigned int *vir_rcc;
    13. struct class *cls;
    14. struct device *dev;
    15. int mycdev_open(struct inode *inode, struct file *file)
    16. {
    17. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    18. return 0;
    19. }
    20. ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
    21. {
    22. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    23. unsigned long ret;
    24. //向用户空间读取拷贝
    25. if(size>sizeof(kbuf))//用户空间期待读取的大小内核满足不了,那就给内核支持的最大大小
    26. size=sizeof(kbuf);
    27. ret=copy_to_user(ubuf,kbuf,size);
    28. if(ret)//拷贝失败
    29. {
    30. printk("copy_to_user filed\n");
    31. return ret;
    32. }
    33. return 0;
    34. }
    35. ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
    36. {
    37. unsigned long ret;
    38. //从用户空间读取数据
    39. if(size>sizeof(kbuf))//用户空间期待读取的大小内核满足不了,那就给内核支持的最大大小
    40. size=sizeof(kbuf);
    41. ret=copy_from_user(kbuf,ubuf,size);
    42. if(ret)//拷贝失败
    43. {
    44. printk("copy_to_user filed\n");
    45. return ret;
    46. }
    47. switch(kbuf[0]){
    48. case '1'://LED1
    49. if(kbuf[1]=='0')//关灯
    50. vir_led1->ODR &= (~(1<<10));
    51. else//开灯
    52. vir_led1->ODR |= 1<<10;
    53. break;
    54. case '2'://LED2
    55. if(kbuf[1]=='0')//关灯
    56. vir_led2->ODR &= (~(1<<10));
    57. else//开灯
    58. vir_led2->ODR |= 1<<10;
    59. break;
    60. case '3'://LED3
    61. if(kbuf[1]=='0')//关灯
    62. vir_led3->ODR &= (~(1<<8));
    63. else//开灯
    64. vir_led3->ODR |= 1<<8;
    65. break;
    66. }
    67. return 0;
    68. }
    69. int mycdev_close(struct inode *inode, struct file *file)
    70. {
    71. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    72. return 0;
    73. }
    74. //定义操作方法结构体变量并赋值
    75. struct file_operations fops={
    76. .open=mycdev_open,
    77. .read=mycdev_read,
    78. .write=mycdev_write,
    79. .release=mycdev_close,
    80. };
    81. int all_led_init(void)
    82. {
    83. //寄存器地址的映射
    84. vir_led1=ioremap(PHY_LED1_ADDR,sizeof(gpio_t));
    85. if(vir_led1==NULL)
    86. {
    87. printk("ioremap filed:%d\n",__LINE__);
    88. return -ENOMEM;
    89. }
    90. vir_led2=ioremap(PHY_LED2_ADDR,sizeof(gpio_t));
    91. if(vir_led2==NULL)
    92. {
    93. printk("ioremap filed:%d\n",__LINE__);
    94. return -ENOMEM;
    95. }
    96. vir_led3=vir_led1;
    97. vir_rcc=ioremap(PHY_RCC_ADDR,4);
    98. if(vir_rcc==NULL)
    99. {
    100. printk("ioremap filed:%d\n",__LINE__);
    101. return -ENOMEM;
    102. }
    103. printk("物理地址映射成功\n");
    104. //寄存器的初始化
    105. //rcc
    106. (*vir_rcc) |= (0X3<<4);
    107. //led1
    108. vir_led1->MODER &= (~(3<<20));
    109. vir_led1->MODER |= (1<<20);
    110. vir_led1->ODR &= (~(1<<10));
    111. //led2
    112. vir_led2->MODER &= (~(3<<20));
    113. vir_led2->MODER |= (1<<20);
    114. vir_led2->ODR &= (~(1<<10));
    115. //led3
    116. vir_led3->MODER &= (~(3<<16));
    117. vir_led1->MODER |= (1<<16);
    118. vir_led1->ODR &= (~(1<<8));
    119. printk("寄存器初始化成功\n");
    120. return 0;
    121. }
    122. static int __init mycdev_init(void)
    123. {
    124. //字符设备驱动注册
    125. major=register_chrdev(0,"mychrdev",&fops);
    126. if(major<0)
    127. {
    128. printk("字符设备驱动注册失败\n");
    129. return major;
    130. }
    131. printk("字符设备驱动注册成功:major=%d\n",major);
    132. //寄存器映射以及初始化
    133. all_led_init();
    134. //向上提交目录
    135. cls=class_create(THIS_MODULE,"mychrdev");
    136. if(IS_ERR(cls))
    137. {
    138. printk("向上提交目录失败\n");
    139. return -PTR_ERR(cls);
    140. }
    141. printk("向上提交目录成功\n");
    142. //向上提交设备节点信息
    143. int i;
    144. for(i=0;i<3;i++)
    145. {
    146. dev=device_create(cls,NULL,MKDEV(major,i),NULL,"mychrdev%d",i);
    147. if(IS_ERR(dev))
    148. {
    149. printk("向上提交设备节点信息失败\n");
    150. return -PTR_ERR(dev);
    151. }
    152. }
    153. printk("向上提交设备节点信息成功\n");
    154. return 0;
    155. }
    156. static void __exit mycdev_exit(void)
    157. {
    158. /*销毁设备节点信息*/
    159. int i;
    160. for(i=0;i<3;i++)
    161. {
    162. device_destroy(cls,MKDEV(major,i));
    163. }
    164. //销毁目录信息
    165. class_destroy(cls);
    166. //取消地址映射
    167. iounmap(vir_led1);
    168. iounmap(vir_led2);
    169. iounmap(vir_rcc);
    170. //注销字符设备驱动
    171. unregister_chrdev(major,"mychrdev");
    172. }
    173. module_init(mycdev_init);
    174. module_exit(mycdev_exit);
    175. MODULE_LICENSE("GPL");

    2.应用程序

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. int main(int argc, char const *argv[])
    9. {
    10. char buf[128]={0};
    11. int fd=open("/dev/mychrdev0",O_RDWR);
    12. if(fd<0)
    13. {
    14. printf("打开设备文件失败\n");
    15. exit(-1);
    16. }
    17. while(1)
    18. {
    19. //从终端读取
    20. printf("请输入两个字符\n");
    21. printf("第一个字符:1(LED1) 2(LED2) 3(LED3)\n");
    22. printf("第二个字符:0(关灯) 1(开灯)\n");
    23. printf("请输入>");
    24. fgets(buf,sizeof(buf),stdin);
    25. buf[strlen(buf)-1]='\0';
    26. //向设备文件中写
    27. write(fd,buf,sizeof(buf));
    28. }
    29. close(fd);
    30. return 0;
    31. }

    3.头文件

    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. #endif

  • 相关阅读:
    Intel 7工艺的极限!酷睿i9-14900K/i7-14700K首发评测:6GHz单核性能无敌
    int指令
    Android之App跳转其他软件
    北京化工大学数据结构2022/12/1作业 题解
    自定义数据训练的rknn模型部署 踩坑记录
    同花顺_代码解析_五彩K线
    bgp链路聚合配置与详解
    金仓数据库KingbaseES客户端应用参考手册--7. sys_basebackup
    C++ Primer 类与构造函数 三五法则
    C++多态 万字详解
  • 原文地址:https://blog.csdn.net/m0_62774039/article/details/132838576