From 006289c784ebebcfea14ca8ce2db63d3c40831ba Mon Sep 17 00:00:00 2001 From: Adam Honse Date: Wed, 30 Jan 2019 22:00:41 -0600 Subject: [PATCH] Initial commit --- OpenAuraSDK.sln | 31 ++ OpenAuraSDK/AuraController.cpp | 40 ++ OpenAuraSDK/AuraController.h | 58 +++ OpenAuraSDK/OpenAuraSDK.cpp | Bin 0 -> 16978 bytes OpenAuraSDK/OpenAuraSDK.h | 10 + OpenAuraSDK/OpenAuraSDK.vcxproj | 186 +++++++ OpenAuraSDK/OpenAuraSDK.vcxproj.filters | 57 +++ OpenAuraSDK/dllmain.cpp | Bin 0 -> 906 bytes OpenAuraSDK/i2c_smbus.cpp | 121 +++++ OpenAuraSDK/i2c_smbus.h | 67 +++ OpenAuraSDK/i2c_smbus_i801.cpp | 478 ++++++++++++++++++ OpenAuraSDK/i2c_smbus_i801.h | 87 ++++ OpenAuraSDK/i2c_smbus_piix4.cpp | 168 ++++++ OpenAuraSDK/i2c_smbus_piix4.h | 48 ++ dependencies/inpout32_1501/Win32/inpout32.dll | Bin 0 -> 98304 bytes dependencies/inpout32_1501/Win32/inpout32.h | 32 ++ dependencies/inpout32_1501/Win32/inpout32.lib | Bin 0 -> 5116 bytes 17 files changed, 1383 insertions(+) create mode 100644 OpenAuraSDK.sln create mode 100644 OpenAuraSDK/AuraController.cpp create mode 100644 OpenAuraSDK/AuraController.h create mode 100644 OpenAuraSDK/OpenAuraSDK.cpp create mode 100644 OpenAuraSDK/OpenAuraSDK.h create mode 100644 OpenAuraSDK/OpenAuraSDK.vcxproj create mode 100644 OpenAuraSDK/OpenAuraSDK.vcxproj.filters create mode 100644 OpenAuraSDK/dllmain.cpp create mode 100644 OpenAuraSDK/i2c_smbus.cpp create mode 100644 OpenAuraSDK/i2c_smbus.h create mode 100644 OpenAuraSDK/i2c_smbus_i801.cpp create mode 100644 OpenAuraSDK/i2c_smbus_i801.h create mode 100644 OpenAuraSDK/i2c_smbus_piix4.cpp create mode 100644 OpenAuraSDK/i2c_smbus_piix4.h create mode 100644 dependencies/inpout32_1501/Win32/inpout32.dll create mode 100644 dependencies/inpout32_1501/Win32/inpout32.h create mode 100644 dependencies/inpout32_1501/Win32/inpout32.lib diff --git a/OpenAuraSDK.sln b/OpenAuraSDK.sln new file mode 100644 index 000000000..efc9459cc --- /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 000000000..8319df4a9 --- /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 000000000..626efceea --- /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 0000000000000000000000000000000000000000..711a178eda765eea38e58d22d1643d2bdcf08d57 GIT binary patch literal 16978 zcmd5@Yj4{&6y?_p*nbc@v`E`E59is(1~|5}1$|{{wrpq%BTeGQT^eVxleX*n*SDQR z`dXAk+N`9=fnmv(D4u&RFYmpi$p8MGSMw@T&()baQm3k}F4Vc&S1(jkJyvt-0N2lO z{{g;Dl<24~N*$>_{twhKent3xM429*8{qdLu5?h#DV`mmbPvB+x}!_PPc_vOd?H{G z;RGcQ@LQgkQ{Sp@AlbY=^Y?ce`2Zy^fI-|FxKhJYZPfo>y}|W9BtFLV@bYb7ck%hC zmUBGYRqJX&Elzk+blT9m7(h=wus8vS^9fJ-TE)-tk-9{^)I8hc$C38>xN?YAe2}>R zXw=>=*&=lZHAJY5ZJ3n1uO5!-zQp~mZubT-k8~>@jcTUVT;l!#&ao#KFYnt+1M9taDY2+fYrw}mfA--T5elg$0g22CfdrSx~--C ztd9{&^OLn6KEs;XG9A=KnW+UL(Yg$0d462Gnx{mjSXc6FUwr`900_sZeKx__$SNh1 zGP946aiq3j`wg&csvZ3PO|@`tqu)MN8|qh_+iDxvx76>j><0bs%-kg2VV{sgc`5J>FLLU|Dg!(u4OQ0i}_4bz{9j>(I*nv}{o1_!|9e z4SR1f?T8QfdfmvASsZs)Ey*a8wVRIiEj=BHPGK98VEn_InsnLz`^z{F(+~I@nFZ7;m z^%r^-b4dDYm#*0pjTcJhKzlkn+J)~E?=Euq>yJSI(si@v&uVf;waSGirT;O)!&o zX`yV6CQdQ-`m=_#e!B2E%xH~AF_s^pg-!qcsFt+1yQOZSRNOb%qvH~5p5C0siqt>& z5Y4VB##)((wW2nG<@Oy}G;<}~g3E5VBb{3uIlXOhX|H#Gi?cExQ?Wd0AI6A<32i&x z-w9GWlHJ4jg)wYWe={;mE$MSeYvz+rB5fRJB?je_*v%uYm29RVjLq|L3))%a1v2Qf z(Yye&N|`O_qhGsn!EBDkT$=MKbMTF!nVHBIXBqx^26~q`|KLB`mT!!~xr)EFkEXWi z<+AySyIr#qaDHGPagehj#5=+FTzfUj=0O>X^5EEY+B_&jQ63z9Pn!p2D9VHL2h-+3 z8H)1Y49K*3P==yB>eqk=WhlyH;~Maw3`Kb~t^p6qP?QH}d#Bw$C__;mt!u!8G6)aX z9NxH`m-GMA$lY6*-PkNKcei;|nY;UVOaw|P{VyZd>9(HYGK`0XO!pI9@ZZ<>^zSvZNmDKAITpz zY^3n0;YadE4I3#uYWR`-QNuufk z!$t~^8h#{y)Uc7lqlO>JA2n>G@TlQO@<$CDDLiWUk^E7^MhcG_ek6a?u#v)}h9Aiv zHEg8tsNqNQM-3Y(8#U4^__nY+WEVN=9>!3o*uk=|&$H@htQLEQbz{4#uJ?~{2()q-;u6GADo?yjb1M3D4u}+QnrbdzJba?LtkbBsj;aWq; zojsFxE6R%UkUe%BdzzJT8+vt|{9jX9pHU@xHd)uPwX^3v|hjy(ru zSe)!y6r4?MZ80wQ*rYQtvTkC|Vf;#4lfBKLr?TI0H#hghu-9@|U|+o)?gn~2%=2cD zFS49je=qy9%nX@-7g4+xc1C^HBfS|#OdE&mS4}n|<2jR|VTMt<+det>7bC5=pLJDtpe<^oZ(Z5NjcRyqa3B za$R*@N5u`SsotA{j_TM6zKuxvhxSdegz@z@W+m$=;nH2aYF}EFv*EH&I6|b~!3y%$ J&?kIR{{w#pbrt{s literal 0 HcmV?d00001 diff --git a/OpenAuraSDK/OpenAuraSDK.h b/OpenAuraSDK/OpenAuraSDK.h new file mode 100644 index 000000000..3f8cb34b7 --- /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 000000000..351f9daaa --- /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 000000000..d7d7b34d1 --- /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 0000000000000000000000000000000000000000..44c1a0c401f1b6e0d2e4572add2e869d0005f854 GIT binary patch literal 906 zcmbu7QA+|*5QWck(0^F$#US*(o~#uVv|`hur={GLjZ9^CO(Oj3)io zoHJ+UzP~lqRG>r?>`8Ze&{PeLG{*uRb3&yWdpuRay;Mdd;7svzz2MI^^NbRIjGuqX z3)RB{unluU-Uz?sf972K+S7qokNCQv7elXU>9K^YCA8Gw@^1AMqpZv;lyZ8;VfKLyqQAm zT5Yy}Vdf{Q#s*l6NQd`j+uS03uN{yRQP~3RKb0XEyK;W*_vhMe-}jr{KkB5S XXH~h``zV=j&Z`gnwGQcOU9r*!+OT 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 000000000..e1d5e0164 --- /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 000000000..267fc6bfc --- /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 000000000..aeda780c7 --- /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 000000000..b762a5a80 --- /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 000000000..262e0c583 --- /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 0000000000000000000000000000000000000000..8889280046028c78b7a379a7e284399b6e1ab0c4 GIT binary patch literal 98304 zcmeFae|S{YwLg3&Gf7Th!WlGy$S((pibg3KP~s2_k_kZxPKcQ}LIU1GI*zoZ@f^S_ zfuv_bbFvxb-qQQhZ)poR^nU3r@4d9ON?VH)1`|+Jet4A%*G8M_4ns8*OajE5?`Q2Z zlLWo(z3=nB&-4Bx4|C4hzt&!R?X}k4d+oJ%${yP$*(FJG;AfhWbO3MqS0tW)`_YNy zF*p8ZjP!iQ>r)Td7Qa6Ak>C?gx!2Zx^J{gFf8G7n$G`E7Z>sLUTkWpXzTtl28}8zV zE8JiI=Bm{*GBZczCO}{Pw;wKf`OS-ylfNAq&rbe#gm+~8X!84bZ;bxib^>GYw>d>+T24C!~cp1 zUft?7-$cf55FF4za^t-c?-BosB!7o3*q`;RH_>ux&Qs7Gpd`W>XDexr)zNEmH z6!?+?UsB-z1qJlNy**gVsZ)bHelEGp?9%;`Yd1yt%xoXNJ5ohDYKR@9f91OyK9O8H zx2eT=Xp34F=Q=}D)+WaWnDiZUL z@mHLZ)OeW69dZET)?8Y5=0|;mKq^p^m$GcCJY;Jw&K(1coW4*>t+6;aiybKsI)Kqq z3!|o}cAJ@91l)YV=Rpo+bp>G*k$l{XI`qS?$l_cX=o6J{l@}bj!$=fei^O(;L?Zco z{xRf^@<}7}2y&vmE|?L9+v`NgUllx0wTE-F(2$@54_&7`R0)3vkrfC}qHL#| z&ZrxLZ=vWgRK6DVBx(l9sD7%92dwJR-BKupo3sS4Ok zM*^5;ajvV}SK&9a=OT<3@!PWC{gOh^Bs1HQD6idOb&B4fsx1*L6hm+l@nr4pV}@B)-5R(?ZfxVwdS) z)!X^ksIlSPNkn*HIY~6QoUcJuptWeMKoJGqOG7ra+!i!#iX^&CJkS~$*vB0Z2ALH) z@$EC;@tf}e@hsrFq9*@Xew2?MM&4ov@B<|e^8+;u{LoKmhI4b09q;2l6ixC&ZZf)@ zAAv3Dzu|}AHT>`b2=fJg*p0}M{Gf!NMa<`UVmaypPf+b6dBRK4kK|5Y%I}AbO+P$I z5bUpW$8E$NxkEVo4dwt;*HV5touE4Y=bS<`1gHE6*fbs{^2T-(qp(cDDcOQkAnCh@ z8KpSaP3%$2G6koAZ(6birxfSj8j_$`7U$m4{7CK$UTBek1hSmCL2$}a{(xxsNKPrv z&Gn7s6zWjXtAC4Aa)4`sQ{G3T6UZkx#d`VKY!Z`Usd*bp?7<;<(dtPc8-zT)&7iy} z=q`t-yAr~sE~7+X0qY-hfwmZ*#I6U(;#m_T{VaHU>Bur5!iX|{Ei+MuEXg%7E07

HRkK)BNb?$D4;p@u%G#4G1NV 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 z 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 literal 0 HcmV?d00001