sysfs的了解及libudev的浅析 (四) —— 第二层 精髓

      还没看,我认为是我想要的实现的精髓,看懂了就知道了怎么去获取了。

 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是一个鼠标还是一个键盘,还是触摸屏。

      



你可能感兴趣的:(sysfs的了解及libudev的浅析 (四) —— 第二层 精髓)