mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-11-17 20:17:38 +01:00
175 lines
4.6 KiB
C
175 lines
4.6 KiB
C
#include "librfu.h"
|
|
|
|
static void Sio32IDIntr(void);
|
|
static void Sio32IDInit(void);
|
|
static s32 Sio32IDMain(void);
|
|
|
|
struct RfuSIO32Id
|
|
{
|
|
u8 MS_mode;
|
|
u8 state;
|
|
u16 count;
|
|
u16 send_id;
|
|
u16 recv_id;
|
|
u16 unk8; // unused
|
|
u16 lastId;
|
|
};
|
|
|
|
struct RfuSIO32Id gRfuSIO32Id;
|
|
|
|
static const u16 Sio32ConnectionData[] = { 0x494e, 0x544e, 0x4e45, 0x4f44 }; // NINTENDO
|
|
static const char Sio32IDLib_Var[] = "Sio32ID_030820";
|
|
|
|
s32 AgbRFU_checkID(u8 maxTries)
|
|
{
|
|
u16 ieBak;
|
|
vu16 *regTMCNTL;
|
|
s32 id;
|
|
|
|
// Interrupts must be enabled
|
|
if (REG_IME == 0)
|
|
return -1;
|
|
ieBak = REG_IE;
|
|
gSTWIStatus->state = 10;
|
|
STWI_set_Callback_ID(Sio32IDIntr);
|
|
Sio32IDInit();
|
|
regTMCNTL = ®_TMCNT_L(gSTWIStatus->timerSelect);
|
|
maxTries *= 8;
|
|
while (--maxTries != 0xFF)
|
|
{
|
|
id = Sio32IDMain();
|
|
if (id != 0)
|
|
break;
|
|
regTMCNTL[1] = 0;
|
|
regTMCNTL[0] = 0;
|
|
regTMCNTL[1] = TIMER_1024CLK | TIMER_ENABLE;
|
|
while (regTMCNTL[0] < 32)
|
|
;
|
|
regTMCNTL[1] = 0;
|
|
regTMCNTL[0] = 0;
|
|
}
|
|
REG_IME = 0;
|
|
REG_IE = ieBak;
|
|
REG_IME = 1;
|
|
gSTWIStatus->state = 0;
|
|
STWI_set_Callback_ID(NULL);
|
|
return id;
|
|
}
|
|
|
|
static void Sio32IDInit(void)
|
|
{
|
|
REG_IME = 0;
|
|
REG_IE &= ~((8 << gSTWIStatus->timerSelect) | INTR_FLAG_SERIAL);
|
|
REG_IME = 1;
|
|
REG_RCNT = 0;
|
|
REG_SIOCNT = SIO_32BIT_MODE;
|
|
REG_SIOCNT |= SIO_INTR_ENABLE | SIO_ENABLE;
|
|
CpuFill32(0, &gRfuSIO32Id, sizeof(struct RfuSIO32Id));
|
|
REG_IF = INTR_FLAG_SERIAL;
|
|
}
|
|
|
|
static s32 Sio32IDMain(void)
|
|
{
|
|
switch (gRfuSIO32Id.state)
|
|
{
|
|
case 0:
|
|
gRfuSIO32Id.MS_mode = AGB_CLK_MASTER;
|
|
REG_SIOCNT |= SIO_38400_BPS;
|
|
REG_IME = 0;
|
|
REG_IE |= INTR_FLAG_SERIAL;
|
|
REG_IME = 1;
|
|
gRfuSIO32Id.state = 1;
|
|
*(vu8 *)®_SIOCNT |= SIO_ENABLE;
|
|
break;
|
|
case 1:
|
|
if (gRfuSIO32Id.lastId == 0)
|
|
{
|
|
if (gRfuSIO32Id.MS_mode == AGB_CLK_MASTER)
|
|
{
|
|
if (gRfuSIO32Id.count == 0)
|
|
{
|
|
REG_IME = 0;
|
|
REG_SIOCNT |= SIO_ENABLE;
|
|
REG_IME = 1;
|
|
}
|
|
}
|
|
else if (gRfuSIO32Id.send_id != RFU_ID && !gRfuSIO32Id.count)
|
|
{
|
|
REG_IME = 0;
|
|
REG_IE &= ~INTR_FLAG_SERIAL;
|
|
REG_IME = 1;
|
|
REG_SIOCNT = 0;
|
|
REG_SIOCNT = SIO_32BIT_MODE;
|
|
REG_IF = INTR_FLAG_SERIAL;
|
|
REG_SIOCNT |= SIO_INTR_ENABLE | SIO_ENABLE;
|
|
REG_IME = 0;
|
|
REG_IE |= INTR_FLAG_SERIAL;
|
|
REG_IME = 1;
|
|
}
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
gRfuSIO32Id.state = 2;
|
|
// fallthrough
|
|
}
|
|
default:
|
|
return gRfuSIO32Id.lastId;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void Sio32IDIntr(void)
|
|
{
|
|
u32 regSIODATA32;
|
|
u16 delay;
|
|
#ifndef NONMATCHING
|
|
register u32 rfuSIO32IdUnk0_times_16 asm("r1");
|
|
register u16 negRfuSIO32IdUnk6 asm("r0");
|
|
#else
|
|
u32 rfuSIO32IdUnk0_times_16;
|
|
u16 negRfuSIO32IdUnk6;
|
|
#endif
|
|
|
|
regSIODATA32 = REG_SIODATA32;
|
|
if (gRfuSIO32Id.MS_mode != AGB_CLK_MASTER)
|
|
REG_SIOCNT |= SIO_ENABLE;
|
|
rfuSIO32IdUnk0_times_16 = 16 * gRfuSIO32Id.MS_mode; // to handle side effect of inline asm
|
|
rfuSIO32IdUnk0_times_16 = (regSIODATA32 << rfuSIO32IdUnk0_times_16) >> 16;
|
|
regSIODATA32 = (regSIODATA32 << 16 * (1 - gRfuSIO32Id.MS_mode)) >> 16;
|
|
if (gRfuSIO32Id.lastId == 0)
|
|
{
|
|
if (rfuSIO32IdUnk0_times_16 == gRfuSIO32Id.recv_id)
|
|
{
|
|
if (gRfuSIO32Id.count > 3)
|
|
{
|
|
gRfuSIO32Id.lastId = regSIODATA32;
|
|
}
|
|
else if (rfuSIO32IdUnk0_times_16 == (u16)~gRfuSIO32Id.send_id)
|
|
{
|
|
negRfuSIO32IdUnk6 = ~gRfuSIO32Id.recv_id;
|
|
if (regSIODATA32 == negRfuSIO32IdUnk6)
|
|
++gRfuSIO32Id.count;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gRfuSIO32Id.count = 0;
|
|
}
|
|
}
|
|
if (gRfuSIO32Id.count < 4)
|
|
gRfuSIO32Id.send_id = *(gRfuSIO32Id.count + Sio32ConnectionData);
|
|
else
|
|
gRfuSIO32Id.send_id = RFU_ID;
|
|
gRfuSIO32Id.recv_id = ~regSIODATA32;
|
|
REG_SIODATA32 = (gRfuSIO32Id.send_id << 16 * (1 - gRfuSIO32Id.MS_mode))
|
|
+ (gRfuSIO32Id.recv_id << 16 * gRfuSIO32Id.MS_mode);
|
|
if (gRfuSIO32Id.MS_mode == AGB_CLK_MASTER && (gRfuSIO32Id.count != 0 || regSIODATA32 == 0x494e))
|
|
{
|
|
for (delay = 0; delay < 600; ++delay)
|
|
;
|
|
if (gRfuSIO32Id.lastId == 0)
|
|
REG_SIOCNT |= SIO_ENABLE;
|
|
}
|
|
}
|