From 2bc6dec1267c742892db76d7a764342a0ce3b99d Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Fri, 20 Nov 2020 22:29:24 -0800 Subject: [PATCH] exo/mariko fatal: stop sound output on fatal error --- exosphere/mariko_fatal/source/fatal_main.cpp | 10 ++- exosphere/mariko_fatal/source/fatal_sound.cpp | 62 +++++++++++++++++++ exosphere/mariko_fatal/source/fatal_sound.hpp | 23 +++++++ .../fatal/source/fatal_task_sound.cpp | 20 +++--- 4 files changed, 102 insertions(+), 13 deletions(-) create mode 100644 exosphere/mariko_fatal/source/fatal_sound.cpp create mode 100644 exosphere/mariko_fatal/source/fatal_sound.hpp diff --git a/exosphere/mariko_fatal/source/fatal_main.cpp b/exosphere/mariko_fatal/source/fatal_main.cpp index 205f3a845..7afde1017 100644 --- a/exosphere/mariko_fatal/source/fatal_main.cpp +++ b/exosphere/mariko_fatal/source/fatal_main.cpp @@ -16,6 +16,7 @@ #include #include "fatal_sdmmc.hpp" #include "fatal_save_context.hpp" +#include "fatal_sound.hpp" #include "fatal_display.hpp" namespace ams::secmon::fatal { @@ -60,10 +61,17 @@ namespace ams::secmon::fatal { AMS_SECMON_LOG("Failed to save fatal error context: %08x\n", result.GetValue()); } - /* Ensure that i2c-5 is usable for communicating with the pmic. */ + /* Ensure that i2c-1/i2c-5 are usable for communicating with the audio device/pmic. */ + clkrst::EnableI2c1Clock(); clkrst::EnableI2c5Clock(); + i2c::Initialize(i2c::Port_1); i2c::Initialize(i2c::Port_5); + /* Shut down audio. */ + { + StopSound(); + } + /* Display the fatal error. */ { AMS_SECMON_LOG("Showing Display, LCD Vendor = %04x\n", GetLcdVendor()); diff --git a/exosphere/mariko_fatal/source/fatal_sound.cpp b/exosphere/mariko_fatal/source/fatal_sound.cpp new file mode 100644 index 000000000..7ce00b080 --- /dev/null +++ b/exosphere/mariko_fatal/source/fatal_sound.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 "fatal_sound.hpp" + +namespace ams::secmon::fatal { + + namespace { + + constexpr inline int I2cAddressMaxAlc5639 = 0x1C; + + constexpr inline uintptr_t GPIO = secmon::MemoryRegionVirtualDeviceGpio.GetAddress(); + + constexpr size_t GPIO_PORT7_CNF_1 = 0x604; + constexpr size_t GPIO_PORT7_OE_1 = 0x614; + constexpr size_t GPIO_PORT7_OUT_1 = 0x624; + + void WriteAlc5639Register(int r, u16 val) { + i2c::Send(i2c::Port_1, I2cAddressMaxAlc5639, r, std::addressof(val), sizeof(val)); + } + + } + + void StopSound() { + /* Mute output to the speaker, setting left/right volume to 0 DB. */ + WriteAlc5639Register(0x01, 0xC8C8); + + /* Mute output to headphones, setting left/right volume to 0 DB. */ + WriteAlc5639Register(0x02, 0xC8C8); + + /* Clear all Power Management Control registers by writing 0x0000 to them. */ + for (int r = 0x61; r <= 0x66; ++r) { + WriteAlc5639Register(r, 0x0000); + } + + /* Configure CodecLdoEn as GPIO. */ + reg::SetBits(GPIO + GPIO_PORT7_CNF_1, (1u << 4)); + + /* Configure CodecLdoEn as Output. */ + reg::SetBits(GPIO + GPIO_PORT7_OE_1, (1u << 4)); + + /* Wait 200 milliseconds for config to take effect. */ + util::WaitMicroSeconds(200'000ul); + + /* Pull CodecLdoEn low. */ + reg::ClearBits(GPIO + GPIO_PORT7_OUT_1, (1u << 4)); + } + +} diff --git a/exosphere/mariko_fatal/source/fatal_sound.hpp b/exosphere/mariko_fatal/source/fatal_sound.hpp new file mode 100644 index 000000000..462deb9fe --- /dev/null +++ b/exosphere/mariko_fatal/source/fatal_sound.hpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 . + */ +#pragma once +#include + +namespace ams::secmon::fatal { + + void StopSound(); + +} diff --git a/stratosphere/fatal/source/fatal_task_sound.cpp b/stratosphere/fatal/source/fatal_task_sound.cpp index ad5d6eb59..a22d9ecf4 100644 --- a/stratosphere/fatal/source/fatal_task_sound.cpp +++ b/stratosphere/fatal/source/fatal_task_sound.cpp @@ -43,25 +43,21 @@ namespace ams::fatal::srv { ON_SCOPE_EXIT { i2csessionClose(&audio); }; struct { - u16 dev; - u8 val; + u8 reg; + u16 val; } __attribute__((packed)) cmd; static_assert(sizeof(cmd) == 3, "I2C command definition!"); - cmd.dev = 0xC801; - cmd.val = 200; + cmd.reg = 0x01; + cmd.val = 0xC8C8; i2csessionSendAuto(&audio, &cmd, sizeof(cmd), I2cTransactionOption_All); - cmd.dev = 0xC802; - cmd.val = 200; + cmd.reg = 0x02; + cmd.val = 0xC8C8; i2csessionSendAuto(&audio, &cmd, sizeof(cmd), I2cTransactionOption_All); - cmd.dev = 0xC802; - cmd.val = 200; - i2csessionSendAuto(&audio, &cmd, sizeof(cmd), I2cTransactionOption_All); - - for (u16 dev = 97; dev <= 102; dev++) { - cmd.dev = dev; + for (u8 reg = 97; reg <= 102; reg++) { + cmd.reg = reg; cmd.val = 0; i2csessionSendAuto(&audio, &cmd, sizeof(cmd), I2cTransactionOption_All); }