因为最终要在tiny210上实现此功能,最终选择了hotplug。

http://hi.baidu.com/hdy5200075/item/7751f48647f3d12a100ef3f6这里是hotplug检测U盘的源码,我在qt里将其写到一个hostplug.h文件里。

[cpp]  view plain copy print ?
  1. #ifndef HOSTPLUG_H
  2. #define HOSTPLUG_H
  3. #include <iostream>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <ctype.h>
  8. #include <sys/un.h>
  9. #include <sys/ioctl.h>
  10. #include <sys/socket.h>
  11. #include <linux/types.h>
  12. #include <linux/netlink.h>
  13. #include <errno.h>
  14. #include <fcntl.h>
  15. static int init_hotplug_sock(void)
  16. {
  17. struct sockaddr_nl snl;
  18. const int buffersize = 16 * 1024 * 1024;
  19. int retval;
  20. memset(&snl, 0x00, sizeof(struct sockaddr_nl));
  21. snl.nl_family = AF_NETLINK;
  22. snl.nl_pid = getpid();
  23. snl.nl_groups = 1;
  24. int hotplug_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
  25. if(hotplug_sock == -1)
  26. {
  27. printf("Error getting socket;%s\n", strerror(errno));
  28. return -1;
  29. }
  30. /*set receive buffersize*/
  31. setsockopt(hotplug_sock, SOL_SOCKET, SO_RCVBUFFORCE, &buffersize, sizeof(buffersize));
  32. <strong><u><span style="color:#ff0000;">    int flags=fcntl(hotplug_sock, F_GETFL,0);
  33. fcntl(hotplug_sock, F_SETFL, flags | O_NONBLOCK);</span></u></strong>
  34. retval = bind(hotplug_sock, (struct sockaddr*)&snl, sizeof(struct sockaddr_nl) );
  35. if(retval < 0)
  36. {
  37. printf("bind failed: %s", strerror(errno));
  38. close(hotplug_sock);
  39. hotplug_sock = -1;
  40. return -1;
  41. }
  42. return hotplug_sock;
  43. }
  44. #endif // HOSTPLUG_H

然后添加一个定时器,定时器时间为500ms,即每500ms扫描一次,如下:

[cpp]  view plain copy print ?
  1. void Widget::timerEvent(QTimerEvent *event)
  2. {
  3. static int n = 0;
  4. char buf[1024] = {0};   //UEVENT_BUFFER_SIZE*2
  5. if(event->timerId() == timer.timerId())
  6. {
  7. recv(hotplug_sock, &buf, sizeof(buf), 0); //use a timer to query socket from core -netlink
  8. QString result = buf;
  9. rectFlag = result;
  10. qDebug()<<result;
  11. if(result.contains("add"))
  12. {
  13. n++;
  14. if (n>10)
  15. n = 10;
  16. ui->progressBar->setValue(n);
  17. }
  18. else if(result.contains("remove"))
  19. {
  20. n--;
  21. if(n<0)
  22. n = 0;
  23. ui->progressBar->setValue(n);
  24. }
  25. }
  26. else
  27. QWidget::timerEvent(event);
  28. }

注意这里最关键的就是

[cpp]  view plain copy print ?
  1. recv(hotplug_sock, &buf, sizeof(buf), 0);

这个函数,接收消息存至buf里。但默认的hotplug_sock是阻塞的,也就是当执行到recv时,程序就会停在这里,直到再次接收到内核新的消息,程序才会往下执行。为此,程序必须改动,一种思路是开一个线程,专门运行recv,停在那也无所谓;另外一种思路是将这个sock改成非阻塞的,改动部分见.h文件里画红线部分!

    int flags=fcntl(hotplug_sock, F_GETFL,0);
    fcntl(hotplug_sock, F_SETFL, flags | O_NONBLOCK);

当内核没有消息时,recv()之后的buf是空的。 交叉编译后,程序至Tiny210里运行良好!

上一张效果图:


但遗憾的是,工业是这么做是很不高明的,为了扫描一个U盘要开一个定时器在那扫描,因此最终采用判断/proc/scsi/usb-storage是否存在来判断u盘是否插入。曾考虑过U盘插入后,挂载点/udisk是否存在来判断。但当用户在/udisk目录下时,这时突然拔掉U盘。/udisk就会存在,而且ls查看的结果是报错。这时因为未推出U盘目录就拔掉,linux无法正常卸载造成的。当U盘插入良好时,usb-storage文件夹里会有三个文件,当卸载不成功时,会有两个文件。当卸载成功时,usb-storage这个文件夹会消失。采用像/udisk里写测试文件来判断/udisk是否可用,不可用的话就提示给用户:(自己是写了一个自动挂载的规则,见博客Linux上用udev自动识别并挂载U盘 ,然后判断usb-storage文件夹里文件的个数,是3的话就是有U盘插上了,否则就是U盘拔掉了。)

