mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-12 09:58:03 +02:00
Compare commits
82 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b80da99fac | |||
| a95a80aa93 | |||
| 553338b2bc | |||
| a56c092a78 | |||
| 3f553b3266 | |||
| cae4b1c657 | |||
| bb489f9af3 | |||
| 275b53c6c0 | |||
| adae31304d | |||
| db6d5d7fd6 | |||
| bce96cf3f0 | |||
| 0707902532 | |||
| ef1d102e05 | |||
| c1f511c8f2 | |||
| 0284f6bfd1 | |||
| 6d50f1efdd | |||
| 4066c0d9e8 | |||
| 150e9fc650 | |||
| 36bce8fb0e | |||
| e5e70c1d92 | |||
| 12065bcfb0 | |||
| 73a30da7bc | |||
| 01fb491289 | |||
| 6c4a4bfe13 | |||
| 62647c3cb9 | |||
| 42694042f5 | |||
| d5997b9f29 | |||
| 969a67ed0f | |||
| 54bd4346ec | |||
| 17d6f84850 | |||
| 0972eb6986 | |||
| 0ee892f2de | |||
| b1f54ab7a2 | |||
| 5a372882fa | |||
| 16d34b6933 | |||
| f319a80dc5 | |||
| 60f5cc9079 | |||
| dd3b3f22ba | |||
| e672e40f8b | |||
| 91089a7fe9 | |||
| 677f39420b | |||
| f2da8305c7 | |||
| 060082885b | |||
| 3134a04b5c | |||
| d3bcef61da | |||
| b2cabd2af7 | |||
| 5e85864ab0 | |||
| cb68dccd0e | |||
| 3b6d5468da | |||
| 350388295d | |||
| e7aa6c3757 | |||
| c100e0dff7 | |||
| 02999ae4bf | |||
| b5a01400e9 | |||
| ef8bd63075 | |||
| 58e8403e16 | |||
| 34b0bbac26 | |||
| 97c6966939 | |||
| be38182ab2 | |||
| d2d4ee89d8 | |||
| 113b1b8fc2 | |||
| cf98e6f5a1 | |||
| e85a4b9ff5 | |||
| b7935aa238 | |||
| a13520c5ff | |||
| dfb0eecf86 | |||
| c5695542b2 | |||
| a1d81b4964 | |||
| 72ed11ec9e | |||
| 1c5179d3b0 | |||
| adc506d2b3 | |||
| b2236cc046 | |||
| 3040bc38cb | |||
| b9368ac20d | |||
| a4f5a9af03 | |||
| f8be6322df | |||
| 4a1bbb6a03 | |||
| 961e9a6a5f | |||
| 2f4b210f33 | |||
| 456a58c8f5 | |||
| b8b15c5170 | |||
| 61485cb133 |
+35
-10
@@ -132,7 +132,7 @@ jobs:
|
||||
run: echo "ffversion=$(./fastfetch --version-raw)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-linux
|
||||
path: ./fastfetch-*.*
|
||||
@@ -188,7 +188,7 @@ jobs:
|
||||
run: ctest
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-macos
|
||||
path: ./fastfetch-*.*
|
||||
@@ -204,7 +204,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: run VM
|
||||
uses: cross-platform-actions/action@v0.21.1
|
||||
uses: cross-platform-actions/action@master
|
||||
with:
|
||||
operating_system: freebsd
|
||||
version: '13.2'
|
||||
@@ -222,7 +222,7 @@ jobs:
|
||||
ctest
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-freebsd
|
||||
path: ./fastfetch-*.*
|
||||
@@ -284,7 +284,7 @@ jobs:
|
||||
run: 7z a -t7z -mx9 -bd -y fastfetch-$(./fastfetch --version-raw)-Win64.7z *.dll fastfetch.exe flashfetch.exe presets
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-win64
|
||||
path: ./fastfetch-*-Win64.*
|
||||
@@ -351,7 +351,7 @@ jobs:
|
||||
run: 7z a -t7z -mx9 -bd -y fastfetch-$(./fastfetch --version-raw)-Win32.7z *.dll fastfetch.exe flashfetch.exe presets
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-win32
|
||||
path: ./fastfetch-*-Win32.*
|
||||
@@ -369,15 +369,16 @@ jobs:
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: download artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
|
||||
- name: get latest release version
|
||||
id: get_version_release
|
||||
uses: pozetroninc/github-action-get-latest-release@master
|
||||
with:
|
||||
repository: ${{ github.repository }}
|
||||
|
||||
- name: download artifacts
|
||||
if: needs.linux.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- name: create release
|
||||
if: needs.linux.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
uses: ncipollo/release-action@v1
|
||||
@@ -385,4 +386,28 @@ jobs:
|
||||
tag: ${{ needs.linux.outputs.ffversion }}
|
||||
commit: ${{ github.sha }}
|
||||
artifactErrorsFailBuild: true
|
||||
artifacts: fastfetch-linux/*,fastfetch-macos/*,fastfetch-freebsd/*,fastfetch-win64/*,fastfetch-win32/*
|
||||
artifacts: fastfetch-*/fastfetch-*
|
||||
body: "Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ needs.linux.outputs.ffversion }}/CHANGELOG.md) for details."
|
||||
|
||||
- name: download source tarballs
|
||||
if: needs.linux.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
run: |
|
||||
for i in 1 2 3 4 5; do curl -L --remote-name-all --output-dir fastfetch-source --create-dirs https://github.com/${{ github.repository }}/archive/refs/tags/${{ needs.linux.outputs.ffversion }}.{tar.gz,zip} && break || sleep 5; done
|
||||
ls fastfetch-*/*
|
||||
|
||||
- name: generate release notes
|
||||
if: needs.linux.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
run: |
|
||||
echo "Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ needs.linux.outputs.ffversion }}/CHANGELOG.md) for details." > fastfetch-release-notes.md
|
||||
echo -e "\n---\n\n<details><summary>SHA256SUMs</summary><br>\n\n\`\`\`" >> fastfetch-release-notes.md
|
||||
sha256sum fastfetch-*/* >> fastfetch-release-notes.md
|
||||
echo -e "\`\`\`\n</details>" >> fastfetch-release-notes.md
|
||||
|
||||
- name: update release body
|
||||
if: needs.linux.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
tag: ${{ needs.linux.outputs.ffversion }}
|
||||
commit: ${{ github.sha }}
|
||||
bodyFile: fastfetch-release-notes.md
|
||||
allowUpdates: true
|
||||
|
||||
@@ -1,3 +1,25 @@
|
||||
# 2.5.0
|
||||
|
||||
Changes:
|
||||
* `--gpu-use-nvml` has been renamed to `--gpu-driver-specific` due to using of `IGCL` and `AGS`
|
||||
* We now detect external partitions more conservatively in Linux. USB partitions will not be detected as external always ( eg. The Linux kernel itself is installed in a USB drive )
|
||||
|
||||
Features:
|
||||
* Support more authentication type detection for macOS Sonoma (Wifi, macOS)
|
||||
* Default preset names to `.jsonc`. For example, `fastfetch -c all` will load `presets/all.jsonc` (#666)
|
||||
* Use Intel Graphics Control Library (IGCL) to detect more GPU information. Windows only (GPU, Windows)
|
||||
* Improve support of Asahi Linux (Brightness / CPU / GPU / Disk, Linux)
|
||||
* Support more properties of physical disks (PhysicalDisk)
|
||||
* Support SSD temperature detection with `--physicaldisk-temp` (PhysicalDisk)
|
||||
* Support partition label detection (Disk, FreeBSD)
|
||||
* Support platform specific graphic API version detection (GPU, macOS / Windows)
|
||||
|
||||
Bugfixes:
|
||||
* Fix Windows partition detection for WSL2 (Linux, Disk)
|
||||
* Fix Btrfs subvolumes being detected as external partitions some times (Linux, Disk)
|
||||
* Fix battery cycle counts in some places (Battery)
|
||||
* Fix CodeWhisperer compatibility (#676, Terminal, macOS)
|
||||
|
||||
# 2.4.0
|
||||
|
||||
**We are deprecating flags based config files (will be removed in v3.0.0). We suggest you migrate to json based config files.** One may use `-c /path/to/config.conf --gen-config` to migrate existing flag based config files.
|
||||
|
||||
+5
-1
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
|
||||
|
||||
project(fastfetch
|
||||
VERSION 2.4.0
|
||||
VERSION 2.5.0
|
||||
LANGUAGES C
|
||||
DESCRIPTION "Fast neofetch-like system information tool"
|
||||
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
|
||||
@@ -575,6 +575,7 @@ elseif(APPLE)
|
||||
src/detection/displayserver/displayserver_apple.c
|
||||
src/detection/font/font_apple.m
|
||||
src/detection/gpu/gpu_apple.c
|
||||
src/detection/gpu/gpu_apple.m
|
||||
src/detection/host/host_apple.c
|
||||
src/detection/lm/lm_nosupport.c
|
||||
src/detection/icons/icons_nosupport.c
|
||||
@@ -630,6 +631,8 @@ elseif(WIN32)
|
||||
src/detection/font/font_windows.c
|
||||
src/detection/gpu/gpu_windows.c
|
||||
src/detection/gpu/gpu_nvidia.c
|
||||
src/detection/gpu/gpu_intel.c
|
||||
src/detection/gpu/gpu_amd.c
|
||||
src/detection/host/host_windows.c
|
||||
src/detection/icons/icons_windows.c
|
||||
src/detection/libc/libc_windows.cpp
|
||||
@@ -903,6 +906,7 @@ elseif(APPLE)
|
||||
PRIVATE "-framework CoreWLAN"
|
||||
PRIVATE "-framework IOBluetooth"
|
||||
PRIVATE "-framework IOKit"
|
||||
PRIVATE "-framework Metal"
|
||||
PRIVATE "-framework OpenGL"
|
||||
PRIVATE "-framework OpenCL"
|
||||
PRIVATE "-framework SystemConfiguration"
|
||||
|
||||
@@ -27,10 +27,14 @@ There are [screenshots on different platforms](https://github.com/fastfetch-cli/
|
||||
|
||||
### Linux
|
||||
|
||||
* Debian / Ubuntu: Download `fastfetch-<version>-Linux.deb` from [Github release page](https://github.com/fastfetch-cli/fastfetch/releases/latest) and `sudo apt install fastfetch-<version>-Linux.deb`
|
||||
* Debian / Ubuntu: Download `fastfetch-<version>-Linux.deb` from [Github release page](https://github.com/fastfetch-cli/fastfetch/releases/latest) and `dpkg -i fastfetch-<version>-Linux.deb`
|
||||
* Arch Linux: `sudo pacman -S fastfetch`
|
||||
* Fedora: `sudo dnf install fastfetch`
|
||||
* Gentoo: `sudo emerge --ask app-misc/fastfetch`
|
||||
* NixOS: `sudo nix-shell -p fastfetch`
|
||||
* openSUSE: `sudo zypper install fastfetch`
|
||||
|
||||
Replace sudo with doas depending on what you use.
|
||||
|
||||
[See also if fastfetch has been packaged for your favorite Linux distro](#Packaging)
|
||||
|
||||
|
||||
@@ -1191,8 +1191,8 @@
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"useNvml": {
|
||||
"description": "Use nvml (NVIDIA Management Library) to detect more detailed GPU information (memory usage, CUDA core count, etc)",
|
||||
"driverSpecific": {
|
||||
"description": "Use driver specific method to detect more detailed GPU information (memory usage, core count, etc)",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
@@ -1381,6 +1381,11 @@
|
||||
"description": "Show disks with given name prefix only",
|
||||
"type": "string"
|
||||
},
|
||||
"temp": {
|
||||
"description": "Detect and display SSD temperature if supported",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"key": {
|
||||
"$ref": "#/$defs/key"
|
||||
},
|
||||
|
||||
Vendored
+383
@@ -0,0 +1,383 @@
|
||||
//
|
||||
// Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
/// \file
|
||||
/// \mainpage
|
||||
/// AGS Library Overview
|
||||
/// --------------------
|
||||
/// This document provides an overview of the AGS (AMD GPU Services) library. The AGS library provides software developers with the ability to query
|
||||
/// AMD GPU software and hardware state information that is not normally available through standard operating systems or graphic APIs.
|
||||
///
|
||||
/// The latest version of the API is publicly hosted here: https://github.com/GPUOpen-LibrariesAndSDKs/AGS_SDK/.
|
||||
/// It is also worth checking http://gpuopen.com/gaming-product/amd-gpu-services-ags-library/ for any updates and articles on AGS.
|
||||
/// \internal
|
||||
/// Online documentation is publicly hosted here: http://gpuopen-librariesandsdks.github.io/ags/
|
||||
/// \endinternal
|
||||
///
|
||||
/// ---------------------------------------
|
||||
/// What's new in AGS 6.2 since version 6.1
|
||||
/// ---------------------------------------
|
||||
/// AGS 6.2 includes the following updates:
|
||||
/// * Shader clock intrinsics
|
||||
/// * Minor improvements and fixes
|
||||
///
|
||||
/// ---------------------------------------
|
||||
/// What's new in AGS 6.1 since version 6.0
|
||||
/// ---------------------------------------
|
||||
/// AGS 6.1 includes the following updates:
|
||||
/// * RDNA3 detection
|
||||
///
|
||||
/// ---------------------------------------
|
||||
/// What's new in AGS 6.0 since version 5.4.2
|
||||
/// ---------------------------------------
|
||||
/// AGS 6.0 includes the following updates:
|
||||
/// * DX12 ray tracing hit token for RDNA2 hardware.
|
||||
/// * Shader intrinsic that exposes ReadLaneAt in DX12.
|
||||
/// * Shader intrinsics that expose explicit float conversions in DX12.
|
||||
/// * Refactored and revised API to minimize user error.
|
||||
/// * Added agsGetVersionNumber.
|
||||
/// * Detection for external GPUs.
|
||||
/// * Detection of RDNA2 architecture.
|
||||
/// * Grouped the more established intrinsics together into per year support.
|
||||
/// * Function pointer typedefs for the API
|
||||
///
|
||||
/// ---------------------------------------
|
||||
/// What's new in AGS 5.4.2 since version 5.4.1
|
||||
/// ---------------------------------------
|
||||
/// AGS 5.4.2 includes the following updates:
|
||||
/// * sharedMemoryInBytes has been reinstated.
|
||||
/// * Clock speed returned for APUs.
|
||||
///
|
||||
/// ---------------------------------------
|
||||
/// What's new in AGS 5.4.1 since version 5.4.0
|
||||
/// ---------------------------------------
|
||||
/// AGS 5.4.1 includes the following updates:
|
||||
/// * AsicFamily_Count to help with code maintenance.
|
||||
/// * Visual Studio 2019 support.
|
||||
/// * x86 support
|
||||
/// * BaseInstance and BaseVertex intrinsics along with corresponding caps bits.
|
||||
/// * GetWaveSize intrinsic along with corresponding caps bits.
|
||||
///
|
||||
/// ---------------------------------------
|
||||
/// What's new in AGS 5.4 since version 5.3
|
||||
/// ---------------------------------------
|
||||
/// AGS 5.4 includes the following updates:
|
||||
/// * A more detailed description of the GPU architecture, now including RDNA GPUs.
|
||||
/// * Radeon 7 core and memory speeds returned.
|
||||
/// * Draw index and Atomic U64 intrinsics for both DX11 and DX12.
|
||||
///
|
||||
/// ---------------------------------------
|
||||
/// What's new in AGS 5.3 since version 5.2
|
||||
/// ---------------------------------------
|
||||
/// AGS 5.3 includes the following updates:
|
||||
/// * DX11 deferred context support for Multi Draw Indirect and UAV Overlap extensions.
|
||||
/// * A Radeon Software Version helper to determine whether the installed driver meets your game's minimum driver version requirements.
|
||||
/// * Freesync HDR Gamma 2.2 mode which uses a 1010102 swapchain and can be considered as an alternative to using the 64 bit swapchain required for Freesync HDR scRGB.
|
||||
///
|
||||
/// Using the AGS library
|
||||
/// ---------------------
|
||||
/// It is recommended to take a look at the source code for the samples that come with the AGS SDK:
|
||||
/// * AGSSample
|
||||
/// * CrossfireSample
|
||||
/// * EyefinitySample
|
||||
/// The AGSSample application is the simplest of the three examples and demonstrates the code required to initialize AGS and use it to query the GPU and Eyefinity state.
|
||||
/// The CrossfireSample application demonstrates the use of the new API to transfer resources on GPUs in Crossfire mode. Lastly, the EyefinitySample application provides a more
|
||||
/// extensive example of Eyefinity setup than the basic example provided in AGSSample.
|
||||
/// There are other samples on Github that demonstrate the DirectX shader extensions, such as the Barycentrics11 and Barycentrics12 samples.
|
||||
///
|
||||
/// To add AGS support to an existing project, follow these steps:
|
||||
/// * Link your project against the correct import library. Choose from either the 32 bit or 64 bit version.
|
||||
/// * Copy the AGS dll into the same directory as your game executable.
|
||||
/// * Include the amd_ags.h header file from your source code.
|
||||
/// * Include the AGS hlsl files if you are using the shader intrinsics.
|
||||
/// * Declare a pointer to an AGSContext and make this available for all subsequent calls to AGS.
|
||||
/// * On game initialization, call \ref agsInitialize passing in the address of the context. On success, this function will return a valid context pointer.
|
||||
///
|
||||
/// Don't forget to cleanup AGS by calling \ref agsDeInitialize when the app exits, after the device has been destroyed.
|
||||
|
||||
#ifndef AMD_AGS_H
|
||||
#define AMD_AGS_H
|
||||
|
||||
#define AMD_AGS_VERSION_MAJOR 6 ///< AGS major version
|
||||
#define AMD_AGS_VERSION_MINOR 2 ///< AGS minor version
|
||||
#define AMD_AGS_VERSION_PATCH 0 ///< AGS patch version
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// \defgroup Defines AGS defines
|
||||
/// @{
|
||||
#if defined (AGS_GCC)
|
||||
#define AMD_AGS_API
|
||||
#else
|
||||
#define AMD_AGS_API __declspec(dllexport) ///< AGS exported functions
|
||||
#endif
|
||||
|
||||
#define AGS_MAKE_VERSION( major, minor, patch ) ( ( major << 22 ) | ( minor << 12 ) | patch ) ///< Macro to create the app and engine versions for the fields in \ref AGSDX12ExtensionParams and \ref AGSDX11ExtensionParams and the Radeon Software Version
|
||||
#define AGS_UNSPECIFIED_VERSION 0xFFFFAD00 ///< Use this to specify no version
|
||||
#define AGS_CURRENT_VERSION AGS_MAKE_VERSION( AMD_AGS_VERSION_MAJOR, AMD_AGS_VERSION_MINOR, AMD_AGS_VERSION_PATCH ) ///< Macro to return the current AGS version as defined by the AGS header file
|
||||
/// @}
|
||||
|
||||
/// \defgroup enums General enumerations
|
||||
/// @{
|
||||
|
||||
/// The return codes
|
||||
typedef enum AGSReturnCode
|
||||
{
|
||||
AGS_SUCCESS, ///< Successful function call
|
||||
AGS_FAILURE, ///< Failed to complete call for some unspecified reason
|
||||
AGS_INVALID_ARGS, ///< Invalid arguments into the function
|
||||
AGS_OUT_OF_MEMORY, ///< Out of memory when allocating space internally
|
||||
AGS_MISSING_D3D_DLL, ///< Returned when a D3D dll fails to load
|
||||
AGS_LEGACY_DRIVER, ///< Returned if a feature is not present in the installed driver
|
||||
AGS_NO_AMD_DRIVER_INSTALLED, ///< Returned if the AMD GPU driver does not appear to be installed
|
||||
AGS_EXTENSION_NOT_SUPPORTED, ///< Returned if the driver does not support the requested driver extension
|
||||
AGS_ADL_FAILURE, ///< Failure in ADL (the AMD Display Library)
|
||||
AGS_DX_FAILURE, ///< Failure from DirectX runtime
|
||||
AGS_D3DDEVICE_NOT_CREATED ///< Failure due to not creating the D3D device successfully via AGS.
|
||||
} AGSReturnCode;
|
||||
|
||||
/// @}
|
||||
|
||||
typedef struct AGSContext AGSContext; ///< All function calls in AGS require a pointer to a context. This is generated via \ref agsInitialize
|
||||
|
||||
/// The rectangle struct used by AGS.
|
||||
typedef struct AGSRect
|
||||
{
|
||||
int offsetX; ///< Offset on X axis
|
||||
int offsetY; ///< Offset on Y axis
|
||||
int width; ///< Width of rectangle
|
||||
int height; ///< Height of rectangle
|
||||
} AGSRect;
|
||||
|
||||
/// The display info struct used to describe a display enumerated by AGS
|
||||
typedef struct AGSDisplayInfo
|
||||
{
|
||||
char name[ 256 ]; ///< The name of the display
|
||||
char displayDeviceName[ 32 ]; ///< The display device name, i.e. DISPLAY_DEVICE::DeviceName
|
||||
|
||||
unsigned int isPrimaryDisplay : 1; ///< Whether this display is marked as the primary display
|
||||
unsigned int HDR10 : 1; ///< HDR10 is supported on this display
|
||||
unsigned int dolbyVision : 1; ///< Dolby Vision is supported on this display
|
||||
unsigned int freesync : 1; ///< Freesync is supported on this display
|
||||
unsigned int freesyncHDR : 1; ///< Freesync HDR is supported on this display
|
||||
unsigned int eyefinityInGroup : 1; ///< The display is part of the Eyefinity group
|
||||
unsigned int eyefinityPreferredDisplay : 1; ///< The display is the preferred display in the Eyefinity group for displaying the UI
|
||||
unsigned int eyefinityInPortraitMode : 1; ///< The display is in the Eyefinity group but in portrait mode
|
||||
unsigned int reservedPadding : 24; ///< Reserved for future use
|
||||
|
||||
int maxResolutionX; ///< The maximum supported resolution of the unrotated display
|
||||
int maxResolutionY; ///< The maximum supported resolution of the unrotated display
|
||||
float maxRefreshRate; ///< The maximum supported refresh rate of the display
|
||||
|
||||
AGSRect currentResolution; ///< The current resolution and position in the desktop, ignoring Eyefinity bezel compensation
|
||||
AGSRect visibleResolution; ///< The visible resolution and position. When Eyefinity bezel compensation is enabled this will
|
||||
///< be the sub region in the Eyefinity single large surface (SLS)
|
||||
float currentRefreshRate; ///< The current refresh rate
|
||||
|
||||
int eyefinityGridCoordX; ///< The X coordinate in the Eyefinity grid. -1 if not in an Eyefinity group
|
||||
int eyefinityGridCoordY; ///< The Y coordinate in the Eyefinity grid. -1 if not in an Eyefinity group
|
||||
|
||||
double chromaticityRedX; ///< Red display primary X coord
|
||||
double chromaticityRedY; ///< Red display primary Y coord
|
||||
|
||||
double chromaticityGreenX; ///< Green display primary X coord
|
||||
double chromaticityGreenY; ///< Green display primary Y coord
|
||||
|
||||
double chromaticityBlueX; ///< Blue display primary X coord
|
||||
double chromaticityBlueY; ///< Blue display primary Y coord
|
||||
|
||||
double chromaticityWhitePointX; ///< White point X coord
|
||||
double chromaticityWhitePointY; ///< White point Y coord
|
||||
|
||||
double screenDiffuseReflectance; ///< Percentage expressed between 0 - 1
|
||||
double screenSpecularReflectance; ///< Percentage expressed between 0 - 1
|
||||
|
||||
double minLuminance; ///< The minimum luminance of the display in nits
|
||||
double maxLuminance; ///< The maximum luminance of the display in nits
|
||||
double avgLuminance; ///< The average luminance of the display in nits
|
||||
|
||||
int logicalDisplayIndex; ///< The internally used index of this display
|
||||
int adlAdapterIndex; ///< The internally used ADL adapter index
|
||||
int reserved; ///< reserved field
|
||||
} AGSDisplayInfo;
|
||||
|
||||
/// The ASIC family
|
||||
typedef enum AsicFamily
|
||||
{
|
||||
AsicFamily_Unknown, ///< Unknown architecture, potentially from another IHV. Check \ref AGSDeviceInfo::vendorId
|
||||
AsicFamily_PreGCN, ///< Pre GCN architecture.
|
||||
AsicFamily_GCN1, ///< AMD GCN 1 architecture: Oland, Cape Verde, Pitcairn & Tahiti.
|
||||
AsicFamily_GCN2, ///< AMD GCN 2 architecture: Hawaii & Bonaire. This also includes APUs Kaveri and Carrizo.
|
||||
AsicFamily_GCN3, ///< AMD GCN 3 architecture: Tonga & Fiji.
|
||||
AsicFamily_GCN4, ///< AMD GCN 4 architecture: Polaris.
|
||||
AsicFamily_Vega, ///< AMD Vega architecture, including Raven Ridge (ie AMD Ryzen CPU + AMD Vega GPU).
|
||||
AsicFamily_RDNA, ///< AMD RDNA architecture
|
||||
AsicFamily_RDNA2, ///< AMD RDNA2 architecture
|
||||
AsicFamily_RDNA3, ///< AMD RDNA3 architecture
|
||||
|
||||
AsicFamily_Count ///< Number of enumerated ASIC families
|
||||
} AsicFamily;
|
||||
|
||||
/// The device info struct used to describe a physical GPU enumerated by AGS
|
||||
typedef struct AGSDeviceInfo
|
||||
{
|
||||
const char* adapterString; ///< The adapter name string
|
||||
AsicFamily asicFamily; ///< Set to Unknown if not AMD hardware
|
||||
unsigned int isAPU : 1; ///< Whether this device is an APU
|
||||
unsigned int isPrimaryDevice : 1; ///< Whether this device is marked as the primary device
|
||||
unsigned int isExternal :1; ///< Whether this device is a detachable, external device
|
||||
unsigned int reservedPadding : 29; ///< Reserved for future use
|
||||
|
||||
int vendorId; ///< The vendor id
|
||||
int deviceId; ///< The device id
|
||||
int revisionId; ///< The revision id
|
||||
|
||||
int numCUs; ///< Number of compute units
|
||||
int numWGPs; ///< Number of RDNA Work Group Processors. Only valid if ASIC is RDNA onwards.
|
||||
|
||||
int numROPs; ///< Number of ROPs
|
||||
int coreClock; ///< Core clock speed at 100% power in MHz
|
||||
int memoryClock; ///< Memory clock speed at 100% power in MHz
|
||||
int memoryBandwidth; ///< Memory bandwidth in MB/s
|
||||
float teraFlops; ///< Teraflops of GPU. Zero if not GCN onwards. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD
|
||||
|
||||
unsigned long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware.
|
||||
unsigned long long sharedMemoryInBytes; ///< The size of system memory available to the GPU in bytes. It is important to factor this into your VRAM budget for APUs
|
||||
///< as the reported local memory will only be a small fraction of the total memory available to the GPU.
|
||||
|
||||
int numDisplays; ///< The number of active displays found to be attached to this adapter.
|
||||
AGSDisplayInfo* displays; ///< List of displays allocated by AGS to be numDisplays in length.
|
||||
|
||||
int eyefinityEnabled; ///< Indicates if Eyefinity is active
|
||||
int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface.
|
||||
int eyefinityGridHeight; ///< Contains height of the multi-monitor grid that makes up the Eyefinity Single Large Surface.
|
||||
int eyefinityResolutionX; ///< Contains width in pixels of the multi-monitor Single Large Surface.
|
||||
int eyefinityResolutionY; ///< Contains height in pixels of the multi-monitor Single Large Surface.
|
||||
int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled.
|
||||
|
||||
int adlAdapterIndex; ///< Internally used index into the ADL list of adapters
|
||||
int reserved; ///< reserved field
|
||||
} AGSDeviceInfo;
|
||||
|
||||
/// \defgroup general General API functions
|
||||
/// API for initialization, cleanup, HDR display modes and Crossfire GPU count
|
||||
/// @{
|
||||
|
||||
typedef void* (__stdcall *AGS_ALLOC_CALLBACK)( size_t allocationSize ); ///< AGS user defined allocation prototype
|
||||
typedef void (__stdcall *AGS_FREE_CALLBACK)( void* allocationPtr ); ///< AGS user defined free prototype
|
||||
|
||||
/// The configuration options that can be passed in to \ref agsInitialize
|
||||
typedef struct AGSConfiguration
|
||||
{
|
||||
AGS_ALLOC_CALLBACK allocCallback; ///< Optional memory allocation callback. If not supplied, malloc() is used
|
||||
AGS_FREE_CALLBACK freeCallback; ///< Optional memory freeing callback. If not supplied, free() is used
|
||||
} AGSConfiguration;
|
||||
|
||||
/// The top level GPU information returned from \ref agsInitialize
|
||||
typedef struct AGSGPUInfo
|
||||
{
|
||||
const char* driverVersion; ///< The AMD driver package version
|
||||
const char* radeonSoftwareVersion; ///< The Radeon Software Version
|
||||
|
||||
int numDevices; ///< Number of GPUs in the system
|
||||
AGSDeviceInfo* devices; ///< List of GPUs in the system
|
||||
} AGSGPUInfo;
|
||||
|
||||
/// The struct to specify the display settings to the driver.
|
||||
typedef struct AGSDisplaySettings AGSDisplaySettings;
|
||||
|
||||
|
||||
/// The result returned from \ref agsCheckDriverVersion
|
||||
typedef enum AGSDriverVersionResult
|
||||
{
|
||||
AGS_SOFTWAREVERSIONCHECK_OK, ///< The reported Radeon Software Version is newer or the same as the required version
|
||||
AGS_SOFTWAREVERSIONCHECK_OLDER, ///< The reported Radeon Software Version is older than the required version
|
||||
AGS_SOFTWAREVERSIONCHECK_UNDEFINED ///< The check could not determine as result. This could be because it is a private or custom driver or just invalid arguments.
|
||||
} AGSDriverVersionResult;
|
||||
|
||||
///
|
||||
/// Helper function to check the installed software version against the required software version.
|
||||
///
|
||||
/// \param [in] radeonSoftwareVersionReported The Radeon Software Version returned from \ref AGSGPUInfo::radeonSoftwareVersion.
|
||||
/// \param [in] radeonSoftwareVersionRequired The Radeon Software Version to check against. This is specificed using \ref AGS_MAKE_VERSION.
|
||||
/// \return The result of the check.
|
||||
///
|
||||
AMD_AGS_API AGSDriverVersionResult agsCheckDriverVersion( const char* radeonSoftwareVersionReported, unsigned int radeonSoftwareVersionRequired );
|
||||
|
||||
///
|
||||
/// Function to return the AGS version number.
|
||||
///
|
||||
/// \return The version number made using AGS_MAKE_VERSION( AMD_AGS_VERSION_MAJOR, AMD_AGS_VERSION_MINOR, AMD_AGS_VERSION_PATCH ).
|
||||
///
|
||||
AMD_AGS_API int agsGetVersionNumber();
|
||||
|
||||
///
|
||||
/// Function used to initialize the AGS library.
|
||||
/// agsVersion must be specified as AGS_CURRENT_VERSION or the call will return \ref AGS_INVALID_ARGS.
|
||||
/// Must be called prior to any of the subsequent AGS API calls.
|
||||
/// Must be called prior to ID3D11Device or ID3D12Device creation.
|
||||
/// \note The caller of this function should handle the possibility of the call failing in the cases below. One option is to do a vendor id check and only call \ref agsInitialize if there is an AMD GPU present.
|
||||
/// \note This function will fail with \ref AGS_NO_AMD_DRIVER_INSTALLED if there is no AMD driver found on the system.
|
||||
/// \note This function will fail with \ref AGS_LEGACY_DRIVER in Catalyst versions before 12.20.
|
||||
///
|
||||
/// \param [in] agsVersion The API version specified using the \ref AGS_CURRENT_VERSION macro. If this does not match the version in the binary this initialization call will fail.
|
||||
/// \param [in] config Optional pointer to a AGSConfiguration struct to override the default library configuration.
|
||||
/// \param [out] context Address of a pointer to a context. This function allocates a context on the heap which is then required for all subsequent API calls.
|
||||
/// \param [out] gpuInfo Optional pointer to a AGSGPUInfo struct which will get filled in for all the GPUs in the system.
|
||||
///
|
||||
AMD_AGS_API AGSReturnCode agsInitialize( int agsVersion, const AGSConfiguration* config, AGSContext** context, AGSGPUInfo* gpuInfo );
|
||||
|
||||
///
|
||||
/// Function used to clean up the AGS library.
|
||||
///
|
||||
/// \param [in] context Pointer to a context. This function will deallocate the context from the heap.
|
||||
///
|
||||
AMD_AGS_API AGSReturnCode agsDeInitialize( AGSContext* context );
|
||||
|
||||
///
|
||||
/// Function used to set a specific display into HDR mode
|
||||
/// \note Setting all of the values apart from color space and transfer function to zero will cause the display to use defaults.
|
||||
/// \note Call this function after each mode change (switch to fullscreen, any change in swapchain etc).
|
||||
/// \note HDR10 PQ mode requires a 1010102 swapchain.
|
||||
/// \note HDR10 scRGB mode requires an FP16 swapchain.
|
||||
/// \note Freesync HDR scRGB mode requires an FP16 swapchain.
|
||||
/// \note Freesync HDR Gamma 2.2 mode requires a 1010102 swapchain.
|
||||
/// \note Dolby Vision requires a 8888 UNORM swapchain.
|
||||
///
|
||||
/// \param [in] context Pointer to a context. This is generated by \ref agsInitialize
|
||||
/// \param [in] deviceIndex The index of the device listed in \ref AGSGPUInfo::devices.
|
||||
/// \param [in] displayIndex The index of the display listed in \ref AGSDeviceInfo::displays.
|
||||
/// \param [in] settings Pointer to the display settings to use.
|
||||
///
|
||||
AMD_AGS_API AGSReturnCode agsSetDisplayMode( AGSContext* context, int deviceIndex, int displayIndex, const AGSDisplaySettings* settings );
|
||||
|
||||
/// @}
|
||||
|
||||
/// @}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AMD_AGS_H
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"home": "https://github.com/GPUOpen-LibrariesAndSDKs/AGS_SDK",
|
||||
"license": "MIT (embeded in source)",
|
||||
"version": "AGS v6.2.0",
|
||||
"author": "Advanced Micro Devices, Inc",
|
||||
"modified": "CarterLi"
|
||||
}
|
||||
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
Intel Software License Agreement
|
||||
10.07.21
|
||||
|
||||
Use and Redistribution. You may use and redistribute Intel’s Control API software and the header files for the Intel® Graphics Control Library (collectively, the “Software”), solely for use on Intel platforms, provided the following conditions are met:
|
||||
* Redistributions must reproduce the above copyright notice and the following terms of use in the Software and in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Intel nor the names of its suppliers may be used to endorse or promote products derived from this Software without specific prior written permission.
|
||||
* No reverse engineering, decompilation, or disassembly of Software provided to you in binary form is permitted.
|
||||
|
||||
Third Party Software. The Software may contain Third Party Software. “Third Party Software” is third party software, open source software or other Intel software listed in the “third-party-software.txt” or other similarly named text file that is included with the Software. Third Party Software, even if included with the distribution of the Software, may be governed by separate license terms, including without limitation, third party license terms, open source software notices and terms, and/or other Intel software license terms. These separate license terms solely govern your use of the Third Party Software.
|
||||
|
||||
Ownership. Title to the Software and all copies remain with Intel or its suppliers.
|
||||
|
||||
DISCLAIMER. THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED. THIS SOFTWARE IS NOT INTENDED FOR USE IN SYSTEMS OR APPLICATIONS WHERE FAILURE OF THE SOFTWARE MAY CAUSE PERSONAL INJURY OR DEATH AND YOU AGREE THAT YOU ARE FULLY RESPONSIBLE FOR ANY CLAIMS, COSTS, DAMAGES, EXPENSES, AND ATTORNEYS’ FEES ARISING OUT OF ANY SUCH USE, EVEN IF ANY CLAIM ALLEGES THAT INTEL WAS NEGLIGENT REGARDING THE DESIGN OR MANUFACTURE OF THE SOFTWARE.
|
||||
|
||||
LIMITATION OF LIABILITY; INDEMNITY. IN NO EVENT WILL INTEL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. YOU AGREE TO INDEMNIFY, DEFEND, AND HOLD INTEL HARMLESS AGAINST ANY CLAIMS, DAMAGES, AND EXPENSES RESULTING FROM YOUR USE OR UNAUTHORIZED USE OF THE SOFTWARE.
|
||||
|
||||
No support. Intel may make changes to the Software, at any time without notice, and is not obligated to support, update or provide training for the Software.
|
||||
|
||||
Termination. Your right to use the Software is terminated immediately in the event of your breach of this agreement.
|
||||
|
||||
Feedback. Should you provide Intel with comments, modifications, corrections, enhancements or other input (“Feedback”) related to the Software Intel will be free to use, disclose, reproduce, license or otherwise distribute or exploit the Feedback in its sole discretion without any obligations or restrictions of any kind, including without limitation, intellectual property rights or licensing obligations.
|
||||
|
||||
Compliance with laws. You agree to comply with all applicable laws and regulations governing your use, transfer, import or export (or prohibition thereof) of the Software.
|
||||
|
||||
Governing law. All disputes will be governed by the laws of the United States of America and the State of Delaware without reference to conflict of law principles and subject to the exclusive jurisdiction of the state or federal courts sitting in the State of Delaware, and each party agrees that it submits to the personal jurisdiction and venue of those courts and waives any objections. The United Nations Convention on Contracts for the International Sale of Goods (1980) is specifically excluded and will not apply to the Software.
|
||||
|
||||
Severability. The parties intend that if a court holds that any provision of this agreement is invalid or unenforceable under applicable law, the court will modify the provision to the minimum extent necessary to make it valid and enforceable or sever and delete the provision from this agreement. Any change to or deletion of a provision of this agreement under this Section will not affect the validity or enforceability of the remainder of this agreement, which will continue in full force and effect.
|
||||
Vendored
+7649
File diff suppressed because it is too large
Load Diff
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"home": "https://github.com/intel/drivers.gpu.control-library",
|
||||
"license": "./LICENSE",
|
||||
"version": "e1776b7be2ceead1296204371447b27860d25a66",
|
||||
"author": "Intel Corporation"
|
||||
}
|
||||
+18
-7
@@ -12,6 +12,22 @@ void ffFontInit(FFfont* font)
|
||||
ffListInit(&font->styles, sizeof(FFstrbuf));
|
||||
}
|
||||
|
||||
static void strbufAppendNSExcludingC(FFstrbuf* strbuf, uint32_t length, const char* value, char exclude)
|
||||
{
|
||||
if(value == NULL || length == 0)
|
||||
return;
|
||||
|
||||
ffStrbufEnsureFree(strbuf, length);
|
||||
|
||||
for(uint32_t i = 0; i < length; i++)
|
||||
{
|
||||
if(value[i] != exclude)
|
||||
strbuf->chars[strbuf->length++] = value[i];
|
||||
}
|
||||
|
||||
strbuf->chars[strbuf->length] = '\0';
|
||||
}
|
||||
|
||||
static void fontInitPretty(FFfont* font)
|
||||
{
|
||||
ffStrbufAppend(&font->pretty, &font->name);
|
||||
@@ -155,7 +171,7 @@ static void fontPangoParseWord(const char** data, FFfont* font, FFstrbuf* altern
|
||||
ffStrbufInit(alternativeBuffer);
|
||||
}
|
||||
|
||||
ffStrbufAppendNSExludingC(alternativeBuffer, wordLength, wordStart, '-');
|
||||
strbufAppendNSExcludingC(alternativeBuffer, wordLength, wordStart, '-');
|
||||
|
||||
if(
|
||||
strncasecmp(wordStart, "Ultra ", 6) == 0 ||
|
||||
@@ -171,7 +187,7 @@ static void fontPangoParseWord(const char** data, FFfont* font, FFstrbuf* altern
|
||||
|
||||
if(alternativeBuffer != NULL)
|
||||
{
|
||||
ffStrbufAppendNSExludingC(alternativeBuffer, wordLength, wordStart, '-');
|
||||
strbufAppendNSExcludingC(alternativeBuffer, wordLength, wordStart, '-');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -200,11 +216,6 @@ void ffFontInitValues(FFfont* font, const char* name, const char* size)
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
void ffFontInitCopy(FFfont* font, const char* name)
|
||||
{
|
||||
ffFontInitValues(font, name, NULL);
|
||||
}
|
||||
|
||||
void ffFontInitWithSpace(FFfont* font, const char* rawName)
|
||||
{
|
||||
const char* pspace = strrchr(rawName, ' ');
|
||||
|
||||
+5
-1
@@ -14,7 +14,11 @@ typedef struct FFfont
|
||||
void ffFontInit(FFfont* font);
|
||||
void ffFontInitQt(FFfont* font, const char* data);
|
||||
void ffFontInitPango(FFfont* font, const char* data);
|
||||
void ffFontInitCopy(FFfont* font, const char* name);
|
||||
void ffFontInitValues(FFfont* font, const char* name, const char* size);
|
||||
void ffFontInitWithSpace(FFfont* font, const char* rawName);
|
||||
void ffFontDestroy(FFfont* font);
|
||||
|
||||
static inline void ffFontInitCopy(FFfont* font, const char* name)
|
||||
{
|
||||
ffFontInitValues(font, name, NULL);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/FFstrbuf.h"
|
||||
#include "util/FFlist.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <fileapi.h>
|
||||
@@ -185,3 +186,18 @@ static inline bool wrapClosedir(HANDLE* pdir)
|
||||
}
|
||||
#endif
|
||||
#define FF_AUTO_CLOSE_DIR __attribute__((__cleanup__(wrapClosedir)))
|
||||
|
||||
static inline bool ffSearchUserConfigFile(const FFlist* configDirs, const char* fileSubpath, FFstrbuf* result)
|
||||
{
|
||||
// configDirs is a list of FFstrbufs include the trailing slash
|
||||
FF_LIST_FOR_EACH(FFstrbuf, dir, *configDirs)
|
||||
{
|
||||
ffStrbufClear(result);
|
||||
ffStrbufAppend(result, dir);
|
||||
ffStrbufAppendS(result, fileSubpath);
|
||||
if (ffPathExists(result->chars, FF_PATHTYPE_FILE))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
+29
-29
@@ -47,46 +47,46 @@ bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data)
|
||||
return write(fd, data, dataSize) > 0;
|
||||
}
|
||||
|
||||
static inline void readWithLength(int fd, FFstrbuf* buffer, uint32_t length)
|
||||
{
|
||||
ffStrbufEnsureFixedLengthFree(buffer, length);
|
||||
ssize_t bytesRead = 0;
|
||||
while(
|
||||
length > 0 && (bytesRead = read(fd, buffer->chars + buffer->length, length)) > 0
|
||||
) {
|
||||
buffer->length += (uint32_t) bytesRead;
|
||||
length -= (uint32_t) bytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void readUntilEOF(int fd, FFstrbuf* buffer)
|
||||
{
|
||||
ffStrbufEnsureFree(buffer, 31);
|
||||
uint32_t available = ffStrbufGetFree(buffer);
|
||||
ssize_t bytesRead = 0;
|
||||
while(
|
||||
(bytesRead = read(fd, buffer->chars + buffer->length, available)) > 0
|
||||
) {
|
||||
buffer->length += (uint32_t) bytesRead;
|
||||
if((uint32_t) bytesRead == available)
|
||||
ffStrbufEnsureFree(buffer, buffer->allocated - 1); // Doubles capacity every round. -1 for the null byte.
|
||||
available = ffStrbufGetFree(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
bool ffAppendFDBuffer(int fd, FFstrbuf* buffer)
|
||||
{
|
||||
ssize_t bytesRead = 0;
|
||||
|
||||
struct stat fileInfo;
|
||||
if(fstat(fd, &fileInfo) != 0)
|
||||
return false;
|
||||
|
||||
if (fileInfo.st_size > 0)
|
||||
{
|
||||
// optimize for files has a fixed length,
|
||||
// file can be very large, only keep necessary memory to save time and resources.
|
||||
ffStrbufEnsureFixedLengthFree(buffer, (uint32_t)fileInfo.st_size);
|
||||
}
|
||||
readWithLength(fd, buffer, (uint32_t)fileInfo.st_size);
|
||||
else
|
||||
ffStrbufEnsureFree(buffer, 31);
|
||||
uint32_t free = ffStrbufGetFree(buffer);
|
||||
// procfs file's st_size is always zero
|
||||
// choose a signed int type so that can store a native number
|
||||
ssize_t remain = fileInfo.st_size;
|
||||
|
||||
while(
|
||||
(bytesRead = read(fd, buffer->chars + buffer->length, free)) > 0
|
||||
) {
|
||||
buffer->length += (uint32_t) bytesRead;
|
||||
// if remain > 0, it means there is some data left in the file.
|
||||
// if remain == 0, it means reading has completed, no need to grow up the buffer.
|
||||
// if remain < 0, we are reading a file from procfs/sysfs and its st_size is zero,
|
||||
// we cannot detect how many data remains in the file, we only can call ffStrbufEnsureFree and read again.
|
||||
remain -= bytesRead;
|
||||
if((uint32_t) bytesRead == free && remain != 0)
|
||||
ffStrbufEnsureFree(buffer, buffer->allocated - 1); // Doubles capacity every round. -1 for the null byte.
|
||||
free = ffStrbufGetFree(buffer);
|
||||
}
|
||||
readUntilEOF(fd, buffer);
|
||||
|
||||
buffer->chars[buffer->length] = '\0';
|
||||
|
||||
ffStrbufTrimRight(buffer, '\n');
|
||||
ffStrbufTrimRight(buffer, ' ');
|
||||
|
||||
return buffer->length > 0;
|
||||
}
|
||||
|
||||
|
||||
+33
-26
@@ -35,43 +35,50 @@ bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data)
|
||||
return !!WriteFile(handle, data, (DWORD)dataSize, &written, NULL);
|
||||
}
|
||||
|
||||
static inline void readWithLength(HANDLE handle, FFstrbuf* buffer, uint32_t length)
|
||||
{
|
||||
ffStrbufEnsureFixedLengthFree(buffer, length);
|
||||
DWORD bytesRead = 0;
|
||||
while(
|
||||
length > 0 &&
|
||||
ReadFile(handle, buffer->chars + buffer->length, length, &bytesRead, NULL) != FALSE &&
|
||||
bytesRead > 0
|
||||
) {
|
||||
buffer->length += (uint32_t) bytesRead;
|
||||
length -= (uint32_t) bytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void readUntilEOF(HANDLE handle, FFstrbuf* buffer)
|
||||
{
|
||||
ffStrbufEnsureFree(buffer, 31);
|
||||
uint32_t available = ffStrbufGetFree(buffer);
|
||||
DWORD bytesRead = 0;
|
||||
while(
|
||||
ReadFile(handle, buffer->chars + buffer->length, available, &bytesRead, NULL) != FALSE &&
|
||||
bytesRead > 0
|
||||
) {
|
||||
buffer->length += (uint32_t) bytesRead;
|
||||
if((uint32_t) bytesRead == available)
|
||||
ffStrbufEnsureFree(buffer, buffer->allocated - 1); // Doubles capacity every round. -1 for the null byte.
|
||||
available = ffStrbufGetFree(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
bool ffAppendFDBuffer(HANDLE handle, FFstrbuf* buffer)
|
||||
{
|
||||
DWORD bytesRead = 0;
|
||||
|
||||
LARGE_INTEGER fileSize;
|
||||
if(!GetFileSizeEx(handle, &fileSize))
|
||||
fileSize.QuadPart = 0;
|
||||
|
||||
if (fileSize.QuadPart > 0)
|
||||
{
|
||||
// optimize for files has a fixed length,
|
||||
// file can be very large, only keep necessary memory to save time and resources.
|
||||
ffStrbufEnsureFixedLengthFree(buffer, (uint32_t)fileSize.QuadPart);
|
||||
}
|
||||
readWithLength(handle, buffer, (uint32_t)fileSize.QuadPart);
|
||||
else
|
||||
ffStrbufEnsureFree(buffer, 31);
|
||||
uint32_t free = ffStrbufGetFree(buffer);
|
||||
ssize_t remain = fileSize.QuadPart;
|
||||
|
||||
bool success;
|
||||
while(
|
||||
(success = !!ReadFile(handle, buffer->chars + buffer->length, free, &bytesRead, NULL)) &&
|
||||
bytesRead > 0
|
||||
) {
|
||||
buffer->length += (uint32_t) bytesRead;
|
||||
remain -= (ssize_t)bytesRead;
|
||||
if((uint32_t) bytesRead == free && remain != 0)
|
||||
ffStrbufEnsureFree(buffer, buffer->allocated - 1); // Doubles capacity every round. -1 for the null byte.
|
||||
free = ffStrbufGetFree(buffer);
|
||||
}
|
||||
readUntilEOF(handle, buffer);
|
||||
|
||||
buffer->chars[buffer->length] = '\0';
|
||||
|
||||
ffStrbufTrimRight(buffer, '\n');
|
||||
ffStrbufTrimRight(buffer, ' ');
|
||||
|
||||
return success;
|
||||
return buffer->length > 0;
|
||||
}
|
||||
|
||||
ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data)
|
||||
|
||||
@@ -7,22 +7,18 @@
|
||||
|
||||
static LPFN_CONNECTEX ConnectEx;
|
||||
|
||||
static BOOL WINAPI initWsaData(PINIT_ONCE once, PVOID param, PVOID* context)
|
||||
static const char* initWsaData(WSADATA* wsaData)
|
||||
{
|
||||
(void)once;
|
||||
(void)param;
|
||||
static WSADATA wsaData;
|
||||
*context = &wsaData;
|
||||
if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
|
||||
return FALSE;
|
||||
if(WSAStartup(MAKEWORD(2, 2), wsaData) != 0)
|
||||
return "WSAStartup() failed";
|
||||
|
||||
if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
|
||||
return FALSE;
|
||||
if(LOBYTE(wsaData->wVersion) != 2 || HIBYTE(wsaData->wVersion) != 2)
|
||||
return "Invalid wsaData version found";
|
||||
|
||||
//Dummy socket needed for WSAIoctl
|
||||
SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if(sockfd == INVALID_SOCKET)
|
||||
return FALSE;
|
||||
return "socket(AF_INET, SOCK_STREAM) failed";
|
||||
|
||||
DWORD dwBytes;
|
||||
GUID guid = WSAID_CONNECTEX;
|
||||
@@ -30,28 +26,35 @@ static BOOL WINAPI initWsaData(PINIT_ONCE once, PVOID param, PVOID* context)
|
||||
&guid, sizeof(guid),
|
||||
&ConnectEx, sizeof(ConnectEx),
|
||||
&dwBytes, NULL, NULL) != 0)
|
||||
return FALSE;
|
||||
return "WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER) failed";
|
||||
|
||||
return closesocket(sockfd) == 0;
|
||||
closesocket(sockfd);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers)
|
||||
{
|
||||
static INIT_ONCE once = INIT_ONCE_STATIC_INIT;
|
||||
WSADATA* pData;
|
||||
if(!InitOnceExecuteOnce(&once, initWsaData, NULL, (LPVOID*) &pData))
|
||||
static WSADATA wsaData;
|
||||
if (wsaData.wVersion == 0)
|
||||
{
|
||||
if (initWsaData(&wsaData) != NULL)
|
||||
{
|
||||
wsaData.wVersion = (WORD) -1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (wsaData.wVersion == (WORD) -1)
|
||||
return false;
|
||||
|
||||
memset(state, 0, sizeof(*state));
|
||||
|
||||
struct addrinfo hints = {
|
||||
.ai_family = AF_INET,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
};
|
||||
|
||||
struct addrinfo* addr;
|
||||
|
||||
if(getaddrinfo(host, "80", &hints, &addr) != 0)
|
||||
if(getaddrinfo(host, "80", &(struct addrinfo) {
|
||||
.ai_family = AF_INET,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
}, &addr) != 0)
|
||||
return false;
|
||||
|
||||
state->sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||
|
||||
+13
-4
@@ -82,7 +82,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"pseudo": [
|
||||
"General": [
|
||||
{
|
||||
"long": "thread",
|
||||
"desc": "Use separate threads to send HTTP requests",
|
||||
@@ -954,6 +954,15 @@
|
||||
"type": "str"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "physicaldisk-temp",
|
||||
"desc": "Detect and display SSD temperature if supported",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "bluetooth-show-disconnected",
|
||||
"desc": "Set if disconnected bluetooth devices should be printed",
|
||||
@@ -1082,9 +1091,9 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "gpu-use-nvml",
|
||||
"desc": "Use nvml (NVIDIA Management Library) to detect more detailed GPU information",
|
||||
"remark": "Detects memory usage, CUDA core count, etc. Requires NVIDIA proprietary driver installed",
|
||||
"long": "gpu-driver-specific",
|
||||
"desc": "Use driver specific method to detect more detailed GPU information (memory usage, core count, etc)",
|
||||
"remark": "Correctly NVML (NVIDIA) and IGCL (Intel, Windows only) are supported. Both require the latest proprietary driver to be installed",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
|
||||
@@ -71,6 +71,7 @@ static const char* parseDumpsys(FFBatteryOptions* options, FFlist* results)
|
||||
|
||||
FFBatteryResult* battery = ffListAdd(results);
|
||||
battery->temperature = FF_BATTERY_TEMP_UNSET;
|
||||
battery->cycleCount = 0;
|
||||
ffStrbufInit(&battery->manufacturer);
|
||||
ffStrbufInit(&battery->modelName);
|
||||
ffStrbufInit(&battery->status);
|
||||
|
||||
@@ -56,7 +56,9 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
|
||||
ffStrbufAppendS(&battery->modelName, "Built-in");
|
||||
}
|
||||
|
||||
ffCfDictGetInt(properties, CFSTR("CycleCount"), (int32_t*) &battery->cycleCount);
|
||||
int32_t cycleCount = 0;
|
||||
ffCfDictGetInt(properties, CFSTR("CycleCount"), &cycleCount);
|
||||
battery->cycleCount = cycleCount < 0 ? 0 : (uint32_t) cycleCount;
|
||||
|
||||
if (!ffCfDictGetBool(properties, CFSTR("ExternalConnected"), &boolValue) && boolValue)
|
||||
ffStrbufAppendS(&battery->status, "AC connected, ");
|
||||
@@ -75,7 +77,7 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
|
||||
if (!ffCfDictGetInt64(properties, CFSTR("Temperature"), &temp))
|
||||
battery->temperature = (double) temp / 10 - 273.15;
|
||||
else
|
||||
ffDetectCoreTemps(FF_TEMP_BATTERY, &battery->temperature);
|
||||
ffDetectSmcTemps(FF_TEMP_BATTERY, &battery->temperature);
|
||||
}
|
||||
|
||||
IOObjectRelease(registryEntry);
|
||||
|
||||
@@ -14,6 +14,7 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option
|
||||
//type must exist and be "Battery"
|
||||
ffStrbufAppendS(dir, "/type");
|
||||
ffReadFileBuffer(dir->chars, &testBatteryBuffer);
|
||||
ffStrbufTrimRightSpace(&testBatteryBuffer);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
|
||||
if(ffStrbufIgnCaseCompS(&testBatteryBuffer, "Battery") != 0)
|
||||
@@ -22,6 +23,7 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option
|
||||
//scope may not exist or must not be "Device"
|
||||
ffStrbufAppendS(dir, "/scope");
|
||||
ffReadFileBuffer(dir->chars, &testBatteryBuffer);
|
||||
ffStrbufTrimRightSpace(&testBatteryBuffer);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
|
||||
if(ffStrbufIgnCaseCompS(&testBatteryBuffer, "Device") == 0)
|
||||
@@ -48,28 +50,37 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option
|
||||
ffStrbufInit(&result->manufacturer);
|
||||
ffStrbufAppendS(dir, "/manufacturer");
|
||||
ffReadFileBuffer(dir->chars, &result->manufacturer);
|
||||
ffStrbufTrimRightSpace(&result->manufacturer);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
|
||||
ffStrbufInit(&result->modelName);
|
||||
ffStrbufAppendS(dir, "/model_name");
|
||||
ffReadFileBuffer(dir->chars, &result->modelName);
|
||||
ffStrbufTrimRightSpace(&result->modelName);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
|
||||
ffStrbufInit(&result->technology);
|
||||
ffStrbufAppendS(dir, "/technology");
|
||||
ffReadFileBuffer(dir->chars, &result->technology);
|
||||
ffStrbufTrimRightSpace(&result->technology);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
|
||||
ffStrbufInit(&result->status);
|
||||
ffStrbufAppendS(dir, "/status");
|
||||
ffReadFileBuffer(dir->chars, &result->status);
|
||||
ffStrbufTrimRightSpace(&result->status);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
|
||||
ffStrbufAppendS(dir, "/cycle_count");
|
||||
ffReadFileBuffer(dir->chars, &testBatteryBuffer);
|
||||
ffStrbufTrimRightSpace(&testBatteryBuffer);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
if(dir->length)
|
||||
result->cycleCount = (uint32_t) ffStrbufToUInt(&testBatteryBuffer, 0);
|
||||
if (dir->length)
|
||||
{
|
||||
int64_t cycleCount = 0;
|
||||
cycleCount = (int64_t) strtoll(testBatteryBuffer.chars, NULL, 10);
|
||||
result->cycleCount = cycleCount < 0 || cycleCount > UINT32_MAX ? 0 : (uint32_t) cycleCount;
|
||||
}
|
||||
|
||||
result->temperature = FF_BATTERY_TEMP_UNSET;
|
||||
if (options->temp)
|
||||
@@ -78,7 +89,7 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option
|
||||
|
||||
FF_LIST_FOR_EACH(FFTempValue, value, *tempsResult)
|
||||
{
|
||||
if (ffStrbufEqualS(&value->name, id))
|
||||
if (ffStrbufEqualS(&value->deviceName, id))
|
||||
{
|
||||
result->temperature = value->value;
|
||||
break;
|
||||
@@ -90,16 +101,8 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option
|
||||
const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateA(64);
|
||||
|
||||
if(options->dir.length > 0)
|
||||
{
|
||||
ffStrbufAppend(&baseDir, &options->dir);
|
||||
ffStrbufEnsureEndsWithC(&baseDir, '/');
|
||||
}
|
||||
else
|
||||
{
|
||||
ffStrbufAppendS(&baseDir, "/sys/class/power_supply/");
|
||||
}
|
||||
ffStrbufAppend(&baseDir, &options->dir);
|
||||
ffStrbufEnsureEndsWithC(&baseDir, '/');
|
||||
|
||||
uint32_t baseDirLength = baseDir.length;
|
||||
|
||||
|
||||
@@ -150,7 +150,7 @@ static const char* detectWithNtApi(FF_MAYBE_UNUSED FFBatteryOptions* options, FF
|
||||
ffStrbufInit(&battery->manufacturer);
|
||||
ffStrbufInit(&battery->technology);
|
||||
ffStrbufInit(&battery->status);
|
||||
battery->temperature = 0.0/0.0;
|
||||
battery->temperature = FF_BATTERY_TEMP_UNSET;
|
||||
battery->cycleCount = 0;
|
||||
|
||||
battery->capacity = info.RemainingCapacity * 100.0 / info.MaxCapacity;
|
||||
|
||||
@@ -4,25 +4,12 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static void getSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer)
|
||||
const char* ffDetectBios(FFBiosResult* bios)
|
||||
{
|
||||
ffReadFileBuffer(devicesPath, buffer);
|
||||
if(ffIsSmbiosValueSet(buffer))
|
||||
return;
|
||||
|
||||
ffReadFileBuffer(classPath, buffer);
|
||||
if(ffIsSmbiosValueSet(buffer))
|
||||
return;
|
||||
|
||||
ffStrbufClear(buffer);
|
||||
}
|
||||
|
||||
const char* ffDetectBios(FFBiosResult* bios)
|
||||
{
|
||||
getSmbiosValue("/sys/devices/virtual/dmi/id/bios_date", "/sys/class/dmi/id/bios_date", &bios->date);
|
||||
getSmbiosValue("/sys/devices/virtual/dmi/id/bios_release", "/sys/class/dmi/id/bios_release", &bios->release);
|
||||
getSmbiosValue("/sys/devices/virtual/dmi/id/bios_vendor", "/sys/class/dmi/id/bios_vendor", &bios->vendor);
|
||||
getSmbiosValue("/sys/devices/virtual/dmi/id/bios_version", "/sys/class/dmi/id/bios_version", &bios->version);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/bios_date", "/sys/class/dmi/id/bios_date", &bios->date);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/bios_release", "/sys/class/dmi/id/bios_release", &bios->release);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/bios_vendor", "/sys/class/dmi/id/bios_vendor", &bios->vendor);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/bios_version", "/sys/class/dmi/id/bios_version", &bios->version);
|
||||
if (ffPathExists("/sys/firmware/efi", FF_PATHTYPE_DIRECTORY) || ffPathExists("/sys/firmware/acpi/tables/UEFI", FF_PATHTYPE_FILE))
|
||||
ffStrbufSetStatic(&bios->type, "UEFI");
|
||||
else
|
||||
|
||||
@@ -4,23 +4,10 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static void getSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer)
|
||||
{
|
||||
ffReadFileBuffer(devicesPath, buffer);
|
||||
if(ffIsSmbiosValueSet(buffer))
|
||||
return;
|
||||
|
||||
ffReadFileBuffer(classPath, buffer);
|
||||
if(ffIsSmbiosValueSet(buffer))
|
||||
return;
|
||||
|
||||
ffStrbufClear(buffer);
|
||||
}
|
||||
|
||||
const char* ffDetectBoard(FFBoardResult* board)
|
||||
{
|
||||
getSmbiosValue("/sys/devices/virtual/dmi/id/board_name", "/sys/class/dmi/id/board_name", &board->name);
|
||||
getSmbiosValue("/sys/devices/virtual/dmi/id/board_vendor", "/sys/class/dmi/id/board_vendor", &board->vendor);
|
||||
getSmbiosValue("/sys/devices/virtual/dmi/id/board_version", "/sys/class/dmi/id/board_version", &board->version);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/board_name", "/sys/class/dmi/id/board_name", &board->name);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/board_vendor", "/sys/class/dmi/id/board_vendor", &board->vendor);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/board_version", "/sys/class/dmi/id/board_version", &board->version);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -58,9 +58,9 @@ static const char* detectWithBacklight(FFlist* result)
|
||||
{
|
||||
ffStrbufSubstrBeforeLastC(&brightness->name, '/'); // remove "/edid"
|
||||
ffStrbufSubstrAfterLastC(&brightness->name, '/'); // try getting DRM connector name
|
||||
if(ffStrbufStartsWithS(&brightness->name, "0000:"))
|
||||
if(isdigit(brightness->name.chars[0]))
|
||||
{
|
||||
// PCI address, give up
|
||||
// PCI address or some unknown path, give up
|
||||
ffStrbufSetS(&brightness->name, entry->d_name);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -4,24 +4,11 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static void getSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer)
|
||||
{
|
||||
ffReadFileBuffer(devicesPath, buffer);
|
||||
if(ffIsSmbiosValueSet(buffer))
|
||||
return;
|
||||
|
||||
ffReadFileBuffer(classPath, buffer);
|
||||
if(ffIsSmbiosValueSet(buffer))
|
||||
return;
|
||||
|
||||
ffStrbufClear(buffer);
|
||||
}
|
||||
|
||||
const char* ffDetectChassis(FFChassisResult* result, FF_MAYBE_UNUSED FFChassisOptions* options)
|
||||
{
|
||||
getSmbiosValue("/sys/devices/virtual/dmi/id/chassis_type", "/sys/class/dmi/id/chassis_type", &result->type);
|
||||
getSmbiosValue("/sys/devices/virtual/dmi/id/chassis_vendor", "/sys/class/dmi/id/chassis_vendor", &result->vendor);
|
||||
getSmbiosValue("/sys/devices/virtual/dmi/id/chassis_version", "/sys/class/dmi/id/chassis_version", &result->version);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_type", "/sys/class/dmi/id/chassis_type", &result->type);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_vendor", "/sys/class/dmi/id/chassis_vendor", &result->vendor);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_version", "/sys/class/dmi/id/chassis_version", &result->version);
|
||||
|
||||
if(result->type.length)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "cpu.h"
|
||||
#include "detection/internal.h"
|
||||
|
||||
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu);
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ typedef struct FFCPUResult
|
||||
uint16_t coresLogical;
|
||||
uint16_t coresOnline;
|
||||
|
||||
double frequencyMin;
|
||||
double frequencyMax;
|
||||
double frequencyMin; // GHz
|
||||
double frequencyMax; // GHz
|
||||
|
||||
double temperature;
|
||||
} FFCPUResult;
|
||||
|
||||
@@ -11,14 +11,14 @@ static double detectCpuTemp(const FFstrbuf* cpuName)
|
||||
{
|
||||
switch (strtol(cpuName->chars + strlen("Apple M"), NULL, 10))
|
||||
{
|
||||
case 1: error = ffDetectCoreTemps(FF_TEMP_CPU_M1X, &result); break;
|
||||
case 2: error = ffDetectCoreTemps(FF_TEMP_CPU_M2X, &result); break;
|
||||
case 3: error = ffDetectCoreTemps(FF_TEMP_CPU_M3X, &result); break;
|
||||
case 1: error = ffDetectSmcTemps(FF_TEMP_CPU_M1X, &result); break;
|
||||
case 2: error = ffDetectSmcTemps(FF_TEMP_CPU_M2X, &result); break;
|
||||
case 3: error = ffDetectSmcTemps(FF_TEMP_CPU_M3X, &result); break;
|
||||
default: error = "Unsupported Apple Silicon CPU";
|
||||
}
|
||||
}
|
||||
else // PPC?
|
||||
error = ffDetectCoreTemps(FF_TEMP_CPU_X64, &result);
|
||||
error = ffDetectSmcTemps(FF_TEMP_CPU_X64, &result);
|
||||
|
||||
if(error)
|
||||
return FF_CPU_TEMP_UNSET;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <sys/sysinfo.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include "common/settings.h"
|
||||
@@ -132,10 +133,9 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
const char* error = parseCpuInfo(cpu, &physicalCoresBuffer, &cpuMHz, &cpuIsa, &cpuUarch);
|
||||
if (error) return error;
|
||||
|
||||
cpu->coresPhysical = (uint16_t) ffStrbufToUInt(&physicalCoresBuffer, 1);
|
||||
|
||||
cpu->coresLogical = (uint16_t) get_nprocs_conf();
|
||||
cpu->coresOnline = (uint16_t) get_nprocs();
|
||||
cpu->coresPhysical = (uint16_t) ffStrbufToUInt(&physicalCoresBuffer, cpu->coresLogical);
|
||||
|
||||
#define BP "/sys/devices/system/cpu/cpufreq/policy0/"
|
||||
if(ffPathExists(BP, FF_PATHTYPE_DIRECTORY))
|
||||
@@ -167,17 +167,64 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
detectAndroid(cpu);
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
if (cpu->name.length == 0)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
if (!ffProcessAppendStdOut(&buffer, (char *const[]) { "lscpu", NULL }))
|
||||
if (ffProcessAppendStdOut(&buffer, (char *const[]) { "lscpu", NULL }) == NULL)
|
||||
{
|
||||
ffParsePropLines(buffer.chars, "Model name:", &cpu->name);
|
||||
if (ffStrbufEqualS(&cpu->name, "-")) ffStrbufClear(&cpu->name);
|
||||
char* pstart = buffer.chars;
|
||||
|
||||
if (cpu->vendor.length == 0)
|
||||
{
|
||||
pstart = strstr(pstart, "Vendor ID:");
|
||||
if (pstart)
|
||||
{
|
||||
pstart += strlen("Vendor ID:");
|
||||
while (isspace(*pstart)) ++pstart;
|
||||
if (*pstart)
|
||||
{
|
||||
char* pend = strchr(pstart, '\n');
|
||||
if (pend != NULL)
|
||||
ffStrbufAppendNS(&cpu->vendor, (uint32_t) (pend - pstart), pstart);
|
||||
else
|
||||
{
|
||||
ffStrbufAppendS(&cpu->vendor, pstart);
|
||||
}
|
||||
pstart = pend + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while ((pstart = strstr(pstart, "Model name:")))
|
||||
{
|
||||
pstart += strlen("Model name:");
|
||||
while (isspace(*pstart)) ++pstart;
|
||||
if (*pstart == '\0')
|
||||
break;
|
||||
|
||||
if (cpu->name.length > 0)
|
||||
ffStrbufAppendS(&cpu->name, " + ");
|
||||
|
||||
if (*pstart == '-')
|
||||
{
|
||||
ffStrbufAppendS(&cpu->name, "Unknown");
|
||||
++pstart;
|
||||
continue;
|
||||
}
|
||||
|
||||
char* pend = strchr(pstart, '\n');
|
||||
if (pend != NULL)
|
||||
ffStrbufAppendNS(&cpu->name, (uint32_t) (pend - pstart), pstart);
|
||||
else
|
||||
{
|
||||
ffStrbufAppendS(&cpu->name, pstart);
|
||||
break;
|
||||
}
|
||||
|
||||
pstart = pend + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,43 @@
|
||||
#include <sys/mount.h>
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <libgeom.h>
|
||||
|
||||
static const char* detectFsLabel(struct statfs* fs, FFDisk* disk)
|
||||
{
|
||||
if (!ffStrStartsWith(fs->f_mntfromname, "/dev/"))
|
||||
return "Only block devices are supported";
|
||||
|
||||
// Detect volume label in geom tree
|
||||
static struct gmesh geomTree;
|
||||
static struct gclass* cLabels;
|
||||
if (!cLabels)
|
||||
{
|
||||
if (geomTree.lg_ident)
|
||||
return "Previous geom_gettree() failed";
|
||||
|
||||
if (geom_gettree(&geomTree) < 0)
|
||||
{
|
||||
geomTree.lg_ident = (void*)(intptr_t)-1;
|
||||
return "geom_gettree() failed";
|
||||
}
|
||||
|
||||
for (cLabels = geomTree.lg_class.lh_first; !ffStrEquals(cLabels->lg_name, "LABEL"); cLabels = cLabels->lg_class.le_next);
|
||||
if (!cLabels)
|
||||
return "Class LABEL is not found";
|
||||
}
|
||||
|
||||
for (struct ggeom* label = cLabels->lg_geom.lh_first; label; label = label->lg_geom.le_next)
|
||||
{
|
||||
struct gprovider* provider = label->lg_provider.lh_first;
|
||||
if (!provider || !ffStrEquals(label->lg_name, fs->f_mntfromname + strlen("/dev/"))) continue;
|
||||
const char* str = strchr(provider->lg_name, '/');
|
||||
ffStrbufSetS(&disk->name, str ? str + 1 : provider->lg_name);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void detectFsInfo(struct statfs* fs, FFDisk* disk)
|
||||
{
|
||||
if(ffStrbufEqualS(&disk->filesystem, "zfs"))
|
||||
@@ -19,6 +56,8 @@ static void detectFsInfo(struct statfs* fs, FFDisk* disk)
|
||||
disk->type = FF_DISK_VOLUME_TYPE_EXTERNAL_BIT;
|
||||
else
|
||||
disk->type = FF_DISK_VOLUME_TYPE_REGULAR_BIT;
|
||||
|
||||
detectFsLabel(fs, disk);
|
||||
}
|
||||
#elif __APPLE__
|
||||
#include "util/apple/cf_helpers.h"
|
||||
@@ -26,10 +65,10 @@ static void detectFsInfo(struct statfs* fs, FFDisk* disk)
|
||||
#include <sys/attr.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct VolAttrBuf {
|
||||
struct CmnAttrBuf {
|
||||
uint32_t length;
|
||||
attrreference_t volNameRef;
|
||||
char volNameSpace[MAXPATHLEN];
|
||||
attrreference_t nameRef;
|
||||
char nameSpace[NAME_MAX * 3 + 1];
|
||||
} __attribute__((aligned(4), packed));
|
||||
|
||||
void detectFsInfo(struct statfs* fs, FFDisk* disk)
|
||||
@@ -41,12 +80,12 @@ void detectFsInfo(struct statfs* fs, FFDisk* disk)
|
||||
else
|
||||
disk->type = FF_DISK_VOLUME_TYPE_REGULAR_BIT;
|
||||
|
||||
struct VolAttrBuf attrBuf;
|
||||
struct CmnAttrBuf attrBuf;
|
||||
if (getattrlist(disk->mountpoint.chars, &(struct attrlist) {
|
||||
.bitmapcount = ATTR_BIT_MAP_COUNT,
|
||||
.volattr = ATTR_VOL_INFO | ATTR_VOL_NAME,
|
||||
.commonattr = ATTR_CMN_NAME,
|
||||
}, &attrBuf, sizeof(attrBuf), 0) == 0)
|
||||
ffStrbufInitNS(&disk->name, attrBuf.volNameRef.attr_length - 1 /* excluding '\0' */, attrBuf.volNameSpace);
|
||||
ffStrbufInitNS(&disk->name, attrBuf.nameRef.attr_length - 1 /* excluding '\0' */, attrBuf.nameSpace);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -26,8 +26,11 @@ static bool isPhysicalDevice(const struct mntent* device)
|
||||
if(ffStrEquals(device->mnt_dir, "/"))
|
||||
return true;
|
||||
|
||||
if(ffStrEquals(device->mnt_fsname, "none"))
|
||||
return false;
|
||||
|
||||
//DrvFs is a filesystem plugin to WSL that was designed to support interop between WSL and the Windows filesystem.
|
||||
if(ffStrEquals(device->mnt_fsname, "drvfs"))
|
||||
if(ffStrEquals(device->mnt_type, "9p"))
|
||||
return true;
|
||||
|
||||
//ZFS pool
|
||||
@@ -189,41 +192,29 @@ static bool isSubvolume(const FFlist* disks, FFDisk* currentDisk)
|
||||
|
||||
static bool isRemovable(FFDisk* currentDisk)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY basePath = ffStrbufCreateS("/sys/block/");
|
||||
|
||||
FF_AUTO_CLOSE_DIR DIR* dir = opendir(basePath.chars);
|
||||
if(dir == NULL)
|
||||
if (!ffStrbufStartsWithS(¤tDisk->mountFrom, "/dev/"))
|
||||
return false;
|
||||
|
||||
uint32_t index = ffStrbufLastIndexC(¤tDisk->mountFrom, '/');
|
||||
const char* partitionName = index == currentDisk->mountFrom.length ? NULL : currentDisk->mountFrom.chars + index + 1;
|
||||
if (!partitionName || !*partitionName) return false;
|
||||
char sysBlockPartition[64];
|
||||
snprintf(sysBlockPartition, sizeof(sysBlockPartition), "/sys/class/block/%s", currentDisk->mountFrom.chars + strlen("/dev/"));
|
||||
|
||||
struct dirent* entry;
|
||||
while((entry = readdir(dir)) != NULL)
|
||||
{
|
||||
if(entry->d_name[0] == '.')
|
||||
continue;
|
||||
char sysBlockVolume[PATH_MAX]; // /sys/devices/pci0000:00/0000:00:14.0/usb4/4-3/4-3:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda1
|
||||
if (realpath(sysBlockPartition, sysBlockVolume) == NULL)
|
||||
return false;
|
||||
strcpy(strrchr(sysBlockVolume, '/') + 1, "removable");
|
||||
|
||||
if (!ffStrStartsWith(partitionName, entry->d_name)) continue;
|
||||
|
||||
// /sys/block/sdx/device/delete
|
||||
ffStrbufAppendS(&basePath, entry->d_name);
|
||||
ffStrbufAppendS(&basePath, "/device/delete");
|
||||
return ffPathExists(basePath.chars, FF_PATHTYPE_FILE);
|
||||
}
|
||||
|
||||
return false;
|
||||
char removableChar = '0';
|
||||
return ffReadFileData(sysBlockVolume, 1, &removableChar) > 0 && removableChar == '1';
|
||||
}
|
||||
|
||||
static void detectType(const FFlist* disks, FFDisk* currentDisk)
|
||||
{
|
||||
if(ffStrbufStartsWithS(¤tDisk->mountpoint, "/boot") || ffStrbufStartsWithS(¤tDisk->mountpoint, "/efi"))
|
||||
currentDisk->type = FF_DISK_VOLUME_TYPE_HIDDEN_BIT;
|
||||
else if(isRemovable(currentDisk))
|
||||
currentDisk->type = FF_DISK_VOLUME_TYPE_EXTERNAL_BIT;
|
||||
else if(isSubvolume(disks, currentDisk))
|
||||
currentDisk->type = FF_DISK_VOLUME_TYPE_SUBVOLUME_BIT;
|
||||
else if(isRemovable(currentDisk))
|
||||
currentDisk->type = FF_DISK_VOLUME_TYPE_EXTERNAL_BIT;
|
||||
else
|
||||
currentDisk->type = FF_DISK_VOLUME_TYPE_REGULAR_BIT;
|
||||
}
|
||||
|
||||
@@ -41,16 +41,37 @@ const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options)
|
||||
|
||||
{
|
||||
snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/vendor", devName);
|
||||
ffAppendFileBuffer(pathSysBlock, &device->name);
|
||||
if (device->name.length > 0)
|
||||
ffStrbufAppendC(&device->name, ' ');
|
||||
if (ffAppendFileBuffer(pathSysBlock, &device->name))
|
||||
{
|
||||
ffStrbufTrimRightSpace(&device->name);
|
||||
if (device->name.length > 0)
|
||||
ffStrbufAppendC(&device->name, ' ');
|
||||
}
|
||||
|
||||
snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/model", devName);
|
||||
ffAppendFileBuffer(pathSysBlock, &device->name);
|
||||
ffStrbufTrim(&device->name, ' ');
|
||||
ffStrbufTrimRightSpace(&device->name);
|
||||
|
||||
if (device->name.length == 0)
|
||||
ffStrbufSetS(&device->name, devName);
|
||||
else if (ffStrStartsWith(devName, "nvme"))
|
||||
{
|
||||
int devid, nsid;
|
||||
if (sscanf(devName, "nvme%dn%d", &devid, &nsid) == 2)
|
||||
{
|
||||
bool multiNs = nsid > 1;
|
||||
if (!multiNs)
|
||||
{
|
||||
snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/nvme%dn2", devName, devid);
|
||||
multiNs = ffPathExists(pathSysBlock, FF_PATHTYPE_DIRECTORY);
|
||||
}
|
||||
if (multiNs)
|
||||
{
|
||||
// In Asahi Linux, there are multiple namespaces for the same NVMe drive.
|
||||
ffStrbufAppendF(&device->name, " - %d", nsid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (options->namePrefix.length && !ffStrbufStartsWith(&device->name, &options->namePrefix))
|
||||
{
|
||||
|
||||
@@ -5,78 +5,99 @@
|
||||
#include <windows.h>
|
||||
#include <winioctl.h>
|
||||
|
||||
static bool detectPhysicalDisk(const wchar_t* szDevice, FFlist* result, FFDiskIOOptions* options)
|
||||
{
|
||||
FF_AUTO_CLOSE_FD HANDLE hDevice = CreateFileW(szDevice, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (hDevice == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
DWORD retSize;
|
||||
char sddBuffer[4096];
|
||||
if(!DeviceIoControl(
|
||||
hDevice,
|
||||
IOCTL_STORAGE_QUERY_PROPERTY,
|
||||
&(STORAGE_PROPERTY_QUERY) {
|
||||
.PropertyId = StorageDeviceProperty,
|
||||
.QueryType = PropertyStandardQuery,
|
||||
},
|
||||
sizeof(STORAGE_PROPERTY_QUERY),
|
||||
&sddBuffer,
|
||||
sizeof(sddBuffer),
|
||||
&retSize,
|
||||
NULL
|
||||
) || retSize == 0)
|
||||
return true;
|
||||
|
||||
FFDiskIOResult* device = (FFDiskIOResult*) ffListAdd(result);
|
||||
STORAGE_DEVICE_DESCRIPTOR* sdd = (STORAGE_DEVICE_DESCRIPTOR*) sddBuffer;
|
||||
|
||||
ffStrbufInit(&device->name);
|
||||
if (sdd->VendorIdOffset != 0)
|
||||
{
|
||||
ffStrbufSetS(&device->name, (const char*) sddBuffer + sdd->VendorIdOffset);
|
||||
ffStrbufTrim(&device->name, ' ');
|
||||
}
|
||||
if (sdd->ProductIdOffset != 0)
|
||||
{
|
||||
if (device->name.length)
|
||||
ffStrbufAppendC(&device->name, ' ');
|
||||
|
||||
ffStrbufAppendS(&device->name, (const char*) sddBuffer + sdd->ProductIdOffset);
|
||||
ffStrbufTrimRight(&device->name, ' ');
|
||||
}
|
||||
|
||||
if (!device->name.length)
|
||||
ffStrbufSetWS(&device->name, szDevice);
|
||||
|
||||
if (options->namePrefix.length && !ffStrbufStartsWith(&device->name, &options->namePrefix))
|
||||
{
|
||||
ffStrbufDestroy(&device->name);
|
||||
result->length--;
|
||||
return true;
|
||||
}
|
||||
|
||||
ffStrbufInitWS(&device->devPath, szDevice);
|
||||
|
||||
DISK_PERFORMANCE dp = {};
|
||||
if (DeviceIoControl(hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, &dp, sizeof(dp), &retSize, NULL))
|
||||
{
|
||||
device->bytesRead = (uint64_t) dp.BytesRead.QuadPart;
|
||||
device->readCount = (uint64_t) dp.ReadCount;
|
||||
device->bytesWritten = (uint64_t) dp.BytesWritten.QuadPart;
|
||||
device->writeCount = (uint64_t) dp.WriteCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
ffStrbufDestroy(&device->name);
|
||||
result->length--;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options)
|
||||
{
|
||||
wchar_t szDevice[32] = L"\\\\.\\PhysicalDrive";
|
||||
wchar_t* pNum = szDevice + strlen("\\\\.\\PhysicalDrive");
|
||||
for (uint32_t idev = 0; ; ++idev)
|
||||
{
|
||||
_ultow(idev, pNum, 10);
|
||||
|
||||
FF_AUTO_CLOSE_FD HANDLE hDevice = CreateFileW(szDevice, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (hDevice == INVALID_HANDLE_VALUE)
|
||||
break;
|
||||
|
||||
DWORD retSize;
|
||||
char sddBuffer[4096];
|
||||
if(!DeviceIoControl(
|
||||
hDevice,
|
||||
IOCTL_STORAGE_QUERY_PROPERTY,
|
||||
&(STORAGE_PROPERTY_QUERY) {
|
||||
.PropertyId = StorageDeviceProperty,
|
||||
.QueryType = PropertyStandardQuery,
|
||||
},
|
||||
sizeof(STORAGE_PROPERTY_QUERY),
|
||||
&sddBuffer,
|
||||
sizeof(sddBuffer),
|
||||
&retSize,
|
||||
NULL
|
||||
) || retSize == 0)
|
||||
continue;
|
||||
|
||||
FFDiskIOResult* device = (FFDiskIOResult*) ffListAdd(result);
|
||||
STORAGE_DEVICE_DESCRIPTOR* sdd = (STORAGE_DEVICE_DESCRIPTOR*) sddBuffer;
|
||||
|
||||
ffStrbufInit(&device->name);
|
||||
if (sdd->VendorIdOffset != 0)
|
||||
wchar_t szPhysicalDrive[32] = L"\\\\.\\PhysicalDrive";
|
||||
wchar_t* pNum = szPhysicalDrive + strlen("\\\\.\\PhysicalDrive");
|
||||
for (uint32_t idev = 0; ; ++idev)
|
||||
{
|
||||
ffStrbufSetS(&device->name, (const char*) sddBuffer + sdd->VendorIdOffset);
|
||||
ffStrbufTrim(&device->name, ' ');
|
||||
_ultow(idev, pNum, 10);
|
||||
|
||||
if (!detectPhysicalDisk(szPhysicalDrive, result, options))
|
||||
break;
|
||||
}
|
||||
if (sdd->ProductIdOffset != 0)
|
||||
}
|
||||
|
||||
{
|
||||
wchar_t szCdrom[32] = L"\\\\.\\CDROM";
|
||||
wchar_t* pNum = szCdrom + strlen("\\\\.\\CDROM");
|
||||
for (uint32_t idev = 0; ; ++idev)
|
||||
{
|
||||
if (device->name.length)
|
||||
ffStrbufAppendC(&device->name, ' ');
|
||||
_ultow(idev, pNum, 10);
|
||||
|
||||
ffStrbufAppendS(&device->name, (const char*) sddBuffer + sdd->ProductIdOffset);
|
||||
ffStrbufTrimRight(&device->name, ' ');
|
||||
}
|
||||
|
||||
if (!device->name.length)
|
||||
ffStrbufAppendF(&device->name, "PhysicalDrive%u", (unsigned) idev);
|
||||
|
||||
if (options->namePrefix.length && !ffStrbufStartsWith(&device->name, &options->namePrefix))
|
||||
{
|
||||
ffStrbufDestroy(&device->name);
|
||||
result->length--;
|
||||
continue;
|
||||
}
|
||||
|
||||
ffStrbufInitWS(&device->devPath, szDevice);
|
||||
|
||||
DISK_PERFORMANCE dp = {};
|
||||
if (DeviceIoControl(hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, &dp, sizeof(dp), &retSize, NULL))
|
||||
{
|
||||
device->bytesRead = (uint64_t) dp.BytesRead.QuadPart;
|
||||
device->readCount = (uint64_t) dp.ReadCount;
|
||||
device->bytesWritten = (uint64_t) dp.BytesWritten.QuadPart;
|
||||
device->writeCount = (uint64_t) dp.WriteCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
ffStrbufDestroy(&device->name);
|
||||
result->length--;
|
||||
continue;
|
||||
if (!detectPhysicalDisk(szCdrom, result, options))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "displayserver.h"
|
||||
#include "detection/internal.h"
|
||||
|
||||
bool ffdsAppendDisplay(
|
||||
FFDisplayServerResult* result,
|
||||
@@ -36,7 +35,16 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds);
|
||||
|
||||
const FFDisplayServerResult* ffConnectDisplayServer()
|
||||
{
|
||||
FF_DETECTION_INTERNAL_GUARD(FFDisplayServerResult,
|
||||
static FFDisplayServerResult result;
|
||||
if (result.displays.elementSize == 0)
|
||||
{
|
||||
ffStrbufInit(&result.wmProcessName);
|
||||
ffStrbufInit(&result.wmPrettyName);
|
||||
ffStrbufInit(&result.wmProtocolName);
|
||||
ffStrbufInit(&result.deProcessName);
|
||||
ffStrbufInit(&result.dePrettyName);
|
||||
ffListInit(&result.displays, sizeof(FFDisplayResult));
|
||||
ffConnectDisplayServerImpl(&result);
|
||||
);
|
||||
}
|
||||
return &result;
|
||||
}
|
||||
|
||||
@@ -102,12 +102,8 @@ static bool detectWithGetprop(FFDisplayServerResult* ds)
|
||||
|
||||
void ffConnectDisplayServerImpl(FFDisplayServerResult* ds)
|
||||
{
|
||||
ffStrbufInitStatic(&ds->wmProcessName, "WindowManager");
|
||||
ffStrbufInitStatic(&ds->wmPrettyName, "Window Manager");
|
||||
ffStrbufInit(&ds->wmProtocolName);
|
||||
ffStrbufInit(&ds->deProcessName);
|
||||
ffStrbufInit(&ds->dePrettyName);
|
||||
ffListInitA(&ds->displays, sizeof(FFDisplayResult), 0);
|
||||
ffStrbufSetStatic(&ds->wmProcessName, "WindowManager");
|
||||
ffStrbufSetStatic(&ds->wmPrettyName, "Window Manager");
|
||||
|
||||
if (!detectWithGetprop(ds))
|
||||
detectWithDumpsys(ds);
|
||||
|
||||
@@ -73,20 +73,11 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds)
|
||||
FF_CFTYPE_AUTO_RELEASE CFMachPortRef port = CGWindowServerCreateServerPort();
|
||||
if (port)
|
||||
{
|
||||
ffStrbufInitStatic(&ds->wmProcessName, "WindowServer");
|
||||
ffStrbufInitStatic(&ds->wmPrettyName, "Quartz Compositor");
|
||||
}
|
||||
else
|
||||
{
|
||||
ffStrbufInit(&ds->wmProcessName);
|
||||
ffStrbufInit(&ds->wmPrettyName);
|
||||
ffStrbufSetStatic(&ds->wmProcessName, "WindowServer");
|
||||
ffStrbufSetStatic(&ds->wmPrettyName, "Quartz Compositor");
|
||||
}
|
||||
}
|
||||
ffStrbufInit(&ds->wmProtocolName);
|
||||
ffStrbufSetStatic(&ds->dePrettyName, "Aqua");
|
||||
|
||||
ffStrbufInit(&ds->deProcessName);
|
||||
ffStrbufInitStatic(&ds->dePrettyName, "Aqua");
|
||||
|
||||
ffListInitA(&ds->displays, sizeof(FFDisplayResult), 4);
|
||||
detectDisplays(ds);
|
||||
}
|
||||
|
||||
@@ -13,10 +13,10 @@ typedef struct FFMonitorInfo
|
||||
} FFMonitorInfo;
|
||||
|
||||
static CALLBACK BOOL MonitorEnumProc(
|
||||
HMONITOR hMonitor,
|
||||
FF_MAYBE_UNUSED HDC hdc,
|
||||
FF_MAYBE_UNUSED LPRECT lpRect,
|
||||
LPARAM lParam
|
||||
HMONITOR hMonitor,
|
||||
FF_MAYBE_UNUSED HDC hdc,
|
||||
FF_MAYBE_UNUSED LPRECT lpRect,
|
||||
LPARAM lParam
|
||||
)
|
||||
{
|
||||
FFlist* monitors = (FFlist*) lParam;
|
||||
@@ -145,20 +145,16 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds)
|
||||
BOOL enabled;
|
||||
if(SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled)
|
||||
{
|
||||
ffStrbufInitStatic(&ds->wmProcessName, "dwm.exe");
|
||||
ffStrbufInitStatic(&ds->wmPrettyName, "Desktop Window Manager");
|
||||
ffStrbufSetStatic(&ds->wmProcessName, "dwm.exe");
|
||||
ffStrbufSetStatic(&ds->wmPrettyName, "Desktop Window Manager");
|
||||
}
|
||||
else
|
||||
{
|
||||
// `explorer.exe` only provides a subset of WM functions, as well as the taskbar and desktop icons.
|
||||
// While a window itself is drawn by kernel (GDI). Killing `explorer.exe` won't affect how windows are displayed generally.
|
||||
ffStrbufInitStatic(&ds->wmProcessName, "explorer.exe");
|
||||
ffStrbufInitStatic(&ds->wmPrettyName, "Internal");
|
||||
ffStrbufSetStatic(&ds->wmProcessName, "explorer.exe");
|
||||
ffStrbufSetStatic(&ds->wmPrettyName, "Internal");
|
||||
}
|
||||
ffStrbufInit(&ds->wmProtocolName);
|
||||
ffStrbufInit(&ds->deProcessName);
|
||||
ffStrbufInit(&ds->dePrettyName);
|
||||
ffListInit(&ds->displays, sizeof(FFDisplayResult));
|
||||
|
||||
detectDisplays(ds);
|
||||
|
||||
|
||||
@@ -3,13 +3,6 @@
|
||||
|
||||
void ffConnectDisplayServerImpl(FFDisplayServerResult* ds)
|
||||
{
|
||||
ffStrbufInit(&ds->wmProcessName);
|
||||
ffStrbufInit(&ds->wmPrettyName);
|
||||
ffStrbufInit(&ds->wmProtocolName);
|
||||
ffStrbufInit(&ds->deProcessName);
|
||||
ffStrbufInit(&ds->dePrettyName);
|
||||
ffListInitA(&ds->displays, sizeof(FFDisplayResult), 4);
|
||||
|
||||
if (instance.config.general.dsForceDrm == FF_DS_FORCE_DRM_TYPE_FALSE)
|
||||
{
|
||||
//We try wayland as our preferred display server, as it supports the most features.
|
||||
|
||||
@@ -50,6 +50,7 @@ static void waylandDetectWM(int fd, FFDisplayServerResult* result)
|
||||
FF_STRBUF_AUTO_DESTROY procPath = ffStrbufCreate();
|
||||
ffStrbufAppendF(&procPath, "/proc/%d/cmdline", ucred.pid); //We check the cmdline for the process name, because it is not trimmed.
|
||||
ffReadFileBuffer(procPath.chars, &result->wmProcessName);
|
||||
ffStrbufTrimRightSpace(&result->wmProcessName);
|
||||
ffStrbufSubstrBeforeFirstC(&result->wmProcessName, '\0'); //Trim the arguments
|
||||
ffStrbufSubstrAfterLastC(&result->wmProcessName, '/'); //Trim the path
|
||||
}
|
||||
|
||||
@@ -326,6 +326,7 @@ static const char* getFromProcesses(FFDisplayServerResult* result)
|
||||
//We check the cmdline for the process name, because it is not trimmed.
|
||||
ffStrbufAppendS(&procPath, "/cmdline");
|
||||
ffReadFileBuffer(procPath.chars, &processName);
|
||||
ffStrbufTrimRightSpace(&processName);
|
||||
ffStrbufSubstrBeforeFirstC(&processName, '\0'); //Trim the arguments
|
||||
ffStrbufSubstrAfterLastC(&processName, '/');
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "font.h"
|
||||
#include "detection/internal.h"
|
||||
|
||||
const char* ffDetectFontImpl(FFFontResult* font);
|
||||
|
||||
|
||||
@@ -30,7 +30,8 @@ const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */)
|
||||
FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(devices);
|
||||
ffStrbufInitS(&device->identifier, entry->d_name);
|
||||
ffStrbufInit(&device->name);
|
||||
ffAppendFileBuffer(path.chars, &device->name);
|
||||
if (ffAppendFileBuffer(path.chars, &device->name))
|
||||
ffStrbufTrimRightSpace(&device->name);
|
||||
}
|
||||
|
||||
ffStrbufSubstrBefore(&path, baseLen);
|
||||
|
||||
+56
-6
@@ -1,6 +1,6 @@
|
||||
#include "gpu.h"
|
||||
#include "detection/internal.h"
|
||||
#include "detection/vulkan/vulkan.h"
|
||||
#include "detection/opengl/opengl.h"
|
||||
|
||||
const char* FF_GPU_VENDOR_NAME_APPLE = "Apple";
|
||||
const char* FF_GPU_VENDOR_NAME_AMD = "AMD";
|
||||
@@ -46,17 +46,67 @@ const char* ffGetGPUVendorString(unsigned vendorId)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* detectByOpenGL(FFlist* gpus)
|
||||
{
|
||||
FFOpenGLResult result;
|
||||
ffStrbufInit(&result.version);
|
||||
ffStrbufInit(&result.renderer);
|
||||
ffStrbufInit(&result.vendor);
|
||||
ffStrbufInit(&result.slv);
|
||||
const char* error = ffDetectOpenGL(&instance.config.modules.openGL, &result);
|
||||
if (!error)
|
||||
{
|
||||
FFGPUResult* gpu = (FFGPUResult*) ffListAdd(gpus);
|
||||
gpu->type = FF_GPU_TYPE_UNKNOWN;
|
||||
ffStrbufInitMove(&gpu->vendor, &result.vendor);
|
||||
ffStrbufInitMove(&gpu->name, &result.renderer);
|
||||
ffStrbufInit(&gpu->driver);
|
||||
ffStrbufInitF(&gpu->platformApi, "OpenGL %s", result.version.chars);
|
||||
gpu->temperature = FF_GPU_TEMP_UNSET;
|
||||
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
|
||||
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
|
||||
gpu->dedicated = gpu->shared = (FFGPUMemory){0, 0};
|
||||
gpu->deviceId = 0;
|
||||
|
||||
if (ffStrbufIgnCaseEqualS(&gpu->vendor, "Mesa"))
|
||||
ffStrbufClear(&gpu->vendor);
|
||||
|
||||
if (!gpu->vendor.length)
|
||||
{
|
||||
if (ffStrbufContainS(&result.renderer, "Apple"))
|
||||
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE);
|
||||
else if (ffStrbufContainS(&result.renderer, "Intel"))
|
||||
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL);
|
||||
else if (ffStrbufContainS(&result.renderer, "AMD") || ffStrbufContainS(&result.renderer, "ATI"))
|
||||
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD);
|
||||
else if (ffStrbufContainS(&result.renderer, "NVIDIA"))
|
||||
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_NVIDIA);
|
||||
}
|
||||
}
|
||||
|
||||
ffStrbufDestroy(&result.version);
|
||||
ffStrbufDestroy(&result.renderer);
|
||||
ffStrbufDestroy(&result.vendor);
|
||||
ffStrbufDestroy(&result.slv);
|
||||
return error;
|
||||
}
|
||||
|
||||
const char* ffDetectGPU(const FFGPUOptions* options, FFlist* result)
|
||||
{
|
||||
if (!options->forceVulkan)
|
||||
{
|
||||
const char* error = ffDetectGPUImpl(options, result);
|
||||
if (!error) return NULL;
|
||||
if (!error && result->length > 0) return NULL;
|
||||
}
|
||||
FFVulkanResult* vulkan = ffDetectVulkan();
|
||||
if (vulkan->error) return "GPU detection failed";
|
||||
ffListDestroy(result);
|
||||
ffListInitMove(result, &vulkan->gpus);
|
||||
if (!vulkan->error && vulkan->gpus.length > 0)
|
||||
{
|
||||
ffListDestroy(result);
|
||||
ffListInitMove(result, &vulkan->gpus);
|
||||
return NULL;
|
||||
}
|
||||
if (detectByOpenGL(result) == NULL)
|
||||
return NULL;
|
||||
|
||||
return NULL;
|
||||
return "GPU detection failed";
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#define FF_GPU_TEMP_UNSET (0/0.0)
|
||||
#define FF_GPU_CORE_COUNT_UNSET -1
|
||||
#define FF_GPU_VMEM_SIZE_UNSET ((uint64_t)-1)
|
||||
#define FF_GPU_FREQUENCY_UNSET (0/0.0)
|
||||
|
||||
extern const char* FF_GPU_VENDOR_NAME_APPLE;
|
||||
extern const char* FF_GPU_VENDOR_NAME_AMD;
|
||||
@@ -28,11 +29,13 @@ typedef struct FFGPUResult
|
||||
FFstrbuf vendor;
|
||||
FFstrbuf name;
|
||||
FFstrbuf driver;
|
||||
FFstrbuf platformApi;
|
||||
double temperature;
|
||||
int coreCount;
|
||||
int32_t coreCount;
|
||||
double frequency; // Real time clock frequency in GHz
|
||||
FFGPUMemory dedicated;
|
||||
FFGPUMemory shared;
|
||||
uint32_t vulkanDeviceId; // Only used for vulkan
|
||||
uint64_t deviceId; // Used internally, may be uninitialized
|
||||
} FFGPUResult;
|
||||
|
||||
const char* ffDetectGPU(const FFGPUOptions* options, FFlist* result);
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
#include "gpu_driver_specific.h"
|
||||
|
||||
// Everything detected in this file is static.
|
||||
// The real time monitoring requires ADLX, whose interface is much more complicated than AGS
|
||||
// Whoever has AMD graphic cards interested in this may contribute
|
||||
// * ADLX (AMD Device Library eXtra): https://github.com/GPUOpen-LibrariesAndSDKs/ADLX
|
||||
|
||||
#include "3rdparty/ags/amd_ags.h"
|
||||
#include "common/library.h"
|
||||
#include "util/mallocHelper.h"
|
||||
|
||||
const char* ffDetectAmdGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResult result, const char* soName)
|
||||
{
|
||||
static bool inited = false;
|
||||
static AGSGPUInfo gpuInfo;
|
||||
|
||||
if (!inited)
|
||||
{
|
||||
inited = true;
|
||||
FF_LIBRARY_LOAD(libags, NULL, "dlopen amd_ags failed", soName , 1);
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libags, agsInitialize)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libags, agsDeInitialize)
|
||||
|
||||
struct AGSContext* apiHandle;
|
||||
if (ffagsInitialize(AGS_CURRENT_VERSION, NULL, &apiHandle, &gpuInfo) != AGS_SUCCESS)
|
||||
return "loading ags library failed";
|
||||
|
||||
ffagsDeInitialize(apiHandle);
|
||||
}
|
||||
|
||||
if (gpuInfo.numDevices == 0)
|
||||
return "loading ags library failed or no AMD gpus found";
|
||||
|
||||
AGSDeviceInfo* device = NULL;
|
||||
|
||||
for (int iDev = 0; iDev < gpuInfo.numDevices; iDev++)
|
||||
{
|
||||
if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID)
|
||||
{
|
||||
if (
|
||||
cond->pciDeviceId.deviceId == (uint32_t) gpuInfo.devices[iDev].deviceId &&
|
||||
cond->pciDeviceId.vendorId == (uint32_t) gpuInfo.devices[iDev].vendorId &&
|
||||
cond->pciDeviceId.revId == (uint32_t) gpuInfo.devices[iDev].revisionId)
|
||||
{
|
||||
device = &gpuInfo.devices[iDev];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!device)
|
||||
return "Device not found";
|
||||
|
||||
if (result.coreCount)
|
||||
*result.coreCount = (uint32_t) device->numCUs;
|
||||
|
||||
if (result.memory)
|
||||
{
|
||||
result.memory->total = device->localMemoryInBytes;
|
||||
result.memory->used = FF_GPU_VMEM_SIZE_UNSET;
|
||||
}
|
||||
|
||||
if (result.frequency)
|
||||
*result.frequency = device->coreClock / 1000.; // Maximum frequency
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include <IOKit/graphics/IOGraphicsLib.h>
|
||||
|
||||
const char* ffGpuDetectMetal(FFlist* gpus);
|
||||
|
||||
static double detectGpuTemp(const FFstrbuf* gpuName)
|
||||
{
|
||||
double result = 0;
|
||||
@@ -15,18 +17,18 @@ static double detectGpuTemp(const FFstrbuf* gpuName)
|
||||
{
|
||||
switch (strtol(gpuName->chars + strlen("Apple M"), NULL, 10))
|
||||
{
|
||||
case 1: error = ffDetectCoreTemps(FF_TEMP_GPU_M1X, &result); break;
|
||||
case 2: error = ffDetectCoreTemps(FF_TEMP_GPU_M2X, &result); break;
|
||||
case 3: error = ffDetectCoreTemps(FF_TEMP_GPU_M3X, &result); break;
|
||||
case 1: error = ffDetectSmcTemps(FF_TEMP_GPU_M1X, &result); break;
|
||||
case 2: error = ffDetectSmcTemps(FF_TEMP_GPU_M2X, &result); break;
|
||||
case 3: error = ffDetectSmcTemps(FF_TEMP_GPU_M3X, &result); break;
|
||||
default: error = "Unsupported Apple Silicon GPU";
|
||||
}
|
||||
}
|
||||
else if (ffStrbufStartsWithS(gpuName, "Intel"))
|
||||
error = ffDetectCoreTemps(FF_TEMP_GPU_INTEL, &result);
|
||||
error = ffDetectSmcTemps(FF_TEMP_GPU_INTEL, &result);
|
||||
else if (ffStrbufStartsWithS(gpuName, "Radeon") || ffStrbufStartsWithS(gpuName, "AMD"))
|
||||
error = ffDetectCoreTemps(FF_TEMP_GPU_AMD, &result);
|
||||
error = ffDetectSmcTemps(FF_TEMP_GPU_AMD, &result);
|
||||
else
|
||||
error = ffDetectCoreTemps(FF_TEMP_GPU_UNKNOWN, &result);
|
||||
error = ffDetectSmcTemps(FF_TEMP_GPU_UNKNOWN, &result);
|
||||
|
||||
if (error)
|
||||
return FF_GPU_TEMP_UNSET;
|
||||
@@ -54,6 +56,9 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
|
||||
|
||||
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
|
||||
gpu->type = FF_GPU_TYPE_UNKNOWN;
|
||||
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
|
||||
IORegistryEntryGetRegistryEntryID(registryEntry, &gpu->deviceId);
|
||||
ffStrbufInitStatic(&gpu->platformApi, "Metal");
|
||||
|
||||
ffStrbufInit(&gpu->driver); // Ok for both Apple and Intel
|
||||
ffCfDictGetString(properties, CFSTR("CFBundleIdentifier"), &gpu->driver);
|
||||
@@ -102,5 +107,7 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
|
||||
}
|
||||
|
||||
IOObjectRelease(iterator);
|
||||
|
||||
ffGpuDetectMetal(gpus);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
#include "gpu.h"
|
||||
|
||||
#import <Metal/MTLDevice.h>
|
||||
|
||||
#ifndef MAC_OS_VERSION_13_0
|
||||
#define MTLGPUFamilyMetal3 ((MTLGPUFamily) 5001)
|
||||
#endif
|
||||
|
||||
const char* ffGpuDetectMetal(FFlist* gpus)
|
||||
{
|
||||
if (@available(macOS 10.15, *))
|
||||
{
|
||||
for (id<MTLDevice> device in MTLCopyAllDevices())
|
||||
{
|
||||
FFGPUResult* gpu = NULL;
|
||||
FF_LIST_FOR_EACH(FFGPUResult, x, *gpus)
|
||||
{
|
||||
if (x->deviceId == device.registryID || ffStrbufEqualS(&x->name, device.name.UTF8String))
|
||||
{
|
||||
gpu = x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!gpu) continue;
|
||||
|
||||
if ([device supportsFamily:MTLGPUFamilyMetal3])
|
||||
ffStrbufSetStatic(&gpu->platformApi, "Metal 3");
|
||||
else if ([device supportsFamily:MTLGPUFamilyCommon3])
|
||||
ffStrbufSetStatic(&gpu->platformApi, "Metal Common 3");
|
||||
else if ([device supportsFamily:MTLGPUFamilyCommon2])
|
||||
ffStrbufSetStatic(&gpu->platformApi, "Metal Common 2");
|
||||
else if ([device supportsFamily:MTLGPUFamilyCommon1])
|
||||
ffStrbufSetStatic(&gpu->platformApi, "Metal Common 1");
|
||||
|
||||
gpu->type = device.hasUnifiedMemory ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include "gpu.h"
|
||||
|
||||
typedef enum FFGpuDriverConditionType
|
||||
{
|
||||
FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID = 1 << 0,
|
||||
FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID = 1 << 1,
|
||||
FF_GPU_DRIVER_CONDITION_TYPE_LUID = 1 << 2,
|
||||
} FFGpuDriverConditionType;
|
||||
|
||||
typedef struct FFGpuDriverPciBusId
|
||||
{
|
||||
uint32_t domain;
|
||||
uint32_t bus;
|
||||
uint32_t device;
|
||||
uint32_t func;
|
||||
} FFGpuDriverPciBusId;
|
||||
|
||||
typedef struct FFGpuDriverPciDeviceId
|
||||
{
|
||||
uint32_t deviceId;
|
||||
uint32_t vendorId;
|
||||
uint32_t subSystemId;
|
||||
uint32_t revId;
|
||||
} FFGpuDriverPciDeviceId;
|
||||
|
||||
// Use pciBusId if not NULL; use pciDeviceId otherwise
|
||||
typedef struct FFGpuDriverCondition
|
||||
{
|
||||
FFGpuDriverConditionType type;
|
||||
FFGpuDriverPciBusId pciBusId;
|
||||
FFGpuDriverPciDeviceId pciDeviceId;
|
||||
uint64_t luid;
|
||||
} FFGpuDriverCondition;
|
||||
|
||||
// detect x if not NULL
|
||||
typedef struct FFGpuDriverResult
|
||||
{
|
||||
double* temp;
|
||||
FFGPUMemory* memory;
|
||||
uint32_t* coreCount;
|
||||
FFGPUType* type;
|
||||
double* frequency;
|
||||
} FFGpuDriverResult;
|
||||
|
||||
const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResult result, const char* soName);
|
||||
const char* ffDetectIntelGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResult result, const char* soName);
|
||||
const char* ffDetectAmdGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResult result, const char* soName);
|
||||
@@ -0,0 +1,200 @@
|
||||
#include "gpu_driver_specific.h"
|
||||
|
||||
#include "3rdparty/igcl/igcl_api.h"
|
||||
#include "common/library.h"
|
||||
#include "util/mallocHelper.h"
|
||||
|
||||
struct FFIgclData {
|
||||
FF_LIBRARY_SYMBOL(ctlClose)
|
||||
|
||||
FF_LIBRARY_SYMBOL(ctlEnumerateDevices)
|
||||
FF_LIBRARY_SYMBOL(ctlGetDeviceProperties)
|
||||
FF_LIBRARY_SYMBOL(ctlEnumTemperatureSensors)
|
||||
FF_LIBRARY_SYMBOL(ctlTemperatureGetState)
|
||||
FF_LIBRARY_SYMBOL(ctlEnumMemoryModules)
|
||||
FF_LIBRARY_SYMBOL(ctlMemoryGetState)
|
||||
FF_LIBRARY_SYMBOL(ctlEnumFrequencyDomains)
|
||||
FF_LIBRARY_SYMBOL(ctlFrequencyGetState)
|
||||
|
||||
bool inited;
|
||||
ctl_api_handle_t apiHandle;
|
||||
} igclData;
|
||||
|
||||
static void shutdownIgcl()
|
||||
{
|
||||
if (igclData.apiHandle)
|
||||
{
|
||||
igclData.ffctlClose(igclData.apiHandle);
|
||||
igclData.apiHandle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const char* ffDetectIntelGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResult result, const char* soName)
|
||||
{
|
||||
if (!igclData.inited)
|
||||
{
|
||||
igclData.inited = true;
|
||||
FF_LIBRARY_LOAD(libigcl, NULL, "dlopen igcl (ControlLib) failed", soName , 1);
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libigcl, ctlInit)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlClose)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlEnumerateDevices)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlGetDeviceProperties)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlEnumTemperatureSensors)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlTemperatureGetState)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlEnumMemoryModules)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlMemoryGetState)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlEnumFrequencyDomains)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlFrequencyGetState)
|
||||
|
||||
if (ffctlInit(&(ctl_init_args_t) {
|
||||
.AppVersion = CTL_MAKE_VERSION(CTL_IMPL_MAJOR_VERSION, CTL_IMPL_MINOR_VERSION),
|
||||
.flags = CTL_INIT_FLAG_USE_LEVEL_ZERO,
|
||||
.Size = sizeof(ctl_init_args_t),
|
||||
.Version = 0,
|
||||
}, &igclData.apiHandle) != CTL_RESULT_SUCCESS)
|
||||
return "loading igcl library failed";
|
||||
atexit(shutdownIgcl);
|
||||
libigcl = NULL; // don't close igcl
|
||||
}
|
||||
|
||||
if (!igclData.apiHandle)
|
||||
return "loading igcl library failed";
|
||||
|
||||
uint32_t deviceCount = 0;
|
||||
if (igclData.ffctlEnumerateDevices(igclData.apiHandle, &deviceCount, NULL))
|
||||
return "ctlEnumerateDevices(NULL) failed";
|
||||
if (deviceCount == 0)
|
||||
return "No Intel graphics adapter found";
|
||||
|
||||
FF_AUTO_FREE ctl_device_adapter_handle_t* devices = malloc(deviceCount * sizeof(*devices));
|
||||
if (igclData.ffctlEnumerateDevices(igclData.apiHandle, &deviceCount, devices))
|
||||
return "ctlEnumerateDevices(devices) failed";
|
||||
|
||||
ctl_device_adapter_handle_t device = NULL;
|
||||
|
||||
uint64_t /* LUID */ deviceId = 0;
|
||||
ctl_device_adapter_properties_t properties = {
|
||||
.Size = sizeof(properties),
|
||||
.pDeviceID = &deviceId,
|
||||
.device_id_size = sizeof(deviceId),
|
||||
.Version = 2,
|
||||
};
|
||||
for (uint32_t iDev = 0; iDev < deviceCount; iDev++)
|
||||
{
|
||||
if (igclData.ffctlGetDeviceProperties(devices[iDev], &properties) != CTL_RESULT_SUCCESS)
|
||||
continue;
|
||||
|
||||
if (properties.device_type != CTL_DEVICE_TYPE_GRAPHICS)
|
||||
continue;
|
||||
|
||||
if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_LUID)
|
||||
{
|
||||
if (cond->luid == deviceId)
|
||||
{
|
||||
device = devices[iDev];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID)
|
||||
{
|
||||
if (cond->pciBusId.bus == properties.adapter_bdf.bus &&
|
||||
cond->pciBusId.device == properties.adapter_bdf.device &&
|
||||
cond->pciBusId.func == properties.adapter_bdf.function)
|
||||
{
|
||||
device = devices[iDev];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID)
|
||||
{
|
||||
if (
|
||||
cond->pciDeviceId.deviceId == properties.pci_device_id &&
|
||||
cond->pciDeviceId.vendorId == properties.pci_vendor_id &&
|
||||
cond->pciDeviceId.subSystemId == (uint32_t) ((properties.pci_subsys_id << 16u) | properties.pci_subsys_vendor_id) &&
|
||||
cond->pciDeviceId.revId == properties.rev_id)
|
||||
{
|
||||
device = devices[iDev];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!device)
|
||||
return "Device not found";
|
||||
|
||||
if (result.coreCount)
|
||||
*result.coreCount = properties.num_slices * properties.num_sub_slices_per_slice * properties.num_eus_per_sub_slice;
|
||||
|
||||
if (result.memory)
|
||||
{
|
||||
ctl_mem_handle_t memoryModules[16];
|
||||
uint32_t memoryCount = sizeof(memoryModules) / sizeof(memoryModules[0]);
|
||||
if (igclData.ffctlEnumMemoryModules(device, &memoryCount, memoryModules) == CTL_RESULT_SUCCESS && memoryCount > 0)
|
||||
{
|
||||
result.memory->used = 0;
|
||||
result.memory->total = 0;
|
||||
for (uint32_t iMem = 0; iMem < memoryCount; iMem++)
|
||||
{
|
||||
ctl_mem_state_t memoryState = {
|
||||
.Size = sizeof(ctl_mem_state_t),
|
||||
.Version = 0,
|
||||
};
|
||||
if (igclData.ffctlMemoryGetState(memoryModules[iMem], &memoryState) == CTL_RESULT_SUCCESS)
|
||||
{
|
||||
result.memory->total += memoryState.size;
|
||||
result.memory->used += memoryState.size - memoryState.free;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result.type)
|
||||
{
|
||||
*result.type = properties.graphics_adapter_properties & CTL_ADAPTER_PROPERTIES_FLAG_INTEGRATED
|
||||
? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
|
||||
}
|
||||
|
||||
if (result.temp)
|
||||
{
|
||||
ctl_temp_handle_t sensors[16];
|
||||
uint32_t sensorCount = sizeof(sensors) / sizeof(sensors[0]);
|
||||
if (igclData.ffctlEnumTemperatureSensors(device, &sensorCount, sensors) == CTL_RESULT_SUCCESS && sensorCount > 0)
|
||||
{
|
||||
double sumValue = 0;
|
||||
uint32_t availableCount = 0;
|
||||
for (uint32_t iSensor = 0; iSensor < sensorCount; iSensor++)
|
||||
{
|
||||
double value;
|
||||
if (igclData.ffctlTemperatureGetState(sensors[iSensor], &value) == CTL_RESULT_SUCCESS)
|
||||
{
|
||||
sumValue += value;
|
||||
availableCount++;
|
||||
}
|
||||
}
|
||||
*result.temp = sumValue / availableCount;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.frequency)
|
||||
{
|
||||
ctl_freq_handle_t freqs[16];
|
||||
uint32_t freqCount = sizeof(freqs) / sizeof(freqs[0]);
|
||||
if (igclData.ffctlEnumFrequencyDomains(device, &freqCount, freqs) == CTL_RESULT_SUCCESS && freqCount > 0)
|
||||
{
|
||||
double sumValue = 0;
|
||||
uint32_t availableCount = 0;
|
||||
for (uint32_t iFreq = 0; iFreq < freqCount; iFreq++)
|
||||
{
|
||||
ctl_freq_state_t state = { .Size = sizeof(state), .Version = 0 };
|
||||
if (igclData.ffctlFrequencyGetState(freqs[iFreq], &state) == CTL_RESULT_SUCCESS)
|
||||
{
|
||||
sumValue += state.actual;
|
||||
availableCount++;
|
||||
}
|
||||
}
|
||||
*result.frequency = (sumValue / availableCount) / 1000.;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "detection/gpu/gpu.h"
|
||||
#include "detection/gpu/gpu_nvidia.h"
|
||||
#include "detection/gpu/gpu_driver_specific.h"
|
||||
#include "detection/vulkan/vulkan.h"
|
||||
|
||||
#ifdef FF_HAVE_LIBPCI
|
||||
@@ -46,12 +46,14 @@ static void pciDetectVendorName(FFGPUResult* gpu, PCIData* pci, struct pci_dev*
|
||||
pci->ffpci_lookup_name(pci->access, gpu->vendor.chars, (int) gpu->vendor.allocated, PCI_LOOKUP_VENDOR, device->vendor_id);
|
||||
ffStrbufRecalculateLength(&gpu->vendor);
|
||||
|
||||
if(ffStrbufContainS(&gpu->vendor, "AMD") || ffStrbufContainS(&gpu->vendor, "ATI"))
|
||||
if(ffStrbufContainIgnCaseS(&gpu->vendor, "AMD") || ffStrbufContainS(&gpu->vendor, "ATI"))
|
||||
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD);
|
||||
else if(ffStrbufContainS(&gpu->vendor, "Intel"))
|
||||
else if(ffStrbufContainIgnCaseS(&gpu->vendor, "Intel"))
|
||||
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL);
|
||||
else if(ffStrbufContainS(&gpu->vendor, "NVIDIA"))
|
||||
else if(ffStrbufContainIgnCaseS(&gpu->vendor, "NVIDIA"))
|
||||
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_NVIDIA);
|
||||
else if(ffStrbufContainIgnCaseS(&gpu->vendor, "Apple"))
|
||||
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE);
|
||||
}
|
||||
|
||||
static void drmDetectDeviceName(FFGPUResult* gpu, PCIData* pci, struct pci_dev* device)
|
||||
@@ -133,7 +135,7 @@ static void pciDetectDriverName(FFGPUResult* gpu, PCIData* pci, struct pci_dev*
|
||||
ffStrbufAppendC(&gpu->driver, ' ');
|
||||
ffStrbufAppendS(&path, "/module/version");
|
||||
ffAppendFileBuffer(path.chars, &gpu->driver);
|
||||
ffStrbufTrimRight(&gpu->driver, ' ');
|
||||
ffStrbufTrimRightSpace(&gpu->driver);
|
||||
}
|
||||
|
||||
FF_MAYBE_UNUSED static void pciDetectTemp(FFGPUResult* gpu, struct pci_dev* device)
|
||||
@@ -219,6 +221,8 @@ static void pciHandleDevice(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
|
||||
|
||||
FFGPUResult* gpu = ffListAdd(results);
|
||||
|
||||
ffStrbufInit(&gpu->platformApi);
|
||||
|
||||
ffStrbufInit(&gpu->vendor);
|
||||
pciDetectVendorName(gpu, pci, device);
|
||||
|
||||
@@ -239,16 +243,24 @@ static void pciHandleDevice(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
|
||||
|
||||
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
|
||||
gpu->temperature = FF_GPU_TEMP_UNSET;
|
||||
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
|
||||
|
||||
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA && (options->temp || options->useNvml))
|
||||
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA && (options->temp || options->driverSpecific))
|
||||
{
|
||||
char pciDeviceId[32];
|
||||
snprintf(pciDeviceId, sizeof(pciDeviceId) - 1, "%04x:%02x:%02x.%d", device->domain, device->bus, device->dev, device->func);
|
||||
|
||||
ffDetectNvidiaGpuInfo((FFGpuNvidiaCondition) { .pciBusId = pciDeviceId }, (FFGpuNvidiaResult) {
|
||||
ffDetectNvidiaGpuInfo(&(FFGpuDriverCondition) {
|
||||
.type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID,
|
||||
.pciBusId = {
|
||||
.domain = (uint32_t) device->domain,
|
||||
.bus = device->bus,
|
||||
.device = device->dev,
|
||||
.func = device->func,
|
||||
},
|
||||
}, (FFGpuDriverResult) {
|
||||
.temp = options->temp ? &gpu->temperature : NULL,
|
||||
.memory = options->useNvml ? &gpu->dedicated : NULL,
|
||||
.coreCount = options->useNvml ? (uint32_t*) &gpu->coreCount : NULL,
|
||||
.memory = options->driverSpecific ? &gpu->dedicated : NULL,
|
||||
.coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL,
|
||||
.type = &gpu->type,
|
||||
.frequency = &gpu->frequency,
|
||||
}, "libnvidia-ml.so");
|
||||
|
||||
if (gpu->dedicated.total != FF_GPU_VMEM_SIZE_UNSET)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "gpu_nvidia.h"
|
||||
#include "gpu_driver_specific.h"
|
||||
|
||||
#include "3rdparty/nvml/nvml.h"
|
||||
#include "common/library.h"
|
||||
@@ -11,11 +11,12 @@ struct FFNvmlData {
|
||||
FF_LIBRARY_SYMBOL(nvmlDeviceGetTemperature)
|
||||
FF_LIBRARY_SYMBOL(nvmlDeviceGetMemoryInfo_v2)
|
||||
FF_LIBRARY_SYMBOL(nvmlDeviceGetNumGpuCores)
|
||||
FF_LIBRARY_SYMBOL(nvmlDeviceGetClockInfo)
|
||||
|
||||
bool inited;
|
||||
} nvmlData;
|
||||
|
||||
const char* ffDetectNvidiaGpuInfo(FFGpuNvidiaCondition cond, FFGpuNvidiaResult result, const char* soName)
|
||||
const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResult result, const char* soName)
|
||||
{
|
||||
if (!nvmlData.inited)
|
||||
{
|
||||
@@ -30,6 +31,7 @@ const char* ffDetectNvidiaGpuInfo(FFGpuNvidiaCondition cond, FFGpuNvidiaResult r
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetTemperature)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMemoryInfo_v2)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetNumGpuCores)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetClockInfo)
|
||||
|
||||
if (ffnvmlInit_v2() != NVML_SUCCESS)
|
||||
{
|
||||
@@ -44,13 +46,16 @@ const char* ffDetectNvidiaGpuInfo(FFGpuNvidiaCondition cond, FFGpuNvidiaResult r
|
||||
return "loading nvml library failed";
|
||||
|
||||
nvmlDevice_t device = NULL;
|
||||
if (cond.pciBusId)
|
||||
if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID)
|
||||
{
|
||||
nvmlReturn_t ret = nvmlData.ffnvmlDeviceGetHandleByPciBusId_v2(cond.pciBusId, &device);
|
||||
char pciBusIdStr[32];
|
||||
snprintf(pciBusIdStr, sizeof(pciBusIdStr) - 1, "%04x:%02x:%02x.%d", cond->pciBusId.domain, cond->pciBusId.bus, cond->pciBusId.device, cond->pciBusId.func);
|
||||
|
||||
nvmlReturn_t ret = nvmlData.ffnvmlDeviceGetHandleByPciBusId_v2(pciBusIdStr, &device);
|
||||
if (ret != NVML_SUCCESS)
|
||||
return "nvmlDeviceGetHandleByPciBusId_v2() failed";
|
||||
}
|
||||
else
|
||||
else if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID)
|
||||
{
|
||||
uint32_t count;
|
||||
if (nvmlData.ffnvmlDeviceGetCount_v2(&count) != NVML_SUCCESS)
|
||||
@@ -65,7 +70,8 @@ const char* ffDetectNvidiaGpuInfo(FFGpuNvidiaCondition cond, FFGpuNvidiaResult r
|
||||
if (nvmlData.ffnvmlDeviceGetPciInfo_v3(device, &pciInfo) != NVML_SUCCESS)
|
||||
continue;
|
||||
|
||||
if (pciInfo.pciDeviceId != cond.pciDeviceId || pciInfo.pciSubSystemId != cond.pciSubSystemId)
|
||||
if (pciInfo.pciDeviceId != ((cond->pciDeviceId.deviceId << 16u) | cond->pciDeviceId.vendorId) ||
|
||||
pciInfo.pciSubSystemId != cond->pciDeviceId.subSystemId)
|
||||
continue;
|
||||
|
||||
break;
|
||||
@@ -93,5 +99,12 @@ const char* ffDetectNvidiaGpuInfo(FFGpuNvidiaCondition cond, FFGpuNvidiaResult r
|
||||
if (result.coreCount)
|
||||
nvmlData.ffnvmlDeviceGetNumGpuCores(device, result.coreCount);
|
||||
|
||||
if (result.frequency)
|
||||
{
|
||||
uint32_t clockMHz;
|
||||
if (nvmlData.ffnvmlDeviceGetClockInfo(device, NVML_CLOCK_GRAPHICS, &clockMHz) == NVML_SUCCESS)
|
||||
*result.frequency = clockMHz / 1000.;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "gpu.h"
|
||||
|
||||
// Use pciBusId if not NULL; use pciDeviceId and pciSubSystemId otherwise
|
||||
typedef struct FFGpuNvidiaCondition
|
||||
{
|
||||
// "domain:bus:device.function"
|
||||
const char* pciBusId;
|
||||
// (deviceId << 16) | vendorId
|
||||
uint32_t pciDeviceId;
|
||||
uint32_t pciSubSystemId;
|
||||
} FFGpuNvidiaCondition;
|
||||
|
||||
// detect x if not NULL
|
||||
typedef struct FFGpuNvidiaResult
|
||||
{
|
||||
double* temp;
|
||||
FFGPUMemory* memory;
|
||||
uint32_t* coreCount;
|
||||
} FFGpuNvidiaResult;
|
||||
|
||||
const char* ffDetectNvidiaGpuInfo(FFGpuNvidiaCondition cond, FFGpuNvidiaResult result, const char* soName);
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "gpu.h"
|
||||
#include "detection/gpu/gpu_nvidia.h"
|
||||
#include "detection/gpu/gpu_driver_specific.h"
|
||||
#include "util/windows/unicode.h"
|
||||
#include "util/windows/registry.h"
|
||||
|
||||
@@ -10,6 +10,41 @@ static int isGpuNameEqual(const FFGPUResult* gpu, const FFstrbuf* name)
|
||||
return ffStrbufEqual(&gpu->name, name);
|
||||
}
|
||||
|
||||
static inline bool getDriverSpecificDetectionFn(const char* vendor, __typeof__(&ffDetectNvidiaGpuInfo)* pDetectFn, const char** pDllName)
|
||||
{
|
||||
if (vendor == FF_GPU_VENDOR_NAME_NVIDIA)
|
||||
{
|
||||
*pDetectFn = ffDetectNvidiaGpuInfo;
|
||||
*pDllName = "nvml.dll";
|
||||
}
|
||||
else if (vendor == FF_GPU_VENDOR_NAME_INTEL)
|
||||
{
|
||||
*pDetectFn = ffDetectIntelGpuInfo;
|
||||
#ifdef _WIN64
|
||||
*pDllName = "ControlLib.dll";
|
||||
#else
|
||||
*pDllName = "ControlLib32.dll";
|
||||
#endif
|
||||
}
|
||||
else if (vendor == FF_GPU_VENDOR_NAME_AMD)
|
||||
{
|
||||
*pDetectFn = ffDetectAmdGpuInfo;
|
||||
#ifdef _WIN64
|
||||
*pDllName = "amd_ags_x64.dll";
|
||||
#else
|
||||
*pDllName = "amd_ags_x86.dll";
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
*pDetectFn = NULL;
|
||||
*pDllName = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
|
||||
{
|
||||
DISPLAY_DEVICEW displayDevice = { .cb = sizeof(displayDevice) };
|
||||
@@ -35,14 +70,22 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
|
||||
if (ffListContains(gpus, &gpuName, (void*) isGpuNameEqual)) continue;
|
||||
}
|
||||
|
||||
// See: https://download.nvidia.com/XFree86/Linux-x86_64/545.23.06/README/supportedchips.html
|
||||
// displayDevice.DeviceID = MatchingDeviceId "PCI\\VEN_10DE&DEV_2782&SUBSYS_513417AA&REV_A1"
|
||||
uint32_t vendorId = 0, deviceId = 0, subSystemId = 0, revId = 0;
|
||||
swscanf(displayDevice.DeviceID, L"PCI\\VEN_%x&DEV_%x&SUBSYS_%x&REV_%x", &vendorId, &deviceId, &subSystemId, &revId);
|
||||
|
||||
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
|
||||
ffStrbufInit(&gpu->vendor);
|
||||
ffStrbufInitStatic(&gpu->vendor, ffGetGPUVendorString(vendorId));
|
||||
ffStrbufInitWS(&gpu->name, displayDevice.DeviceString);
|
||||
ffStrbufInit(&gpu->driver);
|
||||
ffStrbufInitStatic(&gpu->platformApi, "Direct3D");
|
||||
gpu->temperature = FF_GPU_TEMP_UNSET;
|
||||
gpu->coreCount = FF_GPU_CORE_COUNT_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;
|
||||
|
||||
if (deviceKeyLength == 100 && displayDevice.DeviceKey[deviceKeyPrefixLength - 1] == '{')
|
||||
{
|
||||
@@ -51,14 +94,6 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
|
||||
if (!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regControlVideoKey, &hKey, NULL)) continue;
|
||||
|
||||
ffRegReadStrbuf(hKey, L"DriverVersion", &gpu->driver, NULL);
|
||||
ffRegReadStrbuf(hKey, L"ProviderName", &gpu->vendor, NULL);
|
||||
|
||||
if(ffStrbufContainS(&gpu->vendor, "AMD") || ffStrbufContainS(&gpu->vendor, "ATI"))
|
||||
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD);
|
||||
else if(ffStrbufContainS(&gpu->vendor, "Intel"))
|
||||
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL);
|
||||
else if(ffStrbufContainS(&gpu->vendor, "NVIDIA"))
|
||||
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_NVIDIA);
|
||||
|
||||
wmemcpy(regDirectxKey + regDirectxKeyPrefixLength, displayDevice.DeviceKey + deviceKeyPrefixLength, strlen("00000000-0000-0000-0000-000000000000}"));
|
||||
FF_HKEY_AUTO_DESTROY hDirectxKey = NULL;
|
||||
@@ -75,6 +110,14 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
|
||||
gpu->dedicated.total = dedicatedVideoMemory + dedicatedSystemMemory;
|
||||
gpu->shared.total = sharedSystemMemory;
|
||||
}
|
||||
|
||||
ffRegReadUint64(hDirectxKey, L"AdapterLuid", &gpu->deviceId, NULL);
|
||||
|
||||
uint32_t featureLevel = 0;
|
||||
if(ffRegReadUint(hDirectxKey, L"MaxD3D12FeatureLevel", &featureLevel, NULL) && featureLevel)
|
||||
ffStrbufSetF(&gpu->platformApi, "Direct3D 12.%u", (featureLevel & 0x0F00) >> 8);
|
||||
else if(ffRegReadUint(hDirectxKey, L"MaxD3D11FeatureLevel", &featureLevel, NULL) && featureLevel)
|
||||
ffStrbufSetF(&gpu->platformApi, "Direct3D 11.%u", (featureLevel & 0x0F00) >> 8);
|
||||
}
|
||||
else if (!ffRegReadUint64(hKey, L"HardwareInformation.qwMemorySize", &gpu->dedicated.total, NULL))
|
||||
{
|
||||
@@ -83,23 +126,46 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
|
||||
gpu->dedicated.total = vmem;
|
||||
gpu->type = gpu->dedicated.total > 1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
|
||||
}
|
||||
|
||||
if (gpu->vendor.length == 0)
|
||||
{
|
||||
ffRegReadStrbuf(hKey, L"ProviderName", &gpu->vendor, NULL);
|
||||
if (ffStrbufContainS(&gpu->vendor, "Intel"))
|
||||
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL);
|
||||
else if (ffStrbufContainS(&gpu->vendor, "NVIDIA"))
|
||||
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_NVIDIA);
|
||||
else if (ffStrbufContainS(&gpu->vendor, "AMD") || ffStrbufContainS(&gpu->vendor, "ATI"))
|
||||
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD);
|
||||
}
|
||||
}
|
||||
|
||||
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA && (options->temp || options->useNvml))
|
||||
__typeof__(&ffDetectNvidiaGpuInfo) detectFn;
|
||||
const char* dllName;
|
||||
|
||||
if (getDriverSpecificDetectionFn(gpu->vendor.chars, &detectFn, &dllName) && (options->temp || options->driverSpecific))
|
||||
{
|
||||
uint32_t vendorId, deviceId, subSystemId;
|
||||
// See: https://download.nvidia.com/XFree86/Linux-x86_64/545.23.06/README/supportedchips.html
|
||||
// displayDevice.DeviceID = MatchingDeviceId "PCI\\VEN_10DE&DEV_2782&SUBSYS_513417AA&REV_A1"
|
||||
if (swscanf(displayDevice.DeviceID, L"PCI\\VEN_%x&DEV_%x&SUBSYS_%x", &vendorId, &deviceId, &subSystemId) == 3)
|
||||
if (vendorId && deviceId && subSystemId && revId)
|
||||
{
|
||||
ffDetectNvidiaGpuInfo((FFGpuNvidiaCondition) {
|
||||
.pciDeviceId = (deviceId << 16) | vendorId,
|
||||
.pciSubSystemId = subSystemId,
|
||||
}, (FFGpuNvidiaResult) {
|
||||
.temp = options->temp ? &gpu->temperature : NULL,
|
||||
.memory = options->useNvml ? &gpu->dedicated : NULL,
|
||||
.coreCount = options->useNvml ? (uint32_t*) &gpu->coreCount : NULL,
|
||||
}, "nvml.dll");
|
||||
detectFn(
|
||||
&(FFGpuDriverCondition) {
|
||||
.type = FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID | FF_GPU_DRIVER_CONDITION_TYPE_LUID,
|
||||
.pciDeviceId = {
|
||||
.deviceId = deviceId,
|
||||
.vendorId = vendorId,
|
||||
.subSystemId = subSystemId,
|
||||
.revId = revId,
|
||||
},
|
||||
.luid = gpu->deviceId,
|
||||
},
|
||||
(FFGpuDriverResult) {
|
||||
.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,
|
||||
},
|
||||
dllName
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
extern "C" {
|
||||
#include "common/library.h"
|
||||
#include "detection/gpu/gpu.h"
|
||||
#include "detection/gpu/gpu_nvidia.h"
|
||||
#include "detection/gpu/gpu_driver_specific.h"
|
||||
}
|
||||
|
||||
#include <wsl/winadapter.h>
|
||||
@@ -14,6 +14,8 @@ extern "C" {
|
||||
#include <utility>
|
||||
#include <cinttypes>
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
|
||||
template <typename Fn>
|
||||
struct on_scope_exit {
|
||||
on_scope_exit(Fn &&fn): _fn(std::move(fn)) {}
|
||||
@@ -65,6 +67,7 @@ const char* ffGPUDetectByDirectX(FF_MAYBE_UNUSED const FFGPUOptions* options, FF
|
||||
ffStrbufInitS(&gpu->name, desc);
|
||||
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
|
||||
gpu->temperature = FF_GPU_TEMP_UNSET;
|
||||
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
|
||||
|
||||
ffStrbufInit(&gpu->driver);
|
||||
uint64_t value = 0;
|
||||
@@ -95,16 +98,23 @@ const char* ffGPUDetectByDirectX(FF_MAYBE_UNUSED const FFGPUOptions* options, FF
|
||||
const char* vendorStr = ffGetGPUVendorString((unsigned) hardwareId.vendorID);
|
||||
ffStrbufSetStatic(&gpu->vendor, vendorStr);
|
||||
|
||||
if (vendorStr == FF_GPU_VENDOR_NAME_NVIDIA && options->useNvml)
|
||||
if (vendorStr == FF_GPU_VENDOR_NAME_NVIDIA && (options->driverSpecific || options->temp))
|
||||
{
|
||||
ffDetectNvidiaGpuInfo((FFGpuNvidiaCondition) {
|
||||
.pciBusId = nullptr,
|
||||
.pciDeviceId = (hardwareId.deviceID << 16) | hardwareId.vendorID,
|
||||
.pciSubSystemId = hardwareId.subSysID
|
||||
}, (FFGpuNvidiaResult) {
|
||||
FFGpuDriverCondition cond = {
|
||||
.type = FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID,
|
||||
.pciDeviceId = {
|
||||
.deviceId = hardwareId.deviceID,
|
||||
.vendorId = hardwareId.vendorID,
|
||||
.subSystemId = hardwareId.subSysID,
|
||||
.revId = hardwareId.revision,
|
||||
},
|
||||
};
|
||||
ffDetectNvidiaGpuInfo(&cond, (FFGpuDriverResult) {
|
||||
.temp = options->temp ? &gpu->temperature : NULL,
|
||||
.memory = options->useNvml ? &gpu->dedicated : NULL,
|
||||
.coreCount = options->useNvml ? (uint32_t*) &gpu->coreCount : NULL,
|
||||
.memory = options->driverSpecific ? &gpu->dedicated : NULL,
|
||||
.coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL,
|
||||
.type = &gpu->type,
|
||||
.frequency = &gpu->frequency,
|
||||
}, "/usr/lib/wsl/lib/libnvidia-ml.so");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,22 +5,9 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static void getSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer)
|
||||
{
|
||||
ffReadFileBuffer(devicesPath, buffer);
|
||||
if(ffIsSmbiosValueSet(buffer))
|
||||
return;
|
||||
|
||||
ffReadFileBuffer(classPath, buffer);
|
||||
if(ffIsSmbiosValueSet(buffer))
|
||||
return;
|
||||
|
||||
ffStrbufClear(buffer);
|
||||
}
|
||||
|
||||
static void getHostProductName(FFstrbuf* name)
|
||||
{
|
||||
getSmbiosValue("/sys/devices/virtual/dmi/id/product_name", "/sys/class/dmi/id/product_name", name);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_name", "/sys/class/dmi/id/product_name", name);
|
||||
if(name->length > 0)
|
||||
return;
|
||||
|
||||
@@ -42,11 +29,11 @@ static void getHostProductName(FFstrbuf* name)
|
||||
|
||||
const char* ffDetectHost(FFHostResult* host)
|
||||
{
|
||||
getSmbiosValue("/sys/devices/virtual/dmi/id/product_family", "/sys/class/dmi/id/product_family", &host->productFamily);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_family", "/sys/class/dmi/id/product_family", &host->productFamily);
|
||||
getHostProductName(&host->productName);
|
||||
getSmbiosValue("/sys/devices/virtual/dmi/id/product_version", "/sys/class/dmi/id/product_version", &host->productVersion);
|
||||
getSmbiosValue("/sys/devices/virtual/dmi/id/product_sku", "/sys/class/dmi/id/product_sku", &host->productSku);
|
||||
getSmbiosValue("/sys/devices/virtual/dmi/id/sys_vendor", "/sys/class/dmi/id/sys_vendor", &host->sysVendor);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_version", "/sys/class/dmi/id/product_version", &host->productVersion);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_sku", "/sys/class/dmi/id/product_sku", &host->productSku);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/sys_vendor", "/sys/class/dmi/id/sys_vendor", &host->sysVendor);
|
||||
|
||||
//KVM/Qemu virtual machine
|
||||
if(ffStrbufStartsWithS(&host->productName, "Standard PC"))
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/thread.h"
|
||||
|
||||
#define FF_DETECTION_INTERNAL_GUARD(ResultType, ...) \
|
||||
static ResultType result; \
|
||||
static bool init = false; \
|
||||
if(init) \
|
||||
return &result; \
|
||||
init = true; \
|
||||
__VA_ARGS__; \
|
||||
return &result;
|
||||
@@ -1,11 +1,13 @@
|
||||
#include "media.h"
|
||||
#include "detection/internal.h"
|
||||
|
||||
void ffDetectMediaImpl(FFMediaResult* media);
|
||||
|
||||
const FFMediaResult* ffDetectMedia(void)
|
||||
{
|
||||
FF_DETECTION_INTERNAL_GUARD(FFMediaResult,
|
||||
static FFMediaResult result;
|
||||
|
||||
if (result.error.chars == NULL)
|
||||
{
|
||||
ffStrbufInit(&result.error);
|
||||
ffStrbufInit(&result.playerId);
|
||||
ffStrbufInit(&result.player);
|
||||
@@ -14,10 +16,11 @@ const FFMediaResult* ffDetectMedia(void)
|
||||
ffStrbufInit(&result.album);
|
||||
ffStrbufInit(&result.url);
|
||||
ffStrbufInit(&result.status);
|
||||
|
||||
ffDetectMediaImpl(&result);
|
||||
|
||||
if(result.song.length == 0 && result.error.length == 0)
|
||||
ffStrbufAppendS(&result.error, "No media found");
|
||||
);
|
||||
}
|
||||
|
||||
return &result;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,6 @@ static const char* getMedia(FFMediaResult* result)
|
||||
|
||||
void ffDetectMediaImpl(FFMediaResult* media)
|
||||
{
|
||||
FF_UNUSED(instance)
|
||||
const char* error = getMedia(media);
|
||||
ffStrbufAppendS(&media->error, error);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
static void getData(FFstrbuf* buffer, const char* ifName, bool isDefaultRoute, FFstrbuf* path, FFlist* result)
|
||||
{
|
||||
ffStrbufSetF(path, "/sys/class/net/%s/operstate", ifName);
|
||||
if(!ffReadFileBuffer(path->chars, buffer) || !ffStrbufEqualS(buffer, "up"))
|
||||
if(!ffReadFileBuffer(path->chars, buffer) || !ffStrbufEqualS(buffer, "up\n"))
|
||||
return;
|
||||
|
||||
FFNetIOResult* counters = (FFNetIOResult*) ffListAdd(result);
|
||||
|
||||
+16
-4
@@ -1,11 +1,23 @@
|
||||
#include "os.h"
|
||||
#include "detection/internal.h"
|
||||
|
||||
void ffDetectOSImpl(FFOSResult* os);
|
||||
|
||||
const FFOSResult* ffDetectOS(void)
|
||||
{
|
||||
FF_DETECTION_INTERNAL_GUARD(FFOSResult,
|
||||
ffDetectOSImpl(&result)
|
||||
);
|
||||
static FFOSResult result;
|
||||
if (result.name.chars == NULL)
|
||||
{
|
||||
ffStrbufInit(&result.name);
|
||||
ffStrbufInit(&result.prettyName);
|
||||
ffStrbufInit(&result.id);
|
||||
ffStrbufInit(&result.version);
|
||||
ffStrbufInit(&result.versionID);
|
||||
ffStrbufInit(&result.codename);
|
||||
ffStrbufInit(&result.buildID);
|
||||
ffStrbufInit(&result.idLike);
|
||||
ffStrbufInit(&result.variant);
|
||||
ffStrbufInit(&result.variantID);
|
||||
ffDetectOSImpl(&result);
|
||||
}
|
||||
return &result;
|
||||
}
|
||||
|
||||
@@ -3,25 +3,17 @@
|
||||
|
||||
void ffDetectOSImpl(FFOSResult* os)
|
||||
{
|
||||
ffStrbufInitStatic(&os->name, "Android");
|
||||
ffStrbufSetStatic(&os->name, "Android");
|
||||
|
||||
ffStrbufInitStatic(&os->prettyName, "Android");
|
||||
ffStrbufSetStatic(&os->prettyName, "Android");
|
||||
|
||||
ffStrbufInitStatic(&os->id, "android");
|
||||
ffStrbufSetStatic(&os->id, "android");
|
||||
|
||||
ffStrbufInit(&os->version);
|
||||
ffSettingsGetAndroidProperty("ro.build.version.release", &os->version);
|
||||
|
||||
ffStrbufInit(&os->versionID);
|
||||
ffSettingsGetAndroidProperty("ro.build.version.release", &os->versionID);
|
||||
|
||||
ffStrbufInit(&os->codename);
|
||||
ffSettingsGetAndroidProperty("ro.build.version.codename", &os->codename);
|
||||
|
||||
ffStrbufInit(&os->buildID);
|
||||
ffSettingsGetAndroidProperty("ro.build.id", &os->buildID);
|
||||
|
||||
ffStrbufInit(&os->idLike);
|
||||
ffStrbufInit(&os->variant);
|
||||
ffStrbufInit(&os->variantID);
|
||||
}
|
||||
|
||||
@@ -98,18 +98,6 @@ static void parseOSXSoftwareLicense(FFOSResult* os)
|
||||
|
||||
void ffDetectOSImpl(FFOSResult* os)
|
||||
{
|
||||
ffStrbufInit(&os->name);
|
||||
ffStrbufInit(&os->version);
|
||||
ffStrbufInit(&os->buildID);
|
||||
ffStrbufInit(&os->id);
|
||||
ffStrbufInit(&os->prettyName);
|
||||
ffStrbufInit(&os->versionID);
|
||||
|
||||
ffStrbufInit(&os->codename);
|
||||
ffStrbufInit(&os->idLike);
|
||||
ffStrbufInit(&os->variant);
|
||||
ffStrbufInit(&os->variantID);
|
||||
|
||||
parseSystemVersion(os);
|
||||
|
||||
if(ffStrbufStartsWithIgnCaseS(&os->name, "MacOS"))
|
||||
|
||||
@@ -126,6 +126,7 @@ static void getDebianVersion(FFOSResult* result)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY debianVersion = ffStrbufCreate();
|
||||
ffAppendFileBuffer("/etc/debian_version", &debianVersion);
|
||||
ffStrbufTrimRightSpace(&debianVersion);
|
||||
if (!debianVersion.length) return;
|
||||
ffStrbufSet(&result->version, &debianVersion);
|
||||
ffStrbufSet(&result->versionID, &debianVersion);
|
||||
@@ -166,17 +167,6 @@ static void detectOS(FFOSResult* os)
|
||||
|
||||
void ffDetectOSImpl(FFOSResult* os)
|
||||
{
|
||||
ffStrbufInit(&os->name);
|
||||
ffStrbufInit(&os->prettyName);
|
||||
ffStrbufInit(&os->id);
|
||||
ffStrbufInit(&os->idLike);
|
||||
ffStrbufInit(&os->variant);
|
||||
ffStrbufInit(&os->variantID);
|
||||
ffStrbufInit(&os->version);
|
||||
ffStrbufInit(&os->versionID);
|
||||
ffStrbufInit(&os->codename);
|
||||
ffStrbufInit(&os->buildID);
|
||||
|
||||
detectOS(os);
|
||||
|
||||
if(ffStrbufIgnCaseEqualS(&os->id, "ubuntu"))
|
||||
|
||||
@@ -42,17 +42,6 @@ static const char* getOsNameByWinbrand(FFstrbuf* osName)
|
||||
extern "C"
|
||||
void ffDetectOSImpl(FFOSResult* os)
|
||||
{
|
||||
ffStrbufInit(&os->name);
|
||||
ffStrbufInit(&os->prettyName);
|
||||
ffStrbufInit(&os->id);
|
||||
ffStrbufInit(&os->idLike);
|
||||
ffStrbufInit(&os->variant);
|
||||
ffStrbufInit(&os->variantID);
|
||||
ffStrbufInit(&os->version);
|
||||
ffStrbufInit(&os->versionID);
|
||||
ffStrbufInit(&os->codename);
|
||||
ffStrbufInit(&os->buildID);
|
||||
|
||||
if(getOsNameByWinbrand(&os->variant) && getOsNameByWmi(&os->variant))
|
||||
return;
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "packages.h"
|
||||
#include "detection/internal.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "fastfetch.h"
|
||||
|
||||
#define FF_PHYSICALDISK_TEMP_UNSET (0/0.0)
|
||||
|
||||
typedef enum FFPhysicalDiskType
|
||||
{
|
||||
FF_PHYSICALDISK_TYPE_NONE = 0,
|
||||
@@ -10,6 +12,9 @@ typedef enum FFPhysicalDiskType
|
||||
|
||||
FF_PHYSICALDISK_TYPE_FIXED = 1 << 2,
|
||||
FF_PHYSICALDISK_TYPE_REMOVABLE = 1 << 3,
|
||||
|
||||
FF_PHYSICALDISK_TYPE_READWRITE = 1 << 4,
|
||||
FF_PHYSICALDISK_TYPE_READONLY = 1 << 5,
|
||||
} FFPhysicalDiskType;
|
||||
|
||||
typedef struct FFPhysicalDiskResult
|
||||
@@ -18,8 +23,10 @@ typedef struct FFPhysicalDiskResult
|
||||
FFstrbuf interconnect;
|
||||
FFstrbuf serial;
|
||||
FFstrbuf devPath;
|
||||
FFstrbuf revision;
|
||||
FFPhysicalDiskType type;
|
||||
uint64_t size;
|
||||
double temperature;
|
||||
} FFPhysicalDiskResult;
|
||||
|
||||
const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <IOKit/storage/IOBlockStorageDriver.h>
|
||||
#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
|
||||
#include <IOKit/storage/IOStorageProtocolCharacteristics.h>
|
||||
#include <IOKit/storage/nvme/NVMeSMARTLibExternal.h>
|
||||
|
||||
static inline void wrapIoObjectRelease(io_service_t* service)
|
||||
{
|
||||
@@ -16,6 +17,35 @@ static inline void wrapIoObjectRelease(io_service_t* service)
|
||||
}
|
||||
#define FF_IOOBJECT_AUTO_RELEASE __attribute__((__cleanup__(wrapIoObjectRelease)))
|
||||
|
||||
static inline void wrapIoDestroyPlugInInterface(IOCFPlugInInterface*** pluginInf)
|
||||
{
|
||||
assert(pluginInf);
|
||||
if (*pluginInf)
|
||||
IODestroyPlugInInterface(*pluginInf);
|
||||
}
|
||||
|
||||
static const char* detectSsdTemp(io_service_t entryPhysical, double* temp)
|
||||
{
|
||||
__attribute__((__cleanup__(wrapIoDestroyPlugInInterface))) IOCFPlugInInterface** pluginInf = NULL;
|
||||
int32_t score;
|
||||
if (IOCreatePlugInInterfaceForService(entryPhysical, kIONVMeSMARTUserClientTypeID, kIOCFPlugInInterfaceID, &pluginInf, &score) != kIOReturnSuccess)
|
||||
return "IOCreatePlugInInterfaceForService() failed";
|
||||
|
||||
IONVMeSMARTInterface** smartInf = NULL;
|
||||
if ((*pluginInf)->QueryInterface(pluginInf, CFUUIDGetUUIDBytes(kIONVMeSMARTInterfaceID), (LPVOID) &smartInf) != kIOReturnSuccess)
|
||||
return "QueryInterface() failed";
|
||||
|
||||
NVMeSMARTData smartData;
|
||||
const char* error = NULL;
|
||||
if ((*smartInf)->SMARTReadData(smartInf, &smartData) == kIOReturnSuccess)
|
||||
*temp = smartData.TEMPERATURE - 273;
|
||||
else
|
||||
error = "SMARTReadData() failed";
|
||||
|
||||
(*pluginInf)->Release(smartInf);
|
||||
return error;
|
||||
}
|
||||
|
||||
const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
|
||||
{
|
||||
FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = 0;
|
||||
@@ -43,15 +73,20 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
|
||||
|
||||
FFPhysicalDiskResult* device = (FFPhysicalDiskResult*) ffListAdd(result);
|
||||
ffStrbufInit(&device->serial);
|
||||
ffStrbufInit(&device->revision);
|
||||
ffStrbufInitS(&device->name, deviceName);
|
||||
ffStrbufInit(&device->devPath);
|
||||
ffStrbufInit(&device->interconnect);
|
||||
device->type = FF_PHYSICALDISK_TYPE_NONE;
|
||||
device->size = 0;
|
||||
device->temperature = FF_PHYSICALDISK_TEMP_UNSET;
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFBooleanRef removable = IORegistryEntryCreateCFProperty(entryPartition, CFSTR(kIOMediaRemovableKey), kCFAllocatorDefault, kNilOptions);
|
||||
device->type |= CFBooleanGetValue(removable) ? FF_PHYSICALDISK_TYPE_REMOVABLE : FF_PHYSICALDISK_TYPE_FIXED;
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFBooleanRef writable = IORegistryEntryCreateCFProperty(entryPartition, CFSTR(kIOMediaWritableKey), kCFAllocatorDefault, kNilOptions);
|
||||
device->type |= CFBooleanGetValue(writable) ? FF_PHYSICALDISK_TYPE_READWRITE : FF_PHYSICALDISK_TYPE_READONLY;
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFStringRef bsdName = IORegistryEntryCreateCFProperty(entryPartition, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, kNilOptions);
|
||||
if (bsdName)
|
||||
{
|
||||
@@ -76,6 +111,9 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
|
||||
if (deviceCharacteristics)
|
||||
{
|
||||
ffCfDictGetString(deviceCharacteristics, CFSTR(kIOPropertyProductSerialNumberKey), &device->serial);
|
||||
ffStrbufTrim(&device->serial, ' ');
|
||||
ffCfDictGetString(deviceCharacteristics, CFSTR(kIOPropertyProductRevisionLevelKey), &device->revision);
|
||||
ffStrbufTrim(&device->revision, ' ');
|
||||
|
||||
CFStringRef mediumType = (CFStringRef) CFDictionaryGetValue(deviceCharacteristics, CFSTR(kIOPropertyMediumTypeKey));
|
||||
if (mediumType)
|
||||
@@ -86,6 +124,13 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
|
||||
device->type |= FF_PHYSICALDISK_TYPE_HDD;
|
||||
}
|
||||
}
|
||||
|
||||
if (options->temp)
|
||||
{
|
||||
FF_CFTYPE_AUTO_RELEASE CFBooleanRef nvmeSMARTCapable = IORegistryEntryCreateCFProperty(entryPhysical, CFSTR(kIOPropertyNVMeSMARTCapableKey), kCFAllocatorDefault, kNilOptions);
|
||||
if (nvmeSMARTCapable && CFBooleanGetValue(nvmeSMARTCapable))
|
||||
detectSsdTemp(entryPhysical, &device->temperature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,10 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
|
||||
if (provider->lg_geom->lg_rank != 1)
|
||||
continue;
|
||||
|
||||
// Should memory disk (MD) be considered as physical disk?
|
||||
//if (!ffStrEquals(provider->lg_geom->lg_class->lg_name, "DISK"))
|
||||
// continue;
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY name = ffStrbufCreateS(provider->lg_name);
|
||||
FF_STRBUF_AUTO_DESTROY identifier = ffStrbufCreate();
|
||||
FFPhysicalDiskType type = FF_PHYSICALDISK_TYPE_NONE;
|
||||
@@ -43,6 +47,13 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
|
||||
type |= ffStrEquals(ptr->lg_val, "0") ? FF_PHYSICALDISK_TYPE_SSD : FF_PHYSICALDISK_TYPE_HDD;
|
||||
else if (ffStrEquals(ptr->lg_name, "ident"))
|
||||
ffStrbufSetS(&identifier, ptr->lg_val);
|
||||
else if (ffStrEquals(ptr->lg_name, "access"))
|
||||
{
|
||||
if (ffStrEquals(ptr->lg_val, "read-only"))
|
||||
type |= FF_PHYSICALDISK_TYPE_READONLY;
|
||||
else if (ffStrEquals(ptr->lg_val, "read-write"))
|
||||
type |= FF_PHYSICALDISK_TYPE_READWRITE;
|
||||
}
|
||||
}
|
||||
|
||||
if (options->namePrefix.length && !ffStrbufStartsWith(&name, &options->namePrefix))
|
||||
@@ -51,16 +62,29 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
|
||||
FFPhysicalDiskResult* device = (FFPhysicalDiskResult*) ffListAdd(result);
|
||||
ffStrbufInitF(&device->devPath, "/dev/%s", provider->lg_name);
|
||||
ffStrbufInitMove(&device->serial, &identifier);
|
||||
ffStrbufInit(&device->revision);
|
||||
ffStrbufInit(&device->interconnect);
|
||||
switch (snapIter->device_type & DEVSTAT_TYPE_IF_MASK)
|
||||
{
|
||||
case DEVSTAT_TYPE_IF_SCSI: ffStrbufAppendS(&device->interconnect, "SCSI"); break;
|
||||
case DEVSTAT_TYPE_IF_IDE: ffStrbufAppendS(&device->interconnect, "IDE"); break;
|
||||
case DEVSTAT_TYPE_IF_OTHER: ffStrbufAppendS(&device->interconnect, "OTHER"); break;
|
||||
|
||||
// https://github.com/freebsd/freebsd-src/commit/d282baddb0b029ca8466d23ac51e95c918442535
|
||||
case 0x040 /*DEVSTAT_TYPE_IF_NVME*/: ffStrbufAppendS(&device->interconnect, "NVMe"); break;
|
||||
}
|
||||
device->size = (uint64_t) provider->lg_mediasize;
|
||||
ffStrbufInitMove(&device->name, &name);
|
||||
|
||||
if (!(device->type & FF_PHYSICALDISK_TYPE_READONLY) && !(device->type & FF_PHYSICALDISK_TYPE_READWRITE))
|
||||
{
|
||||
int acr = 1, acw = 1; // Number of partitions mounted for reading or writing
|
||||
if (sscanf(provider->lg_mode, "r%dw%de%*d", &acr, &acw) == 2 && acr)
|
||||
type |= acw ? FF_PHYSICALDISK_TYPE_READWRITE : FF_PHYSICALDISK_TYPE_READONLY;
|
||||
}
|
||||
|
||||
device->type = type;
|
||||
device->temperature = FF_PHYSICALDISK_TEMP_UNSET;
|
||||
}
|
||||
|
||||
geom_stats_snapshot_free(snap);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "physicaldisk.h"
|
||||
#include "common/io/io.h"
|
||||
#include "common/properties.h"
|
||||
#include "detection/temps/temps_linux.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#include <ctype.h>
|
||||
@@ -42,16 +43,37 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
|
||||
|
||||
{
|
||||
snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/vendor", devName);
|
||||
ffAppendFileBuffer(pathSysBlock, &device->name);
|
||||
if (device->name.length > 0)
|
||||
ffStrbufAppendC(&device->name, ' ');
|
||||
if (ffAppendFileBuffer(pathSysBlock, &device->name))
|
||||
{
|
||||
ffStrbufTrimRightSpace(&device->name);
|
||||
if (device->name.length > 0)
|
||||
ffStrbufAppendC(&device->name, ' ');
|
||||
}
|
||||
|
||||
snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/model", devName);
|
||||
ffAppendFileBuffer(pathSysBlock, &device->name);
|
||||
ffStrbufTrim(&device->name, ' ');
|
||||
ffStrbufTrimRightSpace(&device->name);
|
||||
|
||||
if (device->name.length == 0)
|
||||
ffStrbufSetS(&device->name, devName);
|
||||
else if (ffStrStartsWith(devName, "nvme"))
|
||||
{
|
||||
int devid, nsid;
|
||||
if (sscanf(devName, "nvme%dn%d", &devid, &nsid) == 2)
|
||||
{
|
||||
bool multiNs = nsid > 1;
|
||||
if (!multiNs)
|
||||
{
|
||||
snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/nvme%dn2", devName, devid);
|
||||
multiNs = ffPathExists(pathSysBlock, FF_PATHTYPE_DIRECTORY);
|
||||
}
|
||||
if (multiNs)
|
||||
{
|
||||
// In Asahi Linux, there are multiple namespaces for the same NVMe drive.
|
||||
ffStrbufAppendF(&device->name, " - %d", nsid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (options->namePrefix.length && !ffStrbufStartsWith(&device->name, &options->namePrefix))
|
||||
{
|
||||
@@ -66,16 +88,18 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
|
||||
{
|
||||
ffStrbufInit(&device->interconnect);
|
||||
if (strstr(pathSysDeviceReal, "/usb") != NULL)
|
||||
ffStrbufSetS(&device->interconnect, "usb");
|
||||
ffStrbufSetS(&device->interconnect, "USB");
|
||||
else if (strstr(pathSysDeviceReal, "/nvme") != NULL)
|
||||
ffStrbufSetS(&device->interconnect, "NVMe");
|
||||
else if (strstr(pathSysDeviceReal, "/ata") != NULL)
|
||||
ffStrbufSetS(&device->interconnect, "ATA");
|
||||
else if (strstr(pathSysDeviceReal, "/scsi") != NULL)
|
||||
ffStrbufSetS(&device->interconnect, "SCSI");
|
||||
else
|
||||
{
|
||||
snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/transport", devName);
|
||||
if (!ffAppendFileBuffer(pathSysBlock, &device->interconnect))
|
||||
{
|
||||
snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/uevent", devName);
|
||||
if (ffParsePropFile(pathSysBlock, "DEVTYPE=", &device->interconnect))
|
||||
ffStrbufSubstrBeforeLastC(&device->interconnect, '_');
|
||||
}
|
||||
if (ffAppendFileBuffer(pathSysBlock, &device->interconnect))
|
||||
ffStrbufTrimRightSpace(&device->interconnect);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,10 +130,40 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
|
||||
device->type |= removableChar == '1' ? FF_PHYSICALDISK_TYPE_REMOVABLE : FF_PHYSICALDISK_TYPE_FIXED;
|
||||
}
|
||||
|
||||
{
|
||||
char roChar = '0';
|
||||
snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/ro", devName);
|
||||
if (ffReadFileData(pathSysBlock, 1, &roChar) > 0)
|
||||
device->type |= roChar == '1' ? FF_PHYSICALDISK_TYPE_READONLY : FF_PHYSICALDISK_TYPE_READWRITE;
|
||||
}
|
||||
|
||||
{
|
||||
ffStrbufInit(&device->serial);
|
||||
snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/serial", devName);
|
||||
ffReadFileBuffer(pathSysBlock, &device->serial);
|
||||
if (ffReadFileBuffer(pathSysBlock, &device->serial))
|
||||
ffStrbufTrimRightSpace(&device->serial);
|
||||
}
|
||||
|
||||
{
|
||||
ffStrbufInit(&device->revision);
|
||||
snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/firmware_rev", devName);
|
||||
if (ffReadFileBuffer(pathSysBlock, &device->revision))
|
||||
ffStrbufTrimRightSpace(&device->revision);
|
||||
}
|
||||
|
||||
device->temperature = FF_PHYSICALDISK_TEMP_UNSET;
|
||||
if (options->temp)
|
||||
{
|
||||
const FFlist* tempsResult = ffDetectTemps();
|
||||
|
||||
FF_LIST_FOR_EACH(FFTempValue, value, *tempsResult)
|
||||
{
|
||||
if (ffStrStartsWith(devName, value->deviceName.chars)) // nvme0 - nvme0n1
|
||||
{
|
||||
device->temperature = value->value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,97 +5,102 @@
|
||||
#include <windows.h>
|
||||
#include <winioctl.h>
|
||||
|
||||
const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
|
||||
static bool detectPhysicalDisk(const wchar_t* szDevice, FFlist* result, FFPhysicalDiskOptions* options)
|
||||
{
|
||||
wchar_t szDevice[32] = L"\\\\.\\PhysicalDrive";
|
||||
wchar_t* pNum = szDevice + strlen("\\\\.\\PhysicalDrive");
|
||||
for (uint32_t idev = 0; ; ++idev)
|
||||
FF_AUTO_CLOSE_FD HANDLE hDevice = CreateFileW(szDevice, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (hDevice == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
DWORD retSize;
|
||||
char sddBuffer[4096];
|
||||
if(!DeviceIoControl(
|
||||
hDevice,
|
||||
IOCTL_STORAGE_QUERY_PROPERTY,
|
||||
&(STORAGE_PROPERTY_QUERY) {
|
||||
.PropertyId = StorageDeviceProperty,
|
||||
.QueryType = PropertyStandardQuery,
|
||||
},
|
||||
sizeof(STORAGE_PROPERTY_QUERY),
|
||||
&sddBuffer,
|
||||
sizeof(sddBuffer),
|
||||
&retSize,
|
||||
NULL
|
||||
) || retSize == 0)
|
||||
return true;
|
||||
|
||||
FFPhysicalDiskResult* device = (FFPhysicalDiskResult*) ffListAdd(result);
|
||||
device->type = FF_PHYSICALDISK_TYPE_NONE;
|
||||
STORAGE_DEVICE_DESCRIPTOR* sdd = (STORAGE_DEVICE_DESCRIPTOR*) sddBuffer;
|
||||
|
||||
ffStrbufInit(&device->name);
|
||||
if (sdd->VendorIdOffset != 0)
|
||||
{
|
||||
_ultow(idev, pNum, 10);
|
||||
ffStrbufSetS(&device->name, (const char*) sddBuffer + sdd->VendorIdOffset);
|
||||
ffStrbufTrim(&device->name, ' ');
|
||||
}
|
||||
if (sdd->ProductIdOffset != 0)
|
||||
{
|
||||
if (device->name.length)
|
||||
ffStrbufAppendC(&device->name, ' ');
|
||||
|
||||
FF_AUTO_CLOSE_FD HANDLE hDevice = CreateFileW(szDevice, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (hDevice == INVALID_HANDLE_VALUE)
|
||||
break;
|
||||
ffStrbufAppendS(&device->name, (const char*) sddBuffer + sdd->ProductIdOffset);
|
||||
ffStrbufTrimRight(&device->name, ' ');
|
||||
}
|
||||
|
||||
DWORD retSize;
|
||||
char sddBuffer[4096];
|
||||
if(!DeviceIoControl(
|
||||
hDevice,
|
||||
IOCTL_STORAGE_QUERY_PROPERTY,
|
||||
&(STORAGE_PROPERTY_QUERY) {
|
||||
.PropertyId = StorageDeviceProperty,
|
||||
.QueryType = PropertyStandardQuery,
|
||||
},
|
||||
sizeof(STORAGE_PROPERTY_QUERY),
|
||||
&sddBuffer,
|
||||
sizeof(sddBuffer),
|
||||
&retSize,
|
||||
NULL
|
||||
) || retSize == 0)
|
||||
continue;
|
||||
if (!device->name.length)
|
||||
ffStrbufSetWS(&device->name, szDevice);
|
||||
|
||||
FFPhysicalDiskResult* device = (FFPhysicalDiskResult*) ffListAdd(result);
|
||||
device->type = FF_PHYSICALDISK_TYPE_NONE;
|
||||
STORAGE_DEVICE_DESCRIPTOR* sdd = (STORAGE_DEVICE_DESCRIPTOR*) sddBuffer;
|
||||
if (options->namePrefix.length && !ffStrbufStartsWith(&device->name, &options->namePrefix))
|
||||
{
|
||||
ffStrbufDestroy(&device->name);
|
||||
result->length--;
|
||||
return true;
|
||||
}
|
||||
|
||||
ffStrbufInit(&device->name);
|
||||
if (sdd->VendorIdOffset != 0)
|
||||
{
|
||||
ffStrbufSetS(&device->name, (const char*) sddBuffer + sdd->VendorIdOffset);
|
||||
ffStrbufTrim(&device->name, ' ');
|
||||
}
|
||||
if (sdd->ProductIdOffset != 0)
|
||||
{
|
||||
if (device->name.length)
|
||||
ffStrbufAppendC(&device->name, ' ');
|
||||
ffStrbufInitWS(&device->devPath, szDevice);
|
||||
ffStrbufInit(&device->serial);
|
||||
if (sdd->SerialNumberOffset != 0)
|
||||
{
|
||||
ffStrbufSetS(&device->serial, (const char*) sddBuffer + sdd->SerialNumberOffset);
|
||||
ffStrbufTrim(&device->serial, ' ');
|
||||
}
|
||||
|
||||
ffStrbufAppendS(&device->name, (const char*) sddBuffer + sdd->ProductIdOffset);
|
||||
ffStrbufTrimRight(&device->name, ' ');
|
||||
}
|
||||
ffStrbufInit(&device->revision);
|
||||
if (sdd->ProductRevisionOffset != 0)
|
||||
{
|
||||
ffStrbufSetS(&device->revision, (const char*) sddBuffer + sdd->ProductRevisionOffset);
|
||||
ffStrbufTrim(&device->revision, ' ');
|
||||
}
|
||||
|
||||
if (options->namePrefix.length && !ffStrbufStartsWith(&device->name, &options->namePrefix))
|
||||
{
|
||||
ffStrbufDestroy(&device->name);
|
||||
result->length--;
|
||||
continue;
|
||||
}
|
||||
device->type |= sdd->RemovableMedia ? FF_PHYSICALDISK_TYPE_REMOVABLE : FF_PHYSICALDISK_TYPE_FIXED;
|
||||
|
||||
ffStrbufInitWS(&device->devPath, szDevice);
|
||||
ffStrbufInit(&device->serial);
|
||||
if (sdd->SerialNumberOffset != 0)
|
||||
{
|
||||
ffStrbufSetS(&device->serial, (const char*) sddBuffer + sdd->SerialNumberOffset);
|
||||
ffStrbufTrim(&device->serial, ' ');
|
||||
}
|
||||
|
||||
device->type |= sdd->RemovableMedia ? FF_PHYSICALDISK_TYPE_REMOVABLE : FF_PHYSICALDISK_TYPE_FIXED;
|
||||
|
||||
ffStrbufInit(&device->interconnect);
|
||||
switch (sdd->BusType)
|
||||
{
|
||||
case BusTypeUnknown: ffStrbufSetStatic(&device->interconnect, "Unknown"); break;
|
||||
case BusTypeScsi: ffStrbufSetStatic(&device->interconnect, "Scsi"); break;
|
||||
case BusTypeAtapi: ffStrbufSetStatic(&device->interconnect, "Atapi"); break;
|
||||
case BusTypeAta: ffStrbufSetStatic(&device->interconnect, "Ata"); break;
|
||||
case BusType1394: ffStrbufSetStatic(&device->interconnect, "1394"); break;
|
||||
case BusTypeSsa: ffStrbufSetStatic(&device->interconnect, "Ssa"); break;
|
||||
case BusTypeFibre: ffStrbufSetStatic(&device->interconnect, "Fibra"); break;
|
||||
case BusTypeUsb: ffStrbufSetStatic(&device->interconnect, "Usb"); break;
|
||||
case BusTypeRAID: ffStrbufSetStatic(&device->interconnect, "RAID"); break;
|
||||
case BusTypeiScsi: ffStrbufSetStatic(&device->interconnect, "iScsi"); break;
|
||||
case BusTypeSas: ffStrbufSetStatic(&device->interconnect, "Sas"); break;
|
||||
case BusTypeSata: ffStrbufSetStatic(&device->interconnect, "Sata"); break;
|
||||
case BusTypeSd: ffStrbufSetStatic(&device->interconnect, "Sd"); break;
|
||||
case BusTypeMmc: ffStrbufSetStatic(&device->interconnect, "Mmc"); break;
|
||||
case BusTypeVirtual: ffStrbufSetStatic(&device->interconnect, "Virtual"); break;
|
||||
case BusTypeFileBackedVirtual: ffStrbufSetStatic(&device->interconnect, "FileBackedVirtual"); break;
|
||||
case BusTypeSpaces: ffStrbufSetStatic(&device->interconnect, "Spaces"); break;
|
||||
case BusTypeNvme: ffStrbufSetStatic(&device->interconnect, "Nvme"); break;
|
||||
case BusTypeSCM: ffStrbufSetStatic(&device->interconnect, "SCM"); break;
|
||||
case BusTypeUfs: ffStrbufSetStatic(&device->interconnect, "Ufs"); break;
|
||||
default: ffStrbufSetF(&device->interconnect, "Unknown (%d)", (int) sdd->BusType); break;
|
||||
}
|
||||
ffStrbufInit(&device->interconnect);
|
||||
switch (sdd->BusType)
|
||||
{
|
||||
case BusTypeUnknown: ffStrbufSetStatic(&device->interconnect, "Unknown"); break;
|
||||
case BusTypeScsi: ffStrbufSetStatic(&device->interconnect, "SCSI"); break;
|
||||
case BusTypeAtapi: ffStrbufSetStatic(&device->interconnect, "ATAPI"); break;
|
||||
case BusTypeAta: ffStrbufSetStatic(&device->interconnect, "ATA"); break;
|
||||
case BusType1394: ffStrbufSetStatic(&device->interconnect, "1394"); break;
|
||||
case BusTypeSsa: ffStrbufSetStatic(&device->interconnect, "SSA"); break;
|
||||
case BusTypeFibre: ffStrbufSetStatic(&device->interconnect, "Fibre"); break;
|
||||
case BusTypeUsb: ffStrbufSetStatic(&device->interconnect, "USB"); break;
|
||||
case BusTypeRAID: ffStrbufSetStatic(&device->interconnect, "RAID"); break;
|
||||
case BusTypeiScsi: ffStrbufSetStatic(&device->interconnect, "iSCSI"); break;
|
||||
case BusTypeSas: ffStrbufSetStatic(&device->interconnect, "SAS"); break;
|
||||
case BusTypeSata: ffStrbufSetStatic(&device->interconnect, "SATA"); break;
|
||||
case BusTypeSd: ffStrbufSetStatic(&device->interconnect, "SD"); break;
|
||||
case BusTypeMmc: ffStrbufSetStatic(&device->interconnect, "MMC"); break;
|
||||
case BusTypeVirtual: ffStrbufSetStatic(&device->interconnect, "Virtual"); break;
|
||||
case BusTypeFileBackedVirtual: ffStrbufSetStatic(&device->interconnect, "File Backed Virtual"); break;
|
||||
case BusTypeSpaces: ffStrbufSetStatic(&device->interconnect, "Spaces"); break;
|
||||
case BusTypeNvme: ffStrbufSetStatic(&device->interconnect, "NVMe"); break;
|
||||
case BusTypeSCM: ffStrbufSetStatic(&device->interconnect, "SCM"); break;
|
||||
case BusTypeUfs: ffStrbufSetStatic(&device->interconnect, "UFS"); break;
|
||||
default: ffStrbufSetF(&device->interconnect, "Unknown (%d)", (int) sdd->BusType); break;
|
||||
}
|
||||
|
||||
{
|
||||
DEVICE_SEEK_PENALTY_DESCRIPTOR dspd = {};
|
||||
if(DeviceIoControl(
|
||||
hDevice,
|
||||
@@ -111,7 +116,9 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
|
||||
NULL
|
||||
) && retSize == sizeof(dspd))
|
||||
device->type |= dspd.IncursSeekPenalty ? FF_PHYSICALDISK_TYPE_HDD : FF_PHYSICALDISK_TYPE_SSD;
|
||||
}
|
||||
|
||||
{
|
||||
DISK_GEOMETRY_EX dge = {};
|
||||
if(DeviceIoControl(
|
||||
hDevice,
|
||||
@@ -127,5 +134,90 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
|
||||
device->size = 0;
|
||||
}
|
||||
|
||||
{
|
||||
uint8_t buffer[sizeof(GET_MEDIA_TYPES) + sizeof(DEVICE_MEDIA_INFO) * 7] = "";
|
||||
GET_MEDIA_TYPES* gmt = (GET_MEDIA_TYPES*) buffer;
|
||||
if(DeviceIoControl(
|
||||
hDevice,
|
||||
IOCTL_STORAGE_GET_MEDIA_TYPES_EX,
|
||||
NULL,
|
||||
0,
|
||||
gmt,
|
||||
sizeof(buffer),
|
||||
&retSize,
|
||||
NULL) && gmt->MediaInfoCount > 0
|
||||
)
|
||||
{
|
||||
// DiskInfo and RemovableDiskInfo have the same structures. TapeInfo doesn't.
|
||||
if (gmt->DeviceType != FILE_DEVICE_TAPE)
|
||||
{
|
||||
__typeof__(gmt->MediaInfo[0].DeviceSpecific.DiskInfo)* diskInfo = &gmt->MediaInfo[0].DeviceSpecific.DiskInfo;
|
||||
if (diskInfo->MediaCharacteristics & MEDIA_READ_ONLY)
|
||||
device->type |= FF_PHYSICALDISK_TYPE_READONLY;
|
||||
else if (diskInfo->MediaCharacteristics & MEDIA_READ_WRITE)
|
||||
device->type |= FF_PHYSICALDISK_TYPE_READWRITE;
|
||||
if (device->size == 0)
|
||||
device->size = (uint64_t) diskInfo->NumberMediaSides * diskInfo->TracksPerCylinder * diskInfo->SectorsPerTrack * diskInfo->BytesPerSector;
|
||||
}
|
||||
else
|
||||
{
|
||||
__typeof__(gmt->MediaInfo[0].DeviceSpecific.TapeInfo)* tapeInfo = &gmt->MediaInfo[0].DeviceSpecific.TapeInfo;
|
||||
if (tapeInfo->MediaCharacteristics & MEDIA_READ_ONLY)
|
||||
device->type |= FF_PHYSICALDISK_TYPE_READONLY;
|
||||
else if (tapeInfo->MediaCharacteristics & MEDIA_READ_WRITE)
|
||||
device->type |= FF_PHYSICALDISK_TYPE_READWRITE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
device->temperature = FF_PHYSICALDISK_TEMP_UNSET;
|
||||
if (options->temp)
|
||||
{
|
||||
STORAGE_TEMPERATURE_DATA_DESCRIPTOR stdd = {};
|
||||
if(DeviceIoControl(
|
||||
hDevice,
|
||||
IOCTL_STORAGE_QUERY_PROPERTY,
|
||||
&(STORAGE_PROPERTY_QUERY) {
|
||||
.PropertyId = StorageDeviceTemperatureProperty,
|
||||
.QueryType = PropertyStandardQuery,
|
||||
},
|
||||
sizeof(STORAGE_PROPERTY_QUERY),
|
||||
&stdd,
|
||||
sizeof(stdd),
|
||||
&retSize,
|
||||
NULL
|
||||
) && retSize == sizeof(stdd))
|
||||
device->temperature = stdd.TemperatureInfo[0].Temperature;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
|
||||
{
|
||||
{
|
||||
wchar_t szPhysicalDrive[32] = L"\\\\.\\PhysicalDrive";
|
||||
wchar_t* pNum = szPhysicalDrive + strlen("\\\\.\\PhysicalDrive");
|
||||
for (uint32_t idev = 0; ; ++idev)
|
||||
{
|
||||
_ultow(idev, pNum, 10);
|
||||
|
||||
if (!detectPhysicalDisk(szPhysicalDrive, result, options))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
wchar_t szCdrom[32] = L"\\\\.\\CDROM";
|
||||
wchar_t* pNum = szCdrom + strlen("\\\\.\\CDROM");
|
||||
for (uint32_t idev = 0; ; ++idev)
|
||||
{
|
||||
_ultow(idev, pNum, 10);
|
||||
|
||||
if (!detectPhysicalDisk(szCdrom, result, options))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -287,7 +287,7 @@ static bool detectTemp(io_connect_t conn, const char *sensor, double* sum)
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *ffDetectCoreTemps(enum FFTempType type, double *result)
|
||||
const char *ffDetectSmcTemps(enum FFTempType type, double *result)
|
||||
{
|
||||
static io_connect_t conn;
|
||||
static dispatch_once_t once_control;
|
||||
@@ -323,14 +323,19 @@ const char *ffDetectCoreTemps(enum FFTempType type, double *result)
|
||||
break;
|
||||
|
||||
case FF_TEMP_CPU_M2X:
|
||||
count += detectTemp(conn, "Tp0A", result); // CPU core 1
|
||||
count += detectTemp(conn, "Tp0D", result); // CPU core 2
|
||||
count += detectTemp(conn, "Tp0E", result); // CPU core 3
|
||||
count += detectTemp(conn, "Tp01", result); // CPU core 4
|
||||
count += detectTemp(conn, "Tp02", result); // CPU core 5
|
||||
count += detectTemp(conn, "Tp05", result); // CPU core 6
|
||||
count += detectTemp(conn, "Tp06", result); // CPU core 7
|
||||
count += detectTemp(conn, "Tp09", result); // CPU core 8
|
||||
count += detectTemp(conn, "Tp1h", result); // CPU efficiency core 1
|
||||
count += detectTemp(conn, "Tp1t", result); // CPU efficiency core 2
|
||||
count += detectTemp(conn, "Tp1p", result); // CPU efficiency core 3
|
||||
count += detectTemp(conn, "Tp1l", result); // CPU efficiency core 4
|
||||
|
||||
count += detectTemp(conn, "Tp01", result); // CPU performance core 1
|
||||
count += detectTemp(conn, "Tp05", result); // CPU performance core 2
|
||||
count += detectTemp(conn, "Tp09", result); // CPU performance core 3
|
||||
count += detectTemp(conn, "Tp0D", result); // CPU performance core 4
|
||||
count += detectTemp(conn, "Tp0X", result); // CPU performance core 5
|
||||
count += detectTemp(conn, "Tp0b", result); // CPU performance core 6
|
||||
count += detectTemp(conn, "Tp0f", result); // CPU performance core 7
|
||||
count += detectTemp(conn, "Tp0j", result); // CPU performance core 8
|
||||
break;
|
||||
|
||||
case FF_TEMP_CPU_M3X:
|
||||
|
||||
@@ -29,4 +29,4 @@ enum FFTempType
|
||||
FF_TEMP_MEMORY,
|
||||
};
|
||||
|
||||
const char *ffDetectCoreTemps(enum FFTempType type, double* result);
|
||||
const char *ffDetectSmcTemps(enum FFTempType type, double* result);
|
||||
|
||||
@@ -26,6 +26,7 @@ static bool parseHwmonDir(FFstrbuf* dir, FFTempValue* value)
|
||||
|
||||
ffStrbufAppendS(dir, "name");
|
||||
ffReadFileBuffer(dir->chars, &value->name);
|
||||
ffStrbufTrimRightSpace(&value->name);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
|
||||
ffStrbufAppendS(dir, "device/class");
|
||||
@@ -35,9 +36,25 @@ static bool parseHwmonDir(FFstrbuf* dir, FFTempValue* value)
|
||||
ffStrbufAppendS(dir, "device/device/class");
|
||||
ffReadFileBuffer(dir->chars, &valueBuffer);
|
||||
}
|
||||
ffStrbufTrimRightSpace(&valueBuffer);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
if(valueBuffer.length)
|
||||
value->deviceClass = (uint32_t) strtoul(valueBuffer.chars, NULL, 16);
|
||||
|
||||
ffStrbufClear(&valueBuffer);
|
||||
ffStrbufEnsureFree(&valueBuffer, 64);
|
||||
ffStrbufAppendS(dir, "device");
|
||||
ssize_t linkLen = readlink(dir->chars, valueBuffer.chars, valueBuffer.allocated - 1);
|
||||
if (linkLen > 0)
|
||||
{
|
||||
valueBuffer.length = (uint32_t) linkLen;
|
||||
valueBuffer.chars[linkLen] = 0;
|
||||
ffStrbufSubstrAfterLastC(&valueBuffer, '/');
|
||||
ffStrbufInitMove(&value->deviceName, &valueBuffer);
|
||||
}
|
||||
else
|
||||
ffStrbufInit(&value->deviceName);
|
||||
|
||||
return value->name.length > 0 || value->deviceClass > 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
typedef struct FFTempValue
|
||||
{
|
||||
FFstrbuf name;
|
||||
FFstrbuf deviceName;
|
||||
uint32_t deviceClass;
|
||||
double value;
|
||||
} FFTempValue;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "terminalfont.h"
|
||||
#include "common/properties.h"
|
||||
#include "common/processing.h"
|
||||
#include "detection/internal.h"
|
||||
#include "detection/terminalshell/terminalshell.h"
|
||||
|
||||
static void detectAlacritty(FFTerminalFontResult* terminalFont)
|
||||
|
||||
@@ -172,10 +172,9 @@ static void detectDeepinTerminal(FFTerminalFontResult* terminalFont)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY fontName = ffStrbufCreate();
|
||||
FF_STRBUF_AUTO_DESTROY fontSize = ffStrbufCreate();
|
||||
FF_STRBUF_AUTO_DESTROY profile = ffStrbufCreate();
|
||||
|
||||
ffStrbufAppend(&profile, &instance.state.platform.homeDir);
|
||||
ffStrbufAppendS(&profile, ".config/deepin/deepin-terminal/config.conf"); //TODO: Use config dirs
|
||||
FF_STRBUF_AUTO_DESTROY profile = ffStrbufCreateA(64);
|
||||
ffSearchUserConfigFile(&instance.state.platform.configDirs, "deepin/deepin-terminal/config.conf", &profile);
|
||||
FILE* file = fopen(profile.chars, "r");
|
||||
|
||||
if(file)
|
||||
|
||||
@@ -37,6 +37,7 @@ static void getProcessInformation(pid_t pid, FFstrbuf* processName, FFstrbuf* ex
|
||||
|
||||
if(ffAppendFileBuffer(cmdlineFilePath, exe))
|
||||
{
|
||||
ffStrbufTrimRightSpace(exe);
|
||||
ffStrbufSubstrBeforeFirstC(exe, '\0'); //Trim the arguments
|
||||
ffStrbufTrimLeft(exe, '-'); //Happens in TTY
|
||||
}
|
||||
@@ -180,7 +181,7 @@ static void getTerminalShell(FFTerminalShellResult* result, pid_t pid)
|
||||
|
||||
#ifdef __APPLE__
|
||||
// https://github.com/fastfetch-cli/fastfetch/discussions/501
|
||||
if (ffStrEndsWith(name, " (figterm)"))
|
||||
if (ffStrEndsWith(name, " (figterm)") || ffStrEndsWith(name, " (cwterm)"))
|
||||
getProcessNameAndPpid(ppid, name, &ppid);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -141,10 +141,14 @@ static const char* detectVulkan(FFVulkanResult* result)
|
||||
else
|
||||
ffvkGetPhysicalDeviceProperties(physicalDevices[i], &physicalDeviceProperties.properties);
|
||||
|
||||
|
||||
//We don't want software rasterizers to show up as physical gpu
|
||||
if(physicalDeviceProperties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU)
|
||||
continue;
|
||||
|
||||
//If the device api version is higher than the current highest device api version, overwrite it
|
||||
//In this case, also use the current device driver name as the shown driver name
|
||||
|
||||
|
||||
FFVersion deviceAPIVersion = FF_VERSION_INIT;
|
||||
applyVulkanVersion(physicalDeviceProperties.properties.apiVersion, &deviceAPIVersion);
|
||||
if(ffVersionCompare(&deviceAPIVersion, &maxDeviceApiVersion) > 0)
|
||||
@@ -168,20 +172,17 @@ static const char* detectVulkan(FFVulkanResult* result)
|
||||
|
||||
//Add the device to the list of devices shown by the GPU module
|
||||
|
||||
//We don't want software rasterizers to show up as physical gpu
|
||||
if(physicalDeviceProperties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU)
|
||||
continue;
|
||||
|
||||
// #456
|
||||
FF_LIST_FOR_EACH(FFGPUResult, gpu, result->gpus)
|
||||
{
|
||||
if (gpu->vulkanDeviceId == physicalDeviceProperties.properties.deviceID)
|
||||
if (gpu->deviceId == physicalDeviceProperties.properties.deviceID)
|
||||
goto next;
|
||||
}
|
||||
|
||||
FFGPUResult* gpu = ffListAdd(&result->gpus);
|
||||
|
||||
gpu->vulkanDeviceId = physicalDeviceProperties.properties.deviceID;
|
||||
ffStrbufInitF(&gpu->platformApi, "Vulkan %u.%u.%u", deviceAPIVersion.major, deviceAPIVersion.minor, deviceAPIVersion.patch);
|
||||
gpu->deviceId = physicalDeviceProperties.properties.deviceID;
|
||||
|
||||
ffStrbufInitS(&gpu->name, physicalDeviceProperties.properties.deviceName);
|
||||
|
||||
@@ -204,6 +205,7 @@ static const char* detectVulkan(FFVulkanResult* result)
|
||||
//No way to detect those using vulkan
|
||||
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
|
||||
gpu->temperature = FF_GPU_TEMP_UNSET;
|
||||
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
|
||||
|
||||
next:
|
||||
continue;
|
||||
@@ -228,22 +230,20 @@ static const char* detectVulkan(FFVulkanResult* result)
|
||||
FFVulkanResult* ffDetectVulkan(void)
|
||||
{
|
||||
static FFVulkanResult result;
|
||||
static bool init = false;
|
||||
|
||||
if(init)
|
||||
return &result;
|
||||
init = true;
|
||||
if (result.gpus.elementSize == 0)
|
||||
{
|
||||
ffStrbufInit(&result.driver);
|
||||
ffStrbufInit(&result.apiVersion);
|
||||
ffStrbufInit(&result.conformanceVersion);
|
||||
ffListInit(&result.gpus, sizeof(FFGPUResult));
|
||||
|
||||
ffStrbufInit(&result.driver);
|
||||
ffStrbufInit(&result.apiVersion);
|
||||
ffStrbufInit(&result.conformanceVersion);
|
||||
ffListInit(&result.gpus, sizeof(FFGPUResult));
|
||||
|
||||
#ifdef FF_HAVE_VULKAN
|
||||
result.error = detectVulkan(&result);
|
||||
#else
|
||||
result.error = "fastfetch was compiled without vulkan support";
|
||||
#endif
|
||||
#ifdef FF_HAVE_VULKAN
|
||||
result.error = detectVulkan(&result);
|
||||
#else
|
||||
result.error = "fastfetch was compiled without vulkan support";
|
||||
#endif
|
||||
}
|
||||
|
||||
return &result;
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ const char* ffDetectWifi(FFlist* result)
|
||||
NSDictionary* authType = [apple valueForKey:@"AUTH_TYPE"];
|
||||
if (authType)
|
||||
{
|
||||
if ([[authType valueForKey:@"AUTH_LOWER"] intValue] != 1) break; // APPLE80211_AUTH_TYPE_UNICAST?
|
||||
// AUTH_LOWER seems useless. `airport` verifies if its value is between 1 and 3, and prints `unknown` if not
|
||||
|
||||
NSNumber* authUpper = [authType valueForKey:@"AUTH_UPPER"];
|
||||
if (!authUpper)
|
||||
@@ -167,14 +167,38 @@ const char* ffDetectWifi(FFlist* result)
|
||||
int authUpperValue = [authUpper intValue];
|
||||
switch (authUpperValue)
|
||||
{
|
||||
case 4096:
|
||||
ffStrbufSetStatic(&item->conn.security, "WPA3-SAE");
|
||||
case 1:
|
||||
ffStrbufSetStatic(&item->conn.security, "WPA");
|
||||
break;
|
||||
case 2:
|
||||
ffStrbufSetStatic(&item->conn.security, "WPA-PSK");
|
||||
break;
|
||||
case 4:
|
||||
ffStrbufSetStatic(&item->conn.security, "WPA2");
|
||||
break;
|
||||
case 8:
|
||||
ffStrbufSetStatic(&item->conn.security, "WPA2-PSK");
|
||||
break;
|
||||
case 4:
|
||||
ffStrbufSetStatic(&item->conn.security, "WPA2");
|
||||
case 16:
|
||||
ffStrbufSetStatic(&item->conn.security, "FT-WPA2-PSK");
|
||||
break;
|
||||
case 32:
|
||||
ffStrbufSetStatic(&item->conn.security, "LEAP");
|
||||
break;
|
||||
case 64:
|
||||
ffStrbufSetStatic(&item->conn.security, "802.1X");
|
||||
break;
|
||||
case 128:
|
||||
ffStrbufSetStatic(&item->conn.security, "FT-WPA2");
|
||||
break;
|
||||
case 256:
|
||||
ffStrbufSetStatic(&item->conn.security, "WPS");
|
||||
break;
|
||||
case 4096:
|
||||
ffStrbufSetStatic(&item->conn.security, "WPA3-SAE");
|
||||
break;
|
||||
case 8192:
|
||||
ffStrbufSetStatic(&item->conn.security, "WPA3-FT-SAE");
|
||||
break;
|
||||
default: // TODO: support more auth types
|
||||
ffStrbufAppendF(&item->conn.security, "To be supported (%d)", authUpperValue);
|
||||
|
||||
@@ -248,7 +248,7 @@ static const char* detectWifiWithIoctls(FFlist* result)
|
||||
item->conn.txRate = 0.0/0.0;
|
||||
|
||||
ffStrbufSetF(&path, "/sys/class/net/%s/operstate", i->if_name);
|
||||
if(!ffAppendFileBuffer(path.chars, &item->inf.status) || !ffStrbufEqualS(&item->inf.status, "up"))
|
||||
if (!ffAppendFileBuffer(path.chars, &item->inf.status) || !ffStrbufEqualS(&item->inf.status, "up\n"))
|
||||
continue;
|
||||
|
||||
FF_AUTO_CLOSE_FD int sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "wmtheme.h"
|
||||
#include "common/io/io.h"
|
||||
#include "common/properties.h"
|
||||
#include "common/parsing.h"
|
||||
#include "common/settings.h"
|
||||
@@ -132,60 +133,57 @@ static bool detectXFWM4(FFstrbuf* themeOrError)
|
||||
static bool detectOpenbox(const FFstrbuf* dePrettyName, FFstrbuf* themeOrError)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY absolutePath = ffStrbufCreateA(64);
|
||||
ffStrbufAppend(&absolutePath, &instance.state.platform.homeDir);
|
||||
const char *configFileSubpath = "openbox/rc.xml";
|
||||
if (ffStrbufIgnCaseCompS(dePrettyName, "LXQT") == 0)
|
||||
configFileSubpath = "openbox/lxqt-rc.xml";
|
||||
else if (ffStrbufIgnCaseCompS(dePrettyName, "LXDE") == 0)
|
||||
configFileSubpath = "openbox/lxde-rc.xml";
|
||||
|
||||
//TODO: use config dirs
|
||||
if(ffStrbufIgnCaseCompS(dePrettyName, "LXQT") == 0)
|
||||
ffStrbufAppendS(&absolutePath, ".config/openbox/lxqt-rc.xml");
|
||||
else if(ffStrbufIgnCaseCompS(dePrettyName, "LXDE") == 0)
|
||||
ffStrbufAppendS(&absolutePath, ".config/openbox/lxde-rc.xml");
|
||||
else
|
||||
ffStrbufAppendS(&absolutePath, ".config/openbox/rc.xml");
|
||||
|
||||
char* line = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
FILE* file = fopen(absolutePath.chars, "r");
|
||||
if(file == NULL)
|
||||
if (!ffSearchUserConfigFile(&instance.state.platform.configDirs, configFileSubpath, &absolutePath))
|
||||
{
|
||||
ffStrbufAppendF(themeOrError, "Couldn't open \"%s\"", absolutePath.chars);
|
||||
|
||||
ffStrbufAppendF(themeOrError, "Couldn't find config file \"%s\"", configFileSubpath);
|
||||
return false;
|
||||
}
|
||||
|
||||
while(getline(&line, &len, file) != -1)
|
||||
FF_STRBUF_AUTO_DESTROY content = ffStrbufCreate();
|
||||
if (!ffReadFileBuffer(absolutePath.chars, &content))
|
||||
{
|
||||
if(strstr(line, "<theme>") != 0)
|
||||
break;
|
||||
ffStrbufAppendF(themeOrError, "Couldn't read \"%s\"", absolutePath.chars);
|
||||
return false;
|
||||
}
|
||||
|
||||
while(getline(&line, &len, file) != -1)
|
||||
{
|
||||
if(strstr(line, "<name>") != 0)
|
||||
{
|
||||
ffStrbufAppendS(themeOrError, line);
|
||||
ffStrbufRemoveStrings(themeOrError, 2, (const char*[]) { "<name>", "</name>" });
|
||||
ffStrbufTrimRight(themeOrError, '\n');
|
||||
ffStrbufTrim(themeOrError, ' ');
|
||||
break;
|
||||
}
|
||||
const char *themeStart = strstr(content.chars, "<theme>");
|
||||
if (themeStart == NULL)
|
||||
goto theme_not_found;
|
||||
|
||||
if(strstr(line, "</theme>") != 0) // sanity check
|
||||
break;
|
||||
}
|
||||
const char *themeEnd = strstr(themeStart, "</theme>");
|
||||
if (__builtin_expect(themeEnd == NULL, false)) // very rare case
|
||||
goto theme_not_found;
|
||||
|
||||
if(line != NULL)
|
||||
free(line);
|
||||
const char *nameStart = strstr(themeStart, "<name>");
|
||||
if (nameStart == NULL)
|
||||
goto name_not_found;
|
||||
|
||||
fclose(file);
|
||||
const char *nameEnd = strstr(nameStart, "</name>");
|
||||
if (nameEnd == NULL || nameEnd > themeEnd) // (nameEnd > themeEnd) means name is not a theme's child
|
||||
goto name_not_found;
|
||||
|
||||
nameStart += strlen("<name>");
|
||||
ffStrbufAppendNS(themeOrError, (uint32_t)(nameEnd - nameStart), nameStart);
|
||||
ffStrbufTrim(themeOrError, ' ');
|
||||
|
||||
if(themeOrError->length == 0)
|
||||
{
|
||||
ffStrbufAppendF(themeOrError, "Couldn't find theme name in \"%s\"", absolutePath.chars);
|
||||
return false;
|
||||
}
|
||||
goto name_not_found;
|
||||
|
||||
return true;
|
||||
|
||||
theme_not_found:
|
||||
ffStrbufAppendF(themeOrError, "Couldn't find theme node in \"%s\"", absolutePath.chars);
|
||||
return false;
|
||||
|
||||
name_not_found:
|
||||
ffStrbufAppendF(themeOrError, "Couldn't find theme name in \"%s\"", absolutePath.chars);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffDetectWmTheme(FFstrbuf* themeOrError)
|
||||
|
||||
+11
-1
@@ -267,7 +267,7 @@ static void listConfigPaths(void)
|
||||
FF_LIST_FOR_EACH(FFstrbuf, folder, instance.state.platform.configDirs)
|
||||
{
|
||||
bool exists = false;
|
||||
uint32_t length = folder->length + sizeof("fastfetch");
|
||||
uint32_t length = folder->length + (uint32_t) strlen("fastfetch") + 1 /* trailing slash */;
|
||||
ffStrbufAppendS(folder, "fastfetch/config.jsonc");
|
||||
exists = ffPathExists(folder->chars, FF_PATHTYPE_FILE);
|
||||
if (!exists)
|
||||
@@ -501,6 +501,11 @@ static void optionParseConfigFile(FFdata* data, const char* key, const char* val
|
||||
ffStrbufAppendS(&absolutePath, value);
|
||||
|
||||
bool success = isJsonConfig ? parseJsoncFile(absolutePath.chars) : parseConfigFile(data, absolutePath.chars);
|
||||
if (!success)
|
||||
{
|
||||
ffStrbufAppendS(&absolutePath, ".jsonc");
|
||||
success = parseJsoncFile(absolutePath.chars);
|
||||
}
|
||||
|
||||
if(success)
|
||||
return;
|
||||
@@ -514,6 +519,11 @@ static void optionParseConfigFile(FFdata* data, const char* key, const char* val
|
||||
ffStrbufAppendS(&absolutePath, value);
|
||||
|
||||
bool success = isJsonConfig ? parseJsoncFile(absolutePath.chars) : parseConfigFile(data, absolutePath.chars);
|
||||
if (!success)
|
||||
{
|
||||
ffStrbufAppendS(&absolutePath, ".jsonc");
|
||||
success = parseJsoncFile(absolutePath.chars);
|
||||
}
|
||||
|
||||
if(success)
|
||||
return;
|
||||
|
||||
@@ -258,7 +258,7 @@ void ffInitBatteryOptions(FFBatteryOptions* options)
|
||||
options->temp = false;
|
||||
|
||||
#ifdef __linux__
|
||||
ffStrbufInit(&options->dir);
|
||||
ffStrbufInitStatic(&options->dir, "/sys/class/power_supply/");
|
||||
#elif defined(_WIN32)
|
||||
options->useSetupApi = false;
|
||||
#endif
|
||||
|
||||
+22
-8
@@ -9,7 +9,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define FF_GPU_NUM_FORMAT_ARGS 10
|
||||
#define FF_GPU_NUM_FORMAT_ARGS 12
|
||||
|
||||
static void printGPUResult(FFGPUOptions* options, uint8_t index, const FFGPUResult* gpu)
|
||||
{
|
||||
@@ -38,6 +38,9 @@ static void printGPUResult(FFGPUOptions* options, uint8_t index, const FFGPUResu
|
||||
if(gpu->coreCount != FF_GPU_CORE_COUNT_UNSET)
|
||||
ffStrbufAppendF(&output, " (%d)", gpu->coreCount);
|
||||
|
||||
if(gpu->frequency == gpu->frequency && gpu->frequency > 0 /* Inactive? */)
|
||||
ffStrbufAppendF(&output, " @ %.2f GHz", gpu->frequency);
|
||||
|
||||
if(gpu->temperature == gpu->temperature) //FF_GPU_TEMP_UNSET
|
||||
{
|
||||
ffStrbufAppendS(&output, " - ");
|
||||
@@ -80,6 +83,8 @@ static void printGPUResult(FFGPUOptions* options, uint8_t index, const FFGPUResu
|
||||
{FF_FORMAT_ARG_TYPE_UINT64, &gpu->dedicated.used},
|
||||
{FF_FORMAT_ARG_TYPE_UINT64, &gpu->shared.total},
|
||||
{FF_FORMAT_ARG_TYPE_UINT64, &gpu->shared.used},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &gpu->platformApi},
|
||||
{FF_FORMAT_ARG_TYPE_DOUBLE, &gpu->frequency},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -129,9 +134,9 @@ bool ffParseGPUCommandOptions(FFGPUOptions* options, const char* key, const char
|
||||
if (ffOptionParseModuleArgs(key, subKey, value, &options->moduleArgs))
|
||||
return true;
|
||||
|
||||
if (ffStrEqualsIgnCase(subKey, "use-nvml"))
|
||||
if (ffStrEqualsIgnCase(subKey, "driver-specific"))
|
||||
{
|
||||
options->useNvml = ffOptionParseBoolean(value);
|
||||
options->driverSpecific = ffOptionParseBoolean(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -179,9 +184,9 @@ void ffParseGPUJsonObject(FFGPUOptions* options, yyjson_val* module)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ffStrEqualsIgnCase(key, "useNvml"))
|
||||
if (ffStrEqualsIgnCase(key, "driverSpecific"))
|
||||
{
|
||||
options->useNvml = yyjson_get_bool(val);
|
||||
options->driverSpecific = yyjson_get_bool(val);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -218,8 +223,8 @@ void ffGenerateGPUJsonConfig(FFGPUOptions* options, yyjson_mut_doc* doc, yyjson_
|
||||
|
||||
ffJsonConfigGenerateModuleArgsConfig(doc, module, &defaultOptions.moduleArgs, &options->moduleArgs);
|
||||
|
||||
if (options->useNvml != defaultOptions.useNvml)
|
||||
yyjson_mut_obj_add_bool(doc, module, "useNvml", options->useNvml);
|
||||
if (options->driverSpecific != defaultOptions.driverSpecific)
|
||||
yyjson_mut_obj_add_bool(doc, module, "driverSpecific", options->driverSpecific);
|
||||
|
||||
if (options->forceVulkan != defaultOptions.forceVulkan)
|
||||
yyjson_mut_obj_add_bool(doc, module, "forceVulkan", options->forceVulkan);
|
||||
@@ -304,6 +309,13 @@ void ffGenerateGPUJsonResult(FFGPUOptions* options, yyjson_mut_doc* doc, yyjson_
|
||||
yyjson_mut_obj_add_str(doc, obj, "type", type);
|
||||
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "vendor", &gpu->vendor);
|
||||
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "platformApi", &gpu->platformApi);
|
||||
|
||||
if (gpu->frequency == FF_GPU_FREQUENCY_UNSET)
|
||||
yyjson_mut_obj_add_null(doc, obj, "frequency");
|
||||
else
|
||||
yyjson_mut_obj_add_real(doc, obj, "frequency", gpu->frequency);
|
||||
}
|
||||
|
||||
FF_LIST_FOR_EACH(FFGPUResult, gpu, gpus)
|
||||
@@ -327,6 +339,8 @@ void ffPrintGPUHelpFormat(void)
|
||||
"GPU used dedicated memory",
|
||||
"GPU total shared memory",
|
||||
"GPU used shared memory",
|
||||
"The platform API that GPU supports",
|
||||
"Current frequency in GHz",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -345,7 +359,7 @@ void ffInitGPUOptions(FFGPUOptions* options)
|
||||
);
|
||||
ffOptionInitModuleArg(&options->moduleArgs);
|
||||
|
||||
options->useNvml = false;
|
||||
options->driverSpecific = false;
|
||||
options->forceVulkan = false;
|
||||
options->temp = false;
|
||||
options->hideType = FF_GPU_TYPE_UNKNOWN;
|
||||
|
||||
@@ -18,6 +18,6 @@ typedef struct FFGPUOptions
|
||||
|
||||
FFGPUType hideType;
|
||||
bool temp;
|
||||
bool useNvml;
|
||||
bool driverSpecific;
|
||||
bool forceVulkan;
|
||||
} FFGPUOptions;
|
||||
|
||||
@@ -10,4 +10,5 @@ typedef struct FFPhysicalDiskOptions
|
||||
FFModuleArgs moduleArgs;
|
||||
|
||||
FFstrbuf namePrefix;
|
||||
bool temp;
|
||||
} FFPhysicalDiskOptions;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#define FF_PHYSICALDISK_DISPLAY_NAME "Physical Disk"
|
||||
#define FF_PHYSICALDISK_NUM_FORMAT_ARGS 7
|
||||
#define FF_PHYSICALDISK_NUM_FORMAT_ARGS 9
|
||||
|
||||
static int sortDevices(const FFPhysicalDiskResult* left, const FFPhysicalDiskResult* right)
|
||||
{
|
||||
@@ -63,28 +63,47 @@ void ffPrintPhysicalDisk(FFPhysicalDiskOptions* options)
|
||||
: dev->type & FF_PHYSICALDISK_TYPE_FIXED
|
||||
? "Fixed"
|
||||
: "";
|
||||
const char* readOnlyType = dev->type & FF_PHYSICALDISK_TYPE_READONLY
|
||||
? "Read-only"
|
||||
: "";
|
||||
|
||||
if(options->moduleArgs.outputFormat.length == 0)
|
||||
{
|
||||
ffPrintLogoAndKey(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
|
||||
|
||||
if (physicalType[0] || removableType[0])
|
||||
if (physicalType[0] || removableType[0] || readOnlyType[0])
|
||||
{
|
||||
ffStrbufAppendS(&buffer, " [");
|
||||
if (physicalType[0])
|
||||
ffStrbufAppendS(&buffer, physicalType);
|
||||
if (removableType[0])
|
||||
{
|
||||
if (physicalType[0])
|
||||
if (buffer.chars[buffer.length - 1] != '[')
|
||||
ffStrbufAppendS(&buffer, ", ");
|
||||
ffStrbufAppendS(&buffer, removableType);
|
||||
}
|
||||
if (readOnlyType[0])
|
||||
{
|
||||
if (buffer.chars[buffer.length - 1] != '[')
|
||||
ffStrbufAppendS(&buffer, ", ");
|
||||
ffStrbufAppendS(&buffer, readOnlyType);
|
||||
}
|
||||
ffStrbufAppendC(&buffer, ']');
|
||||
}
|
||||
|
||||
if (dev->temperature == dev->temperature) //FF_PHYSICALDISK_TEMP_UNSET
|
||||
{
|
||||
if(buffer.length > 0)
|
||||
ffStrbufAppendS(&buffer, " - ");
|
||||
|
||||
ffParseTemperature(dev->temperature, &buffer);
|
||||
}
|
||||
ffStrbufPutTo(&buffer, stdout);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dev->type & FF_PHYSICALDISK_TYPE_READWRITE)
|
||||
readOnlyType = "Read-write";
|
||||
ffParseSize(dev->size, &buffer);
|
||||
ffPrintFormatString(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, FF_PHYSICALDISK_NUM_FORMAT_ARGS, (FFformatarg[]){
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &buffer},
|
||||
@@ -94,6 +113,9 @@ void ffPrintPhysicalDisk(FFPhysicalDiskOptions* options)
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &dev->devPath},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &dev->serial},
|
||||
{FF_FORMAT_ARG_TYPE_STRING, removableType},
|
||||
{FF_FORMAT_ARG_TYPE_STRING, readOnlyType},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &dev->revision},
|
||||
{FF_FORMAT_ARG_TYPE_DOUBLE, &dev->temperature},
|
||||
});
|
||||
}
|
||||
++index;
|
||||
@@ -121,6 +143,12 @@ bool ffParsePhysicalDiskCommandOptions(FFPhysicalDiskOptions* options, const cha
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ffStrEqualsIgnCase(subKey, "temp"))
|
||||
{
|
||||
options->temp = ffOptionParseBoolean(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -143,6 +171,12 @@ void ffParsePhysicalDiskJsonObject(FFPhysicalDiskOptions* options, yyjson_val* m
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ffStrEqualsIgnCase(key, "temp"))
|
||||
{
|
||||
options->temp = yyjson_get_bool(val);
|
||||
continue;
|
||||
}
|
||||
|
||||
ffPrintError(FF_PHYSICALDISK_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key);
|
||||
}
|
||||
}
|
||||
@@ -156,6 +190,9 @@ void ffGeneratePhysicalDiskJsonConfig(FFPhysicalDiskOptions* options, yyjson_mut
|
||||
|
||||
if (!ffStrbufEqual(&options->namePrefix, &defaultOptions.namePrefix))
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "namePrefix", &options->namePrefix);
|
||||
|
||||
if (options->temp != defaultOptions.temp)
|
||||
yyjson_mut_obj_add_bool(doc, module, "temp", options->temp);
|
||||
}
|
||||
|
||||
void ffGeneratePhysicalDiskJsonResult(FFPhysicalDiskOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
|
||||
@@ -193,6 +230,17 @@ void ffGeneratePhysicalDiskJsonResult(FFPhysicalDiskOptions* options, yyjson_mut
|
||||
yyjson_mut_obj_add_bool(doc, obj, "removable", false);
|
||||
else
|
||||
yyjson_mut_obj_add_null(doc, obj, "removable");
|
||||
|
||||
if (dev->type & FF_PHYSICALDISK_TYPE_READONLY)
|
||||
yyjson_mut_obj_add_bool(doc, obj, "readOnly", true);
|
||||
else if (dev->type & FF_PHYSICALDISK_TYPE_READWRITE)
|
||||
yyjson_mut_obj_add_bool(doc, obj, "readOnly", false);
|
||||
else
|
||||
yyjson_mut_obj_add_null(doc, obj, "readOnly");
|
||||
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "revision", &dev->revision);
|
||||
|
||||
yyjson_mut_obj_add_real(doc, obj, "temperature", dev->temperature);
|
||||
}
|
||||
|
||||
FF_LIST_FOR_EACH(FFPhysicalDiskResult, dev, result)
|
||||
@@ -213,6 +261,9 @@ void ffPrintPhysicalDiskHelpFormat(void)
|
||||
"Serial number",
|
||||
"Device kind (SSD or HDD)",
|
||||
"Device kind (Removable or Fixed)",
|
||||
"Device kind (Read-only or Read-write)",
|
||||
"Product revision",
|
||||
"Device temperature",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -232,6 +283,7 @@ void ffInitPhysicalDiskOptions(FFPhysicalDiskOptions* options)
|
||||
ffOptionInitModuleArg(&options->moduleArgs);
|
||||
|
||||
ffStrbufInit(&options->namePrefix);
|
||||
options->temp = false;
|
||||
}
|
||||
|
||||
void ffDestroyPhysicalDiskOptions(FFPhysicalDiskOptions* options)
|
||||
|
||||
@@ -130,7 +130,7 @@ void ffGenerateVulkanJsonResult(FF_MAYBE_UNUSED FFVulkanOptions* options, yyjson
|
||||
yyjson_mut_obj_add_null(doc, sharedMemory, "used");
|
||||
}
|
||||
|
||||
yyjson_mut_obj_add_uint(doc, gpuObj, "deviceId", vulkanGpu->vulkanDeviceId);
|
||||
yyjson_mut_obj_add_uint(doc, gpuObj, "deviceId", vulkanGpu->deviceId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+20
-17
@@ -54,6 +54,7 @@ void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free)
|
||||
strbuf->allocated = allocate;
|
||||
}
|
||||
|
||||
// for an empty buffer, free + 1 length memory will be allocated(+1 for the NUL)
|
||||
void ffStrbufEnsureFixedLengthFree(FFstrbuf* strbuf, uint32_t free)
|
||||
{
|
||||
uint32_t oldFree = ffStrbufGetFree(strbuf);
|
||||
@@ -64,7 +65,7 @@ void ffStrbufEnsureFixedLengthFree(FFstrbuf* strbuf, uint32_t free)
|
||||
|
||||
if(strbuf->allocated == 0)
|
||||
{
|
||||
newCap += strbuf->length + 1; // +1 for the NUL
|
||||
newCap += strbuf->length + 1;
|
||||
char* newbuf = malloc(sizeof(*strbuf->chars) * newCap);
|
||||
if(strbuf->length == 0)
|
||||
*newbuf = '\0';
|
||||
@@ -118,22 +119,6 @@ void ffStrbufAppendNS(FFstrbuf* strbuf, uint32_t length, const char* value)
|
||||
strbuf->chars[strbuf->length] = '\0';
|
||||
}
|
||||
|
||||
void ffStrbufAppendNSExludingC(FFstrbuf* strbuf, uint32_t length, const char* value, char exclude)
|
||||
{
|
||||
if(value == NULL || length == 0)
|
||||
return;
|
||||
|
||||
ffStrbufEnsureFree(strbuf, length);
|
||||
|
||||
for(uint32_t i = 0; i < length; i++)
|
||||
{
|
||||
if(value[i] != exclude)
|
||||
strbuf->chars[strbuf->length++] = value[i];
|
||||
}
|
||||
|
||||
strbuf->chars[strbuf->length] = '\0';
|
||||
}
|
||||
|
||||
void ffStrbufAppendTransformS(FFstrbuf* strbuf, const char* value, int(*transformFunc)(int))
|
||||
{
|
||||
if(value == NULL)
|
||||
@@ -280,6 +265,24 @@ void ffStrbufTrimRight(FFstrbuf* strbuf, char c)
|
||||
strbuf->chars[strbuf->length] = '\0';
|
||||
}
|
||||
|
||||
void ffStrbufTrimRightSpace(FFstrbuf* strbuf)
|
||||
{
|
||||
if(strbuf->length == 0)
|
||||
return;
|
||||
|
||||
while(ffStrbufEndsWithFn(strbuf, isspace))
|
||||
--strbuf->length;
|
||||
|
||||
if(strbuf->allocated == 0)
|
||||
{
|
||||
//static string
|
||||
ffStrbufInitNS(strbuf, strbuf->length, strbuf->chars);
|
||||
return;
|
||||
}
|
||||
|
||||
strbuf->chars[strbuf->length] = '\0';
|
||||
}
|
||||
|
||||
void ffStrbufRemoveSubstr(FFstrbuf* strbuf, uint32_t startIndex, uint32_t endIndex)
|
||||
{
|
||||
if(startIndex > strbuf->length || startIndex >= endIndex)
|
||||
|
||||
+7
-1
@@ -41,7 +41,6 @@ static inline void ffStrbufAppend(FFstrbuf* __restrict strbuf, const FFstrbuf* _
|
||||
void ffStrbufAppendC(FFstrbuf* strbuf, char c);
|
||||
void ffStrbufAppendNC(FFstrbuf* strbuf, uint32_t num, char c);
|
||||
void ffStrbufAppendNS(FFstrbuf* strbuf, uint32_t length, const char* value);
|
||||
void ffStrbufAppendNSExludingC(FFstrbuf* strbuf, uint32_t length, const char* value, char exclude);
|
||||
void ffStrbufAppendTransformS(FFstrbuf* strbuf, const char* value, int(*transformFunc)(int));
|
||||
FF_C_PRINTF(2, 3) void ffStrbufAppendF(FFstrbuf* strbuf, const char* format, ...);
|
||||
void ffStrbufAppendVF(FFstrbuf* strbuf, const char* format, va_list arguments);
|
||||
@@ -55,6 +54,7 @@ FF_C_PRINTF(2, 3) void ffStrbufSetF(FFstrbuf* strbuf, const char* format, ...);
|
||||
|
||||
void ffStrbufTrimLeft(FFstrbuf* strbuf, char c);
|
||||
void ffStrbufTrimRight(FFstrbuf* strbuf, char c);
|
||||
void ffStrbufTrimRightSpace(FFstrbuf* strbuf);
|
||||
|
||||
void ffStrbufRemoveSubstr(FFstrbuf* strbuf, uint32_t startIndex, uint32_t endIndex);
|
||||
void ffStrbufRemoveS(FFstrbuf* strbuf, const char* str);
|
||||
@@ -454,6 +454,12 @@ static inline FF_C_NODISCARD bool ffStrbufEndsWithS(const FFstrbuf* strbuf, cons
|
||||
return ffStrbufEndsWithNS(strbuf, (uint32_t) strlen(end), end);
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufEndsWithFn(const FFstrbuf* strbuf, int (*fn)(int))
|
||||
{
|
||||
return strbuf->length == 0 ? false :
|
||||
fn(strbuf->chars[strbuf->length - 1]);
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufEndsWith(const FFstrbuf* strbuf, const FFstrbuf* end)
|
||||
{
|
||||
return ffStrbufEndsWithNS(strbuf, end->length, end->chars);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "smbiosHelper.h"
|
||||
#include "common/io/io.h"
|
||||
|
||||
bool ffIsSmbiosValueSet(FFstrbuf* value)
|
||||
{
|
||||
@@ -26,3 +27,24 @@ bool ffIsSmbiosValueSet(FFstrbuf* value)
|
||||
!ffStrbufIgnCaseEqualS(value, "N/A")
|
||||
;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
void ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer)
|
||||
{
|
||||
if (ffReadFileBuffer(devicesPath, buffer))
|
||||
{
|
||||
ffStrbufTrimRightSpace(buffer);
|
||||
if(ffIsSmbiosValueSet(buffer))
|
||||
return;
|
||||
}
|
||||
|
||||
if (ffReadFileBuffer(classPath, buffer))
|
||||
{
|
||||
ffStrbufTrimRightSpace(buffer);
|
||||
if(ffIsSmbiosValueSet(buffer))
|
||||
return;
|
||||
}
|
||||
|
||||
ffStrbufClear(buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -12,4 +12,8 @@ static inline void ffCleanUpSmbiosValue(FFstrbuf* value)
|
||||
ffStrbufClear(value);
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
void ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include "fastfetch.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <synchapi.h>
|
||||
|
||||
//https://learn.microsoft.com/en-us/windows/win32/wmisdk/example--getting-wmi-data-from-the-local-computer
|
||||
//https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/computer-system-hardware-classes
|
||||
@@ -11,14 +10,11 @@ static void CoUninitializeWrap(void)
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
static BOOL CALLBACK InitHandleFunction(FF_MAYBE_UNUSED PINIT_ONCE lpInitOnce, FF_MAYBE_UNUSED PVOID lpParameter, PVOID* lpContext)
|
||||
static const char* doInitCom()
|
||||
{
|
||||
// Initialize COM
|
||||
if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED)))
|
||||
{
|
||||
*lpContext = (PVOID) "CoInitializeEx() failed";
|
||||
return FALSE;
|
||||
}
|
||||
return "CoInitializeEx() failed";
|
||||
|
||||
// Set general COM security levels
|
||||
if (FAILED(CoInitializeSecurity(
|
||||
@@ -34,18 +30,17 @@ static BOOL CALLBACK InitHandleFunction(FF_MAYBE_UNUSED PINIT_ONCE lpInitOnce, F
|
||||
)))
|
||||
{
|
||||
CoUninitialize();
|
||||
*lpContext = (PVOID) "CoInitializeSecurity() failed";
|
||||
return FALSE;
|
||||
return "CoInitializeSecurity() failed";
|
||||
}
|
||||
|
||||
atexit(CoUninitializeWrap);
|
||||
return TRUE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffInitCom(void)
|
||||
{
|
||||
const char* error = NULL;
|
||||
static INIT_ONCE s_InitOnce;
|
||||
InitOnceExecuteOnce(&s_InitOnce, &InitHandleFunction, NULL, (void**)&error);
|
||||
static const char* error = "";
|
||||
if (error && error[0] == '\0')
|
||||
error = doInitCom();
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,11 @@ extern "C" {
|
||||
|
||||
#include <string_view>
|
||||
|
||||
static inline void ffStrbufInitWSV(FFstrbuf* result, const std::wstring_view source)
|
||||
{
|
||||
return ffStrbufInitNWS(result, (uint32_t) source.size(), source.data());
|
||||
}
|
||||
|
||||
static inline void ffStrbufSetWSV(FFstrbuf* result, const std::wstring_view source)
|
||||
{
|
||||
return ffStrbufSetNWS(result, (uint32_t) source.size(), source.data());
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
#include <oaidl.h>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <string_view>
|
||||
|
||||
struct FFWmiVariant: VARIANT
|
||||
{
|
||||
explicit FFWmiVariant() { VariantInit(this); }
|
||||
~FFWmiVariant() { VariantClear(this); }
|
||||
|
||||
FFWmiVariant(const FFWmiVariant&) = delete;
|
||||
FFWmiVariant(FFWmiVariant&&); // don't define it to enforce NRVO optimization
|
||||
|
||||
bool hasValue() {
|
||||
return this->vt != VT_EMPTY;
|
||||
}
|
||||
|
||||
explicit operator bool() {
|
||||
return this->hasValue();
|
||||
}
|
||||
|
||||
template <typename T> T get()
|
||||
{
|
||||
// boolean
|
||||
if constexpr (std::is_same_v<T, bool>) {
|
||||
assert(this->vt == VT_BOOL);
|
||||
return this->boolVal != VARIANT_FALSE;
|
||||
}
|
||||
|
||||
// signed
|
||||
else if constexpr (std::is_same_v<T, int8_t>) {
|
||||
assert(this->vt == VT_I1);
|
||||
return this->cVal;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, int16_t>) {
|
||||
assert(vt == VT_I2);
|
||||
return this->iVal;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, int32_t>) {
|
||||
assert(this->vt == VT_I4 || vt == VT_INT);
|
||||
return this->intVal;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, int64_t>) {
|
||||
assert(this->vt == VT_I8);
|
||||
return this->llVal;
|
||||
}
|
||||
|
||||
// unsigned
|
||||
else if constexpr (std::is_same_v<T, uint8_t>) {
|
||||
assert(this->vt == VT_UI1);
|
||||
return this->bVal;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, uint16_t>) {
|
||||
assert(this->vt == VT_UI2);
|
||||
return this->uiVal;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, uint32_t>) {
|
||||
assert(this->vt == VT_UI4 || vt == VT_UINT);
|
||||
return this->uintVal;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, uint64_t>) {
|
||||
assert(this->vt == VT_UI8);
|
||||
return this->ullVal;
|
||||
}
|
||||
|
||||
// decimal
|
||||
else if constexpr (std::is_same_v<T, float>) {
|
||||
assert(this->vt == VT_R4);
|
||||
return this->fltVal;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, double>) {
|
||||
assert(this->vt == VT_R8);
|
||||
return this->dblVal;
|
||||
}
|
||||
|
||||
// string
|
||||
else if constexpr (std::is_same_v<T, std::string_view>) {
|
||||
assert(this->vt == VT_LPSTR);
|
||||
return this->pcVal;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::wstring_view>) {
|
||||
assert(this->vt == VT_BSTR || this->vt == VT_LPWSTR);
|
||||
if (this->vt == VT_LPWSTR)
|
||||
return this->bstrVal;
|
||||
else
|
||||
return { this->bstrVal, SysStringLen(this->bstrVal) };
|
||||
}
|
||||
|
||||
// array signed
|
||||
else if constexpr (std::is_same_v<T, std::pair<const int8_t*, uint32_t>>) {
|
||||
assert(this->vt & VT_ARRAY);
|
||||
assert((this->vt & ~VT_ARRAY) == VT_I1);
|
||||
return std::make_pair((int8_t*)this->parray->pvData, this->parray->cDims);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::pair<const int16_t*, uint32_t>>) {
|
||||
assert(this->vt & VT_ARRAY);
|
||||
assert((this->vt & ~VT_ARRAY) == VT_I2);
|
||||
return std::make_pair((int16_t*)this->parray->pvData, this->parray->cDims);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::pair<const int32_t*, uint32_t>>) {
|
||||
assert(this->vt & VT_ARRAY);
|
||||
assert((this->vt & ~VT_ARRAY) == VT_I4);
|
||||
return std::make_pair((int32_t*)this->parray->pvData, this->parray->cDims);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::pair<const int64_t*, uint32_t>>) {
|
||||
assert(this->vt & VT_ARRAY);
|
||||
assert((this->vt & ~VT_ARRAY) == VT_I8);
|
||||
return std::make_pair((int64_t*)this->parray->pvData, this->parray->cDims);
|
||||
}
|
||||
|
||||
// array unsigned
|
||||
else if constexpr (std::is_same_v<T, std::pair<const uint8_t*, uint32_t>>) {
|
||||
assert(this->vt & VT_ARRAY);
|
||||
assert((this->vt & ~VT_ARRAY) == VT_UI1);
|
||||
return std::make_pair((uint8_t*)this->parray->pvData, this->parray->cDims);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::pair<const uint16_t*, uint32_t>>) {
|
||||
assert(this->vt & VT_ARRAY);
|
||||
assert((this->vt & ~VT_ARRAY) == VT_UI2);
|
||||
return std::make_pair((uint16_t*)this->parray->pvData, this->parray->cDims);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::pair<const uint32_t*, uint32_t>>) {
|
||||
assert(this->vt & VT_ARRAY);
|
||||
assert((this->vt & ~VT_ARRAY) == VT_UI4);
|
||||
return std::make_pair((uint32_t*)this->parray->pvData, this->parray->cDims);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::pair<const uint64_t*, uint32_t>>) {
|
||||
assert(this->vt & VT_ARRAY);
|
||||
assert((this->vt & ~VT_ARRAY) == VT_UI8);
|
||||
return std::make_pair((uint64_t*)this->parray->pvData, this->parray->cDims);
|
||||
}
|
||||
else {
|
||||
assert(false && "unsupported type");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
};
|
||||
+23
-28
@@ -21,7 +21,7 @@ namespace
|
||||
};
|
||||
}
|
||||
|
||||
static BOOL CALLBACK InitHandleFunction(PINIT_ONCE, PVOID lpParameter, PVOID* lpContext)
|
||||
static const char* doInitService(const wchar_t* networkResource, IWbemServices** result)
|
||||
{
|
||||
HRESULT hres;
|
||||
|
||||
@@ -35,10 +35,7 @@ static BOOL CALLBACK InitHandleFunction(PINIT_ONCE, PVOID lpParameter, PVOID* lp
|
||||
(LPVOID*) &pLoc);
|
||||
|
||||
if (FAILED(hres))
|
||||
{
|
||||
*((const char**)lpContext) = "Failed to create IWbemLocator object";
|
||||
return FALSE;
|
||||
}
|
||||
return "Failed to create IWbemLocator object";
|
||||
|
||||
// Connect to WMI through the IWbemLocator::ConnectServer method
|
||||
IWbemServices* pSvc = nullptr;
|
||||
@@ -47,7 +44,7 @@ static BOOL CALLBACK InitHandleFunction(PINIT_ONCE, PVOID lpParameter, PVOID* lp
|
||||
// the current user and obtain pointer pSvc
|
||||
// to make IWbemServices calls.
|
||||
hres = pLoc->ConnectServer(
|
||||
bstr_t((const wchar_t*) lpParameter), // Object path of WMI namespace
|
||||
bstr_t(networkResource), // Object path of WMI namespace
|
||||
nullptr, // User name. nullptr = current user
|
||||
nullptr, // User password. nullptr = current
|
||||
0, // Locale. nullptr indicates current
|
||||
@@ -60,10 +57,7 @@ static BOOL CALLBACK InitHandleFunction(PINIT_ONCE, PVOID lpParameter, PVOID* lp
|
||||
pLoc = nullptr;
|
||||
|
||||
if (FAILED(hres))
|
||||
{
|
||||
*((const char**)lpContext) = "Could not connect WMI server";
|
||||
return FALSE;
|
||||
}
|
||||
return "Could not connect WMI server";
|
||||
|
||||
// Set security levels on the proxy -------------------------
|
||||
hres = CoSetProxyBlanket(
|
||||
@@ -80,39 +74,40 @@ static BOOL CALLBACK InitHandleFunction(PINIT_ONCE, PVOID lpParameter, PVOID* lp
|
||||
if (FAILED(hres))
|
||||
{
|
||||
pSvc->Release();
|
||||
*((const char**)lpContext) = "Could not set proxy blanket";
|
||||
return FALSE;
|
||||
return "Could not set proxy blanket";
|
||||
}
|
||||
|
||||
*((IWbemServices**)lpContext) = pSvc;
|
||||
return TRUE;
|
||||
*result = pSvc;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FFWmiQuery::FFWmiQuery(const wchar_t* queryStr, FFstrbuf* error, FFWmiNamespace wmiNs)
|
||||
: pEnumerator(nullptr)
|
||||
{
|
||||
const char* context = ffInitCom();
|
||||
if (context)
|
||||
const char* errStr;
|
||||
if ((errStr = ffInitCom()))
|
||||
{
|
||||
if (error)
|
||||
ffStrbufAppendS(error, context);
|
||||
ffStrbufSetS(error, errStr);
|
||||
return;
|
||||
}
|
||||
|
||||
static INIT_ONCE s_InitOnce[(int) FFWmiNamespace::LAST] = {};
|
||||
if (InitOnceExecuteOnce(
|
||||
&s_InitOnce[(int)wmiNs],
|
||||
&InitHandleFunction,
|
||||
(PVOID) (wmiNs == FFWmiNamespace::CIMV2 ? L"ROOT\\CIMV2" : L"ROOT\\WMI"),
|
||||
(void**)&context) == FALSE
|
||||
) {
|
||||
if(error)
|
||||
ffStrbufAppendS(error, context);
|
||||
return;
|
||||
static IWbemServices* contexts[(int) FFWmiNamespace::LAST];
|
||||
|
||||
IWbemServices* context = contexts[(int)wmiNs];
|
||||
if (!contexts[(int)wmiNs])
|
||||
{
|
||||
if ((errStr = doInitService(wmiNs == FFWmiNamespace::CIMV2 ? L"ROOT\\CIMV2" : L"ROOT\\WMI", &context)))
|
||||
{
|
||||
if (error)
|
||||
ffStrbufSetS(error, errStr);
|
||||
return;
|
||||
}
|
||||
contexts[(int)wmiNs] = context;
|
||||
}
|
||||
|
||||
// Use the IWbemServices pointer to make requests of WMI
|
||||
HRESULT hres = ((IWbemServices*)context)->ExecQuery(
|
||||
HRESULT hres = context->ExecQuery(
|
||||
bstr_t(L"WQL"),
|
||||
bstr_t(queryStr),
|
||||
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
|
||||
|
||||
+2
-135
@@ -8,10 +8,9 @@ extern "C" {
|
||||
|
||||
#include <initguid.h>
|
||||
#include <Wbemidl.h>
|
||||
#include <utility>
|
||||
#include <string_view>
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
|
||||
#include "variant.hpp"
|
||||
|
||||
enum class FFWmiNamespace {
|
||||
CIMV2,
|
||||
@@ -19,138 +18,6 @@ enum class FFWmiNamespace {
|
||||
LAST,
|
||||
};
|
||||
|
||||
struct FFWmiVariant: VARIANT {
|
||||
explicit FFWmiVariant() { VariantInit(this); }
|
||||
~FFWmiVariant() { VariantClear(this); }
|
||||
|
||||
FFWmiVariant(const FFWmiVariant&) = delete;
|
||||
FFWmiVariant(FFWmiVariant&&); // don't define it to enforce NRVO optimization
|
||||
|
||||
bool hasValue() {
|
||||
return this->vt != VT_EMPTY;
|
||||
}
|
||||
|
||||
explicit operator bool() {
|
||||
return this->hasValue();
|
||||
}
|
||||
|
||||
template <typename T> T get()
|
||||
{
|
||||
// boolean
|
||||
if constexpr (std::is_same_v<T, bool>) {
|
||||
assert(this->vt == VT_BOOL);
|
||||
return this->boolVal != VARIANT_FALSE;
|
||||
}
|
||||
|
||||
// signed
|
||||
else if constexpr (std::is_same_v<T, int8_t>) {
|
||||
assert(this->vt == VT_I1);
|
||||
return this->cVal;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, int16_t>) {
|
||||
assert(vt == VT_I2);
|
||||
return this->iVal;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, int32_t>) {
|
||||
assert(this->vt == VT_I4 || vt == VT_INT);
|
||||
return this->intVal;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, int64_t>) {
|
||||
assert(this->vt == VT_I8);
|
||||
return this->llVal;
|
||||
}
|
||||
|
||||
// unsigned
|
||||
else if constexpr (std::is_same_v<T, uint8_t>) {
|
||||
assert(this->vt == VT_UI1);
|
||||
return this->bVal;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, uint16_t>) {
|
||||
assert(this->vt == VT_UI2);
|
||||
return this->uiVal;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, uint32_t>) {
|
||||
assert(this->vt == VT_UI4 || vt == VT_UINT);
|
||||
return this->uintVal;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, uint64_t>) {
|
||||
assert(this->vt == VT_UI8);
|
||||
return this->ullVal;
|
||||
}
|
||||
|
||||
// decimal
|
||||
else if constexpr (std::is_same_v<T, float>) {
|
||||
assert(this->vt == VT_R4);
|
||||
return this->fltVal;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, double>) {
|
||||
assert(this->vt == VT_R8);
|
||||
return this->dblVal;
|
||||
}
|
||||
|
||||
// string
|
||||
else if constexpr (std::is_same_v<T, std::string_view>) {
|
||||
assert(this->vt == VT_LPSTR);
|
||||
return this->pcVal;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::wstring_view>) {
|
||||
assert(this->vt == VT_BSTR || this->vt == VT_LPWSTR);
|
||||
if (this->vt == VT_LPWSTR)
|
||||
return this->bstrVal;
|
||||
else
|
||||
return { this->bstrVal, SysStringLen(this->bstrVal) };
|
||||
}
|
||||
|
||||
// array signed
|
||||
else if constexpr (std::is_same_v<T, std::pair<const int8_t*, uint32_t>>) {
|
||||
assert(this->vt & VT_ARRAY);
|
||||
assert((this->vt & ~VT_ARRAY) == VT_I1);
|
||||
return std::make_pair((int8_t*)this->parray->pvData, this->parray->cDims);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::pair<const int16_t*, uint32_t>>) {
|
||||
assert(this->vt & VT_ARRAY);
|
||||
assert((this->vt & ~VT_ARRAY) == VT_I2);
|
||||
return std::make_pair((int16_t*)this->parray->pvData, this->parray->cDims);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::pair<const int32_t*, uint32_t>>) {
|
||||
assert(this->vt & VT_ARRAY);
|
||||
assert((this->vt & ~VT_ARRAY) == VT_I4);
|
||||
return std::make_pair((int32_t*)this->parray->pvData, this->parray->cDims);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::pair<const int64_t*, uint32_t>>) {
|
||||
assert(this->vt & VT_ARRAY);
|
||||
assert((this->vt & ~VT_ARRAY) == VT_I8);
|
||||
return std::make_pair((int64_t*)this->parray->pvData, this->parray->cDims);
|
||||
}
|
||||
|
||||
// array unsigned
|
||||
else if constexpr (std::is_same_v<T, std::pair<const uint8_t*, uint32_t>>) {
|
||||
assert(this->vt & VT_ARRAY);
|
||||
assert((this->vt & ~VT_ARRAY) == VT_UI1);
|
||||
return std::make_pair((uint8_t*)this->parray->pvData, this->parray->cDims);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::pair<const uint16_t*, uint32_t>>) {
|
||||
assert(this->vt & VT_ARRAY);
|
||||
assert((this->vt & ~VT_ARRAY) == VT_UI2);
|
||||
return std::make_pair((uint16_t*)this->parray->pvData, this->parray->cDims);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::pair<const uint32_t*, uint32_t>>) {
|
||||
assert(this->vt & VT_ARRAY);
|
||||
assert((this->vt & ~VT_ARRAY) == VT_UI4);
|
||||
return std::make_pair((uint32_t*)this->parray->pvData, this->parray->cDims);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::pair<const uint64_t*, uint32_t>>) {
|
||||
assert(this->vt & VT_ARRAY);
|
||||
assert((this->vt & ~VT_ARRAY) == VT_UI8);
|
||||
return std::make_pair((uint64_t*)this->parray->pvData, this->parray->cDims);
|
||||
}
|
||||
else {
|
||||
assert(false && "unsupported type");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct FFWmiRecord
|
||||
{
|
||||
IWbemClassObject* obj;
|
||||
|
||||
Reference in New Issue
Block a user