• linux驱动开发---day3(自启动创建设备节点进行点灯实验、ioctl函数实现点灯实验)


    自动创建设备节点udev机制的实现过程

    1. udev是自动创建设备节点,逻辑在用户空间
    2. 过程:1)首先注册字符设备驱动,得到标识设备的设备号
                 2)获得设备信息后,先创建一个设备类,向上提交目录信息,使用class_create
                 3)然后创建设备对象,向上提交设备节点信息,使用device_create
                 4)在向上提交设备节点信息后,会自动发起热插拔事件通知udev进程去查询设备节点的信息,以及在/dev下创建设备节点

    自动创建设备节点:(led点灯)

    my_led.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. 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) |= (3<<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");
    test.c
    1. #include<stdlib.h>
    2. #include<stdio.h>
    3. #include <sys/types.h>
    4. #include <sys/stat.h>
    5. #include <fcntl.h>
    6. #include<unistd.h>
    7. #include<string.h>
    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. }
    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. #endif
    测试过程:

    make arch=arm modname=my_led

    cp my_led.ko ~/nfs/rootfs/

    arm-linux-gnueabihf-gcc test.c 

     cp a.out ~/nfs/rootfs/

    ---------------------------------------------------------------------------------------------------------------------------------

    insmod my_led.ko---------->./a.out

    通过ls -l /dev/mychrdev*指令查看创建的设备文件

    rmmod my_led

    测试现象:

    ioctl函数实现点灯实验---添加第三个参数(第三个参数为指针)

    myled.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. 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. long mydev_ioctl(struct file* file,unsigned int cmd,unsigned long arg)
    21. {
    22. int which;
    23. //获取arg对应用户空间中的值
    24. int ret=copy_from_user(&which,(void *)arg,4);
    25. if(ret)
    26. {
    27. printk("从用户空间获取数据失败\n");
    28. return -EIO;
    29. }
    30. switch(cmd)
    31. {
    32. case LED_ON://开灯
    33. switch(which)
    34. {
    35. case 1:
    36. vir_led1->ODR |= 1<<10;
    37. break;
    38. case 2:
    39. vir_led2->ODR |= 1<<10;
    40. break;
    41. case 3:
    42. vir_led3->ODR |= 1<<8;
    43. break;
    44. }
    45. break;
    46. case LED_OFF: //关灯
    47. switch(which)
    48. {
    49. case 1:
    50. vir_led1->ODR &= (~(1<<10));
    51. break;
    52. case 2:
    53. vir_led2->ODR &= (~(1<<10));
    54. break;
    55. case 3:
    56. vir_led3->ODR &= (~(1<<8));
    57. break;
    58. }
    59. break;
    60. }
    61. return 0;
    62. }
    63. int mycdev_close(struct inode *inode, struct file *file)
    64. {
    65. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    66. return 0;
    67. }
    68. //定义操作方法结构体变量并赋值
    69. struct file_operations fops={
    70. .open=mycdev_open,
    71. .unlocked_ioctl=mydev_ioctl,
    72. .release=mycdev_close,
    73. };
    74. int all_led_init(void)
    75. {
    76. //寄存器地址的映射
    77. vir_led1=ioremap(PHY_LED1_ADDR,sizeof(gpio_t));
    78. if(vir_led1==NULL)
    79. {
    80. printk("ioremap filed:%d\n",__LINE__);
    81. return -ENOMEM;
    82. }
    83. vir_led2=ioremap(PHY_LED2_ADDR,sizeof(gpio_t));
    84. if(vir_led2==NULL)
    85. {
    86. printk("ioremap filed:%d\n",__LINE__);
    87. return -ENOMEM;
    88. }
    89. vir_led3=vir_led1;
    90. vir_rcc=ioremap(PHY_RCC_ADDR,4);
    91. if(vir_rcc==NULL)
    92. {
    93. printk("ioremap filed:%d\n",__LINE__);
    94. return -ENOMEM;
    95. }
    96. printk("物理地址映射成功\n");
    97. //寄存器的初始化
    98. //rcc
    99. (*vir_rcc) |= (3<<4);
    100. //led1
    101. vir_led1->MODER &= (~(3<<20));
    102. vir_led1->MODER |= (1<<20);
    103. vir_led1->ODR &= (~(1<<10));
    104. //led2
    105. vir_led2->MODER &= (~(3<<20));
    106. vir_led2->MODER |= (1<<20);
    107. vir_led2->ODR &= (~(1<<10));
    108. //led3
    109. vir_led3->MODER &= (~(3<<16));
    110. vir_led1->MODER |= (1<<16);
    111. vir_led1->ODR &= (~(1<<8));
    112. printk("寄存器初始化成功\n");
    113. return 0;
    114. }
    115. static int __init mycdev_init(void)
    116. {
    117. //字符设备驱动注册
    118. major=register_chrdev(0,"mychrdev",&fops);
    119. if(major<0)
    120. {
    121. printk("字符设备驱动注册失败\n");
    122. return major;
    123. }
    124. printk("字符设备驱动注册成功:major=%d\n",major);
    125. //寄存器映射以及初始化
    126. all_led_init();
    127. //向上提交目录
    128. cls=class_create(THIS_MODULE,"mychrdev");
    129. if(IS_ERR(cls))
    130. {
    131. printk("向上提交目录失败\n");
    132. return -PTR_ERR(cls);
    133. }
    134. printk("向上提交目录成功\n");
    135. //向上提交设备节点信息
    136. int i;
    137. for(i=0;i<3;i++)
    138. {
    139. dev=device_create(cls,NULL,MKDEV(major,i),NULL,"mychrdev%d",i);
    140. if(IS_ERR(dev))
    141. {
    142. printk("向上提交设备节点信息失败\n");
    143. return -PTR_ERR(dev);
    144. }
    145. }
    146. printk("向上提交设备节点信息成功\n");
    147. return 0;
    148. }
    149. static void __exit mycdev_exit(void)
    150. {
    151. //销毁设备节点信息
    152. int i;
    153. for(i=0;i<3;i++)
    154. {
    155. device_destroy(cls,MKDEV(major,i));
    156. }
    157. //销毁目录信息
    158. class_destroy(cls);
    159. //取消地址映射
    160. iounmap(vir_led1);
    161. iounmap(vir_led2);
    162. iounmap(vir_rcc);
    163. //注销字符设备驱动
    164. unregister_chrdev(major,"mychrdev");
    165. }
    166. module_init(mycdev_init);
    167. module_exit(mycdev_exit);
    168. MODULE_LICENSE("GPL");
    test.c:
    1. #include<stdlib.h>
    2. #include<stdio.h>
    3. #include <sys/types.h>
    4. #include <sys/stat.h>
    5. #include <fcntl.h>
    6. #include<unistd.h>
    7. #include<string.h>
    8. #include<sys/ioctl.h>
    9. #include"head.h"
    10. int main(int argc, char const *argv[])
    11. {
    12. int a,b;
    13. char buf[128]={0};
    14. int fd=open("/dev/mychrdev0",O_RDWR);
    15. if(fd<0)
    16. {
    17. printf("打开设备文件失败\n");
    18. exit(-1);
    19. }
    20. while(1)
    21. {
    22. //从终端读取
    23. printf("请输入对LED灯的控制:0(关灯) 1(开灯)\n");
    24. scanf("%d",&a);
    25. printf("请输入要控制的灯:1(LED1) 2(LED2) 3(LED3)\n");
    26. scanf("%d",&b);
    27. switch(a)
    28. {
    29. case 1:
    30. ioctl(fd,LED_ON,&b);//开灯
    31. break;
    32. case 0:
    33. ioctl(fd,LED_ON,&b);//关灯
    34. break;
    35. }
    36. }
    37. close(fd);
    38. return 0;
    39. }
    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第三个参数
    16. #define LED_ON _IOW('l',1,int)
    17. #define LED_OFF _IOW('l',0,int)
    18. #endif
    测试步骤同上,以下为现象:

  • 相关阅读:
    SpingBoot快速入门下
    前端监控 SDK 开发分享
    【面向对象】理解面向对象编程中的封装性
    自动驾驶——仿真的几大挑战
    wireshark使用
    12.5 Hierarchical names (层次化名称)
    元代理模型可迁移对抗攻击
    【C语言刷LeetCode】面试题 10.09. 排序矩阵查找(M)
    webpack配置之source-map的使用
    阿里架构师:让Spring不再复杂
  • 原文地址:https://blog.csdn.net/m0_72852022/article/details/132830880