#include #include #include #include #include #include #include #include #include #include #define DEVDRI_DIR "/dev/dri" int get_device_abspath_from_fd(int fd, char *abspath, size_t *abspath_len) { int ret, found; DIR *dir; struct stat st; struct dirent *dp; char path[256]; size_t path_len; ret = fstat(fd, &st); if (ret != 0) return (-1); if (!S_ISCHR(st.st_mode)) { errno = EBADF; return (-1); } dir = opendir(DEVDRI_DIR); if (dir == NULL) return (-1); found = 0; while ((dp = readdir(dir)) != NULL) { struct stat tmp_st; if (dp->d_name[0] == '.') continue; path_len = strlen(DEVDRI_DIR); strcpy(path, DEVDRI_DIR); path[path_len++] = '/'; path[path_len] = '\0'; strcpy(path + path_len, dp->d_name); path_len += dp->d_namlen; path[path_len] = '\0'; ret = stat(path, &tmp_st); if (ret != 0) continue; if (st.st_dev == tmp_st.st_dev && st.st_ino == tmp_st.st_ino) { found = 1; break; } } closedir(dir); if (!found) { errno = ENOENT; return -(1); } if (abspath) { if (*abspath_len < path_len) { *abspath_len = path_len; errno = ENOMEM; return (-1); } memcpy(abspath, path, path_len); } if (abspath_len) *abspath_len = path_len; return (0); } int get_driver_name_from_fd(int fd, char *driver_name, size_t *driver_name_len) { int ret, i; struct stat st; char sysctl_name[32], sysctl_value[128]; size_t sysctl_value_len, name_len; long dev; ret = fstat(fd, &st); if (ret != 0) return (-1); if (!S_ISCHR(st.st_mode)) { errno = EBADF; return (-1); } for (i = 0; i < 16; i++) { sprintf(sysctl_name, "hw.dri.%d.name", i); sysctl_value_len = sizeof(sysctl_value); ret = sysctlbyname(sysctl_name, sysctl_value, &sysctl_value_len, NULL, 0); if (ret != 0) continue; for (name_len = 0; name_len < sysctl_value_len && sysctl_value[name_len] != ' '; ++name_len) ; if (driver_name != NULL) { if (*driver_name_len < name_len) { *driver_name_len = name_len; errno = ENOMEM; return (-1); } memcpy(driver_name, sysctl_value, name_len); } if (driver_name_len) *driver_name_len = name_len; dev = strtol(sysctl_value + name_len, NULL, 16); if (dev == (long)st.st_rdev) return (i); } errno = ENOENT; return (-1); } int get_device_pciid_from_fd(int fd, unsigned int *vendor_id, unsigned int *device_id) { int i, ret, dev, domain, bus, slot, function; char sysctl_name[32], sysctl_value[128]; size_t sysctl_value_len; dev = get_driver_name_from_fd(fd, NULL, NULL); if (dev < 0) return (-1); sprintf(sysctl_name, "hw.dri.%d.busid", dev); sysctl_value_len = sizeof(sysctl_value); ret = sysctlbyname(sysctl_name, sysctl_value, &sysctl_value_len, NULL, 0); if (ret != 0) return (-1); ret = sscanf(sysctl_value, "pci:%d:%d:%d.%d", &domain, &bus, &slot, &function); if (ret != 4) { errno = ENOENT; return (-1); } for (i = 0; i < 16; ++i) { sprintf(sysctl_name, "dev.vgapci.%d.%%location", i); sysctl_value_len = sizeof(sysctl_value); ret = sysctlbyname(sysctl_name, sysctl_value, &sysctl_value_len, NULL, 0); if (ret != 0) continue; int tmp_slot, tmp_function; ret = sscanf(sysctl_value, "slot=%d function=%d %*s", &tmp_slot, &tmp_function); if (ret != 2 || tmp_slot != slot || tmp_function != function) continue; sprintf(sysctl_name, "dev.vgapci.%d.%%parent", i); sysctl_value_len = sizeof(sysctl_value); ret = sysctlbyname(sysctl_name, sysctl_value, &sysctl_value_len, NULL, 0); if (ret != 0) continue; int tmp_bus; ret = sscanf(sysctl_value, "pci%d", &tmp_bus); if (ret != 1 || tmp_bus != bus) continue; break; } if (i == 16) { errno = ENOENT; return (-1); } sprintf(sysctl_name, "dev.vgapci.%d.%%pnpinfo", i); sysctl_value_len = sizeof(sysctl_value); ret = sysctlbyname(sysctl_name, sysctl_value, &sysctl_value_len, NULL, 0); if (ret != 0) return (-1); ret = sscanf(sysctl_value, "vendor=0x%04x device=0x%04x", vendor_id, device_id); if (ret != 2) { errno = EINVAL; return (-1); } return (0); } int main(int argc, char *argv[]) { int i, fd, ret; unsigned int vendor_id, device_id; char device_path[256], driver_name[16]; size_t device_path_len, driver_name_len; if (argc < 2) { fprintf(stderr, "Syntax: %s \n", argv[0]); } for (i = 1; i < argc; ++i) { printf("===> %s\n", argv[i]); fd = open(argv[i], O_RDWR); if (fd < 0) { perror(argv[i]); continue; } device_path_len = sizeof(device_path); ret = get_device_abspath_from_fd(fd, device_path, &device_path_len); if (ret < 0) { perror("get_device_abspath_from_fd"); continue; } driver_name_len = sizeof(driver_name); ret = get_driver_name_from_fd(fd, driver_name, &driver_name_len); if (ret < 0) { perror("get_driver_name_from_fd"); continue; } ret = get_device_pciid_from_fd(fd, &vendor_id, &device_id); if (ret < 0) { perror("get_device_pciid_from_fd"); continue; } printf(" device path: %.*s (%zu)\n", (int)device_path_len, device_path, device_path_len); printf(" driver name: %.*s (%zu)\n", (int)driver_name_len, driver_name, driver_name_len); printf(" vendor ID: 0x%04x\n", vendor_id); printf(" device ID: 0x%04x\n", device_id); close(fd); } return (0); }