• 驱动开发,IO模型之IO多路复用实现过程,select方式


    1.IO多路复用简介

            当在应用程序中同时实现对多个硬件数据读取时就需要用到IO多路复用。io多路复用有select/poll/epoll三种实现方式。如果进程同时监听的多个硬件数据都没有准备好,进程切换进入休眠状态,当一个或者多个硬件数据准备就绪后,休眠的进程被唤醒,读取准备好的硬件数据。

             本实验监听自定义事件和鼠标事件;

     

    2.代码

    ---pro1.c---应用程序(IO多路复用)
    1. #include <sys/types.h>
    2. #include <sys/stat.h>
    3. #include <fcntl.h>
    4. #include <stdio.h>
    5. #include <string.h>
    6. #include <unistd.h>
    7. #include <stdlib.h>
    8. #include <sys/ioctl.h>
    9. #include <sys/select.h>
    10. #include <sys/time.h>
    11. int main(int argc, const char *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. exit(-1);
    20. }
    21. fd2 = open("/dev/myled0", O_RDWR);
    22. if (fd2 < 0)
    23. {
    24. printf("自定义事件文件失败\n");
    25. exit(-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 = select(fd2+1,&readfds,NULL,NULL,NULL);
    38. if(ret < 0)
    39. {
    40. printf("select err\n");
    41. exit(-1);
    42. }
    43. //判断事件的发生
    44. if(FD_ISSET(fd1,&readfds))
    45. {
    46. read(fd1,buf,sizeof(buf));
    47. printf("鼠标事件发生%s\n",buf);
    48. memset(buf,0,sizeof(buf));
    49. }
    50. if(FD_ISSET(fd2,&readfds))
    51. {
    52. read(fd2,buf,sizeof(buf));
    53. printf("自定义设备事件发生%s\n",buf);
    54. memset(buf,0,sizeof(buf));
    55. }
    56. }
    57. close(fd1);
    58. close(fd2);
    59. return 0;
    60. }
    ---pro2.c---应用程序(模拟自定义设备数据就绪)
    1. #include <sys/types.h>
    2. #include <sys/stat.h>
    3. #include <fcntl.h>
    4. #include <stdio.h>
    5. #include <string.h>
    6. #include <unistd.h>
    7. #include <stdlib.h>
    8. int main(int argc, const char *argv[])
    9. {
    10. char buf[128] = "hello world";
    11. int fd = open("/dev/myled0", O_RDWR);
    12. if (fd < 0)
    13. {
    14. printf("打开设备文件失败\n");
    15. exit(-1);
    16. }
    17. write(fd, buf, sizeof(buf));
    18. close(fd);
    19. return 0;
    20. }
    ---mycdev.c---驱动程序
    1. #include <linux/init.h>
    2. #include <linux/module.h>
    3. #include <linux/fs.h>
    4. #include <linux/io.h>
    5. #include "head.h"
    6. #include <linux/device.h>
    7. #include <linux/uaccess.h>
    8. #include <linux/wait.h>
    9. #include<linux/poll.h>
    10. char kbuf[128] = {0};
    11. unsigned int major;
    12. struct class *cls;
    13. struct device *dev;
    14. unsigned int condition = 0;
    15. // 定义一个等待队列头
    16. wait_queue_head_t wq_head;
    17. // 封装操作方法
    18. int mycdev_open(struct inode *inode, struct file *file)
    19. {
    20. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    21. return 0;
    22. }
    23. ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
    24. {
    25. int ret;
    26. // 判断IO方式
    27. /* if (file->f_flags & O_NONBLOCK) // 非堵塞
    28. {
    29. }
    30. else
    31. {
    32. // 堵塞,先检查condition再将进程休眠
    33. wait_event_interruptible(wq_head, condition);
    34. }*/
    35. ret = copy_to_user(ubuf, kbuf, size);
    36. if (ret)
    37. {
    38. printk("copy_to_ user err\n");
    39. return -EIO;
    40. }
    41. condition = 0; // 下一次硬件数据没有就绪
    42. return 0;
    43. }
    44. ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
    45. {
    46. int ret;
    47. // 从用户拷贝数据,模拟硬件数据
    48. ret = copy_from_user(kbuf, ubuf, size);
    49. if (ret)
    50. {
    51. printk("copy_from_user err\n");
    52. return -EIO;
    53. }
    54. condition = 1;
    55. wake_up_interruptible(&wq_head);
    56. return 0;
    57. }
    58. //封装POLL方法
    59. __poll_t mycdev_poll(struct file *file, struct poll_table_struct *wait)
    60. {
    61. __poll_t mask = 0;
    62. //向上提交等待队列头
    63. poll_wait(file,&wq_head,wait);
    64. //根据事件是否发生给一个合适的返回值
    65. if(condition)
    66. {
    67. mask = POLLIN;
    68. }
    69. return mask;
    70. }
    71. int mycdev_close(struct inode *inode, struct file *file)
    72. {
    73. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    74. return 0;
    75. }
    76. struct file_operations fops = {
    77. .open = mycdev_open,
    78. .read = mycdev_read,
    79. .poll = mycdev_poll,
    80. .write = mycdev_write,
    81. .release = mycdev_close,
    82. };
    83. // 入口函数
    84. static int __init mycdev_init(void)
    85. {
    86. //初始化等待队列
    87. init_waitqueue_head(&wq_head);
    88. major = register_chrdev(0, "myled", &fops);
    89. if (major < 0)
    90. {
    91. printk("字符设备驱动注册失败\n");
    92. return major;
    93. }
    94. printk("字符设备驱动注册成功:major=%d\n", major);
    95. // 向上提交目录
    96. cls = class_create(THIS_MODULE, "MYLED");
    97. if (IS_ERR(cls))
    98. {
    99. printk("向上提交目录失败\n");
    100. return -PTR_ERR(cls);
    101. }
    102. printk("向上提交目录成功\n");
    103. // 向上提交设备节点信息
    104. int i;
    105. for (i = 0; i < 3; i++)
    106. {
    107. dev = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i);
    108. if (IS_ERR(dev))
    109. {
    110. printk("向上提交设备节点信息失败\n");
    111. return -PTR_ERR(dev);
    112. }
    113. }
    114. printk("向上提交设备节点信息成功\n");
    115. return 0;
    116. }
    117. // 出口函数
    118. static void __exit mycdev_exit(void)
    119. {
    120. // 销毁设备节点信息
    121. int i;
    122. for (i = 0; i < 3; i++)
    123. {
    124. device_destroy(cls, MKDEV(major, i));
    125. }
    126. // 销毁目录信息
    127. class_destroy(cls);
    128. // 字符设备驱动注销
    129. unregister_chrdev(major, "myled");
    130. }
    131. // 声明
    132. // 入口函数地址
    133. module_init(mycdev_init);
    134. // 出口函数地址
    135. module_exit(mycdev_exit);
    136. // 遵循的GPL协议
    137. MODULE_LICENSE("GPL");

    3.测试结果

            执行pro2.c,自定义事件被监听到;

            在ubuntu上动鼠标,鼠标事件被监听;

  • 相关阅读:
    Linux xfs文件系统stat命令Birth字段为空的原因探究
    网络面试-0x11 TCP为什么需要三次握手和四次挥手?
    【数据结构初阶】直接插入排序和希尔排序&链表排序
    含文档+PPT+源码等]精品微信小程序小说阅读器+后台管理系统|前后分离VUE[包运行成功]微信小程序项目源码Java毕业设计
    解决办法‘npm‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。
    遗传算法bp神经网络原理,bp神经网络和遗传算法
    KL散度
    Ubuntu文件操作(压缩与解压缩、用户组管理、权限)
    C#:实现BinaryInsertionSorter折半插入排序算法(附完整源码)
    GBase 8a 扩容操作意外的处理方案
  • 原文地址:https://blog.csdn.net/weixin_46260677/article/details/132889200