diff --git a/source/common/hid.c b/source/common/hid.c
index c6a0e72..a821c81 100644
--- a/source/common/hid.c
+++ b/source/common/hid.c
@@ -18,11 +18,13 @@ u32 InputWait() {
u32 sd_state = SD_STATE;
if (sd_state != sd_state_old)
return sd_state ? SD_INSERT : SD_EJECT;
- u32 special_key = i2cReadRegister(I2C_DEV_MCU, 0x10);
- if (special_key == 0x01)
- return pad_state | BUTTON_POWER;
- else if (special_key == 0x04)
- return pad_state | BUTTON_HOME;
+ u8 special_key;
+ if (I2C_readRegBuf(I2C_DEV_MCU, 0x10, &special_key, 1)) {
+ if (special_key == 0x01)
+ return pad_state | BUTTON_POWER;
+ else if (special_key == 0x04)
+ return pad_state | BUTTON_HOME;
+ }
pad_state_old = pad_state;
delay = 0;
continue;
diff --git a/source/common/i2c.c b/source/common/i2c.c
index 6edc1da..0c027d8 100644
--- a/source/common/i2c.c
+++ b/source/common/i2c.c
@@ -1,156 +1,195 @@
+/*
+ * This file is part of fastboot 3DS
+ * Copyright (C) 2017 derrek, profi200
+ *
+ * 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 3 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, see .
+ */
+
+#include
#include "i2c.h"
-#include "timer.h"
-//-----------------------------------------------------------------------------
-static const struct { u8 bus_id, reg_addr; } dev_data[] = {
- {0, 0x4A}, {0, 0x7A}, {0, 0x78},
- {1, 0x4A}, {1, 0x78}, {1, 0x2C},
- {1, 0x2E}, {1, 0x40}, {1, 0x44},
- {2, 0xD6}, {2, 0xD0}, {2, 0xD2},
- {2, 0xA4}, {2, 0x9A}, {2, 0xA0},
+#define I2C1_REGS_BASE (0x10161000)
+#define REG_I2C1_DATA *((vu8* )(I2C1_REGS_BASE + 0x00))
+#define REG_I2C1_CNT *((vu8* )(I2C1_REGS_BASE + 0x01))
+#define REG_I2C1_CNTEX *((vu16*)(I2C1_REGS_BASE + 0x02))
+#define REG_I2C1_SCL *((vu16*)(I2C1_REGS_BASE + 0x04))
+
+#define I2C2_REGS_BASE (0x10144000)
+#define REG_I2C2_DATA *((vu8* )(I2C2_REGS_BASE + 0x00))
+#define REG_I2C2_CNT *((vu8* )(I2C2_REGS_BASE + 0x01))
+#define REG_I2C2_CNTEX *((vu16*)(I2C2_REGS_BASE + 0x02))
+#define REG_I2C2_SCL *((vu16*)(I2C2_REGS_BASE + 0x04))
+
+#define I2C3_REGS_BASE (0x10148000)
+#define REG_I2C3_DATA *((vu8* )(I2C3_REGS_BASE + 0x00))
+#define REG_I2C3_CNT *((vu8* )(I2C3_REGS_BASE + 0x01))
+#define REG_I2C3_CNTEX *((vu16*)(I2C3_REGS_BASE + 0x02))
+#define REG_I2C3_SCL *((vu16*)(I2C3_REGS_BASE + 0x04))
+
+
+static const struct
+{
+ u8 busId;
+ u8 devAddr;
+} i2cDevTable[] =
+{
+ {0, 0x4A},
+ {0, 0x7A},
+ {0, 0x78},
+ {1, 0x4A},
+ {1, 0x78},
+ {1, 0x2C},
+ {1, 0x2E},
+ {1, 0x40},
+ {1, 0x44},
+ {2, 0xA6}, // TODO: Find out if 0xA6 or 0xD6 is correct
+ {2, 0xD0},
+ {2, 0xD2},
+ {2, 0xA4},
+ {2, 0x9A},
+ {2, 0xA0},
+ {1, 0xEE},
+ {0, 0x40},
+ {2, 0x54}
};
-inline u8 i2cGetDeviceBusId(u8 device_id) {
- return dev_data[device_id].bus_id;
+
+
+static void i2cWaitBusy(vu8 *cntReg)
+{
+ while(*cntReg & I2C_ENABLE);
}
-inline u8 i2cGetDeviceRegAddr(u8 device_id) {
- return dev_data[device_id].reg_addr;
+static vu8* i2cGetBusRegsBase(u8 busId)
+{
+ vu8 *base;
+ if(!busId) base = (vu8*)I2C1_REGS_BASE;
+ else if(busId == 1) base = (vu8*)I2C2_REGS_BASE;
+ else base = (vu8*)I2C3_REGS_BASE;
+
+ return base;
}
-//-----------------------------------------------------------------------------
+static bool i2cStartTransfer(I2cDevice devId, u8 regAddr, bool read, vu8 *regsBase)
+{
+ const u8 devAddr = i2cDevTable[devId].devAddr;
+ vu8 *const i2cData = regsBase;
+ vu8 *const i2cCnt = regsBase + 1;
-static vu8* reg_data_addrs[] = {
- (vu8*)(I2C1_REG_OFF + I2C_REG_DATA),
- (vu8*)(I2C2_REG_OFF + I2C_REG_DATA),
- (vu8*)(I2C3_REG_OFF + I2C_REG_DATA),
-};
-inline vu8* i2cGetDataReg(u8 bus_id) {
- return reg_data_addrs[bus_id];
+ u32 i = 0;
+ for(; i < 8; i++)
+ {
+ i2cWaitBusy(i2cCnt);
+
+ // Select device and start.
+ *i2cData = devAddr;
+ *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_START;
+ i2cWaitBusy(i2cCnt);
+ if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed.
+ {
+ *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP;
+ continue;
+ }
+
+ // Select register and change direction to write.
+ *i2cData = regAddr;
+ *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE;
+ i2cWaitBusy(i2cCnt);
+ if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed.
+ {
+ *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP;
+ continue;
+ }
+
+ // Select device in read mode for read transfer.
+ if(read)
+ {
+ *i2cData = devAddr | 1u; // Set bit 0 for read.
+ *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_START;
+ i2cWaitBusy(i2cCnt);
+ if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed.
+ {
+ *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP;
+ continue;
+ }
+ }
+
+ break;
+ }
+
+ if(i < 8) return true;
+ else return false;
}
-//-----------------------------------------------------------------------------
+void I2C_init(void)
+{
+ i2cWaitBusy(i2cGetBusRegsBase(0));
+ REG_I2C1_CNTEX = 2; // ?
+ REG_I2C1_SCL = 1280; // ?
-static vu8* reg_cnt_addrs[] = {
- (vu8*)(I2C1_REG_OFF + I2C_REG_CNT),
- (vu8*)(I2C2_REG_OFF + I2C_REG_CNT),
- (vu8*)(I2C3_REG_OFF + I2C_REG_CNT),
-};
+ i2cWaitBusy(i2cGetBusRegsBase(1));
+ REG_I2C2_CNTEX = 2; // ?
+ REG_I2C2_SCL = 1280; // ?
-inline vu8* i2cGetCntReg(u8 bus_id) {
- return reg_cnt_addrs[bus_id];
+ i2cWaitBusy(i2cGetBusRegsBase(2));
+ REG_I2C3_CNTEX = 2; // ?
+ REG_I2C3_SCL = 1280; // ?
}
-//-----------------------------------------------------------------------------
+bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size)
+{
+ const u8 busId = i2cDevTable[devId].busId;
+ vu8 *const i2cData = i2cGetBusRegsBase(busId);
+ vu8 *const i2cCnt = i2cData + 1;
-inline void i2cWaitBusy(u8 bus_id) {
- while (*i2cGetCntReg(bus_id) & 0x80);
+
+ if(!i2cStartTransfer(devId, regAddr, true, i2cData)) return false;
+
+ while(--size)
+ {
+ *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_ACK;
+ i2cWaitBusy(i2cCnt);
+ *out++ = *i2cData;
+ }
+
+ *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_STOP;
+ i2cWaitBusy(i2cCnt);
+ *out = *i2cData; // Last byte
+
+ return true;
}
-inline bool i2cGetResult(u8 bus_id) {
- i2cWaitBusy(bus_id);
- return (*i2cGetCntReg(bus_id) >> 4) & 1;
-}
-
-void i2cStop(u8 bus_id, u8 arg0) {
- *i2cGetCntReg(bus_id) = (arg0 << 5) | 0xC0;
- i2cWaitBusy(bus_id);
- *i2cGetCntReg(bus_id) = 0xC5;
-}
-
-//-----------------------------------------------------------------------------
-
-bool i2cSelectDevice(u8 bus_id, u8 dev_reg) {
- i2cWaitBusy(bus_id);
- *i2cGetDataReg(bus_id) = dev_reg;
- *i2cGetCntReg(bus_id) = 0xC2;
- return i2cGetResult(bus_id);
-}
-
-bool i2cSelectRegister(u8 bus_id, u8 reg) {
- i2cWaitBusy(bus_id);
- *i2cGetDataReg(bus_id) = reg;
- *i2cGetCntReg(bus_id) = 0xC0;
- return i2cGetResult(bus_id);
-}
-
-//-----------------------------------------------------------------------------
-
-u8 i2cReadRegister(u8 dev_id, u8 reg) {
- u8 bus_id = i2cGetDeviceBusId(dev_id);
- u8 dev_addr = i2cGetDeviceRegAddr(dev_id);
-
- for (size_t i = 0; i < 8; i++) {
- if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg)) {
- if (i2cSelectDevice(bus_id, dev_addr | 1)) {
- i2cWaitBusy(bus_id);
- i2cStop(bus_id, 1);
- i2cWaitBusy(bus_id);
- return *i2cGetDataReg(bus_id);
- }
- }
- *i2cGetCntReg(bus_id) = 0xC5;
- i2cWaitBusy(bus_id);
- }
-
- return 0xff;
-}
-
-bool i2cReadRegisterBuffer(unsigned int dev_id, int reg, u8* buffer, size_t buf_size) {
- u8 bus_id = i2cGetDeviceBusId(dev_id);
- u8 dev_addr = i2cGetDeviceRegAddr(dev_id);
-
- size_t j = 0;
- while (!i2cSelectDevice(bus_id, dev_addr)
- || !i2cSelectRegister(bus_id, reg)
- || !i2cSelectDevice(bus_id, dev_addr | 1))
- {
- i2cWaitBusy(bus_id);
- *i2cGetCntReg(bus_id) = 0xC5;
- i2cWaitBusy(bus_id);
- if (++j >= 8)
- return false;
- }
-
- if (buf_size != 1) {
- for (size_t i = 0; i < buf_size - 1; i++) {
- i2cWaitBusy(bus_id);
- *i2cGetCntReg(bus_id) = 0xF0;
- i2cWaitBusy(bus_id);
- buffer[i] = *i2cGetDataReg(bus_id);
- }
- }
-
- i2cWaitBusy(bus_id);
- *i2cGetCntReg(bus_id) = 0xE1;
- i2cWaitBusy(bus_id);
- buffer[buf_size - 1] = *i2cGetDataReg(bus_id);
-
- return true;
-}
-
-bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data) {
- u8 bus_id = i2cGetDeviceBusId(dev_id);
- u8 dev_addr = i2cGetDeviceRegAddr(dev_id);
-
- wait_msec(3ULL);
- for (int i = 0; i < 8; i++) {
- if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg)) {
- i2cWaitBusy(bus_id);
- *i2cGetDataReg(bus_id) = data;
- *i2cGetCntReg(bus_id) = 0xC1;
- i2cStop(bus_id, 0);
- if (i2cGetResult(bus_id)) {
- wait_msec(3ULL);
- return true;
- }
- }
- *i2cGetCntReg(bus_id) = 0xC5;
- i2cWaitBusy(bus_id);
- }
-
- wait_msec(3ULL);
- return false;
+bool I2C_writeReg(I2cDevice devId, u8 regAddr, u8 data)
+{
+ const u8 busId = i2cDevTable[devId].busId;
+ vu8 *const i2cData = i2cGetBusRegsBase(busId);
+ vu8 *const i2cCnt = i2cData + 1;
+
+
+ if(!i2cStartTransfer(devId, regAddr, false, i2cData)) return false;
+
+ *i2cData = data;
+ *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE | I2C_STOP;
+ i2cWaitBusy(i2cCnt);
+
+ if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed.
+ {
+ *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP;
+ return false;
+ }
+
+ return true;
}
diff --git a/source/common/i2c.h b/source/common/i2c.h
index f047c17..8229e3f 100644
--- a/source/common/i2c.h
+++ b/source/common/i2c.h
@@ -1,35 +1,56 @@
#pragma once
+/*
+ * This file is part of fastboot 3DS
+ * Copyright (C) 2017 derrek, profi200
+ *
+ * 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 3 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, see .
+ */
+
+#include
#include "common.h"
-#define I2C1_REG_OFF 0x10161000
-#define I2C2_REG_OFF 0x10144000
-#define I2C3_REG_OFF 0x10148000
-#define I2C_REG_DATA 0
-#define I2C_REG_CNT 1
-#define I2C_REG_CNTEX 2
-#define I2C_REG_SCL 4
+#define I2C_STOP (1u)
+#define I2C_START (1u<<1)
+#define I2C_ERROR (1u<<2)
+#define I2C_ACK (1u<<4)
+#define I2C_DIRE_WRITE (0u)
+#define I2C_DIRE_READ (1u<<5)
+#define I2C_IRQ_ENABLE (1u<<6)
+#define I2C_ENABLE (1u<<7)
-#define I2C_DEV_MCU 3
-#define I2C_DEV_GYRO 10
-#define I2C_DEV_IR 13
+#define I2C_GET_ACK(reg) ((bool)((reg)>>4 & 1u))
-u8 i2cGetDeviceBusId(u8 device_id);
-u8 i2cGetDeviceRegAddr(u8 device_id);
-vu8* i2cGetDataReg(u8 bus_id);
-vu8* i2cGetCntReg(u8 bus_id);
+typedef enum
+{
+ I2C_DEV_POWER = 0, // Unconfirmed
+ I2C_DEV_CAMERA = 1, // Unconfirmed
+ I2C_DEV_CAMERA2 = 2, // Unconfirmed
+ I2C_DEV_MCU = 3,
+ I2C_DEV_GYRO = 10,
+ I2C_DEV_DEBUG_PAD = 12,
+ I2C_DEV_IR = 13,
+ I2C_DEV_EEPROM = 14, // Unconfirmed
+ I2C_DEV_NFC = 15,
+ I2C_DEV_QTM = 16,
+ I2C_DEV_N3DS_HID = 17
+} I2cDevice;
-void i2cWaitBusy(u8 bus_id);
-bool i2cGetResult(u8 bus_id);
-u8 i2cGetData(u8 bus_id);
-void i2cStop(u8 bus_id, u8 arg0);
-bool i2cSelectDevice(u8 bus_id, u8 dev_reg);
-bool i2cSelectRegister(u8 bus_id, u8 reg);
-u8 i2cReadRegister(u8 dev_id, u8 reg);
-bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data);
-
-bool i2cReadRegisterBuffer(unsigned int dev_id, int reg, u8* buffer, size_t buf_size);
+void I2C_init(void);
+bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size);
+bool I2C_writeReg(I2cDevice devId, u8 regAddr, u8 data);
diff --git a/source/common/power.c b/source/common/power.c
index 18b90bb..4b91905 100644
--- a/source/common/power.c
+++ b/source/common/power.c
@@ -6,14 +6,14 @@
void Reboot() {
ClearScreenF(true, true, COLOR_STD_BG);
flushEntireDCache();
- i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2);
- while(true);
+ if (I2C_writeReg(I2C_DEV_MCU, 0x20, 1 << 2))
+ while(true);
}
void PowerOff()
{
ClearScreenF(true, true, COLOR_STD_BG);
flushEntireDCache();
- i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 0);
- while (true);
+ if (I2C_writeReg(I2C_DEV_MCU, 0x20, 1 << 0))
+ while (true);
}
diff --git a/source/godmode.c b/source/godmode.c
index cb798a4..ad7e229 100644
--- a/source/godmode.c
+++ b/source/godmode.c
@@ -23,6 +23,8 @@
#include "chainload.h"
#include "qlzcomp.h"
#include "timer.h"
+#include "power.h"
+#include "i2c.h"
#include QLZ_SPLASH_H
#define N_PANES 2
@@ -1599,6 +1601,9 @@ u32 GodMode() {
clipboard->n_entries = 0;
memset(panedata, 0x00, 0x10000);
+ // I2C init
+ // I2C_init();
+
// check for embedded essential backup
if (IS_SIGHAX && !PathExist("S:/essential.exefs") && CheckGenuineNandNcsd() &&
ShowPrompt(true, "Essential files backup not found.\nCreate one now?")) {