1,内核发送uevent
内核发送uevent的API由lib/kobject_event.c文件实现,include/linux/kobject.h是头文件。
enum kobject_action {
KOBJ_ADD,
KOBJ_REMOVE,
KOBJ_CHANGE,
KOBJ_MOVE,
KOBJ_ONLINE,
KOBJ_OFFLINE,
KOBJ_MAX
};
/* kobject_uevent不能用在中断上下文 */
int kobject_uevent(struct kobject *kobj, enum kobject_action action);
int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, char *envp[]);
在driver中可以调用kobject_uevent或者kobject_uevent_env来向用户空间发送uevent
kobject_uevent默认会发送”ACTION=xxx”,”DEVPATH=xxx”,”SUBSYSTEM=xxx”这三个uevent环境变量。
kobject_uevent_env可以发送一些如”xxx=xxx”的自定义的uevent环境变量。
static ssize_t esd_info_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
if (!buf || count <= 0)
return -EINVAL;
kobject_uevent(&core_data->pdev->dev.kobj, KOBJ_CHANGE);
return count;
}
static int test_uevent(struct device *dev,
struct kobj_uevent_env *env)
{
int ret = 0;
ret = add_uevent_var(env,"COMMENT=%s", "test uevent message");
if(ret)
return ret;
return 0;
}
const struct device_type my_dev_type ={
.name ="william_ts",
.uevent= test_uevent,
};
static int xxx_probe(struct platform_device *pdev)
{
pdev->dev.type = &my_dev_type;
}
2,用户空间解析uevent
#define UEVENT_MSG_LEN 2048
static void uevent_event(uint32_t /*epevents*/, int event_fd)
{
char msg[UEVENT_MSG_LEN + 2];
int n;
char *cp;
n = uevent_kernel_multicast_recv(event_fd, msg, UEVENT_MSG_LEN);
if (n <= 0)
return;
if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
return;
msg[n] = '\0';
msg[n + 1] = '\0';
cp = msg;
ALOGE("william get the uevent size n = %d, msg = %s", n, msg);
while(*cp) {
ALOGE("william receive the msg = %s", cp);
/* advance to after the next \0 */
while(*cp++)
;
}
ALOGE("william uevent received %s", msg);
}
void *MT::uevent_thread_loop(void)
{
int epoll_fd, uevent_fd;
struct epoll_event ev;
int nevents = 0;
ALOGE("creating uevent thread");
uevent_fd = uevent_open_socket(64 * 1024, true);
if (uevent_fd < 0) {
ALOGE("uevent_init: uevent_open_socket failed\n");
return NULL;
}
fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
ev.events = EPOLLIN;
ev.data.ptr = (void *)uevent_event;
epoll_fd = epoll_create(64);
if (epoll_fd == -1) {
ALOGE("epoll_create failed; errno=%d", errno);
goto error;
}
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) {
ALOGE("epoll_ctl failed; errno=%d", errno);
goto error;
}
while (!destroyThread) {
struct epoll_event events[64];
nevents = epoll_wait(epoll_fd, events, 64, -1);
if (nevents == -1) {
if (errno == EINTR) continue;
ALOGE("usb epoll_wait failed; errno=%d", errno);
break;
}
for (int n = 0; n < nevents; ++n) {
if (events[n].data.ptr)
(*(void (*)(uint32_t, int event_fd))events[n].data.ptr)(
events[n].events, uevent_fd);
}
}
ALOGI("exiting worker thread");
error:
close(uevent_fd);
if (epoll_fd >= 0)
close(epoll_fd);
return NULL;
}
void sighandler(int sig) {
if (sig == SIGUSR1) {
destroyThread = true;
ALOGI("destroy set");
return;
}
signal(SIGUSR1, sighandler);
}
3,测试结果
上报的event会通知到所有的用户进程,这里能够收到系统中所有的uevent消息,这里只打印了我们自己添加测试的event。
william get the uevent size n = 234, msg = change@/devices/platform/william_ts.0
william receive the msg = change@/devices/platform/william_ts.0
william receive the msg = ACTION=change
william receive the msg = DEVPATH=/devices/platform/william_ts.0
william receive the msg = SUBSYSTEM=platform
william receive the msg = DEVTYPE=william_ts
william receive the msg = DRIVER=william_ts
william receive the msg = MODALIAS=platform:william_ts
william receive the msg = MAC=05:04:03:02:01:00
william receive the msg = COMMENT=test uevent message
william receive the msg = SEQNUM=13492
william uevent received change@/devices/platform/william_ts.0