Files
fastfetch/src/detection/gpu/gpu_pci.c
T
李通洲 e0eba8ce21 Chore: run clang-format
```bash
find . -type f \( -name "*.c" -o -name "*.h" -o -name "*.cpp" -o -name "*.hpp" \) ! -path "src/3rdparty/*" -print0 | xargs -0 clang-format -i
```
2026-03-29 10:03:32 +08:00

247 lines
8.2 KiB
C

#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 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);
}