Created
August 31, 2023 22:23
-
-
Save drzony/1744b4f72dcd4fde309a125445c474a1 to your computer and use it in GitHub Desktop.
NVAPI DDC code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class DDCControl | |
{ | |
public: | |
DDCControl() | |
: _gpu_handle(NULL) | |
, _display_id(0) | |
{ | |
initNv(); | |
} | |
bool setFeature(uint8_t register_address, uint8_t feature, uint16_t value) | |
{ | |
return setFeatureNv(register_address, feature, value); | |
} | |
bool getFeature(uint8_t register_address, uint8_t feature, uint16_t &value) | |
{ | |
return getFeatureNv(register_address, feature, value); | |
} | |
private: | |
void initNv() | |
{ | |
NvAPI_Status nvapi_status = NVAPI_OK; | |
// Initialize NVAPI. | |
if ((nvapi_status = NvAPI_Initialize()) != NVAPI_OK) | |
{ | |
printf("NvAPI_Initialize() failed with status %d\n", nvapi_status); | |
return; | |
} | |
// | |
// Enumerate display handles | |
// | |
NvDisplayHandle display_handles[NVAPI_MAX_PHYSICAL_GPUS * NVAPI_MAX_DISPLAY_HEADS] = {0}; | |
NvU32 nv_display_count = 0; | |
for (unsigned int i = 0; nvapi_status == NVAPI_OK; i++) | |
{ | |
nvapi_status = NvAPI_EnumNvidiaDisplayHandle(i, &display_handles[i]); | |
if (nvapi_status == NVAPI_OK) | |
{ | |
nv_display_count++; | |
} | |
else if (nvapi_status != NVAPI_END_ENUMERATION) | |
{ | |
printf("NvAPI_EnumNvidiaDisplayHandle() failed with status %d\n", nvapi_status); | |
return; | |
} | |
} | |
printf("No of displays = %u\n", nv_display_count); | |
if (nv_display_count < 1) | |
{ | |
return; | |
} | |
// | |
// Enumerate physical GPU handles | |
// | |
NvPhysicalGpuHandle gpu_handles[NVAPI_MAX_PHYSICAL_GPUS] = {0}; // handle to GPUs | |
NvU32 gpu_count = 0; | |
nvapi_status = NvAPI_EnumPhysicalGPUs(gpu_handles, &gpu_count); | |
if (nvapi_status != NVAPI_OK) | |
{ | |
printf("NvAPI_EnumPhysicalGPUs() failed with status %d\n", nvapi_status); | |
return; | |
} | |
printf("Total number of GPU's = %u\n", gpu_count); | |
if (gpu_count < 1) | |
{ | |
return; | |
} | |
// Get GPU id assiciated with display ID | |
NvU32 p_gpu_count = 0; | |
nvapi_status = NvAPI_GetPhysicalGPUsFromDisplay(display_handles[0], &_gpu_handle, &p_gpu_count); | |
if (nvapi_status != NVAPI_OK) | |
{ | |
_gpu_handle = NULL; | |
printf("NvAPI_GetPhysicalGPUFromDisplay() failed with status %d\n", nvapi_status); | |
return; | |
} | |
// Get the display id for subsequent I2C calls via NVAPI: | |
nvapi_status = NvAPI_GetAssociatedDisplayOutputId(display_handles[0], &_display_id); | |
if (nvapi_status != NVAPI_OK) | |
{ | |
_gpu_handle = NULL; | |
printf("NvAPI_GetAssociatedDisplayOutputId() failed with status %d\n", nvapi_status); | |
return; | |
} | |
} | |
bool setFeatureNv(uint8_t register_address, uint8_t feature, uint16_t value) | |
{ | |
NvAPI_Status nvapi_status = NVAPI_OK; | |
BYTE output_data[] = {0x84, 0x03, feature, (BYTE)((value >> 8) & 0xFF), (BYTE)(value & 0xFF), 0x00}; | |
NV_I2C_INFO i2c_info = {0}; | |
i2c_info.version = NV_I2C_INFO_VER; | |
i2c_info.displayMask = _display_id; | |
i2c_info.bIsDDCPort = TRUE; | |
i2c_info.i2cDevAddress = 0x37 << 1; | |
i2c_info.pbI2cRegAddress = (BYTE *)®ister_address; | |
i2c_info.regAddrSize = 1; | |
i2c_info.pbData = (BYTE *)output_data; | |
i2c_info.cbSize = sizeof(output_data); | |
i2c_info.i2cSpeed = 27; | |
calculateI2cChecksum(i2c_info); | |
printf("Setting feature: 0x%02x @ 0x%02x to 0x%04x\n", feature, register_address, value); | |
nvapi_status = NvAPI_I2CWrite(_gpu_handle, &i2c_info); | |
if (nvapi_status != NVAPI_OK) | |
{ | |
printf("NvAPI_I2CWrite failed with status %d\n", nvapi_status); | |
return false; | |
} | |
printf("NvAPI_I2CWrite SUCCESS\n"); | |
return true; | |
} | |
bool getFeatureNv(uint8_t register_address, uint8_t feature, uint16_t &value) | |
{ | |
NvAPI_Status nvapi_status = NVAPI_OK; | |
BYTE query_data[] = {0x82, 0x01, feature, 0x00}; | |
NV_I2C_INFO i2c_info = {0}; | |
i2c_info.version = NV_I2C_INFO_VER; | |
i2c_info.displayMask = _display_id; | |
i2c_info.bIsDDCPort = TRUE; | |
i2c_info.i2cDevAddress = (0x37 << 1); | |
i2c_info.pbI2cRegAddress = ®ister_address; | |
i2c_info.regAddrSize = 1; | |
i2c_info.pbData = query_data; | |
i2c_info.cbSize = sizeof(query_data); | |
i2c_info.i2cSpeed = 27; | |
calculateI2cChecksum(i2c_info); | |
printf("Getting feature: 0x%02x @ 0x%02x\n", feature, register_address); | |
nvapi_status = NvAPI_I2CWrite(_gpu_handle, &i2c_info); | |
if (nvapi_status != NVAPI_OK) | |
{ | |
printf("NvAPI_I2CWrite failed with status %d\n", nvapi_status); | |
return false; | |
} | |
printf("NvAPI_I2CWrite SUCCESS\n"); | |
Sleep(40); | |
BYTE input_data[11] = {0}; | |
i2c_info.version = NV_I2C_INFO_VER; | |
i2c_info.displayMask = _display_id; | |
i2c_info.bIsDDCPort = TRUE; | |
i2c_info.i2cDevAddress = (0x37 << 1) | 1; | |
i2c_info.pbI2cRegAddress = ®ister_address; | |
i2c_info.regAddrSize = 1; | |
i2c_info.pbData = input_data; | |
i2c_info.cbSize = sizeof(input_data); | |
i2c_info.i2cSpeed = 27; | |
nvapi_status = NvAPI_I2CRead(_gpu_handle, &i2c_info); | |
if (nvapi_status != NVAPI_OK) | |
{ | |
printf("NvAPI_I2CRead failed with status %d\n", nvapi_status); | |
return false; | |
} | |
for (int i = 0; i < sizeof(input_data); i++) | |
{ | |
printf("%02x ", input_data[i]); | |
} | |
printf("\n"); | |
if (feature == 0xCA) | |
{ | |
printf((char *)(input_data + 1)); | |
} | |
printf("\n"); | |
if (input_data[0] != 0x6E) | |
{ | |
printf("Invalid response: 0x%02x\n", input_data[0]); | |
return false; | |
} | |
if (input_data[3] != 0x00) | |
{ | |
printf("Device returned non-zero code: 0x%02x\n", input_data[3]); | |
return false; | |
} | |
if (input_data[1] != 0x02) | |
{ | |
printf("Invalid response flag: 0x%02x\n", input_data[1]); | |
return false; | |
} | |
if (input_data[2] != 0x88) | |
{ | |
printf("Invalid response size: 0x%02x\n", input_data[2]); | |
return false; | |
} | |
if (input_data[4] != feature) | |
{ | |
printf("Invalid response feature: 0x%02x\n", input_data[4]); | |
return false; | |
} | |
value = ((uint16_t)(input_data[8]) << 8) | (uint16_t)(input_data[9]); | |
return true; | |
} | |
bool setFeatureWin(uint8_t feature) | |
{ | |
} | |
bool getFeatureWin(uint8_t feature, uint16_t value) | |
{ | |
} | |
void calculateI2cChecksum(const NV_I2C_INFO &i2c_info) const | |
{ | |
// Calculate the i2c packet checksum and place the | |
// value into the packet | |
// i2c checksum is the result of xor'ing all the bytes in the | |
// packet (except for the last data byte, which is the checksum | |
// itself) | |
// Packet consists of: | |
// The device address... | |
BYTE checksum = i2c_info.i2cDevAddress; | |
// Register address... | |
for (unsigned int i = 0; i < i2c_info.regAddrSize; ++i) | |
{ | |
checksum ^= i2c_info.pbI2cRegAddress[i]; | |
} | |
// And data bytes less last byte for checksum... | |
for (unsigned int i = 0; i < i2c_info.cbSize - 1; ++i) | |
{ | |
checksum ^= i2c_info.pbData[i]; | |
} | |
// Store calculated checksum in the last byte of i2c packet | |
i2c_info.pbData[i2c_info.cbSize - 1] = checksum; | |
} | |
NvPhysicalGpuHandle _gpu_handle; | |
NvU32 _display_id; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment