mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-02-09 19:25:10 +01:00
sdmmc: finish outward-facing api (untested)
This commit is contained in:
parent
5120b70231
commit
a6c6a95053
@ -25,3 +25,4 @@
|
|||||||
#include <vapours/sdmmc/sdmmc_common.hpp>
|
#include <vapours/sdmmc/sdmmc_common.hpp>
|
||||||
#include <vapours/sdmmc/sdmmc_mmc.hpp>
|
#include <vapours/sdmmc/sdmmc_mmc.hpp>
|
||||||
#include <vapours/sdmmc/sdmmc_sd_card.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();
|
AMS_SDMMC_LOCK_MMC_DEVICE_MUTEX();
|
||||||
|
|
||||||
/* If the device is awake, we don't need to do anything. */
|
/* If the device is awake, we don't need to do anything. */
|
||||||
if (!this->mmc_device.IsAwake()) {
|
if (this->mmc_device.IsAwake()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
#else
|
#else
|
||||||
#include <vapours.hpp>
|
#include <vapours.hpp>
|
||||||
#endif
|
#endif
|
||||||
#include "sdmmc_port_mmc0.hpp"
|
#include "sdmmc_port_gc_asic0.hpp"
|
||||||
#include "sdmmc_select_sdmmc_controller.hpp"
|
#include "sdmmc_select_sdmmc_controller.hpp"
|
||||||
|
|
||||||
|
|
||||||
@ -31,6 +31,7 @@ namespace ams::sdmmc::impl {
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
SdmmcControllerForPortGcAsic0 g_gc_asic0_host_controller;
|
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);
|
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 <vapours.hpp>
|
||||||
#include "sdmmc_i_host_controller.hpp"
|
#include "sdmmc_i_host_controller.hpp"
|
||||||
#include "sdmmc_i_device_accessor.hpp"
|
#include "sdmmc_i_device_accessor.hpp"
|
||||||
|
#include "sdmmc_gc_asic_device_accessor.hpp"
|
||||||
|
|
||||||
namespace ams::sdmmc::impl {
|
namespace ams::sdmmc::impl {
|
||||||
|
|
||||||
IHostController *GetHostControllerOfPortGcAsic0();
|
IHostController *GetHostControllerOfPortGcAsic0();
|
||||||
IDeviceAccessor *GetDeviceAccessorOfPortGcAsic0();
|
IDeviceAccessor *GetDeviceAccessorOfPortGcAsic0();
|
||||||
|
GcAsicDeviceAccessor *GetGcAsicDeviceAccessorOfPortGcAsic0();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -885,7 +885,7 @@ namespace ams::sdmmc::impl {
|
|||||||
AMS_SDMMC_LOCK_SD_CARD_DEVICE_MUTEX();
|
AMS_SDMMC_LOCK_SD_CARD_DEVICE_MUTEX();
|
||||||
|
|
||||||
/* If the device is awake, we don't need to do anything. */
|
/* 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ namespace ams::sdmmc {
|
|||||||
switch (port) {
|
switch (port) {
|
||||||
case Port_Mmc0: host_controller = impl::GetHostControllerOfPortMmc0(); break;
|
case Port_Mmc0: host_controller = impl::GetHostControllerOfPortMmc0(); break;
|
||||||
case Port_SdCard0: host_controller = impl::GetHostControllerOfPortSdCard0(); 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();
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ namespace ams::sdmmc {
|
|||||||
switch (port) {
|
switch (port) {
|
||||||
case Port_Mmc0: device_accessor = impl::GetDeviceAccessorOfPortMmc0(); break;
|
case Port_Mmc0: device_accessor = impl::GetDeviceAccessorOfPortMmc0(); break;
|
||||||
case Port_SdCard0: device_accessor = impl::GetDeviceAccessorOfPortSdCard0(); 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();
|
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…
x
Reference in New Issue
Block a user