From a6c6a950531b37789e82897008f894b96a41aa4b Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 27 Oct 2020 23:32:45 -0700 Subject: [PATCH] sdmmc: finish outward-facing api (untested) --- .../libvapours/include/vapours/sdmmc.hpp | 1 + .../include/vapours/sdmmc/sdmmc_gc_asic.hpp | 34 ++ .../impl/sdmmc_gc_asic_device_accessor.cpp | 352 ++++++++++++++++++ .../impl/sdmmc_gc_asic_device_accessor.hpp | 96 +++++ .../sdmmc/impl/sdmmc_mmc_device_accessor.cpp | 2 +- .../source/sdmmc/impl/sdmmc_port_gc_asic0.cpp | 11 +- .../source/sdmmc/impl/sdmmc_port_gc_asic0.hpp | 2 + .../impl/sdmmc_sd_card_device_accessor.cpp | 2 +- .../libvapours/source/sdmmc/sdmmc_common.cpp | 4 +- .../libvapours/source/sdmmc/sdmmc_gc_asic.cpp | 85 +++++ 10 files changed, 584 insertions(+), 5 deletions(-) create mode 100644 libraries/libvapours/include/vapours/sdmmc/sdmmc_gc_asic.hpp create mode 100644 libraries/libvapours/source/sdmmc/impl/sdmmc_gc_asic_device_accessor.cpp create mode 100644 libraries/libvapours/source/sdmmc/impl/sdmmc_gc_asic_device_accessor.hpp create mode 100644 libraries/libvapours/source/sdmmc/sdmmc_gc_asic.cpp diff --git a/libraries/libvapours/include/vapours/sdmmc.hpp b/libraries/libvapours/include/vapours/sdmmc.hpp index 43c39906e..444071a17 100644 --- a/libraries/libvapours/include/vapours/sdmmc.hpp +++ b/libraries/libvapours/include/vapours/sdmmc.hpp @@ -25,3 +25,4 @@ #include #include #include +#include diff --git a/libraries/libvapours/include/vapours/sdmmc/sdmmc_gc_asic.hpp b/libraries/libvapours/include/vapours/sdmmc/sdmmc_gc_asic.hpp new file mode 100644 index 000000000..a1355de55 --- /dev/null +++ b/libraries/libvapours/include/vapours/sdmmc/sdmmc_gc_asic.hpp @@ -0,0 +1,34 @@ +/* + * 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::sdmmc { + + constexpr inline size_t GcAsicOperationSize = 0x40; + + void PutGcAsicToSleep(Port port); + Result AwakenGcAsic(Port port); + Result WriteGcAsicOperation(Port port, const void *op_buf, size_t op_buf_size); + Result FinishGcAsicOperation(Port port); + Result AbortGcAsicOperation(Port port); + Result SleepGcAsic(Port port); + Result UpdateGcAsicKey(Port port); + + void SignalGcRemovedEvent(Port port); + void ClearGcRemovedEvent(Port port); + +} diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_gc_asic_device_accessor.cpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_gc_asic_device_accessor.cpp new file mode 100644 index 000000000..a1ebe02f6 --- /dev/null +++ b/libraries/libvapours/source/sdmmc/impl/sdmmc_gc_asic_device_accessor.cpp @@ -0,0 +1,352 @@ +/* + * 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 . + */ +#if defined(ATMOSPHERE_IS_STRATOSPHERE) +#include +#elif defined(ATMOSPHERE_IS_MESOSPHERE) +#include +#elif defined(ATMOSPHERE_IS_EXOSPHERE) +#include +#else +#include +#endif +#include "sdmmc_gc_asic_device_accessor.hpp" +#include "sdmmc_timer.hpp" + +namespace ams::sdmmc::impl { + + #if defined(AMS_SDMMC_THREAD_SAFE) + + #define AMS_SDMMC_LOCK_GC_ASIC_DEVICE_MUTEX() std::scoped_lock lk(this->gc_asic_device.device_mutex) + + #else + + #define AMS_SDMMC_LOCK_GC_ASIC_DEVICE_MUTEX() + + #endif + + #if defined(AMS_SDMMC_USE_OS_EVENTS) + + #define AMS_SDMMC_CHECK_GC_ASIC_REMOVED() R_UNLESS(!this->gc_asic_device.IsRemoved(), sdmmc::ResultDeviceRemoved()) + + #else + + #define AMS_SDMMC_CHECK_GC_ASIC_REMOVED() + + #endif + + Result GcAsicDeviceAccessor::IssueCommandWriteOperation(const void *op_buf, size_t op_buf_size) const { + /* Validate the operation buffer. */ + AMS_ABORT_UNLESS(op_buf != nullptr); + AMS_ABORT_UNLESS(op_buf_size >= GcAsicOperationSize); + + /* Issue the command. */ + constexpr ResponseType CommandResponseType = ResponseType_R1; + Command command(CommandIndex_GcAsicWriteOperation, 0, CommandResponseType, false); + TransferData xfer_data(const_cast(op_buf), GcAsicOperationSize, 1, TransferDirection_WriteToDevice); + IHostController *hc = BaseDeviceAccessor::GetHostController(); + Result result = hc->IssueCommand(std::addressof(command), std::addressof(xfer_data)); + if (R_FAILED(result)) { + /* We failed to write operation. Check if we were removed. */ + AMS_SDMMC_CHECK_GC_ASIC_REMOVED(); + + /* Determine what result we should return. */ + Result return_result = result; + { + /* Issue a stop transmission command. */ + u32 resp = 0; + result = hc->IssueStopTransmissionCommand(std::addressof(resp)); + if (R_SUCCEEDED(result)) { + /* If we successfully stopped transmission but have an error status, we prefer to return that. */ + result = this->gc_asic_device.CheckDeviceStatus(resp); + if (R_FAILED(result)) { + return_result = result; + } + } + + /* Check again if we were removed. */ + AMS_SDMMC_CHECK_GC_ASIC_REMOVED(); + + /* Request device status. */ + u32 device_status; + result = BaseDeviceAccessor::IssueCommandSendStatus(std::addressof(device_status), 0); + + /* If we got a device status error here and we didn't previously, we prefer to return that. */ + if (!sdmmc::ResultDeviceStatusHasError::Includes(return_result) && sdmmc::ResultDeviceStatusHasError::Includes(result)) { + return_result = result; + } + } + return return_result; + } + + /* Get the response. */ + u32 resp; + hc->GetLastResponse(std::addressof(resp), sizeof(resp), CommandResponseType); + R_TRY(this->gc_asic_device.CheckDeviceStatus(resp)); + + return ResultSuccess(); + } + + Result GcAsicDeviceAccessor::IssueCommandFinishOperation() const { + /* Issue the command. */ + R_TRY(BaseDeviceAccessor::IssueCommandAndCheckR1(CommandIndex_GcAsicFinishOperation, 0, true, DeviceState_Tran)); + return ResultSuccess(); + } + + Result GcAsicDeviceAccessor::IssueCommandSleep() { + /* Issue the command. */ + R_TRY(BaseDeviceAccessor::IssueCommandAndCheckR1(CommandIndex_GcAsicSleep, 0, true, DeviceState_Tran)); + return ResultSuccess(); + } + + Result GcAsicDeviceAccessor::IssueCommandUpdateKey() const { + /* Issue the command. */ + R_TRY(BaseDeviceAccessor::IssueCommandAndCheckR1(CommandIndex_GcAsicUpdateKey, 0, true, DeviceState_Tran)); + return ResultSuccess(); + } + + Result GcAsicDeviceAccessor::StartupGcAsicDevice() { + /* Start up the host controller. */ + IHostController *hc = BaseDeviceAccessor::GetHostController(); + R_TRY(hc->Startup(BusPower_1_8V, BusWidth_8Bit, SpeedMode_GcAsicSpeed, false)); + + /* Wait 10 clocks for configuration to take. */ + WaitClocks(10, hc->GetDeviceClockFrequencyKHz()); + + /* Perform tuning with command index 21. */ + AMS_ABORT_UNLESS(hc->IsSupportedTuning()); + R_TRY(hc->Tuning(SpeedMode_GcAsicSpeed, 21)); + + /* Set the device as low capacity/no memory. */ + this->gc_asic_device.SetHighCapacity(false); + this->gc_asic_device.SetMemoryCapacity(0); + + /* Enable power saving. */ + hc->SetPowerSaving(true); + + return ResultSuccess(); + } + + Result GcAsicDeviceAccessor::OnActivate() { + /* If we fail to start up the device, ensure the host controller is shut down. */ + auto power_guard = SCOPE_GUARD { BaseDeviceAccessor::GetHostController()->Shutdown(); }; + + /* Try to start up the device. */ + R_TRY(this->StartupGcAsicDevice()); + + /* We started up, so we don't need to power down. */ + power_guard.Cancel(); + return ResultSuccess(); + } + + Result GcAsicDeviceAccessor::OnReadWrite(u32 sector_index, u32 num_sectors, void *buf, size_t buf_size, bool is_read) { + /* Check that we're not performing zero-byte rw. */ + AMS_ABORT_UNLESS(num_sectors > 0); + + /* Check that the buffer is big enough for the rw. */ + AMS_ABORT_UNLESS((buf_size / SectorSize) >= num_sectors); + + /* Perform the read/write. */ + u32 num_transferred_blocks; + R_TRY(BaseDeviceAccessor::ReadWriteSingle(std::addressof(num_transferred_blocks), sector_index, num_sectors, buf, is_read)); + + /* Require that we read/wrote as many sectors as we expected. */ + AMS_ABORT_UNLESS(num_transferred_blocks == num_sectors); + + return ResultSuccess(); + } + + void GcAsicDeviceAccessor::Initialize() { + /* Acquire exclusive access to the device. */ + AMS_SDMMC_LOCK_GC_ASIC_DEVICE_MUTEX(); + + /* If we've already initialized, we don't need to do anything. */ + if (this->is_initialized) { + return; + } + + /* Set the base device to our gc asic device. */ + BaseDeviceAccessor::SetDevice(std::addressof(this->gc_asic_device)); + + /* Initialize. */ + IHostController *hc = BaseDeviceAccessor::GetHostController(); + #if defined(AMS_SDMMC_USE_OS_EVENTS) + { + this->gc_asic_device.InitializeRemovedEvent(); + hc->PreSetRemovedEvent(this->gc_asic_device.GetRemovedEvent()); + } + #endif + hc->Initialize(); + + /* Mark ourselves as initialized. */ + this->is_initialized = true; + } + + void GcAsicDeviceAccessor::Finalize() { + /* Acquire exclusive access to the device. */ + AMS_SDMMC_LOCK_GC_ASIC_DEVICE_MUTEX(); + + /* If we've already finalized, we don't need to do anything. */ + if (!this->is_initialized) { + return; + } + this->is_initialized = false; + + /* Deactivate the device. */ + BaseDeviceAccessor::Deactivate(); + + /* Finalize the host controller. */ + BaseDeviceAccessor::GetHostController()->Finalize(); + + /* Finalize the removed event. */ + #if defined(AMS_SDMMC_USE_OS_EVENTS) + { + this->gc_asic_device.FinalizeRemovedEvent(); + } + #endif + } + + Result GcAsicDeviceAccessor::GetSpeedMode(SpeedMode *out_speed_mode) const { + /* Check that we can write to output. */ + AMS_ABORT_UNLESS(out_speed_mode != nullptr); + + /* Acquire exclusive access to the device. */ + AMS_SDMMC_LOCK_GC_ASIC_DEVICE_MUTEX(); + + /* Check that we're accessible. */ + R_TRY(this->gc_asic_device.CheckAccessible()); + + *out_speed_mode = SpeedMode_GcAsicSpeed; + return ResultSuccess(); + } + + void GcAsicDeviceAccessor::PutGcAsicToSleep() { + /* Acquire exclusive access to the device. */ + AMS_SDMMC_LOCK_GC_ASIC_DEVICE_MUTEX(); + + /* If the device isn't awake, we don't need to do anything. */ + if (!this->gc_asic_device.IsAwake()) { + return; + } + + /* If necessary, put the host controller to sleep. */ + #if defined(AMS_SDMMC_USE_OS_EVENTS) + if (this->gc_asic_device.IsActive() && !this->gc_asic_device.IsRemoved()) + #else + if (this->gc_asic_device.IsActive()) + #endif + { + BaseDeviceAccessor::GetHostController()->PutToSleep(); + } + + /* Put the gc asic device to sleep. */ + this->gc_asic_device.PutToSleep(); + } + + Result GcAsicDeviceAccessor::AwakenGcAsic() { + /* Acquire exclusive access to the device. */ + AMS_SDMMC_LOCK_GC_ASIC_DEVICE_MUTEX(); + + /* If the device is awake, we don't need to do anything. */ + R_SUCCEED_IF(this->gc_asic_device.IsAwake()); + + /* Wake the device. */ + this->gc_asic_device.Awaken(); + + /* Wake the host controller, if we need to.*/ + #if defined(AMS_SDMMC_USE_OS_EVENTS) + if (this->gc_asic_device.IsActive() && !this->gc_asic_device.IsRemoved()) + #else + if (this->gc_asic_device.IsActive()) + #endif + { + R_TRY(BaseDeviceAccessor::GetHostController()->Awaken()); + } + + return ResultSuccess(); + } + + Result GcAsicDeviceAccessor::WriteGcAsicOperation(const void *op_buf, size_t op_buf_size) { + /* Acquire exclusive access to the device. */ + AMS_SDMMC_LOCK_GC_ASIC_DEVICE_MUTEX(); + + /* Check that we're accessible. */ + R_TRY(this->gc_asic_device.CheckAccessible()); + + /* Issue the command. */ + R_TRY(this->IssueCommandWriteOperation(op_buf, op_buf_size)); + R_TRY(BaseDeviceAccessor::IssueCommandSendStatus()); + + return ResultSuccess(); + } + + Result GcAsicDeviceAccessor::FinishGcAsicOperation() { + /* Acquire exclusive access to the device. */ + AMS_SDMMC_LOCK_GC_ASIC_DEVICE_MUTEX(); + + /* Check that we're accessible. */ + R_TRY(this->gc_asic_device.CheckAccessible()); + + /* Issue the command. */ + R_TRY(this->IssueCommandFinishOperation()); + R_TRY(BaseDeviceAccessor::IssueCommandSendStatus()); + + return ResultSuccess(); + } + + Result GcAsicDeviceAccessor::AbortGcAsicOperation() { + /* Acquire exclusive access to the device. */ + AMS_SDMMC_LOCK_GC_ASIC_DEVICE_MUTEX(); + + /* Check that we're accessible. */ + R_TRY(this->gc_asic_device.CheckAccessible()); + + /* Issue stop transmission command. */ + u32 resp = 0; + R_TRY(BaseDeviceAccessor::GetHostController()->IssueStopTransmissionCommand(std::addressof(resp))); + R_TRY(this->gc_asic_device.CheckDeviceStatus(resp)); + + return ResultSuccess(); + } + + Result GcAsicDeviceAccessor::SleepGcAsic() { + /* Acquire exclusive access to the device. */ + AMS_SDMMC_LOCK_GC_ASIC_DEVICE_MUTEX(); + + /* Check that we're accessible. */ + R_TRY(this->gc_asic_device.CheckAccessible()); + + /* Issue the command. */ + R_TRY(this->IssueCommandSleep()); + R_TRY(BaseDeviceAccessor::IssueCommandSendStatus()); + + return ResultSuccess(); + } + + Result GcAsicDeviceAccessor::UpdateGcAsicKey() { + /* Acquire exclusive access to the device. */ + AMS_SDMMC_LOCK_GC_ASIC_DEVICE_MUTEX(); + + /* Check that we're accessible. */ + R_TRY(this->gc_asic_device.CheckAccessible()); + + /* Issue the command. */ + R_TRY(this->IssueCommandUpdateKey()); + R_TRY(BaseDeviceAccessor::IssueCommandSendStatus()); + + return ResultSuccess(); + } + +} diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_gc_asic_device_accessor.hpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_gc_asic_device_accessor.hpp new file mode 100644 index 000000000..c6c24ec1c --- /dev/null +++ b/libraries/libvapours/source/sdmmc/impl/sdmmc_gc_asic_device_accessor.hpp @@ -0,0 +1,96 @@ +/* + * 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 +#include "sdmmc_base_device_accessor.hpp" + +namespace ams::sdmmc::impl { + + class GcAsicDevice : public BaseDevice { + private: + static constexpr u16 Rca = 0; + private: + #if defined(AMS_SDMMC_USE_OS_EVENTS) + mutable os::EventType removed_event; + #endif + public: + #if defined(AMS_SDMMC_USE_OS_EVENTS) + virtual os::EventType *GetRemovedEvent() const override { + return std::addressof(this->removed_event); + } + #endif + + virtual DeviceType GetDeviceType() const override { + return DeviceType_GcAsic; + } + + virtual u16 GetRca() const override { + return Rca; + } + }; + + class GcAsicDeviceAccessor : public BaseDeviceAccessor { + private: + GcAsicDevice gc_asic_device; + bool is_initialized; + private: + Result IssueCommandWriteOperation(const void *op_buf, size_t op_buf_size) const; + Result IssueCommandFinishOperation() const; + Result IssueCommandSleep(); + Result IssueCommandUpdateKey() const; + Result StartupGcAsicDevice(); + protected: + virtual Result OnActivate() override; + virtual Result OnReadWrite(u32 sector_index, u32 num_sectors, void *buf, size_t buf_size, bool is_read) override; + + virtual Result ReStartup() override { + AMS_ABORT("Can't ReStartup GcAsic\n"); + } + public: + virtual void Initialize() override; + virtual void Finalize() override; + virtual Result GetSpeedMode(SpeedMode *out_speed_mode) const override; + public: + explicit GcAsicDeviceAccessor(IHostController *hc) : BaseDeviceAccessor(hc), is_initialized(false) { + /* ... */ + } + + void PutGcAsicToSleep(); + Result AwakenGcAsic(); + Result WriteGcAsicOperation(const void *op_buf, size_t op_buf_size); + Result FinishGcAsicOperation(); + Result AbortGcAsicOperation(); + Result SleepGcAsic(); + Result UpdateGcAsicKey(); + + void SignalGcRemovedEvent() { + #if defined(AMS_SDMMC_USE_OS_EVENTS) + this->gc_asic_device.SignalRemovedEvent(); + #else + AMS_ABORT("SignalGcRemovedEvent called without event support\n"); + #endif + } + + void ClearGcRemovedEvent() { + #if defined(AMS_SDMMC_USE_OS_EVENTS) + this->gc_asic_device.ClearRemovedEvent(); + #else + AMS_ABORT("ClearGcRemovedEvent called without event support\n"); + #endif + } + }; + +} diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_mmc_device_accessor.cpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_mmc_device_accessor.cpp index 3a4d45d9b..7468aaba2 100644 --- a/libraries/libvapours/source/sdmmc/impl/sdmmc_mmc_device_accessor.cpp +++ b/libraries/libvapours/source/sdmmc/impl/sdmmc_mmc_device_accessor.cpp @@ -590,7 +590,7 @@ namespace ams::sdmmc::impl { AMS_SDMMC_LOCK_MMC_DEVICE_MUTEX(); /* If the device is awake, we don't need to do anything. */ - if (!this->mmc_device.IsAwake()) { + if (this->mmc_device.IsAwake()) { return; } diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_port_gc_asic0.cpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_port_gc_asic0.cpp index 6a321aa24..763869d54 100644 --- a/libraries/libvapours/source/sdmmc/impl/sdmmc_port_gc_asic0.cpp +++ b/libraries/libvapours/source/sdmmc/impl/sdmmc_port_gc_asic0.cpp @@ -22,7 +22,7 @@ #else #include #endif -#include "sdmmc_port_mmc0.hpp" +#include "sdmmc_port_gc_asic0.hpp" #include "sdmmc_select_sdmmc_controller.hpp" @@ -31,6 +31,7 @@ namespace ams::sdmmc::impl { namespace { SdmmcControllerForPortGcAsic0 g_gc_asic0_host_controller; + GcAsicDeviceAccessor g_gc_asic0_device_accessor(std::addressof(g_gc_asic0_host_controller)); } @@ -38,4 +39,12 @@ namespace ams::sdmmc::impl { return std::addressof(g_gc_asic0_host_controller); } + IDeviceAccessor *GetDeviceAccessorOfPortGcAsic0() { + return std::addressof(g_gc_asic0_device_accessor); + } + + GcAsicDeviceAccessor *GetGcAsicDeviceAccessorOfPortGcAsic0() { + return std::addressof(g_gc_asic0_device_accessor); + } + } diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_port_gc_asic0.hpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_port_gc_asic0.hpp index 7dada879f..8dc7880a0 100644 --- a/libraries/libvapours/source/sdmmc/impl/sdmmc_port_gc_asic0.hpp +++ b/libraries/libvapours/source/sdmmc/impl/sdmmc_port_gc_asic0.hpp @@ -17,10 +17,12 @@ #include #include "sdmmc_i_host_controller.hpp" #include "sdmmc_i_device_accessor.hpp" +#include "sdmmc_gc_asic_device_accessor.hpp" namespace ams::sdmmc::impl { IHostController *GetHostControllerOfPortGcAsic0(); IDeviceAccessor *GetDeviceAccessorOfPortGcAsic0(); + GcAsicDeviceAccessor *GetGcAsicDeviceAccessorOfPortGcAsic0(); } diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_sd_card_device_accessor.cpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_sd_card_device_accessor.cpp index 43aa297c2..9bfff1ad3 100644 --- a/libraries/libvapours/source/sdmmc/impl/sdmmc_sd_card_device_accessor.cpp +++ b/libraries/libvapours/source/sdmmc/impl/sdmmc_sd_card_device_accessor.cpp @@ -885,7 +885,7 @@ namespace ams::sdmmc::impl { AMS_SDMMC_LOCK_SD_CARD_DEVICE_MUTEX(); /* If the device is awake, we don't need to do anything. */ - if (!this->sd_card_device.IsAwake()) { + if (this->sd_card_device.IsAwake()) { return; } diff --git a/libraries/libvapours/source/sdmmc/sdmmc_common.cpp b/libraries/libvapours/source/sdmmc/sdmmc_common.cpp index 0f0c470f5..598e048bf 100644 --- a/libraries/libvapours/source/sdmmc/sdmmc_common.cpp +++ b/libraries/libvapours/source/sdmmc/sdmmc_common.cpp @@ -39,7 +39,7 @@ namespace ams::sdmmc { switch (port) { case Port_Mmc0: host_controller = impl::GetHostControllerOfPortMmc0(); break; case Port_SdCard0: host_controller = impl::GetHostControllerOfPortSdCard0(); break; - //TODO: case Port_GcAsic0: host_controller = impl::GetHostControllerOfPortGcAsic0(); break; + case Port_GcAsic0: host_controller = impl::GetHostControllerOfPortGcAsic0(); break; AMS_UNREACHABLE_DEFAULT_CASE(); } @@ -54,7 +54,7 @@ namespace ams::sdmmc { switch (port) { case Port_Mmc0: device_accessor = impl::GetDeviceAccessorOfPortMmc0(); break; case Port_SdCard0: device_accessor = impl::GetDeviceAccessorOfPortSdCard0(); break; - //TODO: case Port_GcAsic0: device_accessor = impl::GetDeviceAccessorOfPortGcAsic0(); break; + case Port_GcAsic0: device_accessor = impl::GetDeviceAccessorOfPortGcAsic0(); break; AMS_UNREACHABLE_DEFAULT_CASE(); } diff --git a/libraries/libvapours/source/sdmmc/sdmmc_gc_asic.cpp b/libraries/libvapours/source/sdmmc/sdmmc_gc_asic.cpp new file mode 100644 index 000000000..2071fd315 --- /dev/null +++ b/libraries/libvapours/source/sdmmc/sdmmc_gc_asic.cpp @@ -0,0 +1,85 @@ +/* + * 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 . + */ +#if defined(ATMOSPHERE_IS_STRATOSPHERE) +#include +#elif defined(ATMOSPHERE_IS_MESOSPHERE) +#include +#elif defined(ATMOSPHERE_IS_EXOSPHERE) +#include +#else +#include +#endif +#include "impl/sdmmc_gc_asic_device_accessor.hpp" +#include "impl/sdmmc_port_mmc0.hpp" +#include "impl/sdmmc_port_sd_card0.hpp" +#include "impl/sdmmc_port_gc_asic0.hpp" + +namespace ams::sdmmc { + + namespace { + + impl::GcAsicDeviceAccessor *GetGcAsicDeviceAccessor(Port port) { + /* Get the accessor. */ + impl::GcAsicDeviceAccessor *gc_asic_device_accessor = nullptr; + switch (port) { + case Port_GcAsic0: gc_asic_device_accessor = impl::GetGcAsicDeviceAccessorOfPortGcAsic0(); break; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + + /* Ensure it's valid */ + AMS_ABORT_UNLESS(gc_asic_device_accessor != nullptr); + return gc_asic_device_accessor; + } + + } + + void PutGcAsicToSleep(Port port) { + return GetGcAsicDeviceAccessor(port)->PutGcAsicToSleep(); + } + + Result AwakenGcAsic(Port port) { + return GetGcAsicDeviceAccessor(port)->AwakenGcAsic(); + } + + Result WriteGcAsicOperation(Port port, const void *op_buf, size_t op_buf_size) { + return GetGcAsicDeviceAccessor(port)->WriteGcAsicOperation(op_buf, op_buf_size); + } + + Result FinishGcAsicOperation(Port port) { + return GetGcAsicDeviceAccessor(port)->FinishGcAsicOperation(); + } + + Result AbortGcAsicOperation(Port port) { + return GetGcAsicDeviceAccessor(port)->AbortGcAsicOperation(); + } + + Result SleepGcAsic(Port port) { + return GetGcAsicDeviceAccessor(port)->SleepGcAsic(); + } + + Result UpdateGcAsicKey(Port port) { + return GetGcAsicDeviceAccessor(port)->UpdateGcAsicKey(); + } + + void SignalGcRemovedEvent(Port port) { + return GetGcAsicDeviceAccessor(port)->SignalGcRemovedEvent(); + } + + void ClearGcRemovedEvent(Port port) { + return GetGcAsicDeviceAccessor(port)->ClearGcRemovedEvent(); + } + +}