Linux下自动检测USB热插拔
2016-08-04 16:53
441 查看
做嵌入式开发,尤其在网关、路由器或者其他支持USB设备的终端上,为了提高用户体验,我们常常需要支持自动识别并挂载USB设备功能。某些应用程序,在使用USB设备的过程中,也希望能够侦测到USB断开事件,不至于某些工作因为USB已经不存在而白做。在Linux下,我们主要有两种办法检测USB热插拔。
第一种便是定时检查/proc/scsi/scsi文件,该文件内会按照标准格式保存着当前设备内挂载的存储介质基本信息,如果在PC端,除了硬盘(ATA)、光驱(CD-ROM)外,就是USB设备(Direct-Access)了,轮询该scsi文件,检查文件内是否新增或减少数据便可实现自动侦测USB热插拔的效果。但是这种方法对于热插拔(hotplug)设备,如U盘,效果就没那么理想了,因为我们不知道设备什么时候插上,又是什么时候被拔掉了,只能验证当前是否已经插上或者已经拔除的事实。于是便有了另一种办法,我们采用一种特殊类的的文件描述符(套结字)专门用于Linux内核跟用户空间之间的异步通信,这种技术通常被成为NETLINK。
由于NETLINK是Linux内置功能,所以使用起来很简单:创建一个AF_NETLINK协议族下NETLINK_KOBJECT_UEVENT类型的特殊文件描述符(套结字)CppLive,然后利用setsocketopt允许该文件描述符(套结字)复用其他端口,再利用band函数将自身进程绑定到特殊文件描述符(套结字)CppLive,最后利用select在while循环内监听CppLive是否可读,如果可读则调用recv接收Linux系统内核传递过来的数据并打印出来,这些输出便是USB热插拔信息。当然你也可以个性化地处理来自内核的热插拔信息,让程序变得更加智能以及人性化。
利用NETLINK检测USB热插拔的C语言实现代码如下:
view
plaincopy
to clipboardprint?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#define UEVENT_BUFFER_SIZE 2048
int main(void)
{
struct sockaddr_nl client;
struct timeval tv;
int CppLive, rcvlen, ret;
fd_set fds;
int buffersize = 1024;
CppLive = socket(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
memset(&client, 0, sizeof(client));
client.nl_family = AF_NETLINK;
client.nl_pid = getpid();
client.nl_groups = 1; /* receive broadcast message*/
setsockopt(CppLive, SOL_SOCKET, SO_RCVBUF, &buffersize, sizeof(buffersize));
bind(CppLive, (struct sockaddr*)&client, sizeof(client));
while (1) {
char buf[UEVENT_BUFFER_SIZE] = { 0 };
FD_ZERO(&fds);
FD_SET(CppLive, &fds);
tv.tv_sec = 0;
tv.tv_usec = 100 * 1000;
ret = select(CppLive + 1, &fds, NULL, NULL, &tv);
if(ret < 0)
continue;
if(!(ret > 0 && FD_ISSET(CppLive, &fds)))
continue;
/* receive data */
rcvlen = recv(CppLive, &buf, sizeof(buf), 0);
if (rcvlen > 0) {
printf("%s\n", buf);
/*You can do something here to make the program more perfect!!!*/
}
}
close(CppLive);
return 0;
}
运行程序,测试U盘插入/拔除,输出如下:
view
plaincopy
to clipboardprint?
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0
add@/module/usb_storage
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/scsi_host/host6
add@/bus/usb/drivers/usb-storage
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/scsi_disk/6:0:0:0
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/scsi_device/6:0:0:0
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/scsi_generic/sg2
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/bsg/6:0:0:0
change@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/block/sdb
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/block/sdb/sdb4
add@/devices/virtual/bdi/8:16
add@/module/fat
add@/kernel/slab/fat_cache
add@/kernel/slab/fat_inode_cache
add@/module/vfat
add@/module/nls_cp437
add@/module/nls_iso8859_1
remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/bsg/6:0:0:0
remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/scsi_generic/sg2
remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/scsi_device/6:0:0:0
remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/scsi_disk/6:0:0:0
remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/block/sdb/sdb4
remove@/devices/virtual/bdi/8:16
remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/block/sdb
remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0
remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/scsi_host/host6
remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6
remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0
remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1
remove@/host6/target6:0:0
转自http://www.cpplive.com/html/1355.html
第一种便是定时检查/proc/scsi/scsi文件,该文件内会按照标准格式保存着当前设备内挂载的存储介质基本信息,如果在PC端,除了硬盘(ATA)、光驱(CD-ROM)外,就是USB设备(Direct-Access)了,轮询该scsi文件,检查文件内是否新增或减少数据便可实现自动侦测USB热插拔的效果。但是这种方法对于热插拔(hotplug)设备,如U盘,效果就没那么理想了,因为我们不知道设备什么时候插上,又是什么时候被拔掉了,只能验证当前是否已经插上或者已经拔除的事实。于是便有了另一种办法,我们采用一种特殊类的的文件描述符(套结字)专门用于Linux内核跟用户空间之间的异步通信,这种技术通常被成为NETLINK。
由于NETLINK是Linux内置功能,所以使用起来很简单:创建一个AF_NETLINK协议族下NETLINK_KOBJECT_UEVENT类型的特殊文件描述符(套结字)CppLive,然后利用setsocketopt允许该文件描述符(套结字)复用其他端口,再利用band函数将自身进程绑定到特殊文件描述符(套结字)CppLive,最后利用select在while循环内监听CppLive是否可读,如果可读则调用recv接收Linux系统内核传递过来的数据并打印出来,这些输出便是USB热插拔信息。当然你也可以个性化地处理来自内核的热插拔信息,让程序变得更加智能以及人性化。
利用NETLINK检测USB热插拔的C语言实现代码如下:
view
plaincopy
to clipboardprint?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#define UEVENT_BUFFER_SIZE 2048
int main(void)
{
struct sockaddr_nl client;
struct timeval tv;
int CppLive, rcvlen, ret;
fd_set fds;
int buffersize = 1024;
CppLive = socket(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
memset(&client, 0, sizeof(client));
client.nl_family = AF_NETLINK;
client.nl_pid = getpid();
client.nl_groups = 1; /* receive broadcast message*/
setsockopt(CppLive, SOL_SOCKET, SO_RCVBUF, &buffersize, sizeof(buffersize));
bind(CppLive, (struct sockaddr*)&client, sizeof(client));
while (1) {
char buf[UEVENT_BUFFER_SIZE] = { 0 };
FD_ZERO(&fds);
FD_SET(CppLive, &fds);
tv.tv_sec = 0;
tv.tv_usec = 100 * 1000;
ret = select(CppLive + 1, &fds, NULL, NULL, &tv);
if(ret < 0)
continue;
if(!(ret > 0 && FD_ISSET(CppLive, &fds)))
continue;
/* receive data */
rcvlen = recv(CppLive, &buf, sizeof(buf), 0);
if (rcvlen > 0) {
printf("%s\n", buf);
/*You can do something here to make the program more perfect!!!*/
}
}
close(CppLive);
return 0;
}
运行程序,测试U盘插入/拔除,输出如下:
view
plaincopy
to clipboardprint?
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0
add@/module/usb_storage
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/scsi_host/host6
add@/bus/usb/drivers/usb-storage
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/scsi_disk/6:0:0:0
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/scsi_device/6:0:0:0
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/scsi_generic/sg2
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/bsg/6:0:0:0
change@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/block/sdb
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/block/sdb/sdb4
add@/devices/virtual/bdi/8:16
add@/module/fat
add@/kernel/slab/fat_cache
add@/kernel/slab/fat_inode_cache
add@/module/vfat
add@/module/nls_cp437
add@/module/nls_iso8859_1
remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/bsg/6:0:0:0
remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/scsi_generic/sg2
remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/scsi_device/6:0:0:0
remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/scsi_disk/6:0:0:0
remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/block/sdb/sdb4
remove@/devices/virtual/bdi/8:16
remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/block/sdb
remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0
remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/scsi_host/host6
remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6
remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0
remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1
remove@/host6/target6:0:0
转自http://www.cpplive.com/html/1355.html
相关文章推荐
- centos 同步外网源到本地
- Kali linux
- gun/linux 命令 parallel的使用
- (总结)CentOS Linux下VNC Server远程桌面配置详解
- linux 下搭建gitlab服务器
- Linux的常见命令
- linux热插拔
- 如何远程登录linux服务器
- linux操作串口的代码,linux串口通信以及串口初始化代码,linux串口读写方法和代码
- VNC轻松连接远程Linux桌面(1)
- Linux系统开发 3 文件系统开发 文件/目录
- linux 常用命令
- (转)Linux开机启动(bootstrap)
- linux和windows下实现日志写入文件功能
- Linux下实现USB口的热插拔
- Linux学习篇之服务管理
- Linux 文件夹权限
- ssh 登陆redhat linux时中文显示乱码解决方法
- linux php添加ftp扩展模块
- CentOS7安装Hadoop2.7完整流程