一个简单的利用UEVENT监控USB热插拔的例子

最近工作中要用到UEVENT这个东东,记录一下. 最主要的就是怎么把UEVENT收到的消息给分析一下,刚开始不知道,直接打出来一串东西,原来返回的值里面有‘\0’, 把它换为‘\n’就能打出来了。这个东西虽然很简单,但是不知道的情况下还是需要研究一番才能用起来,而且KMD那边印度哥们给我的patch不能用,会导致系统挂掉,我研究了一下,貌似是由于异步的原因,kernel发送event上来的时候貌似是要走异步的,但印度哥们可能为了偷懒给我直接嫁接在isr的handler里面了,没有放到队列里导致的。不知道这个是我们KMD驱动的设计问题还是内核这样要求的,有空在研究一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/types.h>
#include <linux/netlink.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define UEVENT_BUFFER_SIZE 2048
static int init_hotplug_sock()
{
const int buffersize = 1024;
int ret;
struct sockaddr_nl snl;
bzero(&snl, sizeof(struct sockaddr_nl));
snl.nl_family = AF_NETLINK;
snl.nl_pid = getpid();
snl.nl_groups = 1;
int s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
if (s == -1)
{
perror("socket");
return -1;
}
setsockopt(s, SOL_SOCKET, SO_RCVBUF, &buffersize, sizeof(buffersize));
ret = bind(s, (struct sockaddr *)&snl, sizeof(struct sockaddr_nl));
if (ret < 0)
{
perror("bind");
close(s);
return -1;
}
return s;
}
int main(int argc, char* argv[])
{
int hotplug_sock = init_hotplug_sock();
int len;
struct iovec iov;
struct msghdr msg;
memset(&msg,0,sizeof(msg));
iov.iov_base=(void *)buf;
iov.iov_len=sizeof(buf);
msg.msg_name=(void *)&sa;
msg.msg_namelen=sizeof(sa);
msg.msg_iov=&iov;
msg.msg_iovlen=1;
while(1)
{
/* Netlink message buffer */
char buf[UEVENT_BUFFER_SIZE * 2] = {0};
recvmsg(hotplug_sock, &msg, 0);
printf("%s\n", buf);
if(len<0)
printf("receive error\n");
else if(len<32||len>sizeof(buf))
printf("invalid message");
for(i=0;i<len;i++)
if(*(buf+i)=='\0')
buf[i]='\n';
printf("received %d bytes\n%s\n",len,buf);
}
return 0;
}