/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2020 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #include "xenia/kernel/xam/xam_content_device.h" #include "xenia/base/logging.h" #include "xenia/base/math.h" #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/xam/xam_private.h" #include "xenia/kernel/xenumerator.h" #include "xenia/xbox.h" namespace xe { namespace kernel { namespace xam { // TODO(gibbed): real information. // // Until we expose real information about a HDD device, we // claim there is 3GB free on a 4GB dummy HDD. // // There is a possibility that certain games are bugged in that // they incorrectly only look at the lower 32-bits of free_bytes, // when it is a 64-bit value. Which means any size above ~4GB // will not be recognized properly. #define ONE_GB (1024ull * 1024ull * 1024ull) static const DummyDeviceInfo dummy_hdd_device_info_ = { DummyDeviceId::HDD, DeviceType::HDD, 20ull * ONE_GB, // 20GB 3ull * ONE_GB, // 3GB, so it looks a little used. u"Dummy HDD", }; static const DummyDeviceInfo dummy_odd_device_info_ = { DummyDeviceId::ODD, DeviceType::ODD, 7ull * ONE_GB, // 7GB (rough maximum) 0ull * ONE_GB, // read-only FS, so no free space u"Dummy ODD", }; static const DummyDeviceInfo* dummy_device_infos_[] = { &dummy_hdd_device_info_, &dummy_odd_device_info_, }; #undef ONE_GB const DummyDeviceInfo* GetDummyDeviceInfo(uint32_t device_id) { const auto& begin = std::begin(dummy_device_infos_); const auto& end = std::end(dummy_device_infos_); auto it = std::find_if(begin, end, [device_id](const auto& item) { return static_cast(item->device_id) == device_id; }); return it == end ? nullptr : *it; } dword_result_t XamContentGetDeviceName(dword_t device_id, lpu16string_t name_buffer, dword_t name_capacity) { auto device_info = GetDummyDeviceInfo(device_id); if (device_info == nullptr) { return X_ERROR_DEVICE_NOT_CONNECTED; } auto name = std::u16string(device_info->name); if (name_capacity < name.size() + 1) { return X_ERROR_INSUFFICIENT_BUFFER; } xe::string_util::copy_and_swap_truncating(name_buffer, name, name_capacity); return X_ERROR_SUCCESS; } DECLARE_XAM_EXPORT1(XamContentGetDeviceName, kContent, kImplemented); dword_result_t XamContentGetDeviceState(dword_t device_id, lpunknown_t overlapped_ptr) { auto device_info = GetDummyDeviceInfo(device_id); if (device_info == nullptr) { if (overlapped_ptr) { kernel_state()->CompleteOverlappedImmediateEx( overlapped_ptr, X_ERROR_FUNCTION_FAILED, X_ERROR_DEVICE_NOT_CONNECTED, 0); return X_ERROR_IO_PENDING; } else { return X_ERROR_DEVICE_NOT_CONNECTED; } } if (overlapped_ptr) { kernel_state()->CompleteOverlappedImmediate(overlapped_ptr, X_ERROR_SUCCESS); return X_ERROR_IO_PENDING; } else { return X_ERROR_SUCCESS; } } DECLARE_XAM_EXPORT1(XamContentGetDeviceState, kContent, kStub); typedef struct { xe::be device_id; xe::be device_type; xe::be total_bytes; xe::be free_bytes; union { xe::be name[28]; char16_t name_chars[28]; }; } X_CONTENT_DEVICE_DATA; static_assert_size(X_CONTENT_DEVICE_DATA, 0x50); dword_result_t XamContentGetDeviceData( dword_t device_id, pointer_t device_data) { auto device_info = GetDummyDeviceInfo(device_id); if (device_info == nullptr) { return X_ERROR_DEVICE_NOT_CONNECTED; } device_data.Zero(); device_data->device_id = static_cast(device_info->device_id); device_data->device_type = static_cast(device_info->device_type); device_data->total_bytes = device_info->total_bytes; device_data->free_bytes = device_info->free_bytes; xe::string_util::copy_and_swap_truncating( device_data->name_chars, device_info->name, xe::countof(device_data->name_chars)); return X_ERROR_SUCCESS; } DECLARE_XAM_EXPORT1(XamContentGetDeviceData, kContent, kImplemented); dword_result_t XamContentCreateDeviceEnumerator(dword_t content_type, dword_t content_flags, dword_t max_count, lpdword_t buffer_size_ptr, lpdword_t handle_out) { assert_not_null(handle_out); if (buffer_size_ptr) { *buffer_size_ptr = sizeof(X_CONTENT_DEVICE_DATA) * max_count; } auto e = make_object>(kernel_state(), max_count); auto result = e->Initialize(0xFE, 0xFE, 0x2000A, 0x20009, 0); if (XFAILED(result)) { return result; } for (const auto& device_info : dummy_device_infos_) { // Copy our dummy device into the enumerator auto device_data = e->AppendItem(); assert_not_null(device_data); if (device_data) { device_data->device_id = static_cast(device_info->device_id); device_data->device_type = static_cast(device_info->device_type); device_data->total_bytes = device_info->total_bytes; device_data->free_bytes = device_info->free_bytes; xe::string_util::copy_and_swap_truncating( device_data->name_chars, device_info->name, xe::countof(device_data->name_chars)); } } *handle_out = e->handle(); return X_ERROR_SUCCESS; } DECLARE_XAM_EXPORT1(XamContentCreateDeviceEnumerator, kNone, kImplemented); void RegisterContentDeviceExports(xe::cpu::ExportResolver* export_resolver, KernelState* kernel_state) {} } // namespace xam } // namespace kernel } // namespace xe