3cf1cf615ebf2659009018e16ddad4ab6f551793
[pcsx_rearmed.git] / libpcsxcore / plugins.c
1 /***************************************************************************
2  *   Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team              *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
18  ***************************************************************************/
19
20 /*
21 * Plugin library callback/access functions.
22 */
23
24 #include "plugins.h"
25 #include "cdriso.h"
26 #include "cdrom-async.h"
27 #include "psxcounters.h"
28
29 static char IsoFile[MAXPATHLEN] = "";
30 static s64 cdOpenCaseTime = 0;
31
32 GPUupdateLace         GPU_updateLace;
33 GPUinit               GPU_init;
34 GPUshutdown           GPU_shutdown;
35 GPUopen               GPU_open;
36 GPUclose              GPU_close;
37 GPUreadStatus         GPU_readStatus;
38 GPUreadData           GPU_readData;
39 GPUreadDataMem        GPU_readDataMem;
40 GPUwriteStatus        GPU_writeStatus;
41 GPUwriteData          GPU_writeData;
42 GPUwriteDataMem       GPU_writeDataMem;
43 GPUdmaChain           GPU_dmaChain;
44 GPUfreeze             GPU_freeze;
45 GPUvBlank             GPU_vBlank;
46 GPUgetScreenInfo      GPU_getScreenInfo;
47
48 SPUinit               SPU_init;
49 SPUshutdown           SPU_shutdown;
50 SPUopen               SPU_open;
51 SPUclose              SPU_close;
52 SPUwriteRegister      SPU_writeRegister;
53 SPUreadRegister       SPU_readRegister;
54 SPUwriteDMAMem        SPU_writeDMAMem;
55 SPUreadDMAMem         SPU_readDMAMem;
56 SPUplayADPCMchannel   SPU_playADPCMchannel;
57 SPUfreeze             SPU_freeze;
58 SPUregisterCallback   SPU_registerCallback;
59 SPUregisterScheduleCb SPU_registerScheduleCb;
60 SPUasync              SPU_async;
61 SPUplayCDDAchannel    SPU_playCDDAchannel;
62 SPUsetCDvol           SPU_setCDvol;
63
64 #ifdef ENABLE_SIO1API
65
66 SIO1init              SIO1_init;
67 SIO1shutdown          SIO1_shutdown;
68 SIO1open              SIO1_open;
69 SIO1close             SIO1_close;
70 SIO1test              SIO1_test;
71 SIO1configure         SIO1_configure;
72 SIO1about             SIO1_about;
73 SIO1pause             SIO1_pause;
74 SIO1resume            SIO1_resume;
75 SIO1keypressed        SIO1_keypressed;
76 SIO1writeData8        SIO1_writeData8;
77 SIO1writeData16       SIO1_writeData16;
78 SIO1writeData32       SIO1_writeData32;
79 SIO1writeStat16       SIO1_writeStat16;
80 SIO1writeStat32       SIO1_writeStat32;
81 SIO1writeMode16       SIO1_writeMode16;
82 SIO1writeMode32       SIO1_writeMode32;
83 SIO1writeCtrl16       SIO1_writeCtrl16;
84 SIO1writeCtrl32       SIO1_writeCtrl32;
85 SIO1writeBaud16       SIO1_writeBaud16;
86 SIO1writeBaud32       SIO1_writeBaud32;
87 SIO1readData8         SIO1_readData8;
88 SIO1readData16        SIO1_readData16;
89 SIO1readData32        SIO1_readData32;
90 SIO1readStat16        SIO1_readStat16;
91 SIO1readStat32        SIO1_readStat32;
92 SIO1readMode16        SIO1_readMode16;
93 SIO1readMode32        SIO1_readMode32;
94 SIO1readCtrl16        SIO1_readCtrl16;
95 SIO1readCtrl32        SIO1_readCtrl32;
96 SIO1readBaud16        SIO1_readBaud16;
97 SIO1readBaud32        SIO1_readBaud32;
98 SIO1registerCallback  SIO1_registerCallback;
99
100 #endif
101
102 static const char *err;
103
104 #define CheckErr(func) { \
105         err = SysLibError(); \
106         if (err != NULL) { SysMessage(_("Error loading %s: %s"), func, err); return -1; } \
107 }
108
109 #define LoadSym(dest, src, name, checkerr) { \
110         dest = (src)SysLoadSym(drv, name); \
111         if (checkerr) { CheckErr(name); } \
112 }
113
114 void *hGPUDriver = NULL;
115
116 static void CALLBACK GPU__vBlank(int val) {}
117 static void CALLBACK GPU__getScreenInfo(int *y, int *base_hres) {}
118
119 #define LoadGpuSym1(dest, name) \
120         LoadSym(GPU_##dest, GPU##dest, name, TRUE);
121
122 #define LoadGpuSym0(dest, name) \
123         LoadSym(GPU_##dest, GPU##dest, name, FALSE); \
124         if (GPU_##dest == NULL) GPU_##dest = (GPU##dest) GPU__##dest;
125
126 #define LoadGpuSymN(dest, name) \
127         LoadSym(GPU_##dest, GPU##dest, name, FALSE);
128
129 static int LoadGPUplugin(const char *GPUdll) {
130         void *drv;
131
132         hGPUDriver = SysLoadLibrary(GPUdll);
133         if (hGPUDriver == NULL) {
134                 SysMessage (_("Could not load GPU plugin %s!"), GPUdll); return -1;
135         }
136         drv = hGPUDriver;
137         LoadGpuSym1(init, "GPUinit");
138         LoadGpuSym1(shutdown, "GPUshutdown");
139         LoadGpuSym1(open, "GPUopen");
140         LoadGpuSym1(close, "GPUclose");
141         LoadGpuSym1(readData, "GPUreadData");
142         LoadGpuSym1(readDataMem, "GPUreadDataMem");
143         LoadGpuSym1(readStatus, "GPUreadStatus");
144         LoadGpuSym1(writeData, "GPUwriteData");
145         LoadGpuSym1(writeDataMem, "GPUwriteDataMem");
146         LoadGpuSym1(writeStatus, "GPUwriteStatus");
147         LoadGpuSym1(dmaChain, "GPUdmaChain");
148         LoadGpuSym1(updateLace, "GPUupdateLace");
149         LoadGpuSym1(freeze, "GPUfreeze");
150         LoadGpuSym0(vBlank, "GPUvBlank");
151         LoadGpuSym0(getScreenInfo, "GPUgetScreenInfo");
152
153         return 0;
154 }
155
156 int CDR__getStatus(struct CdrStat *stat) {
157         if (cdOpenCaseTime < 0 || cdOpenCaseTime > (s64)time(NULL))
158                 stat->Status = 0x10;
159         else
160                 stat->Status = 0;
161
162         return 0;
163 }
164
165 static void *hSPUDriver = NULL;\r
166 static void CALLBACK SPU__registerScheduleCb(void (CALLBACK *cb)(unsigned int)) {}\r
167 static void CALLBACK SPU__setCDvol(unsigned char ll, unsigned char lr,
168                 unsigned char rl, unsigned char rr, unsigned int cycle) {}
169
170 #define LoadSpuSym1(dest, name) \
171         LoadSym(SPU_##dest, SPU##dest, name, TRUE);
172
173 #define LoadSpuSym0(dest, name) \
174         LoadSym(SPU_##dest, SPU##dest, name, FALSE); \
175         if (SPU_##dest == NULL) SPU_##dest = SPU__##dest;
176
177 #define LoadSpuSymN(dest, name) \
178         LoadSym(SPU_##dest, SPU##dest, name, FALSE);
179
180 static int LoadSPUplugin(const char *SPUdll) {
181         void *drv;
182
183         hSPUDriver = SysLoadLibrary(SPUdll);
184         if (hSPUDriver == NULL) {
185                 SysMessage (_("Could not load SPU plugin %s!"), SPUdll); return -1;
186         }
187         drv = hSPUDriver;
188         LoadSpuSym1(init, "SPUinit");
189         LoadSpuSym1(shutdown, "SPUshutdown");
190         LoadSpuSym1(open, "SPUopen");
191         LoadSpuSym1(close, "SPUclose");
192         LoadSpuSym1(writeRegister, "SPUwriteRegister");
193         LoadSpuSym1(readRegister, "SPUreadRegister");
194         LoadSpuSym1(writeDMAMem, "SPUwriteDMAMem");
195         LoadSpuSym1(readDMAMem, "SPUreadDMAMem");
196         LoadSpuSym1(playADPCMchannel, "SPUplayADPCMchannel");
197         LoadSpuSym1(freeze, "SPUfreeze");
198         LoadSpuSym1(registerCallback, "SPUregisterCallback");
199         LoadSpuSym0(registerScheduleCb, "SPUregisterScheduleCb");
200         LoadSpuSymN(async, "SPUasync");
201         LoadSpuSymN(playCDDAchannel, "SPUplayCDDAchannel");
202         LoadSpuSym0(setCDvol, "SPUsetCDvol");
203
204         return 0;
205 }
206
207 extern int in_type[8];
208
209 // Pad information, keystate, mode, config mode, vibration
210 static PadDataS pads[8];
211
212 static int reqPos, respSize;
213
214 static unsigned char buf[256];
215
216 static unsigned char stdpar[8] = { 0x41, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
217
218 //response for request 44, 45, 46, 47, 4C, 4D
219 static const u8 resp45[8]    = {0xF3, 0x5A, 0x01, 0x02, 0x00, 0x02, 0x01, 0x00};
220 static const u8 resp46_00[8] = {0xF3, 0x5A, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0A};
221 static const u8 resp46_01[8] = {0xF3, 0x5A, 0x00, 0x00, 0x01, 0x01, 0x01, 0x14};
222 static const u8 resp47[8]    = {0xF3, 0x5A, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00};
223 static const u8 resp4C_00[8] = {0xF3, 0x5A, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00};
224 static const u8 resp4C_01[8] = {0xF3, 0x5A, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00};
225
226 //fixed reponse of request number 41, 48, 49, 4A, 4B, 4E, 4F
227 static const u8 resp40[8] = {0xF3, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
228 static const u8 resp41[8] = {0xF3, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
229 static const u8 resp43[8] = {0xF3, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
230 static const u8 resp44[8] = {0xF3, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
231 static const u8 resp49[8] = {0xF3, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
232 static const u8 resp4A[8] = {0xF3, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
233 static const u8 resp4B[8] = {0xF3, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
234 static const u8 resp4E[8] = {0xF3, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
235 static const u8 resp4F[8] = {0xF3, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
236
237 // Resquest of psx core
238 enum {
239         // REQUEST
240         // first call of this request for the pad, the pad is configured as an digital pad.
241         // 0x0X, 0x42, 0x0Y, 0xZZ, 0xAA, 0x00, 0x00, 0x00, 0x00
242         // X pad number (used for the multitap, first request response 0x00, 0x80, 0x5A, (8 bytes pad A), (8 bytes pad B), (8 bytes pad C), (8 bytes pad D)
243         // Y if 1 : psx request the full length response for the multitap, 3 bytes header and 4 block of 8 bytes per pad
244         // Y if 0 : psx request a pad key state
245         // ZZ rumble small motor 00-> OFF, 01 -> ON
246         // AA rumble large motor speed 0x00 -> 0xFF
247         // RESPONSE
248         // header 3 Bytes
249         // 0x00
250         // PadId -> 0x41 for digital pas, 0x73 for analog pad
251         // 0x5A mode has not change (no press on analog button on the center of pad), 0x00 the analog button have been pressed and the mode switch
252         // 6 Bytes for keystates
253         CMD_READ_DATA_AND_VIBRATE = 0x42,
254
255         // REQUEST
256         // Header
257         // 0x0N, 0x43, 0x00, XX, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
258         // XX = 00 -> Normal mode : Seconde bytes of response = padId
259         // XX = 01 -> Configuration mode : Seconde bytes of response = 0xF3
260         // RESPONSE
261         // enter in config mode example :
262         // req : 01 43 00 01 00 00 00 00 00 00
263         // res : 00 41 5A buttons state, analog states
264         // exit config mode :
265         // req : 01 43 00 00 00 00 00 00 00 00
266         // res : 00 F3 5A buttons state, analog states
267         CMD_CONFIG_MODE = 0x43,
268
269         // Set led State
270         // REQUEST
271         // 0x0N, 0x44, 0x00, VAL, SEL, 0x00, 0x00, 0x00, 0x00
272         // If sel = 2 then
273         // VAL = 00 -> OFF
274         // VAL = 01 -> ON
275         // RESPONSE
276         // 0x00, 0xF3, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
277         CMD_SET_MODE_AND_LOCK = 0x44,
278
279         // Get Analog Led state
280         // REQUEST
281         // 0x0N, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
282         // RESPONSE
283         // 0x00, 0xF3, 0x5A, 0x01, 0x02, VAL, 0x02, 0x01, 0x00
284         // VAL = 00 Led OFF
285         // VAL = 01 Led ON
286         CMD_QUERY_MODEL_AND_MODE = 0x45,
287
288         //Get Variable A
289         // REQUEST
290         // 0x0N, 0x46, 0x00, 0xXX, 0x00, 0x00, 0x00, 0x00, 0x00
291         // RESPONSE
292         // XX=00
293         // 0x00, 0xF3, 0x5A, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0A
294         // XX=01
295         // 0x00, 0xF3, 0x5A, 0x00, 0x00, 0x01, 0x01, 0x01, 0x14
296         CMD_QUERY_ACT = 0x46,
297
298         // REQUEST
299         // 0x0N, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
300         // RESPONSE
301         // 0x00, 0xF3, 0x5A, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00
302         CMD_QUERY_COMB = 0x47,
303
304         // REQUEST
305         // 0x0N, 0x4C, 0x00, 0xXX, 0x00, 0x00, 0x00, 0x00, 0x00
306         // RESPONSE
307         // XX = 0
308         // 0x00, 0xF3, 0x5A, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00
309         // XX = 1
310         // 0x00, 0xF3, 0x5A, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00
311         CMD_QUERY_MODE = 0x4C,
312
313         // REQUEST
314         // 0x0N, 0x4D, 0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
315         // RESPONSE
316         // 0x00, 0xF3, 0x5A, old value or
317         // AA = 01 unlock large motor (and swap VAL1 and VAL2)
318         // BB = 01 unlock large motor (default)
319         // CC, DD, EE, FF = all FF -> unlock small motor
320         //
321         // default repsonse for analog pad with 2 motor : 0x00 0xF3 0x5A 0x00 0x01 0xFF 0xFF 0xFF 0xFF
322         //
323         CMD_VIBRATION_TOGGLE = 0x4D,
324         REQ40 = 0x40,
325         REQ41 = 0x41,
326         REQ49 = 0x49,
327         REQ4A = 0x4A,
328         REQ4B = 0x4B,
329         REQ4E = 0x4E,
330         REQ4F = 0x4F
331 };
332
333
334 static void initBufForRequest(int padIndex, char value) {
335         if (pads[padIndex].ds.configMode) {
336                 buf[0] = 0xf3; buf[1] = 0x5a;
337                 respSize = 8;
338         }
339         else if (value != 0x42 && value != 0x43) {
340                 respSize = 1;
341                 return;
342         }
343
344         if ((u32)(frame_counter - pads[padIndex].ds.lastUseFrame) > 2*60u
345             && pads[padIndex].ds.configModeUsed
346             && !Config.hacks.dualshock_init_analog)
347         {
348                 //SysPrintf("Pad reset\n");
349                 pads[padIndex].ds.padMode = 0; // according to nocash
350                 pads[padIndex].ds.autoAnalogTried = 0;
351         }
352         else if (pads[padIndex].ds.padMode == 0 && value == CMD_READ_DATA_AND_VIBRATE
353                  && pads[padIndex].ds.configModeUsed
354                  && !pads[padIndex].ds.configMode
355                  && !pads[padIndex].ds.userToggled)
356         {
357                 if (pads[padIndex].ds.autoAnalogTried == 16) {
358                         // auto-enable for convenience
359                         SysPrintf("Auto-enabling dualshock analog mode.\n");
360                         pads[padIndex].ds.padMode = 1;
361                         pads[padIndex].ds.autoAnalogTried = 255;
362                 }
363                 else if (pads[padIndex].ds.autoAnalogTried < 16)
364                         pads[padIndex].ds.autoAnalogTried++;
365         }
366         pads[padIndex].ds.lastUseFrame = frame_counter;
367
368         switch (value) {
369                 // keystate already in buffer, set by PADstartPoll_()
370                 //case CMD_READ_DATA_AND_VIBRATE :
371                 //      break;
372                 case CMD_CONFIG_MODE :
373                         if (pads[padIndex].ds.configMode) {
374                                 memcpy(buf, resp43, 8);
375                                 break;
376                         }
377                         // else not in config mode, pad keystate return
378                         break;
379                 case CMD_SET_MODE_AND_LOCK :
380                         memcpy(buf, resp44, 8);
381                         break;
382                 case CMD_QUERY_MODEL_AND_MODE :
383                         memcpy(buf, resp45, 8);
384                         buf[4] = pads[padIndex].ds.padMode;
385                         break;
386                 case CMD_QUERY_ACT :
387                         memcpy(buf, resp46_00, 8);
388                         break;
389                 case CMD_QUERY_COMB :
390                         memcpy(buf, resp47, 8);
391                         break;
392                 case CMD_QUERY_MODE :
393                         memcpy(buf, resp4C_00, 8);
394                         break;
395                 case CMD_VIBRATION_TOGGLE: // 4d
396                         memcpy(buf + 2, pads[padIndex].ds.cmd4dConfig, 6);
397                         break;
398                 case REQ40 :
399                         memcpy(buf, resp40, 8);
400                         break;
401                 case REQ41 :
402                         memcpy(buf, resp41, 8);
403                         break;
404                 case REQ49 :
405                         memcpy(buf, resp49, 8);
406                         break;
407                 case REQ4A :
408                         memcpy(buf, resp4A, 8);
409                         break;
410                 case REQ4B :
411                         memcpy(buf, resp4B, 8);
412                         break;
413                 case REQ4E :
414                         memcpy(buf, resp4E, 8);
415                         break;
416                 case REQ4F :
417                         memcpy(buf, resp4F, 8);
418                         break;
419         }
420 }
421
422 static void reqIndex2Treatment(int padIndex, u8 value) {
423         switch (pads[padIndex].txData[0]) {
424                 case CMD_CONFIG_MODE :
425                         //0x43
426                         if (value == 0) {
427                                 pads[padIndex].ds.configMode = 0;
428                         } else if (value == 1) {
429                                 pads[padIndex].ds.configMode = 1;
430                                 pads[padIndex].ds.configModeUsed = 1;
431                         }
432                         break;
433                 case CMD_SET_MODE_AND_LOCK :
434                         //0x44 store the led state for change mode if the next value = 0x02
435                         //0x01 analog ON
436                         //0x00 analog OFF
437                         if ((value & ~1) == 0)
438                                 pads[padIndex].ds.padMode = value;
439                         break;
440                 case CMD_QUERY_ACT :
441                         //0x46
442                         if (value == 1) {
443                                 memcpy(buf, resp46_01, 8);
444                         }
445                         break;
446                 case CMD_QUERY_MODE :
447                         if (value == 1) {
448                                 memcpy(buf, resp4C_01, 8);
449                         }
450                         break;
451         }
452 }
453
454 static void ds_update_vibrate(int padIndex) {
455         PadDataS *pad = &pads[padIndex];
456         if (pad->ds.configModeUsed) {
457                 pad->Vib[0] = (pad->Vib[0] == 1) ? 1 : 0;
458         }
459         else {
460                 // compat mode
461                 pad->Vib[0] = (pad->Vib[0] & 0xc0) == 0x40 && (pad->Vib[1] & 1);
462                 pad->Vib[1] = 0;
463         }
464         if (pad->Vib[0] != pad->VibF[0] || pad->Vib[1] != pad->VibF[1]) {
465                 //value is different update Value and call libretro for vibration
466                 pad->VibF[0] = pad->Vib[0];
467                 pad->VibF[1] = pad->Vib[1];
468                 plat_trigger_vibrate(padIndex, pad->VibF[0], pad->VibF[1]);
469                 //printf("vib%i %02x %02x\n", padIndex, pad->VibF[0], pad->VibF[1]);
470         }
471 }
472
473 static void log_pad(int port, int pos)
474 {
475 #if 0
476         if (port == 0 && pos == respSize - 1) {
477                 int i;
478                 for (i = 0; i < respSize; i++)
479                         printf("%02x ", pads[port].txData[i]);
480                 printf("|");
481                 for (i = 0; i < respSize; i++)
482                         printf(" %02x", buf[i]);
483                 printf("\n");
484         }
485 #endif
486 }
487
488 static void adjust_analog(unsigned char *b)
489 {
490         // ff8 hates 0x80 for whatever reason (broken in 2d area menus),
491         // or is this caused by something else we do wrong??
492         // Also S.C.A.R.S. treats 0x7f as turning left.
493         if (b[6] == 0x7f || b[6] == 0x80)
494                 b[6] = 0x81;
495 }
496
497 // Build response for 0x42 request Pad in port
498 static void PADstartPoll_(PadDataS *pad) {
499         switch (pad->controllerType) {
500                 case PSE_PAD_TYPE_MOUSE:
501                         stdpar[0] = 0x12;
502                         stdpar[1] = 0x5a;
503                         stdpar[2] = pad->buttonStatus & 0xff;
504                         stdpar[3] = pad->buttonStatus >> 8;
505                         stdpar[4] = pad->moveX;
506                         stdpar[5] = pad->moveY;
507                         memcpy(buf, stdpar, 6);
508                         respSize = 6;
509                         break;
510                 case PSE_PAD_TYPE_NEGCON: // npc101/npc104(slph00001/slph00069)
511                         stdpar[0] = 0x23;
512                         stdpar[1] = 0x5a;
513                         stdpar[2] = pad->buttonStatus & 0xff;
514                         stdpar[3] = pad->buttonStatus >> 8;
515                         stdpar[4] = pad->rightJoyX;
516                         stdpar[5] = pad->rightJoyY;
517                         stdpar[6] = pad->leftJoyX;
518                         stdpar[7] = pad->leftJoyY;
519                         memcpy(buf, stdpar, 8);
520                         respSize = 8;
521                         break;
522                 case PSE_PAD_TYPE_GUNCON: // GUNCON - gun controller SLPH-00034 from Namco
523                         stdpar[0] = 0x63;
524                         stdpar[1] = 0x5a;
525                         stdpar[2] = pad->buttonStatus & 0xff;
526                         stdpar[3] = pad->buttonStatus >> 8;
527
528                         int absX = pad->absoluteX; // 0-1023
529                         int absY = pad->absoluteY;
530
531                         if (absX == 65536 || absY == 65536) {
532                                 stdpar[4] = 0x01;
533                                 stdpar[5] = 0x00;
534                                 stdpar[6] = 0x0A;
535                                 stdpar[7] = 0x00;
536                         }
537                         else {
538                                 int y_ofs = 0, yres = 240;
539                                 GPU_getScreenInfo(&y_ofs, &yres);
540                                 int y_top = (Config.PsxType ? 0x30 : 0x19) + y_ofs;
541                                 int w = Config.PsxType ? 385 : 378;
542                                 int x = 0x40 + (w * absX >> 10);
543                                 int y = y_top + (yres * absY >> 10);
544                                 //printf("%3d %3d %4x %4x\n", absX, absY, x, y);
545
546                                 stdpar[4] = x;
547                                 stdpar[5] = x >> 8;
548                                 stdpar[6] = y;
549                                 stdpar[7] = y >> 8;
550                         }
551
552                         memcpy(buf, stdpar, 8);
553                         respSize = 8;
554                         break;
555                 case PSE_PAD_TYPE_GUN: // GUN CONTROLLER - gun controller SLPH-00014 from Konami
556                         stdpar[0] = 0x31;
557                         stdpar[1] = 0x5a;
558                         stdpar[2] = pad->buttonStatus & 0xff;
559                         stdpar[3] = pad->buttonStatus >> 8;
560                         memcpy(buf, stdpar, 4);
561                         respSize = 4;
562                         break;
563                 case PSE_PAD_TYPE_ANALOGPAD: // scph1150
564                         if (pad->ds.padMode == 0)
565                                 goto standard;
566                         stdpar[0] = 0x73;
567                         stdpar[1] = 0x5a;
568                         stdpar[2] = pad->buttonStatus & 0xff;
569                         stdpar[3] = pad->buttonStatus >> 8;
570                         stdpar[4] = pad->rightJoyX;
571                         stdpar[5] = pad->rightJoyY;
572                         stdpar[6] = pad->leftJoyX;
573                         stdpar[7] = pad->leftJoyY;
574                         adjust_analog(stdpar);
575                         memcpy(buf, stdpar, 8);
576                         respSize = 8;
577                         break;
578                 case PSE_PAD_TYPE_ANALOGJOY: // scph1110
579                         stdpar[0] = 0x53;
580                         stdpar[1] = 0x5a;
581                         stdpar[2] = pad->buttonStatus & 0xff;
582                         stdpar[3] = pad->buttonStatus >> 8;
583                         stdpar[4] = pad->rightJoyX;
584                         stdpar[5] = pad->rightJoyY;
585                         stdpar[6] = pad->leftJoyX;
586                         stdpar[7] = pad->leftJoyY;
587                         adjust_analog(stdpar);
588                         memcpy(buf, stdpar, 8);
589                         respSize = 8;
590                         break;
591                 case PSE_PAD_TYPE_STANDARD:
592                 standard:
593                         stdpar[0] = 0x41;
594                         stdpar[1] = 0x5a;
595                         stdpar[2] = pad->buttonStatus & 0xff;
596                         stdpar[3] = pad->buttonStatus >> 8;
597                         memcpy(buf, stdpar, 4);
598                         respSize = 4;
599                         break;
600                 default:
601                         respSize = 0;
602                         break;
603         }
604 }
605
606 static void PADpoll_dualshock(int port, unsigned char value, int pos)
607 {
608         switch (pos) {
609                 case 0:
610                         initBufForRequest(port, value);
611                         break;
612                 case 2:
613                         reqIndex2Treatment(port, value);
614                         break;
615                 case 7:
616                         if (pads[port].txData[0] == CMD_VIBRATION_TOGGLE)
617                                 memcpy(pads[port].ds.cmd4dConfig, pads[port].txData + 2, 6);
618                         break;
619         }
620
621         if (pads[port].txData[0] == CMD_READ_DATA_AND_VIBRATE
622             && !pads[port].ds.configModeUsed && 2 <= pos && pos < 4)
623         {
624                 // "compat" single motor mode
625                 pads[port].Vib[pos - 2] = value;
626         }
627         else if (pads[port].txData[0] == CMD_READ_DATA_AND_VIBRATE
628                  && 2 <= pos && pos < 8)
629         {
630                 // 0 - weak motor, 1 - strong motor
631                 int dev = pads[port].ds.cmd4dConfig[pos - 2];
632                 if (dev < 2)
633                         pads[port].Vib[dev] = value;
634         }
635         if (pos == respSize - 1)
636                 ds_update_vibrate(port);
637 }
638
639 static unsigned char PADpoll_(int port, unsigned char value, int pos, int *more_data) {
640         if (pos == 0 && value != 0x42 && in_type[port] != PSE_PAD_TYPE_ANALOGPAD)
641                 respSize = 1;
642
643         switch (in_type[port]) {
644                 case PSE_PAD_TYPE_ANALOGPAD:
645                         PADpoll_dualshock(port, value, pos);
646                         break;
647                 case PSE_PAD_TYPE_GUN:
648                         if (pos == 2)
649                                 pl_gun_byte2(port, value);
650                         break;
651         }
652
653         *more_data = pos < respSize - 1;
654         if (pos >= respSize)
655                 return 0xff; // no response/HiZ
656
657         log_pad(port, pos);
658         return buf[pos];
659 }
660
661 // response: 0x80, 0x5A, 8 bytes each for ports A, B, C, D
662 static unsigned char PADpollMultitap(int port, unsigned char value, int pos, int *more_data) {
663         unsigned int devByte, dev;
664         int unused = 0;
665
666         if (pos == 0) {
667                 *more_data = (value == 0x42);
668                 return 0x80;
669         }
670         *more_data = pos < 34 - 1;
671         if (pos == 1)
672                 return 0x5a;
673         if (pos >= 34)
674                 return 0xff;
675
676         devByte = pos - 2;
677         dev = devByte / 8;
678         if (devByte % 8 == 0)
679                 PADstartPoll_(&pads[port + dev]);
680         return PADpoll_(port + dev, value, devByte % 8, &unused);
681 }
682
683 static unsigned char PADpollMain(int port, unsigned char value, int *more_data) {
684         unsigned char ret;
685         int pos = reqPos++;
686
687         if (pos < sizeof(pads[port].txData))
688                 pads[port].txData[pos] = value;
689         if (!pads[port].portMultitap || !pads[port].multitapLongModeEnabled)
690                 ret = PADpoll_(port, value, pos, more_data);
691         else
692                 ret = PADpollMultitap(port, value, pos, more_data);
693         return ret;
694
695 }
696
697 // refresh the button state on port 1.
698 // int pad is not needed.
699 unsigned char PAD1_startPoll(int unused) {
700         int i;
701
702         reqPos = 0;
703         pads[0].requestPadIndex = 0;
704         PAD1_readPort(&pads[0]);
705
706         pads[0].multitapLongModeEnabled = 0;
707         if (pads[0].portMultitap)
708                 pads[0].multitapLongModeEnabled = pads[0].txData[1] & 1;
709
710         if (!pads[0].portMultitap || !pads[0].multitapLongModeEnabled) {
711                 PADstartPoll_(&pads[0]);
712         } else {
713                 // a multitap is plugged and enabled: refresh pads 1-3
714                 for (i = 1; i < 4; i++) {
715                         pads[i].requestPadIndex = i;
716                         PAD1_readPort(&pads[i]);
717                 }
718         }
719         return 0xff;
720 }
721
722 unsigned char PAD1_poll(unsigned char value, int *more_data) {
723         return PADpollMain(0, value, more_data);
724 }
725
726
727 unsigned char PAD2_startPoll(int pad) {
728         int pad_index = pads[0].portMultitap ? 4 : 1;
729         int i;
730
731         reqPos = 0;
732         pads[pad_index].requestPadIndex = pad_index;
733         PAD2_readPort(&pads[pad_index]);
734
735         pads[pad_index].multitapLongModeEnabled = 0;
736         if (pads[pad_index].portMultitap)
737                 pads[pad_index].multitapLongModeEnabled = pads[pad_index].txData[1] & 1;
738
739         if (!pads[pad_index].portMultitap || !pads[pad_index].multitapLongModeEnabled) {
740                 PADstartPoll_(&pads[pad_index]);
741         } else {
742                 for (i = 1; i < 4; i++) {
743                         pads[pad_index + i].requestPadIndex = pad_index + i;
744                         PAD2_readPort(&pads[pad_index + i]);
745                 }
746         }
747         return 0xff;
748 }
749
750 unsigned char PAD2_poll(unsigned char value, int *more_data) {
751         return PADpollMain(pads[0].portMultitap ? 4 : 1, value, more_data);
752 }
753
754 static void PAD_init(void) {
755         size_t p;
756
757         memset(pads, 0, sizeof(pads));
758         for (p = 0; p < sizeof(pads) / sizeof(pads[0]); p++) {
759                 memset(pads[p].ds.cmd4dConfig, 0xff, sizeof(pads[p].ds.cmd4dConfig));
760         }
761 }
762
763 int padFreeze(void *f, int Mode) {
764         size_t i;
765
766         for (i = 0; i < sizeof(pads) / sizeof(pads[0]); i++) {
767                 pads[i].saveSize = sizeof(pads[i]);
768                 gzfreeze(&pads[i], sizeof(pads[i]));
769                 if (Mode == 0 && pads[i].saveSize != sizeof(pads[i]))
770                         SaveFuncs.seek(f, pads[i].saveSize - sizeof(pads[i]), SEEK_CUR);
771         }
772
773         return 0;
774 }
775
776 int padToggleAnalog(unsigned int index)
777 {
778         int r = -1;
779
780         if (index < sizeof(pads) / sizeof(pads[0])) {
781                 r = (pads[index].ds.padMode ^= 1);
782                 pads[index].ds.userToggled = 1;
783         }
784         return r;
785 }
786
787 #ifdef ENABLE_SIO1API
788
789 void *hSIO1Driver = NULL;
790
791 long CALLBACK SIO1__init(void) { return 0; }
792 long CALLBACK SIO1__shutdown(void) { return 0; }
793 long CALLBACK SIO1__open(void) { return 0; }
794 long CALLBACK SIO1__close(void) { return 0; }
795 long CALLBACK SIO1__configure(void) { return 0; }
796 long CALLBACK SIO1__test(void) { return 0; }
797 void CALLBACK SIO1__about(void) {}
798 void CALLBACK SIO1__pause(void) {}
799 void CALLBACK SIO1__resume(void) {}
800 long CALLBACK SIO1__keypressed(int key) { return 0; }
801 void CALLBACK SIO1__writeData8(unsigned char val) {}
802 void CALLBACK SIO1__writeData16(unsigned short val) {}
803 void CALLBACK SIO1__writeData32(unsigned long val) {}
804 void CALLBACK SIO1__writeStat16(unsigned short val) {}
805 void CALLBACK SIO1__writeStat32(unsigned long val) {}
806 void CALLBACK SIO1__writeMode16(unsigned short val) {}
807 void CALLBACK SIO1__writeMode32(unsigned long val) {}
808 void CALLBACK SIO1__writeCtrl16(unsigned short val) {}
809 void CALLBACK SIO1__writeCtrl32(unsigned long val) {}
810 void CALLBACK SIO1__writeBaud16(unsigned short val) {}
811 void CALLBACK SIO1__writeBaud32(unsigned long val) {}
812 unsigned char CALLBACK SIO1__readData8(void) { return 0; }
813 unsigned short CALLBACK SIO1__readData16(void) { return 0; }
814 unsigned long CALLBACK SIO1__readData32(void) { return 0; }
815 unsigned short CALLBACK SIO1__readStat16(void) { return 0; }
816 unsigned long CALLBACK SIO1__readStat32(void) { return 0; }
817 unsigned short CALLBACK SIO1__readMode16(void) { return 0; }
818 unsigned long CALLBACK SIO1__readMode32(void) { return 0; }
819 unsigned short CALLBACK SIO1__readCtrl16(void) { return 0; }
820 unsigned long CALLBACK SIO1__readCtrl32(void) { return 0; }
821 unsigned short CALLBACK SIO1__readBaud16(void) { return 0; }
822 unsigned long CALLBACK SIO1__readBaud32(void) { return 0; }
823 void CALLBACK SIO1__registerCallback(void (CALLBACK *callback)(void)) {};
824
825 void CALLBACK SIO1irq(void) {
826         psxHu32ref(0x1070) |= SWAPu32(0x100);
827 }
828
829 #define LoadSio1Sym1(dest, name) \
830         LoadSym(SIO1_##dest, SIO1##dest, name, TRUE);
831
832 #define LoadSio1SymN(dest, name) \
833         LoadSym(SIO1_##dest, SIO1##dest, name, FALSE);
834
835 #define LoadSio1Sym0(dest, name) \
836         LoadSym(SIO1_##dest, SIO1##dest, name, FALSE); \
837         if (SIO1_##dest == NULL) SIO1_##dest = (SIO1##dest) SIO1__##dest;
838
839 static int LoadSIO1plugin(const char *SIO1dll) {
840         void *drv;
841
842         hSIO1Driver = SysLoadLibrary(SIO1dll);
843         if (hSIO1Driver == NULL) {
844                 SysMessage (_("Could not load SIO1 plugin %s!"), SIO1dll); return -1;
845         }
846         drv = hSIO1Driver;
847
848         LoadSio1Sym0(init, "SIO1init");
849         LoadSio1Sym0(shutdown, "SIO1shutdown");
850         LoadSio1Sym0(open, "SIO1open");
851         LoadSio1Sym0(close, "SIO1close");
852         LoadSio1Sym0(pause, "SIO1pause");
853         LoadSio1Sym0(resume, "SIO1resume");
854         LoadSio1Sym0(keypressed, "SIO1keypressed");
855         LoadSio1Sym0(configure, "SIO1configure");
856         LoadSio1Sym0(test, "SIO1test");
857         LoadSio1Sym0(about, "SIO1about");
858         LoadSio1Sym0(writeData8, "SIO1writeData8");
859         LoadSio1Sym0(writeData16, "SIO1writeData16");
860         LoadSio1Sym0(writeData32, "SIO1writeData32");
861         LoadSio1Sym0(writeStat16, "SIO1writeStat16");
862         LoadSio1Sym0(writeStat32, "SIO1writeStat32");
863         LoadSio1Sym0(writeMode16, "SIO1writeMode16");
864         LoadSio1Sym0(writeMode32, "SIO1writeMode32");
865         LoadSio1Sym0(writeCtrl16, "SIO1writeCtrl16");
866         LoadSio1Sym0(writeCtrl32, "SIO1writeCtrl32");
867         LoadSio1Sym0(writeBaud16, "SIO1writeBaud16");
868         LoadSio1Sym0(writeBaud32, "SIO1writeBaud32");
869         LoadSio1Sym0(readData16, "SIO1readData16");
870         LoadSio1Sym0(readData32, "SIO1readData32");
871         LoadSio1Sym0(readStat16, "SIO1readStat16");
872         LoadSio1Sym0(readStat32, "SIO1readStat32");
873         LoadSio1Sym0(readMode16, "SIO1readMode16");
874         LoadSio1Sym0(readMode32, "SIO1readMode32");
875         LoadSio1Sym0(readCtrl16, "SIO1readCtrl16");
876         LoadSio1Sym0(readCtrl32, "SIO1readCtrl32");
877         LoadSio1Sym0(readBaud16, "SIO1readBaud16");
878         LoadSio1Sym0(readBaud32, "SIO1readBaud32");
879         LoadSio1Sym0(registerCallback, "SIO1registerCallback");
880
881         return 0;
882 }
883
884 #endif
885
886 int LoadPlugins() {
887         char Plugin[MAXPATHLEN * 2];
888         int ret;
889
890         ReleasePlugins();
891         SysLibError();
892
893         sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Gpu);
894         if (LoadGPUplugin(Plugin) == -1) return -1;
895
896         sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Spu);
897         if (LoadSPUplugin(Plugin) == -1) return -1;
898
899 #ifdef ENABLE_SIO1API
900         sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Sio1);
901         if (LoadSIO1plugin(Plugin) == -1) return -1;
902 #endif
903
904         ret = cdra_init();
905         if (ret < 0) { SysMessage (_("Error initializing CD-ROM plugin: %d"), ret); return -1; }
906         ret = GPU_init();
907         if (ret < 0) { SysMessage (_("Error initializing GPU plugin: %d"), ret); return -1; }
908         ret = SPU_init();
909         if (ret < 0) { SysMessage (_("Error initializing SPU plugin: %d"), ret); return -1; }
910         PAD_init();
911
912 #ifdef ENABLE_SIO1API
913         ret = SIO1_init();
914         if (ret < 0) { SysMessage (_("Error initializing SIO1 plugin: %d"), ret); return -1; }
915 #endif
916
917         SysPrintf(_("Plugins loaded.\n"));
918         return 0;
919 }
920
921 void ReleasePlugins() {
922         cdra_shutdown();
923         if (hGPUDriver != NULL) GPU_shutdown();
924         if (hSPUDriver != NULL) SPU_shutdown();
925
926         if (hGPUDriver != NULL) { SysCloseLibrary(hGPUDriver); hGPUDriver = NULL; }
927         if (hSPUDriver != NULL) { SysCloseLibrary(hSPUDriver); hSPUDriver = NULL; }
928
929 #ifdef ENABLE_SIO1API
930         if (hSIO1Driver != NULL) {
931                 SIO1_shutdown();
932                 SysCloseLibrary(hSIO1Driver);
933                 hSIO1Driver = NULL;
934         }
935 #endif
936 }
937
938 // for CD swap
939 int ReloadCdromPlugin()
940 {
941         cdra_shutdown();
942         return cdra_init();
943 }
944
945 void SetIsoFile(const char *filename) {
946         if (filename == NULL) {
947                 IsoFile[0] = '\0';
948                 return;
949         }
950         strncpy(IsoFile, filename, MAXPATHLEN - 1);
951 }
952
953 const char *GetIsoFile(void) {
954         return IsoFile;
955 }
956
957 boolean UsingIso(void) {
958         return (IsoFile[0] != '\0');
959 }
960
961 void SetCdOpenCaseTime(s64 time) {
962         cdOpenCaseTime = time;
963 }