• xf86-video-intel源码分析7 —— intel_device.c和intel_driver.h(2)


    接上一篇文章《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函数,再列一下代码:

    1. static int __intel_open_device(const struct pci_device *pci, const char *path)
    2. {
    3. int fd;
    4. if (path == NULL) {
    5. if (pci == NULL)
    6. return -1;
    7. fd = __intel_open_device__pci(pci);
    8. if (fd == -1)
    9. fd = __intel_open_device__legacy(pci);
    10. } else
    11. fd = open_cloexec(path);
    12. return fd;
    13. }

    可以看到,函数共分为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函数在同文件中实现,代码如下:

    1. static int __intel_open_device__legacy(const struct pci_device *pci)
    2. {
    3. char id[20];
    4. int ret;
    5. snprintf(id, sizeof(id),
    6. "pci:%04x:%02x:%02x.%d",
    7. pci->domain, pci->bus, pci->dev, pci->func);
    8. ret = drmCheckModesettingSupported(id);
    9. if (ret) {
    10. if (load_i915_kernel_module() == 0)
    11. ret = drmCheckModesettingSupported(id);
    12. if (ret)
    13. return -1;
    14. /* Be nice to the user and load fbcon too */
    15. (void)xf86LoadKernelModule("fbcon");
    16. }
    17. return fd_set_nonblock(drmOpen(NULL, id));
    18. }

    一上来先通过snprintf函数生成id,id的内容为"pci:xxxx:xx:xx.x"。4个为x的部分分别代表域、总线、设备和功能。通过lspci命令可以看到相关内容,笔者电脑中的信息为:

    1. $ lspci | cut -d : -f1-3
    2. 0000:00:00.0 Host bridge
    3. 0000:00:02.0 VGA compatible controller
    4. 0000:00:04.0 Signal processing controller
    5. 0000:00:06.0 System peripheral
    6. 0000:00:07.0 PCI bridge
    7. 0000:00:0d.0 USB controller
    8. 0000:00:0d.2 USB controller
    9. 0000:00:0e.0 RAID bus controller
    10. 0000:00:14.0 USB controller
    11. 0000:00:14.2 RAM memory
    12. 0000:00:14.3 Network controller
    13. 0000:00:15.0 Serial bus controller
    14. 0000:00:15.3 Serial bus controller
    15. 0000:00:16.0 Communication controller
    16. 0000:00:17.0 System peripheral
    17. 0000:00:1d.0 PCI bridge
    18. 0000:00:1d.1 PCI bridge
    19. 0000:00:1f.0 ISA bridge
    20. 0000:00:1f.3 Multimedia audio controller
    21. 0000:00:1f.4 SMBus
    22. 0000:00:1f.5 Serial bus controller
    23. 0000:2b:00.0 Ethernet controller
    24. 0000:2c:00.0 Unassigned class [ff00]
    25. 10000:e0:06.0 PCI bridge
    26. 10000:e0:17.0 SATA controller
    27. 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/下进行搜索,结果如下:

    1. $ grep -rn "drmCheckModesettingSupported" /usr/include/
    2. /usr/include/xf86drmMode.h:403:extern int drmCheckModesettingSupported(const char *busid);

    而xf86drmMode.h来自于libdrm。链接暨上游地址为:

    Mesa / drm · GitLab

    drmCheckModesettingSupported函数源码如下:

    1. /*
    2. * checks if a modesetting capable driver has attached to the pci id
    3. * returns 0 if modesetting supported.
    4. * -EINVAL or invalid bus id
    5. * -ENOSYS if no modesetting support
    6. */
    7. drm_public int drmCheckModesettingSupported(const char *busid)
    8. {
    9. #if defined (__linux__)
    10. char pci_dev_dir[1024];
    11. int domain, bus, dev, func;
    12. DIR *sysdir;
    13. struct dirent *dent;
    14. int found = 0, ret;
    15. ret = sscanf(busid, "pci:%04x:%02x:%02x.%d", &domain, &bus, &dev, &func);
    16. if (ret != 4)
    17. return -EINVAL;
    18. sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/drm",
    19. domain, bus, dev, func);
    20. sysdir = opendir(pci_dev_dir);
    21. if (sysdir) {
    22. dent = readdir(sysdir);
    23. while (dent) {
    24. if (!strncmp(dent->d_name, "controlD", 8)) {
    25. found = 1;
    26. break;
    27. }
    28. dent = readdir(sysdir);
    29. }
    30. closedir(sysdir);
    31. if (found)
    32. return 0;
    33. }
    34. sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/",
    35. domain, bus, dev, func);
    36. sysdir = opendir(pci_dev_dir);
    37. if (!sysdir)
    38. return -EINVAL;
    39. dent = readdir(sysdir);
    40. while (dent) {
    41. if (!strncmp(dent->d_name, "drm:controlD", 12)) {
    42. found = 1;
    43. break;
    44. }
    45. dent = readdir(sysdir);
    46. }
    47. closedir(sysdir);
    48. if (found)
    49. return 0;
    50. #elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
    51. char sbusid[1024];
    52. char oid[128];
    53. int i, modesetting, ret;
    54. size_t len;
    55. /* How many GPUs do we expect in the machine ? */
    56. for (i = 0; i < 10; i++) {
    57. snprintf(oid, sizeof(oid), "hw.dri.%d.busid", i);
    58. len = sizeof(sbusid);
    59. ret = sysctlbyname(oid, sbusid, &len, NULL, 0);
    60. if (ret == -1) {
    61. if (errno == ENOENT)
    62. continue;
    63. return -EINVAL;
    64. }
    65. if (strcmp(sbusid, busid) != 0)
    66. continue;
    67. snprintf(oid, sizeof(oid), "hw.dri.%d.modesetting", i);
    68. len = sizeof(modesetting);
    69. ret = sysctlbyname(oid, &modesetting, &len, NULL, 0);
    70. if (ret == -1 || len != sizeof(modesetting))
    71. return -EINVAL;
    72. return (modesetting ? 0 : -ENOSYS);
    73. }
    74. #elif defined(__DragonFly__)
    75. return 0;
    76. #elif defined(__OpenBSD__)
    77. int fd;
    78. struct drm_mode_card_res res;
    79. drmModeResPtr r = 0;
    80. if ((fd = drmOpen(NULL, busid)) < 0)
    81. return -EINVAL;
    82. memset(&res, 0, sizeof(struct drm_mode_card_res));
    83. if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) {
    84. drmClose(fd);
    85. return -errno;
    86. }
    87. drmClose(fd);
    88. return 0;
    89. #endif
    90. return -ENOSYS;
    91. }

  • 相关阅读:
    运动规划问答 -路径规划
    招商银行余额截图生成器在线,虚拟金额中国农业邮政建设工商,易语言开源例子
    C练题笔记之:Leetcode-137. 只出现一次的数字 II
    猿创征文|AnimeGANv2 照片动漫化:如何基于 PyTorch 和神经网络给 GirlFriend 制作漫画风头像?
    Elasticsearch:使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation (二)
    自学 TypeScript 第三天 使用webpack打包 TS 代码
    被Gartner列入十大战略技术趋势的“行业云”,不再是个伪命题?
    数据库知识点整合
    .net 温故知新:Asp.Net Core WebAPI 入门使用及介绍
    Builder模式
  • 原文地址:https://blog.csdn.net/phmatthaus/article/details/128036808