mikage-dev/source/processes/cdc.cpp
2024-03-08 10:54:13 +01:00

118 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