diff --git a/src/xenia/kernel/app.cc b/src/xenia/kernel/app.cc index 4541ade59..bb2e5a1bc 100644 --- a/src/xenia/kernel/app.cc +++ b/src/xenia/kernel/app.cc @@ -26,12 +26,13 @@ void XAppManager::RegisterApp(std::unique_ptr app) { } X_RESULT XAppManager::DispatchMessageSync(uint32_t app_id, uint32_t message, - uint32_t arg1, uint32_t arg2) { + uint32_t buffer_ptr, + uint32_t buffer_length) { const auto& it = app_lookup_.find(app_id); if (it == app_lookup_.end()) { return X_ERROR_NOT_FOUND; } - return it->second->DispatchMessageSync(message, arg1, arg2); + return it->second->DispatchMessageSync(message, buffer_ptr, buffer_length); } X_RESULT XAppManager::DispatchMessageAsync(uint32_t app_id, uint32_t message, @@ -41,7 +42,7 @@ X_RESULT XAppManager::DispatchMessageAsync(uint32_t app_id, uint32_t message, if (it == app_lookup_.end()) { return X_ERROR_NOT_FOUND; } - return it->second->DispatchMessageAsync(message, buffer_ptr, buffer_length); + return it->second->DispatchMessageSync(message, buffer_ptr, buffer_length); } } // namespace kernel diff --git a/src/xenia/kernel/app.h b/src/xenia/kernel/app.h index 4b4782a69..3ff461cc0 100644 --- a/src/xenia/kernel/app.h +++ b/src/xenia/kernel/app.h @@ -26,10 +26,8 @@ class XApp { public: uint32_t app_id() const { return app_id_; } - virtual X_RESULT DispatchMessageSync(uint32_t message, uint32_t arg1, - uint32_t arg2) = 0; - virtual X_RESULT DispatchMessageAsync(uint32_t message, uint32_t buffer_ptr, - size_t buffer_length) = 0; + virtual X_RESULT DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, + uint32_t buffer_length) = 0; protected: XApp(KernelState* kernel_state, uint32_t app_id); @@ -43,8 +41,8 @@ class XAppManager { public: void RegisterApp(std::unique_ptr app); - X_RESULT DispatchMessageSync(uint32_t app_id, uint32_t message, uint32_t arg1, - uint32_t arg2); + X_RESULT DispatchMessageSync(uint32_t app_id, uint32_t message, + uint32_t buffer_ptr, uint32_t buffer_length); X_RESULT DispatchMessageAsync(uint32_t app_id, uint32_t message, uint32_t buffer_ptr, size_t buffer_length); diff --git a/src/xenia/kernel/apps/xmp_app.cc b/src/xenia/kernel/apps/xmp_app.cc index e3ce93c27..68a906e4a 100644 --- a/src/xenia/kernel/apps/xmp_app.cc +++ b/src/xenia/kernel/apps/xmp_app.cc @@ -13,91 +13,219 @@ namespace xe { namespace kernel { namespace apps { -X_RESULT XXMPApp::XMPGetStatus(uint32_t unk, uint32_t status_ptr) { +XXMPApp::XXMPApp(KernelState* kernel_state) + : XApp(kernel_state, 0xFA), + status_(Status::kStopped), + disabled_(0), + unknown_state1_(0), + unknown_state2_(0), + unknown_flags_(0), + unknown_float_(0.0f) {} + +X_RESULT XXMPApp::XMPGetStatus(uint32_t status_ptr) { // Some stupid games will hammer this on a thread - induce a delay // here to keep from starving real threads. Sleep(1); - XELOGD("XMPGetStatus(%.8X, %.8X)", unk, status_ptr); - - assert_true(unk == 2); - poly::store_and_swap(membase_ + status_ptr, 0); - + XELOGD("XMPGetStatus(%.8X)", status_ptr); + poly::store_and_swap(membase_ + status_ptr, + static_cast(status_)); + OnStatusChanged(); return X_ERROR_SUCCESS; } -X_RESULT XXMPApp::XMPGetStatusEx(uint32_t unk, uint32_t unk_ptr, - uint32_t disabled_ptr) { - // Some stupid games will hammer this on a thread - induce a delay - // here to keep from starving real threads. - Sleep(10); - - XELOGD("XMPGetStatusEx(%.8X, %.8X, %.8X)", unk, unk_ptr, disabled_ptr); - - assert_true(unk == 2); - poly::store_and_swap(membase_ + unk_ptr, 0); - poly::store_and_swap(membase_ + disabled_ptr, 1); - +X_RESULT XXMPApp::XMPContinue() { + XELOGD("XMPContinue()"); + if (status_ == Status::kPaused) { + status_ = Status::kPlaying; + } + OnStatusChanged(); return X_ERROR_SUCCESS; } -X_RESULT XXMPApp::DispatchMessageSync(uint32_t message, uint32_t arg1, - uint32_t arg2) { +X_RESULT XXMPApp::XMPStop(uint32_t unk) { + assert_zero(unk); + XELOGD("XMPStop(%.8X)", unk); + status_ = Status::kStopped; + OnStatusChanged(); + return X_ERROR_SUCCESS; +} + +X_RESULT XXMPApp::XMPPause() { + XELOGD("XMPPause()"); + if (status_ == Status::kPlaying) { + status_ = Status::kPaused; + } + OnStatusChanged(); + return X_ERROR_SUCCESS; +} + +X_RESULT XXMPApp::XMPNext() { + XELOGD("XMPNext()"); + status_ = Status::kPlaying; + OnStatusChanged(); + return X_ERROR_SUCCESS; +} + +X_RESULT XXMPApp::XMPPrevious() { + XELOGD("XMPPrevious()"); + status_ = Status::kPlaying; + OnStatusChanged(); + return X_ERROR_SUCCESS; +} + +void XXMPApp::OnStatusChanged() { + kernel_state_->BroadcastNotification(kMsgStatusChanged, + static_cast(status_)); +} + +X_RESULT XXMPApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, + uint32_t buffer_length) { + // NOTE: buffer_length may be zero or valid. // http://freestyledash.googlecode.com/svn-history/r1/trunk/Freestyle/Scenes/Media/Music/ScnMusic.cpp switch (message) { + case 0x00070003: { + assert_true(!buffer_length || buffer_length == 4); + uint32_t xmp_client = + poly::load_and_swap(membase_ + buffer_ptr + 0); + assert_true(xmp_client == 0x00000002); + return XMPContinue(); + } + case 0x00070004: { + assert_true(!buffer_length || buffer_length == 8); + uint32_t xmp_client = + poly::load_and_swap(membase_ + buffer_ptr + 0); + uint32_t unk = poly::load_and_swap(membase_ + buffer_ptr + 4); + assert_true(xmp_client == 0x00000002); + return XMPStop(unk); + } + case 0x00070005: { + assert_true(!buffer_length || buffer_length == 4); + uint32_t xmp_client = + poly::load_and_swap(membase_ + buffer_ptr + 0); + assert_true(xmp_client == 0x00000002); + return XMPPause(); + } + case 0x00070006: { + assert_true(!buffer_length || buffer_length == 4); + uint32_t xmp_client = + poly::load_and_swap(membase_ + buffer_ptr + 0); + assert_true(xmp_client == 0x00000002); + return XMPNext(); + } + case 0x00070007: { + assert_true(!buffer_length || buffer_length == 4); + uint32_t xmp_client = + poly::load_and_swap(membase_ + buffer_ptr + 0); + assert_true(xmp_client == 0x00000002); + return XMPPrevious(); + } + case 0x00070008: { + assert_true(!buffer_length || buffer_length == 16); + uint32_t xmp_client = + poly::load_and_swap(membase_ + buffer_ptr + 0); + uint32_t unk1 = poly::load_and_swap(membase_ + buffer_ptr + 4); + uint32_t unk2 = poly::load_and_swap(membase_ + buffer_ptr + 8); + uint32_t flags = + poly::load_and_swap(membase_ + buffer_ptr + 12); + assert_true(xmp_client == 0x00000002); + XELOGD("XMPSetState?(%.8X, %.8X, %.8X)", unk1, unk2, flags); + unknown_state1_ = unk1; + unknown_state2_ = unk2; + unknown_flags_ = flags; + kernel_state_->BroadcastNotification(kMsgStateChanged, 0); + return X_ERROR_SUCCESS; + } case 0x00070009: { - uint32_t unk = - poly::load_and_swap(membase_ + arg1 + 0); // 0x00000002 - uint32_t status_ptr = poly::load_and_swap( - membase_ + arg1 + 4); // out ptr to 4b - expect 0 - assert_zero(arg2); - return XMPGetStatus(unk, status_ptr); - } - case 0x0007001A: { - // dcz - // arg1 = ? - // arg2 = 0 - break; - } - case 0x0007001B: { - uint32_t unk = - poly::load_and_swap(membase_ + arg1 + 0); // 0x00000002 - uint32_t unk_ptr = poly::load_and_swap( - membase_ + arg1 + 4); // out ptr to 4b - expect 0 - uint32_t disabled_ptr = poly::load_and_swap( - membase_ + arg1 + 8); // out ptr to 4b - expect 1 (to skip) - assert_zero(arg2); - return XMPGetStatusEx(unk, unk_ptr, disabled_ptr); - } - } - XELOGE("Unimplemented XMsg message app=%.8X, msg=%.8X, arg1=%.8X, arg2=%.8X", - app_id(), message, arg1, arg2); - return X_ERROR_NOT_FOUND; -} - -X_RESULT XXMPApp::DispatchMessageAsync(uint32_t message, uint32_t buffer_ptr, - size_t buffer_length) { - switch (message) { - case 0x00070009: { - uint32_t unk = poly::load_and_swap(membase_ + buffer_ptr + - 0); // 0x00000002 + assert_true(!buffer_length || buffer_length == 8); + uint32_t xmp_client = + poly::load_and_swap(membase_ + buffer_ptr + 0); uint32_t status_ptr = poly::load_and_swap( membase_ + buffer_ptr + 4); // out ptr to 4b - expect 0 - assert_true(buffer_length == 8); - return XMPGetStatus(unk, status_ptr); + assert_true(xmp_client == 0x00000002); + return XMPGetStatus(status_ptr); + } + case 0x0007000B: { + assert_true(!buffer_length || buffer_length == 8); + uint32_t xmp_client = + poly::load_and_swap(membase_ + buffer_ptr + 0); + uint32_t float_ptr = poly::load_and_swap( + membase_ + buffer_ptr + 4); // out ptr to 4b - floating point + assert_true(xmp_client == 0x00000002); + XELOGD("XMPGetFloat?(%.8X)", float_ptr); + poly::store_and_swap(membase_ + float_ptr, unknown_float_); + return X_ERROR_SUCCESS; + } + case 0x0007000C: { + assert_true(!buffer_length || buffer_length == 8); + uint32_t xmp_client = + poly::load_and_swap(membase_ + buffer_ptr + 0); + float float_value = poly::load_and_swap(membase_ + buffer_ptr + 4); + assert_true(xmp_client == 0x00000002); + XELOGD("XMPSetFloat?(%g)", float_value); + unknown_float_ = float_value; + return X_ERROR_SUCCESS; + } + case 0x0007001A: { + assert_true(!buffer_length || buffer_length == 12); + uint32_t xmp_client = + poly::load_and_swap(membase_ + buffer_ptr + 0); + uint32_t unk1 = poly::load_and_swap(membase_ + buffer_ptr + 4); + uint32_t disabled = + poly::load_and_swap(membase_ + buffer_ptr + 8); + assert_true(xmp_client == 0x00000002); + assert_zero(unk1); + XELOGD("XMPSetDisabled(%.8X, %.8X)", unk1, disabled); + disabled_ = disabled; + kernel_state_->BroadcastNotification(kMsgDisableChanged, disabled_); + return X_ERROR_SUCCESS; } case 0x0007001B: { - uint32_t unk = poly::load_and_swap(membase_ + buffer_ptr + - 0); // 0x00000002 + assert_true(!buffer_length || buffer_length == 12); + uint32_t xmp_client = + poly::load_and_swap(membase_ + buffer_ptr + 0); uint32_t unk_ptr = poly::load_and_swap( membase_ + buffer_ptr + 4); // out ptr to 4b - expect 0 uint32_t disabled_ptr = poly::load_and_swap( membase_ + buffer_ptr + 8); // out ptr to 4b - expect 1 (to skip) - assert_true(buffer_length == 0xC); - return XMPGetStatusEx(unk, unk_ptr, disabled_ptr); + assert_true(xmp_client == 0x00000002); + XELOGD("XMPGetDisabled(%.8X, %.8X)", unk_ptr, disabled_ptr); + poly::store_and_swap(membase_ + unk_ptr, 0); + poly::store_and_swap(membase_ + disabled_ptr, disabled_); + return X_ERROR_SUCCESS; + } + case 0x00070029: { + assert_true(!buffer_length || buffer_length == 16); + uint32_t xmp_client = + poly::load_and_swap(membase_ + buffer_ptr + 0); + uint32_t unk1_ptr = + poly::load_and_swap(membase_ + buffer_ptr + 4); + uint32_t unk2_ptr = + poly::load_and_swap(membase_ + buffer_ptr + 8); + uint32_t unk3_ptr = + poly::load_and_swap(membase_ + buffer_ptr + 12); + assert_true(xmp_client == 0x00000002); + XELOGD("XMPGetState?(%.8X, %.8X, %.8X)", unk1_ptr, unk2_ptr, unk3_ptr); + poly::store_and_swap(membase_ + unk1_ptr, unknown_state1_); + poly::store_and_swap(membase_ + unk2_ptr, unknown_state2_); + poly::store_and_swap(membase_ + unk3_ptr, unknown_flags_); + return X_ERROR_SUCCESS; + } + case 0x0007002E: { + assert_true(!buffer_length || buffer_length == 12); + // 00000002 00000003 20049ce0 + uint32_t xmp_client = poly::load_and_swap( + membase_ + buffer_ptr + 0); // 0x00000002 + uint32_t unk1 = poly::load_and_swap(membase_ + buffer_ptr + + 4); // 0x00000003 + uint32_t unk_ptr = + poly::load_and_swap(membase_ + buffer_ptr + 8); + assert_true(xmp_client == 0x00000002); + // + break; } } - XELOGE("Unimplemented XMsg message app=%.8X, msg=%.8X, buffer=%.8X, len=%d", + XELOGE("Unimplemented XMsg message app=%.8X, msg=%.8X, arg1=%.8X, arg2=%.8X", app_id(), message, buffer_ptr, buffer_length); return X_ERROR_NOT_FOUND; } diff --git a/src/xenia/kernel/apps/xmp_app.h b/src/xenia/kernel/apps/xmp_app.h index b851ea5c2..a9fbe76b7 100644 --- a/src/xenia/kernel/apps/xmp_app.h +++ b/src/xenia/kernel/apps/xmp_app.h @@ -20,16 +20,38 @@ namespace apps { class XXMPApp : public XApp { public: - XXMPApp(KernelState* kernel_state) : XApp(kernel_state, 0xFA) {} + enum class Status : uint32_t { + kStopped = 0, + kPlaying = 1, + kPaused = 2, + }; - X_RESULT XMPGetStatus(uint32_t unk, uint32_t status_ptr); - X_RESULT XMPGetStatusEx(uint32_t unk, uint32_t unk_ptr, - uint32_t disabled_ptr); + XXMPApp(KernelState* kernel_state); - X_RESULT DispatchMessageSync(uint32_t message, uint32_t arg1, - uint32_t arg2) override; - X_RESULT DispatchMessageAsync(uint32_t message, uint32_t buffer_ptr, - size_t buffer_length) override; + X_RESULT XMPGetStatus(uint32_t status_ptr); + + X_RESULT XMPContinue(); + X_RESULT XMPStop(uint32_t unk); + X_RESULT XMPPause(); + X_RESULT XMPNext(); + X_RESULT XMPPrevious(); + + X_RESULT DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, + uint32_t buffer_length) override; + + private: + static const uint32_t kMsgStatusChanged = 0xA000001; + static const uint32_t kMsgStateChanged = 0xA000002; + static const uint32_t kMsgDisableChanged = 0xA000003; + + void OnStatusChanged(); + + Status status_; + uint32_t disabled_; + uint32_t unknown_state1_; + uint32_t unknown_state2_; + uint32_t unknown_flags_; + float unknown_float_; }; } // namespace apps