#include "cdc.hpp" #include "os.hpp" #include "platform/cdc.hpp" namespace HLE { namespace OS { struct FakeCDC final { spdlog::logger& logger; public: FakeCDC(FakeThread& thread); void ServiceThread( FakeThread& thread, const char* service_name, decltype(ServiceHelper::SendReply) (*command_handler)(FakeThread&, FakeCDC&, const IPC::CommandHeader&)); }; static OS::ResultAnd HIDGetTouchData(FakeThread& thread, FakeCDC& context) { context.logger.info("{}received GetTouchData", ThreadPrinter{thread}); // TODO: This should return the actual touch data instead of dummy zeroes return std::make_tuple(RESULT_OK, 0, 0); } static OS::ResultAnd<> HIDInitialize(FakeThread& thread, FakeCDC& context) { context.logger.info("{}received Initialize", ThreadPrinter{thread}); return std::make_tuple(RESULT_OK); } static decltype(ServiceHelper::SendReply) HIDCommandHandler(FakeThread& thread, FakeCDC& context, const IPC::CommandHeader& header) { using namespace Platform::CDC::HID; switch (header.command_id) { case GetTouchData::id: IPC::HandleIPCCommand(HIDGetTouchData, thread, thread, context); break; case Initialize::id: IPC::HandleIPCCommand(HIDInitialize, thread, thread, context); break; default: throw std::runtime_error(fmt::format("Unknown cdc:HID service command with header {:#010x}", header.raw)); } return ServiceHelper::SendReply; } static decltype(ServiceHelper::SendReply) DSPCommandHandler(FakeThread& thread, FakeCDC& context, const IPC::CommandHeader& header) { // 3dbrew erratum: This command takes no input parameters using Command0x6 = IPC::IPCCommand<0x6>::response::add_uint32; using Command0x7 = IPC::IPCCommand<0x7>::add_uint32::response; switch (header.command_id) { case Command0x6::id: context.logger.info("{}received cdc:DSP command 0x6", ThreadPrinter{thread}); thread.WriteTLS(0x80, IPC::CommandHeader::Make(0, 2, 0).raw); thread.WriteTLS(0x84, RESULT_OK); thread.WriteTLS(0x88, 0); break; case Command0x7::id: context.logger.info("{}received cdc:DSP command 0x7 with arg {:#x}", ThreadPrinter{thread}, thread.ReadTLS(0x84)); thread.WriteTLS(0x80, IPC::CommandHeader::Make(0, 1, 0).raw); thread.WriteTLS(0x84, RESULT_OK); break; using Command0x8 = IPC::IPCCommand<0x8>::add_uint32::response; case Command0x8::id: context.logger.info("{}received cdc:DSP command 0x8 with arg {:#x}", ThreadPrinter{thread}, thread.ReadTLS(0x84)); thread.WriteTLS(0x80, IPC::CommandHeader::Make(0, 1, 0).raw); thread.WriteTLS(0x84, RESULT_OK); break; default: throw std::runtime_error(fmt::format("Unknown cdc:DSP service command with header {:#010x}", header.raw)); } return ServiceHelper::SendReply; } void FakeCDC::ServiceThread(FakeThread& thread, const char* service_name, decltype(ServiceHelper::SendReply) (*command_handler)(FakeThread&, FakeCDC&, const IPC::CommandHeader&)) { ServiceHelper service; service.Append(ServiceUtil::SetupService(thread, service_name, 1)); auto InvokeCommandHandler = [&](FakeThread& thread, uint32_t /*signalled_handle_index*/) { Platform::IPC::CommandHeader header = { thread.ReadTLS(0x80) }; return command_handler(thread, *this, header); }; service.Run(thread, std::move(InvokeCommandHandler)); } FakeCDC::FakeCDC(FakeThread& thread) : logger(*thread.GetLogger()) { { auto new_thread = std::make_shared( thread.GetParentProcess(), [this](FakeThread& thread) { ServiceThread(thread, "cdc:DSP", DSPCommandHandler); }); new_thread->name = "cdc:DSPThread"; thread.GetParentProcess().AttachThread(new_thread); } thread.name = "cdc:HIDThread"; ServiceThread(thread, "cdc:HID", HIDCommandHandler); } template<> std::shared_ptr CreateFakeProcessViaContext(OS& os, Interpreter::Setup& setup, uint32_t pid, const std::string& name) { return WrappedFakeProcess::CreateWithContext(os, setup, pid, name); } } // namespace OS } // namespace HLE