mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
sdmmc: finish outward-facing api (untested)
This commit is contained in:
parent
5120b70231
commit
a6c6a95053
10 changed files with 584 additions and 5 deletions
|
@ -25,3 +25,4 @@
|
|||
#include <vapours/sdmmc/sdmmc_common.hpp>
|
||||
#include <vapours/sdmmc/sdmmc_mmc.hpp>
|
||||
#include <vapours/sdmmc/sdmmc_sd_card.hpp>
|
||||
#include <vapours/sdmmc/sdmmc_gc_asic.hpp>
|
||||
|
|
34
libraries/libvapours/include/vapours/sdmmc/sdmmc_gc_asic.hpp
Normal file
34
libraries/libvapours/include/vapours/sdmmc/sdmmc_gc_asic.hpp
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours/sdmmc/sdmmc_build_config.hpp>
|
||||
|
||||
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);
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
|
||||
#include <stratosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
|
||||
#include <mesosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
|
||||
#include <exosphere.hpp>
|
||||
#else
|
||||
#include <vapours.hpp>
|
||||
#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<void *>(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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#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
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#else
|
||||
#include <vapours.hpp>
|
||||
#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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,10 +17,12 @@
|
|||
#include <vapours.hpp>
|
||||
#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();
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
85
libraries/libvapours/source/sdmmc/sdmmc_gc_asic.cpp
Normal file
85
libraries/libvapours/source/sdmmc/sdmmc_gc_asic.cpp
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
|
||||
#include <stratosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
|
||||
#include <mesosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
|
||||
#include <exosphere.hpp>
|
||||
#else
|
||||
#include <vapours.hpp>
|
||||
#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();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue