还没看,我认为是我想要的实现的精髓,看懂了就知道了怎么去获取了。
dev = udev_device_new_from_syspath( , /sys/class/input/event0)
<span style="font-size:14px;">UDEV_EXPORT struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath) { size_t len; const char *subdir; char path[UTIL_PATH_SIZE]; char *pos; struct stat statbuf; struct udev_device *udev_device; if (udev == NULL) return NULL; if (syspath == NULL) return NULL; /* path starts in sys */ len = strlen(udev_get_sys_path(udev)); if (strncmp(syspath, udev_get_sys_path(udev), len) != 0) { info(udev, "not in sys :%s\n", syspath); return NULL; } /* path is not a root directory */ subdir = &syspath[len+1]; pos = strrchr(subdir, '/'); if (pos == NULL || pos[1] == '\0' || pos < &subdir[2]) { dbg(udev, "not a subdir :%s\n", syspath); return NULL; } /* resolve possible symlink to real path */ util_strscpy(path, sizeof(path), syspath); util_resolve_sys_link(udev, path, sizeof(path)); if (strncmp(&path[len], "/devices/", 9) == 0) { char file[UTIL_PATH_SIZE]; /* all "devices" require a "uevent" file */ util_strscpyl(file, sizeof(file), path, "/uevent", NULL); if (stat(file, &statbuf) != 0) { dbg(udev, "not a device: %s\n", syspath); return NULL; } } else { /* everything else just needs to be a directory */ if (stat(path, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) { dbg(udev, "directory not found: %s\n", syspath); return NULL; } } udev_device = udev_device_new(udev); if (udev_device == NULL) return NULL; udev_device_set_syspath(udev_device, path); info(udev, "device %p has devpath '%s'\n", udev_device, udev_device_get_devpath(udev_device)); return udev_device; }</span>strrchr() 函数查找字符在指定字符串中从正面开始的最后一次出现的位置。
这里会怀疑,传进来的可能是/sys/class/input/event0/
根据判断条件,传进来的是/sys/class/input/event0,不接'/'
util_resolve_sys_link(udev, path, sizeof(path));解决链接符号文件,得到真实的路径文件
event0 -> ../../devices/LNXSYSTM:00/LNXPWRBN:00/input/input0/event0
也就是得到/sys/devices/LNXSYSTM:00/LNXPWRBN:00/input/input0/event0,我们在看udev或者它的例子打印出来了就是/devices/LNXSYSTM:00/LNXPWRBN:00/input/input0/event0这样的形式。
如果包含“/devices/”,继续,得到
/sys/devices/LNXSYSTM:00/LNXPWRBN:00/input/input0/event0/uevent,每个设备都会有uevent,所以判断是否存在。
存在,OK了,创建一个udev_device,并添加path
udev_device_set_syspath(udev_device, /sys/devices/LNXSYSTM:00/LNXPWRBN:00/input/input0/event0);
注意了,这里是set_syspath。
这就完了,但还是没有关联到/dev下的东西。难到是我遗漏了???
那接下来就看看是怎么得到/dev下的node的。
node = udev_device_get_devnode(device);
/**
* udev_device_get_devnode:
* @udev_device: udev device
*
* Retrieve the device node file name belonging to the udev device.
* The path is an absolute path, and starts with the device directory.
*
* Returns: the device node file name of the udev device, or #NULL if no device node exists
**/
UDEV_EXPORT const char *udev_device_get_devnode(struct udev_device *udev_device)
{
if (udev_device == NULL)
return NULL;
if (!udev_device->info_loaded) {
udev_device_read_uevent_file(udev_device);
udev_device_read_db(udev_device, NULL);
}
/* we might get called before we handled an event and have a db, use the kernel-provided name */
if (udev_device->devnode == NULL && udev_device_get_knodename(udev_device) != NULL) {
char filename[UTIL_NAME_SIZE];
util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_device->udev), "/",
udev_device_get_knodename(udev_device), NULL);
udev_device_set_devnode(udev_device, filename);
return udev_device->devnode;
}
return udev_device->devnode;
}
这里会去读取uevent文件,db文件。这是什么呢
可以看到devnode是devpath + '/' + knodename,
devpath及knodename
int udev_device_read_uevent_file(struct udev_device *udev_device)
{
char filename[UTIL_PATH_SIZE];
FILE *f;
char line[UTIL_LINE_SIZE];
int maj = 0;
int min = 0;
if (udev_device->uevent_loaded)
return 0;
util_strscpyl(filename, sizeof(filename), udev_device->syspath, "/uevent", NULL);
f = fopen(filename, "re");
if (f == NULL)
return -1;
udev_device->uevent_loaded = true;
while (fgets(line, sizeof(line), f)) {
char *pos;
pos = strchr(line, '\n');
if (pos == NULL)
continue;
pos[0] = '\0';
if (strncmp(line, "DEVTYPE=", 8) == 0)
udev_device_set_devtype(udev_device, &line[8]);
else if (strncmp(line, "MAJOR=", 6) == 0)
maj = strtoull(&line[6], NULL, 10);
else if (strncmp(line, "MINOR=", 6) == 0)
min = strtoull(&line[6], NULL, 10);
else if (strncmp(line, "IFINDEX=", 8) == 0)
udev_device_set_ifindex(udev_device, strtoull(&line[8], NULL, 10));
else if (strncmp(line, "DEVNAME=", 8) == 0)
udev_device_set_knodename(udev_device, &line[8]);
else if (strncmp(line, "DEVMODE=", 8) == 0)
udev_device->devnode_mode = strtoul(&line[8], NULL, 8);
udev_device_add_property_from_string(udev_device, line);
}
udev_device->devnum = makedev(maj, min);
fclose(f);
return 0;
}
可以看到是从前面得到的带路径的uevent中读取
[root@localhost event0]# cat uevent
MAJOR=13
MINOR=64
DEVNAME=input/event0
DEVNAME设置为knodename。
至于devpath,初始化时默认是/dev
/* set defaults */
if (udev->dev_path == NULL)
if (set_value(&udev->dev_path, "/dev") == NULL)
goto err;
所以得到了devnode,/dev/input/event0。MAJOR和MINOR可以用来判断是什么(键盘、鼠标、触摸设备)吗?
下面就剩下了一个问题,怎么判断/dev/input/event0是一个鼠标还是一个键盘,还是触摸屏。