diff --git a/OpenAuraSDK.sln b/OpenAuraSDK.sln new file mode 100644 index 00000000..efc9459c --- /dev/null +++ b/OpenAuraSDK.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27703.2026 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenAuraSDK", "OpenAuraSDK\OpenAuraSDK.vcxproj", "{6D22BFF3-C1DF-407A-8816-05D63919A991}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6D22BFF3-C1DF-407A-8816-05D63919A991}.Debug|x64.ActiveCfg = Debug|x64 + {6D22BFF3-C1DF-407A-8816-05D63919A991}.Debug|x64.Build.0 = Debug|x64 + {6D22BFF3-C1DF-407A-8816-05D63919A991}.Debug|x86.ActiveCfg = Debug|Win32 + {6D22BFF3-C1DF-407A-8816-05D63919A991}.Debug|x86.Build.0 = Debug|Win32 + {6D22BFF3-C1DF-407A-8816-05D63919A991}.Release|x64.ActiveCfg = Release|x64 + {6D22BFF3-C1DF-407A-8816-05D63919A991}.Release|x64.Build.0 = Release|x64 + {6D22BFF3-C1DF-407A-8816-05D63919A991}.Release|x86.ActiveCfg = Release|Win32 + {6D22BFF3-C1DF-407A-8816-05D63919A991}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A2BB3E13-D506-413D-900E-F2B1323B3BB3} + EndGlobalSection +EndGlobal diff --git a/OpenAuraSDK/AuraController.cpp b/OpenAuraSDK/AuraController.cpp new file mode 100644 index 00000000..8319df4a --- /dev/null +++ b/OpenAuraSDK/AuraController.cpp @@ -0,0 +1,40 @@ +/*-----------------------------------------*\ +| AuraController.h | +| | +| Driver for ASUS Aura RGB lighting | +| controller | +| | +| Adam Honse (CalcProgrammer1) 8/19/2018 | +\*-----------------------------------------*/ + +#include "AuraController.h" + +unsigned char AuraController::AuraRegisterRead(aura_register reg) +{ + //Write Aura register + bus->i2c_smbus_write_word_data(dev, 0x00, ((reg << 8) & 0xFF00) | ((reg >> 8) & 0x00FF)); + + //Read Aura value + return(bus->i2c_smbus_read_byte_data(dev, 0x81)); + +} + +void AuraController::AuraRegisterWrite(aura_register reg, unsigned char val) +{ + //Write Aura register + bus->i2c_smbus_write_word_data(dev, 0x00, ((reg << 8) & 0xFF00) | ((reg >> 8) & 0x00FF)); + + //Write Aura value + bus->i2c_smbus_write_byte_data(dev, 0x01, val); + +} + +void AuraController::AuraRegisterWriteBlock(aura_register reg, unsigned char * data, unsigned char sz) +{ + //Write Aura register (0x8000 for colors) + bus->i2c_smbus_write_word_data(dev, 0x00, ((reg << 8) & 0xFF00) | ((reg >> 8) & 0x00FF)); + + //Write Aura block data + bus->i2c_smbus_write_block_data(dev, 0x03, 15, data); + +} \ No newline at end of file diff --git a/OpenAuraSDK/AuraController.h b/OpenAuraSDK/AuraController.h new file mode 100644 index 00000000..626efcee --- /dev/null +++ b/OpenAuraSDK/AuraController.h @@ -0,0 +1,58 @@ +/*-----------------------------------------*\ +| AuraController.h | +| | +| Definitions and types for ASUS Aura RGB | +| lighting controller | +| | +| Adam Honse (CalcProgrammer1) 8/19/2018 | +\*-----------------------------------------*/ + +#include "i2c_smbus.h" + +#pragma once + +typedef unsigned char aura_dev_id; +typedef unsigned short aura_register; + +#define AURA_APPLY_VAL 0x01 /* Value for Apply Changes Register */ + +enum +{ + AURA_REG_COLORS_DIRECT = 0x8000, /* Colors for Direct Mode 15 bytes */ + AURA_REG_COLORS_EFFECT = 0x8010, /* Colors for Internal Effects 15 bytes */ + AURA_REG_DIRECT = 0x8020, /* "Direct Access" Selection Register */ + AURA_REG_MODE = 0x8021, /* AURA Mode Selection Register */ + AURA_REG_APPLY = 0x80A0 /* AURA Apply Changes Register */ +}; + +enum +{ + AURA_MODE_OFF = 0, /* OFF mode */ + AURA_MODE_STATIC = 1, /* Static color mode */ + AURA_MODE_BREATHING = 2, /* Breathing effect mode */ + AURA_MODE_FLASHING = 3, /* Flashing effect mode */ + AURA_MODE_SPECTRUM_CYCLE = 4, /* Spectrum Cycle mode */ + AURA_MODE_RAINBOW = 5, /* Rainbow effect mode */ + AURA_MODE_SPECTRUM_CYCLE_BREATHING = 6, /* Rainbow Breathing effect mode */ + AURA_MODE_CHASE_FADE = 7, /* Chase with Fade effect mode */ + AURA_MODE_SPECTRUM_CYCLE_CHASE_FADE = 8, /* Chase with Fade, Rainbow effect mode */ + AURA_MODE_CHASE = 9, /* Chase effect mode */ + AURA_MODE_SPECTRUM_CYCLE_CHASE = 10, /* Chase with Rainbow effect mode */ + AURA_MODE_SPECTRUM_CYCLE_WAVE = 11, /* Wave effect mode */ + AURA_MODE_CHASE_RAINBOW_PULSE = 12, /* Chase with Rainbow Pulse effect mode*/ + AURA_MODE_RANDOM_FLICKER = 13, /* Random flicker effect mode */ +}; + +class AuraController +{ +public: + unsigned char AuraRegisterRead(aura_register reg); + void AuraRegisterWrite(aura_register reg, unsigned char val); + void AuraRegisterWriteBlock(aura_register reg, unsigned char * data, unsigned char sz); + i2c_smbus_interface * bus; + aura_dev_id dev; + +private: + + +}; \ No newline at end of file diff --git a/OpenAuraSDK/OpenAuraSDK.cpp b/OpenAuraSDK/OpenAuraSDK.cpp new file mode 100644 index 00000000..711a178e Binary files /dev/null and b/OpenAuraSDK/OpenAuraSDK.cpp differ diff --git a/OpenAuraSDK/OpenAuraSDK.h b/OpenAuraSDK/OpenAuraSDK.h new file mode 100644 index 00000000..3f8cb34b --- /dev/null +++ b/OpenAuraSDK/OpenAuraSDK.h @@ -0,0 +1,10 @@ +#pragma once + +typedef unsigned int AuraBusDriverType; + +enum +{ + I2C_DRIVER_SMBUS_PIIX4, + I2C_DRIVER_SMBUS_I801, + NUM_I2C_DRIVERS +}; \ No newline at end of file diff --git a/OpenAuraSDK/OpenAuraSDK.vcxproj b/OpenAuraSDK/OpenAuraSDK.vcxproj new file mode 100644 index 00000000..351f9daa --- /dev/null +++ b/OpenAuraSDK/OpenAuraSDK.vcxproj @@ -0,0 +1,186 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {6D22BFF3-C1DF-407A-8816-05D63919A991} + Win32Proj + OpenAuraSDK + 10.0.17134.0 + + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + .exe + + + true + .exe + + + false + .exe + + + false + .exe + + + + NotUsing + Level3 + Disabled + true + WIN32;_DEBUG;OPENAURASDK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS + true + ..\dependencies\inpout32_1501\Win32;%(AdditionalIncludeDirectories) + true + + + + + Windows + true + ..\dependencies\inpout32_1501\Win32;%(AdditionalLibraryDirectories) + + + + + NotUsing + Level3 + Disabled + true + _DEBUG;OPENAURASDK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS + true + + + + + Windows + true + + + + + NotUsing + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;OPENAURASDK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS + true + ..\dependencies\inpout32_1501\Win32;%(AdditionalIncludeDirectories) + true + + + + + Windows + true + true + true + ..\dependencies\inpout32_1501\Win32;%(AdditionalLibraryDirectories) + + + + + NotUsing + Level3 + MaxSpeed + true + true + true + NDEBUG;OPENAURASDK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS + true + + + + + Windows + true + true + true + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OpenAuraSDK/OpenAuraSDK.vcxproj.filters b/OpenAuraSDK/OpenAuraSDK.vcxproj.filters new file mode 100644 index 00000000..d7d7b34d --- /dev/null +++ b/OpenAuraSDK/OpenAuraSDK.vcxproj.filters @@ -0,0 +1,57 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/OpenAuraSDK/dllmain.cpp b/OpenAuraSDK/dllmain.cpp new file mode 100644 index 00000000..44c1a0c4 Binary files /dev/null and b/OpenAuraSDK/dllmain.cpp differ diff --git a/OpenAuraSDK/i2c_smbus.cpp b/OpenAuraSDK/i2c_smbus.cpp new file mode 100644 index 00000000..c0ae78b5 --- /dev/null +++ b/OpenAuraSDK/i2c_smbus.cpp @@ -0,0 +1,121 @@ +#include "i2c_smbus.h" + +s32 i2c_smbus_interface::i2c_smbus_write_quick(u8 addr, u8 value) +{ + return i2c_smbus_xfer(addr, value, 0, I2C_SMBUS_QUICK, NULL); +} + +s32 i2c_smbus_interface::i2c_smbus_read_byte(u8 addr) +{ + i2c_smbus_data data; + if (i2c_smbus_xfer(addr, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data)) + { + return -1; + } + else + { + return data.byte; + } +} + +s32 i2c_smbus_interface::i2c_smbus_write_byte(u8 addr, u8 value) +{ + return i2c_smbus_xfer(addr, I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL); +} + +s32 i2c_smbus_interface::i2c_smbus_read_byte_data(u8 addr, u8 command) +{ + i2c_smbus_data data; + if (i2c_smbus_xfer(addr, I2C_SMBUS_READ, command, I2C_SMBUS_BYTE_DATA, &data)) + { + return -1; + } + else + { + return data.byte; + } +} + +s32 i2c_smbus_interface::i2c_smbus_write_byte_data(u8 addr, u8 command, u8 value) +{ + i2c_smbus_data data; + data.byte = value; + return i2c_smbus_xfer(addr, I2C_SMBUS_WRITE, command, I2C_SMBUS_BYTE_DATA, &data); +} + +s32 i2c_smbus_interface::i2c_smbus_read_word_data(u8 addr, u8 command) +{ + i2c_smbus_data data; + if (i2c_smbus_xfer(addr, I2C_SMBUS_READ, command, I2C_SMBUS_WORD_DATA, &data)) + { + return -1; + } + else + { + return data.word; + } +} + +s32 i2c_smbus_interface::i2c_smbus_write_word_data(u8 addr, u8 command, u16 value) +{ + i2c_smbus_data data; + data.word = value; + return i2c_smbus_xfer(addr, I2C_SMBUS_WRITE, command, I2C_SMBUS_WORD_DATA, &data); +} + +s32 i2c_smbus_interface::i2c_smbus_read_block_data(u8 addr, u8 command, u8 *values) +{ + i2c_smbus_data data; + if (i2c_smbus_xfer(addr, I2C_SMBUS_READ, command, I2C_SMBUS_BLOCK_DATA, &data)) + { + return -1; + } + else + { + memcpy(values, &data.block[1], data.block[0]); + return data.block[0]; + } +} + +s32 i2c_smbus_interface::i2c_smbus_write_block_data(u8 addr, u8 command, u8 length, const u8 *values) +{ + i2c_smbus_data data; + if (length > I2C_SMBUS_BLOCK_MAX) + { + length = I2C_SMBUS_BLOCK_MAX; + } + data.block[0] = length; + memcpy(&data.block[1], values, length); + return i2c_smbus_xfer(addr, I2C_SMBUS_WRITE, command, I2C_SMBUS_BLOCK_DATA, &data); +} + +s32 i2c_smbus_interface::i2c_smbus_read_i2c_block_data(u8 addr, u8 command, u8 length, u8 *values) +{ + i2c_smbus_data data; + if (length > I2C_SMBUS_BLOCK_MAX) + { + length = I2C_SMBUS_BLOCK_MAX; + } + data.block[0] = length; + if (i2c_smbus_xfer(addr, I2C_SMBUS_READ, command, I2C_SMBUS_I2C_BLOCK_DATA, &data)) + { + return -1; + } + else + { + memcpy(values, &data.block[1], data.block[0]); + return data.block[0]; + } +} + +s32 i2c_smbus_interface::i2c_smbus_write_i2c_block_data(u8 addr, u8 command, u8 length, const u8 *values) +{ + i2c_smbus_data data; + if (length > I2C_SMBUS_BLOCK_MAX) + { + length = I2C_SMBUS_BLOCK_MAX; + } + data.block[0] = length; + memcpy(&data.block[1], values, length); + return i2c_smbus_xfer(addr, I2C_SMBUS_WRITE, command, I2C_SMBUS_I2C_BLOCK_DATA, &data); +} \ No newline at end of file diff --git a/OpenAuraSDK/i2c_smbus.h b/OpenAuraSDK/i2c_smbus.h new file mode 100644 index 00000000..e1d5e016 --- /dev/null +++ b/OpenAuraSDK/i2c_smbus.h @@ -0,0 +1,67 @@ +/*-----------------------------------------*\ +| i2c_smbus.h | +| | +| Definitions and types for SMBUS drivers | +| | +| Adam Honse (CalcProgrammer1) 8/8/2018 | +| Portions based on Linux source code | +| GNU GPL v2 | +\*-----------------------------------------*/ + +#include +#include +#include +#include "inpout32.h" + +typedef UINT8 u8; +typedef UINT16 u16; +typedef UINT32 uint32_t; +typedef INT32 s32; + +#pragma comment(lib, "inpout32.lib") +#pragma once + +//Data for SMBus Messages +#define I2C_SMBUS_BLOCK_MAX 32 + +union i2c_smbus_data +{ + u8 byte; + u16 word; + u8 block[I2C_SMBUS_BLOCK_MAX + 2]; +}; + +// i2c_smbus_xfer read or write markers +#define I2C_SMBUS_READ 1 +#define I2C_SMBUS_WRITE 0 + +// SMBus transaction types (size parameter in the above functions) +#define I2C_SMBUS_QUICK 0 +#define I2C_SMBUS_BYTE 1 +#define I2C_SMBUS_BYTE_DATA 2 +#define I2C_SMBUS_WORD_DATA 3 +#define I2C_SMBUS_PROC_CALL 4 +#define I2C_SMBUS_BLOCK_DATA 5 +#define I2C_SMBUS_I2C_BLOCK_BROKEN 6 +#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */ +#define I2C_SMBUS_I2C_BLOCK_DATA 8 + +class i2c_smbus_interface +{ +public: + //Functions derived from i2c-core.c + s32 i2c_smbus_write_quick(u8 addr, u8 value); + s32 i2c_smbus_read_byte(u8 addr); + s32 i2c_smbus_write_byte(u8 addr, u8 value); + s32 i2c_smbus_read_byte_data(u8 addr, u8 command); + s32 i2c_smbus_write_byte_data(u8 addr, u8 command, u8 value); + s32 i2c_smbus_read_word_data(u8 addr, u8 command); + s32 i2c_smbus_write_word_data(u8 addr, u8 command, u16 value); + s32 i2c_smbus_read_block_data(u8 addr, u8 command, u8 *values); + s32 i2c_smbus_write_block_data(u8 addr, u8 command, u8 length, const u8 *values); + s32 i2c_smbus_read_i2c_block_data(u8 addr, u8 command, u8 length, u8 *values); + s32 i2c_smbus_write_i2c_block_data(u8 addr, u8 command, u8 length, const u8 *values); + + //Virtual function to be implemented by the driver + virtual s32 i2c_smbus_xfer(u8 addr, char read_write, u8 command, int size, i2c_smbus_data* data) = 0; +}; \ No newline at end of file diff --git a/OpenAuraSDK/i2c_smbus_i801.cpp b/OpenAuraSDK/i2c_smbus_i801.cpp new file mode 100644 index 00000000..267fc6bf --- /dev/null +++ b/OpenAuraSDK/i2c_smbus_i801.cpp @@ -0,0 +1,478 @@ +/*-----------------------------------------*\ +| i2c_smbus_i801.cpp | +| | +| i801 SMBUS driver for Windows | +| | +| Adam Honse (CalcProgrammer1) 1/29/2019 | +| Portions based on Linux source code | +| GNU GPL v2 | +\*-----------------------------------------*/ + +#include "i2c_smbus_i801.h" + +/* Return negative errno on error. */ +s32 i2c_smbus_i801::i801_access(u16 addr, char read_write, u8 command, int size, i2c_smbus_data *data) +{ + int hwpec = 0; + int block = 0; + int ret = 0, xact = 0; + //struct i801_priv *priv = i2c_get_adapdata(adap); + + //mutex_lock(&priv->acpi_lock); + //if (priv->acpi_reserved) { + // mutex_unlock(&priv->acpi_lock); + // return -EBUSY; + //} + + //pm_runtime_get_sync(&priv->pci_dev->dev); + + //hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC) + // && size != I2C_SMBUS_QUICK + // && size != I2C_SMBUS_I2C_BLOCK_DATA; + + switch (size) + { + case I2C_SMBUS_QUICK: + Out32(SMBHSTADD, ((addr & 0x7f) << 1) | (read_write & 0x01)); + xact = I801_QUICK; + break; + case I2C_SMBUS_BYTE: + Out32(SMBHSTADD, ((addr & 0x7f) << 1) | (read_write & 0x01)); + if (read_write == I2C_SMBUS_WRITE) + Out32(SMBHSTCMD, command); + xact = I801_BYTE; + break; + case I2C_SMBUS_BYTE_DATA: + Out32(SMBHSTADD, ((addr & 0x7f) << 1) | (read_write & 0x01)); + Out32(SMBHSTCMD, command); + if (read_write == I2C_SMBUS_WRITE) + Out32(SMBHSTDAT0, data->byte); + xact = I801_BYTE_DATA; + break; + case I2C_SMBUS_WORD_DATA: + Out32(SMBHSTADD, ((addr & 0x7f) << 1) | (read_write & 0x01)); + Out32(SMBHSTCMD, command); + if (read_write == I2C_SMBUS_WRITE) + { + Out32(SMBHSTDAT0, data->word & 0xff); + Out32(SMBHSTDAT1, (data->word & 0xff00) >> 8); + } + xact = I801_WORD_DATA; + break; + case I2C_SMBUS_BLOCK_DATA: + Out32(SMBHSTADD, ((addr & 0x7f) << 1) | (read_write & 0x01)); + Out32(SMBHSTCMD, command); + block = 1; + break; + case I2C_SMBUS_I2C_BLOCK_DATA: + /* + * NB: page 240 of ICH5 datasheet shows that the R/#W + * bit should be cleared here, even when reading. + * However if SPD Write Disable is set (Lynx Point and later), + * the read will fail if we don't set the R/#W bit. + */ + Out32(SMBHSTADD, ((addr & 0x7f) << 1) | (read_write & 0x01)); + + if (read_write == I2C_SMBUS_READ) + { + /* NB: page 240 of ICH5 datasheet also shows + * that DATA1 is the cmd field when reading */ + Out32(SMBHSTDAT1, command); + } + else + { + Out32(SMBHSTCMD, command); + } + block = 1; + break; + default: + ret = -EOPNOTSUPP; + goto out; + } + + //if (hwpec) /* enable/disable hardware PEC */ + // outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv)); + //else + // outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC), + // SMBAUXCTL(priv)); + + if (block) + ret = i801_block_transaction(data, read_write, size, hwpec); + else + ret = i801_transaction(xact); + + /* Some BIOSes don't like it when PEC is enabled at reboot or resume + time, so we forcibly disable it after every transaction. Turn off + E32B for the same reason. */ + //if (hwpec || block) + // outb_p(inb_p(SMBAUXCTL(priv)) & + // ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv)); + + if (block) + goto out; + if (ret) + goto out; + if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK)) + goto out; + + switch (xact & 0x7f) + { + case I801_BYTE: /* Result put in SMBHSTDAT0 */ + case I801_BYTE_DATA: + data->byte = Inp32(SMBHSTDAT0); + break; + case I801_WORD_DATA: + data->word = Inp32(SMBHSTDAT0) + (Inp32(SMBHSTDAT1) << 8); + break; + } + +out: + //pm_runtime_mark_last_busy(&priv->pci_dev->dev); + //pm_runtime_put_autosuspend(&priv->pci_dev->dev); + //mutex_unlock(&priv->acpi_lock); + return ret; +} + +/* Block transaction function */ +int i2c_smbus_i801::i801_block_transaction(i2c_smbus_data *data, char read_write, int command, int hwpec) +{ + int result = 0; + unsigned char hostc; + + //if (command == I2C_SMBUS_I2C_BLOCK_DATA) + //{ + // if (read_write == I2C_SMBUS_WRITE) + // { + // /* set I2C_EN bit in configuration register */ + // pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc); + // pci_write_config_byte(priv->pci_dev, SMBHSTCFG, + // hostc | SMBHSTCFG_I2C_EN); + // } + // else if (!(priv->features & FEATURE_I2C_BLOCK_READ)) { + // dev_err(&priv->pci_dev->dev, + // "I2C block read is unsupported!\n"); + // return -EOPNOTSUPP; + // } + //} + + if (read_write == I2C_SMBUS_WRITE || command == I2C_SMBUS_I2C_BLOCK_DATA) + { + if (data->block[0] < 1) + data->block[0] = 1; + if (data->block[0] > I2C_SMBUS_BLOCK_MAX) + data->block[0] = I2C_SMBUS_BLOCK_MAX; + } + else + { + data->block[0] = 32; /* max for SMBus block reads */ + } + + /* Experience has shown that the block buffer can only be used for + SMBus (not I2C) block transactions, even though the datasheet + doesn't mention this limitation. */ + //if ((priv->features & FEATURE_BLOCK_BUFFER) + // && command != I2C_SMBUS_I2C_BLOCK_DATA + // && i801_set_block_buffer_mode(priv) == 0) + // result = i801_block_transaction_by_block(priv, data, + // read_write, hwpec); + //else + result = i801_block_transaction_byte_by_byte(data, read_write, command, hwpec); + + //if (command == I2C_SMBUS_I2C_BLOCK_DATA + // && read_write == I2C_SMBUS_WRITE) { + // /* restore saved configuration register value */ + // pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc); + //} + return result; +} + +/* +* For "byte-by-byte" block transactions: +* I2C write uses cmd=I801_BLOCK_DATA, I2C_EN=1 +* I2C read uses cmd=I801_I2C_BLOCK_DATA +*/ +int i2c_smbus_i801::i801_block_transaction_byte_by_byte(i2c_smbus_data *data, char read_write, int command, int hwpec) +{ + int i, len; + int smbcmd; + int status; + int result; + + result = i801_check_pre(); + if (result < 0) + return result; + + len = data->block[0]; + + if (read_write == I2C_SMBUS_WRITE) + { + Out32(SMBHSTDAT0, len); + Out32(SMBBLKDAT, data->block[1]); + } + + if (command == I2C_SMBUS_I2C_BLOCK_DATA && read_write == I2C_SMBUS_READ) + smbcmd = I801_I2C_BLOCK_DATA; + else + smbcmd = I801_BLOCK_DATA; + + //if (priv->features & FEATURE_IRQ) { + // priv->is_read = (read_write == I2C_SMBUS_READ); + // if (len == 1 && priv->is_read) + // smbcmd |= SMBHSTCNT_LAST_BYTE; + // priv->cmd = smbcmd | SMBHSTCNT_INTREN; + // priv->len = len; + // priv->count = 0; + // priv->data = &data->block[1]; + // + // outb_p(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv)); + // result = wait_event_timeout(priv->waitq, + // (status = priv->status), + // adap->timeout); + // if (!result) { + // status = -ETIMEDOUT; + // dev_warn(&priv->pci_dev->dev, + // "Timeout waiting for interrupt!\n"); + // } + // priv->status = 0; + // return i801_check_post(priv, status); + //} + + for (i = 1; i <= len; i++) + { + if (i == len && read_write == I2C_SMBUS_READ) + smbcmd |= SMBHSTCNT_LAST_BYTE; + Out32(SMBHSTCNT, smbcmd); + + if (i == 1) + Out32(SMBHSTCNT, Inp32(SMBHSTCNT) | SMBHSTCNT_START); + + status = i801_wait_byte_done(); + if (status) + goto exit; + + if (i == 1 && read_write == I2C_SMBUS_READ && command != I2C_SMBUS_I2C_BLOCK_DATA) + { + len = Inp32(SMBHSTDAT0); + if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) + { + /* Recover */ + while (Inp32(SMBHSTSTS) & SMBHSTSTS_HOST_BUSY) + Out32(SMBHSTSTS, SMBHSTSTS_BYTE_DONE); + Out32(SMBHSTSTS, SMBHSTSTS_INTR); + return -EPROTO; + } + data->block[0] = len; + } + + /* Retrieve/store value in SMBBLKDAT */ + if (read_write == I2C_SMBUS_READ) + data->block[i] = Inp32(SMBBLKDAT); + if (read_write == I2C_SMBUS_WRITE && i + 1 <= len) + Out32(SMBBLKDAT, data->block[i + 1]); + + /* signals SMBBLKDAT ready */ + Out32(SMBHSTSTS, SMBHSTSTS_BYTE_DONE); + } + + status = i801_wait_intr(); +exit: + return i801_check_post(status); +} + +/* +* Convert the status register to an error code, and clear it. +* Note that status only contains the bits we want to clear, not the +* actual register value. +*/ +int i2c_smbus_i801::i801_check_post(int status) +{ + int result = 0; + + /* + * If the SMBus is still busy, we give up + * Note: This timeout condition only happens when using polling + * transactions. For interrupt operation, NAK/timeout is indicated by + * DEV_ERR. + */ + if (status < 0) + { + /* try to stop the current command */ + Out32(SMBHSTCNT, Inp32(SMBHSTCNT) | SMBHSTCNT_KILL); + //usleep_range(1000, 2000); + Out32(SMBHSTCNT, Inp32(SMBHSTCNT) & (~SMBHSTCNT_KILL)); + + Out32(SMBHSTSTS, STATUS_FLAGS); + return -ETIMEDOUT; + } + + if (status & SMBHSTSTS_FAILED) + { + result = -EIO; + } + + if (status & SMBHSTSTS_DEV_ERR) + { + /* + * This may be a PEC error, check and clear it. + * + * AUXSTS is handled differently from HSTSTS. + * For HSTSTS, i801_isr() or i801_wait_intr() + * has already cleared the error bits in hardware, + * and we are passed a copy of the original value + * in "status". + * For AUXSTS, the hardware register is left + * for us to handle here. + * This is asymmetric, slightly iffy, but safe, + * since all this code is serialized and the CRCE + * bit is harmless as long as it's cleared before + * the next operation. + */ + //if ((priv->features & FEATURE_SMBUS_PEC) && + // (inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE)) { + // outb_p(SMBAUXSTS_CRCE, SMBAUXSTS(priv)); + // result = -EBADMSG; + // dev_dbg(&priv->pci_dev->dev, "PEC error\n"); + //} + //else { + result = -ENXIO; + // dev_dbg(&priv->pci_dev->dev, "No response\n"); + //} + } + + if (status & SMBHSTSTS_BUS_ERR) + { + result = -EAGAIN; + } + + /* Clear status flags except BYTE_DONE, to be cleared by caller */ + Out32(SMBHSTSTS, status); + + return result; +} + +/* Make sure the SMBus host is ready to start transmitting. +Return 0 if it is, -EBUSY if it is not. */ +int i2c_smbus_i801::i801_check_pre() +{ + int status; + + status = Inp32(SMBHSTSTS); + if (status & SMBHSTSTS_HOST_BUSY) + { + return -EBUSY; + } + + status &= STATUS_FLAGS; + if (status) + { + Out32(SMBHSTSTS, status); + status = Inp32(SMBHSTSTS) & STATUS_FLAGS; + if (status) + { + return -EBUSY; + } + } + + /* + * Clear CRC status if needed. + * During normal operation, i801_check_post() takes care + * of it after every operation. We do it here only in case + * the hardware was already in this state when the driver + * started. + */ + //if (priv->features & FEATURE_SMBUS_PEC) { + // status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE; + // if (status) { + // dev_dbg(&priv->pci_dev->dev, + // "Clearing aux status flags (%02x)\n", status); + // outb_p(status, SMBAUXSTS(priv)); + // status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE; + // if (status) { + // dev_err(&priv->pci_dev->dev, + // "Failed clearing aux status flags (%02x)\n", + // status); + // return -EBUSY; + // } + // } + //} + + return 0; +} + +int i2c_smbus_i801::i801_transaction(int xact) +{ + int status; + int result; + + result = i801_check_pre(); + if (result < 0) + return result; + + //if (priv->features & FEATURE_IRQ) + //{ + // outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START, + // SMBHSTCNT(priv)); + // result = wait_event_timeout(priv->waitq, + // (status = priv->status), + // adap->timeout); + // if (!result) { + // status = -ETIMEDOUT; + // dev_warn(&priv->pci_dev->dev, + // "Timeout waiting for interrupt!\n"); + // } + // priv->status = 0; + // return i801_check_post(priv, status); + //} + + /* the current contents of SMBHSTCNT can be overwritten, since PEC, + * SMBSCMD are passed in xact */ + Out32(SMBHSTCNT, xact | SMBHSTCNT_START); + + status = i801_wait_intr(); + return i801_check_post(status); +} + +/* Wait for either BYTE_DONE or an error flag being set */ +int i2c_smbus_i801::i801_wait_byte_done() +{ + int timeout = 0; + int status; + + /* We will always wait for a fraction of a second! */ + do + { + //usleep_range(250, 500); + status = Inp32(SMBHSTSTS); + } while (!(status & (STATUS_ERROR_FLAGS | SMBHSTSTS_BYTE_DONE)) && (timeout++ < MAX_RETRIES)); + + if (timeout > MAX_RETRIES) + { + return -ETIMEDOUT; + } + return status & STATUS_ERROR_FLAGS; +} + +/* Wait for BUSY being cleared and either INTR or an error flag being set */ +int i2c_smbus_i801::i801_wait_intr() +{ + int timeout = 0; + int status; + + /* We will always wait for a fraction of a second! */ + do + { + //usleep_range(250, 500); + status = Inp32(SMBHSTSTS); + } while (((status & SMBHSTSTS_HOST_BUSY) || !(status & (STATUS_ERROR_FLAGS | SMBHSTSTS_INTR))) && (timeout++ < MAX_RETRIES)); + + if (timeout > MAX_RETRIES) + { + return -ETIMEDOUT; + } + return status & (STATUS_ERROR_FLAGS | SMBHSTSTS_INTR); +} + +s32 i2c_smbus_i801::i2c_smbus_xfer(u8 addr, char read_write, u8 command, int size, i2c_smbus_data* data) +{ + return i801_access(addr, read_write, command, size, data); +} \ No newline at end of file diff --git a/OpenAuraSDK/i2c_smbus_i801.h b/OpenAuraSDK/i2c_smbus_i801.h new file mode 100644 index 00000000..aeda780c --- /dev/null +++ b/OpenAuraSDK/i2c_smbus_i801.h @@ -0,0 +1,87 @@ +/*-----------------------------------------*\ +| i2c_smbus_i801.h | +| | +| i801 SMBUS driver for Windows | +| | +| Adam Honse (CalcProgrammer1) 1/29/2019 | +| Portions based on Linux source code | +| GNU GPL v2 | +\*-----------------------------------------*/ + +#include "i2c_smbus.h" + +#pragma once + +/* BIT shifting macro */ +#define BIT(x) ( 1 << x ) + +/* I801 SMBus address offsets */ +#define SMBHSTSTS (0 + i801_smba) +#define SMBHSTCNT (2 + i801_smba) +#define SMBHSTCMD (3 + i801_smba) +#define SMBHSTADD (4 + i801_smba) +#define SMBHSTDAT0 (5 + i801_smba) +#define SMBHSTDAT1 (6 + i801_smba) +#define SMBBLKDAT (7 + i801_smba) +#define SMBPEC (8 + i801_smba) /* ICH3 and later */ +#define SMBAUXSTS (12 + i801_smba) /* ICH4 and later */ +#define SMBAUXCTL (13 + i801_smba) /* ICH4 and later */ +#define SMBSLVSTS (16 + i801_smba) /* ICH3 and later */ +#define SMBSLVCMD (17 + i801_smba) /* ICH3 and later */ +#define SMBNTFDADD (20 + i801_smba) /* ICH3 and later */ + +/* Other settings */ +#define MAX_RETRIES 400 + +/* I801 command constants */ +#define I801_QUICK 0x00 +#define I801_BYTE 0x04 +#define I801_BYTE_DATA 0x08 +#define I801_WORD_DATA 0x0C +#define I801_PROC_CALL 0x10 /* unimplemented */ +#define I801_BLOCK_DATA 0x14 +#define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */ + +/* I801 Host Control register bits */ +#define SMBHSTCNT_INTREN BIT(0) +#define SMBHSTCNT_KILL BIT(1) +#define SMBHSTCNT_LAST_BYTE BIT(5) +#define SMBHSTCNT_START BIT(6) +#define SMBHSTCNT_PEC_EN BIT(7) /* ICH3 and later */ + +/* I801 Hosts Status register bits */ +#define SMBHSTSTS_BYTE_DONE BIT(7) +#define SMBHSTSTS_INUSE_STS BIT(6) +#define SMBHSTSTS_SMBALERT_STS BIT(5) +#define SMBHSTSTS_FAILED BIT(4) +#define SMBHSTSTS_BUS_ERR BIT(3) +#define SMBHSTSTS_DEV_ERR BIT(2) +#define SMBHSTSTS_INTR BIT(1) +#define SMBHSTSTS_HOST_BUSY BIT(0) + +/* Host Notify Status register bits */ +#define SMBSLVSTS_HST_NTFY_STS BIT(0) + +/* Host Notify Command register bits */ +#define SMBSLVCMD_HST_NTFY_INTREN BIT(0) + +#define STATUS_ERROR_FLAGS (SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR) +#define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR | STATUS_ERROR_FLAGS) + +class i2c_smbus_i801 : public i2c_smbus_interface +{ +public: + u16 i801_smba = 0xF000; + +private: + s32 i801_access(u16 addr, char read_write, u8 command, int size, i2c_smbus_data *data); + int i801_block_transaction(i2c_smbus_data *data, char read_write, int command, int hwpec); + int i801_block_transaction_byte_by_byte(i2c_smbus_data *data, char read_write, int command, int hwpec); + int i801_check_post(int status); + int i801_check_pre(); + int i801_transaction(int xact); + int i801_wait_byte_done(); + int i801_wait_intr(); + s32 i2c_smbus_xfer(u8 addr, char read_write, u8 command, int size, i2c_smbus_data* data); + +}; \ No newline at end of file diff --git a/OpenAuraSDK/i2c_smbus_piix4.cpp b/OpenAuraSDK/i2c_smbus_piix4.cpp new file mode 100644 index 00000000..b762a5a8 --- /dev/null +++ b/OpenAuraSDK/i2c_smbus_piix4.cpp @@ -0,0 +1,168 @@ +/*-----------------------------------------*\ +| i2c_smbus_piix4.cpp | +| | +| PIIX4 SMBUS driver for Windows | +| | +| Adam Honse (CalcProgrammer1) 8/8/2018 | +| Portions based on Linux source code | +| GNU GPL v2 | +\*-----------------------------------------*/ + +#include "i2c_smbus_piix4.h" + +//Logic adapted from piix4_transaction() in i2c-piix4.c +int i2c_smbus_piix4::piix4_transaction() +{ + int result = 0; + int temp; + int timeout = 0; + + /* Make sure the SMBus host is ready to start transmitting */ + temp = Inp32(SMBHSTSTS); + + if (temp != 0x00) + { + Out32(SMBHSTSTS, temp); + + temp = Inp32(SMBHSTSTS); + + if (temp != 0x00) + { + return -EBUSY; + } + } + + /* start the transaction by setting bit 6 */ + temp = Inp32(SMBHSTCNT); + Out32(SMBHSTCNT, temp | 0x040); + + /* We will always wait for a fraction of a second! (See PIIX4 docs errata) */ + temp = 0; + while ((++timeout < MAX_TIMEOUT) && temp <= 1) + { + temp = Inp32(SMBHSTSTS); + } + + /* If the SMBus is still busy, we give up */ + if (timeout == MAX_TIMEOUT) + { + result = -ETIMEDOUT; + } + + if (temp & 0x10) + { + result = -EIO; + } + + if (temp & 0x08) + { + result = -EIO; + } + + if (temp & 0x04) + { + result = -ENXIO; + } + + temp = Inp32(SMBHSTSTS); + if (temp != 0x00) + { + Out32(SMBHSTSTS, temp); + } + + return result; +} + +//Logic adapted from piix4_access() in i2c-piix4.c +s32 i2c_smbus_piix4::piix4_access(u16 addr, char read_write, u8 command, int size, i2c_smbus_data *data) +{ + int i, len, status; + + switch (size) + { + case I2C_SMBUS_QUICK: + Out32(SMBHSTADD, (addr << 1) | read_write); + size = PIIX4_QUICK; + break; + case I2C_SMBUS_BYTE_DATA: + Out32(SMBHSTADD, (addr << 1) | read_write); + Out32(SMBHSTCMD, command); + if (read_write == I2C_SMBUS_WRITE) + { + Out32(SMBHSTDAT0, data->byte); + } + size = PIIX4_BYTE_DATA; + break; + case I2C_SMBUS_WORD_DATA: + Out32(SMBHSTADD, (addr << 1) | read_write); + Out32(SMBHSTCMD, command); + if (read_write == I2C_SMBUS_WRITE) + { + Out32(SMBHSTDAT0, data->word & 0xFF); + Out32(SMBHSTDAT1, (data->word & 0xFF00) >> 8); + } + size = PIIX4_WORD_DATA; + break; + case I2C_SMBUS_BLOCK_DATA: + Out32(SMBHSTADD, (addr << 1) | read_write); + Out32(SMBHSTCMD, command); + if (read_write == I2C_SMBUS_WRITE) + { + len = data->block[0]; + if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) + { + return -EINVAL; + } + Out32(SMBHSTDAT0, len); + Inp32(SMBHSTCNT); + for (i = 1; i <= len; i++) + { + Out32(SMBBLKDAT, data->block[i]); + } + } + size = PIIX4_BLOCK_DATA; + break; + default: + return -EOPNOTSUPP; + } + + Out32(SMBHSTCNT, (size & 0x1C)); + + status = piix4_transaction(); + + if (status) + return status; + + if ((read_write == I2C_SMBUS_WRITE) || (size == PIIX4_QUICK)) + return 0; + + switch (size) + { + case PIIX4_BYTE: + case PIIX4_BYTE_DATA: + data->byte = (u8)Inp32(SMBHSTDAT0); + break; + case PIIX4_WORD_DATA: + data->word = Inp32(SMBHSTDAT0) + (Inp32(SMBHSTDAT1) << 8); + break; + case PIIX4_BLOCK_DATA: + data->block[0] = (u8)Inp32(SMBHSTDAT0); + if (data->block[0] == 0 || data->block[0] > I2C_SMBUS_BLOCK_MAX) + { + return -EPROTO; + } + Inp32(SMBHSTCNT); + for (i = 1; i <= data->block[0]; i++) + { + data->block[i] = (u8)Inp32(SMBBLKDAT); + } + break; + } + + return 0; +} + +s32 i2c_smbus_piix4::i2c_smbus_xfer(u8 addr, char read_write, u8 command, int size, i2c_smbus_data* data) +{ + return piix4_access(addr, read_write, command, size, data); +} \ No newline at end of file diff --git a/OpenAuraSDK/i2c_smbus_piix4.h b/OpenAuraSDK/i2c_smbus_piix4.h new file mode 100644 index 00000000..262e0c58 --- /dev/null +++ b/OpenAuraSDK/i2c_smbus_piix4.h @@ -0,0 +1,48 @@ +/*-----------------------------------------*\ +| i2c_smbus_piix4.h | +| | +| Definitions and types for PIIX4 SMBUS | +| driver | +| | +| Adam Honse (CalcProgrammer1) 8/8/2018 | +| Portions based on Linux source code | +| GNU GPL v2 | +\*-----------------------------------------*/ + +#include "i2c_smbus.h" + +#pragma once + +// PIIX4 SMBus address offsets +#define SMBHSTSTS (0 + piix4_smba) +#define SMBHSLVSTS (1 + piix4_smba) +#define SMBHSTCNT (2 + piix4_smba) +#define SMBHSTCMD (3 + piix4_smba) +#define SMBHSTADD (4 + piix4_smba) +#define SMBHSTDAT0 (5 + piix4_smba) +#define SMBHSTDAT1 (6 + piix4_smba) +#define SMBBLKDAT (7 + piix4_smba) +#define SMBSLVCNT (8 + piix4_smba) +#define SMBSHDWCMD (9 + piix4_smba) +#define SMBSLVEVT (0xA + piix4_smba) +#define SMBSLVDAT (0xC + piix4_smba) + +#define MAX_TIMEOUT 5000 + +// PIIX4 constants +#define PIIX4_QUICK 0x00 +#define PIIX4_BYTE 0x04 +#define PIIX4_BYTE_DATA 0x08 +#define PIIX4_WORD_DATA 0x0C +#define PIIX4_BLOCK_DATA 0x14 + +class i2c_smbus_piix4 : public i2c_smbus_interface +{ +public: + u16 piix4_smba = 0x0B00; + +private: + int piix4_transaction(); + s32 piix4_access(u16 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); +}; \ No newline at end of file diff --git a/dependencies/inpout32_1501/Win32/inpout32.dll b/dependencies/inpout32_1501/Win32/inpout32.dll new file mode 100644 index 00000000..88892800 Binary files /dev/null and b/dependencies/inpout32_1501/Win32/inpout32.dll differ diff --git a/dependencies/inpout32_1501/Win32/inpout32.h b/dependencies/inpout32_1501/Win32/inpout32.h new file mode 100644 index 00000000..65df0969 --- /dev/null +++ b/dependencies/inpout32_1501/Win32/inpout32.h @@ -0,0 +1,32 @@ +#pragma once + +//Functions exported from DLL. +//For easy inclusion is user projects. +//Original InpOut32 function support +void _stdcall Out32(short PortAddress, short data); +short _stdcall Inp32(short PortAddress); + +//My extra functions for making life easy +BOOL _stdcall IsInpOutDriverOpen(); //Returns TRUE if the InpOut driver was opened successfully +BOOL _stdcall IsXP64Bit(); //Returns TRUE if the OS is 64bit (x64) Windows. + +//DLLPortIO function support +UCHAR _stdcall DlPortReadPortUchar (USHORT port); +void _stdcall DlPortWritePortUchar(USHORT port, UCHAR Value); + +USHORT _stdcall DlPortReadPortUshort (USHORT port); +void _stdcall DlPortWritePortUshort(USHORT port, USHORT Value); + +ULONG _stdcall DlPortReadPortUlong(ULONG port); +void _stdcall DlPortWritePortUlong(ULONG port, ULONG Value); + +//WinIO function support (Untested and probably does NOT work - esp. on x64!) +PBYTE _stdcall MapPhysToLin(PBYTE pbPhysAddr, DWORD dwPhysSize, HANDLE *pPhysicalMemoryHandle); +BOOL _stdcall UnmapPhysicalMemory(HANDLE PhysicalMemoryHandle, PBYTE pbLinAddr); +BOOL _stdcall GetPhysLong(PBYTE pbPhysAddr, PDWORD pdwPhysVal); +BOOL _stdcall SetPhysLong(PBYTE pbPhysAddr, DWORD dwPhysVal); + + + + + diff --git a/dependencies/inpout32_1501/Win32/inpout32.lib b/dependencies/inpout32_1501/Win32/inpout32.lib new file mode 100644 index 00000000..25b70560 Binary files /dev/null and b/dependencies/inpout32_1501/Win32/inpout32.lib differ