Skip to content

Instantly share code, notes, and snippets.

@drzony
Created August 31, 2023 22:23
Show Gist options
  • Save drzony/1744b4f72dcd4fde309a125445c474a1 to your computer and use it in GitHub Desktop.
Save drzony/1744b4f72dcd4fde309a125445c474a1 to your computer and use it in GitHub Desktop.
NVAPI DDC code
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 *)&register_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 = &register_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 = &register_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