Compare commits

...

221 Commits

Author SHA1 Message Date
Carter Li 8b40a81e22 Merge pull request #1826 from fastfetch-cli/dev
Release: v2.47.0
2025-07-03 14:05:23 +08:00
李通洲 8be64714ba OS (Linux): remove duplicated code 2025-07-03 11:03:14 +08:00
李通洲 fe5d739cba Doc: update README [ci skip] 2025-07-03 10:51:42 +08:00
李通洲 dba0672a11 CMake: remove the unused option ENABLE_CPUUSAGE_PERFLIB 2025-07-03 10:47:44 +08:00
李通洲 3ed6acf3ca Release: v2.47.0 2025-07-03 10:45:41 +08:00
李通洲 8c74c54bb0 README 2025-07-03 10:27:44 +08:00
Carter Li 818473102c Logo (Builtin): always use FG_DEFAULT on title and keys 2025-07-03 09:39:32 +08:00
Carter Li f1cc4a7805 Logo (Builtin): fix colors of raw Linux logo 2025-07-03 09:36:39 +08:00
Carter Li c574af97a4 Logo (Builtin): fix colors of DragonFly 2025-07-03 09:33:04 +08:00
Carter Li 74ae84e719 Revert "Logo (Builtin): :%s/FG_WHITE/FG_DEFAULT/g"
This reverts commit bdbc885811.
2025-07-03 09:03:23 +08:00
李通洲 98738b6920 CPUUsage (Windows): detect perflib support dynamically based on OS version 2025-07-02 19:40:22 +08:00
李通洲 2e5769def2 OS (Linux): add support of Xubuntu
Fix #1825
2025-07-02 09:41:07 +08:00
李通洲 18a6929662 CPUUsage (Windows): disable ENABLE_CPUUSAGE_PERFLIB by default
Because Windows 7 doesn't support it
2025-07-01 22:08:08 +08:00
李通洲 0e61d1134d CMake: fix typo 2025-07-01 21:05:37 +08:00
李通洲 4abb183735 CPUUsage(Windows): add new method using Windows Performance Library 2025-07-01 20:53:46 +08:00
李通洲 d5b56be4ff CMake (SunOS): drop pciaccess dependency 2025-07-01 20:32:45 +08:00
李通洲 1854953d8c Chore (Windows): move perflib_.h to somewhere global 2025-07-01 14:57:40 +08:00
李通洲 2406015c81 Terminal (Linux): ignore init and systemd 2025-06-30 19:41:59 +08:00
李通洲 ec7f14ab96 CpuUsage (Windows): refine KernelTime calculation by removing unused DPC and interrupt time 2025-06-30 19:37:04 +08:00
李通洲 d94cdf4424 CpuUsage (Linux / BSD): include interrupt and softirq times in CPU usage calculations 2025-06-30 19:36:46 +08:00
李通洲 40e57b7698 IO: increase PROC_FILE_BUFFSIZ to avoid possible short reads 2025-06-30 19:16:08 +08:00
李通洲 974c658fff README: add the OpenBSD and DragonFly installation method [ci skip]
Fix https://github.com/fastfetch-cli/fastfetch/issues/1819#issuecomment-3015070008
2025-06-28 23:39:01 +08:00
李通洲 ad0ddfd7f1 Media (macOS): support old macOS version 2025-06-27 16:00:27 +08:00
李通洲 1da8367f55 Media (macOS): simplify now playing handling
Also improve performance
2025-06-27 14:28:45 +08:00
李通洲 bdbc885811 Logo (Builtin): :%s/FG_WHITE/FG_DEFAULT/g
To improve visibility on white background
2025-06-26 22:36:15 +08:00
李通洲 86e5a5997b Display (FreeBSD): silence a compiler warning 2025-06-26 21:44:06 +08:00
李通洲 9832a0e45b GPU (FreeBSD): fix compiling when libdrm is not available
Fix #1820
2025-06-26 21:34:34 +08:00
李通洲 addf674621 OS (Linux): append version string for Ubuntu variants 2025-06-26 21:31:16 +08:00
李通洲 863c5583ef GPU (OpenBSD): fix pci.ids file location
Fix #1819

