mirror of
https://github.com/mikage-emu/mikage-dev.git
synced 2025-01-09 15:01:00 +01:00
119 lines
4.3 KiB
C++
119 lines
4.3 KiB
C++
|
#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<uint32_t, uint32_t> 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<GetTouchData>(HIDGetTouchData, thread, thread, context);
|
||
|
break;
|
||
|
|
||
|
case Initialize::id:
|
||
|
IPC::HandleIPCCommand<Initialize>(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<WrappedFakeThread>( 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<WrappedFakeProcess> CreateFakeProcessViaContext<FakeCDC>(OS& os, Interpreter::Setup& setup, uint32_t pid, const std::string& name) {
|
||
|
return WrappedFakeProcess::CreateWithContext<FakeCDC>(os, setup, pid, name);
|
||
|
}
|
||
|
|
||
|
} // namespace OS
|
||
|
|
||
|
} // namespace HLE
|