[cpp]  view plain copy print ?
  1. bool Widget::checkSaveFile()
  2. {
  3. QString fileName = "/proc/scsi/usb-storage/a.txt";
  4. QFile file(fileName);
  5. if(!file.open(QFile::WriteOnly|QFile::Text))
  6. return false;
  7. else
  8. {   file.close();
  9. file.remove();
  10. return true;
  11. }
  12. }

查询U盘状态的槽函数:

[cpp]  view plain copy print ?
  1. void Widget::on_queryButton_clicked()
  2. {
  3. QDir dir("/proc/scsi/usb-storage"); //在板子上,如果检测挂载点,改为:QDir dir("/udisk")检测挂载点
  4. QMessageBox box;
  5. QString mess;
  6. box.setWindowTitle(tc->toUnicode("U盘状态"));
  7. qDebug()<<"dir.count() = "<<dir.count();
  8. if(rectFlag.contains("add"))
  9. mess = tc->toUnicode("正在识别,请稍等-----");
  10. else if(rectFlag.contains("remove"))
  11. mess = tc->toUnicode("正在删除您的U盘-------");
  12. else if(dir.exists())
  13. {
  14. if(dir.count()>2 )
  15. {
  16. // if(checkSaveFile())
  17. mess = tc->toUnicode("U盘已连接!");
  18. // else
  19. // mess = tc->toUnicode("您的U盘已插入,但挂载点有问题,不能正常使用!建议拔掉U盘,然后重启!");
  20. }
  21. else if((dir.count() == 2) )
  22. {
  23. QDir dirMount("/udisk");
  24. if(dirMount.exists())
  25. {
  26. int fd =  system("umount /udisk");
  27. qDebug()<<"fd = "<<fd;
  28. }
  29. else
  30. mess = tc->toUnicode("/udisk No Exist!");
  31. //            if(checkSaveFile())
  32. //                mess = tc->toUnicode("您未插入U盘。但挂载点可写,不影响使用。如果需要请插入U盘!"); //这种情况从逻辑上讲不可能出现。
  33. //            else
  34. //                mess = tc->toUnicode("您未插入U盘。但当前挂载点有问题,建议重启后再插入U盘!");
  35. }
  36. else
  37. mess = tc->toUnicode("U盘连接有故障,请重启后再插入U盘!");
  38. }
  39. else
  40. mess = tc->toUnicode("U盘未连接!");
  41. // process->start("ls /mnt\n");
  42. //QString test = QString::number(a, 10);
  43. //    QString test = process->readAllStandardOutput();
  44. //    ui->getTextEdit->insertPlainText(test + "\n");
  45. ui->getTextEdit->insertPlainText(mess + "\n");
  46. autoScroll();
[cpp]  view plain copy print ?
  1. }

这样就能正常检测U盘了,如果想加进度条就加上。不加,也能正常检测。

问题又来了,上面采用向/udisk里写测试文件来检测/udisk是否可用,但有时用户会将U盘进行写保护。我试遍所有的方法,用open、opendir、access、stat等来检查异常情况下/udisk的属性与正常状态有何不同,最终也没查出来。也用了ls /udisk > /a.txt,截取ls的内容。但当/udisk出现异常时,报错的内容是板子上报的,并不是ls显示的内容。ls此时显示结果为空。

其实,与其判断这种误拔U盘的行为,倒不如防止。经过我研究发现,当ls出现/udisk fatal error,只要执行/umount /udisk,手动将这个文件夹卸载,再次插上U盘就可以了。为此,大家看到我上面程序里,当检测dir.count == 2时,检查/udisk是否存在,如果存在则将/udisk卸载。

这样做基本算完美解决问题了。美中不足的是,当异常出现时,如果板子程序一直在运行,则拔掉U盘再插上无事。如果此时板子重启,在板子重启前就将U盘再次插入到板子,这时候因为咱们的应用程序还未运行,还没有执行 umount /udisk,这个时候程序就检测不出来了。

要避免这个问题,就采用往U盘里写数据的方法判断,或者如果允许扫描用hostplug查询出来的信息可以得知usb的注册情况,这种思路应该也可以。一个小小的U盘检测,终于告一段落了,实现了x86下、arm平台均可用的qt检测U盘!----------------yanzi1225627

这里给一个源码资源,是老外写的,用qtcpsocket来监听netlink的消息,老外写的代码就是不一样啊,大家参考吧:

http://download.csdn.net/detail/yanzi1225627/4514740

