diff options
Diffstat (limited to '')
56 files changed, 1600 insertions, 1446 deletions
diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index bd420f24a..9bcd25821 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp @@ -66,7 +66,7 @@ TextureInfoDockWidget::TextureInfoDockWidget(const Pica::DebugUtils::TextureInfo QComboBox* format_choice = new QComboBox; format_choice->addItem(tr("RGBA8")); format_choice->addItem(tr("RGB8")); - format_choice->addItem(tr("RGBA5551")); + format_choice->addItem(tr("RGB5A1")); format_choice->addItem(tr("RGB565")); format_choice->addItem(tr("RGBA4")); format_choice->addItem(tr("IA8")); diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp index 574f19cc1..5bd6c0235 100644 --- a/src/citra_qt/debugger/graphics_framebuffer.cpp +++ b/src/citra_qt/debugger/graphics_framebuffer.cpp @@ -46,7 +46,7 @@ GraphicsFramebufferWidget::GraphicsFramebufferWidget(std::shared_ptr<Pica::Debug framebuffer_format_control = new QComboBox; framebuffer_format_control->addItem(tr("RGBA8")); framebuffer_format_control->addItem(tr("RGB8")); - framebuffer_format_control->addItem(tr("RGBA5551")); + framebuffer_format_control->addItem(tr("RGB5A1")); framebuffer_format_control->addItem(tr("RGB565")); framebuffer_format_control->addItem(tr("RGBA4")); @@ -199,66 +199,40 @@ void GraphicsFramebufferWidget::OnUpdate() // TODO: Unify this decoding code with the texture decoder u32 bytes_per_pixel = GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(framebuffer_format)); - switch (framebuffer_format) { - case Format::RGBA8: - { - QImage decoded_image(framebuffer_width, framebuffer_height, QImage::Format_ARGB32); - u8* color_buffer = Memory::GetPointer(Pica::PAddrToVAddr(framebuffer_address)); - for (unsigned int y = 0; y < framebuffer_height; ++y) { - for (unsigned int x = 0; x < framebuffer_width; ++x) { - const u32 coarse_y = y & ~7; - u32 offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * framebuffer_width * bytes_per_pixel; - u8* value = color_buffer + offset; - - decoded_image.setPixel(x, y, qRgba(value[3], value[2], value[1], 255/*value >> 24*/)); + QImage decoded_image(framebuffer_width, framebuffer_height, QImage::Format_ARGB32); + u8* color_buffer = Memory::GetPointer(Pica::PAddrToVAddr(framebuffer_address)); + for (unsigned int y = 0; y < framebuffer_height; ++y) { + for (unsigned int x = 0; x < framebuffer_width; ++x) { + const u32 coarse_y = y & ~7; + u32 offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * framebuffer_width * bytes_per_pixel; + const u8* pixel = color_buffer + offset; + Math::Vec4<u8> color = { 0, 0, 0, 0 }; + + switch (framebuffer_format) { + case Format::RGBA8: + color = Color::DecodeRGBA8(pixel); + break; + case Format::RGB8: + color = Color::DecodeRGB8(pixel); + break; + case Format::RGB5A1: + color = Color::DecodeRGB5A1(pixel); + break; + case Format::RGB565: + color = Color::DecodeRGB565(pixel); + break; + case Format::RGBA4: + color = Color::DecodeRGBA4(pixel); + break; + default: + qDebug() << "Unknown fb color format " << static_cast<int>(framebuffer_format); + break; } - } - pixmap = QPixmap::fromImage(decoded_image); - break; - } - case Format::RGB8: - { - QImage decoded_image(framebuffer_width, framebuffer_height, QImage::Format_ARGB32); - u8* color_buffer = Memory::GetPointer(Pica::PAddrToVAddr(framebuffer_address)); - for (unsigned int y = 0; y < framebuffer_height; ++y) { - for (unsigned int x = 0; x < framebuffer_width; ++x) { - const u32 coarse_y = y & ~7; - u32 offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * framebuffer_width * bytes_per_pixel; - u8* pixel_pointer = color_buffer + offset; - - decoded_image.setPixel(x, y, qRgba(pixel_pointer[0], pixel_pointer[1], pixel_pointer[2], 255/*value >> 24*/)); - } + decoded_image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), 255)); } - pixmap = QPixmap::fromImage(decoded_image); - break; - } - - case Format::RGBA5551: - { - QImage decoded_image(framebuffer_width, framebuffer_height, QImage::Format_ARGB32); - u8* color_buffer = Memory::GetPointer(Pica::PAddrToVAddr(framebuffer_address)); - for (unsigned int y = 0; y < framebuffer_height; ++y) { - for (unsigned int x = 0; x < framebuffer_width; ++x) { - const u32 coarse_y = y & ~7; - u32 offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * framebuffer_width * bytes_per_pixel; - u16 value = *(u16*)(color_buffer + offset); - u8 r = Color::Convert5To8((value >> 11) & 0x1F); - u8 g = Color::Convert5To8((value >> 6) & 0x1F); - u8 b = Color::Convert5To8((value >> 1) & 0x1F); - u8 a = Color::Convert1To8(value & 1); - - decoded_image.setPixel(x, y, qRgba(r, g, b, 255/*a*/)); - } - } - pixmap = QPixmap::fromImage(decoded_image); - break; - } - - default: - qDebug() << "Unknown fb color format " << static_cast<int>(framebuffer_format); - break; } + pixmap = QPixmap::fromImage(decoded_image); framebuffer_address_control->SetValue(framebuffer_address); framebuffer_width_control->setValue(framebuffer_width); diff --git a/src/citra_qt/debugger/graphics_framebuffer.h b/src/citra_qt/debugger/graphics_framebuffer.h index c6e293bc9..15ebd1f7d 100644 --- a/src/citra_qt/debugger/graphics_framebuffer.h +++ b/src/citra_qt/debugger/graphics_framebuffer.h @@ -29,7 +29,7 @@ class GraphicsFramebufferWidget : public BreakPointObserverDock { enum class Format { RGBA8 = 0, RGB8 = 1, - RGBA5551 = 2, + RGB5A1 = 2, RGB565 = 3, RGBA4 = 4, }; diff --git a/src/common/common.h b/src/common/common.h index 948dc536a..f7d0f55c5 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -117,40 +117,4 @@ enum EMUSTATE_CHANGE EMUSTATE_CHANGE_STOP }; - -#ifdef _MSC_VER -inline unsigned long long bswap64(unsigned long long x) { return _byteswap_uint64(x); } -inline unsigned int bswap32(unsigned int x) { return _byteswap_ulong(x); } -inline unsigned short bswap16(unsigned short x) { return _byteswap_ushort(x); } -#else -// TODO: speedup -inline unsigned short bswap16(unsigned short x) { return (x << 8) | (x >> 8); } -inline unsigned int bswap32(unsigned int x) { return (x >> 24) | ((x & 0xFF0000) >> 8) | ((x & 0xFF00) << 8) | (x << 24);} -inline unsigned long long bswap64(unsigned long long x) {return ((unsigned long long)bswap32(x) << 32) | bswap32(x >> 32); } -#endif - -inline float bswapf(float f) { - union { - float f; - unsigned int u32; - } dat1, dat2; - - dat1.f = f; - dat2.u32 = bswap32(dat1.u32); - - return dat2.f; -} - -inline double bswapd(double f) { - union { - double f; - unsigned long long u64; - } dat1, dat2; - - dat1.f = f; - dat2.u64 = bswap64(dat1.u64); - - return dat2.f; -} - #include "swap.h" diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index d56156e4a..e76cb7d68 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h @@ -37,11 +37,6 @@ #ifndef _MSC_VER #include <errno.h> -#ifdef __linux__ -#include <byteswap.h> -#elif defined __FreeBSD__ -#include <sys/endian.h> -#endif #if defined(__x86_64__) || defined(_M_X64) #define Crash() __asm__ __volatile__("int $3") @@ -145,75 +140,3 @@ inline u64 _rotr64(u64 x, unsigned int shift){ // This function might change the error code. // Defined in Misc.cpp. const char* GetLastErrorMsg(); - -namespace Common -{ -inline u8 swap8(u8 _data) {return _data;} -inline u32 swap24(const u8* _data) {return (_data[0] << 16) | (_data[1] << 8) | _data[2];} - -#ifdef ANDROID -#undef swap16 -#undef swap32 -#undef swap64 -#endif - -#ifdef _MSC_VER -inline u16 swap16(u16 _data) {return _byteswap_ushort(_data);} -inline u32 swap32(u32 _data) {return _byteswap_ulong (_data);} -inline u64 swap64(u64 _data) {return _byteswap_uint64(_data);} -#elif _M_ARM -inline u16 swap16 (u16 _data) { u32 data = _data; __asm__ ("rev16 %0, %1\n" : "=l" (data) : "l" (data)); return (u16)data;} -inline u32 swap32 (u32 _data) {__asm__ ("rev %0, %1\n" : "=l" (_data) : "l" (_data)); return _data;} -inline u64 swap64(u64 _data) {return ((u64)swap32(_data) << 32) | swap32(_data >> 32);} -#elif __linux__ -inline u16 swap16(u16 _data) {return bswap_16(_data);} -inline u32 swap32(u32 _data) {return bswap_32(_data);} -inline u64 swap64(u64 _data) {return bswap_64(_data);} -#elif __APPLE__ -inline __attribute__((always_inline)) u16 swap16(u16 _data) - {return (_data >> 8) | (_data << 8);} -inline __attribute__((always_inline)) u32 swap32(u32 _data) - {return __builtin_bswap32(_data);} -inline __attribute__((always_inline)) u64 swap64(u64 _data) - {return __builtin_bswap64(_data);} -#elif __FreeBSD__ -inline u16 swap16(u16 _data) {return bswap16(_data);} -inline u32 swap32(u32 _data) {return bswap32(_data);} -inline u64 swap64(u64 _data) {return bswap64(_data);} -#else -// Slow generic implementation. -inline u16 swap16(u16 data) {return (data >> 8) | (data << 8);} -inline u32 swap32(u32 data) {return (swap16(data) << 16) | swap16(data >> 16);} -inline u64 swap64(u64 data) {return ((u64)swap32(data) << 32) | swap32(data >> 32);} -#endif - -inline u16 swap16(const u8* _pData) {return swap16(*(const u16*)_pData);} -inline u32 swap32(const u8* _pData) {return swap32(*(const u32*)_pData);} -inline u64 swap64(const u8* _pData) {return swap64(*(const u64*)_pData);} - -template <int count> -void swap(u8*); - -template <> -inline void swap<1>(u8* data) -{} - -template <> -inline void swap<2>(u8* data) -{ - *reinterpret_cast<u16*>(data) = swap16(data); -} - -template <> -inline void swap<4>(u8* data) -{ - *reinterpret_cast<u32*>(data) = swap32(data); -} - -template <> -inline void swap<8>(u8* data) -{ - *reinterpret_cast<u64*>(data) = swap64(data); -} - -} // Namespace Common diff --git a/src/common/swap.h b/src/common/swap.h index e2d918362..7e37655bf 100644 --- a/src/common/swap.h +++ b/src/common/swap.h @@ -17,18 +17,14 @@ #pragma once -// Android -#if defined(ANDROID) +#if defined(__linux__) +#include <byteswap.h> +#elif defined(__FreeBSD__) #include <sys/endian.h> - -#if _BYTE_ORDER == _LITTLE_ENDIAN && !defined(COMMON_LITTLE_ENDIAN) -#define COMMON_LITTLE_ENDIAN 1 -#elif _BYTE_ORDER == _BIG_ENDIAN && !defined(COMMON_BIG_ENDIAN) -#define COMMON_BIG_ENDIAN 1 #endif // GCC 4.6+ -#elif __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +#if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #if __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) && !defined(COMMON_LITTLE_ENDIAN) #define COMMON_LITTLE_ENDIAN 1 @@ -49,7 +45,6 @@ #elif defined(_MSC_VER) && !defined(COMMON_BIG_ENDIAN) && !defined(COMMON_LITTLE_ENDIAN) #define COMMON_LITTLE_ENDIAN 1 - #endif // Worst case, default to little endian. @@ -57,6 +52,93 @@ #define COMMON_LITTLE_ENDIAN 1 #endif +namespace Common { + +inline u8 swap8(u8 _data) {return _data;} +inline u32 swap24(const u8* _data) {return (_data[0] << 16) | (_data[1] << 8) | _data[2];} + +#ifdef _MSC_VER +inline u16 swap16(u16 _data) {return _byteswap_ushort(_data);} +inline u32 swap32(u32 _data) {return _byteswap_ulong (_data);} +inline u64 swap64(u64 _data) {return _byteswap_uint64(_data);} +#elif _M_ARM +inline u16 swap16 (u16 _data) { u32 data = _data; __asm__ ("rev16 %0, %1\n" : "=l" (data) : "l" (data)); return (u16)data;} +inline u32 swap32 (u32 _data) {__asm__ ("rev %0, %1\n" : "=l" (_data) : "l" (_data)); return _data;} +inline u64 swap64(u64 _data) {return ((u64)swap32(_data) << 32) | swap32(_data >> 32);} +#elif __linux__ +inline u16 swap16(u16 _data) {return bswap_16(_data);} +inline u32 swap32(u32 _data) {return bswap_32(_data);} +inline u64 swap64(u64 _data) {return bswap_64(_data);} +#elif __APPLE__ +inline __attribute__((always_inline)) u16 swap16(u16 _data) +{return (_data >> 8) | (_data << 8);} +inline __attribute__((always_inline)) u32 swap32(u32 _data) +{return __builtin_bswap32(_data);} +inline __attribute__((always_inline)) u64 swap64(u64 _data) +{return __builtin_bswap64(_data);} +#elif __FreeBSD__ +inline u16 swap16(u16 _data) {return bswap16(_data);} +inline u32 swap32(u32 _data) {return bswap32(_data);} +inline u64 swap64(u64 _data) {return bswap64(_data);} +#else +// Slow generic implementation. +inline u16 swap16(u16 data) {return (data >> 8) | (data << 8);} +inline u32 swap32(u32 data) {return (swap16(data) << 16) | swap16(data >> 16);} +inline u64 swap64(u64 data) {return ((u64)swap32(data) << 32) | swap32(data >> 32);} +#endif + +inline float swapf(float f) { + union { + float f; + unsigned int u32; + } dat1, dat2; + + dat1.f = f; + dat2.u32 = swap32(dat1.u32); + + return dat2.f; +} + +inline double swapd(double f) { + union { + double f; + unsigned long long u64; + } dat1, dat2; + + dat1.f = f; + dat2.u64 = swap64(dat1.u64); + + return dat2.f; +} + +inline u16 swap16(const u8* _pData) {return swap16(*(const u16*)_pData);} +inline u32 swap32(const u8* _pData) {return swap32(*(const u32*)_pData);} +inline u64 swap64(const u8* _pData) {return swap64(*(const u64*)_pData);} + +template <int count> +void swap(u8*); + +template <> +inline void swap<1>(u8* data) { } + +template <> +inline void swap<2>(u8* data) { + *reinterpret_cast<u16*>(data) = swap16(data); +} + +template <> +inline void swap<4>(u8* data) { + *reinterpret_cast<u32*>(data) = swap32(data); +} + +template <> +inline void swap<8>(u8* data) { + *reinterpret_cast<u64*>(data) = swap64(data); +} + +} // Namespace Common + + template <typename T, typename F> struct swap_struct_t { typedef swap_struct_t<T, F> swapped_t; @@ -448,35 +530,35 @@ bool operator==(const S &p, const swap_struct_t<T, F> v) { template <typename T> struct swap_64_t { static T swap(T x) { - return (T)bswap64(*(u64 *)&x); + return (T)Common::swap64(*(u64 *)&x); } }; template <typename T> struct swap_32_t { static T swap(T x) { - return (T)bswap32(*(u32 *)&x); + return (T)Common::swap32(*(u32 *)&x); } }; template <typename T> struct swap_16_t { static T swap(T x) { - return (T)bswap16(*(u16 *)&x); + return (T)Common::swap16(*(u16 *)&x); } }; template <typename T> struct swap_float_t { static T swap(T x) { - return (T)bswapf(*(float *)&x); + return (T)Common::swapf(*(float *)&x); } }; template <typename T> struct swap_double_t { static T swap(T x) { - return (T)bswapd(*(double *)&x); + return (T)Common::swapd(*(double *)&x); } }; @@ -527,4 +609,5 @@ typedef s64 s64_be; typedef float float_be; typedef double double_be; + #endif diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 0ab0e440c..212da25c5 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -35,9 +35,10 @@ set(SRCS hle/service/am_app.cpp hle/service/am_net.cpp hle/service/am_sys.cpp - hle/service/apt_a.cpp - hle/service/apt_s.cpp - hle/service/apt_u.cpp + hle/service/apt/apt.cpp + hle/service/apt/apt_a.cpp + hle/service/apt/apt_s.cpp + hle/service/apt/apt_u.cpp hle/service/boss_p.cpp hle/service/boss_u.cpp hle/service/cam_u.cpp @@ -71,9 +72,10 @@ set(SRCS hle/service/ns_s.cpp hle/service/nwm_uds.cpp hle/service/pm_app.cpp - hle/service/ptm_play.cpp - hle/service/ptm_u.cpp - hle/service/ptm_sysm.cpp + hle/service/ptm/ptm.cpp + hle/service/ptm/ptm_play.cpp + hle/service/ptm/ptm_u.cpp + hle/service/ptm/ptm_sysm.cpp hle/service/service.cpp hle/service/soc_u.cpp hle/service/srv.cpp @@ -140,9 +142,10 @@ set(HEADERS hle/service/am_app.h hle/service/am_net.h hle/service/am_sys.h - hle/service/apt_a.h - hle/service/apt_s.h - hle/service/apt_u.h + hle/service/apt/apt.h + hle/service/apt/apt_a.h + hle/service/apt/apt_s.h + hle/service/apt/apt_u.h hle/service/boss_p.h hle/service/boss_u.h hle/service/cam_u.h @@ -176,9 +179,10 @@ set(HEADERS hle/service/ns_s.h hle/service/nwm_uds.h hle/service/pm_app.h - hle/service/ptm_play.h - hle/service/ptm_u.h - hle/service/ptm_sysm.h + hle/service/ptm/ptm.h + hle/service/ptm/ptm_play.h + hle/service/ptm/ptm_u.h + hle/service/ptm/ptm_sysm.h hle/service/service.h hle/service/soc_u.h hle/service/srv.h diff --git a/src/core/arm/skyeye_common/vfp/vfp_helper.h b/src/core/arm/skyeye_common/vfp/vfp_helper.h index 75d860e95..5d1b4e53f 100644 --- a/src/core/arm/skyeye_common/vfp/vfp_helper.h +++ b/src/core/arm/skyeye_common/vfp/vfp_helper.h @@ -144,8 +144,8 @@ static inline void mul64to128(u64* resh, u64* resl, u64 n, u64 m) u32 nh, nl, mh, ml; u64 rh, rma, rmb, rl; - nl = n; - ml = m; + nl = static_cast<u32>(n); + ml = static_cast<u32>(m); rl = (u64)nl * ml; nh = n >> 32; diff --git a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp index 1a05ef8c1..d76d37fd4 100644 --- a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp @@ -661,8 +661,8 @@ static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 if ((rem + incr) < rem && d < 0xffffffff) d += 1; - if (d > (0x7fffffff + (vdm.sign != 0))) { - d = (0x7fffffff + (vdm.sign != 0)); + if (d > (0x7fffffffU + (vdm.sign != 0))) { + d = (0x7fffffffU + (vdm.sign != 0)); exceptions |= FPSCR_IOC; } else if (rem) exceptions |= FPSCR_IXC; diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp index c925279da..1aaeaa9c9 100644 --- a/src/core/hle/hle.cpp +++ b/src/core/hle/hle.cpp @@ -13,9 +13,6 @@ #include "core/hle/shared_page.h" #include "core/hle/kernel/thread.h" #include "core/hle/service/service.h" -#include "core/hle/service/fs/archive.h" -#include "core/hle/service/cfg/cfg.h" -#include "core/hle/service/hid/hid.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -76,9 +73,6 @@ static void RegisterAllModules() { void Init() { Service::Init(); - Service::FS::ArchiveInit(); - Service::CFG::CFGInit(); - Service::HID::HIDInit(); RegisterAllModules(); @@ -89,9 +83,6 @@ void Init() { } void Shutdown() { - Service::HID::HIDShutdown(); - Service::CFG::CFGShutdown(); - Service::FS::ArchiveShutdown(); Service::Shutdown(); g_module_db.clear(); diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 0e391fe2d..3648a168b 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -208,11 +208,11 @@ union ResultCode { } }; -inline bool operator==(const ResultCode a, const ResultCode b) { +inline bool operator==(const ResultCode& a, const ResultCode& b) { return a.raw == b.raw; } -inline bool operator!=(const ResultCode a, const ResultCode b) { +inline bool operator!=(const ResultCode& a, const ResultCode& b) { return a.raw != b.raw; } diff --git a/src/core/hle/service/am_sys.cpp b/src/core/hle/service/am_sys.cpp index 7ab89569f..b244190a2 100644 --- a/src/core/hle/service/am_sys.cpp +++ b/src/core/hle/service/am_sys.cpp @@ -5,19 +5,56 @@ #include "core/hle/hle.h" #include "core/hle/service/am_sys.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace AM_SYS - namespace AM_SYS { -// Empty arrays are illegal -- commented out until an entry is added. -//const Interface::FunctionInfo FunctionTable[] = { }; +/** + * Gets the number of installed titles in the requested media type + * Inputs: + * 0: Command header (0x00010040) + * 1: Media type to load the titles from + * Outputs: + * 1: Result, 0 on success, otherwise error code + * 2: The number of titles in the requested media type + */ +static void TitleIDListGetTotal(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 media_type = cmd_buff[1] & 0xFF; + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = 0; + LOG_WARNING(Service_CFG, "(STUBBED) media_type %u", media_type); +} + +/** + * Loads information about the desired number of titles from the desired media type into an array + * Inputs: + * 0: Command header (0x00020082) + * 1: The maximum number of titles to load + * 2: Media type to load the titles from + * 3: Descriptor of the output buffer pointer + * 4: Address of the output buffer + * Outputs: + * 1: Result, 0 on success, otherwise error code + * 2: The number of titles loaded from the requested media type + */ +static void GetTitleIDList(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 num_titles = cmd_buff[1]; + u32 media_type = cmd_buff[2] & 0xFF; + u32 addr = cmd_buff[4]; + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = 0; + LOG_WARNING(Service_CFG, "(STUBBED) Requested %u titles from media type %u", num_titles, media_type); +} -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class +const Interface::FunctionInfo FunctionTable[] = { + {0x00010040, TitleIDListGetTotal, "TitleIDListGetTotal"}, + {0x00020082, GetTitleIDList, "GetTitleIDList"}, +}; Interface::Interface() { - //Register(FunctionTable); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp new file mode 100644 index 000000000..5971f860b --- /dev/null +++ b/src/core/hle/service/apt/apt.cpp @@ -0,0 +1,285 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/file_util.h" + +#include "core/hle/service/service.h" +#include "core/hle/service/apt/apt.h" +#include "core/hle/service/apt/apt_a.h" +#include "core/hle/service/apt/apt_s.h" +#include "core/hle/service/apt/apt_u.h" + +#include "core/hle/hle.h" +#include "core/hle/kernel/event.h" +#include "core/hle/kernel/mutex.h" +#include "core/hle/kernel/shared_memory.h" +#include "core/hle/kernel/thread.h" + +namespace Service { +namespace APT { + +// Address used for shared font (as observed on HW) +// TODO(bunnei): This is the hard-coded address where we currently dump the shared font from via +// https://github.com/citra-emu/3dsutils. This is technically a hack, and will not work at any +// address other than 0x18000000 due to internal pointers in the shared font dump that would need to +// be relocated. This might be fixed by dumping the shared font @ address 0x00000000 and then +// correctly mapping it in Citra, however we still do not understand how the mapping is determined. +static const VAddr SHARED_FONT_VADDR = 0x18000000; + +/// Handle to shared memory region designated to for shared system font +static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; + +static Kernel::SharedPtr<Kernel::Mutex> lock; +static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event +static Kernel::SharedPtr<Kernel::Event> pause_event = 0; ///< APT pause event +static std::vector<u8> shared_font; + +void Initialize(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom(); + cmd_buff[4] = Kernel::g_handle_table.Create(pause_event).MoveFrom(); + + // TODO(bunnei): Check if these events are cleared/signaled every time Initialize is called. + notification_event->Clear(); + pause_event->Signal(); // Fire start event + + ASSERT_MSG((nullptr != lock), "Cannot initialize without lock"); + lock->Release(); + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error +} + +void GetSharedFont(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + if (!shared_font.empty()) { + // TODO(bunnei): This function shouldn't copy the shared font every time it's called. + // Instead, it should probably map the shared font as RO memory. We don't currently have + // an easy way to do this, but the copy should be sufficient for now. + memcpy(Memory::GetPointer(SHARED_FONT_VADDR), shared_font.data(), shared_font.size()); + + cmd_buff[0] = 0x00440082; + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + cmd_buff[2] = SHARED_FONT_VADDR; + cmd_buff[4] = Kernel::g_handle_table.Create(shared_font_mem).MoveFrom(); + } else { + cmd_buff[1] = -1; // Generic error (not really possible to verify this on hardware) + LOG_ERROR(Kernel_SVC, "called, but %s has not been loaded!", SHARED_FONT); + } +} + +void NotifyToWait(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 app_id = cmd_buff[1]; + // TODO(Subv): Verify this, it seems to get SWKBD and Home Menu further. + pause_event->Signal(); + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id); +} + +void GetLockHandle(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + + // Not sure what these parameters are used for, but retail apps check that they are 0 after + // GetLockHandle has been called. + cmd_buff[2] = 0; + cmd_buff[3] = 0; + cmd_buff[4] = 0; + + cmd_buff[5] = Kernel::g_handle_table.Create(lock).MoveFrom(); + LOG_TRACE(Service_APT, "called handle=0x%08X", cmd_buff[5]); +} + +void Enable(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for? + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); +} + +void GetAppletManInfo(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 unk = cmd_buff[1]; + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + cmd_buff[2] = 0; + cmd_buff[3] = 0; + cmd_buff[4] = static_cast<u32>(AppID::HomeMenu); // Home menu AppID + cmd_buff[5] = static_cast<u32>(AppID::Application); // TODO(purpasmart96): Do this correctly + + LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); +} + +void IsRegistered(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 app_id = cmd_buff[1]; + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + cmd_buff[2] = 1; // Set to registered + LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); +} + +void InquireNotification(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 app_id = cmd_buff[1]; + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + cmd_buff[2] = static_cast<u32>(SignalType::None); // Signal type + LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); +} + +void SendParameter(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 src_app_id = cmd_buff[1]; + u32 dst_app_id = cmd_buff[2]; + u32 signal_type = cmd_buff[3]; + u32 buffer_size = cmd_buff[4]; + u32 value = cmd_buff[5]; + u32 handle = cmd_buff[6]; + u32 size = cmd_buff[7]; + u32 in_param_buffer_ptr = cmd_buff[8]; + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + + LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," + "buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X", + src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, in_param_buffer_ptr); +} + +void ReceiveParameter(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 app_id = cmd_buff[1]; + u32 buffer_size = cmd_buff[2]; + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + cmd_buff[2] = 0; + cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type + cmd_buff[4] = 0x10; // Parameter buffer size (16) + cmd_buff[5] = 0; + cmd_buff[6] = 0; + cmd_buff[7] = 0; + LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); +} + +void GlanceParameter(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 app_id = cmd_buff[1]; + u32 buffer_size = cmd_buff[2]; + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + cmd_buff[2] = 0; + cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type + cmd_buff[4] = 0x10; // Parameter buffer size (16) + cmd_buff[5] = 0; + cmd_buff[6] = 0; + cmd_buff[7] = 0; + + LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); +} + +void CancelParameter(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 flag1 = cmd_buff[1]; + u32 unk = cmd_buff[2]; + u32 flag2 = cmd_buff[3]; + u32 app_id = cmd_buff[4]; + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + cmd_buff[2] = 1; // Set to Success + + LOG_WARNING(Service_APT, "(STUBBED) called flag1=0x%08X, unk=0x%08X, flag2=0x%08X, app_id=0x%08X", + flag1, unk, flag2, app_id); +} + +void AppletUtility(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + // These are from 3dbrew - I'm not really sure what they're used for. + u32 unk = cmd_buff[1]; + u32 buffer1_size = cmd_buff[2]; + u32 buffer2_size = cmd_buff[3]; + u32 buffer1_addr = cmd_buff[5]; + u32 buffer2_addr = cmd_buff[65]; + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + + LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08x, buffer2_size=0x%08x, " + "buffer1_addr=0x%08x, buffer2_addr=0x%08x", unk, buffer1_size, buffer2_size, + buffer1_addr, buffer2_addr); +} + +void SetAppCpuTimeLimit(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 value = cmd_buff[1]; + u32 percent = cmd_buff[2]; + + if (value != 1) { + LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value); + } + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + + LOG_WARNING(Service_APT, "(STUBBED) called percent=0x%08X, value=0x%08x", percent, value); +} + +void GetAppCpuTimeLimit(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 value = cmd_buff[1]; + + if (value != 1) { + LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value); + } + + // TODO(purpasmart96): This is incorrect, I'm pretty sure the percentage should + // be set by the application. + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + cmd_buff[2] = 0x80; // Set to 80% + + LOG_WARNING(Service_APT, "(STUBBED) called value=0x%08x", value); +} + +void APTInit() { + AddService(new APT_A_Interface); + AddService(new APT_S_Interface); + AddService(new APT_U_Interface); + + // Load the shared system font (if available). + // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header + // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided + // a homebrew app to do this: https://github.com/citra-emu/3dsutils. Put the resulting file + // "shared_font.bin" in the Citra "sysdata" directory. + + shared_font.clear(); + std::string filepath = FileUtil::GetUserPath(D_SYSDATA_IDX) + SHARED_FONT; + + FileUtil::CreateFullPath(filepath); // Create path if not already created + FileUtil::IOFile file(filepath, "rb"); + + if (file.IsOpen()) { + // Read shared font data + shared_font.resize((size_t)file.GetSize()); + file.ReadBytes(shared_font.data(), (size_t)file.GetSize()); + + // Create shared font memory object + shared_font_mem = Kernel::SharedMemory::Create("APT_U:shared_font_mem"); + } else { + LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str()); + shared_font_mem = nullptr; + } + + lock = Kernel::Mutex::Create(false, "APT_U:Lock"); + + // TODO(bunnei): Check if these are created in Initialize or on APT process startup. + notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification"); + pause_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Pause"); +} + +void APTShutdown() { + +} + +} // namespace APT +} // namespace Service diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h new file mode 100644 index 000000000..a39adbff9 --- /dev/null +++ b/src/core/hle/service/apt/apt.h @@ -0,0 +1,222 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> +#include "core/hle/result.h" +#include "core/hle/service/service.h" + +namespace Service { +namespace APT { + +/// Signals used by APT functions +enum class SignalType : u32 { + None = 0x0, + AppJustStarted = 0x1, + ReturningToApp = 0xB, + ExitingApp = 0xC, +}; + +/// App Id's used by APT functions +enum class AppID : u32 { + HomeMenu = 0x101, + AlternateMenu = 0x103, + Camera = 0x110, + FriendsList = 0x112, + GameNotes = 0x113, + InternetBrowser = 0x114, + InstructionManual = 0x115, + Notifications = 0x116, + Miiverse = 0x117, + SoftwareKeyboard1 = 0x201, + Ed = 0x202, + PnoteApp = 0x204, + SnoteApp = 0x205, + Error = 0x206, + Mint = 0x207, + Extrapad = 0x208, + Memolib = 0x209, + Application = 0x300, + SoftwareKeyboard2 = 0x401, +}; + +/** + * APT::Initialize service function + * Service function that initializes the APT process for the running application + * Outputs: + * 1 : Result of the function, 0 on success, otherwise error code + * 3 : Handle to the notification event + * 4 : Handle to the pause event + */ +void Initialize(Service::Interface* self); + +/** + * APT::GetSharedFont service function + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Virtual address of where shared font will be loaded in memory + * 4 : Handle to shared font memory + */ +void GetSharedFont(Service::Interface* self); + +/** + * APT::NotifyToWait service function + * Inputs: + * 1 : AppID + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +void NotifyToWait(Service::Interface* self); + +void GetLockHandle(Service::Interface* self); + +void Enable(Service::Interface* self); + +/** + * APT::GetAppletManInfo service function. + * Inputs: + * 1 : Unknown + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Unknown u32 value + * 3 : Unknown u8 value + * 4 : Home Menu AppId + * 5 : AppID of currently active app + */ +void GetAppletManInfo(Service::Interface* self); + +/** + * APT::IsRegistered service function. This returns whether the specified AppID is registered with NS yet. + * An AppID is "registered" once the process associated with the AppID uses APT:Enable. Home Menu uses this + * command to determine when the launched process is running and to determine when to stop using GSP etc, + * while displaying the "Nintendo 3DS" loading screen. + * Inputs: + * 1 : AppID + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Output, 0 = not registered, 1 = registered. + */ +void IsRegistered(Service::Interface* self); + +void InquireNotification(Service::Interface* self); + +/** + * APT::SendParameter service function. This sets the parameter data state. + * Inputs: + * 1 : Source AppID + * 2 : Destination AppID + * 3 : Signal type + * 4 : Parameter buffer size, max size is 0x1000 (this can be zero) + * 5 : Value + * 6 : Handle to the destination process, likely used for shared memory (this can be zero) + * 7 : (Size<<14) | 2 + * 8 : Input parameter buffer ptr + * Outputs: + * 0 : Return Header + * 1 : Result of function, 0 on success, otherwise error code +*/ +void SendParameter(Service::Interface* self); + +/** + * APT::ReceiveParameter service function. This returns the current parameter data from NS state, + * from the source process which set the parameters. Once finished, NS will clear a flag in the NS + * state so that this command will return an error if this command is used again if parameters were + * not set again. This is called when the second Initialize event is triggered. It returns a signal + * type indicating why it was triggered. + * Inputs: + * 1 : AppID + * 2 : Parameter buffer size, max size is 0x1000 + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : AppID of the process which sent these parameters + * 3 : Signal type + * 4 : Actual parameter buffer size, this is <= to the the input size + * 5 : Value + * 6 : Handle from the source process which set the parameters, likely used for shared memory + * 7 : Size + * 8 : Output parameter buffer ptr + */ +void ReceiveParameter(Service::Interface* self); + +/** + * APT::GlanceParameter service function. This is exactly the same as APT_U::ReceiveParameter + * (except for the word value prior to the output handle), except this will not clear the flag + * (except when responseword[3]==8 || responseword[3]==9) in NS state. + * Inputs: + * 1 : AppID + * 2 : Parameter buffer size, max size is 0x1000 + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Unknown, for now assume AppID of the process which sent these parameters + * 3 : Unknown, for now assume Signal type + * 4 : Actual parameter buffer size, this is <= to the the input size + * 5 : Value + * 6 : Handle from the source process which set the parameters, likely used for shared memory + * 7 : Size + * 8 : Output parameter buffer ptr + */ +void GlanceParameter(Service::Interface* self); + +/** + * APT::CancelParameter service function. When the parameter data is available, and when the above + * specified fields match the ones in NS state(for the ones where the checks are enabled), this + * clears the flag which indicates that parameter data is available + * (same flag cleared by APT:ReceiveParameter). + * Inputs: + * 1 : Flag, when non-zero NS will compare the word after this one with a field in the NS state. + * 2 : Unknown, this is the same as the first unknown field returned by APT:ReceiveParameter. + * 3 : Flag, when non-zero NS will compare the word after this one with a field in the NS state. + * 4 : AppID + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Status flag, 0 = failure due to no parameter data being available, or the above enabled + * fields don't match the fields in NS state. 1 = success. + */ +void CancelParameter(Service::Interface* self); + +/** + * APT::AppletUtility service function + * Inputs: + * 1 : Unknown, but clearly used for something + * 2 : Buffer 1 size (purpose is unknown) + * 3 : Buffer 2 size (purpose is unknown) + * 5 : Buffer 1 address (purpose is unknown) + * 65 : Buffer 2 address (purpose is unknown) + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +void AppletUtility(Service::Interface* self); + +/** + * APT::SetAppCpuTimeLimit service function + * Inputs: + * 1 : Value, must be one + * 2 : Percentage of CPU time from 5 to 80 + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +void SetAppCpuTimeLimit(Service::Interface* self); + +/** + * APT::GetAppCpuTimeLimit service function + * Inputs: + * 1 : Value, must be one + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + * 2 : System core CPU time percentage + */ +void GetAppCpuTimeLimit(Service::Interface* self); + +/// Initialize the APT service +void APTInit(); + +/// Shutdown the APT service +void APTShutdown(); + +} // namespace APT +} // namespace Service diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp new file mode 100644 index 000000000..dbe5c1d87 --- /dev/null +++ b/src/core/hle/service/apt/apt_a.cpp @@ -0,0 +1,33 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/apt/apt.h" +#include "core/hle/service/apt/apt_a.h" + +namespace Service { +namespace APT { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010040, GetLockHandle, "GetLockHandle?"}, + {0x00020080, Initialize, "Initialize?"}, + {0x00030040, nullptr, "Enable?"}, + {0x00040040, nullptr, "Finalize?"}, + {0x00050040, nullptr, "GetAppletManInfo?"}, + {0x00060040, nullptr, "GetAppletInfo?"}, + {0x000D0080, ReceiveParameter, "ReceiveParameter?"}, + {0x000E0080, GlanceParameter, "GlanceParameter?"}, + {0x003B0040, nullptr, "CancelLibraryApplet?"}, + {0x00430040, nullptr, "NotifyToWait?"}, + {0x00440000, GetSharedFont, "GetSharedFont?"}, + {0x004B00C2, nullptr, "AppletUtility?"}, + {0x00550040, nullptr, "WriteInputToNsState?"}, +}; + +APT_A_Interface::APT_A_Interface() { + Register(FunctionTable); +} + +} // namespace APT +} // namespace Service diff --git a/src/core/hle/service/apt_a.h b/src/core/hle/service/apt/apt_a.h index 6cbf1288f..331fb5586 100644 --- a/src/core/hle/service/apt_a.h +++ b/src/core/hle/service/apt/apt_a.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace APT_A +namespace Service { +namespace APT { -namespace APT_A { - -class Interface : public Service::Interface { +class APT_A_Interface : public Service::Interface { public: - Interface(); + APT_A_Interface(); std::string GetPortName() const override { return "APT:A"; } }; -} // namespace +} // namespace APT +} // namespace Service
\ No newline at end of file diff --git a/src/core/hle/service/apt/apt_s.cpp b/src/core/hle/service/apt/apt_s.cpp new file mode 100644 index 000000000..3fd348651 --- /dev/null +++ b/src/core/hle/service/apt/apt_s.cpp @@ -0,0 +1,104 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + + +#include "common/common.h" +#include "common/file_util.h" + +#include "core/hle/hle.h" +#include "core/hle/service/apt/apt.h" +#include "core/hle/service/apt/apt_s.h" + +namespace Service { +namespace APT { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010040, GetLockHandle, "GetLockHandle"}, + {0x00020080, Initialize, "Initialize"}, + {0x00030040, Enable, "Enable"}, + {0x00040040, nullptr, "Finalize"}, + {0x00050040, nullptr, "GetAppletManInfo"}, + {0x00060040, nullptr, "GetAppletInfo"}, + {0x00070000, nullptr, "GetLastSignaledAppletId"}, + {0x00080000, nullptr, "CountRegisteredApplet"}, + {0x00090040, nullptr, "IsRegistered"}, + {0x000A0040, nullptr, "GetAttribute"}, + {0x000B0040, InquireNotification, "InquireNotification"}, + {0x000C0104, nullptr, "SendParameter"}, + {0x000D0080, ReceiveParameter, "ReceiveParameter"}, + {0x000E0080, GlanceParameter, "GlanceParameter"}, + {0x000F0100, nullptr, "CancelParameter"}, + {0x001000C2, nullptr, "DebugFunc"}, + {0x001100C0, nullptr, "MapProgramIdForDebug"}, + {0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"}, + {0x00130000, nullptr, "GetPreparationState"}, + {0x00140040, nullptr, "SetPreparationState"}, + {0x00150140, nullptr, "PrepareToStartApplication"}, + {0x00160040, nullptr, "PreloadLibraryApplet"}, + {0x00170040, nullptr, "FinishPreloadingLibraryApplet"}, + {0x00180040, nullptr, "PrepareToStartLibraryApplet"}, + {0x00190040, nullptr, "PrepareToStartSystemApplet"}, + {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"}, + {0x001B00C4, nullptr, "StartApplication"}, + {0x001C0000, nullptr, "WakeupApplication"}, + {0x001D0000, nullptr, "CancelApplication"}, + {0x001E0084, nullptr, "StartLibraryApplet"}, + {0x001F0084, nullptr, "StartSystemApplet"}, + {0x00200044, nullptr, "StartNewestHomeMenu"}, + {0x00210000, nullptr, "OrderToCloseApplication"}, + {0x00220040, nullptr, "PrepareToCloseApplication"}, + {0x00230040, nullptr, "PrepareToJumpToApplication"}, + {0x00240044, nullptr, "JumpToApplication"}, + {0x002500C0, nullptr, "PrepareToCloseLibraryApplet"}, + {0x00260000, nullptr, "PrepareToCloseSystemApplet"}, + {0x00270044, nullptr, "CloseApplication"}, + {0x00280044, nullptr, "CloseLibraryApplet"}, + {0x00290044, nullptr, "CloseSystemApplet"}, + {0x002A0000, nullptr, "OrderToCloseSystemApplet"}, + {0x002B0000, nullptr, "PrepareToJumpToHomeMenu"}, + {0x002C0044, nullptr, "JumpToHomeMenu"}, + {0x002D0000, nullptr, "PrepareToLeaveHomeMenu"}, + {0x002E0044, nullptr, "LeaveHomeMenu"}, + {0x002F0040, nullptr, "PrepareToLeaveResidentApplet"}, + {0x00300044, nullptr, "LeaveResidentApplet"}, + {0x00310100, nullptr, "PrepareToDoApplicationJump"}, + {0x00320084, nullptr, "DoApplicationJump"}, + {0x00330000, nullptr, "GetProgramIdOnApplicationJump"}, + {0x00340084, nullptr, "SendDeliverArg"}, + {0x00350080, nullptr, "ReceiveDeliverArg"}, + {0x00360040, nullptr, "LoadSysMenuArg"}, + {0x00370042, nullptr, "StoreSysMenuArg"}, + {0x00380040, nullptr, "PreloadResidentApplet"}, + {0x00390040, nullptr, "PrepareToStartResidentApplet"}, + {0x003A0044, nullptr, "StartResidentApplet"}, + {0x003B0040, nullptr, "CancelLibraryApplet"}, + {0x003C0042, nullptr, "SendDspSleep"}, + {0x003D0042, nullptr, "SendDspWakeUp"}, + {0x003E0080, nullptr, "ReplySleepQuery"}, + {0x003F0040, nullptr, "ReplySleepNotificationComplete"}, + {0x00400042, nullptr, "SendCaptureBufferInfo"}, + {0x00410040, nullptr, "ReceiveCaptureBufferInfo"}, + {0x00420080, nullptr, "SleepSystem"}, + {0x00430040, NotifyToWait, "NotifyToWait"}, + {0x00440000, GetSharedFont, "GetSharedFont"}, + {0x00450040, nullptr, "GetWirelessRebootInfo"}, + {0x00460104, nullptr, "Wrap"}, + {0x00470104, nullptr, "Unwrap"}, + {0x00480100, nullptr, "GetProgramInfo"}, + {0x00490180, nullptr, "Reboot"}, + {0x004A0040, nullptr, "GetCaptureInfo"}, + {0x004B00C2, AppletUtility, "AppletUtility"}, + {0x004C0000, nullptr, "SetFatalErrDispMode"}, + {0x004D0080, nullptr, "GetAppletProgramInfo"}, + {0x004E0000, nullptr, "HardwareResetAsync"}, + {0x004F0080, nullptr, "SetApplicationCpuTimeLimit"}, + {0x00500040, nullptr, "GetApplicationCpuTimeLimit"}, +}; + +APT_S_Interface::APT_S_Interface() { + Register(FunctionTable); +} + +} // namespace APT +} // namespace Service diff --git a/src/core/hle/service/apt_s.h b/src/core/hle/service/apt/apt_s.h index f097c9747..8e87b69af 100644 --- a/src/core/hle/service/apt_s.h +++ b/src/core/hle/service/apt/apt_s.h @@ -6,10 +6,8 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace APT_S - -namespace APT_S { +namespace Service { +namespace APT { // Application and title launching service. These services handle signaling for home/power button as // well. Only one session for either APT service can be open at a time, normally processes close the @@ -18,13 +16,14 @@ namespace APT_S { // svcBreak when the command isn't accessible). See http://3dbrew.org/wiki/NS#APT_Services. /// Interface to "APT:S" service -class Interface : public Service::Interface { +class APT_S_Interface : public Service::Interface { public: - Interface(); + APT_S_Interface(); std::string GetPortName() const override { return "APT:S"; } }; -} // namespace +} // namespace APT +} // namespace Service
\ No newline at end of file diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp new file mode 100644 index 000000000..5ab23801e --- /dev/null +++ b/src/core/hle/service/apt/apt_u.cpp @@ -0,0 +1,103 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + + +#include "common/common.h" +#include "common/file_util.h" + +#include "core/hle/service/apt/apt.h" +#include "core/hle/service/apt/apt_u.h" + +namespace Service { +namespace APT { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010040, GetLockHandle, "GetLockHandle"}, + {0x00020080, Initialize, "Initialize"}, + {0x00030040, Enable, "Enable"}, + {0x00040040, nullptr, "Finalize"}, + {0x00050040, GetAppletManInfo, "GetAppletManInfo"}, + {0x00060040, nullptr, "GetAppletInfo"}, + {0x00070000, nullptr, "GetLastSignaledAppletId"}, + {0x00080000, nullptr, "CountRegisteredApplet"}, + {0x00090040, IsRegistered, "IsRegistered"}, + {0x000A0040, nullptr, "GetAttribute"}, + {0x000B0040, InquireNotification, "InquireNotification"}, + {0x000C0104, SendParameter, "SendParameter"}, + {0x000D0080, ReceiveParameter, "ReceiveParameter"}, + {0x000E0080, GlanceParameter, "GlanceParameter"}, + {0x000F0100, CancelParameter, "CancelParameter"}, + {0x001000C2, nullptr, "DebugFunc"}, + {0x001100C0, nullptr, "MapProgramIdForDebug"}, + {0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"}, + {0x00130000, nullptr, "GetPreparationState"}, + {0x00140040, nullptr, "SetPreparationState"}, + {0x00150140, nullptr, "PrepareToStartApplication"}, + {0x00160040, nullptr, "PreloadLibraryApplet"}, + {0x00170040, nullptr, "FinishPreloadingLibraryApplet"}, + {0x00180040, nullptr, "PrepareToStartLibraryApplet"}, + {0x00190040, nullptr, "PrepareToStartSystemApplet"}, + {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"}, + {0x001B00C4, nullptr, "StartApplication"}, + {0x001C0000, nullptr, "WakeupApplication"}, + {0x001D0000, nullptr, "CancelApplication"}, + {0x001E0084, nullptr, "StartLibraryApplet"}, + {0x001F0084, nullptr, "StartSystemApplet"}, + {0x00200044, nullptr, "StartNewestHomeMenu"}, + {0x00210000, nullptr, "OrderToCloseApplication"}, + {0x00220040, nullptr, "PrepareToCloseApplication"}, + {0x00230040, nullptr, "PrepareToJumpToApplication"}, + {0x00240044, nullptr, "JumpToApplication"}, + {0x002500C0, nullptr, "PrepareToCloseLibraryApplet"}, + {0x00260000, nullptr, "PrepareToCloseSystemApplet"}, + {0x00270044, nullptr, "CloseApplication"}, + {0x00280044, nullptr, "CloseLibraryApplet"}, + {0x00290044, nullptr, "CloseSystemApplet"}, + {0x002A0000, nullptr, "OrderToCloseSystemApplet"}, + {0x002B0000, nullptr, "PrepareToJumpToHomeMenu"}, + {0x002C0044, nullptr, "JumpToHomeMenu"}, + {0x002D0000, nullptr, "PrepareToLeaveHomeMenu"}, + {0x002E0044, nullptr, "LeaveHomeMenu"}, + {0x002F0040, nullptr, "PrepareToLeaveResidentApplet"}, + {0x00300044, nullptr, "LeaveResidentApplet"}, + {0x00310100, nullptr, "PrepareToDoApplicationJump"}, + {0x00320084, nullptr, "DoApplicationJump"}, + {0x00330000, nullptr, "GetProgramIdOnApplicationJump"}, + {0x00340084, nullptr, "SendDeliverArg"}, + {0x00350080, nullptr, "ReceiveDeliverArg"}, + {0x00360040, nullptr, "LoadSysMenuArg"}, + {0x00370042, nullptr, "StoreSysMenuArg"}, + {0x00380040, nullptr, "PreloadResidentApplet"}, + {0x00390040, nullptr, "PrepareToStartResidentApplet"}, + {0x003A0044, nullptr, "StartResidentApplet"}, + {0x003B0040, nullptr, "CancelLibraryApplet"}, + {0x003C0042, nullptr, "SendDspSleep"}, + {0x003D0042, nullptr, "SendDspWakeUp"}, + {0x003E0080, nullptr, "ReplySleepQuery"}, + {0x003F0040, nullptr, "ReplySleepNotificationComplete"}, + {0x00400042, nullptr, "SendCaptureBufferInfo"}, + {0x00410040, nullptr, "ReceiveCaptureBufferInfo"}, + {0x00420080, nullptr, "SleepSystem"}, + {0x00430040, NotifyToWait, "NotifyToWait"}, + {0x00440000, GetSharedFont, "GetSharedFont"}, + {0x00450040, nullptr, "GetWirelessRebootInfo"}, + {0x00460104, nullptr, "Wrap"}, + {0x00470104, nullptr, "Unwrap"}, + {0x00480100, nullptr, "GetProgramInfo"}, + {0x00490180, nullptr, "Reboot"}, + {0x004A0040, nullptr, "GetCaptureInfo"}, + {0x004B00C2, AppletUtility, "AppletUtility"}, + {0x004C0000, nullptr, "SetFatalErrDispMode"}, + {0x004D0080, nullptr, "GetAppletProgramInfo"}, + {0x004E0000, nullptr, "HardwareResetAsync"}, + {0x004F0080, SetAppCpuTimeLimit, "SetAppCpuTimeLimit"}, + {0x00500040, GetAppCpuTimeLimit, "GetAppCpuTimeLimit"}, +}; + +APT_U_Interface::APT_U_Interface() { + Register(FunctionTable); +} + +} // namespace APT +} // namespace Service diff --git a/src/core/hle/service/apt_u.h b/src/core/hle/service/apt/apt_u.h index aad918cfc..8c7fe0ccb 100644 --- a/src/core/hle/service/apt_u.h +++ b/src/core/hle/service/apt/apt_u.h @@ -6,10 +6,8 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace APT_U - -namespace APT_U { +namespace Service { +namespace APT { // Application and title launching service. These services handle signaling for home/power button as // well. Only one session for either APT service can be open at a time, normally processes close the @@ -18,13 +16,14 @@ namespace APT_U { // svcBreak when the command isn't accessible). See http://3dbrew.org/wiki/NS#APT_Services. /// Interface to "APT:U" service -class Interface : public Service::Interface { +class APT_U_Interface : public Service::Interface { public: - Interface(); + APT_U_Interface(); std::string GetPortName() const override { return "APT:U"; } }; -} // namespace +} // namespace APT +} // namespace Service
\ No newline at end of file diff --git a/src/core/hle/service/apt_a.cpp b/src/core/hle/service/apt_a.cpp deleted file mode 100644 index 1c1d92572..000000000 --- a/src/core/hle/service/apt_a.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/hle.h" -#include "core/hle/service/apt_a.h" - -namespace APT_U { - extern void Initialize(Service::Interface* self); - extern void GetLockHandle(Service::Interface* self); - extern void ReceiveParameter(Service::Interface* self); - extern void GlanceParameter(Service::Interface* self); - extern void GetSharedFont(Service::Interface* self); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace APT_A - -namespace APT_A { - -const Interface::FunctionInfo FunctionTable[] = { - {0x00010040, APT_U::GetLockHandle, "GetLockHandle?"}, - {0x00020080, APT_U::Initialize, "Initialize?"}, - {0x00030040, nullptr, "Enable?"}, - {0x00040040, nullptr, "Finalize?"}, - {0x00050040, nullptr, "GetAppletManInfo?"}, - {0x00060040, nullptr, "GetAppletInfo?"}, - {0x000D0080, APT_U::ReceiveParameter, "ReceiveParameter?"}, - {0x000E0080, APT_U::GlanceParameter, "GlanceParameter?"}, - {0x003B0040, nullptr, "CancelLibraryApplet?"}, - {0x00430040, nullptr, "NotifyToWait?"}, - {0x00440000, APT_U::GetSharedFont, "GetSharedFont?"}, - {0x004B00C2, nullptr, "AppletUtility?"}, - {0x00550040, nullptr, "WriteInputToNsState?"}, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/apt_s.cpp b/src/core/hle/service/apt_s.cpp deleted file mode 100644 index 686335428..000000000 --- a/src/core/hle/service/apt_s.cpp +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - - -#include "common/common.h" -#include "common/file_util.h" - -#include "core/hle/hle.h" -#include "core/hle/kernel/event.h" -#include "core/hle/kernel/mutex.h" -#include "core/hle/kernel/shared_memory.h" -#include "core/hle/kernel/thread.h" -#include "core/hle/service/apt_s.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace APT_S - -namespace APT_U { - extern void GetLockHandle(Service::Interface* self); - extern void Initialize(Service::Interface* self); - extern void Enable(Service::Interface* self); - extern void InquireNotification(Service::Interface* self); - extern void NotifyToWait(Service::Interface* self); - extern void GetSharedFont(Service::Interface* self); - extern void AppletUtility(Service::Interface* self); - extern void GlanceParameter(Service::Interface* self); - extern void ReceiveParameter(Service::Interface* self); -} - -namespace APT_S { - -const Interface::FunctionInfo FunctionTable[] = { - {0x00010040, APT_U::GetLockHandle, "GetLockHandle"}, - {0x00020080, APT_U::Initialize, "Initialize"}, - {0x00030040, APT_U::Enable, "Enable"}, - {0x00040040, nullptr, "Finalize"}, - {0x00050040, nullptr, "GetAppletManInfo"}, - {0x00060040, nullptr, "GetAppletInfo"}, - {0x00070000, nullptr, "GetLastSignaledAppletId"}, - {0x00080000, nullptr, "CountRegisteredApplet"}, - {0x00090040, nullptr, "IsRegistered"}, - {0x000A0040, nullptr, "GetAttribute"}, - {0x000B0040, APT_U::InquireNotification, "InquireNotification"}, - {0x000C0104, nullptr, "SendParameter"}, - {0x000D0080, APT_U::ReceiveParameter, "ReceiveParameter"}, - {0x000E0080, APT_U::GlanceParameter, "GlanceParameter"}, - {0x000F0100, nullptr, "CancelParameter"}, - {0x001000C2, nullptr, "DebugFunc"}, - {0x001100C0, nullptr, "MapProgramIdForDebug"}, - {0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"}, - {0x00130000, nullptr, "GetPreparationState"}, - {0x00140040, nullptr, "SetPreparationState"}, - {0x00150140, nullptr, "PrepareToStartApplication"}, - {0x00160040, nullptr, "PreloadLibraryApplet"}, - {0x00170040, nullptr, "FinishPreloadingLibraryApplet"}, - {0x00180040, nullptr, "PrepareToStartLibraryApplet"}, - {0x00190040, nullptr, "PrepareToStartSystemApplet"}, - {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"}, - {0x001B00C4, nullptr, "StartApplication"}, - {0x001C0000, nullptr, "WakeupApplication"}, - {0x001D0000, nullptr, "CancelApplication"}, - {0x001E0084, nullptr, "StartLibraryApplet"}, - {0x001F0084, nullptr, "StartSystemApplet"}, - {0x00200044, nullptr, "StartNewestHomeMenu"}, - {0x00210000, nullptr, "OrderToCloseApplication"}, - {0x00220040, nullptr, "PrepareToCloseApplication"}, - {0x00230040, nullptr, "PrepareToJumpToApplication"}, - {0x00240044, nullptr, "JumpToApplication"}, - {0x002500C0, nullptr, "PrepareToCloseLibraryApplet"}, - {0x00260000, nullptr, "PrepareToCloseSystemApplet"}, - {0x00270044, nullptr, "CloseApplication"}, - {0x00280044, nullptr, "CloseLibraryApplet"}, - {0x00290044, nullptr, "CloseSystemApplet"}, - {0x002A0000, nullptr, "OrderToCloseSystemApplet"}, - {0x002B0000, nullptr, "PrepareToJumpToHomeMenu"}, - {0x002C0044, nullptr, "JumpToHomeMenu"}, - {0x002D0000, nullptr, "PrepareToLeaveHomeMenu"}, - {0x002E0044, nullptr, "LeaveHomeMenu"}, - {0x002F0040, nullptr, "PrepareToLeaveResidentApplet"}, - {0x00300044, nullptr, "LeaveResidentApplet"}, - {0x00310100, nullptr, "PrepareToDoApplicationJump"}, - {0x00320084, nullptr, "DoApplicationJump"}, - {0x00330000, nullptr, "GetProgramIdOnApplicationJump"}, - {0x00340084, nullptr, "SendDeliverArg"}, - {0x00350080, nullptr, "ReceiveDeliverArg"}, - {0x00360040, nullptr, "LoadSysMenuArg"}, - {0x00370042, nullptr, "StoreSysMenuArg"}, - {0x00380040, nullptr, "PreloadResidentApplet"}, - {0x00390040, nullptr, "PrepareToStartResidentApplet"}, - {0x003A0044, nullptr, "StartResidentApplet"}, - {0x003B0040, nullptr, "CancelLibraryApplet"}, - {0x003C0042, nullptr, "SendDspSleep"}, - {0x003D0042, nullptr, "SendDspWakeUp"}, - {0x003E0080, nullptr, "ReplySleepQuery"}, - {0x003F0040, nullptr, "ReplySleepNotificationComplete"}, - {0x00400042, nullptr, "SendCaptureBufferInfo"}, - {0x00410040, nullptr, "ReceiveCaptureBufferInfo"}, - {0x00420080, nullptr, "SleepSystem"}, - {0x00430040, APT_U::NotifyToWait, "NotifyToWait"}, - {0x00440000, APT_U::GetSharedFont, "GetSharedFont"}, - {0x00450040, nullptr, "GetWirelessRebootInfo"}, - {0x00460104, nullptr, "Wrap"}, - {0x00470104, nullptr, "Unwrap"}, - {0x00480100, nullptr, "GetProgramInfo"}, - {0x00490180, nullptr, "Reboot"}, - {0x004A0040, nullptr, "GetCaptureInfo"}, - {0x004B00C2, APT_U::AppletUtility, "AppletUtility"}, - {0x004C0000, nullptr, "SetFatalErrDispMode"}, - {0x004D0080, nullptr, "GetAppletProgramInfo"}, - {0x004E0000, nullptr, "HardwareResetAsync"}, - {0x004F0080, nullptr, "SetApplicationCpuTimeLimit"}, - {0x00500040, nullptr, "GetApplicationCpuTimeLimit"}, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/apt_u.cpp b/src/core/hle/service/apt_u.cpp deleted file mode 100644 index 2d605a767..000000000 --- a/src/core/hle/service/apt_u.cpp +++ /dev/null @@ -1,526 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - - -#include "common/common.h" -#include "common/file_util.h" - -#include "core/hle/hle.h" -#include "core/hle/kernel/event.h" -#include "core/hle/kernel/mutex.h" -#include "core/hle/kernel/shared_memory.h" -#include "core/hle/kernel/thread.h" -#include "core/hle/service/apt_u.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace APT_U - -namespace APT_U { - -// Address used for shared font (as observed on HW) -// TODO(bunnei): This is the hard-coded address where we currently dump the shared font from via -// https://github.com/citra-emu/3dsutils. This is technically a hack, and will not work at any -// address other than 0x18000000 due to internal pointers in the shared font dump that would need to -// be relocated. This might be fixed by dumping the shared font @ address 0x00000000 and then -// correctly mapping it in Citra, however we still do not understand how the mapping is determined. -static const VAddr SHARED_FONT_VADDR = 0x18000000; - -/// Handle to shared memory region designated to for shared system font -static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; - -static Kernel::SharedPtr<Kernel::Mutex> lock; -static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event -static Kernel::SharedPtr<Kernel::Event> pause_event = 0; ///< APT pause event -static std::vector<u8> shared_font; - -/// Signals used by APT functions -enum class SignalType : u32 { - None = 0x0, - AppJustStarted = 0x1, - ReturningToApp = 0xB, - ExitingApp = 0xC, -}; - -/// App Id's used by APT functions -enum class AppID : u32 { - HomeMenu = 0x101, - AlternateMenu = 0x103, - Camera = 0x110, - FriendsList = 0x112, - GameNotes = 0x113, - InternetBrowser = 0x114, - InstructionManual = 0x115, - Notifications = 0x116, - Miiverse = 0x117, - SoftwareKeyboard1 = 0x201, - Ed = 0x202, - PnoteApp = 0x204, - SnoteApp = 0x205, - Error = 0x206, - Mint = 0x207, - Extrapad = 0x208, - Memolib = 0x209, - Application = 0x300, - SoftwareKeyboard2 = 0x401, -}; - -void Initialize(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - // TODO(bunnei): Check if these are created in Initialize or on APT process startup. - notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification"); - pause_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Pause"); - - cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom(); - cmd_buff[4] = Kernel::g_handle_table.Create(pause_event).MoveFrom(); - - // TODO(bunnei): Check if these events are cleared/signaled every time Initialize is called. - notification_event->Clear(); - pause_event->Signal(); // Fire start event - - ASSERT_MSG((nullptr != lock), "Cannot initialize without lock"); - lock->Release(); - - cmd_buff[1] = RESULT_SUCCESS.raw; // No error -} - -/** - * APT_U::NotifyToWait service function - * Inputs: - * 1 : AppID - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - */ -void NotifyToWait(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 app_id = cmd_buff[1]; - // TODO(Subv): Verify this, it seems to get SWKBD and Home Menu further. - pause_event->Signal(); - - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id); -} - -void GetLockHandle(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field - - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - - // Not sure what these parameters are used for, but retail apps check that they are 0 after - // GetLockHandle has been called. - cmd_buff[2] = 0; - cmd_buff[3] = 0; - cmd_buff[4] = 0; - - cmd_buff[5] = Kernel::g_handle_table.Create(lock).MoveFrom(); - LOG_TRACE(Service_APT, "called handle=0x%08X", cmd_buff[5]); -} - -void Enable(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for? - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); -} - -/** - * APT_U::GetAppletManInfo service function. - * Inputs: - * 1 : Unknown - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : Unknown u32 value - * 3 : Unknown u8 value - * 4 : Home Menu AppId - * 5 : AppID of currently active app - */ -void GetAppletManInfo(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 unk = cmd_buff[1]; - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - cmd_buff[2] = 0; - cmd_buff[3] = 0; - cmd_buff[4] = static_cast<u32>(AppID::HomeMenu); // Home menu AppID - cmd_buff[5] = static_cast<u32>(AppID::Application); // TODO(purpasmart96): Do this correctly - - LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); -} - -/** - * APT_U::IsRegistered service function. This returns whether the specified AppID is registered with NS yet. - * An AppID is "registered" once the process associated with the AppID uses APT:Enable. Home Menu uses this - * command to determine when the launched process is running and to determine when to stop using GSP etc, - * while displaying the "Nintendo 3DS" loading screen. - * Inputs: - * 1 : AppID - * Outputs: - * 0 : Return header - * 1 : Result of function, 0 on success, otherwise error code - * 2 : Output, 0 = not registered, 1 = registered. - */ -static void IsRegistered(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 app_id = cmd_buff[1]; - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - cmd_buff[2] = 1; // Set to registered - LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); -} - -void InquireNotification(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 app_id = cmd_buff[1]; - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - cmd_buff[2] = static_cast<u32>(SignalType::None); // Signal type - LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); -} - -/** - * APT_U::SendParameter service function. This sets the parameter data state. - * Inputs: - * 1 : Source AppID - * 2 : Destination AppID - * 3 : Signal type - * 4 : Parameter buffer size, max size is 0x1000 (this can be zero) - * 5 : Value - * 6 : Handle to the destination process, likely used for shared memory (this can be zero) - * 7 : (Size<<14) | 2 - * 8 : Input parameter buffer ptr - * Outputs: - * 0 : Return Header - * 1 : Result of function, 0 on success, otherwise error code -*/ -static void SendParameter(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 src_app_id = cmd_buff[1]; - u32 dst_app_id = cmd_buff[2]; - u32 signal_type = cmd_buff[3]; - u32 buffer_size = cmd_buff[4]; - u32 value = cmd_buff[5]; - u32 handle = cmd_buff[6]; - u32 size = cmd_buff[7]; - u32 in_param_buffer_ptr = cmd_buff[8]; - - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - - LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," - "buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X", - src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, in_param_buffer_ptr); -} - -/** - * APT_U::ReceiveParameter service function. This returns the current parameter data from NS state, - * from the source process which set the parameters. Once finished, NS will clear a flag in the NS - * state so that this command will return an error if this command is used again if parameters were - * not set again. This is called when the second Initialize event is triggered. It returns a signal - * type indicating why it was triggered. - * Inputs: - * 1 : AppID - * 2 : Parameter buffer size, max size is 0x1000 - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : AppID of the process which sent these parameters - * 3 : Signal type - * 4 : Actual parameter buffer size, this is <= to the the input size - * 5 : Value - * 6 : Handle from the source process which set the parameters, likely used for shared memory - * 7 : Size - * 8 : Output parameter buffer ptr - */ -void ReceiveParameter(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 app_id = cmd_buff[1]; - u32 buffer_size = cmd_buff[2]; - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - cmd_buff[2] = 0; - cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type - cmd_buff[4] = 0x10; // Parameter buffer size (16) - cmd_buff[5] = 0; - cmd_buff[6] = 0; - cmd_buff[7] = 0; - LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); -} - -/** - * APT_U::GlanceParameter service function. This is exactly the same as APT_U::ReceiveParameter - * (except for the word value prior to the output handle), except this will not clear the flag - * (except when responseword[3]==8 || responseword[3]==9) in NS state. - * Inputs: - * 1 : AppID - * 2 : Parameter buffer size, max size is 0x1000 - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : Unknown, for now assume AppID of the process which sent these parameters - * 3 : Unknown, for now assume Signal type - * 4 : Actual parameter buffer size, this is <= to the the input size - * 5 : Value - * 6 : Handle from the source process which set the parameters, likely used for shared memory - * 7 : Size - * 8 : Output parameter buffer ptr - */ -void GlanceParameter(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 app_id = cmd_buff[1]; - u32 buffer_size = cmd_buff[2]; - - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - cmd_buff[2] = 0; - cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type - cmd_buff[4] = 0x10; // Parameter buffer size (16) - cmd_buff[5] = 0; - cmd_buff[6] = 0; - cmd_buff[7] = 0; - - LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); -} - -/** - * APT_U::CancelParameter service function. When the parameter data is available, and when the above - * specified fields match the ones in NS state(for the ones where the checks are enabled), this - * clears the flag which indicates that parameter data is available - * (same flag cleared by APT:ReceiveParameter). - * Inputs: - * 1 : Flag, when non-zero NS will compare the word after this one with a field in the NS state. - * 2 : Unknown, this is the same as the first unknown field returned by APT:ReceiveParameter. - * 3 : Flag, when non-zero NS will compare the word after this one with a field in the NS state. - * 4 : AppID - * Outputs: - * 0 : Return header - * 1 : Result of function, 0 on success, otherwise error code - * 2 : Status flag, 0 = failure due to no parameter data being available, or the above enabled - * fields don't match the fields in NS state. 1 = success. - */ -static void CancelParameter(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 flag1 = cmd_buff[1]; - u32 unk = cmd_buff[2]; - u32 flag2 = cmd_buff[3]; - u32 app_id = cmd_buff[4]; - - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - cmd_buff[2] = 1; // Set to Success - - LOG_WARNING(Service_APT, "(STUBBED) called flag1=0x%08X, unk=0x%08X, flag2=0x%08X, app_id=0x%08X", - flag1, unk, flag2, app_id); -} - -/** - * APT_U::AppletUtility service function - * Inputs: - * 1 : Unknown, but clearly used for something - * 2 : Buffer 1 size (purpose is unknown) - * 3 : Buffer 2 size (purpose is unknown) - * 5 : Buffer 1 address (purpose is unknown) - * 65 : Buffer 2 address (purpose is unknown) - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - */ -void AppletUtility(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - // These are from 3dbrew - I'm not really sure what they're used for. - u32 unk = cmd_buff[1]; - u32 buffer1_size = cmd_buff[2]; - u32 buffer2_size = cmd_buff[3]; - u32 buffer1_addr = cmd_buff[5]; - u32 buffer2_addr = cmd_buff[65]; - - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - - LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08x, buffer2_size=0x%08x, " - "buffer1_addr=0x%08x, buffer2_addr=0x%08x", unk, buffer1_size, buffer2_size, - buffer1_addr, buffer2_addr); -} - -/** - * APT_U::GetSharedFont service function - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : Virtual address of where shared font will be loaded in memory - * 4 : Handle to shared font memory - */ -void GetSharedFont(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - if (!shared_font.empty()) { - // TODO(bunnei): This function shouldn't copy the shared font every time it's called. - // Instead, it should probably map the shared font as RO memory. We don't currently have - // an easy way to do this, but the copy should be sufficient for now. - memcpy(Memory::GetPointer(SHARED_FONT_VADDR), shared_font.data(), shared_font.size()); - - cmd_buff[0] = 0x00440082; - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - cmd_buff[2] = SHARED_FONT_VADDR; - cmd_buff[4] = Kernel::g_handle_table.Create(shared_font_mem).MoveFrom(); - } else { - cmd_buff[1] = -1; // Generic error (not really possible to verify this on hardware) - LOG_ERROR(Kernel_SVC, "called, but %s has not been loaded!", SHARED_FONT); - } -} - -/** - * APT_U::SetAppCpuTimeLimit service function - * Inputs: - * 1 : Value, must be one - * 2 : Percentage of CPU time from 5 to 80 - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - */ -static void SetAppCpuTimeLimit(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 value = cmd_buff[1]; - u32 percent = cmd_buff[2]; - - if (value != 1) { - LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value); - } - - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - - LOG_WARNING(Service_APT, "(STUBBED) called percent=0x%08X, value=0x%08x", percent, value); -} - -/** - * APT_U::GetAppCpuTimeLimit service function - * Inputs: - * 1 : Value, must be one - * Outputs: - * 0 : Return header - * 1 : Result of function, 0 on success, otherwise error code - * 2 : System core CPU time percentage - */ -static void GetAppCpuTimeLimit(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 value = cmd_buff[1]; - - if (value != 1) { - LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value); - } - - // TODO(purpasmart96): This is incorrect, I'm pretty sure the percentage should - // be set by the application. - - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - cmd_buff[2] = 0x80; // Set to 80% - - LOG_WARNING(Service_APT, "(STUBBED) called value=0x%08x", value); -} - -const Interface::FunctionInfo FunctionTable[] = { - {0x00010040, GetLockHandle, "GetLockHandle"}, - {0x00020080, Initialize, "Initialize"}, - {0x00030040, Enable, "Enable"}, - {0x00040040, nullptr, "Finalize"}, - {0x00050040, GetAppletManInfo, "GetAppletManInfo"}, - {0x00060040, nullptr, "GetAppletInfo"}, - {0x00070000, nullptr, "GetLastSignaledAppletId"}, - {0x00080000, nullptr, "CountRegisteredApplet"}, - {0x00090040, IsRegistered, "IsRegistered"}, - {0x000A0040, nullptr, "GetAttribute"}, - {0x000B0040, InquireNotification, "InquireNotification"}, - {0x000C0104, SendParameter, "SendParameter"}, - {0x000D0080, ReceiveParameter, "ReceiveParameter"}, - {0x000E0080, GlanceParameter, "GlanceParameter"}, - {0x000F0100, CancelParameter, "CancelParameter"}, - {0x001000C2, nullptr, "DebugFunc"}, - {0x001100C0, nullptr, "MapProgramIdForDebug"}, - {0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"}, - {0x00130000, nullptr, "GetPreparationState"}, - {0x00140040, nullptr, "SetPreparationState"}, - {0x00150140, nullptr, "PrepareToStartApplication"}, - {0x00160040, nullptr, "PreloadLibraryApplet"}, - {0x00170040, nullptr, "FinishPreloadingLibraryApplet"}, - {0x00180040, nullptr, "PrepareToStartLibraryApplet"}, - {0x00190040, nullptr, "PrepareToStartSystemApplet"}, - {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"}, - {0x001B00C4, nullptr, "StartApplication"}, - {0x001C0000, nullptr, "WakeupApplication"}, - {0x001D0000, nullptr, "CancelApplication"}, - {0x001E0084, nullptr, "StartLibraryApplet"}, - {0x001F0084, nullptr, "StartSystemApplet"}, - {0x00200044, nullptr, "StartNewestHomeMenu"}, - {0x00210000, nullptr, "OrderToCloseApplication"}, - {0x00220040, nullptr, "PrepareToCloseApplication"}, - {0x00230040, nullptr, "PrepareToJumpToApplication"}, - {0x00240044, nullptr, "JumpToApplication"}, - {0x002500C0, nullptr, "PrepareToCloseLibraryApplet"}, - {0x00260000, nullptr, "PrepareToCloseSystemApplet"}, - {0x00270044, nullptr, "CloseApplication"}, - {0x00280044, nullptr, "CloseLibraryApplet"}, - {0x00290044, nullptr, "CloseSystemApplet"}, - {0x002A0000, nullptr, "OrderToCloseSystemApplet"}, - {0x002B0000, nullptr, "PrepareToJumpToHomeMenu"}, - {0x002C0044, nullptr, "JumpToHomeMenu"}, - {0x002D0000, nullptr, "PrepareToLeaveHomeMenu"}, - {0x002E0044, nullptr, "LeaveHomeMenu"}, - {0x002F0040, nullptr, "PrepareToLeaveResidentApplet"}, - {0x00300044, nullptr, "LeaveResidentApplet"}, - {0x00310100, nullptr, "PrepareToDoApplicationJump"}, - {0x00320084, nullptr, "DoApplicationJump"}, - {0x00330000, nullptr, "GetProgramIdOnApplicationJump"}, - {0x00340084, nullptr, "SendDeliverArg"}, - {0x00350080, nullptr, "ReceiveDeliverArg"}, - {0x00360040, nullptr, "LoadSysMenuArg"}, - {0x00370042, nullptr, "StoreSysMenuArg"}, - {0x00380040, nullptr, "PreloadResidentApplet"}, - {0x00390040, nullptr, "PrepareToStartResidentApplet"}, - {0x003A0044, nullptr, "StartResidentApplet"}, - {0x003B0040, nullptr, "CancelLibraryApplet"}, - {0x003C0042, nullptr, "SendDspSleep"}, - {0x003D0042, nullptr, "SendDspWakeUp"}, - {0x003E0080, nullptr, "ReplySleepQuery"}, - {0x003F0040, nullptr, "ReplySleepNotificationComplete"}, - {0x00400042, nullptr, "SendCaptureBufferInfo"}, - {0x00410040, nullptr, "ReceiveCaptureBufferInfo"}, - {0x00420080, nullptr, "SleepSystem"}, - {0x00430040, NotifyToWait, "NotifyToWait"}, - {0x00440000, GetSharedFont, "GetSharedFont"}, - {0x00450040, nullptr, "GetWirelessRebootInfo"}, - {0x00460104, nullptr, "Wrap"}, - {0x00470104, nullptr, "Unwrap"}, - {0x00480100, nullptr, "GetProgramInfo"}, - {0x00490180, nullptr, "Reboot"}, - {0x004A0040, nullptr, "GetCaptureInfo"}, - {0x004B00C2, AppletUtility, "AppletUtility"}, - {0x004C0000, nullptr, "SetFatalErrDispMode"}, - {0x004D0080, nullptr, "GetAppletProgramInfo"}, - {0x004E0000, nullptr, "HardwareResetAsync"}, - {0x004F0080, SetAppCpuTimeLimit, "SetAppCpuTimeLimit"}, - {0x00500040, GetAppCpuTimeLimit, "GetAppCpuTimeLimit"}, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - // Load the shared system font (if available). - // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header - // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided - // a homebrew app to do this: https://github.com/citra-emu/3dsutils. Put the resulting file - // "shared_font.bin" in the Citra "sysdata" directory. - - shared_font.clear(); - std::string filepath = FileUtil::GetUserPath(D_SYSDATA_IDX) + SHARED_FONT; - - FileUtil::CreateFullPath(filepath); // Create path if not already created - FileUtil::IOFile file(filepath, "rb"); - - if (file.IsOpen()) { - // Read shared font data - shared_font.resize((size_t)file.GetSize()); - file.ReadBytes(shared_font.data(), (size_t)file.GetSize()); - - // Create shared font memory object - shared_font_mem = Kernel::SharedMemory::Create("APT_U:shared_font_mem"); - } else { - LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str()); - shared_font_mem = nullptr; - } - - lock = Kernel::Mutex::Create(false, "APT_U:Lock"); - - Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp index b7cdccb86..1eb2562d8 100644 --- a/src/core/hle/service/cfg/cfg.cpp +++ b/src/core/hle/service/cfg/cfg.cpp @@ -3,9 +3,13 @@ // Refer to the license.txt file included. #include <algorithm> -#include "common/make_unique.h" -#include "core/hle/service/cfg/cfg.h" + #include "core/hle/service/fs/archive.h" +#include "core/hle/service/service.h" +#include "core/hle/service/cfg/cfg.h" +#include "core/hle/service/cfg/cfg_i.h" +#include "core/hle/service/cfg/cfg_s.h" +#include "core/hle/service/cfg/cfg_u.h" namespace Service { namespace CFG { @@ -162,6 +166,10 @@ ResultCode FormatConfig() { } void CFGInit() { + AddService(new CFG_I_Interface); + AddService(new CFG_S_Interface); + AddService(new CFG_U_Interface); + // Open the SystemSaveData archive 0x00010017 FileSys::Path archive_path(cfg_system_savedata_id); auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); diff --git a/src/core/hle/service/cfg/cfg_i.cpp b/src/core/hle/service/cfg/cfg_i.cpp index 20b09a8cb..6d1eee4e0 100644 --- a/src/core/hle/service/cfg/cfg_i.cpp +++ b/src/core/hle/service/cfg/cfg_i.cpp @@ -6,10 +6,8 @@ #include "core/hle/service/cfg/cfg.h" #include "core/hle/service/cfg/cfg_i.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CFG_I - -namespace CFG_I { +namespace Service { +namespace CFG { /** * CFG_I::GetConfigInfoBlk8 service function @@ -99,11 +97,9 @@ const Interface::FunctionInfo FunctionTable[] = { {0x08180042, nullptr, "SecureInfoGetSerialNo"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +CFG_I_Interface::CFG_I_Interface() { Register(FunctionTable); } -} // namespace +} // namespace CFG +} // namespace Service
\ No newline at end of file diff --git a/src/core/hle/service/cfg/cfg_i.h b/src/core/hle/service/cfg/cfg_i.h index a498dd589..d0a2cce39 100644 --- a/src/core/hle/service/cfg/cfg_i.h +++ b/src/core/hle/service/cfg/cfg_i.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CFG_I +namespace Service { +namespace CFG { -namespace CFG_I { - -class Interface : public Service::Interface { +class CFG_I_Interface : public Service::Interface { public: - Interface(); + CFG_I_Interface(); std::string GetPortName() const override { return "cfg:i"; } }; -} // namespace +} // namespace CFG +} // namespace Service
\ No newline at end of file diff --git a/src/core/hle/service/cfg/cfg_s.cpp b/src/core/hle/service/cfg/cfg_s.cpp index d80aeae8d..d9a3e5d51 100644 --- a/src/core/hle/service/cfg/cfg_s.cpp +++ b/src/core/hle/service/cfg/cfg_s.cpp @@ -6,10 +6,8 @@ #include "core/hle/service/cfg/cfg.h" #include "core/hle/service/cfg/cfg_s.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CFG_S - -namespace CFG_S { +namespace Service { +namespace CFG { /** * CFG_S::GetConfigInfoBlk2 service function @@ -87,11 +85,9 @@ const Interface::FunctionInfo FunctionTable[] = { {0x04090000, nullptr, "UpdateConfigBlk00040003"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +CFG_S_Interface::CFG_S_Interface() { Register(FunctionTable); } -} // namespace +} // namespace CFG +} // namespace Service diff --git a/src/core/hle/service/cfg/cfg_s.h b/src/core/hle/service/cfg/cfg_s.h index d8b67137f..5568d6485 100644 --- a/src/core/hle/service/cfg/cfg_s.h +++ b/src/core/hle/service/cfg/cfg_s.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CFG_S +namespace Service { +namespace CFG { -namespace CFG_S { - -class Interface : public Service::Interface { +class CFG_S_Interface : public Service::Interface { public: - Interface(); + CFG_S_Interface(); std::string GetPortName() const override { return "cfg:s"; } }; -} // namespace +} // namespace CFG +} // namespace Service diff --git a/src/core/hle/service/cfg/cfg_u.cpp b/src/core/hle/service/cfg/cfg_u.cpp index a65da90c5..c8c1c5b17 100644 --- a/src/core/hle/service/cfg/cfg_u.cpp +++ b/src/core/hle/service/cfg/cfg_u.cpp @@ -10,10 +10,8 @@ #include "core/hle/service/cfg/cfg.h" #include "core/hle/service/cfg/cfg_u.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CFG_U - -namespace CFG_U { +namespace Service { +namespace CFG { // TODO(Link Mauve): use a constexpr once MSVC starts supporting it. #define C(code) ((code)[0] | ((code)[1] << 8)) @@ -241,11 +239,9 @@ const Interface::FunctionInfo FunctionTable[] = { {0x000A0040, GetCountryCodeID, "GetCountryCodeID"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +CFG_U_Interface::CFG_U_Interface() { Register(FunctionTable); } -} // namespace +} // namespace CFG +} // namespace Service diff --git a/src/core/hle/service/cfg/cfg_u.h b/src/core/hle/service/cfg/cfg_u.h index 9ad73f355..5303d8ac6 100644 --- a/src/core/hle/service/cfg/cfg_u.h +++ b/src/core/hle/service/cfg/cfg_u.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CFG_U +namespace Service { +namespace CFG { -namespace CFG_U { - -class Interface : public Service::Interface { +class CFG_U_Interface : public Service::Interface { public: - Interface(); + CFG_U_Interface(); std::string GetPortName() const override { return "cfg:u"; } }; -} // namespace +} // namespace CFG +} // namespace Service diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index c5020cb24..9da2e7aa2 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -20,7 +20,9 @@ #include "core/file_sys/archive_sdmc.h" #include "core/file_sys/archive_systemsavedata.h" #include "core/file_sys/directory_backend.h" +#include "core/hle/service/service.h" #include "core/hle/service/fs/archive.h" +#include "core/hle/service/fs/fs_user.h" #include "core/hle/result.h" // Specializes std::hash for ArchiveIdCode, so that we can use it in std::unordered_map. @@ -419,6 +421,8 @@ ResultCode CreateExtSaveData(u32 high, u32 low) { void ArchiveInit() { next_handle = 1; + AddService(new FS::Interface); + // TODO(Subv): Add the other archive types (see here for the known types: // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes). diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index 71ee4ff55..eb312496e 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -487,6 +487,15 @@ static void FormatThisUserSaveData(Service::Interface* self) { cmd_buff[1] = FormatArchive(ArchiveIdCode::SaveData).raw; } +/** + * FS_User::CreateExtSaveData service function + * Inputs: + * 0: 0x08510242 + * 1: High word of the saveid to create + * 2: Low word of the saveid to create + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ static void CreateExtSaveData(Service::Interface* self) { // TODO(Subv): Figure out the other parameters. u32* cmd_buff = Kernel::GetCommandBuffer(); @@ -496,7 +505,22 @@ static void CreateExtSaveData(Service::Interface* self) { cmd_buff[1] = CreateExtSaveData(save_high, save_low).raw; } -const FSUserInterface::FunctionInfo FunctionTable[] = { +/** + * FS_User::CardSlotIsInserted service function. + * Inputs: + * 0: 0x08210000 + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Whether there is a game card inserted into the slot or not. + */ +static void CardSlotIsInserted(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = 0; + LOG_WARNING(Service_FS, "(STUBBED) called"); +} + +const Interface::FunctionInfo FunctionTable[] = { {0x000100C6, nullptr, "Dummy1"}, {0x040100C4, nullptr, "Control"}, {0x08010002, Initialize, "Initialize"}, @@ -531,7 +555,7 @@ const FSUserInterface::FunctionInfo FunctionTable[] = { {0x081E0042, nullptr, "GetNandLog"}, {0x081F0000, nullptr, "ClearSdmcLog"}, {0x08200000, nullptr, "ClearNandLog"}, - {0x08210000, nullptr, "CardSlotIsInserted"}, + {0x08210000, CardSlotIsInserted, "CardSlotIsInserted"}, {0x08220000, nullptr, "CardSlotPowerOn"}, {0x08230000, nullptr, "CardSlotPowerOff"}, {0x08240000, nullptr, "CardSlotGetCardIFPowerStatus"}, @@ -590,7 +614,7 @@ const FSUserInterface::FunctionInfo FunctionTable[] = { //////////////////////////////////////////////////////////////////////////////////////////////////// // Interface class -FSUserInterface::FSUserInterface() { +Interface::Interface() { Register(FunctionTable); } diff --git a/src/core/hle/service/fs/fs_user.h b/src/core/hle/service/fs/fs_user.h index 2d896dd5f..bb6ab195e 100644 --- a/src/core/hle/service/fs/fs_user.h +++ b/src/core/hle/service/fs/fs_user.h @@ -6,16 +6,13 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace FS_User - namespace Service { namespace FS { /// Interface to "fs:USER" service -class FSUserInterface : public Service::Interface { +class Interface : public Service::Interface { public: - FSUserInterface(); + Interface(); std::string GetPortName() const override { return "fs:USER"; diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 7cb01729e..e0689be2e 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -2,7 +2,10 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "core/hle/service/service.h" #include "core/hle/service/hid/hid.h" +#include "core/hle/service/hid/hid_spvr.h" +#include "core/hle/service/hid/hid_user.h" #include "core/arm/arm_interface.h" #include "core/hle/kernel/event.h" @@ -35,6 +38,19 @@ static inline PadData* GetPadData() { return reinterpret_cast<PadData*>(g_shared_mem->GetPointer().ValueOr(nullptr)); } +// TODO(peachum): +// Add a method for setting analog input from joystick device for the circle Pad. +// +// This method should: +// * Be called after both PadButton<Press, Release>(). +// * Be called before PadUpdateComplete() +// * Set current PadEntry.circle_pad_<axis> using analog data +// * Set PadData.raw_circle_pad_data +// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_x >= 41 +// * Set PadData.current_state.circle_up = 1 if current PadEntry.circle_pad_y >= 41 +// * Set PadData.current_state.circle_left = 1 if current PadEntry.circle_pad_x <= -41 +// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41 + /** * Circle Pad from keys. * @@ -121,9 +137,25 @@ void PadUpdateComplete() { g_event_pad_or_touch_2->Signal(); } +void GetIPCHandles(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + cmd_buff[1] = 0; // No error + // TODO(yuriks): Return error from SendSyncRequest is this fails (part of IPC marshalling) + cmd_buff[3] = Kernel::g_handle_table.Create(Service::HID::g_shared_mem).MoveFrom(); + cmd_buff[4] = Kernel::g_handle_table.Create(Service::HID::g_event_pad_or_touch_1).MoveFrom(); + cmd_buff[5] = Kernel::g_handle_table.Create(Service::HID::g_event_pad_or_touch_2).MoveFrom(); + cmd_buff[6] = Kernel::g_handle_table.Create(Service::HID::g_event_accelerometer).MoveFrom(); + cmd_buff[7] = Kernel::g_handle_table.Create(Service::HID::g_event_gyroscope).MoveFrom(); + cmd_buff[8] = Kernel::g_handle_table.Create(Service::HID::g_event_debug_pad).MoveFrom(); +} + void HIDInit() { using namespace Kernel; + AddService(new HID_U_Interface); + AddService(new HID_SPVR_Interface); + g_shared_mem = SharedMemory::Create("HID:SharedMem"); // Create event handles diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index fc628f36a..9c6e86f77 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -7,6 +7,7 @@ #include <array> #include "core/hle/kernel/kernel.h" +#include "core/hle/service/service.h" #include "common/bit_field.h" namespace Kernel { @@ -123,6 +124,22 @@ const PadState PAD_CIRCLE_LEFT = {{1u << 29}}; const PadState PAD_CIRCLE_UP = {{1u << 30}}; const PadState PAD_CIRCLE_DOWN = {{1u << 31}}; +/** + * HID::GetIPCHandles service function + * Inputs: + * None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Unused + * 3 : Handle to HID_User shared memory + * 4 : Event signaled by HID_User + * 5 : Event signaled by HID_User + * 6 : Event signaled by HID_User + * 7 : Gyroscope event + * 8 : Event signaled by HID_User + */ +void GetIPCHandles(Interface* self); + // Methods for updating the HID module's state void PadButtonPress(const PadState& pad_state); void PadButtonRelease(const PadState& pad_state); diff --git a/src/core/hle/service/hid/hid_spvr.cpp b/src/core/hle/service/hid/hid_spvr.cpp index 8f06b224d..790dcabbf 100644 --- a/src/core/hle/service/hid/hid_spvr.cpp +++ b/src/core/hle/service/hid/hid_spvr.cpp @@ -3,19 +3,14 @@ // Refer to the license.txt file included. #include "core/hle/hle.h" +#include "core/hle/service/hid/hid.h" #include "core/hle/service/hid/hid_spvr.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace HID_SPVR - -namespace HID_User { - extern void GetIPCHandles(Service::Interface* self); -} - -namespace HID_SPVR { +namespace Service { +namespace HID { const Interface::FunctionInfo FunctionTable[] = { - {0x000A0000, HID_User::GetIPCHandles, "GetIPCHandles"}, + {0x000A0000, GetIPCHandles, "GetIPCHandles"}, {0x000B0000, nullptr, "StartAnalogStickCalibration"}, {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"}, {0x00110000, nullptr, "EnableAccelerometer"}, @@ -27,11 +22,9 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00170000, nullptr, "GetSoundVolume"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +HID_SPVR_Interface::HID_SPVR_Interface() { Register(FunctionTable); } -} // namespace +} // namespace HID +} // namespace Service diff --git a/src/core/hle/service/hid/hid_spvr.h b/src/core/hle/service/hid/hid_spvr.h index 53ddc8569..ba61583d2 100644 --- a/src/core/hle/service/hid/hid_spvr.h +++ b/src/core/hle/service/hid/hid_spvr.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace HID_SPVR +namespace Service { +namespace HID { -namespace HID_SPVR { - -class Interface : public Service::Interface { +class HID_SPVR_Interface : public Service::Interface { public: - Interface(); + HID_SPVR_Interface(); std::string GetPortName() const override { return "hid:SPVR"; } }; -} // namespace +} // namespace HID +} // namespace Service
\ No newline at end of file diff --git a/src/core/hle/service/hid/hid_user.cpp b/src/core/hle/service/hid/hid_user.cpp index 7f464705f..1d0accefe 100644 --- a/src/core/hle/service/hid/hid_user.cpp +++ b/src/core/hle/service/hid/hid_user.cpp @@ -6,54 +6,10 @@ #include "core/hle/kernel/event.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/service/hid/hid.h" -#include "hid_user.h" +#include "core/hle/service/hid/hid_user.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace HID_User - -namespace HID_User { - - -// TODO(peachum): -// Add a method for setting analog input from joystick device for the circle Pad. -// -// This method should: -// * Be called after both PadButton<Press, Release>(). -// * Be called before PadUpdateComplete() -// * Set current PadEntry.circle_pad_<axis> using analog data -// * Set PadData.raw_circle_pad_data -// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_x >= 41 -// * Set PadData.current_state.circle_up = 1 if current PadEntry.circle_pad_y >= 41 -// * Set PadData.current_state.circle_left = 1 if current PadEntry.circle_pad_x <= -41 -// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41 - - -/** - * HID_User::GetIPCHandles service function - * Inputs: - * None - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : Unused - * 3 : Handle to HID_User shared memory - * 4 : Event signaled by HID_User - * 5 : Event signaled by HID_User - * 6 : Event signaled by HID_User - * 7 : Gyroscope event - * 8 : Event signaled by HID_User - */ -void GetIPCHandles(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - cmd_buff[1] = 0; // No error - // TODO(yuriks): Return error from SendSyncRequest is this fails (part of IPC marshalling) - cmd_buff[3] = Kernel::g_handle_table.Create(Service::HID::g_shared_mem).MoveFrom(); - cmd_buff[4] = Kernel::g_handle_table.Create(Service::HID::g_event_pad_or_touch_1).MoveFrom(); - cmd_buff[5] = Kernel::g_handle_table.Create(Service::HID::g_event_pad_or_touch_2).MoveFrom(); - cmd_buff[6] = Kernel::g_handle_table.Create(Service::HID::g_event_accelerometer).MoveFrom(); - cmd_buff[7] = Kernel::g_handle_table.Create(Service::HID::g_event_gyroscope).MoveFrom(); - cmd_buff[8] = Kernel::g_handle_table.Create(Service::HID::g_event_debug_pad).MoveFrom(); -} +namespace Service { +namespace HID { const Interface::FunctionInfo FunctionTable[] = { {0x000A0000, GetIPCHandles, "GetIPCHandles"}, @@ -66,11 +22,9 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00170000, nullptr, "GetSoundVolume"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +HID_U_Interface::HID_U_Interface() { Register(FunctionTable); } -} // namespace +} // namespace HID +} // namespace Service diff --git a/src/core/hle/service/hid/hid_user.h b/src/core/hle/service/hid/hid_user.h index 1d9929e67..0eeec2c25 100644 --- a/src/core/hle/service/hid/hid_user.h +++ b/src/core/hle/service/hid/hid_user.h @@ -6,24 +6,23 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace HID_User - // This service is used for interfacing to physical user controls. // Uses include game pad controls, touchscreen, accelerometers, gyroscopes, and debug pad. -namespace HID_User { - +namespace Service { +namespace HID { + /** * HID service interface. */ -class Interface : public Service::Interface { +class HID_U_Interface : public Service::Interface { public: - Interface(); + HID_U_Interface(); std::string GetPortName() const override { return "hid:USER"; } }; -} // namespace +} // namespace HID +} // namespace Service
\ No newline at end of file diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp new file mode 100644 index 000000000..56c918d4f --- /dev/null +++ b/src/core/hle/service/ptm/ptm.cpp @@ -0,0 +1,76 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/service.h" +#include "core/hle/service/fs/archive.h" +#include "core/hle/service/ptm/ptm.h" +#include "core/hle/service/ptm/ptm_play.h" +#include "core/hle/service/ptm/ptm_sysm.h" +#include "core/hle/service/ptm/ptm_u.h" + +namespace Service { +namespace PTM { + +/// Values for the default gamecoin.dat file +static const GameCoin default_game_coin = { 0x4F00, 42, 0, 0, 0, 2014, 12, 29 }; + +/// Id of the SharedExtData archive used by the PTM process +static const std::vector<u8> ptm_shared_extdata_id = {0, 0, 0, 0, 0x0B, 0, 0, 0xF0, 0, 0, 0, 0}; + +static bool shell_open = true; + +static bool battery_is_charging = true; + +u32 GetAdapterState() { + // TODO(purpasmart96): This function is only a stub, + // it returns a valid result without implementing full functionality. + return battery_is_charging ? 1 : 0; +} + +u32 GetShellState() { + return shell_open ? 1 : 0; +} + +ChargeLevels GetBatteryLevel() { + // TODO(purpasmart96): This function is only a stub, + // it returns a valid result without implementing full functionality. + return ChargeLevels::CompletelyFull; // Set to a completely full battery +} + +void PTMInit() { + AddService(new PTM_Play_Interface); + AddService(new PTM_Sysm_Interface); + AddService(new PTM_U_Interface); + + // Open the SharedExtSaveData archive 0xF000000B and create the gamecoin.dat file if it doesn't exist + FileSys::Path archive_path(ptm_shared_extdata_id); + auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); + // If the archive didn't exist, create the files inside + if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) { + // Format the archive to create the directories + Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); + // Open it again to get a valid archive now that the folder exists + archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); + ASSERT_MSG(archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!"); + + FileSys::Path gamecoin_path("gamecoin.dat"); + FileSys::Mode open_mode = {}; + open_mode.write_flag = 1; + open_mode.create_flag = 1; + // Open the file and write the default gamecoin information + auto gamecoin_result = Service::FS::OpenFileFromArchive(*archive_result, gamecoin_path, open_mode); + if (gamecoin_result.Succeeded()) { + auto gamecoin = gamecoin_result.MoveFrom(); + gamecoin->backend->Write(0, sizeof(GameCoin), 1, reinterpret_cast<const u8*>(&default_game_coin)); + gamecoin->backend->Close(); + } + } +} + +void PTMShutdown() { + +} + +} // namespace PTM +} // namespace Service diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h new file mode 100644 index 000000000..f697aae4d --- /dev/null +++ b/src/core/hle/service/ptm/ptm.h @@ -0,0 +1,65 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> +#include "core/hle/result.h" + +namespace Service { +namespace PTM { + +/// Charge levels used by PTM functions +enum class ChargeLevels : u32 { + CriticalBattery = 1, + LowBattery = 2, + HalfFull = 3, + MostlyFull = 4, + CompletelyFull = 5, +}; + +/** + * Represents the gamecoin file structure in the SharedExtData archive + * More information in 3dbrew (http://www.3dbrew.org/wiki/Extdata#Shared_Extdata_0xf000000b_gamecoin.dat) + */ +struct GameCoin { + u32 magic; ///< Magic number: 0x4F00 + u16 total_coins; ///< Total Play Coins + u16 total_coins_on_date; ///< Total Play Coins obtained on the date stored below. + u32 step_count; ///< Total step count at the time a new Play Coin was obtained. + u32 last_step_count; ///< Step count for the day the last Play Coin was obtained + u16 year; + u8 month; + u8 day; +}; + +/** + * Returns whether the battery is charging or not. + * It is unknown if GetAdapterState is the same as GetBatteryChargeState, + * it is likely to just be a duplicate function of GetBatteryChargeState + * that controls another part of the HW. + * @returns 1 if the battery is charging, and 0 otherwise. + */ +u32 GetAdapterState(); + +/** + * Returns whether the 3DS's physical shell casing is open or closed + * @returns 1 if the shell is open, and 0 if otherwise + */ +u32 GetShellState(); + +/** + * Get the current battery's charge level. + * @returns The battery's charge level. + */ +ChargeLevels GetBatteryLevel(); + +/// Initialize the PTM service +void PTMInit(); + +/// Shutdown the PTM service +void PTMShutdown(); + +} // namespace PTM +} // namespace Service diff --git a/src/core/hle/service/ptm_play.cpp b/src/core/hle/service/ptm/ptm_play.cpp index f21d9088e..8e8ae8558 100644 --- a/src/core/hle/service/ptm_play.cpp +++ b/src/core/hle/service/ptm/ptm_play.cpp @@ -3,12 +3,10 @@ // Refer to the license.txt file included. #include "core/hle/hle.h" -#include "core/hle/service/ptm_play.h" +#include "core/hle/service/ptm/ptm_play.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace PTM_PLAY - -namespace PTM_PLAY { +namespace Service { +namespace PTM { const Interface::FunctionInfo FunctionTable[] = { { 0x08070082, nullptr, "GetPlayHistory" }, @@ -17,11 +15,9 @@ const Interface::FunctionInfo FunctionTable[] = { { 0x080B0080, nullptr, "CalcPlayHistoryStart" }, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +PTM_Play_Interface::PTM_Play_Interface() { Register(FunctionTable); } -} // namespace +} // namespace PTM +} // namespace Service
\ No newline at end of file diff --git a/src/core/hle/service/ptm_play.h b/src/core/hle/service/ptm/ptm_play.h index 2f4f0d6fd..e5c3e04df 100644 --- a/src/core/hle/service/ptm_play.h +++ b/src/core/hle/service/ptm/ptm_play.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace PTM_PLAY +namespace Service { +namespace PTM { -namespace PTM_PLAY { - -class Interface : public Service::Interface { +class PTM_Play_Interface : public Service::Interface { public: - Interface(); + PTM_Play_Interface(); std::string GetPortName() const override { return "ptm:play"; } }; -} // namespace +} // namespace PTM +} // namespace Service diff --git a/src/core/hle/service/ptm_sysm.cpp b/src/core/hle/service/ptm/ptm_sysm.cpp index 96ef2dce0..2d841f69c 100644 --- a/src/core/hle/service/ptm_sysm.cpp +++ b/src/core/hle/service/ptm/ptm_sysm.cpp @@ -5,12 +5,22 @@ #include "common/make_unique.h" #include "core/file_sys/archive_extsavedata.h" #include "core/hle/hle.h" -#include "core/hle/service/ptm_sysm.h" +#include "core/hle/service/ptm/ptm_sysm.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace PTM_SYSM +namespace Service { +namespace PTM { -namespace PTM_SYSM { +/** + * Returns whether the system is powering off (?) + * Outputs: + * 1: Result code, 0 on success, otherwise error code + * 2: Whether the system is going through a power off + */ +void IsLegacyPowerOff(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = 0; +} const Interface::FunctionInfo FunctionTable[] = { {0x040100C0, nullptr, "SetRtcAlarmEx"}, @@ -37,7 +47,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x080C0080, nullptr, "SetUserTime"}, {0x080D0000, nullptr, "InvalidateSystemTime"}, {0x080E0140, nullptr, "NotifyPlayEvent"}, - {0x080F0000, nullptr, "IsLegacyPowerOff"}, + {0x080F0000, IsLegacyPowerOff, "IsLegacyPowerOff"}, {0x08100000, nullptr, "ClearLegacyPowerOff"}, {0x08110000, nullptr, "GetShellStatus"}, {0x08120000, nullptr, "IsShutdownByBatteryEmpty"}, @@ -45,11 +55,9 @@ const Interface::FunctionInfo FunctionTable[] = { {0x08140000, nullptr, "GetLegacyJumpProhibitedFlag"} }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +PTM_Sysm_Interface::PTM_Sysm_Interface() { Register(FunctionTable); } -} // namespace +} // namespace PTM +} // namespace Service diff --git a/src/core/hle/service/ptm_sysm.h b/src/core/hle/service/ptm/ptm_sysm.h index 0f267b214..e37f20546 100644 --- a/src/core/hle/service/ptm_sysm.h +++ b/src/core/hle/service/ptm/ptm_sysm.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace PTM_SYSM +namespace Service { +namespace PTM { -namespace PTM_SYSM { - -class Interface : public Service::Interface { +class PTM_Sysm_Interface : public Interface { public: - Interface(); + PTM_Sysm_Interface(); std::string GetPortName() const override { return "ptm:sysm"; } }; -} // namespace +} // namespace PTM +} // namespace Service diff --git a/src/core/hle/service/ptm/ptm_u.cpp b/src/core/hle/service/ptm/ptm_u.cpp new file mode 100644 index 000000000..0af7c8bf6 --- /dev/null +++ b/src/core/hle/service/ptm/ptm_u.cpp @@ -0,0 +1,99 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/make_unique.h" + +#include "core/hle/hle.h" +#include "core/hle/service/ptm/ptm.h" +#include "core/hle/service/ptm/ptm_u.h" + +namespace Service { +namespace PTM { + +/** + * PTM_U::GetAdapterState service function + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Output of function, 0 = not charging, 1 = charging. + */ +static void GetAdapterState(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = GetAdapterState(); + + LOG_WARNING(Service_PTM, "(STUBBED) called"); +} + +/* + * PTM_User::GetShellState service function. + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Whether the 3DS's physical shell casing is open (1) or closed (0) + */ +static void GetShellState(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = GetShellState(); +} + +/** + * PTM_U::GetBatteryLevel service function + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Battery level, 5 = completely full battery, 4 = mostly full battery, + * 3 = half full battery, 2 = low battery, 1 = critical battery. + */ +static void GetBatteryLevel(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = static_cast<u32>(GetBatteryLevel()); + + LOG_WARNING(Service_PTM, "(STUBBED) called"); +} + +/** + * PTM_U::GetBatteryChargeState service function + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Output of function, 0 = not charging, 1 = charging. + */ +static void GetBatteryChargeState(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + // TODO(purpasmart96): This function is only a stub, + // it returns a valid result without implementing full functionality. + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = GetAdapterState(); + + LOG_WARNING(Service_PTM, "(STUBBED) called"); +} + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010002, nullptr, "RegisterAlarmClient"}, + {0x00020080, nullptr, "SetRtcAlarm"}, + {0x00030000, nullptr, "GetRtcAlarm"}, + {0x00040000, nullptr, "CancelRtcAlarm"}, + {0x00050000, GetAdapterState, "GetAdapterState"}, + {0x00060000, GetShellState, "GetShellState"}, + {0x00070000, GetBatteryLevel, "GetBatteryLevel"}, + {0x00080000, GetBatteryChargeState, "GetBatteryChargeState"}, + {0x00090000, nullptr, "GetPedometerState"}, + {0x000A0042, nullptr, "GetStepHistoryEntry"}, + {0x000B00C2, nullptr, "GetStepHistory"}, + {0x000C0000, nullptr, "GetTotalStepCount"}, + {0x000D0040, nullptr, "SetPedometerRecordingMode"}, + {0x000E0000, nullptr, "GetPedometerRecordingMode"}, + {0x000F0084, nullptr, "GetStepHistoryAll"}, +}; + +PTM_U_Interface::PTM_U_Interface() { + Register(FunctionTable); +} + +} // namespace PTM +} // namespace Service diff --git a/src/core/hle/service/ptm_u.h b/src/core/hle/service/ptm/ptm_u.h index a44624fd5..bf132f610 100644 --- a/src/core/hle/service/ptm_u.h +++ b/src/core/hle/service/ptm/ptm_u.h @@ -6,20 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace PTM_U +namespace Service { +namespace PTM { -// ptm service - -namespace PTM_U { - -class Interface : public Service::Interface { +class PTM_U_Interface : public Interface { public: - Interface(); + PTM_U_Interface(); std::string GetPortName() const override { return "ptm:u"; } }; -} // namespace +} // namespace PTM +} // namespace Service
\ No newline at end of file diff --git a/src/core/hle/service/ptm_u.cpp b/src/core/hle/service/ptm_u.cpp deleted file mode 100644 index 7121d837c..000000000 --- a/src/core/hle/service/ptm_u.cpp +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/make_unique.h" - -#include "core/hle/hle.h" -#include "core/hle/service/fs/archive.h" -#include "core/hle/service/ptm_u.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace PTM_U - -namespace PTM_U { - -/** - * Represents the gamecoin file structure in the SharedExtData archive - * More information in 3dbrew (http://www.3dbrew.org/wiki/Extdata#Shared_Extdata_0xf000000b_gamecoin.dat) - */ -struct GameCoin { - u32 magic; ///< Magic number: 0x4F00 - u16 total_coins; ///< Total Play Coins - u16 total_coins_on_date; ///< Total Play Coins obtained on the date stored below. - u32 step_count; ///< Total step count at the time a new Play Coin was obtained. - u32 last_step_count; ///< Step count for the day the last Play Coin was obtained - u16 year; - u8 month; - u8 day; -}; -static const GameCoin default_game_coin = { 0x4F00, 42, 0, 0, 0, 2014, 12, 29 }; -static const std::vector<u8> ptm_shared_extdata_id = {0, 0, 0, 0, 0x0B, 0, 0, 0xF0, 0, 0, 0, 0}; - -/// Charge levels used by PTM functions -enum class ChargeLevels : u32 { - CriticalBattery = 1, - LowBattery = 2, - HalfFull = 3, - MostlyFull = 4, - CompletelyFull = 5, -}; - -static bool shell_open = true; - -static bool battery_is_charging = true; - -/** - * It is unknown if GetAdapterState is the same as GetBatteryChargeState, - * it is likely to just be a duplicate function of GetBatteryChargeState - * that controls another part of the HW. - * PTM_U::GetAdapterState service function - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : Output of function, 0 = not charging, 1 = charging. - */ -static void GetAdapterState(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - // TODO(purpasmart96): This function is only a stub, - // it returns a valid result without implementing full functionality. - - cmd_buff[1] = 0; // No error - cmd_buff[2] = battery_is_charging ? 1 : 0; - - LOG_WARNING(Service_PTM, "(STUBBED) called"); -} - -/* - * PTM_User::GetShellState service function. - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : Whether the 3DS's physical shell casing is open (1) or closed (0) - */ -static void GetShellState(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - cmd_buff[1] = 0; - cmd_buff[2] = shell_open ? 1 : 0; -} - -/** - * PTM_U::GetBatteryLevel service function - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : Battery level, 5 = completely full battery, 4 = mostly full battery, - * 3 = half full battery, 2 = low battery, 1 = critical battery. - */ -static void GetBatteryLevel(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - // TODO(purpasmart96): This function is only a stub, - // it returns a valid result without implementing full functionality. - - cmd_buff[1] = 0; // No error - cmd_buff[2] = static_cast<u32>(ChargeLevels::CompletelyFull); // Set to a completely full battery - - LOG_WARNING(Service_PTM, "(STUBBED) called"); -} - -/** - * PTM_U::GetBatteryChargeState service function - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : Output of function, 0 = not charging, 1 = charging. - */ -static void GetBatteryChargeState(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - // TODO(purpasmart96): This function is only a stub, - // it returns a valid result without implementing full functionality. - - cmd_buff[1] = 0; // No error - cmd_buff[2] = battery_is_charging ? 1 : 0; - - LOG_WARNING(Service_PTM, "(STUBBED) called"); -} - -const Interface::FunctionInfo FunctionTable[] = { - {0x00010002, nullptr, "RegisterAlarmClient"}, - {0x00020080, nullptr, "SetRtcAlarm"}, - {0x00030000, nullptr, "GetRtcAlarm"}, - {0x00040000, nullptr, "CancelRtcAlarm"}, - {0x00050000, GetAdapterState, "GetAdapterState"}, - {0x00060000, GetShellState, "GetShellState"}, - {0x00070000, GetBatteryLevel, "GetBatteryLevel"}, - {0x00080000, GetBatteryChargeState, "GetBatteryChargeState"}, - {0x00090000, nullptr, "GetPedometerState"}, - {0x000A0042, nullptr, "GetStepHistoryEntry"}, - {0x000B00C2, nullptr, "GetStepHistory"}, - {0x000C0000, nullptr, "GetTotalStepCount"}, - {0x000D0040, nullptr, "SetPedometerRecordingMode"}, - {0x000E0000, nullptr, "GetPedometerRecordingMode"}, - {0x000F0084, nullptr, "GetStepHistoryAll"}, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - Register(FunctionTable); - - // Open the SharedExtSaveData archive 0xF000000B and the gamecoin.dat file - FileSys::Path archive_path(ptm_shared_extdata_id); - auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); - // If the archive didn't exist, create the files inside - if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) { - // Format the archive to create the directories - Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); - // Open it again to get a valid archive now that the folder exists - archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); - ASSERT_MSG(archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!"); - - FileSys::Path gamecoin_path("gamecoin.dat"); - FileSys::Mode open_mode = {}; - open_mode.write_flag = 1; - open_mode.create_flag = 1; - // Open the file and write the default gamecoin information - auto gamecoin_result = Service::FS::OpenFileFromArchive(*archive_result, gamecoin_path, open_mode); - if (gamecoin_result.Succeeded()) { - auto gamecoin = gamecoin_result.MoveFrom(); - gamecoin->backend->Write(0, sizeof(GameCoin), 1, reinterpret_cast<const u8*>(&default_game_coin)); - gamecoin->backend->Close(); - } - } -} - -} // namespace diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 5dce8068e..91f13cd7e 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -11,26 +11,17 @@ #include "core/hle/service/am_app.h" #include "core/hle/service/am_net.h" #include "core/hle/service/am_sys.h" -#include "core/hle/service/apt_a.h" -#include "core/hle/service/apt_s.h" -#include "core/hle/service/apt_u.h" #include "core/hle/service/boss_p.h" #include "core/hle/service/boss_u.h" #include "core/hle/service/cam_u.h" #include "core/hle/service/cecd_u.h" #include "core/hle/service/cecd_s.h" -#include "core/hle/service/cfg/cfg_i.h" -#include "core/hle/service/cfg/cfg_s.h" -#include "core/hle/service/cfg/cfg_u.h" #include "core/hle/service/csnd_snd.h" #include "core/hle/service/dsp_dsp.h" #include "core/hle/service/err_f.h" -#include "core/hle/service/fs/fs_user.h" #include "core/hle/service/frd_a.h" #include "core/hle/service/frd_u.h" #include "core/hle/service/gsp_gpu.h" -#include "core/hle/service/hid/hid_spvr.h" -#include "core/hle/service/hid/hid_user.h" #include "core/hle/service/gsp_lcd.h" #include "core/hle/service/http_c.h" #include "core/hle/service/ir_rst.h" @@ -44,14 +35,17 @@ #include "core/hle/service/ns_s.h" #include "core/hle/service/nwm_uds.h" #include "core/hle/service/pm_app.h" -#include "core/hle/service/ptm_play.h" -#include "core/hle/service/ptm_u.h" -#include "core/hle/service/ptm_sysm.h" #include "core/hle/service/soc_u.h" #include "core/hle/service/srv.h" #include "core/hle/service/ssl_c.h" #include "core/hle/service/y2r_u.h" +#include "core/hle/service/apt/apt.h" +#include "core/hle/service/fs/archive.h" +#include "core/hle/service/cfg/cfg.h" +#include "core/hle/service/hid/hid.h" +#include "core/hle/service/ptm/ptm.h" + namespace Service { std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_ports; @@ -60,12 +54,12 @@ std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services; //////////////////////////////////////////////////////////////////////////////////////////////////// // Module interface -static void AddNamedPort(Interface* interface) { - g_kernel_named_ports.emplace(interface->GetPortName(), interface); +static void AddNamedPort(Interface* interface_) { + g_kernel_named_ports.emplace(interface_->GetPortName(), interface_); } -static void AddService(Interface* interface) { - g_srv_services.emplace(interface->GetPortName(), interface); +void AddService(Interface* interface_) { + g_srv_services.emplace(interface_->GetPortName(), interface_); } /// Initialize ServiceManager @@ -73,31 +67,28 @@ void Init() { AddNamedPort(new SRV::Interface); AddNamedPort(new ERR_F::Interface); + Service::FS::ArchiveInit(); + Service::CFG::CFGInit(); + Service::APT::APTInit(); + Service::PTM::PTMInit(); + Service::HID::HIDInit(); + AddService(new AC_U::Interface); AddService(new ACT_U::Interface); AddService(new AM_APP::Interface); AddService(new AM_NET::Interface); AddService(new AM_SYS::Interface); - AddService(new APT_A::Interface); - AddService(new APT_S::Interface); - AddService(new APT_U::Interface); AddService(new BOSS_P::Interface); AddService(new BOSS_U::Interface); AddService(new CAM_U::Interface); AddService(new CECD_S::Interface); AddService(new CECD_U::Interface); - AddService(new CFG_I::Interface); - AddService(new CFG_S::Interface); - AddService(new CFG_U::Interface); AddService(new CSND_SND::Interface); AddService(new DSP_DSP::Interface); AddService(new FRD_A::Interface); AddService(new FRD_U::Interface); - AddService(new FS::FSUserInterface); AddService(new GSP_GPU::Interface); AddService(new GSP_LCD::Interface); - AddService(new HID_User::Interface); - AddService(new HID_SPVR::Interface); AddService(new HTTP_C::Interface); AddService(new IR_RST::Interface); AddService(new IR_U::Interface); @@ -110,9 +101,6 @@ void Init() { AddService(new NS_S::Interface); AddService(new NWM_UDS::Interface); AddService(new PM_APP::Interface); - AddService(new PTM_PLAY::Interface); - AddService(new PTM_U::Interface); - AddService(new PTM_SYSM::Interface); AddService(new SOC_U::Interface); AddService(new SSL_C::Interface); AddService(new Y2R_U::Interface); @@ -122,6 +110,12 @@ void Init() { /// Shutdown ServiceManager void Shutdown() { + Service::HID::HIDShutdown(); + Service::PTM::PTMShutdown(); + Service::APT::APTShutdown(); + Service::CFG::CFGShutdown(); + Service::FS::ArchiveShutdown(); + g_srv_services.clear(); g_kernel_named_ports.clear(); LOG_DEBUG(Service, "shutdown OK"); diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 3370f9f9b..bfe16ebad 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -120,4 +120,7 @@ extern std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_na /// Map of services registered with the "srv:" service, retrieved using GetServiceHandle. extern std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services; +/// Adds a service to the services table +void AddService(Interface* interface_); + } // namespace diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index 2f1a69d90..424ce2ca7 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp @@ -113,8 +113,8 @@ inline void Write(u32 addr, const T data) { { const auto& config = g_regs.display_transfer_config; if (config.trigger & 1) { - u8* source_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalInputAddress())); - u8* dest_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalOutputAddress())); + u8* src_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalInputAddress())); + u8* dst_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalOutputAddress())); unsigned horizontal_scale = (config.scale_horizontally != 0) ? 2 : 1; unsigned vertical_scale = (config.scale_vertically != 0) ? 2 : 1; @@ -125,7 +125,7 @@ inline void Write(u32 addr, const T data) { if (config.raw_copy) { // Raw copies do not perform color conversion nor tiled->linear / linear->tiled conversions // TODO(Subv): Verify if raw copies perform scaling - memcpy(dest_pointer, source_pointer, config.output_width * config.output_height * + memcpy(dst_pointer, src_pointer, config.output_width * config.output_height * GPU::Regs::BytesPerPixel(config.output_format)); LOG_TRACE(HW_GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), flags 0x%08X, Raw copy", @@ -142,9 +142,7 @@ inline void Write(u32 addr, const T data) { // right now we're just skipping the extra pixels. for (u32 y = 0; y < output_height; ++y) { for (u32 x = 0; x < output_width; ++x) { - struct { - int r, g, b, a; - } source_color = { 0, 0, 0, 0 }; + Math::Vec4<u8> src_color = { 0, 0, 0, 0 }; u32 scaled_x = x * horizontal_scale; u32 scaled_y = y * vertical_scale; @@ -170,77 +168,54 @@ inline void Write(u32 addr, const T data) { dst_offset = (x + y * output_width) * dst_bytes_per_pixel; } + const u8* src_pixel = src_pointer + src_offset; switch (config.input_format) { case Regs::PixelFormat::RGBA8: - { - u8* srcptr = source_pointer + src_offset; - source_color.r = srcptr[3]; // red - source_color.g = srcptr[2]; // green - source_color.b = srcptr[1]; // blue - source_color.a = srcptr[0]; // alpha + src_color = Color::DecodeRGBA8(src_pixel); + break; + + case Regs::PixelFormat::RGB8: + src_color = Color::DecodeRGB8(src_pixel); + break; + + case Regs::PixelFormat::RGB565: + src_color = Color::DecodeRGB565(src_pixel); break; - } case Regs::PixelFormat::RGB5A1: - { - u16 srcval = *(u16*)(source_pointer + src_offset); - source_color.r = Color::Convert5To8((srcval >> 11) & 0x1F); // red - source_color.g = Color::Convert5To8((srcval >> 6) & 0x1F); // green - source_color.b = Color::Convert5To8((srcval >> 1) & 0x1F); // blue - source_color.a = Color::Convert1To8(srcval & 0x1); // alpha + src_color = Color::DecodeRGB5A1(src_pixel); break; - } case Regs::PixelFormat::RGBA4: - { - u16 srcval = *(u16*)(source_pointer + src_offset); - source_color.r = Color::Convert4To8((srcval >> 12) & 0xF); // red - source_color.g = Color::Convert4To8((srcval >> 8) & 0xF); // green - source_color.b = Color::Convert4To8((srcval >> 4) & 0xF); // blue - source_color.a = Color::Convert4To8( srcval & 0xF); // alpha + src_color = Color::DecodeRGBA4(src_pixel); break; - } default: LOG_ERROR(HW_GPU, "Unknown source framebuffer format %x", config.input_format.Value()); break; } + u8* dst_pixel = dst_pointer + dst_offset; switch (config.output_format) { case Regs::PixelFormat::RGBA8: - { - u8* dstptr = dest_pointer + dst_offset; - dstptr[3] = source_color.r; - dstptr[2] = source_color.g; - dstptr[1] = source_color.b; - dstptr[0] = source_color.a; + Color::EncodeRGBA8(src_color, dst_pixel); break; - } case Regs::PixelFormat::RGB8: - { - u8* dstptr = dest_pointer + dst_offset; - dstptr[2] = source_color.r; // red - dstptr[1] = source_color.g; // green - dstptr[0] = source_color.b; // blue + Color::EncodeRGB8(src_color, dst_pixel); + break; + + case Regs::PixelFormat::RGB565: + Color::EncodeRGB565(src_color, dst_pixel); break; - } case Regs::PixelFormat::RGB5A1: - { - u16* dstptr = (u16*)(dest_pointer + dst_offset); - *dstptr = ((source_color.r >> 3) << 11) | ((source_color.g >> 3) << 6) - | ((source_color.b >> 3) << 1) | ( source_color.a >> 7); + Color::EncodeRGB5A1(src_color, dst_pixel); break; - } case Regs::PixelFormat::RGBA4: - { - u16* dstptr = (u16*)(dest_pointer + dst_offset); - *dstptr = ((source_color.r >> 4) << 12) | ((source_color.g >> 4) << 8) - | ((source_color.b >> 4) << 4) | ( source_color.a >> 4); + Color::EncodeRGBA4(src_color, dst_pixel); break; - } default: LOG_ERROR(HW_GPU, "Unknown destination framebuffer format %x", config.output_format.Value()); diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 13c3f7b22..4c1e6449a 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -19,6 +19,7 @@ set(HEADERS renderer_opengl/gl_shaders.h renderer_opengl/renderer_opengl.h clipper.h + color.h command_processor.h gpu_debugger.h math.h diff --git a/src/video_core/color.h b/src/video_core/color.h index f095d8ac5..35da901f2 100644 --- a/src/video_core/color.h +++ b/src/video_core/color.h @@ -5,47 +5,152 @@ #pragma once #include "common/common_types.h" +#include "video_core/math.h" namespace Color { /// Convert a 1-bit color component to 8 bit -static inline u8 Convert1To8(u8 value) { +inline u8 Convert1To8(u8 value) { return value * 255; } /// Convert a 4-bit color component to 8 bit -static inline u8 Convert4To8(u8 value) { +inline u8 Convert4To8(u8 value) { return (value << 4) | value; } /// Convert a 5-bit color component to 8 bit -static inline u8 Convert5To8(u8 value) { +inline u8 Convert5To8(u8 value) { return (value << 3) | (value >> 2); } /// Convert a 6-bit color component to 8 bit -static inline u8 Convert6To8(u8 value) { +inline u8 Convert6To8(u8 value) { return (value << 2) | (value >> 4); } /// Convert a 8-bit color component to 1 bit -static inline u8 Convert8To1(u8 value) { +inline u8 Convert8To1(u8 value) { return value >> 7; } /// Convert a 8-bit color component to 4 bit -static inline u8 Convert8To4(u8 value) { +inline u8 Convert8To4(u8 value) { return value >> 4; } /// Convert a 8-bit color component to 5 bit -static inline u8 Convert8To5(u8 value) { +inline u8 Convert8To5(u8 value) { return value >> 3; } /// Convert a 8-bit color component to 6 bit -static inline u8 Convert8To6(u8 value) { +inline u8 Convert8To6(u8 value) { return value >> 2; } +/** + * Decode a color stored in RGBA8 format + * @param bytes Pointer to encoded source color + * @return Result color decoded as Math::Vec4<u8> + */ +inline const Math::Vec4<u8> DecodeRGBA8(const u8* bytes) { + return { bytes[3], bytes[2], bytes[1], bytes[0] }; +} + +/** + * Decode a color stored in RGB8 format + * @param bytes Pointer to encoded source color + * @return Result color decoded as Math::Vec4<u8> + */ +inline const Math::Vec4<u8> DecodeRGB8(const u8* bytes) { + return { bytes[2], bytes[1], bytes[0], 255 }; +} + +/** + * Decode a color stored in RGB565 format + * @param bytes Pointer to encoded source color + * @return Result color decoded as Math::Vec4<u8> + */ +inline const Math::Vec4<u8> DecodeRGB565(const u8* bytes) { + const u16_le pixel = *reinterpret_cast<const u16_le*>(bytes); + return { Convert5To8((pixel >> 11) & 0x1F), Convert6To8((pixel >> 5) & 0x3F), + Convert5To8(pixel & 0x1F), 255 }; +} + +/** + * Decode a color stored in RGB5A1 format + * @param bytes Pointer to encoded source color + * @return Result color decoded as Math::Vec4<u8> + */ +inline const Math::Vec4<u8> DecodeRGB5A1(const u8* bytes) { + const u16_le pixel = *reinterpret_cast<const u16_le*>(bytes); + return { Convert5To8((pixel >> 11) & 0x1F), Convert5To8((pixel >> 6) & 0x1F), + Convert5To8((pixel >> 1) & 0x1F), Convert1To8(pixel & 0x1) }; +} + +/** + * Decode a color stored in RGBA4 format + * @param bytes Pointer to encoded source color + * @return Result color decoded as Math::Vec4<u8> + */ +inline const Math::Vec4<u8> DecodeRGBA4(const u8* bytes) { + const u16_le pixel = *reinterpret_cast<const u16_le*>(bytes); + return { Convert4To8((pixel >> 12) & 0xF), Convert4To8((pixel >> 8) & 0xF), + Convert4To8((pixel >> 4) & 0xF), Convert4To8(pixel & 0xF) }; +} + +/** + * Encode a color as RGBA8 format + * @param color Source color to encode + * @param bytes Destination pointer to store encoded color + */ +inline void EncodeRGBA8(const Math::Vec4<u8>& color, u8* bytes) { + bytes[3] = color.r(); + bytes[2] = color.g(); + bytes[1] = color.b(); + bytes[0] = color.a(); +} + +/** + * Encode a color as RGB8 format + * @param color Source color to encode + * @param bytes Destination pointer to store encoded color + */ +inline void EncodeRGB8(const Math::Vec4<u8>& color, u8* bytes) { + bytes[2] = color.r(); + bytes[1] = color.g(); + bytes[0] = color.b(); +} + +/** + * Encode a color as RGB565 format + * @param color Source color to encode + * @param bytes Destination pointer to store encoded color + */ +inline void EncodeRGB565(const Math::Vec4<u8>& color, u8* bytes) { + *reinterpret_cast<u16_le*>(bytes) = (Convert8To5(color.r()) << 11) | + (Convert8To6(color.g()) << 5) | Convert8To5(color.b()); +} + +/** + * Encode a color as RGB5A1 format + * @param color Source color to encode + * @param bytes Destination pointer to store encoded color + */ +inline void EncodeRGB5A1(const Math::Vec4<u8>& color, u8* bytes) { + *reinterpret_cast<u16_le*>(bytes) = (Convert8To5(color.r()) << 11) | + (Convert8To5(color.g()) << 6) | (Convert8To5(color.b()) << 1) | Convert8To1(color.a()); +} + +/** + * Encode a color as RGBA4 format + * @param color Source color to encode + * @param bytes Destination pointer to store encoded color + */ +inline void EncodeRGBA4(const Math::Vec4<u8>& color, u8* bytes) { + *reinterpret_cast<u16_le*>(bytes) = (Convert8To4(color.r()) << 12) | + (Convert8To4(color.g()) << 8) | (Convert8To4(color.b()) << 4) | Convert8To4(color.a()); +} + } // namespace diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp index 27c246a99..a27d3828c 100644 --- a/src/video_core/debug_utils/debug_utils.cpp +++ b/src/video_core/debug_utils/debug_utils.cpp @@ -321,44 +321,32 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture switch (info.format) { case Regs::TextureFormat::RGBA8: { - const u8* source_ptr = source + VideoCore::GetMortonOffset(x, y, 4); - return { source_ptr[3], source_ptr[2], source_ptr[1], disable_alpha ? (u8)255 : source_ptr[0] }; + auto res = Color::DecodeRGBA8(source + VideoCore::GetMortonOffset(x, y, 4)); + return { res.r(), res.g(), res.b(), disable_alpha ? 255 : res.a() }; } case Regs::TextureFormat::RGB8: { - const u8* source_ptr = source + VideoCore::GetMortonOffset(x, y, 3); - return { source_ptr[2], source_ptr[1], source_ptr[0], 255 }; + auto res = Color::DecodeRGB8(source + VideoCore::GetMortonOffset(x, y, 3)); + return { res.r(), res.g(), res.b(), 255 }; } - case Regs::TextureFormat::RGBA5551: + case Regs::TextureFormat::RGB5A1: { - const u16 source_ptr = *(const u16*)(source + VideoCore::GetMortonOffset(x, y, 2)); - u8 r = (source_ptr >> 11) & 0x1F; - u8 g = ((source_ptr) >> 6) & 0x1F; - u8 b = (source_ptr >> 1) & 0x1F; - u8 a = source_ptr & 1; - return Math::MakeVec<u8>(Color::Convert5To8(r), Color::Convert5To8(g), - Color::Convert5To8(b), disable_alpha ? 255 : Color::Convert1To8(a)); + auto res = Color::DecodeRGB5A1(source + VideoCore::GetMortonOffset(x, y, 2)); + return { res.r(), res.g(), res.b(), disable_alpha ? 255 : res.a() }; } case Regs::TextureFormat::RGB565: { - const u16 source_ptr = *(const u16*)(source + VideoCore::GetMortonOffset(x, y, 2)); - u8 r = Color::Convert5To8((source_ptr >> 11) & 0x1F); - u8 g = Color::Convert6To8(((source_ptr) >> 5) & 0x3F); - u8 b = Color::Convert5To8((source_ptr) & 0x1F); - return Math::MakeVec<u8>(r, g, b, 255); + auto res = Color::DecodeRGB565(source + VideoCore::GetMortonOffset(x, y, 2)); + return { res.r(), res.g(), res.b(), 255 }; } case Regs::TextureFormat::RGBA4: { - const u8* source_ptr = source + VideoCore::GetMortonOffset(x, y, 2); - u8 r = Color::Convert4To8(source_ptr[1] >> 4); - u8 g = Color::Convert4To8(source_ptr[1] & 0xF); - u8 b = Color::Convert4To8(source_ptr[0] >> 4); - u8 a = Color::Convert4To8(source_ptr[0] & 0xF); - return { r, g, b, disable_alpha ? (u8)255 : a }; + auto res = Color::DecodeRGBA4(source + VideoCore::GetMortonOffset(x, y, 2)); + return { res.r(), res.g(), res.b(), disable_alpha ? 255 : res.a() }; } case Regs::TextureFormat::IA8: @@ -369,7 +357,7 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture // Show intensity as red, alpha as green return { source_ptr[1], source_ptr[0], 0, 255 }; } else { - return { source_ptr[1], source_ptr[1], source_ptr[1], source_ptr[0]}; + return { source_ptr[1], source_ptr[1], source_ptr[1], source_ptr[0] }; } } diff --git a/src/video_core/pica.h b/src/video_core/pica.h index 96d0c72fe..b14de9278 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -145,7 +145,7 @@ struct Regs { enum class TextureFormat : u32 { RGBA8 = 0, RGB8 = 1, - RGBA5551 = 2, + RGB5A1 = 2, RGB565 = 3, RGBA4 = 4, IA8 = 5, @@ -167,7 +167,7 @@ struct Regs { case TextureFormat::RGB8: return 6; - case TextureFormat::RGBA5551: + case TextureFormat::RGB5A1: case TextureFormat::RGB565: case TextureFormat::RGBA4: case TextureFormat::IA8: @@ -413,7 +413,7 @@ struct Regs { enum ColorFormat : u32 { RGBA8 = 0, RGB8 = 1, - RGBA5551 = 2, + RGB5A1 = 2, RGB565 = 3, RGBA4 = 4, }; diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 8c370781a..5861c1926 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -22,7 +22,6 @@ namespace Rasterizer { static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) { const PAddr addr = registers.framebuffer.GetColorBufferPhysicalAddress(); - u8* color_buffer = Memory::GetPointer(PAddrToVAddr(addr)); // Similarly to textures, the render framebuffer is laid out from bottom to top, too. // NOTE: The framebuffer height register contains the actual FB height minus one. @@ -31,35 +30,28 @@ static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) { const u32 coarse_y = y & ~7; u32 bytes_per_pixel = GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(registers.framebuffer.color_format.Value())); u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * registers.framebuffer.width * bytes_per_pixel; + u8* dst_pixel = Memory::GetPointer(PAddrToVAddr(addr)) + dst_offset; switch (registers.framebuffer.color_format) { case registers.framebuffer.RGBA8: - { - u8* pixel = color_buffer + dst_offset; - pixel[3] = color.r(); - pixel[2] = color.g(); - pixel[1] = color.b(); - pixel[0] = color.a(); + Color::EncodeRGBA8(color, dst_pixel); break; - } - case registers.framebuffer.RGBA4: - { - u8* pixel = color_buffer + dst_offset; - pixel[1] = (color.r() & 0xF0) | (color.g() >> 4); - pixel[0] = (color.b() & 0xF0) | (color.a() >> 4); + case registers.framebuffer.RGB8: + Color::EncodeRGB8(color, dst_pixel); break; - } - case registers.framebuffer.RGBA5551: - { - u16_le* pixel = (u16_le*)(color_buffer + dst_offset); - *pixel = (Color::Convert8To5(color.r()) << 11) | - (Color::Convert8To5(color.g()) << 6) | - (Color::Convert8To5(color.b()) << 1) | - Color::Convert8To1(color.a()); + case registers.framebuffer.RGB5A1: + Color::EncodeRGB5A1(color, dst_pixel); + break; + + case registers.framebuffer.RGB565: + Color::EncodeRGB565(color, dst_pixel); + break; + + case registers.framebuffer.RGBA4: + Color::EncodeRGBA4(color, dst_pixel); break; - } default: LOG_CRITICAL(Render_Software, "Unknown framebuffer color format %x", registers.framebuffer.color_format.Value()); @@ -69,45 +61,29 @@ static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) { static const Math::Vec4<u8> GetPixel(int x, int y) { const PAddr addr = registers.framebuffer.GetColorBufferPhysicalAddress(); - u8* color_buffer = Memory::GetPointer(PAddrToVAddr(addr)); y = (registers.framebuffer.height - y); const u32 coarse_y = y & ~7; u32 bytes_per_pixel = GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(registers.framebuffer.color_format.Value())); u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * registers.framebuffer.width * bytes_per_pixel; - Math::Vec4<u8> ret; + u8* src_pixel = Memory::GetPointer(PAddrToVAddr(addr)) + src_offset; switch (registers.framebuffer.color_format) { case registers.framebuffer.RGBA8: - { - u8* pixel = color_buffer + src_offset; - ret.r() = pixel[3]; - ret.g() = pixel[2]; - ret.b() = pixel[1]; - ret.a() = pixel[0]; - return ret; - } + return Color::DecodeRGBA8(src_pixel); - case registers.framebuffer.RGBA4: - { - u8* pixel = color_buffer + src_offset; - ret.r() = Color::Convert4To8(pixel[1] >> 4); - ret.g() = Color::Convert4To8(pixel[1] & 0x0F); - ret.b() = Color::Convert4To8(pixel[0] >> 4); - ret.a() = Color::Convert4To8(pixel[0] & 0x0F); - return ret; - } + case registers.framebuffer.RGB8: + return Color::DecodeRGB8(src_pixel); - case registers.framebuffer.RGBA5551: - { - u16_le pixel = *(u16_le*)(color_buffer + src_offset); - ret.r() = Color::Convert5To8((pixel >> 11) & 0x1F); - ret.g() = Color::Convert5To8((pixel >> 6) & 0x1F); - ret.b() = Color::Convert5To8((pixel >> 1) & 0x1F); - ret.a() = Color::Convert1To8(pixel & 0x1); - return ret; - } + case registers.framebuffer.RGB5A1: + return Color::DecodeRGB5A1(src_pixel); + + case registers.framebuffer.RGB565: + return Color::DecodeRGB565(src_pixel); + + case registers.framebuffer.RGBA4: + return Color::DecodeRGBA4(src_pixel); default: LOG_CRITICAL(Render_Software, "Unknown framebuffer color format %x", registers.framebuffer.color_format.Value()); |