Signed-off-by: kevlo <kevlo@openbsd.org>
2025-06-25 13:45:49 +08:00
李通洲 45cbc6de83 OS (macOS): force reporting 26 on macOS Tahoe
Fix #1809
2025-06-25 09:19:08 +08:00
李通洲 e68f766b4d OS (Linux): improve RPIOS detection
Ref: https://github.com/fastfetch-cli/fastfetch/issues/1816#issuecomment-2996316164
2025-06-23 22:10:50 +08:00
李通洲 29d7a1acac OS (Linux): use ffStrbufSetStatic where applicatable 2025-06-23 19:41:57 +08:00
李通洲 8d59d14b80 OS (Linux): clean up dietpi related code 2025-06-23 19:41:31 +08:00
Carter Li ed1883909a OS (Linux): detect DietPi
Fix #1816
2025-06-23 18:30:04 +08:00
李通洲 049701a8a9 CI (FreeBSD): run with 14.3 2025-06-23 16:13:40 +08:00
Carter Li 13b7bc89eb Sound (SunOS): rework; drop pulseaudio dependency 2025-06-22 20:35:29 +08:00
Carter Li 92fe44183d Shell (SunOS): ignore leading - 2025-06-22 12:12:49 +08:00
Carter Li 8ebc980c17 GPU (SunOS): simplify 2025-06-22 11:20:19 +08:00
Carter Li dbeb338bda PhysicalDisk (SunOS): rework; support more device types 2025-06-22 11:14:29 +08:00
Carter Li 65ff11a8d0 PhysicalDisk (SunOS): add support 2025-06-22 01:16:50 +08:00
Carter Li 7a73211484 Logo (Builtin): use FG_DEFAULT instead of FG_WHITE 2025-06-21 23:51:40 +08:00
Carter Li ca049997b1 GPU (SunOS): rework GPU detection 2025-06-21 23:22:37 +08:00
李通洲 a9f021ccb9 Chore: remove useless semicolons 2025-06-21 20:46:51 +08:00
Carter Li 55249c2294 BIOS (SunOS): detect BIOS type 2025-06-21 20:46:51 +08:00
李通洲 c13da56959 OS (macOS): remove useless code 2025-06-20 19:28:03 +08:00
Carter Li 665c7cd5d3 Packaging: update debian stuff [ci skip] 2025-06-20 15:02:23 +08:00
Carter Li 469e21cce9 Merge pull request #1813 from fastfetch-cli/dev
Release: v2.46.0
2025-06-20 14:30:06 +08:00
李通洲 925e09c88a Doc: update changelog [ci skip] 2025-06-20 14:28:33 +08:00
李通洲 488454c1aa Logo (Builtin): simplify kali linux 2025-06-20 14:19:05 +08:00
李通洲 c67c52d606 Logo (Builtin): add Kalpa Desktop
Fix #1807
2025-06-20 14:18:21 +08:00
李通洲 e4e11ee509 Release: v2.46.0 2025-06-20 09:51:54 +08:00
李通洲 a3e2592555 Doc: update help.json 2025-06-20 09:51:40 +08:00
Carter Li e0e966dadf Logo (Builtin): rename hydra framework to hydrapwk
Fix #1812
2025-06-20 08:59:53 +08:00
李通洲 b079a8643b Chore: code cleanups 2025-06-19 22:41:30 +08:00
apocelipes 3291a9945f Global: add missing O_CLOEXEC to open() 2025-06-19 22:40:06 +08:00
李通洲 68fd21d0e4 GPU (Linux): fix an issue which vram_usage is bigger t han vram_visible 2025-06-19 22:00:48 +08:00
李通洲 0e1ef96992 GPU (Linux): detect shared vram usage of AMD GPU 2025-06-19 15:54:26 +08:00
李通洲 c377872438 GPU (Linux): correctly call radeon driver 2025-06-19 15:43:37 +08:00
李通洲 4f42d38e4d GPU (FreeBSD): fix mem leaks 2025-06-18 20:20:49 +08:00
李通洲 7b2243496b GPU (Windows): fix build 2025-06-18 18:53:29 +08:00
Carter Li 960a817d03 GPU (Linux): fix building without features 2025-06-18 18:37:30 +08:00
Carter Li 6917f9479e GPU (Linux / FreeBSD): add DRM detection support for old radeon driver
Ref: #1810
2025-06-18 16:41:02 +08:00
Carter Li 8559cc45eb GPU (Linux / FreeBSD): unifies DRM related code and code clean up 2025-06-18 10:01:32 +08:00
李通洲 40e33c676d GPU (FreeBSD): support detection by DRM [wip] 2025-06-17 20:58:09 +08:00
李通洲 d20371040e WM (FreeBSD): fix Hyprland version detection 2025-06-17 20:38:10 +08:00
李通洲 71faf1c7e3 GPU (macOS): detect Metal 4 support 2025-06-17 14:07:18 +08:00
李通洲 d182f3f743 OS (macOS): seems macOS 26 Beta 1 still reports itself as macOS 16. Honor it. 2025-06-17 14:01:22 +08:00
李通洲 39e009b945 CI: upgrade OpenBSD version 2025-06-17 09:30:14 +08:00
李通洲 a1873f3e9e CI: split amd64 and arm64 builds
So we can test both platforms in CI
2025-06-17 09:01:38 +08:00
李通洲 636bcaaaf9 Kmod: remove Chinese comments [ci skip] 2025-06-17 08:43:09 +08:00
李通洲 3fcbd80ef0 Board (macOS): detect board-id if available
Ref: https://github.com/GuillaumeGomez/sysinfo/pull/1545
2025-06-17 00:06:31 +08:00
李通洲 38887e7fbd Logo (Builtin): add GhostFreak
Fix #1801
2025-06-15 12:28:45 +08:00
AVSISP da958e11f9 Logo (Builtin): added AnushOS (#1806)
* Added AnushOS to builtin.c

Added AnushOS config to builtin.c

* Create anushos.txt

Added anushos.txt to ASCII logos

* Update builtin.c

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-06-15 12:23:27 +08:00
李通洲 c2ed71c4eb Global: set SetErrorMode(SEM_FAILCRITICALERRORS) globally
Fix #1805
2025-06-15 00:00:22 +08:00
ᡥᠠᡳᡤᡳᠶᠠ ᡥᠠᠯᠠ·ᠨᡝᡴᠣ 猫 2e1ddcf9f8 Logo (Builtin): Add HarmonyOS support (#1804)
* Logo (Builtin): add HarmonyOS

* OS (HarmonyOS): detect HarmonyOS

* Update src/detection/os/os_linux.c

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update os_linux.c

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-14 09:03:57 +08:00
Carter Li f1cc2d124c Packages (OpenBSD): fix counting by ignoring hidden folders 2025-06-13 20:38:51 +08:00
Techflash 1e32a95f83 CPU (NetBSD): properly support PowerPC (#1802)
Some devices store their CPU name in hw.model, so check that as well
before giving up.  Tested on NetBSD 10.1 evbppc/wii, and allows it to
detect the CPU as "750 (Revision 2.0)".

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-06-11 00:15:40 -05:00
CopticFelo 9e959bc57f WM (MacOS): Added Aerospace WM detection 2025-06-10 11:22:31 +08:00
李通洲 e68406ee22 DE (macOS): report Liquid Glass on macOS 26+ 2025-06-10 10:56:13 +08:00
李通洲 ba69e316b2 OS (MacOS): add macOS 26 Tahoe 2025-06-10 10:48:35 +08:00
李通洲 f3e8e8af52 Logo (Builtin): detect and add TrueNAS Scale 2025-06-10 10:22:13 +08:00
李通洲 c9adab3892 OS (Linux): detect Raspberry Pi OS
Fix #1773
2025-06-10 09:55:13 +08:00
李通洲 c8d1d29017 Disk (Linux): hide /boot/firmware by default 2025-06-10 09:54:11 +08:00
Carter Li 541acca7c0 Logo (Builtin): add xenia_old; update colors of xenia
#1797
2025-06-10 09:13:21 +08:00
Derek Passen ddf5099461 TerminalFont: support rio terminal emulator (#1789)
* Enable terminal font detection for rio terminal emulator

https://rioterm.com
https://rioterm.com/docs/config
https://rioterm.com/docs/config#fonts

* Update src/detection/terminalfont/terminalfont.c

Fix default rio font name

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-06-08 00:00:03 +08:00
李通洲 781a692b06 JsonSchema: document swap.separate 2025-06-07 19:23:25 +08:00
李通洲 9c37f1b370 CPU (Windows): use perflib.h instead of pdh.h for querying CPU temp
Fix #1787
2025-06-07 19:17:46 +08:00
Carter Li a66c26f4df Logo (Builtin): improve colors of bedrock_small
Fix #1790
2025-06-07 17:39:45 +08:00
Carter Li 3bd750bedf Host (Linux): detect Linux Binary Compatibility on FreeBSD
Fix #1786
2025-06-06 15:38:46 +08:00
Carter Li 4a1ada604c Host (Linux): more detailed info of WSL 2025-06-06 14:49:32 +08:00
Noah Michaels e5f57a34a2 Logo (Builtin): Add Fedora2_small (#1785)
* Add 1 more small Fedora logo

* Update builtin.c

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-06-05 20:12:44 -05:00
Carter Li 20a3737dce Packaging: update debian stuff [ci skip] 2025-06-05 10:59:16 +08:00
Carter Li e0452d9db5 Merge pull request #1784 from fastfetch-cli/dev
Release: v2.45.0
2025-06-05 10:47:05 +08:00
李通洲 d8e74ba84c Release: v2.45.0 2025-06-05 10:13:56 +08:00
Carter Li 04b13096ac Swap (Haiku): detect detailed info 2025-06-04 22:01:16 +08:00
李通洲 64d4035cae Chore (Haiku): don't use hard-coded page size 2025-06-04 21:26:37 +08:00
Carter Li 5e0ba57f53 Disk (BSD): silence compiler warnings 2025-06-05 04:55:12 +08:00
李通洲 d89263c218 Swap (DragonFly): add support 2025-06-04 20:51:21 +08:00
Carter Li 6a42588786 Swap (SunOS): detect detailed info 2025-06-04 19:36:22 +08:00
Carter Li 5883bf359c Swap (OpenBSD): detect detailed info 2025-06-04 19:05:02 +08:00
Carter Li 6a6b4070ca Swap (Linux): add fallback for Android 2025-06-04 18:35:53 +08:00
Carter Li 2c80cd6d29 Swap (Linux): support detailed info 2025-06-04 16:44:10 +08:00
Carter Li fa4b00b027 Swap (FreeBSD): detect detailed info 2025-06-04 15:30:03 +08:00
李通洲 5fdc924b5d Swap (macOS): detect detailed info 2025-06-04 15:07:05 +08:00
李通洲 3d4a117093 Swap: support separated output 2025-06-04 15:02:02 +08:00
李通洲 7ec0c664c5 Swap (Windows): detect detailed info 2025-06-04 15:01:37 +08:00
李通洲 9d2df589b5 Smbios (DragonFly): acquire SMBIOS info from /dev/mem 2025-06-04 14:22:33 +08:00
李通洲 7107d08e92 DE (DragonFly): fix build 2025-06-04 14:22:33 +08:00
Carter Li 4c34f99c12 Swap (Linux): use /proc/swaps
Preparing for detailed swap usage
2025-06-04 10:37:07 +08:00
Carter Li d7a8c92b46 CI (Linux): fix musl build 2025-06-04 09:05:04 +08:00
李通洲 bbb29ff766 CI (Linux): add missing deps for musl 2025-06-03 21:15:48 +08:00
amnexya 35235b9557 Logo (Builtin): Update logo for Xenia Linux (#1783)
* Update Xenia Linux logo

* Update builtin.c for xenia colours

* Update src/logo/builtin.c

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-03 21:11:50 +08:00
Carter Li 6b94605804 Disk (BSD): don't ignore sshfs 2025-06-03 18:58:38 +08:00
Carter Li 4b2fa07fdc Packages (Linux): fix dnf package count detection (v2) 2025-06-03 10:53:02 +08:00
Carter Li e203f4eeaf Packages (Linux): fix dnf package count detection
Fix #1777
2025-06-03 09:33:43 +08:00
李通洲 8db70b40e2 CI: add back disabled DFBSD 2025-06-02 22:00:32 +08:00
李通洲 1f967849e5 CMake: fix build of FreeBSD 2025-06-02 19:15:14 +08:00
李通洲 d60b2ddfd4 Disk (Linux): don't ignore sshfs
Fix #1776
2025-06-02 19:09:24 +08:00
李通洲 fb68d8a841 CI (Haiku): add build
Disabled due to https://github.com/cross-platform-actions/action/issues/104
2025-06-02 18:48:16 +08:00
李通洲 047411ba87 CMake: build FreeBSD pkg package 2025-06-02 15:56:18 +08:00
李通洲 08ed14b42a Logo: support "type": "command-raw"
Fix #1780
2025-06-02 11:46:43 +08:00
李通洲 d94a41cc1b Chore: tidy 2025-06-02 11:46:43 +08:00
Anshnk 81b7fb06c1 Fix typo, 15,2 isn't a real mac model number 2025-06-02 11:02:10 +08:00
李通洲 c8debccd16 DE (FreeBSD): support KDE version detection 2025-06-02 10:19:36 +08:00
Carter Li 2853bd15c0 Logo (Builtin): add void2
Ported from hyfetch
2025-05-31 23:28:16 +08:00
Carter Li 2f4146fde8 Logo (Builtin): update default colors of voidlinux
Fix  #1775
2025-05-31 23:18:43 +08:00
李通洲 eeceade14e Logo (Builtin): add rhel_small
Fix #1774
2025-05-31 13:39:40 +08:00
李通洲 1875c78e96 WM: support I3 version detection 2025-05-31 10:41:38 +08:00
李通洲 f389864e17 WM: support FVWM version detection 2025-05-31 10:16:26 +08:00
李通洲 b9317734b9 WM: support CTWM version detection 2025-05-31 10:02:45 +08:00
李通洲 4df4a1de78 Logo (Builtin): add Starry Linux
Fix #1771
2025-05-30 13:56:52 +08:00
李通洲 0cd8c6ead6 Chore: code cleanup 2025-05-30 10:33:37 +08:00
李通洲 f8479dae94 GPU: add more GPU vendors 2025-05-30 10:33:26 +08:00
李通洲 a7d623fa75 JsonSchema: update <module>Format [ci skip] 2025-05-29 10:13:57 +08:00
李通洲 7a8ffb27bd Packages: split code 2025-05-26 15:12:47 +08:00
Carter Li 73c0347469 Merge remote-tracking branch 'origin/dev' into dev 2025-05-26 15:00:58 +08:00
Carter Li fde5f3bd0f Packaging: update debian stuff [ci skip] 2025-05-26 15:00:06 +08:00
李通洲 9e1b1302fb Host (Android): add detection for OnePlus market name
Fix #1768
2025-05-26 14:22:47 +08:00
Carter Li 7e235b6be0 Merge pull request #1766 from fastfetch-cli/dev
Release: v2.44.0
2025-05-23 16:10:12 +08:00
李通洲 f43e1fd614 Release: v2.44.0 2025-05-23 15:41:22 +08:00
Carter Li c7b061eebd DisplayServer (Linux): fix errors on KDE beta
Fix #1765
2025-05-22 09:41:35 +08:00
Carter Li a0f579072f Disk: add --disk-hide-fs
Fix #1762
2025-05-21 16:40:42 +08:00
Carter Li d439ce8eb5 Disk: rename hiddenFolder to hideFolder; add docs 2025-05-21 15:09:19 +08:00
Carter Li e2a714732a Disk: add hiddenFolders (2) 2025-05-21 15:00:42 +08:00
asmeron a993a6f126 Logo (Builtin): Add UBLinux Logo (#1764)
* Logo (Builtin): Add UBLinux Logo

* Update builtin.c

---------

Co-authored-by: asmeron <asmeron@ublinux.com>
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-05-20 21:50:34 -05:00
李通洲 8eb8f710d0 Disk: add option --disk-hidden-folders 2025-05-19 18:32:56 +08:00
李通洲 526868e355 Disk (Linux): don't hard code hidden mount points 2025-05-19 15:25:06 +08:00
李通洲 768238cb46 TerminalShell (Linux): ignore script
Fix #1761
2025-05-17 18:04:41 +08:00
Xavier Xiong 2d938042d0 Logo (Builtin): Add Kylin Logo (Remove ANSI codes) (#1760)
* Logo (Builtin): Add Kylin Logo

* Remove all ANSI escape codes from ASCII Logo

* Add color prefix to kylin logo
2025-05-16 01:05:42 -05:00
李通洲 9a54d92e9f Stat: use ESC 7/8 instead of CSI s/u
Fix Apple Terminal compatibility #1755
2025-05-16 10:33:58 +08:00
Collin 839abab744 Doc: Add information of where to find example config files (#1759) [ci skip] 2025-05-15 19:58:36 -05:00
Md. Iftakhar Awal Chowdhury c054570308 fish complete: add --logo-color-[1-9] completion (#1754)
* fish complete: add `--logo-color-[1-9]` completion

* reverted unnecessary changes
2025-05-15 03:18:19 -05:00
Carter Li ed69a7059b Packaging: update debian stuff [ci skip] 2025-05-14 09:51:44 +08:00
Carter Li 6b92659512 Merge pull request #1752 from fastfetch-cli/dev
Release: v2.43.0
2025-05-14 09:41:33 +08:00
Carter Li 7e04305d1c CI: silence spell check errors 2025-05-14 09:25:15 +08:00
Carter Li 87e13543da GPU (Linux): embed asahi_drm.h 2025-05-14 08:59:53 +08:00
Carter Li 7a2cbc060f 3rdparty (yyjson): upgrade to 0.11.1 2025-05-14 08:52:06 +08:00
Carter Li f22d73d473 PhysicalDisk: trim white spaces of serial 2025-05-13 18:29:46 +08:00
李通洲 e629126d73 Doc: update changelog 2025-05-13 15:52:30 +08:00
李通洲 9ac635e2e6 Media (Windows): detect player name (UMP apps only) 2025-05-13 15:46:33 +08:00
李通洲 1b1b0521f4 Doc: update changelog 2025-05-13 13:49:54 +08:00
李通洲 41d0f61ee0 GPU (AMD): remove usage of ADL2_Adapter_VRAMUsage_Get
It reports dedicated GPU memory usage too.

Ref: https://github.com/GPUOpen-LibrariesAndSDKs/display-library/issues/48
2025-05-13 13:39:42 +08:00
李通洲 9de5d9008b Release: v2.43.0 2025-05-13 10:37:52 +08:00
李通洲 576a9cc6fe Revert "Vulkan: use VK_API_VERSION_* instead of deprecated VK_VERSION_*"
Breaks building with old vulkan-headers

This reverts commit 36b0fdbcda.
2025-05-13 10:02:38 +08:00
李通洲 bd61d08afe Sound (macOS): report the volume of muted device as 0% 2025-05-13 09:35:13 +08:00
李通洲 4672b78481 Sound: don't show 255 in custom format
Fix #1750
2025-05-13 09:30:30 +08:00
李通洲 36b0fdbcda Vulkan: use VK_API_VERSION_* instead of deprecated VK_VERSION_* 2025-05-13 09:29:21 +08:00
Carter Li 7626ef6eaa GPU (Linux): fix CI errors
F**k Ubuntu
2025-05-10 21:40:33 +08:00
Carter Li 115108b3f1 GPU (Linux): detect core usage when libamdgpu is not available 2025-05-10 20:57:51 +08:00
Carter Li 154f9f462b GPU (Linux): detect VRAM type of AMD GPUs 2025-05-10 20:57:51 +08:00
Marvin Friedrich a96a9fc31d Smbios: fix transitive include for loff_t (#1746) 2025-05-10 10:49:22 +08:00
李通洲 23b43244c5 GPU (AMD): seems ADL2_Adapter_VRAMUsage_Get reports system mem usage only, not full memory usage
Because VRAMUsage reports a value which is smaller than DedicatedVRAMUsage
2025-05-09 22:46:31 +08:00
Carter Li 9dfb404a0d GPU (AMD): more verbose logs 2025-05-09 22:01:29 +08:00
Carter Li ff3028c656 GPU: don't hide unknown type of GPUs by default
Fix #1742
2025-05-09 21:58:41 +08:00
Carter Li 2f706ed494 Smbios: discard usless values 2025-05-09 21:55:31 +08:00
Carter Li 06427ee62b Media (Linux): fix duplicated playback status 2025-05-09 19:23:28 +08:00
李通洲 fe66eb3df0 GPU (Windows): fix incorrect used shared memory size 2025-05-08 23:20:53 +08:00
李通洲 6e1ab12399 Memory / Swap: always initialize local variables 2025-05-08 23:17:22 +08:00
Samuli Thomasson 484e05eae3 GPU: optionally hide unknown GPUs (#1742)
The current default behavior of not hiding any GPUs is retained. The new
feature of hiding unknown or unrecognized GPUs can be enabled with
hide-type = "unknown".
2025-05-07 22:06:47 +08:00
Joe_ 5d3fb98072 Logo (Builtin): add Hydra Framework logo (#1740)
* Added: Hydra Framework logo

* Remove extra line: hydra.txt
2025-05-07 03:02:36 -05:00
李通洲 0c30590088 Builtin (Logo): new AthenaOS logo
Fix #1741
2025-05-07 10:45:21 +08:00
李通洲 20cd4ce125 Logo (Builtin): sd '\$\{c(\d)\}' '$$$1' * 2025-05-07 10:44:05 +08:00
apocelipes 1c7aa89228 TerminalShell: use ffBinaryExtractStrings result as possible (#1739) 2025-05-06 18:49:29 +08:00
apocelipes f270255770 DisplayServer (Linux): fix xcb_connect error handling (#1735) 2025-05-06 03:18:53 -05:00
李通洲 4b62a3c75b 3rdparty: upgrade yyjson to 0.11.0 2025-05-06 16:12:58 +08:00
李通洲 1557f0c556 Media (macOS): support macOS 15.4
Fix #1737
2025-05-06 16:12:58 +08:00
Carter Li ef7f61309f GPU (Linux): fix asahi linux support again
Found in kernel-headers-6.14.4-400.asahi.fc42.aarch64
2025-05-06 09:27:54 +08:00
李通洲 f59491b25d Disk (Linux): fix possible bug on 32-bit platforms
Fix #1734
2025-05-05 22:05:22 +08:00
李通洲 e3592eb2c3 CPU (FreeBSD): simplify physical core count detection 2025-05-05 13:41:12 +08:00
Carter Li 305776eb94 CPU (SunOS): support physical core count and package count detection 2025-05-02 14:24:30 +08:00
Carter Li 599e0d393d Display: use height to calculate scale factor
Seems more accurate
2025-05-01 21:28:04 +08:00
李通洲 561574ae94 CPU (Windows): always use XxxW 2025-04-30 16:10:53 +08:00
李通洲 3dd78422eb Global: Improve ARRAY_SIZE macro using __is_array 2025-04-30 14:47:37 +08:00
李通洲 5c546ab8e7 Parsing: silence compiler warnings 2025-04-30 14:14:28 +08:00
Carter Li 3e9274040d Packaging: update debian stuff [ci skip] 2025-04-30 14:12:26 +08:00
Carter Li 630d876e2d Merge pull request #1722 from fastfetch-cli/dev
Release: v2.42.0
2025-04-29 14:05:36 +08:00
李通洲 1938be86ff Wifi (NetBSD): fix the ambiguous comment 2025-04-29 13:53:45 +08:00
李通洲 0980d5f0ad Wifi (BSD): correctly prioritize Wi-Fi protocol detection
by using an `if-else if` chain
2025-04-29 13:50:53 +08:00
李通洲 d8c1b3b61b Release: v2.42.0 2025-04-29 10:38:07 +08:00
李通洲 969523ae8a BIOS: normalize the module name
Fix #1721
2025-04-29 10:26:19 +08:00
李通洲 5d960ec744 Uptime: fix non-normalized time being shown
Fix #1720
2025-04-29 10:22:19 +08:00
apocelipes 3b36b8ca57 Global: use ARRAY_SIZE (#1718) 2025-04-28 21:22:04 -05:00
apocelipes 05f14764e6 Bluetooth (Linux): silence an unused variable warning (#1717) 2025-04-28 22:50:46 +08:00
apocelipes 3a180b24e3 Platform: fix a memory leak (#1716) 2025-04-28 22:49:31 +08:00
李通洲 02ab58e001 Doc: update changelog [ci skip] 2025-04-24 09:31:05 +08:00
Carter Li fd158b41e1 Logo (Chafa): fix setting chafa.symbols
Fix #1709
2025-04-24 09:02:45 +08:00
李通洲 89e0ede12f Camera (OpenBSD): add support 2025-04-23 20:09:08 +08:00
李通洲 4d7b2410ef CPU (OpenBSD): fix CPU temperature detection 2025-04-22 21:19:22 +08:00
李通洲 c1f6a2f755 Refactor: inline printError into ffPrintError and remove unused static helper 2025-04-22 14:30:39 +08:00
李通洲 9c455c3b0f Wifi (FreeBSD): fix possible mem leaks 2025-04-20 12:41:06 +08:00
Carter Li d4ea9dfd21 Wifi (NetBSD): add support
Untested
2025-04-20 12:40:47 +08:00
李通洲 08071e6e7e Wifi (OpenBSD): fix file name 2025-04-20 11:49:40 +08:00
李通洲 ec87174f30 CPU (NetBSD): add one more method to detect CPU frequency 2025-04-20 11:43:39 +08:00
李通洲 835e5b51c9 CPU (SunOS): detect CPU temp
Untested
2025-04-20 11:12:08 +08:00
Noa Himesaka 07c5ef255e Logo (Builtin): Add Codex Linux support (#1701)
* feat: add Codex Linux

* Codex.txt: remove empty lines

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-04-19 21:22:28 +08:00
李通洲 476b55c17d Logo (Builtin): remove GoralixOS
Ref: #1699
2025-04-19 21:18:13 +08:00
李通洲 4a53cfa312 Logo (Builtin): add Aurora
Fix #1700
2025-04-19 21:11:54 +08:00
李通洲 50ea515476 PhysicalDisk (Linux): don't detect disk type of virtual disks
Fix #1697
2025-04-18 16:10:01 +08:00
xzvf cbd9f72bc8 T2/SDE: upstreaming downstream's logo change (#1695)
* T2/SDE: upstreaming downstream's logo change

T2/SDE port of fastfetch applies two patches, improving the
distribution's logo and adding alternative names. I see no point not
having these upstream.

Downstream's patches are found here:
https://github.com/rxrbln/t2sde/tree/main/package/contrib/fastfetch

The old logo has been renamed to "T2_small".

* Fix ASCII art alignment in t2.txt

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-04-17 22:52:45 +08:00
李通洲 29eaa35f4c Color: support #RGB and #RRGGBB
Fix #1694
2025-04-17 10:48:18 +08:00
Carter Li 97c89c39d3 Packaging: update debian stuff [ci skip] 2025-04-16 13:51:09 +08:00
303 changed files with 11154 additions and 4693 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
[codespell]
check-filenames =
builtin = clear,rare,usage,informal
skip = */.git,*/cmake-build-*,*/.idea,*/completions,*/presets,*/screenshots,*/tests,*/3rdparty,*/logo/ascii
skip = */.git,*/cmake-build-*,*/.idea,*/completions,*/presets,*/screenshots,*/tests,*/3rdparty,*/logo/ascii,./src/detection/gpu/asahi_drm.h
ignore-words-list = iterm,compiletime,unknwn,pengwin,siduction,master,slave,sur,doas,conexant,ags,bu
+131 -9
View File
@@ -383,7 +383,7 @@ jobs:
run: |
cat /etc/alpine-release
uname -a
apk add cmake samurai vulkan-loader-dev libxcb-dev wayland-dev libdrm-dev dconf-dev imagemagick-dev chafa-dev zlib-dev dbus-dev mesa-dev opencl-dev xfconf-dev sqlite-dev networkmanager-dev pulseaudio-dev ddcutil-dev elfutils-dev gcc g++
apk add cmake samurai vulkan-loader-dev libxcb-dev libxrandr-dev rpm-dev wayland-dev libdrm-dev dconf-dev imagemagick-dev chafa-dev zlib-dev dbus-dev mesa-dev opencl-dev xfconf-dev sqlite-dev networkmanager-dev pulseaudio-dev ddcutil-dev elfutils-dev gcc g++
shell: alpine.sh --root {0}
- name: build
@@ -408,9 +408,9 @@ jobs:
name: fastfetch-musl-amd64
path: ./fastfetch-*.*
macos-universal:
name: macOS-universal
runs-on: macos-latest
macos-amd64:
name: macOS-amd64
runs-on: macos-13
permissions:
security-events: write
contents: read
@@ -426,7 +426,7 @@ jobs:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install --overwrite vulkan-loader vulkan-headers molten-vk imagemagick chafa
- name: configure project
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' .
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
- name: build project
run: cmake --build . --target package --verbose -j4
@@ -452,7 +452,54 @@ jobs:
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-macos-universal
name: fastfetch-macos-amd64
path: ./fastfetch-*.*
macos-aarch64:
name: macOS-aarch64
runs-on: macos-latest
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v4
- name: uname -a
run: uname -a
- name: install required packages
run: |
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install --overwrite vulkan-loader vulkan-headers molten-vk imagemagick chafa
- name: configure project
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
- name: build project
run: cmake --build . --target package --verbose -j4
- name: list features
run: ./fastfetch --list-features
- name: run fastfetch
run: time ./fastfetch -c presets/ci.jsonc --stat false
- name: run fastfetch --format json
run: time ./fastfetch -c presets/ci.jsonc --format json
- name: run flashfetch
run: time ./flashfetch
- name: print dependencies
run: otool -L fastfetch
- name: run tests
run: ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-macos-aarch64
path: ./fastfetch-*.*
sunos-amd64:
@@ -505,7 +552,7 @@ jobs:
architecture: x86-64
cpu_count: 4
shell: bash
version: '14.2'
version: '14.3'
run: |
uname -a
sudo pkg update
@@ -542,7 +589,7 @@ jobs:
architecture: x86-64
cpu_count: 4
shell: bash
version: '7.6'
version: '7.7'
run: |
uname -a
sudo pkg_add -r cmake git pkgconf wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 xfconf imagemagick chafa
@@ -597,6 +644,80 @@ jobs:
name: fastfetch-netbsd-amd64
path: ./fastfetch-*.*
dragonfly-amd64:
name: DragonFly-amd64
runs-on: ubuntu-latest
if: false
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v4
- name: run VM
uses: vmactions/dragonflybsd-vm@v1
with:
usesh: yes
prepare: |
uname -a
pkg update
pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl xfce4-conf egl opencl ocl-icd v4l_compat chafa libelf
run: |
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ldd fastfetch
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-dragonfly-amd64
path: ./fastfetch-*.*
haiku-amd64:
name: Haiku-amd64
runs-on: ubuntu-latest
if: false
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v4
- name: run VM
uses: cross-platform-actions/action@master
with:
operating_system: haiku
architecture: x86-64
cpu_count: 4
shell: bash
version: 'r1beta5'
run: |
uname -a
ls -l
pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ldd fastfetch
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-haiku-amd64
path: ./fastfetch-*.*
windows-amd64:
name: Windows-amd64
runs-on: windows-latest
@@ -734,7 +855,8 @@ jobs:
- linux-ppc64le
- linux-s390x
- musl-amd64
- macos-universal
- macos-amd64
- macos-aarch64
- freebsd-amd64
- openbsd-amd64
- netbsd-amd64
+157 -4
View File
@@ -1,12 +1,165 @@
# 2.47.0
Features:
* Various improvements for Solaris / OpenIndiana support
* Support BIOS (UEFI or legacy) type detection (BIOS)
* Support physical disk detection (PhysicalDisk)
* Remove leading `-` from login shells (Shell)
* Improve GPU detection performance (GPU)
* Drop `libpciaccess` dependency
* Use native API to detect sound devices (Sound)
* Drop `PulseAudio` dependency
* Improve DietPi OS and Raspberry Pi OS detection (#1816, OS, Linux)
* Force reporting version 26 on macOS Tahoe (OS, macOS)
* Append version string to Ubuntu variants (OS, Linux)
* Improve performance of media detection for macOS 15.4+ (Media, macOS)
* Increase `PROC_FILE_BUFFSIZ` to avoid possible short reads (Linux)
* Fix potential bugs in `DiskIO`, `NetIO` and `CPUUsage` modules
* Improve accuracy of CPU usage calculations by including interrupt and softirq times (CPUUsage, Linux / *BSD)
* Ignore `init` and `systemd` processes when detecting terminals (Terminal, Linux)
* Improve accuracy of CPU usage detection on Windows 10+ with perflib, which matches values reported by Task Manager (CPUUsage, Windows)
Bugfixes:
* Fix `pci.ids` file location (#1819, GPU, OpenBSD)
* Fix compiling on FreeBSD when `libdrm` support is disabled (#1820, GPU, FreeBSD)
Logos:
* Improve visibility on white-background terminals for some logos by replacing white with the default foreground color
* According to Wikipedia, the default foreground color is implementation-defined. It's usually black for white themes and white for dark themes. However, some terminals, notably Konsole with the default theme, use a different color, which may cause issues with some logos.
* Add Xubuntu
# 2.46.0
Features:
* Support Rio terminal font detection (#1789, TerminalFont, Linux)
* Support GPU detection by DRM on FreeBSD (GPU, FreeBSD)
* Enable by `--gpu-detection-method auto`
* Require proper DRM drivers installed and loaded
* Support PowerPC CPU detection on NetBSD (#1802, CPU, NetBSD)
* Support Aerospace WM detection (#1796, WM, macOS)
* Improve Raspberry Pi OS for RPI5 detection (#1773, OS, Linux)
* Support Linux Binary Compatibility detection on FreeBSD (#1786, Host, Linux)
* Use `board-id` as board name if available (Board, macOS)
* Intel only
* Support shared VRAM usage detection for AMD GPUs (GPU, Linux)
* Use `perflib.h` instead of `pdh.h` for CPU temperature querying to get rid of `pdh.dll` dependency (#1787, CPU, Windows)
* Support GPU info detection for old ATI radeon driver (#1810, GPU, Linux)
* Add macOS 26 Tahoe support (macOS)
* Report macOS 26 code name (OS)
* Report Liquid Glass DE on macOS 26+ (DE)
* Detect Metal 4 support (GPU)
Bugfixes:
* Fix packages counting by ignoring hidden folders (Packages, OpenBSD)
* Fix Hyprland version detection (WM, FreeBSD)
* Don't show `Please insert a disk into drive D:` error dialogs (#1805, Disk, Windows)
* Hide `/boot/firmware` by default (Disk, Linux)
Logos:
* Rename Hydra Framework to HydraPwk (#1812)
* Add AnushOS (#1806)
* Add HarmonyOS (#1804)
* Add GhostFreak (#1801)
* Add TrueNAS Scale (#1795)
* Add Fedora2_small (#1785)
* Add xenia_old; update colors of xenia (#1797)
* Improve colors of bedrock_small (#1790)
* Add Kalpa Desktop (#1807)
# 2.45.0
Features:
* Support OnePlus marketing name detection (#1768, Host, Android)
* Recognize additional GPU vendors (GPU, Linux)
* Support CTWM, FVWM and I3 window manager version detection (WM)
* Support KDE version detection on *BSD (DE, FreeBSD)
* Support `"logo": { "type": "command-raw" }` to run a command and display its output as logo (#1780, Logo)
* Useful for displaying custom logos generated by other programs such as `pokeget`: `{ "type": "command-raw", "source": "pokeget random --hide-name" }`
* Supported in JSONC config file only. `pokeget random --hide-name | fastfetch --file-raw -` should be used in shell.
* Acquire SMBIOS information on DragonFly BSD from `/dev/mem`; legacy BIOS only (PhysicalMemory, DragonFly)
* Support swap usage detection on DragonFly BSD (Swap, DragonFly)
* Support `--swap-separate` to display detailed swap devices on separate lines (Swap)
Bugfixes
* Fix MacBook Air model name (#1779, Host, macOS)
* Don't ignore sshfs mountpoints (#1776, Disk, Linux / FreeBSD)
* Fix dnf package count detection (#1777, Packages, Linux)
Logos:
* Add Starry Linux (#1771)
* Add rhel_small (#1774)
* Update color palette of voidlinux (#1775)
* Add void2
* Update Xenia Linux (#1783)
# 2.44.0
Features:
* Add option `--disk-hide-folders` and `--disk-hide-fs` to hide specific mountpoints and filesystems in Disk module (Disk)
* `--disk-hide-folders` defaults to `/efi:/boot:/boot/efi` on Linux and *BSD. Previously these EFI-related folders were hardcoded to be hidden on Linux.
Bugfixes:
* Fix Apple Terminal compatibility with `--stat` (macOS, #1755)
* Ignore `/usr/bin/script` when detecting shell and terminal (Terminal / Shell, #1761)
* Fix compatibility with KDE Plasma 6.4 which is in beta currently (Display, Linux, #1765)
Logos:
* Add Kylin (#1760)
* Add UBLinux (#1764)
# 2.43.0
Features:
* Support physical core count and package count detection on Solaris (CPU, SunOS)
* Improve physical core count detection on FreeBSD (CPU, FreeBSD)
* Add option to hide unknown GPUs (GPU)
* Detect VRAM type of AMD GPUs on Linux (GPU, Linux)
* Support playing media detection on macOS 15.4 (#1737, Media, macOS)
* Whether it works on newer versions is unknown
* Detect player name for Windows UMP apps (Media, Windows)
Bugfixes:
* Fix disk usage detection on 32-bit Linux (#1734, Disk, Linux)
* Fix compiling on Asahi Linux (GPU, Linux)
* Fix duplicated playback status (Media, Linux)
* Don't show 255 in custom format when muted on macOS (#1750, Sound, macOS)
* Remove shared memory detection for AMD GPUs, which doesn't work as expected (GPU, Windows)
Logos:
* new AthenaOS
* add Hydra Framework
# 2.42.0
Changes:
* Normalize the module name `Bios` to `BIOS` (#1721)
* No configuration file changes are required because fastfetch parses module names case-insensitively.
Bugfixes:
* Disable disk type detection for virtual disks (PhysicalDisk, Linux, #1669)
* Fix incorrect CPU temperature reporting (CPU, OpenBSD)
* Fix setting `logo.chafa.symbols` in JSON configuration (Logo, #1709)
* Fix non-normalized time display (Uptime, #1720)
* Miscellaneous minor fixes
Features:
* Add CPU temperature detection support (CPU, SunOS)
* Improve CPU frequency detection (CPU, NetBSD)
* Add Wi-Fi detection support (Wifi, NetBSD)
* Add Webcam detection support (Camera, OpenBSD)
* Requires root privileges
Logos:
* Remove GoralixOS logo (#1699)
* Add Aurora logo (#1700)
* Add Codex Linux logo (#1701)
# 2.41.0
Changes:
* Due to [the deprecation](https://github.com/actions/runner-images/issues/11101), Linux x86_64 binaries are now built with Ubuntu 22.04 (Glibc 2.35, Debian 12)
* You can always build fastfetch yourself on your own. Please don't report bugs related to this change.
Bugfixes:
* Don't detect disk type for virtual disks (PhysicalDisk, Linux, #1669)
Features:
* Support physical core count detection on non-x86 platforms (CPU, Linux / FreeBSD)
* Support CPU frequency detection on PPC64 (CPU, FreeBSD)
@@ -881,7 +1034,7 @@ Bugfixes:
* Fix some presets
* Better detection for XTerm terminal fonts (#1095, TerminalFont, Linux)
* Remove debug output (#1097, Windows)
* Fix command line option `--gpu-hide-type` doesn't work (#1098, GPU)
* Fix flag `--gpu-hide-type` doesn't work (#1098, GPU)
* Fix wrong date on Raspbian 10 (#1108, DateTime, Linux)
* Use `brightness` instead of `actuall_brightness` when detecting current brightness level (Brightness, Linux)
* Ref: https://bugzilla.kernel.org/show_bug.cgi?id=203905
+49 -27
View File
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
project(fastfetch
VERSION 2.41.0
VERSION 2.47.0
LANGUAGES C
DESCRIPTION "Fast neofetch-like system information tool"
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
@@ -61,7 +61,7 @@ cmake_dependent_option(ENABLE_WAYLAND "Enable wayland-client" ON "LINUX OR FreeB
cmake_dependent_option(ENABLE_XCB_RANDR "Enable xcb-randr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_XRANDR "Enable xrandr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_DRM "Enable libdrm" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_DRM_AMDGPU "Enable libdrm_amdgpu" ON "LINUX" OFF)
cmake_dependent_option(ENABLE_DRM_AMDGPU "Enable libdrm_amdgpu" ON "LINUX OR FreeBSD" OFF)
cmake_dependent_option(ENABLE_GIO "Enable gio-2.0" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_DCONF "Enable dconf" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_DBUS "Enable dbus-1" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR Haiku" OFF)
@@ -76,13 +76,13 @@ cmake_dependent_option(ENABLE_EGL "Enable egl" ON "LINUX OR FreeBSD OR OpenBSD O
cmake_dependent_option(ENABLE_GLX "Enable glx" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS" OFF)
cmake_dependent_option(ENABLE_OPENCL "Enable opencl" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR WIN32 OR ANDROID OR SunOS OR Haiku" OFF)
cmake_dependent_option(ENABLE_FREETYPE "Enable freetype" ON "ANDROID" OFF)
cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX OR SunOS" OFF)
cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX" OFF)
cmake_dependent_option(ENABLE_DDCUTIL "Enable ddcutil" ON "LINUX" OFF)
cmake_dependent_option(ENABLE_DIRECTX_HEADERS "Enable DirectX headers for WSL" ON "LINUX" OFF)
cmake_dependent_option(ENABLE_ELF "Enable libelf" ON "LINUX OR ANDROID OR DragonFly OR Haiku" OFF)
cmake_dependent_option(ENABLE_THREADS "Enable multithreading" ON "Threads_FOUND" OFF)
cmake_dependent_option(ENABLE_LIBZFS "Enable libzfs" ON "LINUX OR FreeBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_PCIACCESS "Enable libpciaccess" ON "NetBSD OR OpenBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_PCIACCESS "Enable libpciaccess" ON "NetBSD OR OpenBSD" OFF)
option(ENABLE_SYSTEM_YYJSON "Use system provided (instead of fastfetch embedded) yyjson library" OFF)
option(ENABLE_ASAN "Build fastfetch with ASAN (address sanitizer)" OFF)
@@ -342,7 +342,6 @@ foreach(file ${LOGO_FILES})
fastfetch_load_text("${file}" content)
get_filename_component(file "${file}" NAME_WE)
string(TOUPPER "${file}" file)
string(REGEX REPLACE "\\$\\{c([0-9]+)\\}" "$\\1" content "${content}")
set(LOGO_BUILTIN_H "${LOGO_BUILTIN_H}#define FASTFETCH_DATATEXT_LOGO_${file} ${content}\n")
endforeach()
file(GENERATE OUTPUT logo_builtin.h CONTENT "${LOGO_BUILTIN_H}")
@@ -525,6 +524,7 @@ if(LINUX)
src/detection/displayserver/linux/xlib.c
src/detection/font/font_linux.c
src/detection/gpu/gpu_linux.c
src/detection/gpu/gpu_drm.c
src/detection/gpu/gpu_pci.c
src/detection/gtk_qt/gtk.c
src/detection/host/host_linux.c
@@ -672,6 +672,7 @@ elseif(FreeBSD)
src/detection/displayserver/linux/xlib.c
src/detection/font/font_linux.c
src/detection/gpu/gpu_bsd.c
src/detection/gpu/gpu_drm.c
src/detection/gpu/gpu_pci.c
src/detection/gtk_qt/gtk.c
src/detection/host/host_bsd.c
@@ -783,7 +784,7 @@ elseif(NetBSD)
src/detection/netio/netio_bsd.c
src/detection/opengl/opengl_linux.c
src/detection/os/os_nbsd.c
src/detection/packages/packages_obsd.c
src/detection/packages/packages_nbsd.c
src/detection/poweradapter/poweradapter_nosupport.c
src/detection/processes/processes_nbsd.c
src/detection/gtk_qt/qt.c
@@ -797,8 +798,8 @@ elseif(NetBSD)
src/detection/uptime/uptime_bsd.c
src/detection/users/users_linux.c
src/detection/wallpaper/wallpaper_linux.c
src/detection/wifi/wifi_nosupport.c
src/detection/wm/wm_nosupport.c
src/detection/wifi/wifi_nbsd.c
src/detection/wm/wm_linux.c
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_linux.c
@@ -879,8 +880,8 @@ elseif(OpenBSD)
src/detection/uptime/uptime_bsd.c
src/detection/users/users_obsd.c
src/detection/wallpaper/wallpaper_linux.c
src/detection/wifi/wifi_nbsd.c
src/detection/wm/wm_nosupport.c
src/detection/wifi/wifi_obsd.c
src/detection/wm/wm_linux.c
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_linux.c
@@ -1056,7 +1057,7 @@ elseif(SunOS)
src/detection/bluetoothradio/bluetoothradio_nosupport.c
src/detection/disk/disk_sunos.c
src/detection/dns/dns_linux.c
src/detection/physicaldisk/physicaldisk_nosupport.c
src/detection/physicaldisk/physicaldisk_sunos.c
src/detection/physicalmemory/physicalmemory_linux.c
src/detection/diskio/diskio_sunos.c
src/detection/displayserver/linux/displayserver_linux.c
@@ -1096,7 +1097,7 @@ elseif(SunOS)
src/detection/poweradapter/poweradapter_nosupport.c
src/detection/processes/processes_linux.c
src/detection/gtk_qt/qt.c
src/detection/sound/sound_linux.c
src/detection/sound/sound_sunos.c
src/detection/swap/swap_sunos.c
src/detection/terminalfont/terminalfont_linux.c
src/detection/terminalshell/terminalshell_linux.c
@@ -1589,7 +1590,6 @@ elseif(WIN32)
PRIVATE "winbrand"
PRIVATE "propsys"
PRIVATE "secur32"
PRIVATE "pdh"
)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64")
# WoA only works on Windows 10 or higher
@@ -1632,6 +1632,7 @@ elseif(SunOS)
PRIVATE "proc"
PRIVATE "zfs"
PRIVATE "nvpair"
PRIVATE "devinfo"
)
elseif(ANDROID)
CHECK_LIBRARY_EXISTS(-l:libandroid-wordexp.a wordexp "" HAVE_LIBANDROID_WORDEXP_STATIC)
@@ -1834,10 +1835,26 @@ if (BUILD_TESTS)
PRIVATE libfastfetch
)
add_executable(fastfetch-test-color
tests/color.c
)
target_link_libraries(fastfetch-test-color
PRIVATE libfastfetch
)
add_executable(fastfetch-test-duration
tests/duration.c
)
target_link_libraries(fastfetch-test-duration
PRIVATE libfastfetch
)
enable_testing()
add_test(NAME test-strbuf COMMAND fastfetch-test-strbuf)
add_test(NAME test-list COMMAND fastfetch-test-list)
add_test(NAME test-format COMMAND fastfetch-test-format)
add_test(NAME test-color COMMAND fastfetch-test-color)
add_test(NAME test-duration COMMAND fastfetch-test-duration)
endif()
##################
@@ -1905,17 +1922,17 @@ install(
##################
set(CPACK_GENERATOR "TGZ;ZIP")
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
set(CMAKE_SYSTEM_PROCESSOR "amd64")
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
set(CMAKE_SYSTEM_PROCESSOR "aarch64")
endif()
if(APPLE)
string(TOLOWER "${CMAKE_PROJECT_NAME}-macos-universal" CPACK_PACKAGE_FILE_NAME)
else() # We don't use this in Windows
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
set(CMAKE_SYSTEM_PROCESSOR "amd64")
endif()
if(IS_MUSL)
string(TOLOWER "${CMAKE_PROJECT_NAME}-musl-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME)
else()
string(TOLOWER "${CMAKE_PROJECT_NAME}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME)
endif()
string(TOLOWER "${CMAKE_PROJECT_NAME}-macos-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME) # use macos instead of darwin
elseif(IS_MUSL)
string(TOLOWER "${CMAKE_PROJECT_NAME}-musl-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME)
else()
string(TOLOWER "${CMAKE_PROJECT_NAME}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME)
endif()
if(LINUX)
@@ -1941,12 +1958,17 @@ if(LINUX)
endif()
endif()
find_program(HAVE_RPMBUILD "rpmbuild")
if(HAVE_RPMBUILD)
set(CPACK_GENERATOR "${CPACK_GENERATOR};RPM")
if(NOT IS_MUSL)
find_program(HAVE_RPMBUILD "rpmbuild")
if(HAVE_RPMBUILD)
set(CPACK_GENERATOR "${CPACK_GENERATOR};RPM")
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
endif()
endif()
elseif(FreeBSD)
set(CPACK_FREEBSD_PACKAGE_LICENSE "MIT")
set(CPACK_GENERATOR "${CPACK_GENERATOR};FREEBSD")
endif()
set(CPACK_SET_DESTDIR ON)
+7 -6
View File
@@ -21,6 +21,8 @@ Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for
<img src="screenshots/example3.png" width="48%" align="top" />
<img src="screenshots/example5.png" height="15%" align="top" />
According configuration files for examples are located [here](https://github.com/fastfetch-cli/fastfetch/tree/dev/presets/examples).
There are [screenshots on different platforms](https://github.com/fastfetch-cli/fastfetch/wiki).
## Installation
@@ -67,13 +69,12 @@ If fastfetch is not packaged for your distribution or an outdated version is pac
You may also download the program directly from [the GitHub releases page](https://github.com/fastfetch-cli/fastfetch/releases/latest) in the form of an archive file.
### FreeBSD
### BSD systems
* `pkg install fastfetch`
### NetBSD
* `pkgin in fastfetch`
* FreeBSD: `pkg install fastfetch`
* NetBSD: `pkgin in fastfetch`
* OpenBSD: `pkg_add fastfetch` (Snapshots only)
* DragonFly BSD: `pkg install fastfetch` (Snapshots only)
### Android (Termux)
+8 -1
View File
@@ -62,11 +62,17 @@ end
echo '
import json, subprocess, sys
def main():
data: dict[str, list[dict]] = json.loads(subprocess.check_output(["fastfetch", "--help-raw"]))
for key in data:
for flag in data[key]:
if flag["long"] == "logo-color-[1-9]":
for i in range(1, 10):
print(f"""complete -c fastfetch -d "{flag["desc"]}" -l "logo-color-{i}" -x -a "(__fastfetch_complete_color)" """)
continue
if flag.get("pseudo", False):
continue
@@ -75,7 +81,7 @@ def main():
command_prefix += f""" -o {flag["short"]}"""
if "arg" in flag:
type: str = flag["arg"]["type"];
type: str = flag["arg"]["type"]
if type == "bool":
print(f"{command_prefix} -x -a \"(__fastfetch_complete_bool)\"")
elif type == "color":
@@ -98,6 +104,7 @@ def main():
else:
print(f"{command_prefix} -f")
if __name__ == "__main__":
try:
main()
+48
View File
@@ -1,3 +1,51 @@
fastfetch (2.46.0) jammy; urgency=medium
* Update to 2.46.0
-- Carter Li <zhangsongcui@live.cn> Fri, 20 Jun 2025 15:01:21 +0800
fastfetch (2.45.0) jammy; urgency=medium
* Update to 2.45.0
-- Carter Li <zhangsongcui@live.cn> Thu, 05 Jun 2025 10:56:38 +0800
fastfetch (2.44.0) jammy; urgency=medium
* Update to 2.44.0
-- Carter Li <zhangsongcui@live.cn> Mon, 26 May 2025 14:59:01 +0800
fastfetch (2.43.0) jammy; urgency=medium
* Update to 2.43.0
-- Carter Li <zhangsongcui@live.cn> Wed, 14 May 2025 09:49:50 +0800
fastfetch (2.42.0) jammy; urgency=medium
* Update to 2.42.0
-- Carter Li <zhangsongcui@live.cn> Wed, 30 Apr 2025 14:08:57 +0800
fastfetch (2.41.0) jammy; urgency=medium
* Update to 2.41.0
-- Carter Li <zhangsongcui@live.cn> Wed, 16 Apr 2025 13:42:58 +0800
fastfetch (2.40.4) jammy; urgency=medium
* Update to 2.40.4
-- Carter Li <zhangsongcui@live.cn> Thu, 10 Apr 2025 15:38:21 +0800
fastfetch (2.40.3) jammy; urgency=medium
* Update to 2.40.3
-- Carter Li <zhangsongcui@live.cn> Mon, 07 Apr 2025 09:29:27 +0800
fastfetch (2.40.0) jammy; urgency=medium
* Update to 2.40.0
+1 -1
View File
@@ -1 +1 @@
fastfetch_2.40.0_source.buildinfo universe/utils optional
fastfetch_2.46.0_source.buildinfo universe/utils optional
+17 -2
View File
@@ -115,7 +115,7 @@
"type": "string"
},
"biosFormat": {
"description": "Output format of the module `Bios`. See Wiki for formatting syntax\n 1. {date}: Bios date\n 2. {release}: Bios release\n 3. {vendor}: Bios vendor\n 4. {version}: Bios version\n 5. {type}: Firmware type",
"description": "Output format of the module `BIOS`. See Wiki for formatting syntax\n 1. {date}: Bios date\n 2. {release}: Bios release\n 3. {vendor}: Bios vendor\n 4. {version}: Bios version\n 5. {type}: Firmware type",
"type": "string"
},
"bluetoothFormat": {
@@ -339,7 +339,7 @@
"type": "string"
},
"titleFormat": {
"description": "Output format of the module `Title`. See Wiki for formatting syntax\n 1. {user-name}: User name\n 2. {host-name}: Host name\n 3. {home-dir}: Home directory\n 4. {exe-path}: Executable path of current process\n 5. {user-shell}: User's default shell\n 6. {user-name-colored}: User name (colored)\n 7. {at-symbol-colored}: @ symbol (colored)\n 8. {host-name-colored}: Host name (colored)",
"description": "Output format of the module `Title`. See Wiki for formatting syntax\n 1. {user-name}: User name\n 2. {host-name}: Host name\n 3. {home-dir}: Home directory\n 4. {exe-path}: Executable path of current process\n 5. {user-shell}: User's default shell\n 6. {user-name-colored}: User name (colored)\n 7. {at-symbol-colored}: @ symbol (colored)\n 8. {host-name-colored}: Host name (colored)\n 9. {full-user-name}: Full user name",
"type": "string"
},
"themeFormat": {
@@ -429,6 +429,7 @@
"file-raw",
"data",
"data-raw",
"command-raw",
"sixel",
"kitty",
"kitty-direct",
@@ -1754,6 +1755,14 @@
"type": "string",
"description": "A colon (semicolon on Windows) separated list of folder paths for the disk output\nDefault: auto detection using mount-points\nThis option overrides other `show*` options"
},
"hideFolders": {
"type": "string",
"description": "A colon (semicolon on Windows) separated list of folder paths to hide from the disk output\nDefault: /efi:/boot:/boot/efi"
},
"hideFS": {
"type": "string",
"description": "A colon separated file systems to hide from the disk output"
},
"showExternal": {
"type": "boolean",
"description": "Set if external volume should be printed",
@@ -2053,6 +2062,7 @@
"enum": [
"integrated",
"discrete",
"unknown",
"none"
],
"default": "none"
@@ -2992,6 +3002,11 @@
"const": "swap",
"description": "Print swap (paging file) space usage"
},
"separate": {
"type": "boolean",
"description": "Set if detailed swap devices should be reported on separate lines instead of a summary",
"default": false
},
"percent": {
"$ref": "#/$defs/percent"
},
+4 -1
View File
@@ -52,7 +52,10 @@
},
"memory",
"physicalmemory",
"swap",
{
"type": "swap",
"separate": true
},
"disk",
"btrfs",
"zpool",
+4 -1
View File
@@ -54,7 +54,10 @@
},
"memory",
"physicalmemory",
"swap",
{
"type": "swap",
"separate": true
},
"disk",
"btrfs",
"zpool",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"home": "https://github.com/ibireme/yyjson",
"license": "MIT ( embed in source )",
"version": "0.10.0",
"version": "0.11.1",
"author": "ibireme"
}
+2508 -1264
View File
File diff suppressed because it is too large Load Diff
+800 -570
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -134,7 +134,7 @@ void ffPrintCommandOption(FFdata* data, yyjson_mut_doc* jsonDoc)
int len = snprintf(str, sizeof str, "%.3fms", ms);
if (thres > 0)
snprintf(str, sizeof str, "\e[%sm%.3fms\e[m", (ms <= thres ? FF_COLOR_FG_GREEN : ms <= 2 * thres ? FF_COLOR_FG_YELLOW : FF_COLOR_FG_RED), ms);
printf("\e[s\e[1A\e[9999999C\e[%dD%s\e[u", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
}
}
+1
View File
@@ -105,6 +105,7 @@ void ffStart(void)
ffHideCursor = instance.config.display.hideCursor && !instance.config.display.pipe && !instance.state.resultDoc;
#ifdef _WIN32
SetErrorMode(SEM_FAILCRITICALERRORS);
if (instance.config.display.noBuffer)
setvbuf(stdout, NULL, _IONBF, 0);
else
+1 -2
View File
@@ -19,8 +19,7 @@
#define FF_INVALID_FD (-1)
// procfs's file can be changed between read calls such as /proc/meminfo and /proc/uptime.
// one safe way to read correct data is reading the whole file in a single read syscall
// 8192 comes from procps-ng: https://gitlab.com/procps-ng/procps/-/blob/master/library/meminfo.c?ref_type=heads#L39
#define PROC_FILE_BUFFSIZ 8192
#define PROC_FILE_BUFFSIZ (32 * 1024)
#endif
static inline FFNativeFD FFUnixFD2NativeFD(int unixfd)
+1 -1
View File
@@ -290,7 +290,7 @@ bool ffSuppressIO(bool suppress)
void listFilesRecursively(uint32_t baseLength, FFstrbuf* folder, uint8_t indentation, const char* folderName, bool pretty)
{
FF_AUTO_CLOSE_FD int dfd = open(folder->chars, O_RDONLY);
FF_AUTO_CLOSE_FD int dfd = open(folder->chars, O_RDONLY | O_CLOEXEC);
if (dfd < 0)
return;
+1 -1
View File
@@ -224,7 +224,7 @@ static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc)
int len = snprintf(str, sizeof str, "%.3fms", ms);
if (thres > 0)
snprintf(str, sizeof str, "\e[%sm%.3fms\e[m", (ms <= thres ? FF_COLOR_FG_GREEN : ms <= 2 * thres ? FF_COLOR_FG_YELLOW : FF_COLOR_FG_RED), ms);
printf("\e[s\e[1A\e[9999999C\e[%dD%s\e[u", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
}
}
+30
View File
@@ -177,6 +177,7 @@ void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer)
if (ffCharIsEnglishAlphabet(value[0]))
{
FF_APPEND_COLOR_CODE_COND(reset_, FF_COLOR_MODE_RESET)
else FF_APPEND_COLOR_CODE_COND(bold_, FF_COLOR_MODE_BOLD)
else FF_APPEND_COLOR_CODE_COND(bright_, FF_COLOR_MODE_BOLD)
else FF_APPEND_COLOR_CODE_COND(dim_, FF_COLOR_MODE_DIM)
else FF_APPEND_COLOR_CODE_COND(italic_, FF_COLOR_MODE_ITALIC)
@@ -212,6 +213,35 @@ void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer)
exit(479);
}
}
else if (value[0] == '#')
{
// RGB color
++value;
char* pend = NULL;
uint32_t rgb = (uint32_t) strtoul(value, &pend, 16);
if (pend == value) {
fprintf(stderr, "Error: invalid RGB color code found: %s\n", value);
exit(479);
}
if (pend - value > 6) {
fprintf(stderr, "Error: RGB color code too long: %s\n", value);
exit(479);
}
else if (pend - value == 3) {
rgb = ((rgb & 0xF00) >> 8) * 0x110000 +
((rgb & 0x0F0) >> 4) * 0x001100 +
((rgb & 0x00F) >> 0) * 0x000011;
}
else if (pend - value != 6) {
fprintf(stderr, "Error: invalid RGB color code length: %s\n", value);
exit(479);
}
uint32_t r = rgb >> 16, g = (rgb >> 8) & 0xFF, b = rgb & 0xFF;
ffStrbufAppendF(buffer, FF_COLOR_FG_RGB "%u;%u;%u", r, g, b);
value = pend;
continue;
}
ffStrbufAppendC(buffer, *value);
++value;
+15 -8
View File
@@ -190,19 +190,26 @@ void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, co
}
}
void ffParseDuration(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds, FFstrbuf* result)
void ffParseDuration(uint64_t totalSeconds, FFstrbuf* result)
{
if(days == 0 && hours == 0 && minutes == 0)
if(totalSeconds < 60)
{
ffStrbufAppendF(result, "%u seconds", seconds);
ffStrbufAppendF(result, "%u second", (unsigned) totalSeconds);
if (totalSeconds != 1)
ffStrbufAppendC(result, 's');
return;
}
if(seconds >= 30)
{
minutes++;
seconds = 0;
}
uint32_t seconds = (uint32_t) (totalSeconds % 60);
totalSeconds /= 60;
if (seconds >= 30)
totalSeconds++;
uint32_t minutes = (uint32_t) (totalSeconds % 60);
totalSeconds /= 60;
uint32_t hours = (uint32_t) (totalSeconds % 24);
totalSeconds /= 24;
uint32_t days = (uint32_t) totalSeconds;
if(days > 0)
{
+1 -1
View File
@@ -27,4 +27,4 @@ int8_t ffVersionCompare(const FFVersion* version1, const FFVersion* version2);
void ffParseSize(uint64_t bytes, FFstrbuf* result);
bool ffParseFrequency(uint32_t mhz, FFstrbuf* result);
void ffParseDuration(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds, FFstrbuf* result);
void ffParseDuration(uint64_t totalSeconds, FFstrbuf* result);
+4 -9
View File
@@ -100,7 +100,7 @@ void ffPrintFormat(const char* moduleName, uint8_t moduleIndex, const FFModuleAr
ffStrbufPutTo(&buffer, stdout);
}
static void printError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, va_list arguments)
void ffPrintError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, ...)
{
if(!instance.config.display.showErrors)
return;
@@ -110,7 +110,10 @@ static void printError(const char* moduleName, uint8_t moduleIndex, const FFModu
if(!instance.config.display.pipe)
fputs(FASTFETCH_TEXT_MODIFIER_ERROR, stdout);
va_list arguments;
va_start(arguments, message);
vprintf(message, arguments);
va_end(arguments);
if(!instance.config.display.pipe)
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
@@ -118,14 +121,6 @@ static void printError(const char* moduleName, uint8_t moduleIndex, const FFModu
putchar('\n');
}
void ffPrintError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, ...)
{
va_list arguments;
va_start(arguments, message);
printError(moduleName, moduleIndex, moduleArgs, printType, message, arguments);
va_end(arguments);
}
void ffPrintColor(const FFstrbuf* colorValue)
{
//If the color is not set, this would reset in \033[m, which resets everything.
+4 -2
View File
@@ -279,8 +279,10 @@ void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, cons
psinfo_t proc;
if (ffReadFileData(filePath, sizeof(proc), &proc) == sizeof(proc))
{
ffStrbufSetS(exe, proc.pr_psargs);
ffStrbufSubstrBeforeFirstC(exe, ' ');
const char* args = proc.pr_psargs;
if (args[0] == '-') ++args;
const char* end = strchr(args, ' ');
ffStrbufSetNS(exe, end ? (uint32_t) (end - args) : (uint32_t) strlen(args), args);
}
if (exePath)
+20 -3
View File
@@ -840,6 +840,22 @@
"default": "Auto detection using mount-points"
}
},
{
"long": "disk-hide-folders",
"desc": "A colon (semicolon on Windows) separated list of folder paths to hide from the disk output",
"arg": {
"type": "path",
"default": "/efi:/boot:/boot/efi"
}
},
{
"long": "disk-hide-fs",
"desc": "A colon separated list of file systems to hide from the disk output",
"arg": {
"type": "string",
"default": ""
}
},
{
"long": "disk-show-regular",
"desc": "Specify whether regular volumes should be displayed",
@@ -1128,23 +1144,24 @@
"arg": {
"type": "enum",
"enum": {
"auto": "Query platform-specific graphics APIs. Requires proper GPU drivers to be installed. Not supported on BSDs",
"auto": "Query platform-specific graphics APIs. Requires proper GPU drivers to be installed. Supported on Linux, FreeBSD, Windows and macOS",
"pci": "Search PCI devices, which does not require GPU drivers to be installed. Not supported on Windows and macOS",
"vulkan": "Use Vulkan API. Slow and requires proper Vulkan drivers to be installed. Used for Android",
"opencl": "Use OpenCL API. Slow and requires proper OpenCL drivers to be installed",
"opengl": "Use OpenGL API. Slow and only detects one GPU"
"opengl": "Use OpenGL API. Slow and only detects one GPU. Used for OpenBSD"
},
"default": "auto"
}
},
{
"long": "gpu-hide-type",
"desc": "Specify which types of GPUs should not be displayed",
"desc": "Specify which types of GPUs should not be displayed (default: all GPUs are shown, regardless of recognition)",
"arg": {
"type": "enum",
"enum": {
"integrated": "Hide integrated GPUs",
"discrete": "Hide discrete GPUs",
"unknown": "Hide unknown (unrecognized) GPUs",
"none": "Do not hide any GPUs"
},
"default": "none"
+2 -2
View File
@@ -16,8 +16,8 @@
const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* results)
{
FF_AUTO_CLOSE_FD int fd = open(_PATH_SYSMON, O_RDONLY);
if (fd < 0) return "open(_PATH_SYSMON, O_RDONLY) failed";
FF_AUTO_CLOSE_FD int fd = open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC);
if (fd < 0) return "open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC) failed";
prop_dictionary_t root = NULL;
if (prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &root) < 0)
+2 -2
View File
@@ -8,9 +8,9 @@
const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* result)
{
FF_AUTO_CLOSE_FD int devfd = open("/dev/apm", O_RDONLY);
FF_AUTO_CLOSE_FD int devfd = open("/dev/apm", O_RDONLY | O_CLOEXEC);
if (devfd < 0) return "open(dev/apm, O_RDONLY) failed";
if (devfd < 0) return "open(dev/apm, O_RDONLY | O_CLOEXEC) failed";
struct apm_power_info info = {};
+16
View File
@@ -32,6 +32,10 @@ typedef struct _SYSTEM_BOOT_ENVIRONMENT_INFORMATION
#include <fcntl.h>
#include <unistd.h>
#elif __sun
#include <libdevinfo.h>
#include <sys/sunddi.h>
#endif
typedef struct FFSmbiosBios
@@ -59,6 +63,7 @@ typedef struct FFSmbiosBios
static_assert(offsetof(FFSmbiosBios, ExtendedBiosRomSize) == 0x18,
"FFSmbiosBios: Wrong struct alignment");
const char* ffDetectBios(FFBiosResult* bios)
{
const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable();
@@ -94,6 +99,17 @@ const char* ffDetectBios(FFBiosResult* bios)
default: break;
}
}
#elif __sun
di_node_t rootNode = di_init("/", DINFOPROP);
if (rootNode != DI_NODE_NIL)
{
char* efiVersion = NULL;
if (di_prop_lookup_strings(DDI_DEV_T_ANY, rootNode, "efi-version", &efiVersion) > 0)
ffStrbufSetStatic(&bios->type, "UEFI");
else
ffStrbufSetStatic(&bios->type, "BIOS");
}
di_fini(rootNode);
#elif __HAIKU__ || __OpenBSD__
// Currently SMBIOS detection is supported in legancy BIOS only
ffStrbufSetStatic(&bios->type, "BIOS");
+1 -1
View File
@@ -232,7 +232,7 @@ static uint32_t connectedDevices(void)
#endif
const char* ffDetectBluetooth(FFBluetoothOptions* options, FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */)
const char* ffDetectBluetooth(FF_MAYBE_UNUSED FFBluetoothOptions* options, FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */)
{
#ifdef FF_HAVE_DBUS
int32_t connectedCount = -1;
+13 -3
View File
@@ -9,9 +9,19 @@ const char* ffDetectBoard(FFBoardResult* result)
if (!service)
return "No IOPlatformExpertDevice found";
io_name_t name;
if (IORegistryEntryGetName(service, name) == kIOReturnSuccess)
ffStrbufSetS(&result->name, name);
FF_CFTYPE_AUTO_RELEASE CFTypeRef boardId = IORegistryEntryCreateCFProperty(service, CFSTR("board-id"), kCFAllocatorDefault, kNilOptions);
if (boardId)
ffCfStrGetString(boardId, &result->name);
else
{
io_name_t name;
if (IORegistryEntryGetName(service, name) == kIOReturnSuccess)
ffStrbufSetS(&result->name, name);
}
FF_CFTYPE_AUTO_RELEASE CFStringRef version = IORegistryEntryCreateCFProperty(service, CFSTR("version"), kCFAllocatorDefault, kNilOptions);
if (version)
ffCfStrGetString(version, &result->version);
FF_CFTYPE_AUTO_RELEASE CFTypeRef manufacturer = IORegistryEntryCreateCFProperty(service, CFSTR("manufacturer"), kCFAllocatorDefault, kNilOptions);
if (manufacturer)
+1 -1
View File
@@ -20,7 +20,7 @@
const char* ffDetectBootmgr(FFBootmgrResult* result)
{
FF_AUTO_CLOSE_FD int efifd = open("/dev/efi", O_RDWR);
FF_AUTO_CLOSE_FD int efifd = open("/dev/efi", O_RDWR | O_CLOEXEC);
if (efifd < 0) return "open(/dev/efi) failed";
uint8_t buffer[2048];
+1 -1
View File
@@ -12,7 +12,7 @@ const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFl
for (char i = '0'; i <= '9'; ++i) {
path[strlen("/dev/ttyC")] = i;
FF_AUTO_CLOSE_FD int devfd = open(path, O_RDONLY);
FF_AUTO_CLOSE_FD int devfd = open(path, O_RDONLY | O_CLOEXEC);
if (devfd < 0) {
if (errno == EACCES && i == '0')
+11 -2
View File
@@ -7,6 +7,9 @@
#if FF_HAVE_LINUX_VIDEODEV2
#include <linux/videodev2.h>
#elif __has_include(<sys/videoio.h>) // OpenBSD
#include <sys/videoio.h>
#define FF_HAVE_LINUX_VIDEODEV2 1
#endif
const char* ffDetectCamera(FFlist* result)
@@ -17,9 +20,15 @@ const char* ffDetectCamera(FFlist* result)
for (uint32_t i = 0; i <= 9; ++i)
{
path[ARRAY_SIZE(path) - 2] = (char) (i + '0');
FF_AUTO_CLOSE_FD int fd = open(path, O_RDONLY);
FF_AUTO_CLOSE_FD int fd = open(path, O_RDONLY | O_CLOEXEC);
if (fd < 0)
break;
{
if (errno == ENOENT)
break;
if (errno == ENXIO)
continue;
return "Failed to open /dev/videoN";
}
struct v4l2_capability cap = {};
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0 || !(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
+3 -34
View File
@@ -36,7 +36,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
return "sysctlbyname(hw.model) failed";
cpu->coresLogical = (uint16_t) ffSysctlGetInt("hw.ncpu", 1);
cpu->coresPhysical = 0;
cpu->coresPhysical = (uint16_t) ffSysctlGetInt("kern.smp.cores", 0);
cpu->coresOnline = (uint16_t) ffSysctlGetInt("kern.smp.cpus", cpu->coresLogical);
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
@@ -57,39 +57,8 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
// </children>
// </group>
// </groups>
char* line = NULL;
size_t len = 0;
bool inLvl2 = false, threadGroup = false;
uint32_t cpuCount = 0;
while (ffStrbufGetline(&line, &len, &buffer))
{
if (!inLvl2)
{
if (ffStrStartsWith(line, " <group level=\"2\""))
{
inLvl2 = true;
cpuCount = 0;
threadGroup = false;
}
else if (ffStrStartsWith(line, " <group level=\"1\""))
cpu->packages++;
}
else
{
if (ffStrEquals(line, " </group>"))
{
cpu->coresPhysical += threadGroup ? 1 : cpuCount;
inLvl2 = false;
}
else if (cpuCount == 0 && ffStrStartsWith(line, " <cpu count=\""))
cpuCount = (uint32_t) strtoul(line + strlen(" <cpu count=\""), NULL, 10);
else if (cpuCount > 0 && ffStrStartsWith(line, " <flags>"))
{
if (ffStrContains(line, "<flag name=\"THREAD\">THREAD group</flag>"))
threadGroup = true;
}
}
}
for (char* p = buffer.chars; (p = strstr(p, "\n </group>\n")); ++p)
cpu->packages++;
}
#if FF_HAVE_CPUSET && (__x86_64__ || __i386__)
+1 -1
View File
@@ -474,7 +474,7 @@ FF_MAYBE_UNUSED static const char* detectCPUX86(const FFCPUOptions* options, FFC
static const char* detectPhysicalCores(FFCPUResult* cpu)
{
int dfd = open("/sys/devices/system/cpu/", O_RDONLY | O_DIRECTORY);
int dfd = open("/sys/devices/system/cpu/", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
if (dfd < 0) return "open(\"/sys/devices/system/cpu/\") failed";
FF_AUTO_CLOSE_DIR DIR* dir = fdopendir(dfd);
+5 -3
View File
@@ -18,8 +18,8 @@ static void freePropDict(prop_dictionary_t* pdict)
static const char* detectCpuTemp(double* current)
{
FF_AUTO_CLOSE_FD int fd = open(_PATH_SYSMON, O_RDONLY);
if (fd < 0) return "open(_PATH_SYSMON, O_RDONLY) failed";
FF_AUTO_CLOSE_FD int fd = open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC);
if (fd < 0) return "open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC) failed";
__attribute__((__cleanup__(freePropDict))) prop_dictionary_t root = NULL;
if (prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &root) < 0)
@@ -51,7 +51,8 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
{
if (ffSysctlGetString("machdep.cpu_brand", &cpu->name) != NULL &&
ffSysctlGetString("machdep.dmi.processor-version", &cpu->name) != NULL &&
ffSysctlGetString("hw.cpu0.name", &cpu->name) != NULL)
ffSysctlGetString("hw.cpu0.name", &cpu->name) != NULL &&
ffSysctlGetString("hw.model", &cpu->name) != NULL)
{
ffStrbufSetS(&cpu->name, "Unknown CPU");
}
@@ -67,6 +68,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
uint32_t freq = (uint32_t) ffSysctlGetInt("machdep.cpu.frequency.target", 0);
if (freq == 0) freq = (uint32_t) (ffSysctlGetInt64("hw.cpu0.clock_frequency", 0) / 1000000);
if (freq == 0) freq = (uint32_t) ffSysctlGetInt("machdep.dmi.processor-frequency", 0);
if (freq > cpu->frequencyBase) cpu->frequencyBase = freq;
cpu->temperature = FF_CPU_TEMP_UNSET;
+45 -8
View File
@@ -1,10 +1,53 @@
#include "cpu.h"
#include "common/sysctl.h"
#include "util/stringUtils.h"
#include <errno.h>
#include <sys/time.h>
#include <sys/sensors.h>
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
static const char* detectCPUTemp(FFCPUResult* cpu)
{
int mib[5] = {CTL_HW, HW_SENSORS, 0, SENSOR_TEMP, 0};
for (mib[2] = 0; mib[2] < 1024; mib[2]++)
{
struct sensordev sensordev;
size_t sdlen = sizeof(struct sensordev);
if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) < 0)
{
if (errno == ENOENT)
break;
if (errno == ENXIO)
continue;
return "sysctl(sensordev) failed";
}
if (!ffStrStartsWith(sensordev.xname, "cpu"))
continue;
for (mib[4] = 0; mib[4] < sensordev.maxnumt[SENSOR_TEMP]; mib[4]++)
{
struct sensor sensor;
size_t slen = sizeof(struct sensor);
if (sysctl(mib, 5, &sensor, &slen, NULL, 0) < 0)
{
if (errno != ENOENT)
return "sysctl(sensor) failed";
continue;
}
if (sensor.flags & SENSOR_FINVALID)
continue;
cpu->temperature = (double)(sensor.value - 273150000) / 1E6;
return NULL;
}
}
return "No sensor for CPU temp found";
}
const char *ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
{
if (ffSysctlGetString(CTL_HW, HW_MODEL, &cpu->name))
return "sysctl(hw.model) failed";
@@ -19,13 +62,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
if (cpuspeed > cpu->frequencyBase) cpu->frequencyBase = cpuspeed;
cpu->temperature = FF_CPU_TEMP_UNSET;
if (options->temp)
{
struct sensor sensors;
size_t size = sizeof(sensors);
if (sysctl((int[]) {CTL_HW, HW_SENSORS, 0, SENSOR_TEMP, 0}, 5, &sensors, &size, NULL, 0) == 0)
cpu->temperature = (double) (sensors.value - 273150000) / 1E6;
}
if (options->temp) detectCPUTemp(cpu);
return NULL;
}
+104 -2
View File
@@ -1,6 +1,60 @@
#include "cpu.h"
#include "common/processing.h"
#include "util/stringUtils.h"
#include <kstat.h>
static const char* detectCPUTempByKstat(kstat_ctl_t* kc, FFCPUResult* cpu)
{
const char* possibleModules[] = {"temperature", "cpu_temp", "acpi_thermal", NULL};
for (int i = 0; possibleModules[i] != NULL; i++) {
kstat_t* ks = kstat_lookup(kc, possibleModules[i], -1, NULL);
if (ks && kstat_read(kc, ks, NULL) >= 0) {
kstat_named_t* kn = kstat_data_lookup(ks, "temperature");
if (kn) {
switch (kn->data_type) {
case KSTAT_DATA_INT32:
cpu->temperature = (float)kn->value.i32;
return NULL;
case KSTAT_DATA_UINT32:
cpu->temperature = (float)kn->value.ui32;
return NULL;
case KSTAT_DATA_FLOAT:
cpu->temperature = kn->value.f;
return NULL;
}
}
}
}
return "Failed to find CPU temperature using kstat";
}
static const char* detectCPUTempByIpmiTool(FFCPUResult* cpu)
{
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
const char* error = ffProcessAppendStdOut(&buffer, (char* const[]){
"ipmitool",
"-c",
"sdr",
"list",
NULL
});
if (error)
return error;
char* line = NULL;
size_t len = 0;
while (ffStrbufGetline(&line, &len, &buffer))
{
if (sscanf(line, "CPU%*d Temp,%lf,degrees C,ok", &cpu->temperature) == 1)
return NULL;
}
return "ipmitool sdr list failed to find CPU temperature";
}
static inline void kstatFreeWrap(kstat_ctl_t** pkc)
{
assert(pkc);
@@ -8,7 +62,46 @@ static inline void kstatFreeWrap(kstat_ctl_t** pkc)
kstat_close(*pkc);
}
const char* ffDetectCPUImpl(FF_MAYBE_UNUSED const FFCPUOptions* options, FFCPUResult* cpu)
static inline uint16_t countTypeId(kstat_ctl_t* kc, const char* type)
{
uint64_t low = 0, high = 0;
for (kstat_t* ksp = kc->kc_chain; ksp; ksp = ksp->ks_next)
{
if (ffStrStartsWith(ksp->ks_module, "cpu_info"))
{
if (kstat_read(kc, ksp, NULL) < 0)
continue;
kstat_named_t* stat = kstat_data_lookup(ksp, type);
if (!stat)
continue;
uint32_t id = 0;
switch (stat->data_type)
{
#ifdef _INT64_TYPE
case KSTAT_DATA_INT64:
case KSTAT_DATA_UINT64:
id = (uint32_t) stat->value.ui64;
break;
#endif
case KSTAT_DATA_INT32:
case KSTAT_DATA_UINT32:
id = stat->value.ui32;
break;
default:
continue;
}
if (__builtin_expect(id > 64, false))
high |= 1ULL << (id - 64);
else
low |= 1ULL << id;
}
}
return (uint16_t) (__builtin_popcountll(low) + __builtin_popcountll(high));
}
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
{
__attribute__((__cleanup__(kstatFreeWrap))) kstat_ctl_t* kc = kstat_open();
if (!kc)
@@ -40,7 +133,16 @@ const char* ffDetectCPUImpl(FF_MAYBE_UNUSED const FFCPUOptions* options, FFCPURe
if (ks && kstat_read(kc, ks, NULL) >= 0)
{
kstat_named_t* kn = kstat_data_lookup(ks, "ncpus");
if (kn) cpu->coresLogical = cpu->coresPhysical = cpu->coresOnline = (uint16_t) kn->value.ui32;
if (kn) cpu->coresLogical = cpu->coresOnline = (uint16_t) kn->value.ui32;
}
cpu->packages = countTypeId(kc, "chip_id");
cpu->coresPhysical = countTypeId(kc, "core_id");
if (options->temp)
{
if (detectCPUTempByKstat(kc, cpu) != NULL)
detectCPUTempByIpmiTool(cpu);
}
return NULL;
+98 -24
View File
@@ -4,42 +4,116 @@
#include "util/mallocHelper.h"
#include "util/smbiosHelper.h"
#include <pdh.h>
#include <windows.h>
#include "util/windows/perflib_.h"
#include <wchar.h>
static void ffPdhOpenCloseQuery(HQUERY* query)
static inline void ffPerfCloseQueryHandle(HANDLE* phQuery)
{
assert(query);
if (*query)
if (*phQuery != NULL)
{
PdhCloseQuery(*query);
*query = NULL;
PerfCloseQueryHandle(*phQuery);
*phQuery = NULL;
}
}
static const char* detectThermalTemp(double* result)
const char* detectThermalTemp(double* result)
{
// typeperf.exe -sc 1 "\Thermal Zone Information(*)\Temperature"
struct FFPerfQuerySpec
{
PERF_COUNTER_IDENTIFIER Identifier;
WCHAR Name[16];
} querySpec = {
.Identifier = {
// Thermal Zone Information
// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\_V2Providers\{383487a6-3676-4870-a4e7-d45b30c35629}\{52bc5412-dac2-449c-8bc2-96443888fe6b}
.CounterSetGuid = { 0x52bc5412, 0xdac2, 0x449c, {0x8b, 0xc2, 0x96, 0x44, 0x38, 0x88, 0xfe, 0x6b} },
.Size = sizeof(querySpec),
.CounterId = PERF_WILDCARD_COUNTER,
.InstanceId = PERF_WILDCARD_COUNTER,
},
.Name = L"\\_TZ.CPUZ", // The standard(?) instance name for CPU temperature in the thermal provider
};
__attribute__((__cleanup__(ffPdhOpenCloseQuery))) HQUERY query = NULL;
DWORD dataSize = 0;
if (PerfEnumerateCounterSetInstances(NULL, &querySpec.Identifier.CounterSetGuid, NULL, 0, &dataSize) != ERROR_NOT_ENOUGH_MEMORY)
return "PerfEnumerateCounterSetInstances() failed";
if (PdhOpenQuery(NULL, 0, &query) != ERROR_SUCCESS)
return "Failed to open PDH query";
if (dataSize <= sizeof(PERF_INSTANCE_HEADER))
return "No `Thermal Zone Information` instances found";
HCOUNTER counter = NULL;
if (PdhAddEnglishCounter(query,
L"\\Thermal Zone Information(*)\\Temperature",
0,
&counter) != ERROR_SUCCESS)
return "Failed to add TZI temperature counter";
{
FF_AUTO_FREE PERF_INSTANCE_HEADER* const pHead = malloc(dataSize);
if (PerfEnumerateCounterSetInstances(NULL, &querySpec.Identifier.CounterSetGuid, pHead, dataSize, &dataSize) != ERROR_SUCCESS)
return "PerfEnumerateCounterSetInstances() failed to get instance headers";
if (PdhCollectQueryData(query) != ERROR_SUCCESS)
return "Failed to collect query data";
PERF_INSTANCE_HEADER* pInstanceHeader = pHead;
while (1)
{
const wchar_t* instanceName = (const wchar_t*)((BYTE*)pInstanceHeader + sizeof(*pInstanceHeader));
if (wcscmp(instanceName, querySpec.Name) == 0)
break;
PDH_FMT_COUNTERVALUE value;
if (PdhGetFormattedCounterValue(counter, PDH_FMT_DOUBLE, NULL, &value) != ERROR_SUCCESS)
return "Failed to format counter value";
dataSize -= pInstanceHeader->Size;
if (dataSize == 0)
break;
pInstanceHeader = (PERF_INSTANCE_HEADER*)((BYTE*)pInstanceHeader + pInstanceHeader->Size);
}
*result = value.doubleValue - 273;
if (dataSize == 0)
{
const wchar_t* instanceName = (const wchar_t*)((BYTE*)pHead + sizeof(*pHead));
wcscpy(querySpec.Name, instanceName); // Use the first instance name if the specific one is not found
}
}
__attribute__((__cleanup__(ffPerfCloseQueryHandle)))
HANDLE hQuery = NULL;
if (PerfOpenQueryHandle(NULL, &hQuery) != ERROR_SUCCESS)
return "PerfOpenQueryHandle() failed";
if (PerfAddCounters(hQuery, &querySpec.Identifier, sizeof(querySpec)) != ERROR_SUCCESS)
return "PerfAddCounters() failed";
if (querySpec.Identifier.Status != ERROR_SUCCESS)
return "PerfAddCounters() reports invalid identifier";
if (PerfQueryCounterData(hQuery, NULL, 0, &dataSize) != ERROR_NOT_ENOUGH_MEMORY)
return "PerfQueryCounterData(NULL) failed";
if (dataSize <= sizeof(PERF_DATA_HEADER) + sizeof(PERF_COUNTER_HEADER)) // PERF_ERROR_RETURN, should not happen
return "instance doesn't exist";
FF_AUTO_FREE PERF_DATA_HEADER* const pDataHeader = malloc(dataSize);
if (PerfQueryCounterData(hQuery, pDataHeader, dataSize, &dataSize) != ERROR_SUCCESS)
return "PerfQueryCounterData(pDataHeader) failed";
PERF_COUNTER_HEADER* pCounterHeader = (PERF_COUNTER_HEADER*)(pDataHeader + 1);
if (pCounterHeader->dwType != PERF_MULTIPLE_COUNTERS)
return "Invalid counter type";
PERF_MULTI_COUNTERS* pMultiCounters = (PERF_MULTI_COUNTERS*)(pCounterHeader + 1);
PERF_COUNTER_DATA* pCounterData = (PERF_COUNTER_DATA*)((BYTE*)pMultiCounters + pMultiCounters->dwSize);
for (ULONG iCounter = 0; iCounter != pMultiCounters->dwCounters; iCounter++)
{
if (pCounterData->dwDataSize == sizeof(int32_t))
{
DWORD* pCounterIds = (DWORD*)(pMultiCounters + 1);
switch (pCounterIds[iCounter]) {
case 0: // Temperature
*result = *(int32_t*)(pCounterData + 1) - 273;
break;
case 3: // High Precision Temperature
*result = *(int32_t*)(pCounterData + 1) / 10.0 - 273;
break;
}
}
pCounterData = (PERF_COUNTER_DATA*)((BYTE*)pCounterData + pCounterData->dwSize);
}
return NULL;
}
@@ -151,7 +225,7 @@ static const char* detectNCores(FFCPUResult* cpu)
else if (ptr->Relationship == RelationProcessorCore)
++cpu->coresPhysical;
else if (ptr->Relationship == RelationProcessorPackage)
cpu->packages++;
++cpu->packages;
}
return NULL;
+9
View File
@@ -5,12 +5,14 @@
#include <stdint.h>
static FFlist cpuTimes1;
static uint64_t startTime;
void ffPrepareCPUUsage(void)
{
assert(cpuTimes1.elementSize == 0);
ffListInit(&cpuTimes1, sizeof(FFCpuUsageInfo));
ffGetCpuUsageInfo(&cpuTimes1);
startTime = ffTimeGetNow();
}
const char* ffGetCpuUsageResult(FFCPUUsageOptions* options, FFlist* result)
@@ -23,6 +25,12 @@ const char* ffGetCpuUsageResult(FFCPUUsageOptions* options, FFlist* result)
if(error) return error;
ffTimeSleep(options->waitTime);
}
else
{
uint64_t elapsedTime = ffTimeGetNow() - startTime;
if (elapsedTime < options->waitTime)
ffTimeSleep(options->waitTime - (uint32_t)elapsedTime);
}
if(cpuTimes1.length == 0) return "No CPU cores found";
@@ -57,5 +65,6 @@ retry:
cpuTime1->inUseAll = cpuTime2->inUseAll;
cpuTime1->totalAll = cpuTime2->totalAll;
}
startTime = ffTimeGetNow();
return NULL;
}
+2 -2
View File
@@ -42,8 +42,8 @@ const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
for (uint32_t i = 0; i < coreCount; ++i)
{
uint64_t* cpTime = cpTimes[i];
uint64_t inUse = cpTime[CP_USER] + cpTime[CP_NICE] + cpTime[CP_SYS];
uint64_t total = inUse + cpTime[CP_INTR] + cpTime[CP_IDLE];
uint64_t inUse = cpTime[CP_USER] + cpTime[CP_NICE] + cpTime[CP_SYS] + cpTime[CP_INTR];
uint64_t total = inUse + cpTime[CP_IDLE];
FFCpuUsageInfo* info = (FFCpuUsageInfo*) ffListAdd(cpuTimes);
*info = (FFCpuUsageInfo) {
+2 -2
View File
@@ -31,8 +31,8 @@ const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
{
if(sscanf(start, "cpu%*d%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%*[^\n]\n", &user, &nice, &system, &idle, &iowait, &irq, &softirq) == 7)
{
uint64_t inUse = user + nice + system;
uint64_t total = inUse + idle + iowait + irq + softirq;
uint64_t inUse = user + nice + system + irq + softirq;
uint64_t total = inUse + idle + iowait;
FFCpuUsageInfo* info = (FFCpuUsageInfo*) ffListAdd(cpuTimes);
*info = (FFCpuUsageInfo) {
+139 -5
View File
@@ -5,8 +5,11 @@
#include <ntstatus.h>
#include <winternl.h>
#include <windows.h>
#include <wchar.h>
#include "util/windows/perflib_.h"
const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
static const char* getInfoByNqsi(FFlist* cpuTimes)
{
ULONG size = 0;
if(NtQuerySystemInformation(SystemProcessorPerformanceInformation, NULL, 0, &size) != STATUS_INFO_LENGTH_MISMATCH)
@@ -20,11 +23,8 @@ const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
{
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* coreInfo = pinfo + i;
// KernelTime includes idle time.
LONGLONG dpcTime = coreInfo->Reserved1[0].QuadPart;
LONGLONG interruptTime = coreInfo->Reserved1[1].QuadPart;
// KernelTime includes IdleTime and DpcTime.
coreInfo->KernelTime.QuadPart -= coreInfo->IdleTime.QuadPart;
coreInfo->KernelTime.QuadPart += dpcTime + interruptTime;
uint64_t inUse = (uint64_t) (coreInfo->UserTime.QuadPart + coreInfo->KernelTime.QuadPart);
uint64_t total = inUse + (uint64_t)coreInfo->IdleTime.QuadPart;
@@ -38,3 +38,137 @@ const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
return NULL;
}
static const char* getInfoByPerflib(FFlist* cpuTimes)
{
static HANDLE hQuery = NULL;
if (hQuery == NULL)
{
struct FFPerfQuerySpec
{
PERF_COUNTER_IDENTIFIER Identifier;
WCHAR Name[16];
} querySpec = {
.Identifier = {
// Processor Information GUID
// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\_V2Providers\{383487a6-3676-4870-a4e7-d45b30c35629}\{b4fc721a-0378-476f-89ba-a5a79f810b36}
.CounterSetGuid = { 0xb4fc721a, 0x0378, 0x476f, {0x89, 0xba, 0xa5, 0xa7, 0x9f, 0x81, 0x0b, 0x36} },
.Size = sizeof(querySpec),
.CounterId = PERF_WILDCARD_COUNTER, // https://learn.microsoft.com/en-us/windows/win32/perfctrs/using-the-perflib-functions-to-consume-counter-data
.InstanceId = PERF_WILDCARD_COUNTER,
},
.Name = PERF_WILDCARD_INSTANCE,
};
if (PerfOpenQueryHandle(NULL, &hQuery) != ERROR_SUCCESS)
{
PerfCloseQueryHandle(hQuery);
hQuery = INVALID_HANDLE_VALUE;
return "PerfOpenQueryHandle() failed";
}
if (PerfAddCounters(hQuery, &querySpec.Identifier, sizeof(querySpec)) != ERROR_SUCCESS)
{
PerfCloseQueryHandle(hQuery);
hQuery = INVALID_HANDLE_VALUE;
return "PerfAddCounters() failed";
}
if (querySpec.Identifier.Status != ERROR_SUCCESS)
{
PerfCloseQueryHandle(hQuery);
hQuery = INVALID_HANDLE_VALUE;
return "PerfAddCounters() reports invalid identifier";
}
}
if (hQuery == INVALID_HANDLE_VALUE)
return "Init hQuery failed";
DWORD dataSize = 0;
if (PerfQueryCounterData(hQuery, NULL, 0, &dataSize) != ERROR_NOT_ENOUGH_MEMORY)
return "PerfQueryCounterData(NULL) failed";
if (dataSize <= sizeof(PERF_DATA_HEADER) + sizeof(PERF_COUNTER_HEADER))
return "instance doesn't exist";
FF_AUTO_FREE PERF_DATA_HEADER* const pDataHeader = (PERF_DATA_HEADER*)malloc(dataSize);
if (PerfQueryCounterData(hQuery, pDataHeader, dataSize, &dataSize) != ERROR_SUCCESS)
return "PerfQueryCounterData(pDataHeader) failed";
PERF_COUNTER_HEADER* pCounterHeader = (PERF_COUNTER_HEADER*)(pDataHeader + 1);
if (pCounterHeader->dwType != PERF_COUNTERSET)
return "Invalid counter type";
PERF_MULTI_COUNTERS* pMultiCounters = (PERF_MULTI_COUNTERS*)(pCounterHeader + 1);
if (pMultiCounters->dwCounters == 0)
return "No CPU counters found";
PERF_MULTI_INSTANCES* pMultiInstances = (PERF_MULTI_INSTANCES*)((BYTE*)pMultiCounters + pMultiCounters->dwSize);
if (pMultiInstances->dwInstances == 0)
return "No CPU instances found";
PERF_INSTANCE_HEADER* pInstanceHeader = (PERF_INSTANCE_HEADER*)(pMultiInstances + 1);
for (DWORD iInstance = 0; iInstance < pMultiInstances->dwInstances; ++iInstance)
{
const wchar_t* instanceName = (const wchar_t*)((BYTE*)pInstanceHeader + sizeof(*pInstanceHeader));
PERF_COUNTER_DATA* pCounterData = (PERF_COUNTER_DATA*)((BYTE*)pInstanceHeader + pInstanceHeader->Size);
uint64_t processorUtility = UINT64_MAX, utilityBase = UINT64_MAX;
for (ULONG iCounter = 0; iCounter != pMultiCounters->dwCounters; iCounter++)
{
DWORD* pCounterIds = (DWORD*)(pMultiCounters + 1);
// https://learn.microsoft.com/en-us/windows/win32/perfctrs/using-the-perflib-functions-to-consume-counter-data
switch (pCounterIds[iCounter]) {
case 26: // % Processor Utility (#26, Type=PERF_AVERAGE_BULK)
assert(pCounterData->dwDataSize == sizeof(uint64_t));
processorUtility = *(uint64_t*)(pCounterData + 1);
break;
case 27: // % Utility Base (#27, Type=PERF_AVERAGE_BASE)
assert(pCounterData->dwDataSize == sizeof(uint32_t));
utilityBase = *(uint32_t*)(pCounterData + 1) * 100LLU;
break;
}
pCounterData = (PERF_COUNTER_DATA*)((BYTE*)pCounterData + pCounterData->dwSize);
}
if (wcschr(instanceName, L'_') == NULL /* ignore `_Total` */)
{
if (processorUtility == UINT64_MAX)
return "Counter \"% Processor Utility\" are not supported";
FFCpuUsageInfo* info = (FFCpuUsageInfo*) ffListAdd(cpuTimes);
*info = (FFCpuUsageInfo) {
.inUseAll = processorUtility,
.totalAll = utilityBase,
};
}
pInstanceHeader = (PERF_INSTANCE_HEADER*)pCounterData;
}
return NULL;
}
const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
{
#if __aarch64__
static uint8_t winver = 10; // Assume Windows 10 or later for WoA
#else
static uint8_t winver = 0;
if (winver == 0)
winver = (uint8_t) ffStrbufToUInt(&instance.state.platform.sysinfo.release, 1);
#endif
if (winver >= 10)
{
if (getInfoByPerflib(cpuTimes) == NULL) return NULL;
ffListClear(cpuTimes);
winver = 1; // Fall back to NQSI
}
return getInfoByNqsi(cpuTimes);
}
+19 -8
View File
@@ -10,18 +10,29 @@
#include "util/stringUtils.h"
#include <ctype.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
static void getKDE(FFstrbuf* result, FFDEOptions* options)
{
ffParsePropFileValues(FASTFETCH_TARGET_DIR_USR "/share/wayland-sessions/plasma.desktop", 1, (FFpropquery[]) {
{"X-KDE-PluginInfo-Version =", result}
});
#ifdef _PATH_LOCALBASE
ffParsePropFile(_PATH_LOCALBASE "/share/wayland-sessions/plasma.desktop", "X-KDE-PluginInfo-Version =", result);
if(result->length == 0)
{
ffParsePropFileValues(FASTFETCH_TARGET_DIR_USR "/share/xsessions/plasmax11.desktop", 1, (FFpropquery[]) {
{"X-KDE-PluginInfo-Version =", result}
});
}
ffParsePropFile(_PATH_LOCALBASE "/share/xsessions/plasmax11.desktop", "X-KDE-PluginInfo-Version =", result);
#else
ffParsePropFile(FASTFETCH_TARGET_DIR_USR "/share/wayland-sessions/plasma.desktop", "X-KDE-PluginInfo-Version =", result);
if(result->length == 0)
ffParsePropFile(FASTFETCH_TARGET_DIR_USR "/share/xsessions/plasmax11.desktop", "X-KDE-PluginInfo-Version =", result);
#endif
if(result->length == 0)
ffParsePropFileData("xsessions/plasma.desktop", "X-KDE-PluginInfo-Version =", result);
if(result->length == 0)
+4 -4
View File
@@ -1,6 +1,6 @@
#include "disk.h"
bool ffDiskMatchMountpoint(FFDiskOptions* options, const char* mountpoint)
bool ffDiskMatchMountpoint(FFstrbuf* folders, const char* mountpoint)
{
#ifdef _WIN32
const char separator = ';';
@@ -11,12 +11,12 @@ bool ffDiskMatchMountpoint(FFDiskOptions* options, const char* mountpoint)
uint32_t mountpointLength = (uint32_t) strlen(mountpoint);
uint32_t startIndex = 0;
while(startIndex < options->folders.length)
while(startIndex < folders->length)
{
uint32_t colonIndex = ffStrbufNextIndexC(&options->folders, startIndex, separator);
uint32_t colonIndex = ffStrbufNextIndexC(folders, startIndex, separator);
uint32_t folderLength = colonIndex - startIndex;
if (folderLength == mountpointLength && memcmp(options->folders.chars + startIndex, mountpoint, mountpointLength) == 0)
if (folderLength == mountpointLength && memcmp(folders->chars + startIndex, mountpoint, mountpointLength) == 0)
return true;
startIndex = colonIndex + 1;
+1 -1
View File
@@ -28,4 +28,4 @@ typedef struct FFDisk
const char* ffDetectDisks(FFDiskOptions* options, FFlist* disks /* list of FFDisk */);
const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks);
bool ffDiskMatchMountpoint(FFDiskOptions* options, const char* mountpoint);
bool ffDiskMatchMountpoint(FFstrbuf* folders, const char* mountpoint);
+7 -7
View File
@@ -52,7 +52,7 @@ static const char* detectFsLabel(struct statfs* fs, FFDisk* disk)
return NULL;
}
#else
static const char* detectFsLabel(struct statfs* fs, FFDisk* disk)
static const char* detectFsLabel(FF_MAYBE_UNUSED struct statfs* fs, FF_MAYBE_UNUSED FFDisk* disk)
{
return "Fastfetch was compiled without libgeom support";
}
@@ -145,10 +145,10 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
{
if(__builtin_expect(options->folders.length > 0, 0))
{
if(!ffDiskMatchMountpoint(options, fs->f_mntonname))
if(!ffDiskMatchMountpoint(&options->folders, fs->f_mntonname))
continue;
}
else if(!ffStrEquals(fs->f_mntonname, "/") && !ffStrStartsWith(fs->f_mntfromname, "/dev/") && !ffStrEquals(fs->f_fstypename, "zfs"))
else if(!ffStrEquals(fs->f_mntonname, "/") && !ffStrStartsWith(fs->f_mntfromname, "/dev/") && !ffStrEquals(fs->f_fstypename, "zfs") && !ffStrEquals(fs->f_fstypename, "fusefs.sshfs"))
continue;
#ifdef __FreeBSD__
@@ -159,13 +159,13 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
FFDisk* disk = ffListAdd(disks);
disk->bytesTotal = (uint64_t)fs->f_blocks * fs->f_bsize;
disk->bytesFree = (uint64_t)fs->f_bfree * fs->f_bsize;
disk->bytesAvailable = (uint64_t)fs->f_bavail * fs->f_bsize;
disk->bytesTotal = (uint64_t)fs->f_blocks * (uint64_t)fs->f_bsize;
disk->bytesFree = (uint64_t)fs->f_bfree * (uint64_t)fs->f_bsize;
disk->bytesAvailable = (uint64_t)fs->f_bavail * (uint64_t)fs->f_bsize;
disk->bytesUsed = 0; // To be filled in ./disk.c
disk->filesTotal = (uint32_t) fs->f_files;
disk->filesUsed = (uint32_t) (fs->f_files - fs->f_ffree);
disk->filesUsed = (uint32_t) fs->f_files - (uint32_t) fs->f_ffree;
ffStrbufInitS(&disk->mountFrom, fs->f_mntfromname);
ffStrbufInitS(&disk->mountpoint, fs->f_mntonname);
+1 -1
View File
@@ -23,7 +23,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
if (__builtin_expect(options->folders.length, 0))
{
if (!ffDiskMatchMountpoint(options, path.Path()))
if (!ffDiskMatchMountpoint(&options->folders, path.Path()))
continue;
}
+9 -5
View File
@@ -37,6 +37,10 @@ static bool isPhysicalDevice(const struct mntent* device)
if(ffStrEquals(device->mnt_type, "zfs"))
return true;
//sshfs
if(ffStrEquals(device->mnt_type, "fuse.sshfs"))
return true;
//Pseudo filesystems don't have a device in /dev
if(!ffStrStartsWith(device->mnt_fsname, "/dev/"))
return false;
@@ -220,7 +224,7 @@ static bool isRemovable(FFDisk* currentDisk)
static void detectType(const FFlist* disks, FFDisk* currentDisk, struct mntent* device)
{
if(ffStrbufStartsWithS(&currentDisk->mountpoint, "/boot") || ffStrbufStartsWithS(&currentDisk->mountpoint, "/efi"))
if(hasmntopt(device, "x-gvfs-hide") || hasmntopt(device, "hidden"))
currentDisk->type = FF_DISK_VOLUME_TYPE_HIDDEN_BIT;
else if(isSubvolume(disks, currentDisk))
currentDisk->type = FF_DISK_VOLUME_TYPE_SUBVOLUME_BIT;
@@ -240,9 +244,9 @@ static void detectStats(FFDisk* disk)
if(statvfs(disk->mountpoint.chars, &fs) != 0)
memset(&fs, 0, sizeof(fs)); //Set all values to 0, so our values get initialized to 0 too
disk->bytesTotal = fs.f_blocks * fs.f_frsize;
disk->bytesFree = fs.f_bfree * fs.f_frsize;
disk->bytesAvailable = fs.f_bavail * fs.f_frsize;
disk->bytesTotal = fs.f_blocks * (uint64_t) fs.f_frsize;
disk->bytesFree = fs.f_bfree * (uint64_t) fs.f_frsize;
disk->bytesAvailable = fs.f_bavail * (uint64_t) fs.f_frsize;
disk->bytesUsed = 0; // To be filled in ./disk.c
if (fs.f_files >= fs.f_ffree)
@@ -281,7 +285,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
{
if (__builtin_expect(options->folders.length, 0))
{
if (!ffDiskMatchMountpoint(options, device->mnt_dir))
if (!ffDiskMatchMountpoint(&options->folders, device->mnt_dir))
continue;
}
else if(!isPhysicalDevice(device))
+1 -1
View File
@@ -113,7 +113,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
{
if (__builtin_expect(options->folders.length, 0))
{
if (!ffDiskMatchMountpoint(options, device.mnt_mountp))
if (!ffDiskMatchMountpoint(&options->folders, device.mnt_mountp))
continue;
}
else if(!isPhysicalDevice(&device))
+1 -5
View File
@@ -47,7 +47,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
if (__builtin_expect((long) options->folders.length, 0))
{
if (!ffDiskMatchMountpoint(options, buffer.chars))
if (!ffDiskMatchMountpoint(&options->folders, buffer.chars))
continue;
}
else if(driveType == DRIVE_NO_ROOT_DIR)
@@ -99,9 +99,6 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
wchar_t diskName[MAX_PATH + 1], diskFileSystem[MAX_PATH + 1];
//https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumeinformationa#remarks
UINT errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
DWORD diskFlags;
BOOL result = GetVolumeInformationW(mountpoint,
diskName, ARRAY_SIZE(diskName), //Volume name
@@ -110,7 +107,6 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
&diskFlags, //File system flags
diskFileSystem, ARRAY_SIZE(diskFileSystem)
);
SetErrorMode(errorMode);
if(result)
{
@@ -2,6 +2,7 @@
#include "util/apple/cf_helpers.h"
#include "util/stringUtils.h"
#include "util/edidHelper.h"
#include "detection/os/os.h"
#include <stdlib.h>
#include <string.h>
@@ -194,7 +195,22 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds)
ffStrbufSetStatic(&ds->wmPrettyName, "Quartz Compositor");
}
}
ffStrbufSetStatic(&ds->dePrettyName, "Aqua");
const FFOSResult* os = ffDetectOS();
char* str_end;
const char* version = os->version.chars;
unsigned long osNum = strtoul(version, &str_end, 10);
if (str_end != version)
{
if (osNum > 15) { // Tahoe
ffStrbufSetStatic(&ds->dePrettyName, "Liquid Glass");
} else if (osNum < 10) {
ffStrbufSetStatic(&ds->dePrettyName, "Platinum");
} else {
ffStrbufSetStatic(&ds->dePrettyName, "Aqua");
}
}
detectDisplays(ds);
}
+1 -1
View File
@@ -440,7 +440,7 @@ static const char* drmConnectLibdrm(FFDisplayServerResult* result)
#endif
const char* ffdsConnectDrm(FFDisplayServerResult* result)
const char* ffdsConnectDrm(FF_MAYBE_UNUSED FFDisplayServerResult* result)
{
#ifdef FF_HAVE_DRM
if (instance.config.general.dsForceDrm != FF_DS_FORCE_DRM_TYPE_SYSFS_ONLY)
@@ -5,7 +5,7 @@
#include <stdint.h>
#include <stddef.h>
#include <wayland-util.h>
#include <wayland-client.h>
#ifdef __cplusplus
extern "C" {
@@ -214,6 +214,26 @@ enum kde_output_device_v2_capability {
* @since 9
*/
KDE_OUTPUT_DEVICE_V2_CAPABILITY_BRIGHTNESS = 0x80,
/**
* if this outputdevice supports the built-in color profile
* @since 12
*/
KDE_OUTPUT_DEVICE_V2_CAPABILITY_BUILT_IN_COLOR = 0x100,
/**
* if this outputdevice supports DDC/CI
* @since 14
*/
KDE_OUTPUT_DEVICE_V2_CAPABILITY_DDC_CI = 0x200,
/**
* if this outputdevice supports setting max bpc
* @since 15
*/
KDE_OUTPUT_DEVICE_V2_CAPABILITY_MAX_BITS_PER_COLOR = 0x400,
/**
* if this outputdevice supports EDR
* @since 16
*/
KDE_OUTPUT_DEVICE_V2_CAPABILITY_EDR = 0x800,
};
/**
* @ingroup iface_kde_output_device_v2
@@ -235,6 +255,22 @@ enum kde_output_device_v2_capability {
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_BRIGHTNESS_SINCE_VERSION 9
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_BUILT_IN_COLOR_SINCE_VERSION 12
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_DDC_CI_SINCE_VERSION 14
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_MAX_BITS_PER_COLOR_SINCE_VERSION 15
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_EDR_SINCE_VERSION 16
#endif /* KDE_OUTPUT_DEVICE_V2_CAPABILITY_ENUM */
#ifndef KDE_OUTPUT_DEVICE_V2_VRR_POLICY_ENUM
@@ -316,6 +352,18 @@ enum kde_output_device_v2_color_power_tradeoff {
};
#endif /* KDE_OUTPUT_DEVICE_V2_COLOR_POWER_TRADEOFF_ENUM */
#ifndef KDE_OUTPUT_DEVICE_V2_EDR_POLICY_ENUM
#define KDE_OUTPUT_DEVICE_V2_EDR_POLICY_ENUM
/**
* @ingroup iface_kde_output_device_v2
* when the compositor may make use of EDR
*/
enum kde_output_device_v2_edr_policy {
KDE_OUTPUT_DEVICE_V2_EDR_POLICY_NEVER = 0,
KDE_OUTPUT_DEVICE_V2_EDR_POLICY_ALWAYS = 1,
};
#endif /* KDE_OUTPUT_DEVICE_V2_EDR_POLICY_ENUM */
/**
* @ingroup iface_kde_output_device_v2
* @struct kde_output_device_v2_listener
@@ -658,6 +706,74 @@ struct kde_output_device_v2_listener {
void (*dimming)(void *data,
struct kde_output_device_v2 *kde_output_device_v2,
uint32_t multiplier);
/**
* source output for mirroring
*
*
* @param source uuid of the source output
* @since 13
*/
void (*replication_source)(void *data,
struct kde_output_device_v2 *kde_output_device_v2,
const char *source);
/**
* if DDC/CI should be used to control brightness etc.
*
* If the ddc_ci capability is present, this determines if
* settings such as brightness, contrast or others should be set
* using DDC/CI.
* @param allowed 1 if allowed, 0 if disabled
* @since 14
*/
void (*ddc_ci_allowed)(void *data,
struct kde_output_device_v2 *kde_output_device_v2,
uint32_t allowed);
/**
* override max bpc
*
* This limits the amount of bits per color that are sent to the
* display.
* @param max_bpc 0 for the default / automatic
* @since 15
*/
void (*max_bits_per_color)(void *data,
struct kde_output_device_v2 *kde_output_device_v2,
uint32_t max_bpc);
/**
* range of max bits per color value
*
*
* @param min_value the minimum supported by the driver
* @param max_value the maximum supported by the driver
* @since 15
*/
void (*max_bits_per_color_range)(void *data,
struct kde_output_device_v2 *kde_output_device_v2,
uint32_t min_value,
uint32_t max_value);
/**
* if and to what value automatic max bpc is limited
*
*
* @param max_bpc_limit which value automatic bpc gets limited to. 0 if not limited
* @since 15
*/
void (*automatic_max_bits_per_color_limit)(void *data,
struct kde_output_device_v2 *kde_output_device_v2,
uint32_t max_bpc_limit);
/**
* when the compositor may apply EDR
*
* When EDR is enabled, the compositor may increase the backlight
* beyond the user-specified setting, in order to present HDR
* content on displays without native HDR support. This will
* usually result in better visuals, but also increases battery
* usage.
* @since 16
*/
void (*edr_policy)(void *data,
struct kde_output_device_v2 *kde_output_device_v2,
uint32_t policy);
};
/**
@@ -779,6 +895,30 @@ kde_output_device_v2_add_listener(struct kde_output_device_v2 *kde_output_device
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_DIMMING_SINCE_VERSION 11
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_REPLICATION_SOURCE_SINCE_VERSION 13
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_DDC_CI_ALLOWED_SINCE_VERSION 14
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_MAX_BITS_PER_COLOR_SINCE_VERSION 15
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_MAX_BITS_PER_COLOR_RANGE_SINCE_VERSION 15
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_AUTOMATIC_MAX_BITS_PER_COLOR_LIMIT_SINCE_VERSION 15
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_EDR_POLICY_SINCE_VERSION 16
/** @ingroup iface_kde_output_device_v2 */
@@ -60,12 +60,18 @@ static const struct wl_message kde_output_device_v2_events[] = {
{ "brightness", "8u", kde_output_device_v2_types + 0 },
{ "color_power_tradeoff", "10u", kde_output_device_v2_types + 0 },
{ "dimming", "11u", kde_output_device_v2_types + 0 },
{ "replication_source", "13s", kde_output_device_v2_types + 0 },
{ "ddc_ci_allowed", "14u", kde_output_device_v2_types + 0 },
{ "max_bits_per_color", "15u", kde_output_device_v2_types + 0 },
{ "max_bits_per_color_range", "15uu", kde_output_device_v2_types + 0 },
{ "automatic_max_bits_per_color_limit", "15u", kde_output_device_v2_types + 0 },
{ "edr_policy", "16u", kde_output_device_v2_types + 0 },
};
WL_EXPORT const struct wl_interface kde_output_device_v2_interface = {
"kde_output_device_v2", 11,
"kde_output_device_v2", 16,
0, NULL,
27, kde_output_device_v2_events,
33, kde_output_device_v2_events,
};
static const struct wl_message kde_output_device_mode_v2_events[] = {
@@ -137,6 +137,12 @@ static void waylandKdeHdrListener(void *data, FF_MAYBE_UNUSED struct kde_output_
display->hdrEnabled = !!hdr_enabled;
}
static void waylandKdeMaxBitsPerColorListener(void *data, FF_MAYBE_UNUSED struct kde_output_device_v2 *kde_output_device_v2, uint32_t max_bpc)
{
WaylandDisplay* display = data;
display->bitDepth = (uint8_t) max_bpc;
}
static struct kde_output_device_v2_listener outputListener = {
.geometry = waylandKdeGeometryListener,
.current_mode = waylandKdeCurrentModeListener,
@@ -165,6 +171,12 @@ static struct kde_output_device_v2_listener outputListener = {
.brightness = (void*) stubListener,
.color_power_tradeoff = (void*) stubListener,
.dimming = (void*) stubListener,
.replication_source = (void*) stubListener,
.ddc_ci_allowed = (void*) stubListener,
.max_bits_per_color = (void*) waylandKdeMaxBitsPerColorListener,
.max_bits_per_color_range = (void*) stubListener,
.automatic_max_bits_per_color_limit = (void*) stubListener,
.edr_policy = (void*) stubListener,
};
const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version)
@@ -237,6 +249,7 @@ const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* re
item->manufactureYear = display.myear;
item->manufactureWeek = display.mweek;
item->serial = display.serial;
item->bitDepth = display.bitDepth;
}
ffStrbufDestroy(&display.description);
@@ -34,6 +34,7 @@ typedef struct WaylandData
typedef struct WaylandDisplay
{
WaylandData* parent;
void* internal;
int32_t width;
int32_t height;
int32_t refreshRate;
@@ -55,7 +56,7 @@ typedef struct WaylandDisplay
uint16_t myear;
uint16_t mweek;
uint32_t serial;
void* internal;
uint8_t bitDepth;
} WaylandDisplay;
inline static void stubListener(void* data, ...)
+5 -1
View File
@@ -335,6 +335,7 @@ const char* ffdsConnectXcbRandr(FFDisplayServerResult* result)
{
FF_LIBRARY_LOAD(xcbRandr, "dlopen libxcb-randr failed", "libxcb-randr" FF_LIBRARY_EXTENSION, 1)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_connect)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_connection_has_error)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_get_setup)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_setup_roots_iterator)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_screen_next)
@@ -368,8 +369,11 @@ const char* ffdsConnectXcbRandr(FFDisplayServerResult* result)
data.connection = ffxcb_connect(NULL, NULL);
if(data.connection == NULL)
if(ffxcb_connection_has_error(data.connection) > 0)
{
ffxcb_disconnect(data.connection);
return "xcb_connect() failed";
}
data.result = result;
-3
View File
@@ -20,9 +20,6 @@ extern int ADL2_Adapter_Graphic_Core_Info_Get(ADL_CONTEXT_HANDLE context, int iA
// Function to retrieve memory information from the adapter. Version 2
extern int ADL2_Adapter_MemoryInfo2_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, ADLMemoryInfo2* lpMemoryInfo2);
// This function retrieves the VRAM usage of given adapter.
extern int ADL2_Adapter_VRAMUsage_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* iVRAMUsageInMB);
// This function retrieves the Dedicated VRAM usage of given adapter.
extern int ADL2_Adapter_DedicatedVRAMUsage_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* iVRAMUsageInMB);
File diff suppressed because it is too large Load Diff
+12 -2
View File
@@ -15,6 +15,11 @@ const char* FF_GPU_VENDOR_NAME_PARALLEL = "Parallel";
const char* FF_GPU_VENDOR_NAME_MICROSOFT = "Microsoft";
const char* FF_GPU_VENDOR_NAME_REDHAT = "RedHat";
const char* FF_GPU_VENDOR_NAME_ORACLE = "Oracle";
const char* FF_GPU_VENDOR_NAME_BROADCOM = "Broadcom";
const char* FF_GPU_VENDOR_NAME_LOONGSON = "Loongson";
const char* FF_GPU_VENDOR_NAME_JINGJIA_MICRO = "Jingjia Micro";
const char* FF_GPU_VENDOR_NAME_HUAWEI = "Huawei";
const char* FF_GPU_VENDOR_NAME_ZHAOXIN = "Zhaoxin";
const char* ffGPUGetVendorString(unsigned vendorId)
{
@@ -22,17 +27,22 @@ const char* ffGPUGetVendorString(unsigned vendorId)
switch (vendorId)
{
case 0x106b: return FF_GPU_VENDOR_NAME_APPLE;
case 0x1002: case 0x1022: return FF_GPU_VENDOR_NAME_AMD;
case 0x1002: case 0x1022: case 0x1dd8: return FF_GPU_VENDOR_NAME_AMD;
case 0x8086: case 0x8087: case 0x03e7: return FF_GPU_VENDOR_NAME_INTEL;
case 0x0955: case 0x10de: case 0x12d2: return FF_GPU_VENDOR_NAME_NVIDIA;
case 0x1ed5: return FF_GPU_VENDOR_NAME_MTHREADS;
case 0x5143: return FF_GPU_VENDOR_NAME_QUALCOMM;
case 0x17cb: case 0x5143: return FF_GPU_VENDOR_NAME_QUALCOMM;
case 0x14c3: return FF_GPU_VENDOR_NAME_MTK;
case 0x15ad: return FF_GPU_VENDOR_NAME_VMWARE;
case 0x1af4: return FF_GPU_VENDOR_NAME_REDHAT;
case 0x1ab8: return FF_GPU_VENDOR_NAME_PARALLEL;
case 0x1414: return FF_GPU_VENDOR_NAME_MICROSOFT;
case 0x108e: return FF_GPU_VENDOR_NAME_ORACLE;
case 0x182f: case 0x14e4: return FF_GPU_VENDOR_NAME_BROADCOM;
case 0x0014: return FF_GPU_VENDOR_NAME_LOONGSON;
case 0x0731: return FF_GPU_VENDOR_NAME_JINGJIA_MICRO;
case 0x19e5: return FF_GPU_VENDOR_NAME_HUAWEI;
case 0x1d17: return FF_GPU_VENDOR_NAME_ZHAOXIN;
default: return NULL;
}
}
+19 -1
View File
@@ -49,7 +49,25 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus);
const char* ffGPUGetVendorString(unsigned vendorId);
typedef struct FFGpuDriverPciBusId
{
uint32_t domain;
uint32_t bus;
uint32_t device;
uint32_t func;
} FFGpuDriverPciBusId;
#if defined(__linux__) || defined(__FreeBSD__) || defined(__sun) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
void ffGPUFillVendorAndName(uint8_t subclass, uint16_t vendor, uint16_t device, FFGPUResult* gpu);
void ffGPUQueryAmdGpuName(uint16_t deviceId, uint8_t revisionId, FFGPUResult* gpu);
#endif
#if FF_HAVE_DRM
const char* ffDrmDetectRadeon(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath);
const char* ffDrmDetectAmdgpu(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath);
const char* ffDrmDetectI915(FFGPUResult* gpu, int fd);
const char* ffDrmDetectXe(FFGPUResult* gpu, int fd);
const char* ffDrmDetectAsahi(FFGPUResult* gpu, int fd);
#endif // FF_HAVE_DRM
const char* ffGPUDetectDriverSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFGpuDriverPciBusId pciBusId);
#endif // defined(XXX)
+1 -20
View File
@@ -49,7 +49,6 @@ struct FFAdlData {
FF_LIBRARY_SYMBOL(ADL2_Adapter_Graphic_Core_Info_Get)
FF_LIBRARY_SYMBOL(ADL2_Adapter_MemoryInfo2_Get)
FF_LIBRARY_SYMBOL(ADL2_Adapter_DedicatedVRAMUsage_Get)
FF_LIBRARY_SYMBOL(ADL2_Adapter_VRAMUsage_Get)
FF_LIBRARY_SYMBOL(ADL2_Adapter_ASICFamilyType_Get)
FF_LIBRARY_SYMBOL(ADL2_Overdrive_Caps)
FF_LIBRARY_SYMBOL(ADL2_OverdriveN_CapabilitiesX2_Get)
@@ -91,7 +90,6 @@ const char* ffDetectAmdGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResu
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_Graphic_Core_Info_Get)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_MemoryInfo2_Get)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_DedicatedVRAMUsage_Get)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_VRAMUsage_Get)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_ASICFamilyType_Get)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Overdrive_Caps)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_OverdriveN_CapabilitiesX2_Get)
@@ -188,29 +186,12 @@ const char* ffDetectAmdGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResu
FF_DEBUG("ADL2_Adapter_DedicatedVRAMUsage_Get returned %s (%d), usage: %d MB",
ffAdlStatusToString(status), status, vramUsage);
if (status == ADL_OK) {
if (status == ADL_OK && vramUsage >= 0) {
result.memory->used = (uint64_t) vramUsage * 1024 * 1024;
FF_DEBUG("Dedicated VRAM usage: %llu bytes (%d MB)", result.memory->used, vramUsage);
} else {
FF_DEBUG("Failed to get dedicated VRAM usage");
}
if (result.sharedMemory)
{
vramUsage = 0;
status = adlData.ffADL2_Adapter_VRAMUsage_Get(adlData.apiHandle, device->iAdapterIndex, &vramUsage);
FF_DEBUG("ADL2_Adapter_VRAMUsage_Get returned %s (%d), usage: %d MB",
ffAdlStatusToString(status), status, vramUsage);
if (status == ADL_OK) {
uint64_t totalUsage = (uint64_t) vramUsage * 1024 * 1024;
result.sharedMemory->used = totalUsage - result.memory->used;
FF_DEBUG("Total VRAM usage: %llu bytes, Shared VRAM usage: %llu bytes (%llu MB)",
totalUsage, result.sharedMemory->used, result.sharedMemory->used / (1024 * 1024));
} else {
FF_DEBUG("Failed to get total VRAM usage");
}
}
}
if (result.memoryType)
+6 -1
View File
@@ -3,6 +3,9 @@
#import <Metal/MTLDevice.h>
#import <IOKit/kext/KextManager.h>
#ifndef MAC_OS_VERSION_26_0
#define MTLGPUFamilyMetal4 ((MTLGPUFamily) 5002)
#endif
#ifndef MAC_OS_VERSION_13_0
#define MTLGPUFamilyMetal3 ((MTLGPUFamily) 5001)
#endif
@@ -57,7 +60,9 @@ const char* ffGpuDetectMetal(FFlist* gpus)
else if ([device supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v1])
ffStrbufSetStatic(&gpu->platformApi, "Metal Feature Set 1");
#else // MAC_OS_X_VERSION_10_15
if ([device supportsFamily:MTLGPUFamilyMetal3])
if ([device supportsFamily:MTLGPUFamilyMetal4])
ffStrbufSetStatic(&gpu->platformApi, "Metal 4");
else if ([device supportsFamily:MTLGPUFamilyMetal3])
ffStrbufSetStatic(&gpu->platformApi, "Metal 3");
else if ([device supportsFamily:MTLGPUFamilyCommon3])
ffStrbufSetStatic(&gpu->platformApi, "Metal Common 3");
-91
View File
@@ -1,91 +0,0 @@
#if __aarch64__ && FF_HAVE_DRM
#include <drm.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#if __has_include(<drm/asahi_drm.h>)
#include <drm/asahi_drm.h>
#else
// https://github.com/AsahiLinux/linux/blob/asahi/include/uapi/drm/asahi_drm.h
/* SPDX-License-Identifier: MIT */
/* Copyright (C) The Asahi Linux Contributors */
#define DRM_ASAHI_UNSTABLE_UABI_VERSION 10011
#define DRM_ASAHI_GET_PARAMS 0x00
#define DRM_ASAHI_MAX_CLUSTERS 32
struct drm_asahi_params_global
{
__u32 unstable_uabi_version;
__u32 pad0;
__u64 feat_compat;
__u64 feat_incompat;
__u32 gpu_generation;
__u32 gpu_variant;
__u32 gpu_revision;
__u32 chip_id;
__u32 num_dies;
__u32 num_clusters_total;
__u32 num_cores_per_cluster;
__u32 num_frags_per_cluster;
__u32 num_gps_per_cluster;
__u32 num_cores_total_active;
__u64 core_masks[DRM_ASAHI_MAX_CLUSTERS];
__u32 vm_page_size;
__u32 pad1;
__u64 vm_user_start;
__u64 vm_user_end;
__u64 vm_usc_start;
__u64 vm_usc_end;
__u64 vm_kernel_min_size;
__u32 max_syncs_per_submission;
__u32 max_commands_per_submission;
__u32 max_commands_in_flight;
__u32 max_attachments;
__u32 timer_frequency_hz;
__u32 min_frequency_khz;
__u32 max_frequency_khz;
__u32 max_power_mw;
__u32 result_render_size;
__u32 result_compute_size;
__u32 firmware_version[4];
};
struct drm_asahi_get_params
{
/** @extensions: Pointer to the first extension struct, if any */
__u64 extensions;
/** @param: Parameter group to fetch (MBZ) */
__u32 param_group;
/** @pad: MBZ */
__u32 pad;
/** @value: User pointer to write parameter struct */
__u64 pointer;
/** @value: Size of user buffer, max size supported on return */
__u64 size;
};
enum
{
DRM_IOCTL_ASAHI_GET_PARAMS = DRM_IOWR(DRM_COMMAND_BASE + DRM_ASAHI_GET_PARAMS, struct drm_asahi_get_params),
};
#endif // __has_include
#endif // FF_HAVE_DRM
+158 -44
View File
@@ -1,6 +1,7 @@
#include "gpu_driver_specific.h"
#include "common/io/io.h"
#include "util/mallocHelper.h"
#include <sys/pciio.h>
#include <fcntl.h>
@@ -10,11 +11,145 @@
#include <bus/pci/pcireg.h> // DragonFly
#endif
const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
static void fillGPUTypeGeneric(FFGPUResult* gpu)
{
FF_AUTO_CLOSE_FD int fd = open("/dev/pci", O_RDONLY, 0);
if (gpu->type == FF_GPU_TYPE_UNKNOWN)
{
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA)
{
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "GeForce") ||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Quadro") ||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Tesla"))
gpu->type = FF_GPU_TYPE_DISCRETE;
}
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_MTHREADS)
{
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "MTT "))
gpu->type = FF_GPU_TYPE_DISCRETE;
}
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL)
{
// 0000:00:02.0 is reserved for Intel integrated graphics
gpu->type = gpu->deviceId == 20 ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
}
}
}
#if FF_HAVE_DRM
#include "common/library.h"
#include "util/stringUtils.h"
#include <xf86drm.h>
static const char* detectByDrm(const FFGPUOptions* options, FFlist* gpus)
{
FF_LIBRARY_LOAD(libdrm, "dlopen libdrm" FF_LIBRARY_EXTENSION " failed", "libdrm" FF_LIBRARY_EXTENSION, 2)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmGetDevices)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmFreeDevices)
drmDevicePtr devices[64];
int nDevices = ffdrmGetDevices(devices, ARRAY_SIZE(devices));
if (nDevices < 0)
return "drmGetDevices() failed";
for (int iDev = 0; iDev < nDevices; ++iDev)
{
drmDevice* dev = devices[iDev];
if (!(dev->available_nodes & (1 << DRM_NODE_PRIMARY)))
continue;
const char* path = dev->nodes[DRM_NODE_PRIMARY];
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInit(&gpu->vendor);
ffStrbufInit(&gpu->name);
ffStrbufInit(&gpu->driver);
ffStrbufInitS(&gpu->platformApi, path);
ffStrbufInit(&gpu->memoryType);
gpu->index = FF_GPU_INDEX_UNSET;
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET;
gpu->type = FF_GPU_TYPE_UNKNOWN;
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = 0;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
switch (dev->bustype)
{
case DRM_BUS_PCI:
ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(dev->deviceinfo.pci->vendor_id));
gpu->deviceId = (dev->businfo.pci->domain * 100000ull) + (dev->businfo.pci->bus * 1000ull) + (dev->businfo.pci->dev * 10ull) + dev->businfo.pci->func;
break;
case DRM_BUS_HOST1X:
ffStrbufSetS(&gpu->name, dev->deviceinfo.host1x->compatible[0]);
gpu->type = FF_GPU_TYPE_INTEGRATED;
break;
case DRM_BUS_PLATFORM:
ffStrbufSetS(&gpu->name, dev->deviceinfo.platform->compatible[0]);
gpu->type = FF_GPU_TYPE_INTEGRATED;
break;
case DRM_BUS_USB:
ffStrbufSetF(&gpu->name, "USB Device (%u-%u)", dev->deviceinfo.usb->vendor, dev->deviceinfo.usb->product);
gpu->type = FF_GPU_TYPE_DISCRETE;
break;
}
FF_AUTO_CLOSE_FD int fd = open(path, O_RDONLY | O_CLOEXEC);
if (fd < 0) continue;
char driverName[64];
driverName[0] = '\0';
struct drm_version ver = {
.name = driverName,
.name_len = ARRAY_SIZE(driverName),
};
if (ioctl(fd, DRM_IOCTL_VERSION, &ver) == 0)
ffStrbufSetF(&gpu->driver, "%*s %d.%d.%d", (int) ver.name_len, ver.name, ver.version_major, ver.version_minor, ver.version_patchlevel);
if (ffStrStartsWith(driverName, "i915"))
ffDrmDetectI915(gpu, fd);
else if (ffStrStartsWith(driverName, "amdgpu"))
ffDrmDetectAmdgpu(options, gpu, dev->nodes[DRM_NODE_RENDER]);
else if (ffStrStartsWith(driverName, "radeon"))
ffDrmDetectRadeon(options, gpu, dev->nodes[DRM_NODE_RENDER]);
else if (ffStrStartsWith(driverName, "xe"))
ffDrmDetectXe(gpu, fd);
else if (ffStrStartsWith(driverName, "asahi"))
ffDrmDetectAsahi(gpu, fd);
else if (dev->bustype == DRM_BUS_PCI)
{
ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId) {
.domain = (uint32_t) dev->businfo.pci->domain,
.bus = dev->businfo.pci->bus,
.device = dev->businfo.pci->dev,
.func = dev->businfo.pci->func,
});
}
if (gpu->name.length == 0)
{
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD)
ffGPUQueryAmdGpuName(dev->deviceinfo.pci->device_id, dev->deviceinfo.pci->revision_id, gpu);
if (gpu->name.length == 0)
ffGPUFillVendorAndName(0, dev->deviceinfo.pci->vendor_id, dev->deviceinfo.pci->device_id, gpu);
}
fillGPUTypeGeneric(gpu);
}
ffdrmFreeDevices(devices, nDevices);
return NULL;
}
#endif
static const char* detectByPci(const FFGPUOptions* options, FFlist* gpus)
{
FF_AUTO_CLOSE_FD int fd = open("/dev/pci", O_RDONLY | O_CLOEXEC);
if (fd < 0)
return "open(\"/dev/pci\", O_RDONLY, 0) failed";
return "open(\"/dev/pci\", O_RDONLY | O_CLOEXEC, 0) failed";
struct pci_conf confs[128];
struct pci_match_conf match = {
@@ -54,27 +189,12 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
gpu->deviceId = (pc->pc_sel.pc_domain * 100000ull) + (pc->pc_sel.pc_bus * 1000ull) + (pc->pc_sel.pc_dev * 10ull) + pc->pc_sel.pc_func;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA && (options->temp || options->driverSpecific))
{
ffDetectNvidiaGpuInfo(&(FFGpuDriverCondition) {
.type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID,
.pciBusId = {
.domain = (uint32_t) pc->pc_sel.pc_domain,
.bus = pc->pc_sel.pc_bus,
.device = pc->pc_sel.pc_dev,
.func = pc->pc_sel.pc_func,
},
}, (FFGpuDriverResult) {
.index = &gpu->index,
.temp = options->temp ? &gpu->temperature : NULL,
.memory = options->driverSpecific ? &gpu->dedicated : NULL,
.coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL,
.type = &gpu->type,
.frequency = &gpu->frequency,
.coreUsage = &gpu->coreUsage,
.name = &gpu->name,
}, "libnvidia-ml.so");
}
ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId) {
.domain = (uint32_t) pc->pc_sel.pc_domain,
.bus = pc->pc_sel.pc_bus,
.device = pc->pc_sel.pc_dev,
.func = pc->pc_sel.pc_func,
});
if (gpu->name.length == 0)
{
@@ -84,27 +204,21 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
ffGPUFillVendorAndName(pc->pc_subclass, pc->pc_vendor, pc->pc_device, gpu);
}
if (gpu->type == FF_GPU_TYPE_UNKNOWN)
{
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA)
{
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "GeForce") ||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Quadro") ||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Tesla"))
gpu->type = FF_GPU_TYPE_DISCRETE;
}
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_MTHREADS)
{
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "MTT "))
gpu->type = FF_GPU_TYPE_DISCRETE;
}
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL)
{
// 0000:00:02.0 is reserved for Intel integrated graphics
gpu->type = gpu->deviceId == 20 ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
}
}
fillGPUTypeGeneric(gpu);
}
return NULL;
}
const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
{
#if FF_HAVE_DRM
if (options->detectionMethod == FF_GPU_DETECTION_METHOD_AUTO)
{
detectByDrm(options, gpus);
if (gpus->length > 0) return NULL;
}
#endif
return detectByPci(options, gpus);
}
-8
View File
@@ -10,14 +10,6 @@ typedef enum __attribute__((__packed__)) FFGpuDriverConditionType
FF_GPU_DRIVER_CONDITION_TYPE_FORCE_UNSIGNED = UINT8_MAX,
} FFGpuDriverConditionType;
typedef struct FFGpuDriverPciBusId
{
uint32_t domain;
uint32_t bus;
uint32_t device;
uint32_t func;
} FFGpuDriverPciBusId;
typedef struct FFGpuDriverPciDeviceId
{
uint32_t deviceId;
+372
View File
@@ -0,0 +1,372 @@
#include "gpu.h"
#if FF_HAVE_DRM
#include <drm.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "common/io/io.h"
#include "common/library.h"
#include "util/mallocHelper.h"
#include "util/stringUtils.h"
#include "intel_drm.h"
#include "asahi_drm.h"
#include <radeon_drm.h>
const char* ffDrmDetectRadeon(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath)
{
FF_AUTO_CLOSE_FD int fd = open(renderPath, O_RDONLY | O_CLOEXEC);
if (fd < 0) return "Failed to open DRM render device";
uint32_t value;
// https://github.com/torvalds/linux/blob/fb4d33ab452ea254e2c319bac5703d1b56d895bf/drivers/gpu/drm/radeon/radeon_kms.c#L231
if (ioctl(fd, DRM_IOCTL_RADEON_INFO, &(struct drm_radeon_info) {
.request = RADEON_INFO_ACTIVE_CU_COUNT,
.value = (uintptr_t) &value,
}) >= 0)
gpu->coreCount = (int32_t) value;
if (options->temp)
{
if (ioctl(fd, DRM_IOCTL_RADEON_INFO, &(struct drm_radeon_info) {
.request = RADEON_INFO_CURRENT_GPU_TEMP, // millidegrees C
.value = (uintptr_t) &value,
}) >= 0 && value != 0) // 0 means unavailable
gpu->temperature = (double) value / 1000.0;
}
if (ioctl(fd, DRM_IOCTL_RADEON_INFO, &(struct drm_radeon_info) {
.request = RADEON_INFO_MAX_SCLK, // MHz
.value = (uintptr_t) &value,
}) >= 0)
gpu->frequency = (uint32_t) (value / 1000u);
if (options->driverSpecific)
{
struct drm_radeon_gem_info gemInfo;
if (ioctl(fd, DRM_IOCTL_RADEON_GEM_INFO, &gemInfo) >= 0)
{
// vram_usage can be bigger than vram_usage, so we use vram_size here
gpu->dedicated.total = gemInfo.vram_size;
gpu->shared.total = gemInfo.gart_size;
uint64_t memSize;
if (ioctl(fd, DRM_IOCTL_RADEON_INFO, &(struct drm_radeon_info) {
.request = RADEON_INFO_VRAM_USAGE, // uint64_t
.value = (uintptr_t) &memSize,
}) >= 0)
gpu->dedicated.used = memSize;
if (ioctl(fd, DRM_IOCTL_RADEON_INFO, &(struct drm_radeon_info) {
.request = RADEON_INFO_GTT_USAGE, // uint64_t
.value = (uintptr_t) &memSize,
}) >= 0)
gpu->shared.used = memSize;
}
}
return NULL;
}
#ifdef FF_HAVE_DRM_AMDGPU
#include <amdgpu.h>
#include <amdgpu_drm.h>
const char* ffDrmDetectAmdgpu(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath)
{
#if FF_HAVE_DRM_AMDGPU
FF_LIBRARY_LOAD(libdrm, "dlopen libdrm_amdgpu" FF_LIBRARY_EXTENSION " failed", "libdrm_amdgpu" FF_LIBRARY_EXTENSION, 1)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_initialize)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_get_marketing_name)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_gpu_info)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_sensor_info)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_heap_info)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_deinitialize)
FF_AUTO_CLOSE_FD int fd = open(renderPath, O_RDONLY | O_CLOEXEC);
if (fd < 0) return "Failed to open DRM render device";
amdgpu_device_handle handle;
uint32_t majorVersion, minorVersion;
if (ffamdgpu_device_initialize(fd, &majorVersion, &minorVersion, &handle) < 0)
return "Failed to initialize AMDGPU device";
uint32_t value;
if (options->temp)
{
if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_TEMP, sizeof(value), &value) >= 0)
gpu->temperature = value / 1000.;
}
ffStrbufSetS(&gpu->name, ffamdgpu_get_marketing_name(handle));
struct amdgpu_gpu_info gpuInfo;
if (ffamdgpu_query_gpu_info(handle, &gpuInfo) >= 0)
{
gpu->coreCount = (int32_t) gpuInfo.cu_active_number;
gpu->frequency = (uint32_t) (gpuInfo.max_engine_clk / 1000u);
gpu->index = FF_GPU_INDEX_UNSET;
gpu->type = gpuInfo.ids_flags & AMDGPU_IDS_FLAGS_FUSION ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
#define FF_VRAM_CASE(name, value) case value /* AMDGPU_VRAM_TYPE_ ## name */: ffStrbufSetStatic(&gpu->memoryType, #name); break
switch (gpuInfo.vram_type)
{
FF_VRAM_CASE(UNKNOWN, 0);
FF_VRAM_CASE(GDDR1, 1);
FF_VRAM_CASE(DDR2, 2);
FF_VRAM_CASE(GDDR3, 3);
FF_VRAM_CASE(GDDR4, 4);
FF_VRAM_CASE(GDDR5, 5);
FF_VRAM_CASE(HBM, 6);
FF_VRAM_CASE(DDR3, 7);
FF_VRAM_CASE(DDR4, 8);
FF_VRAM_CASE(GDDR6, 9);
FF_VRAM_CASE(DDR5, 10);
FF_VRAM_CASE(LPDDR4, 11);
FF_VRAM_CASE(LPDDR5, 12);
default:
ffStrbufAppendF(&gpu->memoryType, "Unknown (%u)", gpuInfo.vram_type);
break;
}
struct amdgpu_heap_info heapInfo;
if (ffamdgpu_query_heap_info(handle, AMDGPU_GEM_DOMAIN_VRAM, 0, &heapInfo) >= 0)
{
gpu->dedicated.total = heapInfo.heap_size;
gpu->dedicated.used = heapInfo.heap_usage;
}
if (ffamdgpu_query_heap_info(handle, AMDGPU_GEM_DOMAIN_GTT, 0, &heapInfo) >= 0)
{
gpu->shared.total = heapInfo.heap_size;
gpu->shared.used = heapInfo.heap_usage;
}
}
if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_LOAD, sizeof(value), &value) >= 0)
gpu->coreUsage = value;
ffamdgpu_device_deinitialize(handle);
return NULL;
#else
FF_UNUSED(gpu, renderPath);
return "Fastfetch is compiled without libdrm support";
#endif
}
#endif
const char* ffDrmDetectI915(FFGPUResult* gpu, int fd)
{
{
int value;
drm_i915_getparam_t getparam = { .param = I915_PARAM_EU_TOTAL, .value = &value };
if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &getparam) >= 0)
gpu->coreCount = value;
}
{
struct drm_i915_query_item queryItem = {
.query_id = DRM_I915_QUERY_MEMORY_REGIONS,
};
struct drm_i915_query query = {
.items_ptr = (uintptr_t) &queryItem,
.num_items = 1,
};
if (ioctl(fd, DRM_IOCTL_I915_QUERY, &query) >= 0 )
{
FF_AUTO_FREE uint8_t* buffer = calloc(1, (size_t) queryItem.length);
queryItem.data_ptr = (uintptr_t) buffer;
if (ioctl(fd, DRM_IOCTL_I915_QUERY, &query) >= 0)
{
gpu->dedicated.total = gpu->shared.total = gpu->dedicated.used = gpu->shared.used = 0;
struct drm_i915_query_memory_regions* regionInfo = (void*) buffer;
for (uint32_t i = 0; i < regionInfo->num_regions; i++)
{
struct drm_i915_memory_region_info* region = regionInfo->regions + i;
switch (region->region.memory_class)
{
case I915_MEMORY_CLASS_SYSTEM:
gpu->shared.total += region->probed_size;
gpu->shared.used += region->probed_size - region->unallocated_size;
break;
case I915_MEMORY_CLASS_DEVICE:
gpu->dedicated.total += region->probed_size;
gpu->dedicated.used += region->probed_size - region->unallocated_size;
break;
}
}
}
}
}
return NULL;
}
static inline int popcountBytes(uint8_t* bytes, uint32_t length)
{
int count = 0;
while (length >= 8)
{
count += __builtin_popcountll(*(uint64_t*) bytes);
bytes += 8;
length -= 8;
}
if (length >= 4)
{
count += __builtin_popcountl(*(uint32_t*) bytes);
bytes += 4;
length -= 4;
}
if (length >= 2)
{
count += __builtin_popcountl(*(uint16_t*) bytes);
bytes += 2;
length -= 2;
}
if (length)
{
count += __builtin_popcountl(*(uint8_t*) bytes);
}
return count;
}
const char* ffDrmDetectXe(FFGPUResult* gpu, int fd)
{
bool flag = false;
{
struct drm_xe_device_query query = {
.query = DRM_XE_DEVICE_QUERY_GT_TOPOLOGY,
};
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
{
FF_AUTO_FREE uint8_t* buffer = malloc(query.size);
query.data = (uintptr_t) buffer;
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
{
int dssCount = 0, euPerDssCount = 0;
for (struct drm_xe_query_topology_mask* topo = (void*) buffer;
(uint8_t*) topo < buffer + query.size;
topo = (void*) (topo->mask + topo->num_bytes)
) {
switch (topo->type)
{
case DRM_XE_TOPO_DSS_COMPUTE:
case DRM_XE_TOPO_DSS_GEOMETRY:
dssCount += popcountBytes(topo->mask, topo->num_bytes);
break;
case DRM_XE_TOPO_EU_PER_DSS:
euPerDssCount += popcountBytes(topo->mask, topo->num_bytes);
break;
}
}
gpu->coreCount = dssCount * euPerDssCount;
flag = true;
}
}
}
{
struct drm_xe_device_query query = {
.query = DRM_XE_DEVICE_QUERY_MEM_REGIONS,
};
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
{
FF_AUTO_FREE uint8_t* buffer = malloc(query.size);
query.data = (uintptr_t) buffer;
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
{
gpu->dedicated.total = gpu->shared.total = gpu->dedicated.used = gpu->shared.used = 0;
struct drm_xe_query_mem_regions* regionInfo = (void*) buffer;
for (uint32_t i = 0; i < regionInfo->num_mem_regions; i++)
{
struct drm_xe_mem_region* region = regionInfo->mem_regions + i;
switch (region->mem_class)
{
case DRM_XE_MEM_REGION_CLASS_SYSMEM:
gpu->shared.total += region->total_size;
gpu->shared.used += region->used;
break;
case DRM_XE_MEM_REGION_CLASS_VRAM:
gpu->dedicated.total += region->total_size;
gpu->dedicated.used += region->used;
break;
}
}
flag = true;
}
}
}
return flag ? NULL : "Failed to query Xe GPU information";
}
const char* ffDrmDetectAsahi(FFGPUResult* gpu, int fd)
{
struct drm_asahi_params_global paramsGlobal = {};
if (ioctl(fd, DRM_IOCTL_ASAHI_GET_PARAMS, &(struct drm_asahi_get_params) {
.param_group = DRM_ASAHI_GET_PARAMS,
.pointer = (uint64_t) &paramsGlobal,
.size = sizeof(paramsGlobal),
}) >= 0)
{
// They removed `unstable_uabi_version` from the struct. Hopefully they won't introduce new ABI changes.
gpu->coreCount = (int32_t) (paramsGlobal.num_clusters_total * paramsGlobal.num_cores_per_cluster);
gpu->frequency = paramsGlobal.max_frequency_khz / 1000;
gpu->deviceId = paramsGlobal.chip_id;
if (!gpu->name.length)
{
const char* variant = " Unknown";
switch (paramsGlobal.gpu_variant) {
case 'G':
variant = "";
break;
case 'S':
variant = " Pro";
break;
case 'C':
variant = " Max";
break;
case 'D':
variant = " Ultra";
break;
}
ffStrbufSetF(&gpu->name, "Apple M%d%s (G%d%c %02X)",
paramsGlobal.gpu_generation - 12, variant,
paramsGlobal.gpu_generation, paramsGlobal.gpu_variant,
paramsGlobal.gpu_revision + 0xA0);
}
return NULL;
}
return "Failed to query Asahi GPU information";
}
#endif // FF_HAVE_DRM
#include "gpu_driver_specific.h"
const char* ffGPUDetectDriverSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFGpuDriverPciBusId pciBusId)
{
__typeof__(&ffDetectNvidiaGpuInfo) detectFn;
const char* soName;
if (getDriverSpecificDetectionFn(gpu->vendor.chars, &detectFn, &soName) && (options->temp || options->driverSpecific))
{
return detectFn(&(FFGpuDriverCondition) {
.type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID,
.pciBusId = pciBusId,
}, (FFGpuDriverResult) {
.index = &gpu->index,
.temp = options->temp ? &gpu->temperature : NULL,
.memory = options->driverSpecific ? &gpu->dedicated : NULL,
.coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL,
.coreUsage = options->driverSpecific ? &gpu->coreUsage : NULL,
.type = &gpu->type,
.frequency = options->driverSpecific ? &gpu->frequency : NULL,
.name = &gpu->name,
}, soName);
}
return "No driver-specific detection function found for the GPU vendor";
}
+1 -1
View File
@@ -5,7 +5,7 @@
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
{
FF_AUTO_CLOSE_FD int pokefd = open(POKE_DEVICE_FULLNAME, O_RDWR);
FF_AUTO_CLOSE_FD int pokefd = open(POKE_DEVICE_FULLNAME, O_RDWR | O_CLOEXEC);
if (pokefd < 0) return "open(POKE_DEVICE_FULLNAME) failed";
pci_info dev;
+66 -295
View File
@@ -21,10 +21,16 @@
#include <sys/ioctl.h>
#endif
#include "gpu_asahi.h"
#define FF_STR_INDIR(x) #x
#define FF_STR(x) FF_STR_INDIR(x)
#if defined(FF_HAVE_DRM) && defined(__aarch64__)
// https://github.com/alyssarosenzweig/linux/blob/agx-uapi-v7/include/uapi/drm/asahi_drm.h
// Found in kernel-headers-6.14.4-400.asahi.fc42.aarch64
#if __has_include(<drm/asahi_drm.h>)
#include <drm/asahi_drm.h>
#else
#include "asahi_drm.h"
#endif
#define FF_HAVE_DRM_ASAHI 1
#endif
static bool pciDetectDriver(FFstrbuf* result, FFstrbuf* pciDir, FFstrbuf* buffer, FF_MAYBE_UNUSED const char* drmKey)
{
@@ -99,73 +105,23 @@ FF_MAYBE_UNUSED static const char* drmFindRenderFromCard(const char* drmCardKey,
static const char* drmDetectAmdSpecific(const FFGPUOptions* options, FFGPUResult* gpu, const char* drmKey, FFstrbuf* buffer)
{
#if FF_HAVE_DRM_AMDGPU
FF_LIBRARY_LOAD(libdrm, "dlopen libdrm_amdgpu" FF_LIBRARY_EXTENSION " failed", "libdrm_amdgpu" FF_LIBRARY_EXTENSION, 1)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_initialize)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_get_marketing_name)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_gpu_info)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_sensor_info)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_heap_info)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_deinitialize)
#if FF_HAVE_DRM
const char* error = drmFindRenderFromCard(drmKey, buffer);
if (error) return error;
if (ffStrbufEqualS(&gpu->driver, "radeon"))
return ffDrmDetectRadeon(options, gpu, buffer->chars);
else
{
const char* error = drmFindRenderFromCard(drmKey, buffer);
if (error) return error;
#if FF_HAVE_DRM_AMDGPU
return ffDrmDetectAmdgpu(options, gpu, buffer->chars);
#else
FF_UNUSED(options, gpu, drmKey, buffer);
return "Fastfetch is not compiled with libdrm_amdgpu support";
#endif
}
FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY);
if (fd < 0) return "Failed to open DRM device";
amdgpu_device_handle handle;
uint32_t majorVersion, minorVersion;
if (ffamdgpu_device_initialize(fd, &majorVersion, &minorVersion, &handle) < 0)
return "Failed to initialize AMDGPU device";
ffStrbufAppendF(&gpu->driver, " %u.%u", (unsigned) majorVersion, (unsigned) minorVersion);
uint32_t value;
if (options->temp)
{
if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_TEMP, sizeof(value), &value) >= 0)
gpu->temperature = value / 1000.;
}
ffStrbufSetS(&gpu->name, ffamdgpu_get_marketing_name(handle));
struct amdgpu_gpu_info gpuInfo;
if (ffamdgpu_query_gpu_info(handle, &gpuInfo) >= 0)
{
gpu->coreCount = (int32_t) gpuInfo.cu_active_number;
gpu->frequency = (uint32_t) (gpuInfo.max_engine_clk / 1000u);
gpu->index = FF_GPU_INDEX_UNSET;
gpu->type = gpuInfo.ids_flags & AMDGPU_IDS_FLAGS_FUSION ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
struct amdgpu_heap_info heapInfo;
if (ffamdgpu_query_heap_info(handle, AMDGPU_GEM_DOMAIN_VRAM, 0, &heapInfo) >= 0)
{
if (gpu->type == FF_GPU_TYPE_DISCRETE)
{
gpu->dedicated.total = heapInfo.heap_size;
gpu->dedicated.used = heapInfo.heap_usage;
}
else
{
gpu->shared.total = heapInfo.heap_size;
gpu->shared.used = heapInfo.heap_usage;
}
}
}
if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_LOAD, sizeof(value), &value) >= 0)
gpu->coreUsage = value;
ffamdgpu_device_deinitialize(handle);
return NULL;
#else
FF_UNUSED(options, gpu, drmKey, buffer);
return "Fastfetch is compiled without libdrm support";
FF_UNUSED(gpu, drmKey, buffer);
return "Fastfetch is not compiled with drm support";
#endif
}
@@ -189,41 +145,49 @@ static void pciDetectAmdSpecific(const FFGPUOptions* options, FFGPUResult* gpu,
ffStrbufAppendC(pciDir, '/');
const uint32_t hwmonLen = pciDir->length;
ffStrbufAppendS(pciDir, "in1_input"); // Northbridge voltage in millivolts (APUs only)
if (ffPathExists(pciDir->chars, FF_PATHTYPE_ANY))
gpu->type = FF_GPU_TYPE_INTEGRATED;
else
gpu->type = FF_GPU_TYPE_DISCRETE;
uint64_t value = 0;
if (options->temp)
{
ffStrbufSubstrBefore(pciDir, hwmonLen);
ffStrbufAppendS(pciDir, "temp1_input"); // The on die GPU temperature in millidegrees Celsius
if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0)))
gpu->temperature = (double) value / 1000;
}
if (options->driverSpecific)
if (ffStrbufEqualS(&gpu->driver, "amdgpu")) // Ancient radeon drivers don't have these files
{
ffStrbufSubstrBefore(pciDir, pciDirLen);
ffStrbufAppendS(pciDir, "/mem_info_vis_vram_total");
if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0)))
{
if (gpu->type == FF_GPU_TYPE_DISCRETE)
gpu->dedicated.total = value;
else
gpu->shared.total = value;
ffStrbufSubstrBefore(pciDir, hwmonLen);
ffStrbufAppendS(pciDir, "in1_input"); // Northbridge voltage in millivolts (APUs only)
if (ffPathExists(pciDir->chars, FF_PATHTYPE_ANY))
gpu->type = FF_GPU_TYPE_INTEGRATED;
else
gpu->type = FF_GPU_TYPE_DISCRETE;
ffStrbufSubstrBefore(pciDir, pciDir->length - (uint32_t) strlen("/mem_info_vis_vram_total"));
ffStrbufAppendS(pciDir, "/mem_info_vis_vram_used");
if (options->driverSpecific)
{
ffStrbufSubstrBefore(pciDir, pciDirLen);
ffStrbufAppendS(pciDir, "/mem_info_vis_vram_total");
if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0)))
{
if (gpu->type == FF_GPU_TYPE_DISCRETE)
gpu->dedicated.used = value;
gpu->dedicated.total = value;
else
gpu->shared.used = value;
gpu->shared.total = value;
ffStrbufSubstrBefore(pciDir, pciDir->length - (uint32_t) strlen("/mem_info_vis_vram_total"));
ffStrbufAppendS(pciDir, "/mem_info_vis_vram_used");
if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0)))
{
if (gpu->type == FF_GPU_TYPE_DISCRETE)
gpu->dedicated.used = value;
else
gpu->shared.used = value;
}
}
ffStrbufSubstrBefore(pciDir, pciDirLen);
ffStrbufAppendS(pciDir, "/gpu_busy_percent");
if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0)))
gpu->coreUsage = (double) value;
}
}
}
@@ -280,153 +244,19 @@ static void pciDetectIntelSpecific(const FFGPUOptions* options, FFGPUResult* gpu
}
}
static inline int popcountBytes(uint8_t* bytes, uint32_t length)
{
int count = 0;
while (length >= 8)
{
count += __builtin_popcountll(*(uint64_t*) bytes);
bytes += 8;
length -= 8;
}
if (length >= 4)
{
count += __builtin_popcountl(*(uint32_t*) bytes);
bytes += 4;
length -= 4;
}
if (length >= 2)
{
count += __builtin_popcountl(*(uint16_t*) bytes);
bytes += 2;
length -= 2;
}
if (length)
{
count += __builtin_popcountl(*(uint8_t*) bytes);
}
return count;
}
static const char* drmDetectIntelSpecific(FFGPUResult* gpu, const char* drmKey, FFstrbuf* buffer)
{
#if FF_HAVE_DRM
ffStrbufSetS(buffer, "/dev/dri/");
ffStrbufAppendS(buffer, drmKey);
FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY);
FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY | O_CLOEXEC);
if (fd < 0) return "Failed to open drm device";
if (ffStrbufEqualS(&gpu->driver, "xe"))
{
{
struct drm_xe_device_query query = {
.extensions = 0,
.query = DRM_XE_DEVICE_QUERY_GT_TOPOLOGY,
.size = 0,
.data = 0,
};
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
{
FF_AUTO_FREE uint8_t* buffer = malloc(query.size);
query.data = (uintptr_t) buffer;
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
{
int dssCount = 0, euPerDssCount = 0;
for (struct drm_xe_query_topology_mask* topo = (void*) buffer;
(uint8_t*) topo < buffer + query.size;
topo = (void*) (topo->mask + topo->num_bytes)
) {
switch (topo->type)
{
case DRM_XE_TOPO_DSS_COMPUTE:
case DRM_XE_TOPO_DSS_GEOMETRY:
dssCount += popcountBytes(topo->mask, topo->num_bytes);
break;
case DRM_XE_TOPO_EU_PER_DSS:
euPerDssCount += popcountBytes(topo->mask, topo->num_bytes);
break;
}
}
gpu->coreCount = dssCount * euPerDssCount;
}
}
}
{
struct drm_xe_device_query query = {
.query = DRM_XE_DEVICE_QUERY_MEM_REGIONS,
};
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
{
FF_AUTO_FREE uint8_t* buffer = malloc(query.size);
query.data = (uintptr_t) buffer;
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
{
gpu->dedicated.total = gpu->shared.total = gpu->dedicated.used = gpu->shared.used = 0;
struct drm_xe_query_mem_regions* regionInfo = (void*) buffer;
for (uint32_t i = 0; i < regionInfo->num_mem_regions; i++)
{
struct drm_xe_mem_region* region = regionInfo->mem_regions + i;
switch (region->mem_class)
{
case DRM_XE_MEM_REGION_CLASS_SYSMEM:
gpu->shared.total += region->total_size;
gpu->shared.used += region->used;
break;
case DRM_XE_MEM_REGION_CLASS_VRAM:
gpu->dedicated.total += region->total_size;
gpu->dedicated.used += region->used;
break;
}
}
}
}
}
}
return ffDrmDetectXe(gpu, fd);
else if (ffStrbufEqualS(&gpu->driver, "i915"))
{
{
int value;
drm_i915_getparam_t getparam = { .param = I915_PARAM_EU_TOTAL, .value = &value };
if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &getparam) >= 0)
gpu->coreCount = value;
}
{
struct drm_i915_query_item queryItem = {
.query_id = DRM_I915_QUERY_MEMORY_REGIONS,
};
struct drm_i915_query query = {
.items_ptr = (uintptr_t) &queryItem,
.num_items = 1,
};
if (ioctl(fd, DRM_IOCTL_I915_QUERY, &query) >= 0 )
{
FF_AUTO_FREE uint8_t* buffer = calloc(1, (size_t) queryItem.length);
queryItem.data_ptr = (uintptr_t) buffer;
if (ioctl(fd, DRM_IOCTL_I915_QUERY, &query) >= 0)
{
gpu->dedicated.total = gpu->shared.total = gpu->dedicated.used = gpu->shared.used = 0;
struct drm_i915_query_memory_regions* regionInfo = (void*) buffer;
for (uint32_t i = 0; i < regionInfo->num_regions; i++)
{
struct drm_i915_memory_region_info* region = regionInfo->regions + i;
switch (region->region.memory_class)
{
case I915_MEMORY_CLASS_SYSTEM:
gpu->shared.total += region->probed_size;
gpu->shared.used += region->probed_size - region->unallocated_size;
break;
case I915_MEMORY_CLASS_DEVICE:
gpu->dedicated.total += region->probed_size;
gpu->dedicated.used += region->probed_size - region->unallocated_size;
break;
}
}
}
}
}
}
return NULL;
return ffDrmDetectI915(gpu, fd);
return "Unknown Intel GPU driver";
#else
FF_UNUSED(gpu, drmKey, buffer);
return "Fastfetch is not compiled with drm support";
@@ -541,29 +371,12 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf
}
else
{
__typeof__(&ffDetectNvidiaGpuInfo) detectFn;
const char* soName;
if (getDriverSpecificDetectionFn(gpu->vendor.chars, &detectFn, &soName) && (options->temp || options->driverSpecific))
{
detectFn(&(FFGpuDriverCondition) {
.type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID,
.pciBusId = {
.domain = pciDomain,
.bus = pciBus,
.device = pciDevice,
.func = pciFunc,
},
}, (FFGpuDriverResult) {
.index = &gpu->index,
.temp = options->temp ? &gpu->temperature : NULL,
.memory = options->driverSpecific ? &gpu->dedicated : NULL,
.coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL,
.coreUsage = options->driverSpecific ? &gpu->coreUsage : NULL,
.type = &gpu->type,
.frequency = options->driverSpecific ? &gpu->frequency : NULL,
.name = &gpu->name,
}, soName);
}
ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId) {
.domain = pciDomain,
.bus = pciBus,
.device = pciDevice,
.func = pciFunc,
});
}
if (gpu->name.length == 0)
@@ -590,60 +403,18 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf
#if __aarch64__
FF_MAYBE_UNUSED static const char* drmDetectAsahiSpecific(FFGPUResult* gpu, const char* name, FFstrbuf* buffer, const char* drmKey)
FF_MAYBE_UNUSED static const char* drmDetectAsahiSpecific(FFGPUResult* gpu, const char* name, FF_MAYBE_UNUSED FFstrbuf* buffer, FF_MAYBE_UNUSED const char* drmKey)
{
if (sscanf(name, "agx-t%lu", &gpu->deviceId) == 1)
ffStrbufSetStatic(&gpu->name, ffCPUAppleCodeToName((uint32_t) gpu->deviceId));
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE);
#if FF_HAVE_DRM
#if FF_HAVE_DRM_ASAHI
ffStrbufSetS(buffer, "/dev/dri/");
ffStrbufAppendS(buffer, drmKey);
FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY);
FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY | O_CLOEXEC);
if (fd >= 0)
{
struct drm_asahi_params_global paramsGlobal = {};
if (ioctl(fd, DRM_IOCTL_ASAHI_GET_PARAMS, &(struct drm_asahi_get_params) {
.param_group = DRM_ASAHI_GET_PARAMS,
.pointer = (uint64_t) &paramsGlobal,
.size = sizeof(paramsGlobal),
}) >= 0)
{
ffStrbufAppendF(&gpu->driver, " %u", paramsGlobal.unstable_uabi_version);
// FIXME: They will introduce ABI breaking changes. Always check the latest version
// https://www.reddit.com/r/AsahiLinux/comments/1ei2qiv/comment/lgm0v5s/
if (paramsGlobal.unstable_uabi_version == DRM_ASAHI_UNSTABLE_UABI_VERSION)
{
gpu->coreCount = (int) paramsGlobal.num_cores_total_active;
gpu->frequency = paramsGlobal.max_frequency_khz / 1000;
gpu->deviceId = paramsGlobal.chip_id;
if (!gpu->name.length)
{
const char* variant = " Unknown";
switch (paramsGlobal.gpu_variant) {
case 'G':
variant = "";
break;
case 'S':
variant = " Pro";
break;
case 'C':
variant = " Max";
break;
case 'D':
variant = " Ultra";
break;
}
ffStrbufSetF(&gpu->name, "Apple M%d%s (G%d%c %02X)",
paramsGlobal.gpu_generation - 12, variant,
paramsGlobal.gpu_generation, paramsGlobal.gpu_variant,
paramsGlobal.gpu_revision + 0xA0);
}
}
}
}
return ffDrmDetectAsahi(gpu, fd);
#endif
return NULL;
+3 -1
View File
@@ -45,8 +45,10 @@ static const FFstrbuf* loadPciIds()
if (pciids.length == 0)
ffReadFileBuffer(FASTFETCH_TARGET_DIR_USR "/local/share/hwdata/pci.ids", &pciids);
}
#elif __FreeBSD__ || __OpenBSD__ || __NetBSD__
#elif __FreeBSD__ || __NetBSD__
ffReadFileBuffer(_PATH_LOCALBASE "/share/pciids/pci.ids", &pciids);
#elif __OpenBSD__
ffReadFileBuffer(_PATH_LOCALBASE "/share/hwdata/pci.ids", &pciids);
#elif __sun
ffReadFileBuffer(FASTFETCH_TARGET_DIR_ROOT "/usr/share/hwdata/pci.ids", &pciids);
#elif __HAIKU__
+34 -60
View File
@@ -1,83 +1,57 @@
#include "gpu.h"
#include "common/io/io.h"
#include "common/processing.h"
#include "util/stringUtils.h"
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
#include <libdevinfo.h>
static int walkDevTree(di_node_t node, FF_MAYBE_UNUSED di_minor_t minor, FFlist* gpus)
{
// SunOS requires root permission to query PCI device list, except `/usr/bin/scanpci`
// Same behavior can be observed with `cp $(which scanpci) /tmp/ && /tmp/scanpci`
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
const char* error = ffProcessAppendStdOut(&buffer, (char* const[]) {
"/usr/bin/scanpci",
"-v",
NULL,
});
if (error)
return error;
if (!ffStrbufStartsWithS(&buffer, "\npci "))
return "Invalid scanpci result";
// pci bus 0x0000 cardnum 0x00 function 0x00: vendor 0x1414 device 0x008e
// Device unknown
// CardVendor 0x0000 card 0x0000 (Card unknown)
// STATUS 0x0010 COMMAND 0x0007
// CLASS 0x03 0x02 0x00 REVISION 0x00
// BIST 0x00 HEADER 0x00 LATENCY 0x00 CACHE 0x00
// MAX_LAT 0x00 MIN_GNT 0x00 INT_PIN 0x00 INT_LINE 0x00
for (
const char* pclass = strstr(buffer.chars, "\n CLASS 0x03 ");
pclass;
pclass = strstr(pclass, "\n CLASS 0x03 ")
)
int* vendorId;
int* deviceId;
if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "vendor-id", &vendorId) > 0
&& di_prop_lookup_ints(DDI_DEV_T_ANY, node, "device-id", &deviceId) > 0)
{
// find the start of device entry
const char* pstart = memrchr(buffer.chars, '\n', (size_t) (pclass - buffer.chars));
if (pstart == NULL)
return "PCI info not found, invalid scanpci result";
while (pstart[1] != 'p')
{
pstart = memrchr(buffer.chars, '\n', (size_t) (pstart - buffer.chars - 1));
if (pstart == NULL)
return "PCI info not found, invalid scanpci result";
}
++pstart;
uint32_t vendorId, deviceId;
if (sscanf(pstart, "pci %*[^:]: vendor %x device %x",
&vendorId, &deviceId) != 2)
return "PCI info not found, invalid scanpci result";
pclass += strlen("\n CLASS 0x03 ");
uint32_t subclass = (uint32_t) strtoul(pclass, NULL, 16);
pclass += strlen("0x02 0x00 REVISION ");
uint32_t revision = (uint32_t) strtoul(pclass, NULL, 16);
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(vendorId));
ffStrbufInit(&gpu->memoryType);
ffStrbufInitS(&gpu->vendor, ffGPUGetVendorString((uint16_t) *vendorId));
ffStrbufInit(&gpu->name);
ffStrbufInit(&gpu->driver);
ffStrbufInitStatic(&gpu->platformApi, "/usr/bin/scanpci");
ffStrbufInitS(&gpu->driver, di_driver_name(node));
ffStrbufInitStatic(&gpu->platformApi, "libdevinfo");
ffStrbufInit(&gpu->memoryType);
gpu->index = FF_GPU_INDEX_UNSET;
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET;
gpu->type = FF_GPU_TYPE_UNKNOWN;
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = 0;
gpu->deviceId = strtoul(di_bus_addr(node), NULL, 16);
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD)
ffGPUQueryAmdGpuName((uint16_t) deviceId, (uint8_t) revision, gpu);
{
int* revId;
if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "revision-id", &revId) > 0)
ffGPUQueryAmdGpuName((uint16_t) *deviceId, (uint8_t) *revId, gpu);
}
if (gpu->name.length == 0)
{
ffGPUFillVendorAndName((uint8_t) subclass, (uint16_t) vendorId, (uint16_t) deviceId, gpu);
uint8_t subclass = 0; // assume VGA
int* classCode;
if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "class-code", &classCode) > 0)
subclass = (uint8_t) (*classCode & 0xFFFF);
ffGPUFillVendorAndName(subclass, (uint16_t) *vendorId, (uint16_t) *deviceId, gpu);
}
}
return DI_WALK_CONTINUE;
}
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
{
di_node_t rootNode = di_init("/", DINFOCPYALL);
if (rootNode == DI_NODE_NIL)
return "di_init() failed";
di_walk_minor(rootNode, DDI_NT_DISPLAY, DI_WALK_CLDFIRST, gpus, (void*) walkDevTree);
di_fini(rootNode);
return NULL;
}
+1
View File
@@ -12,6 +12,7 @@ const char* ffDetectHost(FFHostResult* host)
|| ffSettingsGetAndroidProperty("ro.vivo.market.name", &host->name)
|| ffSettingsGetAndroidProperty("ro.product.oppo_model", &host->name)
|| ffSettingsGetAndroidProperty("ro.oppo.market.name", &host->name)
|| ffSettingsGetAndroidProperty("ro.vendor.oplus.market.enname", &host->name)
|| ffSettingsGetAndroidProperty("ro.config.devicename", &host->name)
|| ffSettingsGetAndroidProperty("ro.config.marketing_name", &host->name)
|| ffSettingsGetAndroidProperty("ro.product.vendor.model", &host->name)
+4
View File
@@ -36,6 +36,10 @@ const char* getOthersByIokit(FFHostResult* host)
if (manufacturer)
ffCfStrGetString(manufacturer, &host->vendor);
FF_CFTYPE_AUTO_RELEASE CFStringRef version = IORegistryEntryCreateCFProperty(registryEntry, CFSTR("version"), kCFAllocatorDefault, kNilOptions);
if (version)
ffCfStrGetString(version, &host->version);
return NULL;
}
+14 -2
View File
@@ -77,10 +77,11 @@ const char* ffDetectHost(FFHostResult* host)
//On WSL, the real host can't be detected. Instead use WSL as host.
if(wslDistroName != NULL || getenv("WSL_DISTRO") != NULL || getenv("WSL_INTEROP") != NULL)
{
ffStrbufAppendS(&host->name, "Windows Subsystem for Linux");
ffStrbufSetStatic(&host->name, "Windows Subsystem for Linux");
if (wslDistroName)
ffStrbufAppendF(&host->name, " - %s", wslDistroName);
ffStrbufAppendS(&host->family, "WSL");
ffStrbufSetStatic(&host->family, "WSL");
ffStrbufSetStatic(&host->vendor, "Microsoft Corporation");
if (instance.config.general.detectVersion)
{
@@ -92,6 +93,17 @@ const char* ffDetectHost(FFHostResult* host)
}); // supported in 2.2.3 and later
}
}
else if (ffStrbufStartsWithS(&instance.state.platform.sysinfo.version, "FreeBSD "))
{
ffStrbufSetStatic(&host->name, "Linux Binary Compatibility on FreeBSD");
ffStrbufSetStatic(&host->family, "FreeBSD");
ffStrbufSetStatic(&host->vendor, "FreeBSD Foundation");
if (instance.config.general.detectVersion)
{
ffStrbufSetS(&host->version, instance.state.platform.sysinfo.version.chars + strlen("FreeBSD "));
ffStrbufSubstrBeforeFirstC(&host->version, ' ');
}
}
}
return NULL;
+1 -1
View File
@@ -121,7 +121,7 @@ const char* ffHostGetMacProductNameWithHwModel(const FFstrbuf* hwModel)
ffStrEquals(version, "16,5")) return "MacBook Pro (16-inch, 2024, Three Thunderbolt 5 ports)";
if(ffStrEquals(version, "15,14")) return "Mac Studio (M3 Ultra, 2025)";
if(ffStrEquals(version, "15,13")) return "MacBook Air (15-inch, M3, 2024)";
if(ffStrEquals(version, "15,2")) return "MacBook Air (13-inch, M3, 2024)";
if(ffStrEquals(version, "15,12")) return "MacBook Air (13-inch, M3, 2024)";
if(ffStrEquals(version, "15,3")) return "MacBook Pro (14-inch, Nov 2023, Two Thunderbolt / USB 4 ports)";
if(ffStrEquals(version, "15,4")) return "iMac (24-inch, 2023, Two Thunderbolt / USB 4 ports)";
if(ffStrEquals(version, "15,5")) return "iMac (24-inch, 2023, Two Thunderbolt / USB 4 ports, Two USB 3 ports)";
+95 -40
View File
@@ -1,48 +1,35 @@
#include "fastfetch.h"
#include "detection/media/media.h"
#include "common/library.h"
#include "common/processing.h"
#include "util/apple/cf_helpers.h"
#include "util/apple/osascript.h"
#import <Foundation/Foundation.h>
#import <CoreFoundation/CoreFoundation.h>
// https://github.com/andrewwiik/iOS-Blocks/blob/master/Widgets/Music/MediaRemote.h
extern void MRMediaRemoteGetNowPlayingInfo(dispatch_queue_t dispatcher, void(^callback)(_Nullable CFDictionaryRef info)) __attribute__((weak_import));
extern void MRMediaRemoteGetNowPlayingClient(dispatch_queue_t dispatcher, void (^callback)(_Nullable id clientObj)) __attribute__((weak_import));
extern CFStringRef MRNowPlayingClientGetBundleIdentifier(id clientObj) __attribute__((weak_import));
extern CFStringRef MRNowPlayingClientGetParentAppBundleIdentifier(id clientObj) __attribute__((weak_import));
void MRMediaRemoteGetNowPlayingApplicationIsPlaying(dispatch_queue_t queue, void (^callback)(BOOL playing)) __attribute__((weak_import));
extern void MRMediaRemoteGetNowPlayingApplicationIsPlaying(dispatch_queue_t queue, void (^callback)(BOOL playing)) __attribute__((weak_import));
extern void MRMediaRemoteGetNowPlayingApplicationDisplayID(dispatch_queue_t queue, void (^callback)(_Nullable CFStringRef displayID)) __attribute__((weak_import));
extern void MRMediaRemoteGetNowPlayingApplicationDisplayName(int unknown, dispatch_queue_t queue, void (^callback)(_Nullable CFStringRef name)) __attribute__((weak_import));
static const char* getMedia(FFMediaResult* result)
static const char* getMediaByMediaRemote(FFMediaResult* result)
{
#define FF_TEST_FN_EXISTANCE(fn) if (!fn) return "MediaRemote function " #fn " is not available"
FF_TEST_FN_EXISTANCE(MRMediaRemoteGetNowPlayingInfo);
FF_TEST_FN_EXISTANCE(MRMediaRemoteGetNowPlayingClient);
FF_TEST_FN_EXISTANCE(MRNowPlayingClientGetBundleIdentifier);
FF_TEST_FN_EXISTANCE(MRNowPlayingClientGetParentAppBundleIdentifier);
FF_TEST_FN_EXISTANCE(MRMediaRemoteGetNowPlayingApplicationIsPlaying);
#undef FF_TEST_FN_EXISTANCE
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_group_enter(group);
MRMediaRemoteGetNowPlayingApplicationIsPlaying(queue, ^(BOOL playing) {
ffStrbufSetStatic(&result->status, playing ? "Playing" : "Paused");
dispatch_group_leave(group);
});
dispatch_group_enter(group);
__block const char* error = NULL;
MRMediaRemoteGetNowPlayingInfo(queue, ^(_Nullable CFDictionaryRef info) {
if(info != nil)
{
error = ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoTitle"), &result->song);
if(!error)
{
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtist"), &result->artist);
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoAlbum"), &result->album);
}
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoTitle"), &result->song);
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtist"), &result->artist);
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoAlbum"), &result->album);
}
else
error = "MRMediaRemoteGetNowPlayingInfo() failed";
@@ -51,36 +38,104 @@ static const char* getMedia(FFMediaResult* result)
});
dispatch_group_enter(group);
MRMediaRemoteGetNowPlayingClient(queue, ^(_Nullable id clientObj) {
if (clientObj != nil)
{
CFStringRef identifier = MRNowPlayingClientGetBundleIdentifier(clientObj);
if (identifier == nil)
identifier = MRNowPlayingClientGetParentAppBundleIdentifier(clientObj);
if (identifier != nil)
ffCfStrGetString(identifier, &result->playerId);
}
MRMediaRemoteGetNowPlayingApplicationIsPlaying(queue, ^(BOOL playing) {
ffStrbufSetStatic(&result->status, playing ? "Playing" : "Paused");
dispatch_group_leave(group);
});
if (MRMediaRemoteGetNowPlayingApplicationDisplayID)
{
dispatch_group_enter(group);
MRMediaRemoteGetNowPlayingApplicationDisplayID(queue, ^(_Nullable CFStringRef displayID) {
ffCfStrGetString(displayID, &result->playerId);
dispatch_group_leave(group);
});
}
if (MRMediaRemoteGetNowPlayingApplicationDisplayName)
{
dispatch_group_enter(group);
MRMediaRemoteGetNowPlayingApplicationDisplayName(0, queue, ^(_Nullable CFStringRef name) {
ffCfStrGetString(name, &result->player);
dispatch_group_leave(group);
});
}
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
// Don't dispatch_release because we are using ARC
if(result->playerId.length > 0)
{
char buf[128];
snprintf(buf, ARRAY_SIZE(buf), "name of app id \"%s\"", result->playerId.chars);
ffOsascript(buf, &result->player);
}
if(result->song.length > 0)
return NULL;
return error;
}
__attribute__((visibility("default"), used))
int ffPrintMediaByMediaRemote(void)
{
FFMediaResult media = {
.status = ffStrbufCreate(),
.song = ffStrbufCreate(),
.artist = ffStrbufCreate(),
.album = ffStrbufCreate(),
.playerId = ffStrbufCreate(),
.player = ffStrbufCreate(),
};
if (getMediaByMediaRemote(&media) != NULL)
return 1;
ffStrbufPutTo(&media.status, stdout);
ffStrbufPutTo(&media.song, stdout);
ffStrbufPutTo(&media.artist, stdout);
ffStrbufPutTo(&media.album, stdout);
ffStrbufPutTo(&media.playerId, stdout);
ffStrbufPutTo(&media.player, stdout);
ffStrbufDestroy(&media.status);
ffStrbufDestroy(&media.song);
ffStrbufDestroy(&media.artist);
ffStrbufDestroy(&media.album);
ffStrbufDestroy(&media.playerId);
ffStrbufDestroy(&media.player);
return 0;
}
static const char* getMediaByAuthorizedProcess(FFMediaResult* result)
{
// #1737
FF_STRBUF_AUTO_DESTROY script = ffStrbufCreateF("import ctypes;ctypes.CDLL('%s').ffPrintMediaByMediaRemote()", instance.state.platform.exePath.chars);
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
const char* error = ffProcessAppendStdOut(&buffer, (char* const[]) {
"/usr/bin/python3", // Must be signed by Apple. Homebrew python doesn't work
"-c",
script.chars,
nil
});
if (error) return error;
if (buffer.length == 0) return "No media found";
// status\ntitle\nartist\nalbum\nbundleName\nappName
FFstrbuf* const varList[] = { &result->status, &result->song, &result->artist, &result->album, &result->playerId, &result->player };
char* line = NULL;
size_t len = 0;
for (uint32_t i = 0; i < ARRAY_SIZE(varList) && ffStrbufGetline(&line, &len, &buffer); ++i)
ffStrbufSetS(varList[i], line);
return NULL;
}
void ffDetectMediaImpl(FFMediaResult* media)
{
const char* error = getMedia(media);
ffStrbufAppendS(&media->error, error);
const char* error;
if (@available(macOS 15.4, *))
error = getMediaByAuthorizedProcess(media);
else
error = getMediaByMediaRemote(media);
if (error)
ffStrbufAppendS(&media->error, error);
else if (media->player.length == 0 && media->playerId.length > 0)
{
ffStrbufSet(&media->player, &media->playerId);
if (ffStrbufStartsWithIgnCaseS(&media->player, "com."))
ffStrbufSubstrAfter(&media->player, strlen("com.") - 1);
ffStrbufReplaceAllC(&media->player, '.', ' ');
}
}
+1
View File
@@ -142,6 +142,7 @@ static bool getBusProperties(FFDBusData* data, const char* busName, FFMediaResul
ffStrbufClear(&result->artist);
ffStrbufClear(&result->album);
ffStrbufClear(&result->url);
ffStrbufClear(&result->status);
return false;
}
}
+9 -4
View File
@@ -19,11 +19,16 @@ static const char* getMedia(FFMediaResult* media)
}
ffStrbufSetWS(&media->playerId, result.playerId);
ffStrbufSet(&media->player, &media->playerId);
if (ffStrbufEndsWithIgnCaseS(&media->player, ".exe"))
ffStrbufSubstrBefore(&media->player, media->player.length - 4);
if (result.playerName[0])
{
ffStrbufSetWS(&media->player, result.playerName);
}
else
ffStrbufSubstrAfterFirstC(&media->player, '!'); // UWP ID
{
ffStrbufSet(&media->player, &media->playerId);
if (ffStrbufEndsWithIgnCaseS(&media->player, ".exe"))
ffStrbufSubstrBefore(&media->player, media->player.length - 4);
}
ffStrbufSetWS(&media->song, result.song);
ffStrbufSetWS(&media->artist, result.artist);
ffStrbufSetWS(&media->album, result.album);
@@ -1,5 +1,6 @@
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Media.Control.h>
#include <winrt/Windows.ApplicationModel.h>
#include <wchar.h>
extern "C"
@@ -11,6 +12,7 @@ const char* ffWinrtDetectMedia(FFWinrtMediaResult* result)
// C++/WinRT requires Windows 8.1+ and C++ runtime (std::string, exceptions and other stuff)
// Make it a separate dll in order not to break Windows 7 support
using namespace winrt::Windows::Media::Control;
using namespace winrt::Windows::ApplicationModel;
try
{
@@ -48,6 +50,11 @@ const char* ffWinrtDetectMedia(FFWinrtMediaResult* result)
::wcsncpy(result->song, mediaProps.Title().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
::wcsncpy(result->artist, mediaProps.Artist().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
::wcsncpy(result->album, mediaProps.AlbumTitle().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
try
{
// Only works for UWP apps
::wcsncpy(result->playerName, AppInfo::GetFromAppUserModelId(session.SourceAppUserModelId()).DisplayInfo().DisplayName().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
} catch (...) { }
return NULL;
}
+1
View File
@@ -5,6 +5,7 @@
typedef struct FFWinrtMediaResult
{
wchar_t playerId[FF_MEDIA_WIN_RESULT_BUFLEN];
wchar_t playerName[FF_MEDIA_WIN_RESULT_BUFLEN];
wchar_t song[FF_MEDIA_WIN_RESULT_BUFLEN];
wchar_t artist[FF_MEDIA_WIN_RESULT_BUFLEN];
wchar_t album[FF_MEDIA_WIN_RESULT_BUFLEN];
+3 -2
View File
@@ -8,8 +8,9 @@ const char* ffDetectMemory(FFMemoryResult* ram)
if (get_system_info(&info) != B_OK)
return "Error getting system info";
ram->bytesTotal = B_PAGE_SIZE * info.max_pages;
ram->bytesUsed = B_PAGE_SIZE * info.used_pages;
uint32_t pageSize = instance.state.platform.sysinfo.pageSize;
ram->bytesTotal = pageSize * info.max_pages;
ram->bytesUsed = pageSize * info.used_pages;
return NULL;
}
+8 -1
View File
@@ -25,6 +25,11 @@ static void parseSystemVersion(FFOSResult* os)
ffStrbufInitS(&os->version, value.UTF8String);
if((value = dict[@"ProductBuildVersion"]))
ffStrbufInitS(&os->buildID, value.UTF8String);
if (ffStrbufStartsWithS(&os->version, "16."))
{
// macOS 26 Tahoe. #1809
os->version.chars[0] = '2';
}
}
static bool detectOSCodeName(FFOSResult* os)
@@ -37,6 +42,8 @@ static bool detectOSCodeName(FFOSResult* os)
switch (num)
{
case 26:
case 16: ffStrbufSetStatic(&os->codename, "Tahoe"); return true;
case 15: ffStrbufSetStatic(&os->codename, "Sequoia"); return true;
case 14: ffStrbufSetStatic(&os->codename, "Sonoma"); return true;
case 13: ffStrbufSetStatic(&os->codename, "Ventura"); return true;
@@ -62,7 +69,7 @@ static bool detectOSCodeName(FFOSResult* os)
case 6: ffStrbufSetStatic(&os->codename, "Snow Leopard"); return true;
case 5: ffStrbufSetStatic(&os->codename, "Leopard"); return true;
case 4: ffStrbufSetStatic(&os->codename, "Tiger"); return true;
case 3: ffStrbufSetStatic(&os->codename, "Panther"); ffStrbufSetStatic(&os->prettyName, "Mac OS X"); return true;
case 3: ffStrbufSetStatic(&os->codename, "Panther"); return true;
case 2: ffStrbufSetStatic(&os->codename, "Jaguar"); return true;
case 1: ffStrbufSetStatic(&os->codename, "Puma"); return true;
case 0: ffStrbufSetStatic(&os->codename, "Cheetah"); return true;
+106 -60
View File
@@ -47,7 +47,7 @@ FF_MAYBE_UNUSED static bool detectArmbianVersion(FFOSResult* result)
// - `Armbian_Security` for images with kali repo added
// - `Armbian-unofficial` for an unofficial image built from source, e.g. during development and testing
if (ffStrbufStartsWithS(&result->prettyName, "Armbian"))
ffStrbufSetS(&result->name, "Armbian");
ffStrbufSetStatic(&result->name, "Armbian");
else
return false;
ffStrbufSet(&result->idLike, &result->id);
@@ -69,113 +69,113 @@ FF_MAYBE_UNUSED static void getUbuntuFlavour(FFOSResult* result)
return;
else if(ffStrbufStartsWithS(&result->prettyName, "Linux Lite "))
{
ffStrbufSetS(&result->name, "Linux Lite");
ffStrbufSetS(&result->id, "linuxlite");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->name, "Linux Lite");
ffStrbufSetStatic(&result->id, "linuxlite");
ffStrbufSetStatic(&result->idLike, "ubuntu");
ffStrbufSetS(&result->versionID, result->prettyName.chars + strlen("Linux Lite "));
return;
}
else if(ffStrbufStartsWithS(&result->prettyName, "Rhino Linux "))
{
ffStrbufSetS(&result->name, "Rhino Linux");
ffStrbufSetS(&result->id, "rhinolinux");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->name, "Rhino Linux");
ffStrbufSetStatic(&result->id, "rhinolinux");
ffStrbufSetStatic(&result->idLike, "ubuntu");
ffStrbufSetS(&result->versionID, result->prettyName.chars + strlen("Rhino Linux "));
return;
}
else if(ffStrbufStartsWithS(&result->prettyName, "VanillaOS "))
{
ffStrbufSetS(&result->id, "vanilla");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->id, "vanilla");
ffStrbufSetStatic(&result->idLike, "ubuntu");
}
if(ffStrContains(xdgConfigDirs, "kde") || ffStrContains(xdgConfigDirs, "plasma") || ffStrContains(xdgConfigDirs, "kubuntu"))
{
ffStrbufSetS(&result->name, "Kubuntu");
ffStrbufSetS(&result->prettyName, "Kubuntu");
ffStrbufSetS(&result->id, "kubuntu");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->name, "Kubuntu");
ffStrbufSetF(&result->prettyName, "Kubuntu %s", result->version.chars);
ffStrbufSetStatic(&result->id, "kubuntu");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
}
if(ffStrContains(xdgConfigDirs, "xfce") || ffStrContains(xdgConfigDirs, "xubuntu"))
{
ffStrbufSetS(&result->name, "Xubuntu");
ffStrbufSetS(&result->prettyName, "Xubuntu");
ffStrbufSetS(&result->id, "xubuntu");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->name, "Xubuntu");
ffStrbufSetF(&result->prettyName, "Xubuntu %s", result->version.chars);
ffStrbufSetStatic(&result->id, "xubuntu");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
}
if(ffStrContains(xdgConfigDirs, "lxqt") || ffStrContains(xdgConfigDirs, "lubuntu"))
{
ffStrbufSetS(&result->name, "Lubuntu");
ffStrbufSetS(&result->prettyName, "Lubuntu");
ffStrbufSetS(&result->id, "lubuntu");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->name, "Lubuntu");
ffStrbufSetF(&result->prettyName, "Lubuntu %s", result->version.chars);
ffStrbufSetStatic(&result->id, "lubuntu");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
}
if(ffStrContains(xdgConfigDirs, "budgie"))
{
ffStrbufSetS(&result->name, "Ubuntu Budgie");
ffStrbufSetS(&result->prettyName, "Ubuntu Budgie");
ffStrbufSetS(&result->id, "ubuntu-budgie");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->name, "Ubuntu Budgie");
ffStrbufSetF(&result->prettyName, "Ubuntu Budgie %s", result->version.chars);
ffStrbufSetStatic(&result->id, "ubuntu-budgie");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
}
if(ffStrContains(xdgConfigDirs, "cinnamon"))
{
ffStrbufSetS(&result->name, "Ubuntu Cinnamon");
ffStrbufSetS(&result->prettyName, "Ubuntu Cinnamon");
ffStrbufSetS(&result->id, "ubuntu-cinnamon");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->name, "Ubuntu Cinnamon");
ffStrbufSetF(&result->prettyName, "Ubuntu Cinnamon %s", result->version.chars);
ffStrbufSetStatic(&result->id, "ubuntu-cinnamon");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
}
if(ffStrContains(xdgConfigDirs, "mate"))
{
ffStrbufSetS(&result->name, "Ubuntu MATE");
ffStrbufSetS(&result->prettyName, "Ubuntu MATE");
ffStrbufSetS(&result->id, "ubuntu-mate");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->name, "Ubuntu MATE");
ffStrbufSetF(&result->prettyName, "Ubuntu MATE %s", result->version.chars);
ffStrbufSetStatic(&result->id, "ubuntu-mate");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
}
if(ffStrContains(xdgConfigDirs, "studio"))
{
ffStrbufSetS(&result->name, "Ubuntu Studio");
ffStrbufSetS(&result->prettyName, "Ubuntu Studio");
ffStrbufSetS(&result->id, "ubuntu-studio");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->name, "Ubuntu Studio");
ffStrbufSetF(&result->prettyName, "Ubuntu Studio %s", result->version.chars);
ffStrbufSetStatic(&result->id, "ubuntu-studio");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
}
if(ffStrContains(xdgConfigDirs, "sway"))
{
ffStrbufSetS(&result->name, "Ubuntu Sway");
ffStrbufSetS(&result->prettyName, "Ubuntu Sway");
ffStrbufSetS(&result->id, "ubuntu-sway");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->name, "Ubuntu Sway");
ffStrbufSetF(&result->prettyName, "Ubuntu Sway %s", result->version.chars);
ffStrbufSetStatic(&result->id, "ubuntu-sway");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
}
if(ffStrContains(xdgConfigDirs, "touch"))
{
ffStrbufSetS(&result->name, "Ubuntu Touch");
ffStrbufSetS(&result->prettyName, "Ubuntu Touch");
ffStrbufSetS(&result->id, "ubuntu-touch");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->name, "Ubuntu Touch");
ffStrbufSetF(&result->prettyName, "Ubuntu Touch %s", result->version.chars);
ffStrbufSetStatic(&result->id, "ubuntu-touch");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
}
if(ffStrContains(xdgConfigDirs, "lliurex"))
{
ffStrbufSetS(&result->name, "LliureX");
ffStrbufSetS(&result->prettyName, "LliureX");
ffStrbufSetS(&result->id, "lliurex");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->name, "LliureX");
ffStrbufSetF(&result->prettyName, "LliureX %s", result->version.chars);
ffStrbufSetStatic(&result->id, "lliurex");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
}
}
@@ -196,8 +196,8 @@ FF_MAYBE_UNUSED static bool detectDebianDerived(FFOSResult* result)
return true;
else if (ffStrbufStartsWithS(&result->name, "Loc-OS"))
{
ffStrbufSetS(&result->id, "locos");
ffStrbufSetS(&result->idLike, "debian");
ffStrbufSetStatic(&result->id, "locos");
ffStrbufSetStatic(&result->idLike, "debian");
return true;
}
else if (ffStrbufEqualS(&result->name, "Parrot Security"))
@@ -210,15 +210,15 @@ FF_MAYBE_UNUSED static bool detectDebianDerived(FFOSResult* result)
else if (ffStrbufStartsWithS(&result->name, "Lilidog GNU/Linux"))
{
// https://github.com/fastfetch-cli/fastfetch/issues/1373
ffStrbufSetS(&result->id, "lilidog");
ffStrbufSetS(&result->idLike, "debian");
ffStrbufSetStatic(&result->id, "lilidog");
ffStrbufSetStatic(&result->idLike, "debian");
return true;
}
else if (access("/usr/bin/pveversion", X_OK) == 0)
{
ffStrbufSetS(&result->id, "pve");
ffStrbufSetS(&result->idLike, "debian");
ffStrbufSetS(&result->name, "Proxmox VE");
ffStrbufSetStatic(&result->id, "pve");
ffStrbufSetStatic(&result->idLike, "debian");
ffStrbufSetStatic(&result->name, "Proxmox VE");
ffStrbufClear(&result->versionID);
if (ffProcessAppendStdOut(&result->versionID, (char* const[]) {
"/usr/bin/dpkg-query",
@@ -231,15 +231,50 @@ FF_MAYBE_UNUSED static bool detectDebianDerived(FFOSResult* result)
ffStrbufSetF(&result->prettyName, "Proxmox VE %s", result->versionID.chars);
return true;
}
else if (ffPathExists("/etc/rpi-issue", FF_PATHTYPE_FILE))
{
// Raspberry Pi OS
ffStrbufSetStatic(&result->id, "raspbian");
ffStrbufSetStatic(&result->idLike, "debian");
ffStrbufSetStatic(&result->name, "Raspberry Pi OS");
ffStrbufSetStatic(&result->prettyName, "Raspberry Pi OS");
return true;
}
else if (ffPathExists("/boot/dietpi/.version", FF_PATHTYPE_FILE))
{
// DietPi
ffStrbufSetStatic(&result->id, "dietpi");
ffStrbufSetStatic(&result->name, "DietPi");
ffStrbufSetStatic(&result->prettyName, "DietPi");
ffStrbufSetStatic(&result->idLike, "debian");
FF_STRBUF_AUTO_DESTROY core = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY sub = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY rc = ffStrbufCreate();
if (ffParsePropFileValues("/boot/dietpi/.version", 3, (FFpropquery[]) {
{"G_DIETPI_VERSION_CORE=", &core},
{"G_DIETPI_VERSION_SUB=", &sub},
{"G_DIETPI_VERSION_RC=", &rc},
})) ffStrbufAppendF(&result->prettyName, " %s.%s.%s", core.chars, sub.chars, rc.chars);
return true;
}
else if (ffStrbufEndsWithS(&instance.state.platform.sysinfo.release, "+truenas"))
{
// TrueNAS Scale
ffStrbufSetStatic(&result->id, "truenas-scale");
ffStrbufSetStatic(&result->idLike, "debian");
ffStrbufSetStatic(&result->name, "TrueNAS Scale");
ffStrbufSetStatic(&result->prettyName, "TrueNAS Scale");
return true;
}
else
{
// Hack for MX Linux. See #847
FF_STRBUF_AUTO_DESTROY lsbRelease = ffStrbufCreate();
if (ffAppendFileBuffer("/etc/lsb-release", &lsbRelease) && ffStrbufContainS(&lsbRelease, "DISTRIB_ID=MX"))
{
ffStrbufSetS(&result->id, "mx");
ffStrbufSetS(&result->idLike, "debian");
ffStrbufSetS(&result->name, "MX");
ffStrbufSetStatic(&result->id, "mx");
ffStrbufSetStatic(&result->idLike, "debian");
ffStrbufSetStatic(&result->name, "MX");
ffStrbufClear(&result->version);
ffParsePropLines(lsbRelease.chars, "DISTRIB_RELEASE=", &result->version);
@@ -286,8 +321,19 @@ static void detectOS(FFOSResult* os)
parseOsRelease(FASTFETCH_TARGET_DIR_ETC "/os-release", os);
if (os->id.length == 0 || os->version.length == 0 || os->prettyName.length == 0 || os->codename.length == 0)
parseLsbRelease(FASTFETCH_TARGET_DIR_ETC "/lsb-release", os);
if (os->id.length == 0 || os->name.length > 0 || os->prettyName.length > 0)
if (os->id.length == 0 || os->name.length == 0 || os->prettyName.length == 0)
parseOsRelease(FASTFETCH_TARGET_DIR_USR "/lib/os-release", os);
if (os->id.length == 0 && os->name.length == 0 && os->prettyName.length == 0)
{
// HarmonyOS has no os-release file
if (ffStrbufEqualS(&instance.state.platform.sysinfo.name, "HarmonyOS"))
{
ffStrbufSetS(&os->id, "harmonyos");
ffStrbufSetS(&os->idLike, "harmonyos");
ffStrbufSetS(&os->name, "HarmonyOS");
ffStrbufSetS(&os->prettyName, "HarmonyOS");
}
}
}
void ffDetectOSImpl(FFOSResult* os)
+11 -10
View File
@@ -100,22 +100,23 @@ uint32_t ffPackagesGetNumElements(const char* dirname, bool isdir)
{
bool ok = false;
#if !defined(__sun) && !defined(__HAIKU__)
if(entry->d_type != DT_UNKNOWN && entry->d_type != DT_LNK)
ok = entry->d_type == (isdir ? DT_DIR : DT_REG);
else
#endif
if (entry->d_name[0] != '.')
{
struct stat stbuf;
if (fstatat(dirfd(dirp), entry->d_name, &stbuf, 0) == 0)
ok = isdir ? S_ISDIR(stbuf.st_mode) : S_ISREG(stbuf.st_mode);
#if !defined(__sun) && !defined(__HAIKU__)
if(entry->d_type != DT_UNKNOWN && entry->d_type != DT_LNK)
ok = entry->d_type == (isdir ? DT_DIR : DT_REG);
else
#endif
{
struct stat stbuf;
if (fstatat(dirfd(dirp), entry->d_name, &stbuf, 0) == 0)
ok = isdir ? S_ISDIR(stbuf.st_mode) : S_ISREG(stbuf.st_mode);
}
}
if(ok) ++num_elements;
}
if(isdir && num_elements >= 2)
num_elements -= 2; // accounting for . and ..
return num_elements;
}
+5 -1
View File
@@ -554,7 +554,11 @@ static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts,
if (!(options->disabled & FF_PACKAGES_FLAG_PACMAN_BIT)) packageCounts->pacman += getNumElements(baseDir, "/var/lib/pacman/local", true);
if (!(options->disabled & FF_PACKAGES_FLAG_LPKGBUILD_BIT)) packageCounts->lpkgbuild += getNumElements(baseDir, "/opt/Loc-OS-LPKG/lpkgbuild/remove", false);
if (!(options->disabled & FF_PACKAGES_FLAG_PKGTOOL_BIT)) packageCounts->pkgtool += getNumElements(baseDir, "/var/log/packages", false);
if (!(options->disabled & FF_PACKAGES_FLAG_RPM_BIT)) packageCounts->rpm += getSQLite3Int(baseDir, "/var/lib/rpm/rpmdb.sqlite", "SELECT count(*) FROM Packages", "rpm");
if (!(options->disabled & FF_PACKAGES_FLAG_RPM_BIT))
{
// `Sigmd5` is the only table that doesn't contain the virtual `gpg-pubkey` package
packageCounts->rpm += getSQLite3Int(baseDir, "/var/lib/rpm/rpmdb.sqlite", "SELECT count(*) FROM Sigmd5", "rpm");
}
if (!(options->disabled & FF_PACKAGES_FLAG_SNAP_BIT)) packageCounts->snap += getSnap(baseDir);
if (!(options->disabled & FF_PACKAGES_FLAG_XBPS_BIT)) packageCounts->xbps += getXBPS(baseDir, "/var/db/xbps");
if (!(options->disabled & FF_PACKAGES_FLAG_BREW_BIT))
+9
View File
@@ -0,0 +1,9 @@
#include "packages.h"
#include "common/io/io.h"
void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
{
if (!(options->disabled & FF_PACKAGES_FLAG_PKGSRC_BIT))
result->pkgsrc = ffPackagesGetNumElements(FASTFETCH_TARGET_DIR_ROOT "/usr/pkg/pkgdb", true);
}
-5
View File
@@ -4,11 +4,6 @@
void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
{
#if __OpenBSD__
if (!(options->disabled & FF_PACKAGES_FLAG_PKG_BIT))
result->pkg = ffPackagesGetNumElements(FASTFETCH_TARGET_DIR_ROOT "/var/db/pkg", true);
#elif __NetBSD__
if (!(options->disabled & FF_PACKAGES_FLAG_PKGSRC_BIT))
result->pkgsrc = ffPackagesGetNumElements(FASTFETCH_TARGET_DIR_ROOT "/usr/pkg/pkgdb", true);
#endif
}
@@ -65,6 +65,7 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
FFPhysicalDiskResult* device = (FFPhysicalDiskResult*) ffListAdd(result);
ffStrbufInitF(&device->devPath, "/dev/%s", provider->lg_name);
ffStrbufInitMove(&device->serial, &identifier);
ffStrbufTrim(&device->serial, ' ');
ffStrbufInit(&device->revision);
ffStrbufInit(&device->interconnect);
switch (snapIter->device_type & DEVSTAT_TYPE_IF_MASK)
@@ -10,7 +10,7 @@
static const char* detectDisk(FFstrbuf* path, const char* diskType, FFlist* result)
{
FF_AUTO_CLOSE_FD int rawfd = open(path->chars, O_RDONLY);
FF_AUTO_CLOSE_FD int rawfd = open(path->chars, O_RDONLY | O_CLOEXEC);
if (rawfd < 0) return "detectDisk: open(rawfd) failed";
device_geometry geometry;
@@ -106,7 +106,10 @@ static void parsePhysicalDisk(int dfd, const char* devName, FFPhysicalDiskOption
else if (strstr(pathSysDeviceReal, "/nvme") != NULL)
ffStrbufSetStatic(&device->interconnect, "NVMe");
else if (strstr(pathSysDeviceReal, "/virtio") != NULL)
{
ffStrbufSetStatic(&device->interconnect, "Virtual");
isVirtual = true;
}
else
{
if (ffAppendFileBufferRelative(devfd, "transport", &device->interconnect))
@@ -150,7 +153,7 @@ static void parsePhysicalDisk(int dfd, const char* devName, FFPhysicalDiskOption
{
ffStrbufInit(&device->serial);
if (ffReadFileBufferRelative(devfd, "serial", &device->serial))
ffStrbufTrimRightSpace(&device->serial);
ffStrbufTrim(&device->serial, ' ');
}
{
@@ -0,0 +1,71 @@
#include "physicaldisk.h"
#include "util/stringUtils.h"
#include "sys/scsi/generic/inquiry.h"
#include <libdevinfo.h>
#include <sys/stat.h>
struct FFWalkTreeBundle
{
FFPhysicalDiskOptions* options;
FFlist* disks;
};
static int walkDevTree(di_node_t node, di_minor_t minor, struct FFWalkTreeBundle* bundle)
{
if (di_minor_spectype(minor) != S_IFCHR || !ffStrEquals(di_minor_name(minor), "a,raw")) return DI_WALK_CONTINUE;
char* productId;
char* vendorId;
if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "inquiry-product-id", &productId) > 0
&& di_prop_lookup_strings(DDI_DEV_T_ANY, node, "inquiry-vendor-id", &vendorId) > 0)
{
FF_STRBUF_AUTO_DESTROY name = ffStrbufCreateF("%s %s", vendorId, productId);
if (bundle->options->namePrefix.length && !ffStrbufStartsWithIgnCase(&name, &bundle->options->namePrefix))
return DI_WALK_CONTINUE;
FFPhysicalDiskResult* device = (FFPhysicalDiskResult*) ffListAdd(bundle->disks);
ffStrbufInitMove(&device->name, &name);
ffStrbufInitF(&device->devPath, "/devices%s", di_devfs_path(node));
ffStrbufInit(&device->serial);
ffStrbufInit(&device->revision);
ffStrbufInit(&device->interconnect);
device->temperature = FF_PHYSICALDISK_TEMP_UNSET;
device->type = FF_PHYSICALDISK_TYPE_NONE;
device->size = 0;
char* buf;
if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "inquiry-serial-no", &buf) > 0)
ffStrbufSetS(&device->serial, buf);
if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "inquiry-revision-id", &buf) > 0)
ffStrbufSetS(&device->revision, buf);
if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "class", &buf) > 0)
ffStrbufSetS(&device->interconnect, buf);
device->type |= di_prop_find(DDI_DEV_T_ANY, node, "removable-media") ? FF_PHYSICALDISK_TYPE_REMOVABLE : FF_PHYSICALDISK_TYPE_FIXED;
int* value;
if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "device-solid-state", &value) > 0)
device->type |= *value ? FF_PHYSICALDISK_TYPE_SSD : FF_PHYSICALDISK_TYPE_HDD;
if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "inquiry-device-type", &value) > 0)
device->type |= *value == DTYPE_DIRECT ? FF_PHYSICALDISK_TYPE_READWRITE : *value == DTYPE_RODIRECT ? FF_PHYSICALDISK_TYPE_READONLY : 0;
int64_t* nblocks;
if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, "device-nblocks", &nblocks) > 0
&& di_prop_lookup_ints(DDI_DEV_T_ANY, node, "device-blksize", &value) > 0)
device->size = (uint64_t) ((uint64_t) *nblocks * (uint64_t) *value);
}
return DI_WALK_CONTINUE;
}
const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
{
di_node_t rootNode = di_init("/", DINFOCPYALL);
if (rootNode == DI_NODE_NIL)
return "di_init() failed";
di_walk_minor(rootNode, DDI_NT_BLOCK, DI_WALK_CLDFIRST, &(struct FFWalkTreeBundle) { options, result }, (void*) walkDevTree);
di_fini(rootNode);
return NULL;
}
+909
View File
@@ -0,0 +1,909 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (C) 4Front Technologies 1996-2008.
*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_AUDIO_OSS_H
#define _SYS_AUDIO_OSS_H
#include <sys/types.h>
#include <sys/time.h>
/*
* These are the ioctl calls for all Solaris /dev/dsp and /dev/mixer audio
* devices.
*
* Note that the contents of this file include definitions which exist
* primarily for compatibility. Many of the defines here are not
* actually implemented, but exist solely to facilitate compilation of
* programs from other operating systems. Other definitions here may
* not be fully supported or may otherwise be obsolete. There are many
* things in this file which should not be used on SunOS.
*
* Please read the documentation to determine which portions of the
* API are fully supported and recommended for use in new
* applications.
*/
#ifdef __cplusplus
extern "C" {
#endif
/*
* Buffer status queries.
* SNDCTL_DSP_GETOSPACE and SNDCTL_DSP_GETISPACE
*/
typedef struct audio_buf_info {
int fragments; /* # of available fragments */
int fragstotal; /* Total # of fragments allocated */
int fragsize; /* Size of a fragment in bytes */
int bytes; /* Available space in bytes */
/* Note! 'bytes' could be more than fragments*fragsize */
} audio_buf_info;
/*
* Sync groups for audio devices.
* SNDCTL_DSP_SYNCGROUP and SNDCTL_DSP_SYNCSTART
*/
typedef struct oss_syncgroup {
int id;
int mode;
int filler[16];
} oss_syncgroup;
/*
* SNDCTL_DSP_GETERROR
*/
typedef struct audio_errinfo {
int play_underruns;
int rec_overruns;
unsigned int play_ptradjust;
unsigned int rec_ptradjust;
int play_errorcount;
int rec_errorcount;
int play_lasterror;
int rec_lasterror;
int play_errorparm;
int rec_errorparm;
int filler[16];
} audio_errinfo;
/*
* SNDCTL_DSP_GETIPTR and SNDCTL_DSP_GETOPTR
*/
typedef struct count_info {
unsigned int bytes; /* Total # of bytes processed */
int blocks; /* # of fragment transitions since last time */
int ptr; /* Current DMA pointer value */
} count_info;
/*
* SNDCTL_DSP_CURENT_IPTR and SNDCTL_DSP_CURRENT_OPTR
*/
typedef struct {
long long samples; /* Total # of samples */
int fifo_samples; /* Samples in device FIFO */
int filler[32]; /* For future use */
} oss_count_t;
/*
* SNDCTL_DSP_GET_RECSRC_NAMES and SNDCTL_DSP_GET_PLAYTGT_NAMES
*/
#define OSS_ENUM_MAXVALUE 255
typedef struct oss_mixer_enuminfo {
int dev;
int ctrl;
int nvalues;
int version;
short strindex[OSS_ENUM_MAXVALUE];
char strings[3000];
} oss_mixer_enuminfo;
/*
* Digital interface (S/PDIF) control interface
* SNDCTL_DSP_READCTL and SNDCTL_DSP_WRITECTL
*/
typedef struct oss_digital_control {
unsigned int caps;
#define DIG_CBITIN_NONE 0x00000000
#define DIG_CBITIN_LIMITED 0x00000001
#define DIG_CBITIN_DATA 0x00000002
#define DIG_CBITIN_BYTE0 0x00000004
#define DIG_CBITIN_FULL 0x00000008
#define DIG_CBITIN_MASK 0x0000000f
#define DIG_CBITOUT_NONE 0x00000000
#define DIG_CBITOUT_LIMITED 0x00000010
#define DIG_CBITOUT_BYTE0 0x00000020
#define DIG_CBITOUT_FULL 0x00000040
#define DIG_CBITOUT_DATA 0x00000080
#define DIG_CBITOUT_MASK 0x000000f0
#define DIG_UBITIN 0x00000100
#define DIG_UBITOUT 0x00000200
#define DIG_VBITOUT 0x00000400
#define DIG_OUTRATE 0x00000800
#define DIG_INRATE 0x00001000
#define DIG_INBITS 0x00002000
#define DIG_OUTBITS 0x00004000
#define DIG_EXACT 0x00010000
#define DIG_PRO 0x00020000
#define DIG_CONSUMER 0x00040000
#define DIG_PASSTHROUGH 0x00080000
#define DIG_OUTSEL 0x00100000
unsigned int valid;
#define VAL_CBITIN 0x00000001
#define VAL_UBITIN 0x00000002
#define VAL_CBITOUT 0x00000004
#define VAL_UBITOUT 0x00000008
#define VAL_ISTATUS 0x00000010
#define VAL_IRATE 0x00000020
#define VAL_ORATE 0x00000040
#define VAL_INBITS 0x00000080
#define VAL_OUTBITS 0x00000100
#define VAL_REQUEST 0x00000200
#define VAL_OUTSEL 0x00000400
#define VAL_OUTMASK (VAL_CBITOUT|VAL_UBITOUT|VAL_ORATE|VAL_OUTBITS|VAL_OUTSEL)
unsigned int request;
unsigned int param;
#define SPD_RQ_PASSTHROUGH 1
unsigned char cbitin[24];
unsigned char ubitin[24];
unsigned char cbitout[24];
unsigned char ubitout[24];
unsigned int outsel;
#define OUTSEL_DIGITAL 1
#define OUTSEL_ANALOG 2
#define OUTSEL_BOTH (OUTSEL_DIGITAL|OUTSEL_ANALOG)
int in_data; /* Audio/data if autodetectable by receiver */
#define IND_UNKNOWN 0
#define IND_AUDIO 1
#define IND_DATA 2
int in_locked; /* Receiver locked */
#define LOCK_NOT_INDICATED 0
#define LOCK_UNLOCKED 1
#define LOCK_LOCKED 2
int in_quality; /* Input signal quality */
#define IN_QUAL_NOT_INDICATED 0
#define IN_QUAL_POOR 1
#define IN_QUAL_GOOD 2
int in_vbit;
int out_vbit; /* V bits */
#define VBIT_NOT_INDICATED 0
#define VBIT_OFF 1
#define VBIT_ON 2
unsigned int in_errors; /* Various input error conditions */
#define INERR_CRC 0x0001
#define INERR_QCODE_CRC 0x0002
#define INERR_PARITY 0x0004
#define INERR_BIPHASE 0x0008
int srate_in;
int srate_out;
int bits_in;
int bits_out;
int filler[32];
} oss_digital_control;
/*
* The "new" mixer API.
*
* This improved mixer API makes it possible to access every possible feature
* of every possible device. However you should read the mixer programming
* section of the OSS API Developer's Manual. There is no chance that you
* could use this interface correctly just by examining this header.
*/
#define OSS_VERSION 0x040003
#define SOUND_VERSION OSS_VERSION
typedef struct oss_sysinfo {
char product[32]; /* E.g. SunOS Audio */
char version[32]; /* E.g. 4.0a */
int versionnum; /* See OSS_GETVERSION */
char options[128]; /* NOT SUPPORTED */
int numaudios; /* # of audio/dsp devices */
int openedaudio[8]; /* Mask of audio devices are busy */
int numsynths; /* NOT SUPPORTED, always 0 */
int nummidis; /* NOT SUPPORTED, always 0 */
int numtimers; /* NOT SUPPORTED, always 0 */
int nummixers; /* # of mixer devices */
int openedmidi[8]; /* Mask of midi devices are busy */
int numcards; /* Number of sound cards in the system */
int numaudioengines; /* Number of audio engines in the system */
char license[16]; /* E.g. "GPL" or "CDDL" */
char revision_info[256]; /* For internal use */
int filler[172]; /* For future expansion */
} oss_sysinfo;
typedef struct oss_mixext {
int dev; /* Mixer device number */
int ctrl; /* Extension number */
int type; /* Entry type */
#define MIXT_DEVROOT 0 /* Device root entry */
#define MIXT_GROUP 1 /* Controller group */
#define MIXT_ONOFF 2 /* OFF (0) or ON (1) */
#define MIXT_ENUM 3 /* Enumerated (0 to maxvalue) */
#define MIXT_MONOSLIDER 4 /* Mono slider (0 to 255) */
#define MIXT_STEREOSLIDER 5 /* Stereo slider (dual 0 to 255) */
#define MIXT_MESSAGE 6 /* (Readable) textual message */
#define MIXT_MONOVU 7 /* VU meter value (mono) */
#define MIXT_STEREOVU 8 /* VU meter value (stereo) */
#define MIXT_MONOPEAK 9 /* VU meter peak value (mono) */
#define MIXT_STEREOPEAK 10 /* VU meter peak value (stereo) */
#define MIXT_RADIOGROUP 11 /* Radio button group */
#define MIXT_MARKER 12 /* Separator between entries */
#define MIXT_VALUE 13 /* Decimal value entry */
#define MIXT_HEXVALUE 14 /* Hexadecimal value entry */
#define MIXT_MONODB 15 /* OBSOLETE */
#define MIXT_STEREODB 16 /* OBSOLETE */
#define MIXT_SLIDER 17 /* Slider (mono, 31 bit int range) */
#define MIXT_3D 18
#define MIXT_MONOSLIDER16 19 /* Mono slider (0-32767) */
#define MIXT_STEREOSLIDER16 20 /* Stereo slider (dual 0-32767) */
#define MIXT_MUTE 21 /* Mute=1, unmute=0 */
/* Possible value range (minvalue to maxvalue) */
/* Note that maxvalue may also be smaller than minvalue */
int maxvalue;
int minvalue;
int flags;
#define MIXF_READABLE 0x00000001 /* Has readable value */
#define MIXF_WRITEABLE 0x00000002 /* Has writeable value */
#define MIXF_POLL 0x00000004 /* May change itself */
#define MIXF_HZ 0x00000008 /* Hertz scale */
#define MIXF_STRING 0x00000010 /* Use dynamic extensions for value */
#define MIXF_DYNAMIC 0x00000010 /* Supports dynamic extensions */
#define MIXF_OKFAIL 0x00000020 /* Interpret value as 1=OK, 0=FAIL */
#define MIXF_FLAT 0x00000040 /* NOT SUPPORTED */
#define MIXF_LEGACY 0x00000080 /* NOT SUPPORTED */
#define MIXF_CENTIBEL 0x00000100 /* Centibel (0.1 dB) step size */
#define MIXF_DECIBEL 0x00000200 /* Step size of 1 dB */
#define MIXF_MAINVOL 0x00000400 /* Main volume control */
#define MIXF_PCMVOL 0x00000800 /* PCM output volume control */
#define MIXF_RECVOL 0x00001000 /* PCM recording volume control */
#define MIXF_MONVOL 0x00002000 /* Input->output monitor volume */
#define MIXF_WIDE 0x00004000 /* NOT SUPPORTED */
#define MIXF_DESCR 0x00008000 /* NOT SUPPORTED */
#define MIXF_DISABLE 0x00010000 /* Control has been disabled */
char id[16]; /* Mnemonic ID (internal use) */
int parent; /* Entry# of parent (-1 if root) */
int dummy; /* NOT SUPPORTED */
int timestamp;
char data[64]; /* Misc data (entry type dependent) */
unsigned char enum_present[32]; /* Mask of allowed enum values */
int control_no; /* NOT SUPPORTED, always -1 */
unsigned int desc; /* Scope flags, etc */
#define MIXEXT_SCOPE_MASK 0x0000003f
#define MIXEXT_SCOPE_OTHER 0x00000000
#define MIXEXT_SCOPE_INPUT 0x00000001
#define MIXEXT_SCOPE_OUTPUT 0x00000002
#define MIXEXT_SCOPE_MONITOR 0x00000003
#define MIXEXT_SCOPE_RECSWITCH 0x00000004
char extname[32];
int update_counter;
#ifdef _KERNEL
int filler[6];
int enumbit;
#else
int filler[7];
#endif
} oss_mixext;
typedef struct oss_mixext_root {
char id[16];
char name[48];
} oss_mixext_root;
typedef struct oss_mixer_value {
int dev;
int ctrl;
int value;
int flags; /* Reserved for future use. Initialize to 0 */
int timestamp; /* Must be set to oss_mixext.timestamp */
int filler[8]; /* Reserved for future use. Initialize to 0 */
} oss_mixer_value;
#define OSS_LONGNAME_SIZE 64
#define OSS_LABEL_SIZE 16
#define OSS_DEVNODE_SIZE 32
typedef char oss_longname_t[OSS_LONGNAME_SIZE];
typedef char oss_label_t[OSS_LABEL_SIZE];
typedef char oss_devnode_t[OSS_DEVNODE_SIZE];
typedef struct oss_audioinfo {
int dev; /* Audio device number */
char name[64];
int busy; /* 0, OPEN_READ, OPEN_WRITE, OPEN_READWRITE */
int pid; /* Process ID, not used in SunOS */
int caps; /* PCM_CAP_INPUT, PCM_CAP_OUTPUT */
int iformats; /* Supported input formats */
int oformats; /* Supported output formats */
int magic; /* Internal use only */
char cmd[64]; /* Command using the device (if known) */
int card_number;
int port_number;
int mixer_dev;
int legacy_device; /* Obsolete field. Replaced by devnode */
int enabled; /* 1=enabled, 0=device not ready */
int flags; /* internal use only - no practical meaning */
int min_rate; /* Minimum sample rate */
int max_rate; /* Maximum sample rate */
int min_channels; /* Minimum number of channels */
int max_channels; /* Maximum number of channels */
int binding; /* DSP_BIND_FRONT, etc. 0 means undefined */
int rate_source;
char handle[32];
#define OSS_MAX_SAMPLE_RATES 20 /* Cannot be changed */
unsigned int nrates; /* Array of supported sample rates */
unsigned int rates[OSS_MAX_SAMPLE_RATES];
oss_longname_t song_name; /* Song name (if given) */
oss_label_t label; /* Device label (if given) */
int latency; /* In usecs, -1=unknown */
oss_devnode_t devnode; /* Device special file name (absolute path) */
int next_play_engine;
int next_rec_engine;
int filler[184];
} oss_audioinfo;
typedef struct oss_mixerinfo {
int dev;
char id[16];
char name[32];
int modify_counter;
int card_number;
int port_number;
char handle[32];
int magic; /* Reserved */
int enabled; /* Reserved */
int caps;
#define MIXER_CAP_VIRTUAL 0x00000001
#define MIXER_CAP_LAYOUT_B 0x00000002 /* For internal use only */
#define MIXER_CAP_NARROW 0x00000004 /* Conserve horiz space */
int flags; /* Reserved */
int nrext;
/*
* The priority field can be used to select the default
* (motherboard) mixer device. The mixer with the highest
* priority is the most preferred one. -2 or less means that
* this device cannot be used as the default mixer.
*/
int priority;
oss_devnode_t devnode; /* Device special file name (absolute path) */
int legacy_device;
int filler[245]; /* Reserved */
} oss_mixerinfo;
typedef struct oss_card_info {
int card;
char shortname[16];
char longname[128];
int flags;
char hw_info[400];
int intr_count;
int ack_count;
int filler[154];
} oss_card_info;
typedef struct mixer_info { /* OBSOLETE */
char id[16];
char name[32];
int modify_counter;
int card_number;
int port_number;
char handle[32];
} mixer_info;
#define MAX_PEAK_CHANNELS 128
typedef unsigned short oss_peaks_t[MAX_PEAK_CHANNELS];
/* For use with SNDCTL_DSP_GET_CHNORDER */
#define CHID_UNDEF 0
#define CHID_L 1
#define CHID_R 2
#define CHID_C 3
#define CHID_LFE 4
#define CHID_LS 5
#define CHID_RS 6
#define CHID_LR 7
#define CHID_RR 8
#define CHNORDER_UNDEF 0x0000000000000000ULL
#define CHNORDER_NORMAL 0x0000000087654321ULL
#define OSSIOCPARM_MASK 0x1fff /* parameters must be < 8192 bytes */
#define OSSIOC_VOID 0x00000000 /* no parameters */
#define OSSIOC_OUT 0x20000000 /* copy out parameters */
#define OSSIOC_IN 0x40000000 /* copy in parameters */
#define OSSIOC_INOUT (OSSIOC_IN|OSSIOC_OUT)
#define OSSIOC_SZ(t) ((sizeof (t) & OSSIOCPARM_MASK) << 16)
#define OSSIOC_GETSZ(x) (((x) >> 16) & OSSIOCPARM_MASK)
#define __OSSIO(x, y) ((int)(OSSIOC_VOID|(x<<8)|y))
#define __OSSIOR(x, y, t) ((int)(OSSIOC_OUT|OSSIOC_SZ(t)|(x<<8)|y))
#define __OSSIOW(x, y, t) ((int)(OSSIOC_IN|OSSIOC_SZ(t)|(x<<8)|y))
#define __OSSIOWR(x, y, t) ((int)(OSSIOC_INOUT|OSSIOC_SZ(t)|(x<<8)|y))
#define SNDCTL_SYSINFO __OSSIOR('X', 1, oss_sysinfo)
#define OSS_SYSINFO SNDCTL_SYSINFO /* Old name */
#define SNDCTL_MIX_NRMIX __OSSIOR('X', 2, int)
#define SNDCTL_MIX_NREXT __OSSIOWR('X', 3, int)
#define SNDCTL_MIX_EXTINFO __OSSIOWR('X', 4, oss_mixext)
#define SNDCTL_MIX_READ __OSSIOWR('X', 5, oss_mixer_value)
#define SNDCTL_MIX_WRITE __OSSIOWR('X', 6, oss_mixer_value)
#define SNDCTL_AUDIOINFO __OSSIOWR('X', 7, oss_audioinfo)
#define SNDCTL_MIX_ENUMINFO __OSSIOWR('X', 8, oss_mixer_enuminfo)
#define SNDCTL_MIDIINFO __OSSIO('X', 9)
#define SNDCTL_MIXERINFO __OSSIOWR('X', 10, oss_mixerinfo)
#define SNDCTL_CARDINFO __OSSIOWR('X', 11, oss_card_info)
#define SNDCTL_ENGINEINFO __OSSIOWR('X', 12, oss_audioinfo)
#define SNDCTL_AUDIOINFO_EX __OSSIOWR('X', 13, oss_audioinfo)
#define SNDCTL_MIX_DESCRIPTION __OSSIOWR('X', 14, oss_mixer_enuminfo)
/* ioctl codes 'X', 200-255 are reserved for internal use */
/*
* Few more "globally" available ioctl calls.
*/
#define SNDCTL_SETSONG __OSSIOW('Y', 2, oss_longname_t)
#define SNDCTL_GETSONG __OSSIOR('Y', 2, oss_longname_t)
#define SNDCTL_SETNAME __OSSIOW('Y', 3, oss_longname_t)
#define SNDCTL_SETLABEL __OSSIOW('Y', 4, oss_label_t)
#define SNDCTL_GETLABEL __OSSIOR('Y', 4, oss_label_t)
/*
* IOCTL commands for /dev/dsp
*/
#define SNDCTL_DSP_HALT __OSSIO('P', 0)
#define SNDCTL_DSP_RESET SNDCTL_DSP_HALT /* Old name */
#define SNDCTL_DSP_SYNC __OSSIO('P', 1)
#define SNDCTL_DSP_SPEED __OSSIOWR('P', 2, int)
#define SNDCTL_DSP_STEREO __OSSIOWR('P', 3, int) /* OBSOLETE */
#define SNDCTL_DSP_GETBLKSIZE __OSSIOWR('P', 4, int)
#define SNDCTL_DSP_SAMPLESIZE SNDCTL_DSP_SETFMT
#define SNDCTL_DSP_CHANNELS __OSSIOWR('P', 6, int)
#define SNDCTL_DSP_POST __OSSIO('P', 8)
#define SNDCTL_DSP_SUBDIVIDE __OSSIOWR('P', 9, int)
#define SNDCTL_DSP_SETFRAGMENT __OSSIOWR('P', 10, int)
#define SNDCTL_DSP_GETFMTS __OSSIOR('P', 11, int) /* Returns a mask */
#define SNDCTL_DSP_SETFMT __OSSIOWR('P', 5, int) /* Selects ONE fmt */
#define SNDCTL_DSP_GETOSPACE __OSSIOR('P', 12, audio_buf_info)
#define SNDCTL_DSP_GETISPACE __OSSIOR('P', 13, audio_buf_info)
#define SNDCTL_DSP_NONBLOCK __OSSIO('P', 14) /* Obsolete */
#define SNDCTL_DSP_GETCAPS __OSSIOR('P', 15, int)
#define SNDCTL_DSP_GETTRIGGER __OSSIOR('P', 16, int)
#define SNDCTL_DSP_SETTRIGGER __OSSIOW('P', 16, int)
#define SNDCTL_DSP_GETIPTR __OSSIOR('P', 17, count_info)
#define SNDCTL_DSP_GETOPTR __OSSIOR('P', 18, count_info)
#define SNDCTL_DSP_SETSYNCRO __OSSIO('P', 21)
#define SNDCTL_DSP_SETDUPLEX __OSSIO('P', 22)
#define SNDCTL_DSP_PROFILE __OSSIOW('P', 23, int) /* OBSOLETE */
#define APF_NORMAL 0 /* Normal applications */
#define APF_NETWORK 1 /* Underruns caused by "external" delay */
#define APF_CPUINTENS 2 /* Underruns caused by "overheating" the CPU */
#define SNDCTL_DSP_GETODELAY __OSSIOR('P', 23, int)
#define SNDCTL_DSP_GETPLAYVOL __OSSIOR('P', 24, int)
#define SNDCTL_DSP_SETPLAYVOL __OSSIOWR('P', 24, int)
#define SNDCTL_DSP_GETERROR __OSSIOR('P', 25, audio_errinfo)
#define SNDCTL_DSP_READCTL __OSSIOWR('P', 26, oss_digital_control)
#define SNDCTL_DSP_WRITECTL __OSSIOWR('P', 27, oss_digital_control)
#define SNDCTL_DSP_SYNCGROUP __OSSIOWR('P', 28, oss_syncgroup)
#define SNDCTL_DSP_SYNCSTART __OSSIOW('P', 29, int)
#define SNDCTL_DSP_COOKEDMODE __OSSIOW('P', 30, int)
#define SNDCTL_DSP_SILENCE __OSSIO('P', 31)
#define SNDCTL_DSP_SKIP __OSSIO('P', 32)
#define SNDCTL_DSP_HALT_INPUT __OSSIO('P', 33)
#define SNDCTL_DSP_RESET_INPUT SNDCTL_DSP_HALT_INPUT /* Old name */
#define SNDCTL_DSP_HALT_OUTPUT __OSSIO('P', 34)
#define SNDCTL_DSP_RESET_OUTPUT SNDCTL_DSP_HALT_OUTPUT /* Old name */
#define SNDCTL_DSP_LOW_WATER __OSSIOW('P', 34, int)
#define SNDCTL_DSP_CURRENT_IPTR __OSSIOR('P', 35, oss_count_t)
#define SNDCTL_DSP_CURRENT_OPTR __OSSIOR('P', 36, oss_count_t)
#define SNDCTL_DSP_GET_RECSRC_NAMES __OSSIOR('P', 37, oss_mixer_enuminfo)
#define SNDCTL_DSP_GET_RECSRC __OSSIOR('P', 38, int)
#define SNDCTL_DSP_SET_RECSRC __OSSIOWR('P', 38, int)
#define SNDCTL_DSP_GET_PLAYTGT_NAMES __OSSIOR('P', 39, oss_mixer_enuminfo)
#define SNDCTL_DSP_GET_PLAYTGT __OSSIOR('P', 40, int)
#define SNDCTL_DSP_SET_PLAYTGT __OSSIOWR('P', 40, int)
#define SNDCTL_DSP_GETRECVOL __OSSIOR('P', 41, int)
#define SNDCTL_DSP_SETRECVOL __OSSIOWR('P', 41, int)
#define SNDCTL_DSP_GET_CHNORDER __OSSIOR('P', 42, unsigned long long)
#define SNDCTL_DSP_SET_CHNORDER __OSSIOWR('P', 42, unsigned long long)
#define SNDCTL_DSP_GETIPEAKS __OSSIOR('P', 43, oss_peaks_t)
#define SNDCTL_DSP_GETOPEAKS __OSSIOR('P', 44, oss_peaks_t)
#define SNDCTL_DSP_POLICY __OSSIOW('P', 45, int) /* See the manual */
#define SNDCTL_DSP_GETCHANNELMASK __OSSIOWR('P', 64, int)
#define SNDCTL_DSP_BIND_CHANNEL __OSSIOWR('P', 65, int)
/*
* These definitions are here for the benefit of compiling application
* code. Most of these are NOT implemented in the Solaris code,
* however. This is the older 3.x OSS API, and only the master input and
* output levels are actually supported.
*/
#define SOUND_MIXER_NRDEVICES 28
#define SOUND_MIXER_VOLUME 0
#define SOUND_MIXER_BASS 1
#define SOUND_MIXER_TREBLE 2
#define SOUND_MIXER_SYNTH 3
#define SOUND_MIXER_PCM 4
#define SOUND_MIXER_SPEAKER 5
#define SOUND_MIXER_LINE 6
#define SOUND_MIXER_MIC 7
#define SOUND_MIXER_CD 8
#define SOUND_MIXER_IMIX 9 /* Recording monitor */
#define SOUND_MIXER_ALTPCM 10
#define SOUND_MIXER_RECLEV 11 /* Recording level */
#define SOUND_MIXER_IGAIN 12 /* Input gain */
#define SOUND_MIXER_OGAIN 13 /* Output gain */
#define SOUND_MIXER_LINE1 14 /* Input source 1 (aux1) */
#define SOUND_MIXER_LINE2 15 /* Input source 2 (aux2) */
#define SOUND_MIXER_LINE3 16 /* Input source 3 (line) */
#define SOUND_MIXER_DIGITAL1 17 /* Digital I/O 1 */
#define SOUND_MIXER_DIGITAL2 18 /* Digital I/O 2 */
#define SOUND_MIXER_DIGITAL3 19 /* Digital I/O 3 */
#define SOUND_MIXER_PHONE 20 /* Phone */
#define SOUND_MIXER_MONO 21 /* Mono Output */
#define SOUND_MIXER_VIDEO 22 /* Video/TV (audio) in */
#define SOUND_MIXER_RADIO 23 /* Radio in */
#define SOUND_MIXER_DEPTH 24 /* Surround depth */
#define SOUND_MIXER_REARVOL 25 /* Rear/Surround speaker vol */
#define SOUND_MIXER_CENTERVOL 26 /* Center/LFE speaker vol */
#define SOUND_MIXER_SIDEVOL 27 /* Side-Surround (8speaker) vol */
#define SOUND_MIXER_SURRVOL SOUND_MIXER_SIDEVOL
#define SOUND_ONOFF_MIN 28
#define SOUND_ONOFF_MAX 30
#define SOUND_MIXER_NONE 31
#define SOUND_MIXER_RECSRC 0xff /* Recording sources */
#define SOUND_MIXER_DEVMASK 0xfe /* Supported devices */
#define SOUND_MIXER_RECMASK 0xfd /* Recording sources */
#define SOUND_MIXER_CAPS 0xfc /* Mixer capabilities (do not use) */
#define SOUND_MIXER_STEREODEVS 0xfb /* Mixer channels supporting stereo */
#define SOUND_MIXER_OUTSRC 0xfa
#define SOUND_MIXER_OUTMASK 0xf9
#define SOUND_MIXER_ENHANCE SOUND_MIXER_NONE
#define SOUND_MIXER_MUTE SOUND_MIXER_NONE
#define SOUND_MIXER_LOUD SOUND_MIXER_NONE
#define SOUND_MASK_VOLUME (1 << SOUND_MIXER_VOLUME)
#define SOUND_MASK_BASS (1 << SOUND_MIXER_BASS)
#define SOUND_MASK_TREBLE (1 << SOUND_MIXER_TREBLE)
#define SOUND_MASK_SYNTH (1 << SOUND_MIXER_SYNTH)
#define SOUND_MASK_PCM (1 << SOUND_MIXER_PCM)
#define SOUND_MASK_SPEAKER (1 << SOUND_MIXER_SPEAKER)
#define SOUND_MASK_LINE (1 << SOUND_MIXER_LINE)
#define SOUND_MASK_MIC (1 << SOUND_MIXER_MIC)
#define SOUND_MASK_CD (1 << SOUND_MIXER_CD)
#define SOUND_MASK_IMIX (1 << SOUND_MIXER_IMIX)
#define SOUND_MASK_ALTPCM (1 << SOUND_MIXER_ALTPCM)
#define SOUND_MASK_RECLEV (1 << SOUND_MIXER_RECLEV)
#define SOUND_MASK_IGAIN (1 << SOUND_MIXER_IGAIN)
#define SOUND_MASK_OGAIN (1 << SOUND_MIXER_OGAIN)
#define SOUND_MASK_LINE1 (1 << SOUND_MIXER_LINE1)
#define SOUND_MASK_LINE2 (1 << SOUND_MIXER_LINE2)
#define SOUND_MASK_LINE3 (1 << SOUND_MIXER_LINE3)
#define SOUND_MASK_DIGITAL1 (1 << SOUND_MIXER_DIGITAL1)
#define SOUND_MASK_DIGITAL2 (1 << SOUND_MIXER_DIGITAL2)
#define SOUND_MASK_DIGITAL3 (1 << SOUND_MIXER_DIGITAL3)
#define SOUND_MASK_MONO (1 << SOUND_MIXER_MONO)
#define SOUND_MASK_PHONE (1 << SOUND_MIXER_PHONE)
#define SOUND_MASK_RADIO (1 << SOUND_MIXER_RADIO)
#define SOUND_MASK_VIDEO (1 << SOUND_MIXER_VIDEO)
#define SOUND_MASK_DEPTH (1 << SOUND_MIXER_DEPTH)
#define SOUND_MASK_REARVOL (1 << SOUND_MIXER_REARVOL)
#define SOUND_MASK_CENTERVOL (1 << SOUND_MIXER_CENTERVOL)
#define SOUND_MASK_SIDEVOL (1 << SOUND_MIXER_SIDEVOL)
#define SOUND_MASK_SURRVOL SOUND_MASK_SIDEVOL
#define SOUND_MASK_MUTE (1 << SOUND_MIXER_MUTE)
#define SOUND_MASK_ENHANCE (1 << SOUND_MIXER_ENHANCE)
#define SOUND_MASK_LOUD (1 << SOUND_MIXER_LOUD)
/*
* Again, DO NOT USE the following two macros. They are here for SOURCE
* COMPATIBILITY ONLY.
*/
#define SOUND_DEVICE_LABELS { \
"Vol ", "Bass ", "Treble", "Synth", "Pcm ", "Speaker ", "Line ", \
"Mic ", "CD ", "Mix ", "Pcm2 ", "Rec ", "IGain", "OGain", \
"Aux1", "Aux2", "Aux3", "Digital1", "Digital2", "Digital3", \
"Phone", "Mono", "Video", "Radio", "Depth", \
"Rear", "Center", "Side" }
#define SOUND_DEVICE_NAMES { \
"vol", "bass", "treble", "synth", "pcm", "speaker", "line", \
"mic", "cd", "mix", "pcm2", "rec", "igain", "ogain", \
"aux1", "aux2", "aux3", "dig1", "dig2", "dig3", \
"phone", "mono", "video", "radio", "depth", \
"rear", "center", "side" }
#define MIXER_READ(dev) __OSSIOR('M', dev, int)
#define MIXER_WRITE(dev) __OSSIOWR('M', dev, int)
#define SOUND_MIXER_INFO __OSSIOR('M', 101, mixer_info)
#define OSS_GETVERSION __OSSIOR('M', 118, int)
/*
* These macros are useful for some applications. They are implemented
* as soft values for the application, and do not affect real hardware.
*/
#define SOUND_MIXER_READ_VOLUME MIXER_READ(SOUND_MIXER_VOLUME)
#define SOUND_MIXER_READ_OGAIN MIXER_READ(SOUND_MIXER_OGAIN)
#define SOUND_MIXER_READ_PCM MIXER_READ(SOUND_MIXER_PCM)
#define SOUND_MIXER_READ_IGAIN MIXER_READ(SOUND_MIXER_IGAIN)
#define SOUND_MIXER_READ_RECLEV MIXER_READ(SOUND_MIXER_RECLEV)
#define SOUND_MIXER_READ_RECSRC MIXER_READ(SOUND_MIXER_RECSRC)
#define SOUND_MIXER_READ_DEVMASK MIXER_READ(SOUND_MIXER_DEVMASK)
#define SOUND_MIXER_READ_RECMASK MIXER_READ(SOUND_MIXER_RECMASK)
#define SOUND_MIXER_READ_CAPS MIXER_READ(SOUND_MIXER_CAPS)
#define SOUND_MIXER_READ_STEREODEVS MIXER_READ(SOUND_MIXER_STEREODEVS)
#define SOUND_MIXER_READ_RECGAIN __OSSIOR('M', 119, int)
#define SOUND_MIXER_READ_MONGAIN __OSSIOR('M', 120, int)
#define SOUND_MIXER_WRITE_VOLUME MIXER_WRITE(SOUND_MIXER_VOLUME)
#define SOUND_MIXER_WRITE_OGAIN MIXER_WRITE(SOUND_MIXER_OGAIN)
#define SOUND_MIXER_WRITE_PCM MIXER_WRITE(SOUND_MIXER_PCM)
#define SOUND_MIXER_WRITE_IGAIN MIXER_WRITE(SOUND_MIXER_IGAIN)
#define SOUND_MIXER_WRITE_RECLEV MIXER_WRITE(SOUND_MIXER_RECLEV)
#define SOUND_MIXER_WRITE_RECSRC MIXER_WRITE(SOUND_MIXER_RECSRC)
#define SOUND_MIXER_WRITE_RECGAIN __OSSIOWR('M', 119, int)
#define SOUND_MIXER_WRITE_MONGAIN __OSSIOWR('M', 120, int)
/*
* These macros are here for source compatibility. They intentionally don't
* map to any real hardware. NOT SUPPORTED!
*/
#define SOUND_MIXER_READ_BASS MIXER_READ(SOUND_MIXER_BASS)
#define SOUND_MIXER_READ_TREBLE MIXER_READ(SOUND_MIXER_TREBLE)
#define SOUND_MIXER_READ_SYNTH MIXER_READ(SOUND_MIXER_SYNTH)
#define SOUND_MIXER_READ_SPEAKER MIXER_READ(SOUND_MIXER_SPEAKER)
#define SOUND_MIXER_READ_LINE MIXER_READ(SOUND_MIXER_LINE)
#define SOUND_MIXER_READ_MIC MIXER_READ(SOUND_MIXER_MIC)
#define SOUND_MIXER_READ_CD MIXER_READ(SOUND_MIXER_CD)
#define SOUND_MIXER_READ_IMIX MIXER_READ(SOUND_MIXER_IMIX)
#define SOUND_MIXER_READ_ALTPCM MIXER_READ(SOUND_MIXER_ALTPCM)
#define SOUND_MIXER_READ_LINE1 MIXER_READ(SOUND_MIXER_LINE1)
#define SOUND_MIXER_READ_LINE2 MIXER_READ(SOUND_MIXER_LINE2)
#define SOUND_MIXER_READ_LINE3 MIXER_READ(SOUND_MIXER_LINE3)
#define SOUND_MIXER_WRITE_BASS MIXER_WRITE(SOUND_MIXER_BASS)
#define SOUND_MIXER_WRITE_TREBLE MIXER_WRITE(SOUND_MIXER_TREBLE)
#define SOUND_MIXER_WRITE_SYNTH MIXER_WRITE(SOUND_MIXER_SYNTH)
#define SOUND_MIXER_WRITE_SPEAKER MIXER_WRITE(SOUND_MIXER_SPEAKER)
#define SOUND_MIXER_WRITE_LINE MIXER_WRITE(SOUND_MIXER_LINE)
#define SOUND_MIXER_WRITE_MIC MIXER_WRITE(SOUND_MIXER_MIC)
#define SOUND_MIXER_WRITE_CD MIXER_WRITE(SOUND_MIXER_CD)
#define SOUND_MIXER_WRITE_IMIX MIXER_WRITE(SOUND_MIXER_IMIX)
#define SOUND_MIXER_WRITE_ALTPCM MIXER_WRITE(SOUND_MIXER_ALTPCM)
#define SOUND_MIXER_WRITE_LINE1 MIXER_WRITE(SOUND_MIXER_LINE1)
#define SOUND_MIXER_WRITE_LINE2 MIXER_WRITE(SOUND_MIXER_LINE2)
#define SOUND_MIXER_WRITE_LINE3 MIXER_WRITE(SOUND_MIXER_LINE3)
/*
* Audio encoding types (Note! U8=8 and S16_LE=16 for compatibility)
*/
#define AFMT_QUERY 0x00000000 /* Return current fmt */
#define AFMT_MU_LAW 0x00000001
#define AFMT_A_LAW 0x00000002
#define AFMT_IMA_ADPCM 0x00000004
#define AFMT_U8 0x00000008
#define AFMT_S16_LE 0x00000010
#define AFMT_S16_BE 0x00000020
#define AFMT_S8 0x00000040
#define AFMT_U16_LE 0x00000080
#define AFMT_U16_BE 0x00000100
#define AFMT_MPEG 0x00000200 /* NOT SUPPORTED: MPEG (2) audio */
#define AFMT_AC3 0x00000400 /* NOT SUPPORTED: AC3 compressed */
#define AFMT_VORBIS 0x00000800 /* NOT SUPPORTED: Ogg Vorbis */
#define AFMT_S32_LE 0x00001000
#define AFMT_S32_BE 0x00002000
#define AFMT_FLOAT 0x00004000 /* NOT SUPPORTED: IEEE double float */
#define AFMT_S24_LE 0x00008000 /* LSB aligned in 32 bit word */
#define AFMT_S24_BE 0x00010000 /* LSB aligned in 32 bit word */
#define AFMT_SPDIF_RAW 0x00020000 /* NOT SUPPORTED: Raw S/PDIF frames */
#define AFMT_S24_PACKED 0x00040000 /* 24 bit packed little endian */
/*
* Some big endian/little endian handling macros (native endian and
* opposite endian formats).
*/
#if defined(_BIG_ENDIAN)
#define AFMT_S16_NE AFMT_S16_BE
#define AFMT_U16_NE AFMT_U16_BE
#define AFMT_S32_NE AFMT_S32_BE
#define AFMT_S24_NE AFMT_S24_BE
#define AFMT_S16_OE AFMT_S16_LE
#define AFMT_S32_OE AFMT_S32_LE
#define AFMT_S24_OE AFMT_S24_LE
#else
#define AFMT_S16_NE AFMT_S16_LE
#define AFMT_U16_NE AFMT_U16_LE
#define AFMT_S32_NE AFMT_S32_LE
#define AFMT_S24_NE AFMT_S24_LE
#define AFMT_S16_OE AFMT_S16_BE
#define AFMT_S32_OE AFMT_S32_BE
#define AFMT_S24_OE AFMT_S24_BE
#endif
/*
* SNDCTL_DSP_GETCAPS bits
*/
#define PCM_CAP_REVISION 0x000000ff /* Revision level (0 to 255) */
#define PCM_CAP_DUPLEX 0x00000100 /* Full duplex rec/play */
#define PCM_CAP_REALTIME 0x00000200 /* NOT SUPPORTED */
#define PCM_CAP_BATCH 0x00000400 /* NOT SUPPORTED */
#define PCM_CAP_COPROC 0x00000800 /* NOT SUPPORTED */
#define PCM_CAP_TRIGGER 0x00001000 /* Supports SETTRIGGER */
#define PCM_CAP_MMAP 0x00002000 /* Supports mmap() */
#define PCM_CAP_MULTI 0x00004000 /* Supports multiple open */
#define PCM_CAP_BIND 0x00008000 /* Supports channel binding */
#define PCM_CAP_INPUT 0x00010000 /* Supports recording */
#define PCM_CAP_OUTPUT 0x00020000 /* Supports playback */
#define PCM_CAP_VIRTUAL 0x00040000 /* Virtual device */
#define PCM_CAP_ANALOGOUT 0x00100000 /* NOT SUPPORTED */
#define PCM_CAP_ANALOGIN 0x00200000 /* NOT SUPPORTED */
#define PCM_CAP_DIGITALOUT 0x00400000 /* NOT SUPPORTED */
#define PCM_CAP_DIGITALIN 0x00800000 /* NOT SUPPORTED */
#define PCM_CAP_ADMASK 0x00f00000 /* NOT SUPPORTED */
#define PCM_CAP_SHADOW 0x01000000 /* "Shadow" device */
#define PCM_CAP_CH_MASK 0x06000000 /* See DSP_CH_MASK below */
#define PCM_CAP_HIDDEN 0x08000000 /* NOT SUPPORTED */
#define PCM_CAP_FREERATE 0x10000000
#define PCM_CAP_MODEM 0x20000000 /* NOT SUPPORTED */
#define PCM_CAP_DEFAULT 0x40000000 /* "Default" device */
/*
* Preferred channel usage. These bits can be used to give
* recommendations to the application. Used by few drivers. For
* example if ((caps & DSP_CH_MASK) == DSP_CH_MONO) means that the
* device works best in mono mode. However it doesn't necessarily mean
* that the device cannot be used in stereo. These bits should only be
* used by special applications such as multi track hard disk
* recorders to find out the initial setup. However the user should be
* able to override this selection.
*
* To find out which modes are actually supported the application
* should try to select them using SNDCTL_DSP_CHANNELS.
*/
#define DSP_CH_MASK 0x06000000 /* Mask */
#define DSP_CH_ANY 0x00000000 /* No preferred mode */
#define DSP_CH_MONO 0x02000000
#define DSP_CH_STEREO 0x04000000
#define DSP_CH_MULTI 0x06000000 /* More than two channels */
/*
* The PCM_CAP_* capability names used to be known as DSP_CAP_*, so
* it's necessary to define the older names too.
*/
#define DSP_CAP_ADMASK PCM_CAP_ADMASK
#define DSP_CAP_ANALOGIN PCM_CAP_ANALOGIN
#define DSP_CAP_ANALOGOUT PCM_CAP_ANALOGOUT
#define DSP_CAP_BATCH PCM_CAP_BATCH
#define DSP_CAP_BIND PCM_CAP_BIND
#define DSP_CAP_COPROC PCM_CAP_COPROC
#define DSP_CAP_DEFAULT PCM_CAP_DEFAULT
#define DSP_CAP_DIGITALIN PCM_CAP_DIGITALIN
#define DSP_CAP_DIGITALOUT PCM_CAP_DIGITALOUT
#define DSP_CAP_DUPLEX PCM_CAP_DUPLEX
#define DSP_CAP_FREERATE PCM_CAP_FREERATE
#define DSP_CAP_HIDDEN PCM_CAP_HIDDEN
#define DSP_CAP_INPUT PCM_CAP_INPUT
#define DSP_CAP_MMAP PCM_CAP_MMAP
#define DSP_CAP_MODEM PCM_CAP_MODEM
#define DSP_CAP_MULTI PCM_CAP_MULTI
#define DSP_CAP_OUTPUT PCM_CAP_OUTPUT
#define DSP_CAP_REALTIME PCM_CAP_REALTIME
#define DSP_CAP_REVISION PCM_CAP_REVISION
#define DSP_CAP_SHADOW PCM_CAP_SHADOW
#define DSP_CAP_TRIGGER PCM_CAP_TRIGGER
#define DSP_CAP_VIRTUAL PCM_CAP_VIRTUAL
/*
* SNDCTL_DSP_GETTRIGGER and SNDCTL_DSP_SETTRIGGER
*/
#define PCM_ENABLE_INPUT 0x00000001
#define PCM_ENABLE_OUTPUT 0x00000002
/*
* SNDCTL_DSP_BIND_CHANNEL
*/
#define DSP_BIND_QUERY 0x00000000
#define DSP_BIND_FRONT 0x00000001
#define DSP_BIND_SURR 0x00000002
#define DSP_BIND_CENTER_LFE 0x00000004
#define DSP_BIND_HANDSET 0x00000008
#define DSP_BIND_MIC 0x00000010
#define DSP_BIND_MODEM1 0x00000020
#define DSP_BIND_MODEM2 0x00000040
#define DSP_BIND_I2S 0x00000080
#define DSP_BIND_SPDIF 0x00000100
#define DSP_BIND_REAR 0x00000200
/*
* SOUND_MIXER_READ_CAPS
*/
#define SOUND_CAP_EXCL_INPUT 0x00000001
#define SOUND_CAP_NOLEGACY 0x00000004
#define SOUND_CAP_NORECSRC 0x00000008
/*
* The following ioctl is for internal use only -- it is used to
* coordinate /dev/sndstat numbering with file names in /dev/sound.
* Applications must not use it. (This is duplicated in sys/audioio.h
* as well.)
*/
#define SNDCTL_SUN_SEND_NUMBER __OSSIOW('X', 200, int)
#ifdef __cplusplus
}
#endif
#endif /* _SYS_AUDIO_OSS_H */
+3 -1
View File
@@ -94,7 +94,9 @@ const char* ffDetectSound(FFlist* devices /* List of FFSoundDevice */)
}, 0, NULL, &dataSize, &active) == kAudioHardwareNoError)
device->active = !!active;
if (!muted)
if (muted)
device->volume = 0;
else
{
float volume;
dataSize = sizeof(volume);
+1 -1
View File
@@ -32,7 +32,7 @@ const char* ffDetectSound(FFlist* devices)
for (int idev = 0; idev <= info.nummixers; ++idev)
{
path[strlen("/dev/mixer")] = (char) ('0' + idev);
FF_AUTO_CLOSE_FD int fd = open(path, O_RDWR);
FF_AUTO_CLOSE_FD int fd = open(path, O_RDWR | O_CLOEXEC);
if (fd < 0) break;
if (idev == 0)
+1 -1
View File
@@ -25,7 +25,7 @@ const char* ffDetectSound(FFlist* devices)
for (int idev = 0; idev < 9; ++idev)
{
path[strlen("/dev/audio")] = (char) ('0' + idev);
FF_AUTO_CLOSE_FD int fd = open(path, O_RDWR);
FF_AUTO_CLOSE_FD int fd = open(path, O_RDWR | O_CLOEXEC);
if (fd < 0) break;
audio_device_t ad;
+95
View File
@@ -0,0 +1,95 @@
#include "sound.h"
#include "common/io/io.h"
#include "util/stringUtils.h"
#include <fcntl.h>
#include <unistd.h>
#if __has_include(<sys/soundcard.h>)
#include <sys/soundcard.h>
#else
// Strangely, they don't provide this file on default installation
#include "audio_oss_sunos.h"
#endif
const char* ffDetectSound(FFlist* devices)
{
int defaultDev;
{
char mixerp[12];
ssize_t plen = readlink("/dev/audio", mixerp, ARRAY_SIZE(mixerp));
if (plen < 6)
return "readlink(/dev/audio) failed";
defaultDev = mixerp[plen - 1] - '0';
if (defaultDev < 0 || defaultDev > 9)
return "Invalid mixer device";
}
char path[] = "/dev/mixer0";
FF_STRBUF_AUTO_DESTROY sndstat = ffStrbufCreate();
struct oss_sysinfo info = { .nummixers = 9 };
// The implementation is very different from *BSD's. They call it OSS4
for (int idev = 0; idev < info.nummixers; ++idev)
{
path[strlen("/dev/mixer")] = (char) ('0' + idev);
FF_AUTO_CLOSE_FD int fd = open(path, O_RDWR | O_CLOEXEC);
if (fd < 0) break;
if (idev == 0)
{
if (ioctl(fd, SNDCTL_SYSINFO, &info) != 0)
return "ioctl(SNDCTL_SYSINFO) failed";
if (ffAppendFDBuffer(fd, &sndstat))
ffStrbufSubstrAfterFirstS(&sndstat, "\nMixers:");
}
struct oss_mixerinfo mi = {};
if (ioctl(fd, SNDCTL_MIXERINFO, &mi) < 0)
continue;
int volume = -1;
for (int iext = 0; iext < mi.nrext; ++iext)
{
struct oss_mixext me = { .dev = mi.dev, .ctrl = iext };
if (ioctl(fd, SNDCTL_MIX_EXTINFO, &me) < 0)
continue;
if (me.flags & MIXF_PCMVOL)
{
struct oss_mixer_value mv = { .dev = mi.dev, .ctrl = iext, .timestamp = me.timestamp };
if (ioctl(fd, SNDCTL_MIX_READ, &mv) >= 0)
{
mv.value -= me.minvalue;
me.maxvalue -= me.minvalue;
volume = (uint8_t) ((mv.value * 100 + me.maxvalue / 2) / me.maxvalue);
}
break;
}
}
if (volume == -1) continue;
FFSoundDevice* device = ffListAdd(devices);
ffStrbufInitS(&device->identifier, path);
char buf[16];
int bufLen = snprintf(buf, ARRAY_SIZE(buf), "\n%d: ", mi.dev);
assert(bufLen > 3);
const char* pLine = memmem(sndstat.chars, sndstat.length, buf, (size_t) bufLen);
if (pLine)
{
pLine += bufLen;
const char* pEnd = strchr(pLine, '\n');
if (!pEnd) pEnd = sndstat.chars + sndstat.length;
ffStrbufInitNS(&device->name, (uint32_t) (pEnd - pLine), pLine);
}
else
ffStrbufInitS(&device->name, mi.name);
ffStrbufTrimRightSpace(&device->name);
ffStrbufInitF(&device->platformApi, "%s %s", info.product, info.version);
device->volume = (uint8_t) volume;
device->active = !!mi.enabled;
device->main = defaultDev == idev;
}
return NULL;
}
+2 -1
View File
@@ -4,8 +4,9 @@
typedef struct FFSwapResult
{
FFstrbuf name;
uint64_t bytesUsed;
uint64_t bytesTotal;
} FFSwapResult;
const char* ffDetectSwap(FFSwapResult* swap);
const char* ffDetectSwap(FFlist* result /* List of FFSwapResult */);
+3 -1
View File
@@ -3,13 +3,15 @@
#include <mach/mach.h>
#include <sys/sysctl.h>
const char* ffDetectSwap(FFSwapResult* swap)
const char* ffDetectSwap(FFlist* result)
{
struct xsw_usage xsw;
size_t size = sizeof(xsw);
if(sysctl((int[]){ CTL_VM, VM_SWAPUSAGE }, 2, &xsw, &size, NULL, 0) != 0)
return "Failed to read vm.swapusage";
FFSwapResult* swap = ffListAdd(result);
ffStrbufInitStatic(&swap->name, xsw.xsu_encrypted ? "Encrypted" : "Normal");
swap->bytesTotal = xsw.xsu_total;
swap->bytesUsed = xsw.xsu_used;
return NULL;
+48 -7
View File
@@ -2,15 +2,57 @@
#include "common/sysctl.h"
#include <vm/vm_param.h>
#include <sys/stat.h>
#include <sys/param.h>
const char* ffDetectSwap(FFSwapResult* swap)
static void addSwapEntry(FFlist* result, struct xswdev* xsw, uint32_t pageSize)
{
if (xsw->xsw_nblks == 0) // DFBSD reports some /dev/wdog devices with nblks == 0
return;
FFSwapResult* swap = ffListAdd(result);
if (xsw->xsw_dev == NODEV)
ffStrbufInitStatic(&swap->name, "[NFS]");
else
ffStrbufInitF(&swap->name, "/dev/%s", devname(xsw->xsw_dev, S_IFCHR));
swap->bytesUsed = (uint64_t) xsw->xsw_used * pageSize;
swap->bytesTotal = (uint64_t) xsw->xsw_nblks * pageSize;
}
#if __DragonFly__
const char* ffDetectSwap(FFlist* result)
{
struct xswdev xsws[32];
size_t size = sizeof(xsws);
if (sysctlbyname("vm.swap_info_array", xsws, &size, NULL, 0) < 0)
return "sysctlbyname(\"vm.swap_info_array\") failed";
uint32_t pageSize = instance.state.platform.sysinfo.pageSize;
size_t count = size / sizeof(struct xswdev);
if (count == 0)
return NULL;
if (xsws->xsw_version != XSWDEV_VERSION)
return "xswdev version mismatch";
for (uint32_t i = 0; i < count; ++i)
addSwapEntry(result, &xsws[i], pageSize);
return NULL;
}
#elif __FreeBSD__
const char* ffDetectSwap(FFlist* result)
{
int mib[16];
size_t mibsize = ARRAY_SIZE(mib);
if (sysctlnametomib("vm.swap_info", mib, &mibsize) < 0)
return "sysctlnametomib(\"vm.swap_info\") failed";
swap->bytesUsed = swap->bytesTotal = 0;
uint32_t pageSize = instance.state.platform.sysinfo.pageSize;
for (int n = 0; ; ++n)
{
@@ -21,12 +63,11 @@ const char* ffDetectSwap(FFSwapResult* swap)
break;
if (xsw.xsw_version != XSWDEV_VERSION)
return "xswdev version mismatch";
swap->bytesUsed += (uint64_t) xsw.xsw_used;
swap->bytesTotal += (uint64_t) xsw.xsw_nblks;
}
swap->bytesUsed *= instance.state.platform.sysinfo.pageSize;
swap->bytesTotal *= instance.state.platform.sysinfo.pageSize;
addSwapEntry(result, &xsw, pageSize);
}
return NULL;
}
#endif

Some files were not shown because too many files have changed in this diff Show More