mirror of
https://github.com/skawo/GodMode9-with-Cartridge-Fixer.git
synced 2025-06-19 01:15:33 -04:00

- properly performs gpu/backlight reset - nukes vram so the initrd had to be moved to arm9 memory, and have its size (at least temporarily) limited to 256k
203 lines
4.1 KiB
C
Executable File
203 lines
4.1 KiB
C
Executable File
/*
|
|
* This file is part of GodMode9
|
|
* Copyright (C) 2019 Wolfvak
|
|
*
|
|
* 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, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <hid_map.h>
|
|
#include <types.h>
|
|
#include <arm.h>
|
|
|
|
#include "arm/timer.h"
|
|
|
|
#include "hw/gpio.h"
|
|
#include "hw/gpulcd.h"
|
|
#include "hw/mcu.h"
|
|
|
|
enum {
|
|
MCU_PWR_BTN = 0,
|
|
MCU_PWR_HOLD = 1,
|
|
MCU_HOME_BTN = 2,
|
|
MCU_HOME_LIFT = 3,
|
|
MCU_WIFI_SWITCH = 4,
|
|
MCU_SHELL_CLOSE = 5,
|
|
MCU_SHELL_OPEN = 6,
|
|
MCU_VOL_SLIDER = 22,
|
|
};
|
|
|
|
enum {
|
|
REG_VOL_SLIDER = 0x09,
|
|
|
|
REG_BATTERY_LEVEL = 0x0B,
|
|
REG_CONSOLE_STATE = 0x0F,
|
|
|
|
REG_INT_MASK = 0x10,
|
|
REG_INT_EN = 0x18,
|
|
|
|
REG_LCD_STATE = 0x22,
|
|
|
|
REG_LED_WIFI = 0x2A,
|
|
REG_LED_CAMERA = 0x2B,
|
|
REG_LED_SLIDER = 0x2C,
|
|
REG_LED_NOTIF = 0x2D,
|
|
|
|
REG_RTC = 0x30,
|
|
};
|
|
|
|
typedef struct {
|
|
u8 delay;
|
|
u8 smoothing;
|
|
u8 loop_delay;
|
|
u8 unk;
|
|
u32 red[8];
|
|
u32 green[8];
|
|
u32 blue[8];
|
|
} PACKED_STRUCT MCU_NotificationLED;
|
|
|
|
static u8 cached_volume_slider = 0;
|
|
static u32 spec_hid = 0, shell_state = SHELL_OPEN;
|
|
|
|
static void MCU_UpdateVolumeSlider(void)
|
|
{
|
|
cached_volume_slider = MCU_ReadReg(REG_VOL_SLIDER);
|
|
}
|
|
|
|
static void MCU_UpdateShellState(bool open)
|
|
{
|
|
shell_state = open ? SHELL_OPEN : SHELL_CLOSED;
|
|
}
|
|
|
|
u8 MCU_GetVolumeSlider(void)
|
|
{
|
|
return cached_volume_slider;
|
|
}
|
|
|
|
u32 MCU_GetSpecialHID(void)
|
|
{
|
|
u32 ret = spec_hid | shell_state;
|
|
spec_hid = 0;
|
|
return ret;
|
|
}
|
|
|
|
void MCU_SetNotificationLED(u32 period_ms, u32 color)
|
|
{
|
|
u32 r, g, b;
|
|
MCU_NotificationLED led_state;
|
|
|
|
// handle proper non-zero periods
|
|
// so small the hardware can't handle it
|
|
if (period_ms != 0 && period_ms < 63)
|
|
period_ms = 63;
|
|
|
|
led_state.delay = (period_ms * 0x10) / 1000;
|
|
led_state.smoothing = 0x40;
|
|
led_state.loop_delay = 0x10;
|
|
led_state.unk = 0;
|
|
|
|
// all colors look like 0x00ZZ00ZZ
|
|
// in order to alternate between
|
|
// LED "off" and the wanted color
|
|
r = (color >> 16) & 0xFF;
|
|
r |= r << 16;
|
|
for (int i = 0; i < 8; i++)
|
|
led_state.red[i] = r;
|
|
|
|
g = (color >> 8) & 0xFF;
|
|
g |= g << 16;
|
|
for (int i = 0; i < 8; i++)
|
|
led_state.green[i] = g;
|
|
|
|
b = color & 0xFF;
|
|
b |= b << 16;
|
|
for (int i = 0; i < 8; i++)
|
|
led_state.blue[i] = b;
|
|
|
|
MCU_WriteRegBuf(REG_LED_NOTIF, (const u8*)&led_state, sizeof(led_state));
|
|
}
|
|
|
|
void MCU_ResetLED(void)
|
|
{
|
|
MCU_WriteReg(REG_LED_WIFI, 0);
|
|
MCU_WriteReg(REG_LED_CAMERA, 0);
|
|
MCU_WriteReg(REG_LED_SLIDER, 0);
|
|
MCU_SetNotificationLED(0, 0);
|
|
}
|
|
|
|
void MCU_HandleInterrupts(u32 __attribute__((unused)) irqn)
|
|
{
|
|
u32 ints;
|
|
|
|
// Reading the pending mask automagically acknowledges
|
|
// the interrupts so all of them must be processed in one go
|
|
MCU_ReadRegBuf(REG_INT_MASK, (u8*)&ints, sizeof(ints));
|
|
|
|
while(ints != 0) {
|
|
u32 mcu_int_id = 31 - __builtin_clz(ints);
|
|
|
|
switch(mcu_int_id) {
|
|
case MCU_PWR_BTN:
|
|
case MCU_PWR_HOLD:
|
|
spec_hid |= BUTTON_POWER;
|
|
break;
|
|
|
|
case MCU_HOME_BTN:
|
|
spec_hid |= BUTTON_HOME;
|
|
break;
|
|
|
|
case MCU_HOME_LIFT:
|
|
spec_hid &= ~BUTTON_HOME;
|
|
break;
|
|
|
|
case MCU_WIFI_SWITCH:
|
|
spec_hid |= BUTTON_WIFI;
|
|
break;
|
|
|
|
case MCU_SHELL_OPEN:
|
|
MCU_UpdateShellState(true);
|
|
MCU_ResetLED();
|
|
break;
|
|
|
|
case MCU_SHELL_CLOSE:
|
|
MCU_UpdateShellState(false);
|
|
break;
|
|
|
|
case MCU_VOL_SLIDER:
|
|
MCU_UpdateVolumeSlider();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
ints &= ~BIT(mcu_int_id);
|
|
}
|
|
}
|
|
|
|
void MCU_Init(void)
|
|
{
|
|
u32 clrpend, mask = 0;
|
|
|
|
/* set register mask and clear any pending registers */
|
|
MCU_WriteRegBuf(REG_INT_EN, (const u8*)&mask, sizeof(mask));
|
|
MCU_ReadRegBuf(REG_INT_MASK, (u8*)&clrpend, sizeof(clrpend));
|
|
|
|
MCU_ResetLED();
|
|
|
|
MCU_UpdateVolumeSlider();
|
|
MCU_UpdateShellState(MCU_ReadReg(REG_CONSOLE_STATE) & BIT(1));
|
|
|
|
GPIO_setBit(19, 9);
|
|
}
|