diff --git a/libraries/libvapours/include/vapours/prfile2/pdm/prfile2_pdm_disk.hpp b/libraries/libvapours/include/vapours/prfile2/pdm/prfile2_pdm_disk.hpp index c4c212f3b..af2d2acd6 100644 --- a/libraries/libvapours/include/vapours/prfile2/pdm/prfile2_pdm_disk.hpp +++ b/libraries/libvapours/include/vapours/prfile2/pdm/prfile2_pdm_disk.hpp @@ -28,7 +28,7 @@ namespace ams::prfile2::pdm { Disk *lock_handle; DiskInfo disk_info; InitDisk *init_disk_table; - Partition *current_partition; + HandleType current_partition_handle; DiskCallback erase_callback; bool is_inserted; volatile NonBlockingProtocolType nbc; diff --git a/libraries/libvapours/include/vapours/prfile2/pdm/prfile2_pdm_partition.hpp b/libraries/libvapours/include/vapours/prfile2/pdm/prfile2_pdm_partition.hpp index 49defff95..7302fb06c 100644 --- a/libraries/libvapours/include/vapours/prfile2/pdm/prfile2_pdm_partition.hpp +++ b/libraries/libvapours/include/vapours/prfile2/pdm/prfile2_pdm_partition.hpp @@ -21,7 +21,7 @@ namespace ams::prfile2::pdm { struct Partition { u32 status; - Disk *disk; + HandleType disk_handle; u32 signature; u16 partition_id; u16 open_count; @@ -35,17 +35,39 @@ namespace ams::prfile2::pdm { volatile NonBlockingProtocolType nbc_detect; PartitionEventCallback event_callback; void *event_callback_param; + + template + constexpr ALWAYS_INLINE bool GetStatusBit() const { + constexpr u32 Mask = (1u << Ix); + return (this->status & Mask) != 0; + } + + template + constexpr ALWAYS_INLINE void SetStatusBit(bool en) { + constexpr u32 Mask = (1u << Ix); + if (en) { + this->status |= Mask; + } else { + this->status &= ~Mask; + } + } + + constexpr bool IsOpen() const { return this->GetStatusBit<0>(); } + constexpr void SetOpen(bool en) { this->SetStatusBit<0>(en); } + + constexpr bool IsLocked() const { return this->GetStatusBit<1>(); } + constexpr void SetLocked(bool en) { this->SetStatusBit<1>(en); } }; namespace part { - pdm::Error OpenPartition(Disk *disk, u16 partition_id, Partition **out); - pdm::Error ClosePartition(Partition *part); + pdm::Error OpenPartition(HandleType disk_handle, u16 partition_id, HandleType *out); + pdm::Error ClosePartition(HandleType part_handle); - void SetDriverErrorCode(Partition *part, pdm::Error err); + void SetDriverErrorCode(HandleType part_handle, pdm::Error err); - void CheckPartitionOpen(Disk *disk, bool *out); - void NotifyMediaEvent(Disk *disk, u32 event); + void CheckPartitionOpen(HandleType disk_handle, bool *out); + void NotifyMediaEvent(HandleType disk_handle, u32 event); } diff --git a/libraries/libvapours/include/vapours/util/util_bitpack.hpp b/libraries/libvapours/include/vapours/util/util_bitpack.hpp index 4b5c1e863..96c3ab51b 100644 --- a/libraries/libvapours/include/vapours/util/util_bitpack.hpp +++ b/libraries/libvapours/include/vapours/util/util_bitpack.hpp @@ -75,6 +75,14 @@ namespace ams::util { this->value &= ~FieldMask; this->value |= (static_cast(field_value) << FieldType::Index) & FieldMask; } + + constexpr ALWAYS_INLINE bool operator==(const BitPack &rhs) { + return this->value == rhs.value; + } + + constexpr ALWAYS_INLINE bool operator!=(const BitPack &rhs) { + return !(*this == rhs); + } }; } diff --git a/libraries/libvapours/source/prfile2/pdm/prfile2_pdm_disk.cpp b/libraries/libvapours/source/prfile2/pdm/prfile2_pdm_disk.cpp index ffbfa3578..1f954770c 100644 --- a/libraries/libvapours/source/prfile2/pdm/prfile2_pdm_disk.cpp +++ b/libraries/libvapours/source/prfile2/pdm/prfile2_pdm_disk.cpp @@ -115,12 +115,18 @@ namespace ams::prfile2::pdm::disk { return pdm::Error_StateLocked; } + /* Get the disk holder. */ + DiskHolder *holder = GetDiskHolder(handle); + if (holder == nullptr) { + return pdm::Error_InvalidParameter; + } + /* Close the disk. */ if (disk->open_count == 1) { /* Finalize the disk. */ if (auto err = disk->disk_table.function_table->finalize(handle); err != pdm::Error_Ok) { - if (auto *part = disk->current_partition; part != nullptr) { - /* TODO: part::SetDriverErrorCode(part, err); */ + if (auto part = disk->current_partition_handle; part != InvalidHandle) { + part::SetDriverErrorCode(part, err); } return pdm::Error_DriverError; } @@ -130,7 +136,7 @@ namespace ams::prfile2::pdm::disk { --impl::g_disk_set.num_allocated_disks; /* Clear the disk holder. */ - impl::g_disk_set.disk_holders[GetHandleId(handle)].disk = nullptr; + holder->disk = nullptr; } /* Decrement the disk's open count. */ diff --git a/libraries/libvapours/source/prfile2/pdm/prfile2_pdm_disk_set.hpp b/libraries/libvapours/source/prfile2/pdm/prfile2_pdm_disk_set.hpp index 2b4c08922..871517cc2 100644 --- a/libraries/libvapours/source/prfile2/pdm/prfile2_pdm_disk_set.hpp +++ b/libraries/libvapours/source/prfile2/pdm/prfile2_pdm_disk_set.hpp @@ -41,6 +41,27 @@ namespace ams::prfile2::pdm { return nullptr; } + ALWAYS_INLINE Disk *GetDiskUnsafe(HandleType handle) { + return std::addressof(impl::g_disk_set.disks[GetHandleId(handle)]); + } + + ALWAYS_INLINE DiskHolder *GetDiskHolder(HandleType handle) { + if (AMS_LIKELY(IsDiskHandle(handle))) { + if (const auto id = GetHandleId(handle); AMS_LIKELY(id < MaxDisks)) { + const auto signature = GetHandleSignature(handle); + Disk *disk = std::addressof(impl::g_disk_set.disks[id]); + + for (auto &holder : impl::g_disk_set.disk_holders) { + if (holder.disk == disk && holder.signature == signature) { + return std::addressof(holder); + } + } + } + } + + return nullptr; + } + ALWAYS_INLINE Partition *GetPartition(HandleType handle) { if (AMS_LIKELY(IsPartitionHandle(handle))) { if (const auto id = GetHandleId(handle); AMS_LIKELY(id < MaxPartitions)) { @@ -58,4 +79,25 @@ namespace ams::prfile2::pdm { return nullptr; } + ALWAYS_INLINE Partition *GetPartitionUnsafe(HandleType handle) { + return std::addressof(impl::g_disk_set.partitions[GetHandleId(handle)]); + } + + ALWAYS_INLINE PartitionHolder *GetPartitionHolder(HandleType handle) { + if (AMS_LIKELY(IsPartitionHandle(handle))) { + if (const auto id = GetHandleId(handle); AMS_LIKELY(id < MaxPartitions)) { + const auto signature = GetHandleSignature(handle); + Partition *part = std::addressof(impl::g_disk_set.partitions[id]); + + for (auto &holder : impl::g_disk_set.partition_holders) { + if (holder.partition == part && holder.signature == signature) { + return std::addressof(holder); + } + } + } + } + + return nullptr; + } + } diff --git a/libraries/libvapours/source/prfile2/pdm/prfile2_pdm_partition.cpp b/libraries/libvapours/source/prfile2/pdm/prfile2_pdm_partition.cpp new file mode 100644 index 000000000..10bf0b100 --- /dev/null +++ b/libraries/libvapours/source/prfile2/pdm/prfile2_pdm_partition.cpp @@ -0,0 +1,150 @@ +/* + * 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 "prfile2_pdm_disk_set.hpp" + +namespace ams::prfile2::pdm::part { + + pdm::Error OpenPartition(HandleType disk_handle, u16 partition_id, HandleType *out) { + /* Check the arguments. */ + if (out == nullptr || disk_handle == InvalidHandle) { + return pdm::Error_InvalidParameter; + } + + /* Find a free partition holder. */ + PartitionHolder *holder = nullptr; + for (auto &h : impl::g_disk_set.partition_holders) { + if (h.partition == nullptr) { + holder = std::addressof(h); + break; + } + } + if (holder == nullptr) { + return pdm::Error_NotExistFreePartitionStruct; + } + + /* Locate a free (or matching) partition. */ + Partition *part = nullptr; + bool found_matching = false; + for (auto &p : impl::g_disk_set.partitions) { + if (p.IsOpen()) { + if (p.disk_handle == disk_handle && p.partition_id == partition_id) { + part = std::addressof(p); + found_matching = true; + break; + } + } else { + if (part == nullptr) { + part = std::addressof(p); + } + } + } + if (part == nullptr) { + return pdm::Error_NotExistFreePartitionStruct; + } + const auto part_id = part - impl::g_disk_set.partitions; + + /* If we're not working with a match, open the new partition. */ + if (!found_matching) { + /* Set the partition as open. */ + part->SetOpen(true); + + /* Increment the number of open partitions. */ + ++impl::g_disk_set.num_partitions; + + /* Set the partition's disk/id. */ + part->disk_handle = disk_handle; + part->partition_id = partition_id; + } + + /* Increment the partition's signature. */ + part->signature = static_cast(part->signature + 1); + + /* Increment the partition's open count. */ + ++part->open_count; + + /* Set the holder. */ + holder->signature = part->signature; + holder->partition = part; + + /* Set the output handle. */ + *out = ConstructPartitionHandle(part_id, part->signature); + + return pdm::Error_Ok; + } + + pdm::Error ClosePartition(HandleType part_handle) { + /* Get the partition. */ + Partition *part = GetPartition(part_handle); + if (part == nullptr) { + return pdm::Error_InvalidParameter; + } + + /* Check that the partition is open and unlocked. */ + if (!part->IsOpen()) { + return pdm::Error_StateClosed; + } + if (part->IsLocked()) { + return pdm::Error_StateLocked; + } + + /* Get the partition holder. */ + PartitionHolder *holder = GetPartitionHolder(part_handle); + if (holder == nullptr) { + return pdm::Error_InvalidParameter; + } + + /* Close the partition. */ + if (part->open_count == 1) { + /* Set the partition as closed. */ + part->SetOpen(false); + --impl::g_disk_set.num_partitions; + + /* Clear the partition holder. */ + holder->partition = nullptr; + } + + /* Decrement the partition's open count. */ + --part->open_count; + + return pdm::Error_Ok; + } + + void SetDriverErrorCode(HandleType part_handle, pdm::Error err) { + GetPartitionUnsafe(part_handle)->last_driver_error = err; + } + + void CheckPartitionOpen(HandleType disk_handle, bool *out) { + /* TODO */ + AMS_UNUSED(disk_handle, out); + AMS_ABORT("CheckPartitionOpen"); + } + + void NotifyMediaEvent(HandleType disk_handle, u32 event) { + /* TODO */ + AMS_UNUSED(disk_handle, event); + AMS_ABORT("NotifyMediaEvent"); + } + +}