/* ScummVM - Scumm Interpreter * Copyright (C) 2001-2004 The ScummVM project * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * $Header$ * */ #include #include #include #include "backends/ps2/systemps2.h" #include "backends/ps2/ps2pad.h" Ps2Pad::Ps2Pad(OSystem_PS2 *system) { _system = system; _padBuf = (uint8*)memalign(64, 256); _padStatus = STAT_NONE; padInit(0); // initialize library _port = _slot = 0; // first controller, no multitap initPad(); } void Ps2Pad::initPad(void) { int modes = 0; if (_padStatus == STAT_NONE) { if (padPortOpen(_port, _slot, _padBuf) == 1) { _padStatus = STAT_OPEN; _padInitTime = _system->getMillis(); } else { padPortClose(_port, _slot); printf("Unable to open port (%d/%d)!\n", _port, _slot); } } else { if (checkPadReady(_port, _slot)) { switch (_padStatus) { case STAT_OPEN: _padStatus = STAT_DETECT; break; case STAT_DETECT: _isDualShock = false; modes = padInfoMode(_port, _slot, PAD_MODETABLE, -1); // Verify that the controller has a DUAL SHOCK mode for (int cnt = 0; cnt < modes; cnt++) if (padInfoMode(_port, _slot, PAD_MODETABLE, cnt) == PAD_TYPE_DUALSHOCK) _isDualShock = true; // If ExId != 0x0 => This controller has actuator engines // This check should always pass if the Dual Shock test above passed if (_isDualShock) if (padInfoMode(_port, _slot, PAD_MODECUREXID, 0) == 0) _isDualShock = false; if (_isDualShock) { // When using MMODE_LOCK, user cant change mode with Select button padSetMainMode(_port, _slot, PAD_MMODE_DUALSHOCK, PAD_MMODE_LOCK); _padStatus = STAT_INIT_DSHOCK; } else _padStatus = STAT_WAIT_READY; break; case STAT_INIT_DSHOCK: padEnterPressMode(_port, _slot); _padStatus = STAT_CHECK_ACT; break; case STAT_CHECK_ACT: _actuators = padInfoAct(_port, _slot, -1, 0); if (_actuators != 0) _padStatus = STAT_INIT_ACT; else { _isDualShock = false; _padStatus = STAT_WAIT_READY; } break; case STAT_INIT_ACT: char actAlign[6]; actAlign[0] = 0; actAlign[1] = 1; actAlign[2] = actAlign[3] = actAlign[4] = actAlign[5] = 0xff; padSetActAlign(_port, _slot, actAlign); _padStatus = STAT_WAIT_READY; break; case STAT_WAIT_READY: _padStatus = STAT_OKAY; break; } } else { // check for timeout... if (_system->getMillis() - _padInitTime > 5000) { // still no pad, give up. if (padPortClose(_port, _slot) != 1) printf("WARNING: can't close port: %d/%d\n"); printf("looking for pad, gave up and closed port\n"); _padStatus = STAT_NONE; } } } } bool Ps2Pad::checkPadReady(int port, int slot, uint32 wait, uint32 *waitRes) { int state; for (uint32 cnt = 0; cnt < wait; cnt++) { state = padGetState(port, slot); if ((state == PAD_STATE_STABLE) || (state == PAD_STATE_FINDCTP1)) { if (waitRes) *waitRes = cnt; return true; } } return false; } bool Ps2Pad::padAlive(void) { if ((_padStatus == STAT_OKAY) && checkPadReady(_port, _slot)) return true; initPad(); return false; } bool Ps2Pad::isDualShock(void) { return _isDualShock; } void Ps2Pad::readPad(uint16 *pbuttons, int16 *joyh, int16 *joyv) { if (padAlive()) { struct padButtonStatus buttons; padRead(_port, _slot, &buttons); *pbuttons = ~buttons.btns; if (_isDualShock) { *joyh = (int16)buttons.ljoy_h - 128; *joyv = (int16)buttons.ljoy_v - 128; } else *joyh = *joyv = 0; } else { *joyh = *joyv = 0; *pbuttons = 0; } }