• 驱动开发5 阻塞IO实例、IO多路复用


    1 阻塞IO

    进程1

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. int main(int argc, char const *argv[])
    10. {
    11. char buf[128] = {0};
    12. int a,b;
    13. int fd = open("/dev/myled0",O_RDWR);
    14. if(fd < 0)
    15. {
    16. printf("打开设备文件失败\n");
    17. exit(-1);
    18. }
    19. while(1)
    20. {
    21. memset(buf,0,sizeof(buf));
    22. read(fd,buf,sizeof(buf));
    23. printf("buf:%s\n",buf);
    24. }
    25. }

    进程2

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. int main(int argc, char const *argv[])
    10. {
    11. char buf[128] = "hello world";
    12. int a,b;
    13. int fd = open("/dev/myled0",O_RDWR);
    14. if(fd < 0)
    15. {
    16. printf("打开设备文件失败\n");
    17. exit(-1);
    18. }
    19. write(fd,buf,sizeof(buf));
    20. }

    驱动程序

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. int major;
    9. char kbuf[128] = {0};
    10. unsigned int *vir_rcc;
    11. struct class *cls;
    12. struct device *dev;
    13. //定义等待队列
    14. wait_queue_head_t wq_head;
    15. unsigned int condition=0;
    16. int mycdev_open(struct inode *inode, struct file *file)
    17. {
    18. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    19. return 0;
    20. }
    21. ssize_t mycdev_read(struct file *file, char *ubuf, size_t size,loff_t *lof)
    22. {
    23. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    24. if(file->f_flags&O_NONBLOCK)//用户程序以非阻塞读写数据
    25. {}
    26. else{
    27. wait_event_interruptible(wq_head,condition);//判断condition的值,为假则进程休眠
    28. }
    29. //将获取到的硬件数据拷贝到用户
    30. int ret = copy_to_user(ubuf,kbuf,size);
    31. if(ret)
    32. {
    33. printk("copy_to_user filed\n");
    34. return -EIO;
    35. }
    36. condition = 0; //表示下一次数据没有准备就绪
    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. int ret;
    43. ret = copy_from_user(kbuf,ubuf,size);
    44. if (ret)
    45. {
    46. printk("copy_from_user filed\n");
    47. return -EIO;
    48. }
    49. condition = 1;//表示硬件数据就绪
    50. wake_up_interruptible(&wq_head);//唤醒休眠的进程
    51. return 0;
    52. }
    53. int mycdev_close(struct inode *inode, struct file *file)
    54. {
    55. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    56. return 0;
    57. }
    58. //定义操作方法结构体变量并赋值
    59. struct file_operations fops={
    60. .open = mycdev_open,
    61. .read = mycdev_read,
    62. .write = mycdev_write,
    63. .release = mycdev_close,
    64. };
    65. static int __init mycdev_init(void)
    66. {
    67. //初始化等待队列
    68. init_waitqueue_head(&wq_head);
    69. //字符设备驱动
    70. major = register_chrdev(0,"mychrdev",&fops);
    71. if(major < 0)
    72. {
    73. printk("字符设备驱动注册失败\n");
    74. return major;
    75. }
    76. printk("字符设备驱动注册成功:major=%d\n",major);
    77. //向上提交目录 class_create
    78. cls = class_create(THIS_MODULE,"mychrdev");
    79. if(IS_ERR(cls))
    80. {
    81. printk("向上提交目录失败\n");
    82. return -PTR_ERR(cls);
    83. }
    84. printk("向上提交目录成功\n");
    85. //向上提交设备节点信息 device_create
    86. int i;
    87. for(i=0;i<3;i++)
    88. {
    89. dev = device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);
    90. if(IS_ERR(dev))
    91. {
    92. printk("向上提交设备节点失败\n");
    93. return -PTR_ERR(dev);
    94. }
    95. }
    96. printk("向上提交设备节点信息成功\n");
    97. return 0;
    98. }
    99. static void __exit mycdev_exit(void)
    100. {
    101. //1.销毁设备节点信息
    102. int i;
    103. for(i=0;i<3;i++)
    104. {
    105. device_destroy(cls,MKDEV(major,i));
    106. }
    107. //2.销毁目录
    108. class_destroy(cls);
    109. //3.注销字符设备驱动
    110. unregister_chrdev(major,"mychrdev");
    111. }
    112. module_init(mycdev_init);
    113. module_exit(mycdev_exit);
    114. MODULE_LICENSE("GPL");

    Makefile

    1. modname ?= demo
    2. arch ?= arm
    3. ifeq ($(arch),arm) #通过命令行传过来的架构决定怎么编译
    4. #KERBELDIR保存开发板内核源码路径
    5. KERNELDIR := /home/ubuntu/FSMP1A/linux-stm32mp-5.10.61-stm32mp-r2-r0/linux-5.10.61
    6. else
    7. #保存UBUNTU内核源码路径
    8. KERNELDIR := /lib/modules/$(shell uname -r)/build
    9. endif
    10. #PWD保存当前内核模块的路径
    11. PWD := $(shell pwd)
    12. all:
    13. #make modules是模块化编译命令
    14. #make -C $(KERNLEDIR) 执行make之前先切换到KERNELDIR对应的路径
    15. #M=$(PWD)表示进行模块化编译的路径是PWD保存的路径
    16. make -C $(KERNELDIR) M=$(PWD) modules
    17. clean:
    18. #编译清除
    19. make -C $(KERNELDIR) M=$(PWD) clean
    20. #将obj-m保存的文件单独链接为内核模块
    21. obj-m := $(modname).o

    效果演示

    2 IO多路复用

    驱动程序

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. int major;
    10. char kbuf[128] = {0};
    11. unsigned int *vir_rcc;
    12. struct class *cls;
    13. struct device *dev;
    14. //定义等待队列
    15. wait_queue_head_t wq_head;
    16. unsigned int condition=0;
    17. int mycdev_open(struct inode *inode, struct file *file)
    18. {
    19. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    20. return 0;
    21. }
    22. ssize_t mycdev_read(struct file *file, char *ubuf, size_t size,loff_t *lof)
    23. {
    24. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    25. if(file->f_flags&O_NONBLOCK)//用户程序以非阻塞读写数据
    26. {}
    27. else{
    28. // wait_event_interruptible(wq_head,condition);//判断condition的值,为假则进程休眠
    29. }
    30. //将获取到的硬件数据拷贝到用户
    31. int ret = copy_to_user(ubuf,kbuf,size);
    32. if(ret)
    33. {
    34. printk("copy_to_user filed\n");
    35. return -EIO;
    36. }
    37. condition = 0; //表示下一次数据没有准备就绪
    38. return 0;
    39. }
    40. __poll_t mycdev_poll(struct file *file, struct poll_table_struct *wait)
    41. {
    42. __poll_t mask = 0;
    43. // 向上提交等待队列队头
    44. poll_wait(file, &wq_head, wait);
    45. // 根据数据是否就绪给定一个合适的返回值
    46. if (condition)
    47. mask = POLLIN;
    48. return mask;
    49. }
    50. ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size,loff_t *lof)
    51. {
    52. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    53. int ret = copy_from_user(kbuf,ubuf,size);
    54. if (ret)
    55. {
    56. printk("copy_from_user filed\n");
    57. return -EIO;
    58. }
    59. condition = 1;//表示硬件数据就绪
    60. wake_up_interruptible(&wq_head);//唤醒休眠的进程
    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. .read = mycdev_read,
    72. .write = mycdev_write,
    73. .poll = mycdev_poll,
    74. .release = mycdev_close,
    75. };
    76. static int __init mycdev_init(void)
    77. {
    78. //初始化等待队列
    79. init_waitqueue_head(&wq_head);
    80. //字符设备驱动
    81. major = register_chrdev(0,"mychrdev",&fops);
    82. if(major < 0)
    83. {
    84. printk("字符设备驱动注册失败\n");
    85. return major;
    86. }
    87. printk("字符设备驱动注册成功:major=%d\n",major);
    88. //向上提交目录 class_create
    89. cls = class_create(THIS_MODULE,"mychrdev");
    90. if(IS_ERR(cls))
    91. {
    92. printk("向上提交目录失败\n");
    93. return -PTR_ERR(cls);
    94. }
    95. printk("向上提交目录成功\n");
    96. //向上提交设备节点信息 device_create
    97. int i;
    98. for(i=0;i<3;i++)
    99. {
    100. dev = device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);
    101. if(IS_ERR(dev))
    102. {
    103. printk("向上提交设备节点失败\n");
    104. return -PTR_ERR(dev);
    105. }
    106. }
    107. printk("向上提交设备节点信息成功\n");
    108. return 0;
    109. }
    110. static void __exit mycdev_exit(void)
    111. {
    112. //1.销毁设备节点信息
    113. int i;
    114. for(i=0;i<3;i++)
    115. {
    116. device_destroy(cls,MKDEV(major,i));
    117. }
    118. //2.销毁目录
    119. class_destroy(cls);
    120. //3.注销字符设备驱动
    121. unregister_chrdev(major,"mychrdev");
    122. }
    123. module_init(mycdev_init);
    124. module_exit(mycdev_exit);
    125. MODULE_LICENSE("GPL");

    进程1:监听多个事件

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. int main(int argc, char const *argv[])
    12. {
    13. char buf[128] = {0};
    14. int fd1,fd2;
    15. fd1 = open("/dev/input/mouse0",O_RDWR);
    16. if(fd1 < 0)
    17. {
    18. printf("打开鼠标设备失败\n");
    19. return -1;
    20. }
    21. fd2 = open("/dev/myled0",O_RDWR);
    22. if(fd2 < 0)
    23. {
    24. printf("打开设备失败\n");
    25. return -1;
    26. }
    27. // 定义读事件集合
    28. fd_set readfds;
    29. while(1)
    30. {
    31. // 清空集合
    32. FD_ZERO(&readfds);
    33. // 将要监听的事件添加进集合
    34. FD_SET(fd1, &readfds);
    35. FD_SET(fd2, &readfds);
    36. // 阻塞监听事件
    37. int ret;
    38. ret = select(fd2 + 1, &readfds, NULL, NULL, NULL);
    39. if(ret < 0)
    40. {
    41. printf("select 调用失败\n");
    42. return -1;
    43. }
    44. // 判断事件是否发生
    45. if(FD_ISSET(fd1, &readfds));
    46. {
    47. memset(buf, 0, sizeof(buf));
    48. read(fd1, buf, sizeof(buf));
    49. printf("鼠标事件发生buf:%s\n", buf);
    50. }
    51. if(FD_ISSET(fd2, &readfds))
    52. {
    53. memset(buf,0,sizeof(buf));
    54. read(fd2,buf,sizeof(buf));
    55. printf("事件发生buf:%s\n",buf);
    56. }
    57. }
    58. // 关闭文件描述符
    59. close(fd1);
    60. close(fd2);
    61. return 0;
    62. }

    进程2:模拟自定义事件就绪

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. int main(int argc, char const *argv[])
    10. {
    11. char buf[128] = "hello world";
    12. int a,b;
    13. int fd = open("/dev/myled0",O_RDWR);
    14. if(fd < 0)
    15. {
    16. printf("打开设备文件失败\n");
    17. exit(-1);
    18. }
    19. write(fd,buf,sizeof(buf));
    20. }

    效果演示

  • 相关阅读:
    python调用c++版本dll06-返回数组结构体
    C++ 强制类型转换(int double)、查看数据类型、自动决定类型、三元表达式、取反、
    sdkman 安装以及 graalvm安装
    司徒理财:黄金今日多空走势预测!原油最新操作建议
    echarts图表配置
    大学生面试JAVA程序员应该具备的JAVA面试题库
    [ruby on rails]rails6.0升级6.1
    java 数据脱敏
    数据结构与算法之图: Leetcode 417. 太平洋大西洋水流问题 (Typescript版)
    网络编程及套接字
  • 原文地址:https://blog.csdn.net/Smallxu_/article/details/134016483