scummvm/backends/ps2/ps2pad.cpp

156 lines
4.2 KiB
C++
Raw Normal View History

/* 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 <kernel.h>
#include <malloc.h>
#include <assert.h>
#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;
}
}