diff options
| author | sumuel <samuel@yakubos.org> | 2026-08-17 20:44:55 +0000 |
|---|---|---|
| committer | sumuel <samuel@yakubos.org> | 2026-08-17 20:44:55 +0000 |
| commit | 76424950e373d3b04ac3dd13019151bfba3e8423 (patch) | |
| tree | 4c3cfdbda039e592b9186be3e28f8d7cfd439e8a /src/detection/gpu/gpu_pci.c | |
Add the files
Diffstat (limited to 'src/detection/gpu/gpu_pci.c')
| -rw-r--r-- | src/detection/gpu/gpu_pci.c | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/src/detection/gpu/gpu_pci.c b/src/detection/gpu/gpu_pci.c new file mode 100644 index 0000000..63cd877 --- /dev/null +++ b/src/detection/gpu/gpu_pci.c @@ -0,0 +1,251 @@ +#include "gpu.h" +#include "common/io.h" +#include "common/properties.h" +#include "common/memrchr.h" + +#include <stdlib.h> +#ifdef __FreeBSD__ + #include <paths.h> + #ifndef _PATH_LOCALBASE + #define _PATH_LOCALBASE "/usr/local" + #endif +#elif __OpenBSD__ + #define _PATH_LOCALBASE "/usr/local" +#elif __NetBSD__ + #define _PATH_LOCALBASE "/usr/pkg" +#endif + +#if FF_HAVE_EMBEDDED_PCIIDS + #include "fastfetch_pciids.c.inc" +#endif +#if FF_HAVE_EMBEDDED_AMDGPUIDS + #include "fastfetch_amdgpuids.c.inc" +#endif + +#define FF_STR_INDIR(x) #x +#define FF_STR(x) FF_STR_INDIR(x) + +static const FFstrbuf* loadPciIds() { + static FFstrbuf pciids; + + if (pciids.chars) { + return &pciids; + } + ffStrbufInit(&pciids); + +#ifdef FF_CUSTOM_PCI_IDS_PATH + + ffReadFileBuffer(FF_STR(FF_CUSTOM_PCI_IDS_PATH), &pciids); + +#else // FF_CUSTOM_PCI_IDS_PATH + + #if __linux__ + ffReadFileBuffer(FASTFETCH_TARGET_DIR_USR "/share/hwdata/pci.ids", &pciids); + if (pciids.length == 0) { + ffReadFileBuffer(FASTFETCH_TARGET_DIR_USR "/share/misc/pci.ids", &pciids); // debian? + if (pciids.length == 0) { + ffReadFileBuffer(FASTFETCH_TARGET_DIR_USR "/local/share/hwdata/pci.ids", &pciids); + } + } + #elif __OpenBSD__ || __FreeBSD__ || __NetBSD__ + ffReadFileBuffer(_PATH_LOCALBASE "/share/hwdata/pci.ids", &pciids); + if (pciids.length == 0) { + ffReadFileBuffer(_PATH_LOCALBASE "/share/pciids/pci.ids", &pciids); + } + #elif __sun + ffReadFileBuffer(FASTFETCH_TARGET_DIR_ROOT "/usr/share/hwdata/pci.ids", &pciids); + #elif __HAIKU__ + ffReadFileBuffer(FASTFETCH_TARGET_DIR_ROOT "/system/data/hwdata/pci.ids", &pciids); + #endif + +#endif // FF_CUSTOM_PCI_IDS_PATH + + return &pciids; +} + +static void parsePciIdsFile(const FFstrbuf* content, uint8_t subclass, uint16_t vendor, uint16_t device, FFGPUResult* gpu) { + if (content->length) { + char buffer[32]; + + // Search for vendor + uint32_t len = (uint32_t) snprintf(buffer, ARRAY_SIZE(buffer), "\n%04x ", vendor); + char* start = (char*) memmem(content->chars, content->length, buffer, len); + char* end = content->chars + content->length; + if (start) { + start += len; + end = memchr(start, '\n', (uint32_t) (end - start)); + if (!end) { + end = content->chars + content->length; + } + if (!gpu->vendor.length) { + ffStrbufSetNS(&gpu->vendor, (uint32_t) (end - start), start); + } + + start = end; // point to '\n' of vendor + end = start + 1; // point to start of devices + // find the start of next vendor + while (end[0] == '\t' || end[0] == '#') { + end = strchr(end, '\n'); + if (!end) { + end = content->chars + content->length; + break; + } else { + end++; + } + } + + // Search for device + len = (uint32_t) snprintf(buffer, ARRAY_SIZE(buffer), "\n\t%04x ", device); + start = memmem(start, (size_t) (end - start), buffer, len); + if (start) { + start += len; + end = memchr(start, '\n', (uint32_t) (end - start)); + if (!end) { + end = content->chars + content->length; + } + + char* closingBracket = end - 1; + if (*closingBracket == ']') { + char* openingBracket = memrchr(start, '[', (size_t) (closingBracket - start)); + if (openingBracket) { + openingBracket++; + ffStrbufSetNS(&gpu->name, (uint32_t) (closingBracket - openingBracket), openingBracket); + } + } + if (!gpu->name.length) { + ffStrbufSetNS(&gpu->name, (uint32_t) (end - start), start); + } + } + } + } + + if (!gpu->name.length) { + const char* subclassStr; + switch (subclass) { + case 0 /*PCI_CLASS_DISPLAY_VGA*/: + subclassStr = " (VGA compatible)"; + break; + case 1 /*PCI_CLASS_DISPLAY_XGA*/: + subclassStr = " (XGA compatible)"; + break; + case 2 /*PCI_CLASS_DISPLAY_3D*/: + subclassStr = " (3D)"; + break; + default: + subclassStr = ""; + break; + } + + ffStrbufSetF(&gpu->name, "%s Device %04X%s", gpu->vendor.length ? gpu->vendor.chars : "Unknown", device, subclassStr); + } +} + +#if FF_HAVE_EMBEDDED_PCIIDS +static inline int pciDeviceCmp(const uint16_t* key, const FFPciDevice* element) { + return (int) *key - (int) element->id; +} + +static bool loadPciidsInc(uint8_t subclass, uint16_t vendor, uint16_t device, FFGPUResult* gpu) { + for (const FFPciVendor* pvendor = ffPciVendors; pvendor->name; pvendor++) { + if (pvendor->id != vendor) { + continue; + } + + if (!gpu->vendor.length) { + ffStrbufSetS(&gpu->vendor, pvendor->name); + } + + const FFPciDevice* pdevice = (const FFPciDevice*) bsearch(&device, pvendor->devices, pvendor->nDevices, sizeof(*pdevice), (void*) pciDeviceCmp); + + if (pdevice) { + uint32_t nameLen = (uint32_t) strlen(pdevice->name); + const char* closingBracket = pdevice->name + nameLen - 1; + if (*closingBracket == ']') { + const char* openingBracket = memrchr(pdevice->name, '[', nameLen - 1); + if (openingBracket) { + openingBracket++; + ffStrbufSetNS(&gpu->name, (uint32_t) (closingBracket - openingBracket), openingBracket); + } + } + if (!gpu->name.length) { + ffStrbufSetNS(&gpu->name, nameLen, pdevice->name); + } + return true; + } + + if (!gpu->name.length) { + const char* subclassStr; + switch (subclass) { + case 0 /*PCI_CLASS_DISPLAY_VGA*/: + subclassStr = " (VGA compatible)"; + break; + case 1 /*PCI_CLASS_DISPLAY_XGA*/: + subclassStr = " (XGA compatible)"; + break; + case 2 /*PCI_CLASS_DISPLAY_3D*/: + subclassStr = " (3D)"; + break; + default: + subclassStr = ""; + break; + } + + ffStrbufSetF(&gpu->name, "%s Device %04X%s", gpu->vendor.length ? gpu->vendor.chars : "Unknown", device, subclassStr); + } + return true; + } + return false; +} +#endif + +void ffGPUFillVendorAndName(uint8_t subclass, uint16_t vendor, uint16_t device, FFGPUResult* gpu) { + if (vendor == 0x1234 && device == 0x1111 && subclass == 0) { // Not exist in pci.ids + ffStrbufSetStatic(&gpu->name, "Virtual Video Controller"); + return; + } + +#if FF_HAVE_EMBEDDED_PCIIDS + bool ok = loadPciidsInc(subclass, vendor, device, gpu); + if (ok) { + return; + } +#endif + return parsePciIdsFile(loadPciIds(), subclass, vendor, device, gpu); +} + +#if FF_HAVE_EMBEDDED_AMDGPUIDS +static inline int amdGpuCmp(const uint32_t* key, const FFArmGpuProduct* element) { + // Maximum value of *key is 0x00FFFFFF. `(int) *key` should never overflow + return (int) *key - (int) element->id; +} + +static bool loadAmdGpuIdsInc(uint16_t deviceId, uint8_t revision, FFGPUResult* gpu) { + uint32_t key = (deviceId << 8u) | revision; + FFArmGpuProduct* product = bsearch(&key, ffAmdGpuProducts, ARRAY_SIZE(ffAmdGpuProducts), sizeof(*ffAmdGpuProducts), (void*) amdGpuCmp); + if (product) { + ffStrbufSetS(&gpu->name, product->name); + return true; + } + return false; +} +#endif + +static void parseAmdGpuIdsFile(uint16_t deviceId, uint8_t revision, FFGPUResult* gpu) { + char query[32]; + snprintf(query, ARRAY_SIZE(query), "%X,\t%X,", (unsigned) deviceId, (unsigned) revision); +#ifdef FF_CUSTOM_AMDGPU_IDS_PATH + ffParsePropFile(FF_STR(FF_CUSTOM_AMDGPU_IDS_PATH), query, &gpu->name); +#else + ffParsePropFileData("libdrm/amdgpu.ids", query, &gpu->name); +#endif +} + +void ffGPUQueryAmdGpuName(uint16_t deviceId, uint8_t revisionId, FFGPUResult* gpu) { +#if FF_HAVE_EMBEDDED_AMDGPUIDS + bool ok = loadAmdGpuIdsInc(deviceId, revisionId, gpu); + if (ok) { + return; + } +#endif + return parseAmdGpuIdsFile(deviceId, revisionId, gpu); +} |