接上一篇文章《xf86-video-intel源码分析6 —— intel_device.c和intel_driver.h(1)》,链接为:
xf86-video-intel源码分析6 —— intel_device.c和intel_driver.h(1)_蓝天居士的博客-CSDN博客
上一篇文章分析到了__intel_open_device函数,再列一下代码:
- static int __intel_open_device(const struct pci_device *pci, const char *path)
- {
- int fd;
-
- if (path == NULL) {
- if (pci == NULL)
- return -1;
-
- fd = __intel_open_device__pci(pci);
- if (fd == -1)
- fd = __intel_open_device__legacy(pci);
- } else
- fd = open_cloexec(path);
-
- return fd;
- }
可以看到,函数共分为3条路径:
(1)当path和pci同时为空的时候,直接返回-1,甭往下走了;
(2)如果path为空而pci不为空,那么可以通过入参指针pci进行设备的打开。如果__intel_open_device_pci函数无法打开,还可以通过老版本__intel_open_device__legacy函数尝试打开;
(3)如果path本身就不空,也就是直接指定了路径,则直接通过open_cloexec函数打开。
我们由浅入深地进行分析,先来看第2个函数__intel_open_device_pci__legacy。
__intel_open_device__legacy函数在同文件中实现,代码如下:
- static int __intel_open_device__legacy(const struct pci_device *pci)
- {
- char id[20];
- int ret;
-
- snprintf(id, sizeof(id),
- "pci:%04x:%02x:%02x.%d",
- pci->domain, pci->bus, pci->dev, pci->func);
-
- ret = drmCheckModesettingSupported(id);
- if (ret) {
- if (load_i915_kernel_module() == 0)
- ret = drmCheckModesettingSupported(id);
- if (ret)
- return -1;
- /* Be nice to the user and load fbcon too */
- (void)xf86LoadKernelModule("fbcon");
- }
-
- return fd_set_nonblock(drmOpen(NULL, id));
- }
一上来先通过snprintf函数生成id,id的内容为"pci:xxxx:xx:xx.x"。4个为x的部分分别代表域、总线、设备和功能。通过lspci命令可以看到相关内容,笔者电脑中的信息为:
- $ lspci | cut -d : -f1-3
- 0000:00:00.0 Host bridge
- 0000:00:02.0 VGA compatible controller
- 0000:00:04.0 Signal processing controller
- 0000:00:06.0 System peripheral
- 0000:00:07.0 PCI bridge
- 0000:00:0d.0 USB controller
- 0000:00:0d.2 USB controller
- 0000:00:0e.0 RAID bus controller
- 0000:00:14.0 USB controller
- 0000:00:14.2 RAM memory
- 0000:00:14.3 Network controller
- 0000:00:15.0 Serial bus controller
- 0000:00:15.3 Serial bus controller
- 0000:00:16.0 Communication controller
- 0000:00:17.0 System peripheral
- 0000:00:1d.0 PCI bridge
- 0000:00:1d.1 PCI bridge
- 0000:00:1f.0 ISA bridge
- 0000:00:1f.3 Multimedia audio controller
- 0000:00:1f.4 SMBus
- 0000:00:1f.5 Serial bus controller
- 0000:2b:00.0 Ethernet controller
- 0000:2c:00.0 Unassigned class [ff00]
- 10000:e0:06.0 PCI bridge
- 10000:e0:17.0 SATA controller
- 10000:e1:00.0 Non-Volatile memory controller
因此,对于比着电脑来说,id的值应该为"pci:0000:00:02.0"(信息取自于VGA那一行)。
接下来调用drmCheckModesettingSupported函数对生成的id进行检查,看modesetting是否支持。drmCheckModesettingSupported函数当然不在xf86-video-intel源码中,也不在xorg-server源码中。那么它属于哪个包?
仍然用之前的方法,在/usr/include/下进行搜索,结果如下:
- $ grep -rn "drmCheckModesettingSupported" /usr/include/
- /usr/include/xf86drmMode.h:403:extern int drmCheckModesettingSupported(const char *busid);
而xf86drmMode.h来自于libdrm。链接暨上游地址为:
drmCheckModesettingSupported函数源码如下:
- /*
- * checks if a modesetting capable driver has attached to the pci id
- * returns 0 if modesetting supported.
- * -EINVAL or invalid bus id
- * -ENOSYS if no modesetting support
- */
- drm_public int drmCheckModesettingSupported(const char *busid)
- {
- #if defined (__linux__)
- char pci_dev_dir[1024];
- int domain, bus, dev, func;
- DIR *sysdir;
- struct dirent *dent;
- int found = 0, ret;
-
- ret = sscanf(busid, "pci:%04x:%02x:%02x.%d", &domain, &bus, &dev, &func);
- if (ret != 4)
- return -EINVAL;
-
- sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/drm",
- domain, bus, dev, func);
-
- sysdir = opendir(pci_dev_dir);
- if (sysdir) {
- dent = readdir(sysdir);
- while (dent) {
- if (!strncmp(dent->d_name, "controlD", 8)) {
- found = 1;
- break;
- }
-
- dent = readdir(sysdir);
- }
- closedir(sysdir);
- if (found)
- return 0;
- }
-
- sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/",
- domain, bus, dev, func);
-
- sysdir = opendir(pci_dev_dir);
- if (!sysdir)
- return -EINVAL;
-
- dent = readdir(sysdir);
- while (dent) {
- if (!strncmp(dent->d_name, "drm:controlD", 12)) {
- found = 1;
- break;
- }
-
- dent = readdir(sysdir);
- }
-
- closedir(sysdir);
- if (found)
- return 0;
- #elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
- char sbusid[1024];
- char oid[128];
- int i, modesetting, ret;
- size_t len;
-
- /* How many GPUs do we expect in the machine ? */
- for (i = 0; i < 10; i++) {
- snprintf(oid, sizeof(oid), "hw.dri.%d.busid", i);
- len = sizeof(sbusid);
- ret = sysctlbyname(oid, sbusid, &len, NULL, 0);
- if (ret == -1) {
- if (errno == ENOENT)
- continue;
- return -EINVAL;
- }
- if (strcmp(sbusid, busid) != 0)
- continue;
- snprintf(oid, sizeof(oid), "hw.dri.%d.modesetting", i);
- len = sizeof(modesetting);
- ret = sysctlbyname(oid, &modesetting, &len, NULL, 0);
- if (ret == -1 || len != sizeof(modesetting))
- return -EINVAL;
- return (modesetting ? 0 : -ENOSYS);
- }
- #elif defined(__DragonFly__)
- return 0;
- #elif defined(__OpenBSD__)
- int fd;
- struct drm_mode_card_res res;
- drmModeResPtr r = 0;
-
- if ((fd = drmOpen(NULL, busid)) < 0)
- return -EINVAL;
-
- memset(&res, 0, sizeof(struct drm_mode_card_res));
-
- if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) {
- drmClose(fd);
- return -errno;
- }
-
- drmClose(fd);
- return 0;
- #endif
- return -ENOSYS;
- }