• IO多路复用(select模型实现监控两个设备:自定义设备和鼠标设备)


    1、驱动程序

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. struct cdev *cdev;
    12. char kbuf[128]={0};
    13. unsigned int major=0;
    14. unsigned int minor=0;
    15. dev_t devno;
    16. module_param(major,uint,0664);//方便在命令行传递major的值
    17. struct class*cls;
    18. struct device *dev;
    19. unsigned int condition=0;
    20. //定义一个等待队列头
    21. wait_queue_head_t wq_head;
    22. // 封装操作方法
    23. int mycdev_open(struct inode *inode, struct file *file)
    24. {
    25. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    26. return 0;
    27. }
    28. ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
    29. {
    30. unsigned long ret;
    31. if (size > sizeof(kbuf)) // 用户空间期待读取的大小内核满足不了,那就给内核支持的最大大小
    32. size = sizeof(kbuf);
    33. if(file->f_flags&O_NONBLOCK)//非阻塞IO
    34. {}
    35. else{
    36. //wait_event_interruptible(wq_head,condition);
    37. }
    38. ret = copy_to_user(ubuf, kbuf, size);
    39. if (ret)
    40. {
    41. printk("copy_to_user err\n");
    42. return -EIO;
    43. }
    44. condition=0;
    45. return 0;
    46. }
    47. ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
    48. {
    49. unsigned long ret;
    50. if (size > sizeof(kbuf)) // 用户空间期待读取的大小内核满足不了,那就给内核支持的最大大小
    51. size = sizeof(kbuf);
    52. ret = copy_from_user(kbuf, ubuf, size);
    53. if (ret)
    54. {
    55. printk("copy_from_user err\n");
    56. return -EIO;
    57. }
    58. condition=1;
    59. wake_up_interruptible(&wq_head);
    60. return 0;
    61. }
    62. int mycdev_close(struct inode *inode, struct file *file)
    63. {
    64. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    65. return 0;
    66. }
    67. //封装POLL方法
    68. __poll_t mycdev_poll(struct file *file,struct poll_table_struct *wait)
    69. {
    70. __poll_t mask=0;
    71. //向上提交等待队列头
    72. poll_wait(file,&wq_head,wait);
    73. //根据事件是否发生给一个合适的返回值
    74. if(condition)
    75. {
    76. mask=POLLIN;
    77. }
    78. return mask;
    79. }
    80. struct file_operations fops = {
    81. .open = mycdev_open,
    82. .read = mycdev_read,
    83. .write = mycdev_write,
    84. .poll = mycdev_poll,
    85. .release = mycdev_close,
    86. };
    87. static int __init mycdev_init(void)
    88. {
    89. init_waitqueue_head(&wq_head);
    90. int ret;
    91. //为字符设备驱动对象申请空间
    92. cdev=cdev_alloc();
    93. if(cdev==NULL)
    94. {
    95. printk("字符设备驱动对象申请空间失败\n");
    96. ret=-EFAULT;
    97. goto out1;
    98. }
    99. printk("申请对象空间成功\n");
    100. //初始化字符设备驱动对象
    101. cdev_init(cdev,&fops);
    102. //申请设备号
    103. if(major>0)//静态指定设备号
    104. {
    105. ret=register_chrdev_region(MKDEV(major,minor),3,"myled");
    106. if(ret)
    107. {
    108. printk("静态申请设备号失败\n");
    109. goto out2;
    110. }
    111. }
    112. else if(major==0)//动态申请设备号
    113. {
    114. ret=alloc_chrdev_region(&devno,minor,3,"myled");
    115. if(ret)
    116. {
    117. printk("动态申请设备号失败\n");
    118. goto out2;
    119. }
    120. major=MAJOR(devno);//获取主设备号
    121. minor=MINOR(devno);//获取次设备号
    122. }
    123. printk("申请设备号成功\n");
    124. //注册字符设备驱动对象
    125. ret=cdev_add(cdev,MKDEV(major,minor),3);
    126. if(ret)
    127. {
    128. printk("注册字符设备驱动对象失败\n");
    129. goto out3;
    130. }
    131. printk("注册字符设备驱动对象成功\n");
    132. //向上提交目录信息
    133. cls=class_create(THIS_MODULE,"myled");
    134. if(IS_ERR(cls))
    135. {
    136. printk("向上提交目录失败\n");
    137. ret=-PTR_ERR(cls);
    138. goto out4;
    139. }
    140. printk("向上提交目录成功\n");
    141. //向上提交设备节点信息
    142. int i;
    143. for(i=0;i<3;i++)
    144. {
    145. dev=device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);
    146. if(IS_ERR(dev))
    147. {
    148. printk("向上提交设备节点信息失败\n");
    149. ret=-PTR_ERR(dev);
    150. goto out5;
    151. }
    152. }
    153. printk("向上提交设备信息成功\n");
    154. return 0;
    155. out5:
    156. //释放前一次提交成功的设备信息
    157. for(--i;i>=0;i--)
    158. {
    159. device_destroy(cls,MKDEV(major,i));
    160. }
    161. class_destroy(cls);//释放目录
    162. out4:
    163. cdev_del(cdev);
    164. out3:
    165. unregister_chrdev_region(MKDEV(major,minor),3);
    166. out2:
    167. kfree(cdev);
    168. out1:
    169. return ret;
    170. }
    171. static void __exit mycdev_exit(void)
    172. { //取消地址映射
    173. //注销字符设备驱动
    174. //释放节点信息
    175. int i;
    176. for(i=0;i<3;i++)
    177. {
    178. device_destroy(cls,MKDEV(major,i));
    179. }
    180. //销毁目录
    181. class_destroy(cls);
    182. //注销驱动对象
    183. cdev_del(cdev);
    184. //释放设备号
    185. unregister_chrdev_region(MKDEV(major,minor),3);
    186. //释放对象空间
    187. kfree(cdev);
    188. }
    189. module_init(mycdev_init);
    190. module_exit(mycdev_exit);
    191. MODULE_LICENSE("GPL");

    2、测试程序鼠标设备事件

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

     3、自定义事件设备

    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 fd = open("/dev/myled0", O_RDWR);
    13. if (fd < 0)
    14. {
    15. printf("打开设备文件失败\n");
    16. exit(-1);
    17. }
    18. write(fd,buf,sizeof(buf));
    19. close(fd);
    20. return 0;
    21. }

     4测试结果

  • 相关阅读:
    视频集中存储EasyCVR平台播放一段时间后出现黑屏是什么原因?该如何解决?
    8. Go的函数
    pytorch 入门 (三)案例一:mnist手写数字识别
    HarmonyOS NEXT中怎么理解HAR、HAP、HSP、App的关系
    sqli-labs/Less-53
    如何使用数组——javascript
    传奇开服教程GOM传奇引擎外网全套架设教程
    Mysql与GoldenDB中如何利用sql脚本添加字段和数据表名的备注
    [附源码]SSM计算机毕业设计中学学生学籍管理JAVA
    【C#】rdlc报表答应报错:未能加载文件或程序集“Microsoft.SqlServer.Types
  • 原文地址:https://blog.csdn.net/weixin_60039521/article/details/132889563