/* ZeroPAD - author: zerofrog(@gmail.com) * Copyright (C) 2006-2007 * * 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 */ #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <string.h> #include <stdarg.h> #include "zeropad.h" #ifndef _WIN32 #include <unistd.h> #else #include "svnrev.h" #endif char libraryName[256]; PADAnalog g_lanalog[2], g_ranalog[2]; PADconf conf; keyEvent event; u16 status[2]; int pressure; string s_strIniPath="inis/zeropad.ini"; const unsigned char version = PS2E_PAD_VERSION; const unsigned char revision = 0; const unsigned char build = 2; // increase that with each version u32 pads=0; u8 stdpar[2][20] = { {0xff, 0x5a, 0xff, 0xff, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0xff, 0x5a, 0xff, 0xff, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; u8 cmd40[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x5a}, {0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x5a}}; u8 cmd41[2][8] = { {0xff, 0x5a, 0xff, 0xff, 0x03, 0x00, 0x00, 0x5a}, {0xff, 0x5a, 0xff, 0xff, 0x03, 0x00, 0x00, 0x5a}}; u8 unk46[2][8] = { {0xFF, 0x5A, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0A}, {0xFF, 0x5A, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0A}}; u8 unk47[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00}, {0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00}}; u8 unk4c[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; u8 unk4d[2][8] = { {0xff, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, {0xff, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; u8 cmd4f[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a}, {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a}}; u8 stdcfg[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; // 2 & 3 = 0 u8 stdmode[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; u8 stdmodel[2][8] = { {0xff, 0x5a, 0x03, // 03 - dualshock2, 01 - dualshock 0x02, // number of modes 0x01, // current mode: 01 - analog, 00 - digital 0x02, 0x01, 0x00}, {0xff, 0x5a, 0x03, // 03 - dualshock2, 01 - dualshock 0x02, // number of modes 0x01, // current mode: 01 - analog, 00 - digital 0x02, 0x01, 0x00}}; u8 *buf; int padID[2]; int padMode[2]; int curPad; int curByte; int curCmd; int cmdLen; int ds2mode = 0; // DS Mode at start FILE *padLog = NULL; int POV(u32 direction, u32 angle){ if ((direction==0) && (angle>= 0) && (angle< 4500)) return 1;//forward if ((direction==2) && (angle>= 4500) && (angle<13500)) return 1;//right if ((direction==1) && (angle>=13500) && (angle<22500)) return 1;//backward if ((direction==3) && (angle>=22500) && (angle<31500)) return 1;//left if ((direction==0) && (angle>=31500) && (angle<36000)) return 1;//forward return 0; } void _KeyPress(int pad, u32 key) { int i; for (i=0; i<PADKEYS; i++) { if (key == conf.keys[pad][i]) { status[pad]&=~(1<<i); return; } } event.evt = KEYPRESS; event.key = key; } void _KeyRelease(int pad, u32 key) { int i; for (i=0; i<PADKEYS; i++) { if (key == conf.keys[pad][i]) { status[pad]|= (1<<i); return; } } event.evt = KEYRELEASE; event.key = key; } static void InitLibraryName() { #ifdef _WIN32 #ifdef PUBLIC // Public Release! // Output a simplified string that's just our name: strcpy( libraryName, "ZeroPAD" ); #elif defined( SVN_REV_UNKNOWN ) // Unknown revision. // Output a name that includes devbuild status but not // subversion revision tags: strcpy( libraryName, "ZeroPAD" # ifdef _DEBUG "-Debug" # endif ); #else // Use TortoiseSVN's SubWCRev utility's output // to label the specific revision: sprintf_s( libraryName, "ZeroPAD r%d%s" # ifdef _DEBUG "-Debug" # else "-Dev" # endif ,SVN_REV, SVN_MODS ? "m" : "" ); #endif #else // I'll fix up SVN support later. --arcum42 strcpy( libraryName, "ZeroPAD" # ifdef _DEBUG "-Debug" # endif ); #endif } u32 CALLBACK PS2EgetLibType() { return PS2E_LT_PAD; } char* CALLBACK PS2EgetLibName() { InitLibraryName(); return libraryName; } u32 CALLBACK PS2EgetLibVersion2(u32 type) { return (version<<16)|(revision<<8)|build; } void __Log(char *fmt, ...) { va_list list; if (!conf.log || padLog == NULL) return; va_start(list, fmt); vfprintf(padLog, fmt, list); va_end(list); } s32 CALLBACK PADinit(u32 flags) { #ifdef PAD_LOG if (padLog == NULL) { padLog = fopen("logs/padLog.txt", "w"); if (padLog) setvbuf(padLog, NULL, _IONBF, 0); } PAD_LOG("PADinit\n"); #endif pads|= flags; status[0] = 0xffff; status[1] = 0xffff; #ifdef __LINUX__ char strcurdir[256]; getcwd(strcurdir, 256); s_strIniPath = strcurdir; s_strIniPath += "/inis/zeropad.ini"; #endif LoadConfig(); PADsetMode(0, 0); PADsetMode(1, 0); pressure = 100; for(int i = 0; i < 2; ++i) { g_ranalog[i].x = 0x80; g_ranalog[i].y = 0x80; g_lanalog[i].x = 0x80; g_lanalog[i].y = 0x80; } return 0; } void CALLBACK PADshutdown() { #ifdef PAD_LOG if( padLog != NULL ) { fclose(padLog); padLog = NULL; } #endif } s32 CALLBACK PADopen(void *pDsp) { memset(&event, 0, sizeof(event)); return _PADopen(pDsp); } void CALLBACK PADclose() { _PADclose(); } u32 CALLBACK PADquery() { return 3; // both } void PADsetMode(int pad, int mode) { padMode[pad] = mode; switch(ds2mode) { case 0: // dualshock switch (mode) { case 0: // digital padID[pad] = 0x41; break; case 1: // analog padID[pad] = 0x73; break; } break; case 1: // dualshock2 switch (mode) { case 0: // digital padID[pad] = 0x41; break; case 1: // analog padID[pad] = 0x79; break; } break; } } u8 CALLBACK PADstartPoll(int pad) { #ifdef PAD_LOG PAD_LOG("PADstartPoll: %d\n", pad); #endif curPad = pad-1; curByte = 0; return 0xff; } u8 _PADpoll(u8 value) { u8 button_check = 0, button_check2 = 0; if (curByte == 0) { curByte++; #ifdef PAD_LOG PAD_LOG("PADpoll: cmd: %x\n", value); #endif curCmd = value; switch (value) { case 0x40: // DUALSHOCK2 ENABLER cmdLen = 8; buf = cmd40[curPad]; return 0xf3; case 0x41: // QUERY_DS2_ANALOG_MODE cmdLen = 8; buf = cmd41[curPad]; return 0xf3; case 0x42: // READ_DATA _PADupdate(curPad); stdpar[curPad][2] = status[curPad] >> 8; stdpar[curPad][3] = status[curPad] & 0xff; stdpar[curPad][4] = g_ranalog[curPad].x; stdpar[curPad][5] = g_ranalog[curPad].y; stdpar[curPad][6] = g_lanalog[curPad].x; stdpar[curPad][7] = g_lanalog[curPad].y; if (padMode[curPad] == 1) cmdLen = 20; else cmdLen = 4; button_check2 = stdpar[curPad][2] >> 4; switch(stdpar[curPad][3]) { case 0xBF: // X stdpar[curPad][14] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][16])); break; case 0xDF: // Circle stdpar[curPad][13] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][17])); break; case 0xEF: // Triangle stdpar[curPad][12] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][19])); break; case 0x7F: // Square stdpar[curPad][15] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][18])); break; case 0xFB: // L1 stdpar[curPad][16] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][26])); break; case 0xF7: // R1 stdpar[curPad][17] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][28])); break; case 0xFE: // L2 stdpar[curPad][18] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][27])); break; case 0xFD: // R2 stdpar[curPad][19] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][29])); break; default: stdpar[curPad][14] = 0x00; // Not pressed stdpar[curPad][13] = 0x00; // Not pressed stdpar[curPad][12] = 0x00; // Not pressed stdpar[curPad][15] = 0x00; // Not pressed stdpar[curPad][16] = 0x00; // Not pressed stdpar[curPad][17] = 0x00; // Not pressed stdpar[curPad][18] = 0x00; // Not pressed stdpar[curPad][19] = 0x00; // Not pressed break; } switch(button_check2) { case 0xE: // UP stdpar[curPad][10] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][21])); break; case 0xB: // DOWN stdpar[curPad][11] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][22])); break; case 0x7: // LEFT stdpar[curPad][9] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][23])); break; case 0xD: // RIGHT stdpar[curPad][8] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][24])); break; default: stdpar[curPad][8] = 0x00; // Not pressed stdpar[curPad][9] = 0x00; // Not pressed stdpar[curPad][10] = 0x00; // Not pressed stdpar[curPad][11] = 0x00; // Not pressed break; } buf = stdpar[curPad]; return padID[curPad]; case 0x43: // CONFIG_MODE cmdLen = 8; buf = stdcfg[curPad]; if (stdcfg[curPad][3] == 0xff) return 0xf3; else return padID[curPad]; case 0x44: // SET_MODE_AND_LOCK cmdLen = 8; buf = stdmode[curPad]; return 0xf3; case 0x45: // QUERY_MODEL_AND_MODE cmdLen = 8; buf = stdmodel[curPad]; buf[4] = padMode[curPad]; return 0xf3; case 0x46: // ?? cmdLen = 8; buf = unk46[curPad]; return 0xf3; case 0x47: // ?? cmdLen = 8; buf = unk47[curPad]; return 0xf3; case 0x4c: // QUERY_MODE ?? cmdLen = 8; buf = unk4c[curPad]; return 0xf3; case 0x4d: cmdLen = 8; buf = unk4d[curPad]; return 0xf3; case 0x4f: // SET_DS2_NATIVE_MODE cmdLen = 8; padID[curPad] = 0x79; // setting ds2 mode ds2mode = 1; // Set DS2 Mode buf = cmd4f[curPad]; return 0xf3; default: #ifdef PAD_LOG PAD_LOG("*PADpoll*: unknown cmd %x\n", value); #endif break; } } switch (curCmd) { case 0x43: if(curByte == 2) { switch(value){ case 0: buf[2] = 0; buf[3] = 0; break; case 1: buf[2] = 0xff; buf[3] = 0xff; break; } } break; case 0x44: if (curByte == 2) { PADsetMode(curPad, value); } break; case 0x46: if(curByte == 2) { switch(value) { case 0: // default buf[5] = 0x2; buf[6] = 0x0; buf[7] = 0xA; break; case 1: // Param std conf change buf[5] = 0x1; buf[6] = 0x1; buf[7] = 0x14; break; } } break; case 0x4c: if (curByte == 2) { switch (value) { case 0: // mode 0 - digital mode buf[5] = 0x4; break; case 1: // mode 1 - analog mode buf[5] = 0x7; break; } } break; } if (curByte >= cmdLen) return 0; return buf[curByte++]; } u8 CALLBACK PADpoll(u8 value) { u8 ret; ret = _PADpoll(value); #ifdef PAD_LOG PAD_LOG("PADpoll: %x (%d: %x)\n", value, curByte, ret); #endif return ret; } // PADkeyEvent is called every vsync (return NULL if no event) static keyEvent s_event; keyEvent* CALLBACK PADkeyEvent() { s_event = event; event.evt = 0; return &s_event; }