两个重点中的第一个
UDEV_EXPORT int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate)
{
if (udev_enumerate == NULL)
return -EINVAL;
/* efficiently lookup tags only, we maintain a reverse-index */
if (udev_list_get_entry(&udev_enumerate->tags_match_list) != NULL)
return scan_devices_tags(udev_enumerate);
/* walk the subtree of one parent device only */
if (udev_enumerate->parent_match != NULL)
return scan_devices_children(udev_enumerate);
/* scan devices of all subsystems */
return scan_devices_all(udev_enumerate);
}
初始化时tags_match_list, true,第二个return 可能执行的,第四个return是扫描所有的。我们一般没有设置要匹配的tag,所以第二个return应该是跳过的。第三个,有parent的时候才会去扫描children。所以这里应该是执行第四个。我们姑且认为是这样。
static int scan_devices_all(struct udev_enumerate *udev_enumerate)
{
struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
char base[UTIL_PATH_SIZE];
struct stat statbuf;
util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/subsystem", NULL);
if (stat(base, &statbuf) == 0) {
/* we have /subsystem/, forget all the old stuff */
dbg(udev, "searching '/subsystem/*/devices/*' dir\n");
scan_dir(udev_enumerate, "subsystem", "devices", NULL);
} else {
dbg(udev, "searching '/bus/*/devices/*' dir\n");
scan_dir(udev_enumerate, "bus", "devices", NULL);
dbg(udev, "searching '/class/*' dir\n");
scan_dir(udev_enumerate, "class", NULL, NULL);
}
return 0;
}
sysfs下/subsystem一般不会有,所以会去sysfs下/bus/*/devices/*、/class/*下扫描所有设备。
static int scan_dir(struct udev_enumerate *udev_enumerate,
const char *basedir, const char *subdir, const char *subsystem)
{
struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
char path[UTIL_PATH_SIZE];
DIR *dir;
struct dirent *dent;
util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), "/", basedir, NULL);
dir = opendir(path);
if (dir == NULL)
return -1;
for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
if (dent->d_name[0] == '.')
continue;
if (!match_subsystem(udev_enumerate, subsystem != NULL ? subsystem : dent->d_name))
continue;
scan_dir_and_add_devices(udev_enumerate, basedir, dent->d_name, subdir);
}
closedir(dir);
return 0;
}
sysfs下/bus/、/class/都是有的。readdir()。第四个参数是NULL,所以比较d_name和之前设置的要匹配的subsystem。
bus,总线,有很多,如
[root@localhost bus]# ls
acpi clocksource event_source i2c mdio_bus pci pcmcia pnp serio usb-serial xen
clockevents cpu hid machinecheck node pci_express platform scsi usb workqueue xen-backend
class下面也有很多,
[root@localhost class]# ls
ata_device bdi cpuid graphics ieee80211 mem pci_bus rfkill scsi_generic thermal vtconsole
ata_link block dma hidraw input misc pcmcia_socket rtc scsi_host tty watchdog
ata_port bluetooth dmi hwmon leds msr power_supply scsi_device spi_host usbmon
backlight bsg drm i2c-adapter mdio_bus net raw scsi_disk spi_transport vc
键鼠、触摸,属于输入类,所以subsystem选择input来匹配,即找到/class/input,找到了,之后就是扫描它下面的并添加设备。注意传参的内容,因为匹配到的是class下的,所以scan_dir(udev_enumerate, "class", NULL, NULL); 传 class、input、NULL
static int scan_dir_and_add_devices(struct udev_enumerate *udev_enumerate,
const char *basedir, const char *subdir1, const char *subdir2)
{
struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
char path[UTIL_PATH_SIZE];
size_t l;
char *s;
DIR *dir;
struct dirent *dent;
s = path;
l = util_strpcpyl(&s, sizeof(path), udev_get_sys_path(udev), "/", basedir, NULL);
if (subdir1 != NULL)
l = util_strpcpyl(&s, l, "/", subdir1, NULL);
if (subdir2 != NULL)
util_strpcpyl(&s, l, "/", subdir2, NULL);
dir = opendir(path);
if (dir == NULL)
return -ENOENT;
for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
char syspath[UTIL_PATH_SIZE];
struct udev_device *dev;
if (dent->d_name[0] == '.')
continue;
if (!match_sysname(udev_enumerate, dent->d_name))
continue;
util_strscpyl(syspath, sizeof(syspath), path, "/", dent->d_name, NULL);
dev = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
if (dev == NULL)
continue;
if (udev_enumerate->match_is_initialized) {
/*
* All devices with a device node or network interfaces
* possibly need udev to adjust the device node permission
* or context, or rename the interface before it can be
* reliably used from other processes.
*
* For now, we can only check these types of devices, we
* might not store a database, and have no way to find out
* for all other types of devices.
*/
if (!udev_device_get_is_initialized(dev) &&
(major(udev_device_get_devnum(dev)) > 0 || udev_device_get_ifindex(dev) > 0))
goto nomatch;
}
if (!match_parent(udev_enumerate, dev))
goto nomatch;
if (!match_tag(udev_enumerate, dev))
goto nomatch;
if (!match_property(udev_enumerate, dev))
goto nomatch;
if (!match_sysattr(udev_enumerate, dev))
goto nomatch;
syspath_add(udev_enumerate, udev_device_get_syspath(dev));
nomatch:
udev_device_unref(dev);
}
closedir(dir);
return 0;
}
/class/input下readdir()。
[root@localhost input]# ls
event0 event1 event2 event3 input0 input1 input2 input3 mice mouse0 mouse1
这是PC linux系统下/sys/class/input下的内容,这就是我们要找的已存在的键鼠、触摸设备。但是怎么区分呢?
初始化是sysname_match_list, true,如果不匹配就继续了,说明是要匹配的,匹配什么呢?再说。
现在关注的是怎么区分出来。取event0
dev = udev_device_new_from_syspath( , /sys/class/input/event0)
syspath_add(, udev_device_get_syspath(dev));
这就是它的精髓了。也就是第二个重点。