一、Uevent是一种在内核空间和用户空间之间通信的机制,主要用于热插拔事件(hotplug),比如USB和HDMI拔插事件。
二、uevent事件
uevent事件在include/linux/kobject.h中有的定义,kobject对应的动作可分为以下几种:
三、发送事件方法
内核中通过kobject_uevent_env函数将事件发送到用户空间
四、实例测试
1、kernel驱动文件kobject_uevent_env.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct device *dev = NULL;
char * mesg[2];
static ssize_t send_message(struct device *dev,struct device_attribute *attr, const char *buf, size_t count)
{
int ret = 0;
char s_buf[100]={0};
char *event_string = "HOTPLUG=1";
mesg[0] =s_buf;
//mesg[0]= "HOTPLUG=1";
mesg[1] = NULL;
//strcat(s_buf, "kobject_uevent_env hello");
strcat(s_buf, buf);
printk(KERN_WARNING "received message buf=%s s_buf=%s count=%d\n",buf,s_buf,count);
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, mesg);
return count;
}
static DEVICE_ATTR(m_point, S_IRUGO|S_IWUSR, NULL, send_message);
static const struct attribute *kobject_event_attr[] = {
&dev_attr_m_point.attr,
NULL,
};
static const struct attribute_group kobject_event_attr_group = {
.attrs = (struct attribute **) kobject_event_attr,
};
static struct class kobject_event_class = {
.name = "kobject_event",
.owner = THIS_MODULE,
};
static int __init kobject_uevent_init(void)
{
int ret = 0;
ret = class_register(&kobject_event_class);
if (ret < 0) {
printk(KERN_ERR "song_event: class_register fail\n");
return ret;
}
dev = device_create(&kobject_event_class, NULL, MKDEV(0, 0), NULL, "kobject_event");
if (dev) {
ret = sysfs_create_group(&dev->kobj, &kobject_event_attr_group);
if(ret < 0) {
printk(KERN_ERR "kobject_event:sysfs_create_group fail\r\n");
return ret;
}
} else {
printk(KERN_ERR "kobject_event:device_create fail\r\n");
ret = -1;
return ret;
}
return 0;
}
static __exit void kobject_uevent_exit(void)
{
device_destroy(&kobject_event_class, MKDEV(0,0));
class_destroy(&kobject_event_class);
sysfs_remove_group(&dev->kobj, &kobject_event_attr_group);
printk(KERN_WARNING "kobject_uevent_exit!\n");
}
module_init(kobject_uevent_init);
module_exit(kobject_uevent_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("haiyuexichen");
2、user端c文件user_kobject_uevent_env.c
#include
#include
#include
#define UEVENT_MSG_LEN 4096
int device_fd = -1;
struct listener_gliethttp {
const char *action;
const char *path;
const char *subsystem;
const char *firmware;
int major;
int minor;
};
static int init_socket(void)
{
struct sockaddr_nl addr;
int sz = 64*1024;
int s;
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid();
addr.nl_groups = 0xffffffff;
s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);// uevent_fd_.Set(socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT));
if (s < 0)
return -1;
setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
close(s);
return -1;
}
return s;
}
static void parse_event(const char *msg, struct listener_gliethttp *listener_gliethttp)
{
listener_gliethttp->action = "";
listener_gliethttp->path = "";
listener_gliethttp->subsystem = "";
listener_gliethttp->firmware = "";
listener_gliethttp->major = -1;
listener_gliethttp->minor = -1;
printf("========================================================\n");
while (*msg) {
printf("%s\n", msg);
if (!strncmp(msg, "ACTION=", 7)) {
msg += 7;
listener_gliethttp->action = msg;
} else if (!strncmp(msg, "DEVPATH=", 8)) {
msg += 8;
listener_gliethttp->path = msg;
} else if (!strncmp(msg, "SUBSYSTEM=", 10)) {
msg += 10;
listener_gliethttp->subsystem = msg;
} else if (!strncmp(msg, "FIRMWARE=", 9)) {
msg += 9;
listener_gliethttp->firmware = msg;
} else if (!strncmp(msg, "MAJOR=", 6)) {
msg += 6;
listener_gliethttp->minor = atoi(msg);
} else if (!strncmp(msg, "PANEL_ALIVE=", 12)) {
printf("PANEL_ALIVE==%d\n",atoi(msg));
}
while(*msg++)
;
}
printf("event { '%s', '%s', '%s', '%s', %d, %d }\n",
listener_gliethttp->action, listener_gliethttp->path, listener_gliethttp->subsystem,
listener_gliethttp->firmware, listener_gliethttp->major, listener_gliethttp->minor);
}
void UEventHandler() {
char buffer[1024];
int ret;
while (1) {
printf("*******************************************************************\n");
printf("waiting data sent for kernel!\n");
ret = read(device_fd, &buffer, sizeof(buffer));
if (ret == 0) {
return;
} else if (ret < 0) {
printf("Got error reading uevent %d", ret);
return;
}
printf("recevied message:\r\n");
for (int i = 0; i < ret;) {
char *event = buffer + i;
if (strcmp(event, "DEVTYPE=drm_minor"))
;
else if (strcmp(event, "HOTPLUG=1"))
{
printf("hwc_uevent detect hotplug");
}
printf("*********%s \r\n",event);
i += strlen(event) + 1;
}
}
}
int main()
{
char msg[UEVENT_MSG_LEN+2];
int n;
device_fd = init_socket();
if(device_fd<0){
printf("fail to init socket!\r\n");
return 0;
}else{
printf("success to init socket!\r\n");
}
UEventHandler();
while(1){
while((n = recv(device_fd, msg, UEVENT_MSG_LEN, 0)) > 0){
struct listener_gliethttp listener_gliethttp;
if(n == UEVENT_MSG_LEN)
continue;
msg[n] = '\0';
msg[n+1] = '\0';
printf("----------- msg=%s\n",msg);
parse_event(msg, &listener_gliethttp);
printf("----------- msg=%s\n",msg);
}
}
}
3、在android下真机执行效果