Publish LumaOps source
This commit is contained in:
@@ -0,0 +1,309 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| i2c_smbus_amdadl.cpp |
|
||||
| |
|
||||
| Definitions and types for AMD ADL I2C functions |
|
||||
| |
|
||||
| Niels Westphal (crashniels) 30 May 2020 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <string>
|
||||
#include "Detector.h"
|
||||
#include "i2c_smbus_amdadl.h"
|
||||
#include "LogManager.h"
|
||||
#include "pci_ids.h"
|
||||
|
||||
typedef int ( *ADL2_MAIN_CONTROL_CREATE )(ADL_MAIN_MALLOC_CALLBACK, int, ADL_CONTEXT_HANDLE*);
|
||||
typedef int ( *ADL2_MAIN_CONTROL_DESTROY )(ADL_CONTEXT_HANDLE);
|
||||
typedef int ( *ADL2_ADAPTER_NUMBEROFADAPTERS_GET ) ( ADL_CONTEXT_HANDLE , int* );
|
||||
typedef int ( *ADL2_ADAPTER_PRIMARY_GET) (ADL_CONTEXT_HANDLE, int* lpPrimaryAdapterIndex);
|
||||
typedef int ( *ADL2_ADAPTER_ADAPTERINFOX2_GET) (ADL_CONTEXT_HANDLE, AdapterInfo**);
|
||||
typedef int ( *ADL2_ADAPTER_ADAPTERINFOX4_GET) (ADL_CONTEXT_HANDLE, int iAdapterIndex, int* numAdapters, AdapterInfoX2** lppAdapterInfoX2);
|
||||
typedef int ( *ADL2_DISPLAY_WRITEANDREADI2C) (ADL_CONTEXT_HANDLE, int iAdapterIndex, ADLI2C* plI2C);
|
||||
|
||||
ADL2_MAIN_CONTROL_CREATE ADL2_Main_Control_Create;
|
||||
ADL2_MAIN_CONTROL_DESTROY ADL2_Main_Control_Destroy;
|
||||
ADL2_ADAPTER_NUMBEROFADAPTERS_GET ADL2_Adapter_NumberOfAdapters_Get;
|
||||
ADL2_ADAPTER_PRIMARY_GET ADL2_Adapter_Primary_Get;
|
||||
ADL2_ADAPTER_ADAPTERINFOX2_GET ADL2_Adapter_AdapterInfoX2_Get;
|
||||
ADL2_ADAPTER_ADAPTERINFOX4_GET ADL2_Adapter_AdapterInfoX4_Get;
|
||||
ADL2_DISPLAY_WRITEANDREADI2C ADL2_Display_WriteAndReadI2C;
|
||||
|
||||
int LoadLibraries()
|
||||
{
|
||||
HINSTANCE hDLL;
|
||||
|
||||
hDLL = LoadLibrary("atiadlxx.dll");
|
||||
|
||||
if(hDLL == NULL)
|
||||
{
|
||||
/*---------------------------------------------------------------------*\
|
||||
| A 32 bit calling application on 64 bit OS will fail to LoadLibrary. |
|
||||
| Try to load the 32 bit library (atiadlxy.dll) instead |
|
||||
\*---------------------------------------------------------------------*/
|
||||
hDLL = LoadLibrary("atiadlxy.dll");
|
||||
return ADL_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
ADL2_Main_Control_Create = (ADL2_MAIN_CONTROL_CREATE)GetProcAddress(hDLL, "ADL2_Main_Control_Create");
|
||||
ADL2_Main_Control_Destroy = (ADL2_MAIN_CONTROL_DESTROY)GetProcAddress(hDLL, "ADL2_Main_Control_Destroy");
|
||||
ADL2_Adapter_NumberOfAdapters_Get = (ADL2_ADAPTER_NUMBEROFADAPTERS_GET)GetProcAddress(hDLL, "ADL2_Adapter_NumberOfAdapters_Get");
|
||||
ADL2_Adapter_Primary_Get = (ADL2_ADAPTER_PRIMARY_GET)GetProcAddress(hDLL, "ADL2_Adapter_Primary_Get");
|
||||
ADL2_Adapter_AdapterInfoX2_Get = (ADL2_ADAPTER_ADAPTERINFOX2_GET)GetProcAddress(hDLL, "ADL2_Adapter_AdapterInfoX2_Get");
|
||||
ADL2_Adapter_AdapterInfoX4_Get = (ADL2_ADAPTER_ADAPTERINFOX4_GET)GetProcAddress(hDLL, "ADL2_Adapter_AdapterInfoX4_Get");
|
||||
ADL2_Display_WriteAndReadI2C = (ADL2_DISPLAY_WRITEANDREADI2C)GetProcAddress(hDLL, "ADL2_Display_WriteAndReadI2C");
|
||||
|
||||
/*---------------------------------------------------------------------*\
|
||||
| Only return OK if all function pointers are valid |
|
||||
\*---------------------------------------------------------------------*/
|
||||
if( ADL2_Main_Control_Create
|
||||
&& ADL2_Main_Control_Destroy
|
||||
&& ADL2_Adapter_NumberOfAdapters_Get
|
||||
&& ADL2_Adapter_Primary_Get
|
||||
&& ADL2_Adapter_AdapterInfoX2_Get
|
||||
&& ADL2_Adapter_AdapterInfoX4_Get
|
||||
&& ADL2_Display_WriteAndReadI2C)
|
||||
{
|
||||
return ADL_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ADL_ERR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Memory allocation function
|
||||
void* __stdcall ADL_Main_Memory_Alloc ( int iSize )
|
||||
{
|
||||
void* lpBuffer = malloc ( iSize );
|
||||
return lpBuffer;
|
||||
}
|
||||
|
||||
// Optional Memory de-allocation function
|
||||
void __stdcall ADL_Main_Memory_Free ( void* lpBuffer )
|
||||
{
|
||||
if ( NULL != lpBuffer )
|
||||
{
|
||||
free ( lpBuffer );
|
||||
lpBuffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
i2c_smbus_amdadl::i2c_smbus_amdadl(ADL_CONTEXT_HANDLE context, int adapter_index)
|
||||
{
|
||||
int num_of_devices;
|
||||
AdapterInfoX2* info;
|
||||
|
||||
this->context = context;
|
||||
|
||||
if (ADL_OK != ADL2_Adapter_AdapterInfoX4_Get(context, adapter_index, &num_of_devices, &info))
|
||||
{
|
||||
printf("Cannot get Adapter Info!\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string pnp_str = info->strPNPString;
|
||||
|
||||
std::size_t ven_loc = pnp_str.find("VEN_");
|
||||
std::size_t dev_loc = pnp_str.find("DEV_");
|
||||
std::size_t sub_loc = pnp_str.find("SUBSYS_");
|
||||
|
||||
if((ven_loc != std::string::npos) && (dev_loc != std::string::npos) && (sub_loc != std::string::npos))
|
||||
{
|
||||
std::string ven_str = pnp_str.substr(ven_loc + 4, 4);
|
||||
std::string dev_str = pnp_str.substr(dev_loc + 4, 4);
|
||||
std::string sbv_str = pnp_str.substr(sub_loc + 11, 4);
|
||||
std::string sbd_str = pnp_str.substr(sub_loc + 7, 4);
|
||||
|
||||
int ven_id = (int)std::stoul(ven_str, nullptr, 16);
|
||||
int dev_id = (int)std::stoul(dev_str, nullptr, 16);
|
||||
int sbv_id = (int)std::stoul(sbv_str, nullptr, 16);
|
||||
int sbd_id = (int)std::stoul(sbd_str, nullptr, 16);
|
||||
|
||||
this->pci_vendor = ven_id;
|
||||
this->pci_device = dev_id;
|
||||
this->pci_subsystem_vendor = sbv_id;
|
||||
this->pci_subsystem_device = sbd_id;
|
||||
this->port_id = 1;
|
||||
strcpy(this->device_name, "AMD ADL");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s32 i2c_smbus_amdadl::i2c_smbus_xfer(u8 addr, char read_write, u8 command, int size, i2c_smbus_data* data)
|
||||
{
|
||||
int PrimaryDisplay;
|
||||
int ret;
|
||||
int data_size = 0;
|
||||
char* data_ptr;
|
||||
|
||||
ADLI2C* pI2C;
|
||||
ADLI2C I2Cstore;
|
||||
pI2C = &I2Cstore;
|
||||
|
||||
char i2c_buf[I2C_SMBUS_BLOCK_MAX + 8];
|
||||
|
||||
pI2C->iSize = sizeof(ADLI2C);
|
||||
pI2C->iSpeed = 100;
|
||||
pI2C->iLine = 1; //location of the Aura chip
|
||||
pI2C->iAddress = addr << 1;
|
||||
pI2C->iOffset = 0;
|
||||
pI2C->pcData = (char*)data;
|
||||
|
||||
if (ADL_OK != ADL2_Adapter_Primary_Get(context, &PrimaryDisplay))
|
||||
{
|
||||
printf("Cannot get Display!\n");
|
||||
return ADL_ERR;
|
||||
}
|
||||
|
||||
switch (size)
|
||||
{
|
||||
case I2C_SMBUS_QUICK:
|
||||
//garbo data
|
||||
//pI2C->iDataSize = 0;
|
||||
return -1;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BYTE:
|
||||
//pI2C->iDataSize = 1;
|
||||
//break;
|
||||
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
data_size = 1;
|
||||
data_ptr = (char*)data;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
data_size = 2;
|
||||
data_ptr = (char*)data;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
data_size = data->block[0] + 1;
|
||||
data_ptr = (char*)&data->block[0];
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_I2C_BLOCK_DATA:
|
||||
data_size = data->block[0];
|
||||
data_ptr = (char*)&data->block[1];
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (read_write == I2C_SMBUS_READ)
|
||||
{
|
||||
/* An SMBus read can be achieved by setting the offset to the command (register address) */
|
||||
pI2C->iOffset = command;
|
||||
pI2C->iAction = ADL_DL_I2C_ACTIONREAD;
|
||||
pI2C->iDataSize = data_size;
|
||||
pI2C->pcData = (char *)data_ptr;
|
||||
|
||||
ret = ADL2_Display_WriteAndReadI2C(context, PrimaryDisplay, pI2C);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* An SMBus write has one extra byte, the register address, before the data */
|
||||
pI2C->iAction = ADL_DL_I2C_ACTIONWRITE;
|
||||
pI2C->iDataSize = data_size + 1;
|
||||
pI2C->pcData = i2c_buf;
|
||||
|
||||
i2c_buf[0] = command;
|
||||
memcpy(&i2c_buf[1], data_ptr, data_size);
|
||||
|
||||
ret = ADL2_Display_WriteAndReadI2C(context, PrimaryDisplay, pI2C);
|
||||
}
|
||||
|
||||
return(ret);
|
||||
};
|
||||
|
||||
s32 i2c_smbus_amdadl::i2c_xfer(u8 addr, char read_write, int* size, u8* data)
|
||||
{
|
||||
int PrimaryDisplay;
|
||||
int ret;
|
||||
int data_size = *size;
|
||||
|
||||
ADLI2C* pI2C;
|
||||
ADLI2C I2Cstore;
|
||||
pI2C = &I2Cstore;
|
||||
|
||||
pI2C->iSize = sizeof(ADLI2C);
|
||||
pI2C->iSpeed = 100;
|
||||
pI2C->iLine = 1; //location of the Aura chip
|
||||
pI2C->iAddress = addr << 1;
|
||||
pI2C->iOffset = 0;
|
||||
pI2C->iDataSize = data_size;
|
||||
|
||||
if (ADL_OK != ADL2_Adapter_Primary_Get(context, &PrimaryDisplay))
|
||||
{
|
||||
printf("Cannot get Display!\n");
|
||||
return ADL_ERR;
|
||||
}
|
||||
|
||||
if (read_write == I2C_SMBUS_READ)
|
||||
{
|
||||
pI2C->iAction = ADL_DL_I2C_ACTIONREAD;
|
||||
pI2C->pcData = (char*)data;
|
||||
ret = ADL2_Display_WriteAndReadI2C(context, PrimaryDisplay, pI2C);
|
||||
}
|
||||
else
|
||||
{
|
||||
pI2C->iAction = ADL_DL_I2C_ACTIONWRITE;
|
||||
pI2C->pcData = (char*)data;
|
||||
|
||||
ret = ADL2_Display_WriteAndReadI2C(context, PrimaryDisplay, pI2C);
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
bool i2c_smbus_amdadl_detect()
|
||||
{
|
||||
ADL_CONTEXT_HANDLE context;
|
||||
|
||||
if(ADL_OK == LoadLibraries())
|
||||
{
|
||||
if (ADL_OK != ADL2_Main_Control_Create(::ADL_Main_Memory_Alloc, 1, &context))
|
||||
{
|
||||
printf("Cannot get handle!\n");
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
int num_of_devices;
|
||||
AdapterInfoX2* info;
|
||||
if (ADL_OK == ADL2_Adapter_AdapterInfoX4_Get(context, -1, &num_of_devices, &info))
|
||||
{
|
||||
int last_bus_number = -1;
|
||||
for(int i = 0; i < num_of_devices; i++)
|
||||
{
|
||||
AdapterInfoX2 current = *(info + i);
|
||||
if(last_bus_number == current.iBusNumber)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
last_bus_number = current.iBusNumber;
|
||||
i2c_smbus_amdadl * adl_bus = new i2c_smbus_amdadl(context, current.iAdapterIndex);
|
||||
|
||||
if(adl_bus->pci_vendor != AMD_GPU_VEN)
|
||||
{
|
||||
delete adl_bus;
|
||||
continue;
|
||||
}
|
||||
|
||||
LOG_INFO("ADL GPU Device %04X:%04X Subsystem: %04X:%04X", adl_bus->pci_vendor, adl_bus->pci_device,adl_bus->pci_subsystem_vendor,adl_bus->pci_subsystem_device);
|
||||
ResourceManager::get()->RegisterI2CBus(adl_bus);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(true);
|
||||
} /* DetectAMDADLI2CBusses() */
|
||||
|
||||
REGISTER_I2C_BUS_DETECTOR(i2c_smbus_amdadl_detect);
|
||||
@@ -0,0 +1,37 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| i2c_smbus_amdadl.h |
|
||||
| |
|
||||
| Definitions and types for AMD ADL I2C functions |
|
||||
| |
|
||||
| Niels Westphal (crashniels) 30 May 2020 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <tchar.h>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include "i2c_smbus.h"
|
||||
#include "adl_sdk.h"
|
||||
#include "adl_defines.h"
|
||||
#include "adl_structures.h"
|
||||
#include "windows.h"
|
||||
|
||||
class i2c_smbus_amdadl : public i2c_smbus_interface
|
||||
{
|
||||
public:
|
||||
i2c_smbus_amdadl(ADL_CONTEXT_HANDLE context, int adapter_index);
|
||||
|
||||
int LoadLibraries();
|
||||
//void* __stdcall ADL_Main_Memory_Alloc ( int iSize );
|
||||
//void __stdcall ADL_Main_Memory_Free ( void* lpBuffer );
|
||||
int ADL_Initialize();
|
||||
|
||||
private:
|
||||
s32 i2c_smbus_xfer(u8 addr, char read_write, u8 command, int size, i2c_smbus_data* data);
|
||||
s32 i2c_xfer(u8 addr, char read_write, int* size, u8* data);
|
||||
ADL_CONTEXT_HANDLE context = NULL;
|
||||
};
|
||||
@@ -0,0 +1,204 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| i2c_smbus_nvapi.cpp |
|
||||
| |
|
||||
| Nvidia NvAPI I2C driver |
|
||||
| |
|
||||
| Adam Honse (CalcProgrammer1) 21 Feb 2020 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include "i2c_smbus_nvapi.h"
|
||||
|
||||
i2c_smbus_nvapi::i2c_smbus_nvapi(NV_PHYSICAL_GPU_HANDLE handle)
|
||||
{
|
||||
this->handle = handle;
|
||||
}
|
||||
|
||||
s32 i2c_smbus_nvapi::i2c_smbus_xfer(u8 addr, char read_write, u8 command, int mode, i2c_smbus_data* data)
|
||||
{
|
||||
NV_STATUS ret;
|
||||
unsigned int unknown = 0;
|
||||
NV_I2C_INFO_V3 i2c_data;
|
||||
uint8_t data_buf[I2C_SMBUS_BLOCK_MAX];
|
||||
uint8_t chip_addr;
|
||||
|
||||
// Set up chip register address to command, one byte in length
|
||||
chip_addr = command;
|
||||
i2c_data.i2c_reg_address = &chip_addr;
|
||||
i2c_data.reg_addr_size = 1;
|
||||
|
||||
// Set up data buffer, zero bytes in length
|
||||
i2c_data.data = data_buf;
|
||||
i2c_data.size = 0;
|
||||
|
||||
// Always use GPU port 1 - this is where RGB controllers are attached
|
||||
i2c_data.is_ddc_port = 0;
|
||||
i2c_data.port_id = 1;
|
||||
i2c_data.is_port_id_set = 1;
|
||||
|
||||
// Use default speed
|
||||
i2c_data.i2c_speed = 0xFFFF;
|
||||
i2c_data.i2c_speed_khz = NV_I2C_SPEED::NVAPI_I2C_SPEED_DEFAULT;
|
||||
|
||||
// Load device address
|
||||
i2c_data.i2c_dev_address = (addr << 1);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case I2C_SMBUS_BYTE:
|
||||
// One byte of data with no register address
|
||||
i2c_data.reg_addr_size = 0;
|
||||
data_buf[0] = command;
|
||||
i2c_data.size = 1;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
// One byte of data with one byte of register address
|
||||
data_buf[0] = data->byte;
|
||||
i2c_data.size = 1;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
// One word of data with one byte of register address
|
||||
data_buf[0] = (data->word & 0x00ff);
|
||||
data_buf[1] = (data->word & 0xff00) >> 8;
|
||||
i2c_data.size = 2;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
data_buf[0] = data->block[0];
|
||||
memcpy(&data_buf[1], &(data->block[1]), data->block[0]);
|
||||
i2c_data.size = data->block[0] + 1;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_I2C_BLOCK_DATA:
|
||||
memcpy(&data_buf[0], &(data->block[1]), data->block[0]);
|
||||
i2c_data.size = data->block[0];
|
||||
break;
|
||||
|
||||
// Not supported
|
||||
case I2C_SMBUS_QUICK:
|
||||
return -1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Perform read or write
|
||||
if(read_write == I2C_SMBUS_WRITE)
|
||||
{
|
||||
ret = NvAPI_I2CWriteEx(handle, &i2c_data, &unknown);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = NvAPI_I2CReadEx(handle, &i2c_data, &unknown);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case I2C_SMBUS_BYTE:
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
data->byte = i2c_data.data[0];
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
data->word = (i2c_data.data[0] | (i2c_data.data[1] << 8));
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
case I2C_SMBUS_I2C_BLOCK_DATA:
|
||||
data->block[0] = i2c_data.size;
|
||||
memcpy( &(data->block[1]), i2c_data.data, i2c_data.size);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
s32 i2c_smbus_nvapi::i2c_xfer(u8 addr, char read_write, int* size, u8* data)
|
||||
{
|
||||
NV_STATUS ret;
|
||||
unsigned int unknown = 0;
|
||||
NV_I2C_INFO_V3 i2c_data;
|
||||
|
||||
i2c_data.i2c_reg_address = NULL;
|
||||
i2c_data.reg_addr_size = 0;
|
||||
|
||||
// Set up data buffer, zero bytes in length
|
||||
i2c_data.data = data;
|
||||
i2c_data.size = *size;
|
||||
|
||||
// Always use GPU port 1 - this is where RGB controllers are attached
|
||||
i2c_data.is_ddc_port = 0;
|
||||
i2c_data.port_id = 1;
|
||||
i2c_data.is_port_id_set = 1;
|
||||
|
||||
// Use default speed
|
||||
i2c_data.i2c_speed = 0xFFFF;
|
||||
i2c_data.i2c_speed_khz = NV_I2C_SPEED::NVAPI_I2C_SPEED_DEFAULT;
|
||||
|
||||
// Load device address
|
||||
i2c_data.i2c_dev_address = (addr << 1);
|
||||
|
||||
// Perform read or write
|
||||
if(read_write == I2C_SMBUS_WRITE)
|
||||
{
|
||||
ret = NvAPI_I2CWriteEx(handle, &i2c_data, &unknown);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = NvAPI_I2CReadEx(handle, &i2c_data, &unknown);
|
||||
|
||||
*size = i2c_data.size;
|
||||
memcpy(data, i2c_data.data, i2c_data.size);
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
#include "Detector.h"
|
||||
|
||||
bool i2c_smbus_nvapi_detect()
|
||||
{
|
||||
static NV_PHYSICAL_GPU_HANDLE gpu_handles[64];
|
||||
static NV_S32 gpu_count = 0;
|
||||
NV_U32 device_id;
|
||||
NV_U32 ext_device_id;
|
||||
NV_STATUS res;
|
||||
NV_U32 revision_id;
|
||||
NV_U32 sub_system_id;
|
||||
|
||||
NvAPI_Initialize();
|
||||
|
||||
NvAPI_EnumPhysicalGPUs(gpu_handles, &gpu_count);
|
||||
|
||||
for(NV_S32 gpu_idx = 0; gpu_idx < gpu_count; gpu_idx++)
|
||||
{
|
||||
i2c_smbus_nvapi * nvapi_bus = new i2c_smbus_nvapi(gpu_handles[gpu_idx]);
|
||||
|
||||
snprintf(nvapi_bus->device_name, 512, "Nvidia NvAPI I2C on GPU %d", gpu_idx);
|
||||
|
||||
res = NvAPI_GPU_GetPCIIdentifiers(gpu_handles[gpu_idx], &device_id, &sub_system_id, &revision_id, &ext_device_id);
|
||||
|
||||
if (res == 0)
|
||||
{
|
||||
nvapi_bus->pci_device = device_id >> 16;
|
||||
nvapi_bus->pci_vendor = device_id & 0xffff;
|
||||
nvapi_bus->pci_subsystem_device = sub_system_id >> 16;
|
||||
nvapi_bus->pci_subsystem_vendor = sub_system_id & 0xffff;
|
||||
nvapi_bus->port_id = 1;
|
||||
}
|
||||
|
||||
ResourceManager::get()->RegisterI2CBus(nvapi_bus);
|
||||
}
|
||||
|
||||
return(true);
|
||||
} /* DetectNvAPII2CBusses() */
|
||||
|
||||
REGISTER_I2C_BUS_DETECTOR(i2c_smbus_nvapi_detect);
|
||||
@@ -0,0 +1,28 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| i2c_smbus_nvapi.h |
|
||||
| |
|
||||
| Nvidia NvAPI I2C driver |
|
||||
| |
|
||||
| Adam Honse (CalcProgrammer1) 21 Feb 2020 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "i2c_smbus.h"
|
||||
#include "nvapi.h"
|
||||
|
||||
class i2c_smbus_nvapi : public i2c_smbus_interface
|
||||
{
|
||||
public:
|
||||
i2c_smbus_nvapi(NV_PHYSICAL_GPU_HANDLE handle);
|
||||
s32 i2c_read_block_data(u8 addr, u8 length, u8 *values);
|
||||
s32 i2c_write_block_data(u8 addr, u8 length, u8 *values);
|
||||
|
||||
private:
|
||||
s32 i2c_smbus_xfer(u8 addr, char read_write, u8 command, int mode, i2c_smbus_data* data);
|
||||
s32 i2c_xfer(u8 addr, char read_write, int* size, u8* data);
|
||||
NV_PHYSICAL_GPU_HANDLE handle;
|
||||
};
|
||||
@@ -0,0 +1,458 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| i2c_smbus_pawnio.cpp |
|
||||
| |
|
||||
| PawnIO SMBUS driver for Windows |
|
||||
| |
|
||||
| Stephen Horvath (Steve-Tech) 04 May 2025 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <string>
|
||||
#include "Detector.h"
|
||||
#include "i2c_smbus_pawnio.h"
|
||||
#include "LogManager.h"
|
||||
#include "PawnIOLib.h"
|
||||
#include "ResourceManager.h"
|
||||
#include "SettingsManager.h"
|
||||
#include "wmi.h"
|
||||
|
||||
std::unordered_map<std::string, int> i2c_smbus_pawnio::using_handle;
|
||||
|
||||
s32 imc_index_sel(HANDLE pawnio_handle, s32 index)
|
||||
{
|
||||
const SIZE_T in_size = 1;
|
||||
ULONG64 in[in_size] = {(ULONG64)index};
|
||||
const SIZE_T out_size = 1;
|
||||
ULONG64 out[out_size];
|
||||
SIZE_T return_size;
|
||||
HRESULT status;
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Execute IMC slot_sel ioctl |
|
||||
\*-----------------------------------------------------*/
|
||||
status = pawnio_execute(pawnio_handle, "ioctl_smbus_index", in, in_size, out, 1, &return_size);
|
||||
|
||||
return(status ? -EIO : 0);
|
||||
}
|
||||
|
||||
s32 piix4_port_sel(HANDLE pawnio_handle, s32 port)
|
||||
{
|
||||
const SIZE_T in_size = 1;
|
||||
ULONG64 in[in_size] = {(ULONG64)port};
|
||||
const SIZE_T out_size = 1;
|
||||
ULONG64 out[out_size];
|
||||
SIZE_T return_size;
|
||||
HRESULT status;
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Execute PIIX4 port_sel ioctl |
|
||||
\*-----------------------------------------------------*/
|
||||
status = pawnio_execute(pawnio_handle, "ioctl_piix4_port_sel", in, in_size, out, 1, &return_size);
|
||||
|
||||
return(status ? -EIO : 0);
|
||||
}
|
||||
|
||||
s32 set_sleep_mode(HANDLE pawnio_handle, s32 sleep_mode)
|
||||
{
|
||||
const SIZE_T in_size = 1;
|
||||
ULONG64 in[in_size] = {(ULONG64)sleep_mode};
|
||||
const SIZE_T out_size = 0;
|
||||
SIZE_T return_size;
|
||||
HRESULT status;
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Execute PIIX4 port_sel ioctl |
|
||||
\*-----------------------------------------------------*/
|
||||
status = pawnio_execute(pawnio_handle, "ioctl_set_sleep_mode", in, in_size, NULL, 1, &return_size);
|
||||
|
||||
return(status ? -EIO : 0);
|
||||
}
|
||||
|
||||
i2c_smbus_pawnio::i2c_smbus_pawnio(HANDLE handle, std::string name)
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Store bus information |
|
||||
| TODO: Remove name field once all drivers use the same |
|
||||
| ioctl names |
|
||||
\*-----------------------------------------------------*/
|
||||
this->handle = handle;
|
||||
this->name = name;
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Get driver settings |
|
||||
\*-----------------------------------------------------*/
|
||||
json drivers_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("Drivers");
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Get bus information |
|
||||
\*-----------------------------------------------------*/
|
||||
const SIZE_T in_size = 1;
|
||||
ULONG64 in[in_size] = {0};
|
||||
const SIZE_T out_size = 3;
|
||||
ULONG64 out[out_size];
|
||||
SIZE_T return_size;
|
||||
HRESULT status;
|
||||
|
||||
status = pawnio_execute(handle, "ioctl_identity", in, in_size, out, out_size, &return_size);
|
||||
|
||||
if(!status)
|
||||
{
|
||||
this->pci_vendor = (int)(out[2] & 0x000000000000FFFF);
|
||||
this->pci_device = (int)((out[2] & 0x00000000FFFF0000) >> 16);
|
||||
this->pci_subsystem_vendor = (int)((out[2] & 0x0000FFFF0000FFFF) >> 32);
|
||||
this->pci_subsystem_device = (int)((out[2] & 0xFFFF000000000000) >> 48);
|
||||
|
||||
char name_str[9];
|
||||
name_str[0] = (char)(out[0] & 0x00000000000000FF);
|
||||
name_str[1] = (char)((out[0] & 0x000000000000FF00) >> 8);
|
||||
name_str[2] = (char)((out[0] & 0x0000000000FF0000) >> 16);
|
||||
name_str[3] = (char)((out[0] & 0x00000000FF000000) >> 24);
|
||||
name_str[4] = (char)((out[0] & 0x000000FF00000000) >> 32);
|
||||
name_str[5] = (char)((out[0] & 0x0000FF0000000000) >> 40);
|
||||
name_str[6] = (char)((out[0] & 0x00FF000000000000) >> 48);
|
||||
name_str[7] = (char)((out[0] & 0xFF00000000000000) >> 56);
|
||||
name_str[8] = 0;
|
||||
|
||||
strncpy(this->device_name, name_str, 512 );
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Get shared SMBus access setting |
|
||||
\*-----------------------------------------------------*/
|
||||
bool shared_smbus_access = true;
|
||||
|
||||
if(drivers_settings.contains("shared_smbus_access"))
|
||||
{
|
||||
shared_smbus_access = drivers_settings["shared_smbus_access"].get<bool>();
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Get shared SMBus access setting |
|
||||
\*-----------------------------------------------------*/
|
||||
unsigned int smbus_sleep_mode = PAWNIO_SLEEPMODE_ALWAYSSLEEP;
|
||||
|
||||
if(drivers_settings.contains("smbus_sleep_mode"))
|
||||
{
|
||||
smbus_sleep_mode = drivers_settings["smbus_sleep_mode"];
|
||||
}
|
||||
|
||||
if(smbus_sleep_mode >= PAWNIO_SLEEPMODE_MAX)
|
||||
{
|
||||
smbus_sleep_mode = PAWNIO_SLEEPMODE_ALWAYSSLEEP;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Initialize sleep mode |
|
||||
\*-----------------------------------------------------*/
|
||||
set_sleep_mode(handle, smbus_sleep_mode);
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Create global SMBus mutex if enabled |
|
||||
\*-----------------------------------------------------*/
|
||||
if(shared_smbus_access)
|
||||
{
|
||||
global_smbus_access_handle = CreateMutexA(NULL, FALSE, GLOBAL_SMBUS_MUTEX_NAME);
|
||||
}
|
||||
|
||||
using_handle[name]++;
|
||||
}
|
||||
|
||||
i2c_smbus_pawnio::~i2c_smbus_pawnio()
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Close global SMBus mutex |
|
||||
\*-----------------------------------------------------*/
|
||||
if(global_smbus_access_handle != NULL)
|
||||
{
|
||||
CloseHandle(global_smbus_access_handle);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| TODO: find a way to do this without name field |
|
||||
\*-----------------------------------------------------*/
|
||||
if(--using_handle[name] == 0 && pawnio_close(handle))
|
||||
{
|
||||
LOG_ERROR("PawnIO failed to close");
|
||||
}
|
||||
}
|
||||
|
||||
s32 i2c_smbus_pawnio::i2c_smbus_xfer(u8 addr, char read_write, u8 command, int size, i2c_smbus_data* data)
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Lock SMBus mutex |
|
||||
\*-----------------------------------------------------*/
|
||||
if(global_smbus_access_handle != NULL)
|
||||
{
|
||||
WaitForSingleObject(global_smbus_access_handle, INFINITE);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Pack input data |
|
||||
\*-----------------------------------------------------*/
|
||||
const SIZE_T in_size = 9;
|
||||
ULONG64 in[in_size];
|
||||
const SIZE_T out_size = 5;
|
||||
ULONG64 out[out_size];
|
||||
SIZE_T return_size;
|
||||
HRESULT status;
|
||||
|
||||
in[0] = addr;
|
||||
in[1] = read_write;
|
||||
in[2] = command;
|
||||
in[3] = size;
|
||||
|
||||
if(data != NULL)
|
||||
{
|
||||
memcpy( &in[4], data, sizeof(i2c_smbus_data));
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Perform SMBus transfer |
|
||||
\*-----------------------------------------------------*/
|
||||
status = pawnio_execute(handle, "ioctl_smbus_xfer", in, in_size, out, out_size, &return_size);
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Unpack output data |
|
||||
\*-----------------------------------------------------*/
|
||||
if(data != NULL)
|
||||
{
|
||||
memcpy( data, &out[0], sizeof(i2c_smbus_data));
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Unlock SMBus mutex |
|
||||
\*-----------------------------------------------------*/
|
||||
if(global_smbus_access_handle != NULL)
|
||||
{
|
||||
ReleaseMutex(global_smbus_access_handle);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| If the PawnIO driver returned an error, convert it to |
|
||||
| the appropriate i2c_smbus error instead |
|
||||
\*-----------------------------------------------------*/
|
||||
if(status != 0)
|
||||
{
|
||||
status = -1;
|
||||
}
|
||||
|
||||
return(status);
|
||||
}
|
||||
|
||||
s32 i2c_smbus_pawnio::i2c_xfer(u8 /*addr*/, char /*read_write*/, int* /*size*/, u8* /*data*/)
|
||||
{
|
||||
return(-1);
|
||||
}
|
||||
|
||||
HRESULT i2c_smbus_pawnio::start_pawnio(std::string filename, PHANDLE phandle)
|
||||
{
|
||||
char exePath[MAX_PATH];
|
||||
HANDLE handle;
|
||||
HRESULT status;
|
||||
|
||||
LOG_INFO("Start PawnIO: %s", filename.c_str());
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Get the path of the executable |
|
||||
\*-----------------------------------------------------*/
|
||||
if(!GetModuleFileNameA(NULL, exePath, MAX_PATH))
|
||||
{
|
||||
LOG_ERROR("Failed to get executable path, PawnIO initialization aborted");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Construct the path to `filename` in the executable's |
|
||||
| directory |
|
||||
\*-----------------------------------------------------*/
|
||||
std::filesystem::path exeDir = std::filesystem::path(exePath).parent_path();
|
||||
std::filesystem::path filePath = exeDir / filename;
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Check if the file exists |
|
||||
\*-----------------------------------------------------*/
|
||||
if(!std::filesystem::exists(filePath))
|
||||
{
|
||||
LOG_ERROR("Failed to find %s in the executable's directory, PawnIO initialization aborted", filename.c_str());
|
||||
return(E_FAIL);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Open the file |
|
||||
\*-----------------------------------------------------*/
|
||||
std::ifstream file(filePath, std::ios::binary);
|
||||
|
||||
if(!file.is_open())
|
||||
{
|
||||
LOG_ERROR("Failed to open %s, PawnIO initialization aborted", filename.c_str());
|
||||
return(E_FAIL);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Read the contents of the file into a vector of bytes |
|
||||
\*-----------------------------------------------------*/
|
||||
std::vector<char> blob((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Close the file |
|
||||
\*-----------------------------------------------------*/
|
||||
file.close();
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Open PawnIO driver |
|
||||
\*-----------------------------------------------------*/
|
||||
status = pawnio_open(phandle);
|
||||
|
||||
if(status)
|
||||
{
|
||||
if(status == E_ACCESSDENIED)
|
||||
{
|
||||
LOG_ERROR("Permission Denied, PawnIO initialization aborted");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Could not open PawnIO, PawnIO initialization aborted");
|
||||
}
|
||||
|
||||
return(status);
|
||||
}
|
||||
|
||||
handle = *phandle;
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Load the file into PawnIO |
|
||||
\*-----------------------------------------------------*/
|
||||
status = pawnio_load(handle, reinterpret_cast<const UCHAR*>(blob.data()), blob.size());
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Check if the load was successful |
|
||||
\*-----------------------------------------------------*/
|
||||
if(status)
|
||||
{
|
||||
pawnio_close(handle);
|
||||
|
||||
if (status == HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED))
|
||||
{
|
||||
LOG_INFO("PawnIO module initialization aborted (unsupported)");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("PawnIO module initialization aborted (code=%ld)", status);
|
||||
}
|
||||
|
||||
return(status);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Log a message and return OK if PawnIO successfully |
|
||||
| opened |
|
||||
\*-----------------------------------------------------*/
|
||||
LOG_INFO("PawnIO initialized successully");
|
||||
return(S_OK);
|
||||
}
|
||||
|
||||
bool i2c_smbus_pawnio_detect()
|
||||
{
|
||||
ULONG dll_version;
|
||||
if(pawnio_version(&dll_version))
|
||||
{
|
||||
LOG_INFO("PawnIO is not loaded, PawnIO I2C bus detection aborted");
|
||||
return(false);
|
||||
}
|
||||
|
||||
i2c_smbus_interface * bus;
|
||||
HANDLE pawnio_handle;
|
||||
bool bus_detected;
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Set the detected flag to false, successfully |
|
||||
| any bus will result in a successful return status |
|
||||
\*-----------------------------------------------------*/
|
||||
bus_detected = false;
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Try to load Intel (i801) SMBus driver |
|
||||
\*-----------------------------------------------------*/
|
||||
if(i2c_smbus_pawnio::start_pawnio("SmbusI801.bin", &pawnio_handle) == S_OK)
|
||||
{
|
||||
bus_detected = true;
|
||||
|
||||
bus = new i2c_smbus_pawnio(pawnio_handle, "i801");
|
||||
ResourceManager::get()->RegisterI2CBus(bus);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Try to load AMD (PIIX4) SMBus driver - primary bus |
|
||||
\*-----------------------------------------------------*/
|
||||
if(i2c_smbus_pawnio::start_pawnio("SmbusPIIX4.bin", &pawnio_handle) == S_OK)
|
||||
{
|
||||
bus_detected = true;
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| Select port 0 |
|
||||
\*-------------------------------------------------*/
|
||||
piix4_port_sel(pawnio_handle, 0);
|
||||
|
||||
bus = new i2c_smbus_pawnio(pawnio_handle, "piix4");
|
||||
ResourceManager::get()->RegisterI2CBus(bus);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Try to load AMD (PIIX4 SMBus driver - secondary bus |
|
||||
\*-----------------------------------------------------*/
|
||||
if(i2c_smbus_pawnio::start_pawnio("SmbusPIIX4.bin", &pawnio_handle) == S_OK)
|
||||
{
|
||||
bus_detected = true;
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| Select port 1 |
|
||||
\*-------------------------------------------------*/
|
||||
piix4_port_sel(pawnio_handle, 1);
|
||||
|
||||
bus = new i2c_smbus_pawnio(pawnio_handle, "piix4");
|
||||
ResourceManager::get()->RegisterI2CBus(bus);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Try to load Nuvoton (NCT6793) SMBus driver |
|
||||
\*-----------------------------------------------------*/
|
||||
if(i2c_smbus_pawnio::start_pawnio("SmbusNCT6793.bin", &pawnio_handle) == S_OK)
|
||||
{
|
||||
bus_detected = true;
|
||||
|
||||
bus = new i2c_smbus_pawnio(pawnio_handle, "NCT6793");
|
||||
ResourceManager::get()->RegisterI2CBus(bus);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Try to load Intel Skylake IMC SMBus driver |
|
||||
\*-----------------------------------------------------*/
|
||||
if(i2c_smbus_pawnio::start_pawnio("SmbusIntelSkylakeIMC.bin", &pawnio_handle) == S_OK)
|
||||
{
|
||||
bus_detected = true;
|
||||
|
||||
imc_index_sel(pawnio_handle, 0);
|
||||
|
||||
bus = new i2c_smbus_pawnio(pawnio_handle, "Intel Skylake IMC");
|
||||
ResourceManager::get()->RegisterI2CBus(bus);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Try to load Intel Skylake IMC SMBus driver |
|
||||
\*-----------------------------------------------------*/
|
||||
if(i2c_smbus_pawnio::start_pawnio("SmbusIntelSkylakeIMC.bin", &pawnio_handle) == S_OK)
|
||||
{
|
||||
bus_detected = true;
|
||||
|
||||
imc_index_sel(pawnio_handle, 1);
|
||||
|
||||
bus = new i2c_smbus_pawnio(pawnio_handle, "Intel Skylake IMC");
|
||||
ResourceManager::get()->RegisterI2CBus(bus);
|
||||
}
|
||||
|
||||
return(bus_detected);
|
||||
}
|
||||
|
||||
REGISTER_I2C_BUS_DETECTOR(i2c_smbus_pawnio_detect);
|
||||
@@ -0,0 +1,50 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| i2c_smbus_piix4_pawnio.h |
|
||||
| |
|
||||
| PawnIO PIIX4 SMBUS driver for Windows |
|
||||
| |
|
||||
| Stephen Horvath (Steve-Tech) 21 Apr 2025 |
|
||||
| Based on original OpenRGB PIIX4 source code |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "windows.h"
|
||||
|
||||
#include "i2c_smbus.h"
|
||||
|
||||
#define GLOBAL_SMBUS_MUTEX_NAME "Global\\Access_SMBUS.HTP.Method"
|
||||
|
||||
enum
|
||||
{
|
||||
PAWNIO_SLEEPMODE_ALWAYSBUSY = 0,
|
||||
PAWNIO_SLEEPMODE_SHORTBUSY = 1,
|
||||
PAWNIO_SLEEPMODE_ALWAYSSLEEP = 2,
|
||||
PAWNIO_SLEEPMODE_MAX
|
||||
};
|
||||
|
||||
class i2c_smbus_pawnio : public i2c_smbus_interface
|
||||
{
|
||||
public:
|
||||
static std::unordered_map<std::string, int> using_handle;
|
||||
i2c_smbus_pawnio(HANDLE handle, std::string name);
|
||||
~i2c_smbus_pawnio();
|
||||
|
||||
static HRESULT start_pawnio(std::string filename, PHANDLE phandle);
|
||||
|
||||
private:
|
||||
s32 pawnio_read(u8 addr, char read_write, u8 command, int size, i2c_smbus_data *data);
|
||||
s32 pawnio_write(u8 addr, char read_write, u8 command, int size, i2c_smbus_data *data);
|
||||
s32 i2c_smbus_xfer(u8 addr, char read_write, u8 command, int size, i2c_smbus_data* data);
|
||||
s32 i2c_xfer(u8 addr, char read_write, int* size, u8* data);
|
||||
|
||||
HANDLE global_smbus_access_handle;
|
||||
std::string name;
|
||||
HANDLE handle;
|
||||
};
|
||||
Reference in New Issue
Block a user