#include "Iop_PadMan.h" #include #include #include "Log.h" #include "../states/RegisterStateFile.h" #include "placeholder_def.h" using namespace Iop; using namespace PS2; #define PADNUM (1) #define PAD_MODE_DIGITAL 4 #define PAD_MODE_DUALSHOCK 7 #define LOG_NAME "iop_padman" #define STATE_PADDATA ("iop_padman/paddata.xml") #define STATE_PADDATA_PAD0_ADDRESS ("pad_address0") #define STATE_PADDATA_PAD1_ADDRESS ("pad_address1") #define STATE_PADDATA_TYPE ("type") std::string CPadMan::GetId() const { return "padman"; } std::string CPadMan::GetFunctionName(unsigned int) const { return "unknown"; } void CPadMan::RegisterSifModules(CSifMan& sif) { sif.RegisterModule(MODULE_ID_1, this); sif.RegisterModule(MODULE_ID_2, this); sif.RegisterModule(MODULE_ID_3, this); sif.RegisterModule(MODULE_ID_4, this); } void CPadMan::Invoke(CMIPS& context, unsigned int functionId) { throw std::runtime_error("Not implemented."); } bool CPadMan::Invoke(uint32 method, uint32* args, uint32 argsSize, uint32* ret, uint32 retSize, uint8* ram) { assert(method == 1); method = args[0]; switch(method) { case 0x00000001: case 0x80000100: Open(args, argsSize, ret, retSize, ram); break; case 0x80000105: SetMainMode(args, argsSize, ret, retSize, ram); break; case 0x8000010D: Close(args, argsSize, ret, retSize, ram); break; case 0x00000008: SetActuatorAlign(args, argsSize, ret, retSize, ram); break; case 0x00000010: Init(args, argsSize, ret, retSize, ram); break; case 0x00000012: GetModuleVersion(args, argsSize, ret, retSize, ram); break; default: CLog::GetInstance().Warn(LOG_NAME, "Unknown method invoked (0x%08X).\r\n", method); break; } return true; } void CPadMan::SaveState(Framework::CZipArchiveWriter& archive) const { auto registerFile = std::make_unique(STATE_PADDATA); registerFile->SetRegister32(STATE_PADDATA_PAD0_ADDRESS, m_padDataAddress[0]); registerFile->SetRegister32(STATE_PADDATA_PAD1_ADDRESS, m_padDataAddress[1]); registerFile->SetRegister32(STATE_PADDATA_TYPE, m_padDataType); archive.InsertFile(std::move(registerFile)); } void CPadMan::LoadState(Framework::CZipArchiveReader& archive) { CRegisterStateFile registerFile(*archive.BeginReadFile(STATE_PADDATA)); m_padDataAddress[0] = registerFile.GetRegister32(STATE_PADDATA_PAD0_ADDRESS); m_padDataAddress[1] = registerFile.GetRegister32(STATE_PADDATA_PAD1_ADDRESS); m_padDataType = static_cast(registerFile.GetRegister32(STATE_PADDATA_TYPE)); } void CPadMan::SetButtonState(unsigned int padNumber, CControllerInfo::BUTTON button, bool pressed, uint8* ram) { if(padNumber >= MAX_PADS) return; uint32 padDataAddress = m_padDataAddress[padNumber]; if(padDataAddress == 0) return; ExecutePadDataFunction(std::bind(&CPadMan::PDF_SetButtonState, PLACEHOLDER_1, button, pressed), ram + padDataAddress, PADNUM); } void CPadMan::SetAxisState(unsigned int padNumber, CControllerInfo::BUTTON button, uint8 axisValue, uint8* ram) { if(padNumber >= MAX_PADS) return; uint32 padDataAddress = m_padDataAddress[padNumber]; if(padDataAddress == 0) return; ExecutePadDataFunction(std::bind(&CPadMan::PDF_SetAxisState, std::placeholders::_1, button, axisValue), ram + padDataAddress, PADNUM); } void CPadMan::Open(uint32* args, uint32 argsSize, uint32* ret, uint32 retSize, uint8* ram) { uint32 port = args[1]; uint32 slot = args[2]; uint32 address = args[4]; CLog::GetInstance().Print(LOG_NAME, "Open(port = %d, slot = %d, padAreaAddr = 0x%08x);\r\n", port, slot, address); if(port < MAX_PADS) { m_padDataAddress[port] = address; m_padDataType = GetDataType(ram + address); CLog::GetInstance().Print(LOG_NAME, "Detected data type %d.\r\n", m_padDataType); ExecutePadDataFunction(&CPadMan::PDF_InitializeStruct0, ram + address, 0); ExecutePadDataFunction(&CPadMan::PDF_InitializeStruct1, ram + address, 1); } //Returns 0 on error ret[3] = 0x00000001; } void CPadMan::SetMainMode(uint32* args, uint32 argsSize, uint32* ret, uint32 retSize, uint8* ram) { uint32 port = args[1]; uint32 slot = args[2]; uint32 mode = args[3]; uint32 lock = args[4]; CLog::GetInstance().Print(LOG_NAME, "SetMainMode(port = %d, slot = %d, mode = %d, lock = %d);\r\n", port, slot, mode, lock); assert(mode <= 1); if(port < MAX_PADS) { uint32 padDataAddress = m_padDataAddress[port]; if(padDataAddress != 0) { ExecutePadDataFunction(std::bind(&CPadMan::PDF_SetMode, PLACEHOLDER_1, mode ? PAD_MODE_DUALSHOCK : PAD_MODE_DIGITAL), ram + padDataAddress, PADNUM); } } ret[3] = 1; } void CPadMan::Close(uint32* args, uint32 argsSize, uint32* ret, uint32 retSize, uint8* ram) { uint32 port = args[1]; uint32 slot = args[2]; uint32 wait = args[4]; CLog::GetInstance().Print(LOG_NAME, "Close(port = %d, slot = %d, wait = %d);\r\n", port, slot, wait); if(port < MAX_PADS) { m_padDataAddress[port] = 0; } ret[3] = 1; } void CPadMan::SetActuatorAlign(uint32* args, uint32 argsSize, uint32* ret, uint32 retSize, uint8* ram) { assert(retSize >= 24); ret[5] = 1; } void CPadMan::Init(uint32* args, uint32 argsSize, uint32* ret, uint32 retSize, uint8* ram) { assert(retSize >= 0x10); CLog::GetInstance().Print(LOG_NAME, "Init();\r\n"); ret[3] = 1; } void CPadMan::GetModuleVersion(uint32* args, uint32 argsSize, uint32* ret, uint32 retSize, uint8* ram) { assert(retSize >= 0x10); CLog::GetInstance().Print(LOG_NAME, "GetModuleVersion();\r\n"); ret[3] = 0x00000400; } void CPadMan::ExecutePadDataFunction(const PadDataFunction& func, void* pBase, size_t nOffset) { switch(m_padDataType) { case PAD_DATA_STD: { CPadDataHandler padData(reinterpret_cast(pBase) + nOffset); func(&padData); } break; case PAD_DATA_STD80: { CPadDataHandler padData(reinterpret_cast(pBase) + nOffset); func(&padData); } break; case PAD_DATA_EX: { CPadDataHandler padData(reinterpret_cast(pBase) + nOffset); func(&padData); } break; } } CPadMan::PAD_DATA_TYPE CPadMan::GetDataType(uint8* dataAddress) { PAD_DATA_TYPE result = PAD_DATA_STD; if((dataAddress[0x08] == 0xFF) && (dataAddress[0x48] == 0xFF)) { result = PAD_DATA_STD; } if((dataAddress[0x08] == 0xFF) && (dataAddress[0x88] == 0xFF)) { result = PAD_DATA_STD80; } if((dataAddress[0x00] == 0xFF) && (dataAddress[0x80] == 0xFF)) { result = PAD_DATA_EX; } return result; } void CPadMan::PDF_InitializeStruct0(CPadDataInterface* pPadData) { pPadData->SetFrame(0); pPadData->SetState(6); pPadData->SetReqState(0); pPadData->SetLength(32); pPadData->SetOk(1); //Reset analog sticks for(unsigned int i = 0; i < 4; i++) { pPadData->SetData(4 + i, 0x7F); } } void CPadMan::PDF_InitializeStruct1(CPadDataInterface* padData) { padData->SetFrame(1); padData->SetState(6); padData->SetReqState(0); padData->SetLength(32); padData->SetOk(1); //Reset analog sticks for(unsigned int i = 0; i < 4; i++) { padData->SetData(4 + i, 0x7F); } //Set pad mode padData->SetData(0, 0); padData->SetData(1, PAD_MODE_DUALSHOCK << 4); //EX struct initialization padData->SetModeCurId(PAD_MODE_DUALSHOCK << 4); padData->SetModeCurOffset(0); padData->SetModeTable(0, PAD_MODE_DUALSHOCK); padData->SetNumberOfModes(4); } void CPadMan::PDF_SetMode(CPadDataInterface* padData, uint8 mode) { assert(mode < 0x0F); padData->SetData(0, 0); padData->SetData(1, mode << 4); } void CPadMan::PDF_SetButtonState(CPadDataInterface* pPadData, CControllerInfo::BUTTON nButton, bool nPressed) { uint16 nStatus = (pPadData->GetData(2) << 8) | (pPadData->GetData(3)); uint32 buttonMask = GetButtonMask(nButton); nStatus &= ~buttonMask; if(!nPressed) { nStatus |= buttonMask; } pPadData->SetReqState(0); pPadData->SetData(2, static_cast(nStatus >> 8)); pPadData->SetData(3, static_cast(nStatus >> 0)); } void CPadMan::PDF_SetAxisState(CPadDataInterface* padData, CControllerInfo::BUTTON axis, uint8 axisValue) { assert(axis < 4); // clang-format off unsigned int axisIndex[4] = { 6, //ljoy_h 7, //ljoy_v 4, //rjoy_h 5 //rjoy_v }; // clang-format on padData->SetReqState(0); padData->SetData(axisIndex[axis], axisValue); }