diff --git a/libraries/libvapours/include/vapours.hpp b/libraries/libvapours/include/vapours.hpp index 84820cb2b..6dda2b23d 100644 --- a/libraries/libvapours/include/vapours.hpp +++ b/libraries/libvapours/include/vapours.hpp @@ -29,3 +29,6 @@ #include #include + +#include +#include \ No newline at end of file diff --git a/libraries/libvapours/include/vapours/dd.hpp b/libraries/libvapours/include/vapours/dd.hpp new file mode 100644 index 000000000..38d3f1b71 --- /dev/null +++ b/libraries/libvapours/include/vapours/dd.hpp @@ -0,0 +1,22 @@ +/* + * 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 +#include + +#include diff --git a/libraries/libvapours/include/vapours/dd/dd_device_virtual_address.hpp b/libraries/libvapours/include/vapours/dd/dd_device_virtual_address.hpp new file mode 100644 index 000000000..0d4b971f0 --- /dev/null +++ b/libraries/libvapours/include/vapours/dd/dd_device_virtual_address.hpp @@ -0,0 +1,26 @@ +/* + * 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 +#include + +namespace ams::dd { + + using DeviceVirtualAddress = u64; + +} diff --git a/libraries/libvapours/include/vapours/sdmmc.hpp b/libraries/libvapours/include/vapours/sdmmc.hpp new file mode 100644 index 000000000..c0cf3f79f --- /dev/null +++ b/libraries/libvapours/include/vapours/sdmmc.hpp @@ -0,0 +1,26 @@ +/* + * 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 +#include +#include +#include + +#include +#include +#include diff --git a/libraries/libvapours/include/vapours/sdmmc/sdmmc_build_config.hpp b/libraries/libvapours/include/vapours/sdmmc/sdmmc_build_config.hpp new file mode 100644 index 000000000..2821e9e17 --- /dev/null +++ b/libraries/libvapours/include/vapours/sdmmc/sdmmc_build_config.hpp @@ -0,0 +1,45 @@ +/* + * 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 +#include +#include +#include +#include + +#if defined(ATMOSPHERE_IS_EXOSPHERE) + + //#define AMS_SDMMC_USE_DEVICE_VIRTUAL_ADDRESS + //#define AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL + //#define AMS_SDMMC_USE_OS_EVENTS + +#elif defined(ATMOSPHERE_IS_MESOSPHERE) + + //#define AMS_SDMMC_USE_DEVICE_VIRTUAL_ADDRESS + //#define AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL + //#define AMS_SDMMC_USE_OS_EVENTS + +#elif defined(ATMOSPHERE_IS_STRATOSPHERE) + + #define AMS_SDMMC_USE_DEVICE_VIRTUAL_ADDRESS + #define AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL + #define AMS_SDMMC_USE_OS_EVENTS + +#else + #error "Unknown execution context for ams::sdmmc!" +#endif \ No newline at end of file diff --git a/libraries/libvapours/include/vapours/sdmmc/sdmmc_common.hpp b/libraries/libvapours/include/vapours/sdmmc/sdmmc_common.hpp new file mode 100644 index 000000000..7bbbc0375 --- /dev/null +++ b/libraries/libvapours/include/vapours/sdmmc/sdmmc_common.hpp @@ -0,0 +1,115 @@ +/* + * 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 { + + enum BusPower { + BusPower_Off = 0, + BusPower_1_8V = 1, + BusPower_3_3V = 2, + }; + + enum BusWidth { + BusWidth_1Bit = 0, + BusWidth_4Bit = 1, + BusWidth_8Bit = 2, + }; + + enum SpeedMode { + SpeedMode_MmcIdentification = 0, + SpeedMode_MmcLegacySpeed = 1, + SpeedMode_MmcHighSpeed = 2, + SpeedMode_MmcHs200 = 3, + SpeedMode_MmcHs400 = 4, + SpeedMode_SdCardIdentification = 5, + SpeedMode_SdCardDefaultSpeed = 6, + SpeedMode_SdCardHighSpeed = 7, + SpeedMode_SdCardSdr12 = 8, + SpeedMode_SdCardSdr25 = 9, + SpeedMode_SdCardSdr50 = 10, + SpeedMode_SdCardSdr104 = 11, + SpeedMode_SdCardDdr50 = 12, + SpeedMode_GcAsicFpgaSpeed = 13, + SpeedMode_GcAsicSpeed = 14, + }; + + enum Port { + Port_Mmc0 = 0, + Port_SdCard0 = 1, + Port_GcAsic0 = 2, + }; + + struct ErrorInfo { + u32 num_activation_failures; + u32 num_activation_error_corrections; + u32 num_read_write_failures; + u32 num_read_write_error_corrections; + }; + + struct DataTransfer { + void *buffer; + size_t buffer_size; + size_t block_size; + u32 num_blocks; + bool is_read; + }; + + using DeviceDetectionEventCallback = void (*)(void *); + + constexpr inline size_t DeviceCidSize = 0x10; + constexpr inline size_t DeviceCsdSize = 0x10; + + constexpr inline size_t BufferDeviceVirtualAddressAlignment = alignof(ams::dd::DeviceVirtualAddress); + static_assert(BufferDeviceVirtualAddressAlignment >= 8); + + void Initialize(Port port); + void Finalize(Port port); + +#if defined(AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL) + void SwitchToPcvClockResetControl(); +#endif + +#if defined(AMS_SDMMC_USE_DEVICE_VIRTUAL_ADDRESS) + void RegisterDeviceVirtualAddress(Port port, uintptr_t buffer, size_t buffer_size, ams::dd::DeviceVirtualAddress buffer_device_virtual_address); + void UnregisterDeviceVirtualAddress(Port port, uintptr_t buffer, size_t buffer_size, ams::dd::DeviceVirtualAddress buffer_device_virtual_address); +#endif + + void ChangeCheckTransferInterval(Port port, u32 ms); + void SetDefaultCheckTransferInterval(Port port); + + Result Activate(Port port); + void Deactivate(Port port); + + Result Read(void *dst, size_t dst_size, Port port, u32 sector_index, u32 num_sectors); + Result Write(Port port, u32 sector_index, u32 num_sectors, const void *src, size_t src_size); + + Result CheckConnection(SpeedMode *out_speed_mode, BusWidth *out_bus_width, Port port); + + Result GetDeviceSpeedMode(SpeedMode *out, Port port); + Result GetDeviceMemoryCapacity(u32 *out_num_sectors, Port port); + Result GetDeviceStatus(u32 *out_device_status, Port port); + Result GetDeviceCid(void *out, size_t out_size, Port port); + Result GetDeviceCsd(void *out, size_t out_size, Port port); + + void GetAndClearErrorInfo(ErrorInfo *out_error_info, size_t *out_log_size, char *out_log_buffer, size_t log_buffer_size, Port port); + + + +} \ No newline at end of file diff --git a/libraries/libvapours/include/vapours/sdmmc/sdmmc_mmc.hpp b/libraries/libvapours/include/vapours/sdmmc/sdmmc_mmc.hpp new file mode 100644 index 000000000..d6bab0111 --- /dev/null +++ b/libraries/libvapours/include/vapours/sdmmc/sdmmc_mmc.hpp @@ -0,0 +1,42 @@ +/* + * 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 { + + enum MmcPartition { + MmcPartition_UserData = 0, + MmcPartition_BootPartition1 = 1, + MmcPartition_BootPartition2 = 2, + MmcPartition_Unknown = 3, + }; + + constexpr inline size_t MmcExtendedCsdSize = 0x200; + constexpr inline size_t MmcWorkBufferSize = MmcExtendedCsdSize; + + void SetMmcWorkBuffer(Port port, void *buffer, size_t buffer_size); + void PutMmcToSleep(Port port); + void AwakenMmc(Port port); + Result SelectMmcPartition(Port port, MmcPartition mmc_partition); + Result EraseMmc(Port port); + Result GetMmcBootPartitionCapacity(u32 *out_num_sectors, Port port); + Result GetMmcExtendedCsd(void *out_buffer, size_t buffer_size, Port port); + + +} \ No newline at end of file diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_clock_reset_controller.hpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_clock_reset_controller.hpp new file mode 100644 index 000000000..290d5c637 --- /dev/null +++ b/libraries/libvapours/source/sdmmc/impl/sdmmc_clock_reset_controller.hpp @@ -0,0 +1,45 @@ +/* + * 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::impl::ClockResetController { + + enum Module { + #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) + Module_Sdmmc1 = 0, + Module_Sdmmc2 = 1, + Module_Sdmmc3 = 2, + Module_Sdmmc4 = 3, + #endif + + Module_Count, + }; + + void Initialize(Module module); + void Finalize(Module module); + bool IsAvailable(Module module); + + #if defined(AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL) + void SwitchToPcvControl(); + #endif + + void SetClockFrequencyKHz(u32 *out_actual_frequency, Module module, u32 target_frequency); + void AssertReset(Module module); + void ReleaseReset(Module module, u32 target_frequency_khz); + +} diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_i_device_accessor.hpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_i_device_accessor.hpp new file mode 100644 index 000000000..8468c981a --- /dev/null +++ b/libraries/libvapours/source/sdmmc/impl/sdmmc_i_device_accessor.hpp @@ -0,0 +1,49 @@ +/* + * 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_i_host_controller.hpp" + +namespace ams::sdmmc::impl { + + class IDeviceAccessor { + public: + virtual void Initialize() = 0; + virtual void Finalize() = 0; + + #if defined(AMS_SDMMC_USE_DEVICE_VIRTUAL_ADDRESS) + virtual void RegisterDeviceVirtualAddress(uintptr_t buffer, size_t buffer_size, ams::dd::DeviceVirtualAddress buffer_device_virtual_address) = 0; + virtual void UnregisterDeviceVirtualAddress(uintptr_t buffer, size_t buffer_size, ams::dd::DeviceVirtualAddress buffer_device_virtual_address) = 0; + #endif + + virtual Result Activate() = 0; + virtual void Deactivate() = 0; + + virtual Result ReadWrite(u32 sector_index, u32 num_sectors, void *buffer, size_t buffer_size, bool is_read) = 0; + virtual Result CheckConnection(SpeedMode *out_speed_mode, BusWidth *out_bus_width) = 0; + + virtual Result GetSpeedMode(SpeedMode *out) const = 0; + virtual Result GetMemoryCapacity(u32 *out_sectors) const = 0; + virtual Result GetDeviceStatus(u32 *out) const = 0; + virtual Result GetCid(void *out, size_t size) const = 0; + virtual Result GetCsd(void *out, size_t size) const = 0; + + virtual void GetAndClearErrorInfo(ErrorInfo *out_error_info, size_t *out_log_size, char *out_log_buffer, size_t log_buffer_size) = 0; + /* TODO */ + }; + +} diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_i_host_controller.hpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_i_host_controller.hpp new file mode 100644 index 000000000..2d6857f87 --- /dev/null +++ b/libraries/libvapours/source/sdmmc/impl/sdmmc_i_host_controller.hpp @@ -0,0 +1,89 @@ +/* + * 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 + +#if defined(AMS_SDMMC_USE_OS_EVENTS) +#include +#endif + +namespace ams::sdmmc::impl { + + enum ResponseType { + ResponseType_R0 = 0, + ResponseType_R1 = 1, + ResponseType_R2 = 2, + ResponseType_R3 = 3, + ResponseType_R6 = 4, + ResponseType_R7 = 5, + }; + + enum TransferDirection { + TransferDirection_ReadFromDevice = 0, + TransferDirection_WriteToDevice = 1, + }; + + struct Command { + u32 command_index; + u32 command_argument; + ResponseType response_type; + bool is_busy; + + constexpr Command(u32 ci, u32 ca, ResponseType r, bool b) : command_index(ci), command_argument(ca), response_type(r), is_busy(b) { /* ... */ } + }; + + struct TransferData { + void *buffer; + size_t block_size; + u32 num_blocks; + TransferDirection transfer_direction; + bool is_multi_block_transfer; + bool is_stop_transmission_command_enabled; + + constexpr TransferData(void *b, size_t bs, u32 nb, TransferDirection xd, bool mb, bool st) + : buffer(b), block_size(bs), num_blocks(nb), transfer_direction(xd), is_multi_block_transfer(mb), is_stop_transmission_command_enabled(st) + { + if (this->num_blocks > 1) { + AMS_ABORT_UNLESS(this->is_multi_block_transfer); + } + } + + constexpr TransferData(void *b, size_t bs, u32 nb, TransferDirection xd) + : buffer(b), block_size(bs), num_blocks(nb), transfer_direction(xd), is_multi_block_transfer(false), is_stop_transmission_command_enabled(false) + { + AMS_ABORT_UNLESS(this->num_blocks == 1); + } + }; + + class IHostController { + public: + #if defined(AMS_SDMMC_USE_OS_EVENTS) + virtual void PreSetRemovedEvent(ams::os::EventType *event) = 0; + #endif + + virtual void Initialize() = 0; + virtual void Finalize() = 0; + + /* TODO */ + + virtual void ChangeCheckTransferInterval(u32 ms) = 0; + virtual void SetDefaultCheckTransferInterval() = 0; + + /* TODO */ + }; + +} diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_port_mmc0.hpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_port_mmc0.hpp new file mode 100644 index 000000000..1ceb1f101 --- /dev/null +++ b/libraries/libvapours/source/sdmmc/impl/sdmmc_port_mmc0.hpp @@ -0,0 +1,27 @@ +/* + * 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_i_host_controller.hpp" +#include "sdmmc_i_device_accessor.hpp" + +namespace ams::sdmmc::impl { + + IHostController *GetHostControllerOfPortMmc0(); + IDeviceAccessor *GetDeviceAccessorOfPortMmc0(); + +} diff --git a/libraries/libvapours/source/sdmmc/sdmmc_common.cpp b/libraries/libvapours/source/sdmmc/sdmmc_common.cpp new file mode 100644 index 000000000..bdc61b9fe --- /dev/null +++ b/libraries/libvapours/source/sdmmc/sdmmc_common.cpp @@ -0,0 +1,135 @@ +/* + * 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 "impl/sdmmc_i_host_controller.hpp" +#include "impl/sdmmc_i_device_accessor.hpp" +#include "impl/sdmmc_clock_reset_controller.hpp" +#include "impl/sdmmc_port_mmc0.hpp" + +namespace ams::sdmmc { + + namespace { + + impl::IHostController *GetHostController(Port port) { + /* Get the controller. */ + impl::IHostController *host_controller = nullptr; + switch (port) { + case Port_Mmc0: host_controller = impl::GetHostControllerOfPortMmc0(); break; + case Port_SdCard0: /* TODO */ break; + case Port_GcAsic0: /* TODO */ break; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + + /* Ensure it's valid */ + AMS_ABORT_UNLESS(host_controller != nullptr); + return host_controller; + } + + impl::IDeviceAccessor *GetDeviceAccessor(Port port) { + /* Get the accessor. */ + impl::IDeviceAccessor *device_accessor = nullptr; + switch (port) { + case Port_Mmc0: device_accessor = impl::GetDeviceAccessorOfPortMmc0(); break; + case Port_SdCard0: /* TODO */ break; + case Port_GcAsic0: /* TODO */ break; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + + /* Ensure it's valid */ + AMS_ABORT_UNLESS(device_accessor != nullptr); + return device_accessor; + } + + } + + + + void Initialize(Port port) { + return GetDeviceAccessor(port)->Initialize(); + } + + void Finalize(Port port) { + return GetDeviceAccessor(port)->Finalize(); + } + +#if defined(AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL) + void SwitchToPcvClockResetControl() { + return impl::ClockResetController::SwitchToPcvControl(); + } +#endif + +#if defined(AMS_SDMMC_USE_DEVICE_VIRTUAL_ADDRESS) + void RegisterDeviceVirtualAddress(Port port, uintptr_t buffer, size_t buffer_size, ams::dd::DeviceVirtualAddress buffer_device_virtual_address) { + return GetDeviceAccessor(port)->RegisterDeviceVirtualAddress(buffer, buffer_size, buffer_device_virtual_address); + } + + void UnregisterDeviceVirtualAddress(Port port, uintptr_t buffer, size_t buffer_size, ams::dd::DeviceVirtualAddress buffer_device_virtual_address) { + return GetDeviceAccessor(port)->UnregisterDeviceVirtualAddress(buffer, buffer_size, buffer_device_virtual_address); + } +#endif + + void ChangeCheckTransferInterval(Port port, u32 ms) { + return GetHostController(port)->ChangeCheckTransferInterval(ms); + } + void SetDefaultCheckTransferInterval(Port port) { + return GetHostController(port)->SetDefaultCheckTransferInterval(); + } + + Result Activate(Port port) { + return GetDeviceAccessor(port)->Activate(); + } + + void Deactivate(Port port) { + return GetDeviceAccessor(port)->Deactivate(); + } + + Result Read(void *dst, size_t dst_size, Port port, u32 sector_index, u32 num_sectors) { + return GetDeviceAccessor(port)->ReadWrite(sector_index, num_sectors, dst, dst_size, true); + } + + Result Write(Port port, u32 sector_index, u32 num_sectors, const void *src, size_t src_size) { + return GetDeviceAccessor(port)->ReadWrite(sector_index, num_sectors, const_cast(src), src_size, false); + } + + Result CheckConnection(SpeedMode *out_speed_mode, BusWidth *out_bus_width, Port port) { + return GetDeviceAccessor(port)->CheckConnection(out_speed_mode, out_bus_width); + } + + Result GetDeviceSpeedMode(SpeedMode *out, Port port) { + return GetDeviceAccessor(port)->GetSpeedMode(out); + } + + Result GetDeviceMemoryCapacity(u32 *out_num_sectors, Port port) { + return GetDeviceAccessor(port)->GetMemoryCapacity(out_num_sectors); + } + + Result GetDeviceStatus(u32 *out_device_status, Port port) { + return GetDeviceAccessor(port)->GetDeviceStatus(out_device_status); + } + + Result GetDeviceCid(void *out, size_t out_size, Port port) { + return GetDeviceAccessor(port)->GetCid(out, out_size); + } + + Result GetDeviceCsd(void *out, size_t out_size, Port port) { + return GetDeviceAccessor(port)->GetCsd(out, out_size); + } + + void GetAndClearErrorInfo(ErrorInfo *out_error_info, size_t *out_log_size, char *out_log_buffer, size_t log_buffer_size, Port port) { + return GetDeviceAccessor(port)->GetAndClearErrorInfo(out_error_info, out_log_size, out_log_buffer, log_buffer_size); + } + +}