linux U盘插拔检测相关推荐

  1. MFC使用Windows API实现U盘插拔检测,获取U盘容量,U盘内容移动删除,开启和关闭U盘以及获取盘符

    文章目录 前言 一.利用OS API实现对U盘的管理 二.项目到底长啥样 三.实例代码 1.实时判断U盘插入与拔出 2.能够显示U盘的总容量.使用容量和剩余容量 3.能够将某个目录上的文件或整个目录复 ...

  2. 教程一:windows api(c mfc vs2017)实现U盘插拔检测,获取U盘容量,U盘内容移动,开启和关闭U盘以及获取盘符等

    c++是大二下学期的专业课,大家可能都学过,这里主要介绍U盘这个小项目要用到没学过的知识.(踩坑合集) U盘完整项目源代码下载地址:https://download.csdn.net/download ...

  3. VB中简便的检测U盘插拔的方法(DriveListBox)

    我在网上找了很多资料,实现检测U盘插拔的方法基本上都是监测WM_DEVICECHANGE.这种方法不但臃肿,而且效率不高,很容易出错.于是我摸索出了一种新的方法,以下就是实现过程. 首先在窗体中添加一 ...

  4. android u盘挂载监听,Android SD卡及U盘插拔状态监听及内容读取

    本篇是通过系统方法来对sd卡及U盘插拔监听及数据获取,Android盒子端开发,有系统权限,当然,这个比较简单,知道具体方法,可以通过反射来实现. 先贴上效果图: 获取外置存储设备并监听插拔状态 获取 ...

  5. Android SD卡及U盘插拔状态监听和内容读取

    本篇是通过系统方法来对sd卡及U盘插拔监听及数据获取,Android盒子端开发,有系统权限,当然,这个比较简单,知道具体方法,可以通过反射来实现. 先贴上效果图: 获取外置存储设备并监听插拔状态 获取 ...

  6. 耳机驱动调试(插拔检测与按键检测)

    耳机驱动调试(插拔检测与按键检测) 小白一枚,欢各位大佬指出错误 耳机类型判断 三段和四段.欧标和美标 现在许多设备的耳机接口都采用3.5mm的耳机接口,其中终端就是,终端可以兼容三段和四段耳机:三段 ...

  7. Python:dbus监控U盘插拔

    本文主要介绍在PyQt5中,使用dbus监控U盘插拔. 测试环境:python3 + dbus + pyqt5 当无法引入dbus.mainloop.pyqt5时,安装对应的包即可: sudo apt ...

  8. mtk充电器插拔检测

    以mt6357 pmic为例,充电器插拔检测和类型检测在mt6357-charger-type.c下完成: 一.首先从pmic的probe开始分析: static int mt6357_charger ...

  9. 删除u盘插拔记录linux,电脑u盘插拔记录_电脑u盘插拔时间记录

    2016-06-07 18:50:08 按照如下步骤进行处理,尝试解决问题. 1.USB接口损坏.接触不良也会出现此情况,换一个USB接口,台式机插入主机后接口试试. 2.插入电脑,右下角有图标,不显 ...

最新文章

  1. [转]---UAP中如何判断当前APP在哪个平台设备上运行
  2. html 执行外部js的函数,javascript – Chrome扩展程序:加载并执行外部脚本
  3. 五大新品+两大黑科技,看华为云如何升级基础设施让用户“躺平”
  4. 快速幂(一个简单快速适合整数幂次的运算)
  5. quick time不可用_教程|用Selenium爬资源:DIY还是花钱?
  6. 系统集成项目管理工程师 案例题【2021上】 总结
  7. MT6761 android11 linux4.19上IMX258摄像头点不亮原因备忘
  8. matlab中的全局参量,matlab参数传递及全局变量 | 学步园
  9. 决策树(2)——CART算法
  10. 实现企业邮箱登录验证功能
  11. 中国传媒大学计算机课程表,中国传媒大学新闻学院课程表.doc
  12. 解决 Unrecognized field code , not marked as ignorable 问题
  13. 全国数字金融与量化金融案例大赛经验分享
  14. 网站的养站(养蜘蛛)技巧
  15. 深入理解TCP协议的连接状态与可靠机制
  16. 主成分分析(PCA)(principal component analysis)
  17. OSI七层模型详解物理层、数据链路层、网络层、传输层.....应用层协议
  18. html在浏览器显示图片,html - 在所有Web浏览器中显示TIFF图像
  19. 清华姚班教授: 「读博,你真的想好了吗?」与 UIUC 王鸿伟「读博,我想好了!」...
  20. bootstrap-table自定义列排序

热门文章

  1. html音乐播放器自动切歌,HTML音乐播放——切歌
  2. java openresty 调用_Openresty使用
  3. 消息队列 pulsar 架构学习
  4. 舒亦梵:这四大点作为黄金投资者的你,一定要铭记
  5. Swift AES加密
  6. Mac OS X显示桌面和窗口最小化方法的几个快捷键
  7. 华为业务流程管理体系介绍
  8. Caused by: java.lang.IllegalArgumentException: argument type mismatch
  9. 【项目实战】Python基于GARCH模型进行预测特斯拉股票,以及评估金融资产的风险
  10. 计算机科学导论作业大纲,《计算机科学导论》课程复习大纲与综合练习题.doc...