master ohmu/fastfetch-openbsd / src / detection / gpu / gpu_bsd.c
ohmu  ·  2026-10-15
  1#include "gpu.h"
  2#include "gpu_driver_specific.h"
  3
  4#include "common/debug.h"
  5#include "common/io.h"
  6
  7#include <string.h>
  8#include <sys/pciio.h>
  9#include <fcntl.h>
 10#if __has_include(<dev/pci/pcireg.h>)
 11    #include <dev/pci/pcireg.h> // FreeBSD
 12#else
 13    #include <bus/pci/pcireg.h> // DragonFly
 14#endif
 15
 16static const char* detectByPci(const FFGPUOptions* options, FFlist* gpus) {
 17    FF_AUTO_CLOSE_FD int fd = open("/dev/pci", O_RDONLY | O_CLOEXEC);
 18    if (fd < 0) {
 19        FF_DEBUG("open(\"/dev/pci\") failed: %s", strerror(errno));
 20        return "open(\"/dev/pci\", O_RDONLY | O_CLOEXEC, 0) failed";
 21    }
 22
 23    struct pci_conf confs[128];
 24    struct pci_match_conf match = {
 25        .pc_class = PCIC_DISPLAY,
 26        .flags = PCI_GETCONF_MATCH_CLASS,
 27    };
 28    struct pci_conf_io pcio = {
 29        .pat_buf_len = sizeof(match),
 30        .num_patterns = 1,
 31        .patterns = &match,
 32        .match_buf_len = sizeof(confs),
 33        .matches = confs,
 34    };
 35
 36    if (ioctl(fd, PCIOCGETCONF, &pcio) < 0) {
 37        FF_DEBUG("ioctl(PCIOCGETCONF) failed: %s", strerror(errno));
 38        return "ioctl(fd, PCIOCGETCONF, &pc) failed";
 39    }
 40
 41    if (pcio.status == PCI_GETCONF_ERROR) {
 42        FF_DEBUG("ioctl(fd, PCIOCGETCONF, &pc) returned error");
 43        return "ioctl(fd, PCIOCGETCONF, &pc) returned error";
 44    }
 45
 46    for (uint32_t i = 0; i < pcio.num_matches; ++i) {
 47        struct pci_conf* pc = &confs[i];
 48
 49        if (pc->pc_sel.pc_func > 0 && pc->pc_subclass == 0x80 /*PCI_CLASS_DISPLAY_OTHER*/) {
 50            continue; // Likely an auxiliary display controller (#2034)
 51        }
 52
 53        FFGPUResult* gpu = FF_LIST_ADD(FFGPUResult, *gpus);
 54        ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(pc->pc_vendor));
 55        ffStrbufInit(&gpu->name);
 56        ffStrbufInitS(&gpu->driver, pc->pd_name);
 57        ffStrbufInitStatic(&gpu->platformApi, "/dev/pci");
 58        ffStrbufInit(&gpu->memoryType);
 59        gpu->index = FF_GPU_INDEX_UNSET;
 60        gpu->temperature = FF_GPU_TEMP_UNSET;
 61        gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
 62        gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET;
 63        gpu->type = FF_GPU_TYPE_UNKNOWN;
 64        gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
 65        gpu->deviceId = ffGPUPciAddr2Id(pc->pc_sel.pc_domain, pc->pc_sel.pc_bus, pc->pc_sel.pc_dev, pc->pc_sel.pc_func);
 66        gpu->frequency = FF_GPU_FREQUENCY_UNSET;
 67        gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET;
 68
 69        ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId) {
 70                                                    .domain = (uint32_t) pc->pc_sel.pc_domain,
 71                                                    .bus = pc->pc_sel.pc_bus,
 72                                                    .device = pc->pc_sel.pc_dev,
 73                                                    .func = pc->pc_sel.pc_func,
 74                                                });
 75
 76        if (gpu->name.length == 0) {
 77            if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) {
 78                ffGPUQueryAmdGpuName(pc->pc_device, pc->pc_revid, gpu);
 79            }
 80            if (gpu->name.length == 0) {
 81                ffGPUFillVendorAndName(pc->pc_subclass, pc->pc_vendor, pc->pc_device, gpu);
 82            }
 83        }
 84
 85        ffGPUDetectTypeByVendorAndName(gpu);
 86    }
 87
 88    return nullptr;
 89}
 90
 91const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus) {
 92#if FF_HAVE_DRM
 93    if (options->detectionMethod == FF_GPU_DETECTION_METHOD_AUTO) {
 94        ffGPUDetectByDrmBSD(options, gpus);
 95        if (gpus->length > 0) {
 96            return nullptr;
 97        }
 98    }
 99#endif
100
101    return detectByPci(options, gpus);
102}