mirror of
https://github.com/reactos/reactos.git
synced 2024-06-25 15:31:47 +00:00
224 lines
6 KiB
C
224 lines
6 KiB
C
/*
|
|
* FreeLoader
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include <freeldr.h>
|
|
|
|
// These functions are used only inside xbox-specific code
|
|
// thus I didn't include them in header
|
|
|
|
#define I2C_IO_BASE 0xc000
|
|
|
|
static BOOLEAN
|
|
WriteToSMBus(UCHAR Address, UCHAR bRegister, UCHAR Size, ULONG Data_to_smbus)
|
|
{
|
|
int nRetriesToLive=50;
|
|
|
|
while(READ_PORT_USHORT((PUSHORT) (I2C_IO_BASE+0)) & 0x0800)
|
|
{
|
|
; // Franz's spin while bus busy with any master traffic
|
|
}
|
|
|
|
while(nRetriesToLive--)
|
|
{
|
|
UCHAR b;
|
|
unsigned int temp;
|
|
|
|
WRITE_PORT_UCHAR((PUCHAR)(I2C_IO_BASE + 4), (Address << 1) | 0);
|
|
WRITE_PORT_UCHAR((PUCHAR)(I2C_IO_BASE + 8), bRegister);
|
|
|
|
switch (Size)
|
|
{
|
|
case 4:
|
|
WRITE_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 9), Data_to_smbus & 0xff);
|
|
WRITE_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 9), (Data_to_smbus >> 8) & 0xff );
|
|
WRITE_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 9), (Data_to_smbus >> 16) & 0xff );
|
|
WRITE_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 9), (Data_to_smbus >> 24) & 0xff );
|
|
WRITE_PORT_USHORT((PUSHORT) (I2C_IO_BASE + 6), 4);
|
|
break;
|
|
case 2:
|
|
WRITE_PORT_USHORT((PUSHORT) (I2C_IO_BASE + 6), Data_to_smbus&0xffff);
|
|
break;
|
|
default: // 1
|
|
WRITE_PORT_USHORT((PUSHORT) (I2C_IO_BASE + 6), Data_to_smbus&0xff);
|
|
break;
|
|
}
|
|
|
|
|
|
temp = READ_PORT_USHORT((PUSHORT) (I2C_IO_BASE + 0));
|
|
WRITE_PORT_USHORT((PUSHORT) (I2C_IO_BASE + 0), temp); // clear down all preexisting errors
|
|
|
|
switch (Size)
|
|
{
|
|
case 4:
|
|
WRITE_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 2), 0x1d); // DWORD modus
|
|
break;
|
|
case 2:
|
|
WRITE_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 2), 0x1b); // WORD modus
|
|
break;
|
|
default: // 1
|
|
WRITE_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 2), 0x1a); // BYTE modus
|
|
break;
|
|
}
|
|
|
|
b = 0;
|
|
|
|
while( (b&0x36)==0 )
|
|
{
|
|
b=READ_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 0));
|
|
}
|
|
|
|
if ((b&0x10) != 0)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
StallExecutionProcessor(1);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static BOOLEAN
|
|
ReadfromSMBus(UCHAR Address, UCHAR bRegister, UCHAR Size, ULONG *Data_to_smbus)
|
|
{
|
|
int nRetriesToLive=50;
|
|
|
|
while (0 != (READ_PORT_USHORT((PUSHORT) (I2C_IO_BASE + 0)) & 0x0800))
|
|
{
|
|
; /* Franz's spin while bus busy with any master traffic */
|
|
}
|
|
|
|
while (0 != nRetriesToLive--)
|
|
{
|
|
UCHAR b;
|
|
int temp;
|
|
|
|
WRITE_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 4), (Address << 1) | 1);
|
|
WRITE_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 8), bRegister);
|
|
|
|
temp = READ_PORT_USHORT((USHORT *) (I2C_IO_BASE + 0));
|
|
WRITE_PORT_USHORT((PUSHORT) (I2C_IO_BASE + 0), temp); /* clear down all preexisting errors */
|
|
|
|
switch (Size)
|
|
{
|
|
case 4:
|
|
WRITE_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 2), 0x0d); /* DWORD modus ? */
|
|
break;
|
|
case 2:
|
|
WRITE_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 2), 0x0b); /* WORD modus */
|
|
break;
|
|
default:
|
|
WRITE_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 2), 0x0a); // BYTE
|
|
break;
|
|
}
|
|
|
|
b = 0;
|
|
|
|
while (0 == (b & 0x36))
|
|
{
|
|
b = READ_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 0));
|
|
}
|
|
|
|
if (0 != (b & 0x24))
|
|
{
|
|
/* printf("I2CTransmitByteGetReturn error %x\n", b); */
|
|
}
|
|
|
|
if(0 == (b & 0x10))
|
|
{
|
|
/* printf("I2CTransmitByteGetReturn no complete, retry\n"); */
|
|
}
|
|
else
|
|
{
|
|
switch (Size)
|
|
{
|
|
case 4:
|
|
READ_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 6));
|
|
READ_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 9));
|
|
READ_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 9));
|
|
READ_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 9));
|
|
READ_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 9));
|
|
break;
|
|
case 2:
|
|
*Data_to_smbus = READ_PORT_USHORT((USHORT *) (I2C_IO_BASE + 6));
|
|
break;
|
|
default:
|
|
*Data_to_smbus = READ_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 6));
|
|
break;
|
|
}
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOLEAN
|
|
I2CTransmitByteGetReturn(UCHAR bPicAddressI2cFormat, UCHAR bDataToWrite, ULONG *Return)
|
|
{
|
|
return ReadfromSMBus(bPicAddressI2cFormat, bDataToWrite, 1, Return);
|
|
}
|
|
|
|
// transmit a word, no returned data from I2C device
|
|
static BOOLEAN
|
|
I2CTransmitWord(UCHAR bPicAddressI2cFormat, USHORT wDataToWrite)
|
|
{
|
|
return WriteToSMBus(bPicAddressI2cFormat,(wDataToWrite>>8)&0xff,1,(wDataToWrite&0xff));
|
|
}
|
|
|
|
static void
|
|
I2cSetFrontpanelLed(UCHAR b)
|
|
{
|
|
I2CTransmitWord( 0x10, 0x800 | b); // sequencing thanks to Jarin the Penguin!
|
|
I2CTransmitWord( 0x10, 0x701);
|
|
}
|
|
|
|
// Set the pattern of the LED.
|
|
// r = Red, g = Green, o = Orange, x = Off
|
|
// This func is taken from cromwell, all credits goes for them
|
|
void
|
|
XboxSetLED(PCSTR pattern) {
|
|
const char *x = pattern;
|
|
int r, g;
|
|
|
|
if(strlen(pattern) == 4) {
|
|
r = g = 0;
|
|
while (*x) {
|
|
r *= 2;
|
|
g *= 2;
|
|
switch (*x) {
|
|
case 'r':
|
|
r++;
|
|
break;
|
|
case 'g':
|
|
g++;
|
|
break;
|
|
case 'o':
|
|
r++;
|
|
g++;
|
|
break;
|
|
}
|
|
x++;
|
|
}
|
|
I2cSetFrontpanelLed(((r<<4) & 0xF0) + (g & 0xF));
|
|
}
|
|
}
|