/[pcsx2_0.9.7]/trunk/pcsx2/PluginManager.cpp
ViewVC logotype

Contents of /trunk/pcsx2/PluginManager.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 280 - (show annotations) (download)
Thu Dec 23 12:02:12 2010 UTC (9 years, 1 month ago) by william
File size: 47801 byte(s)
re-commit (had local access denied errors when committing)
1 /* PCSX2 - PS2 Emulator for PCs
2 * Copyright (C) 2002-2010 PCSX2 Dev Team
3 *
4 * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5 * of the GNU Lesser General Public License as published by the Free Software Found-
6 * ation, either version 3 of the License, or (at your option) any later version.
7 *
8 * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with PCSX2.
13 * If not, see <http://www.gnu.org/licenses/>.
14 */
15
16 #include "PrecompiledHeader.h"
17 #include "IopCommon.h"
18
19 #include <wx/dir.h>
20 #include <wx/file.h>
21
22 #include "GS.h"
23 #include "CDVD/CDVDisoReader.h"
24
25 #include "Utilities/ScopedPtr.h"
26
27 #if _MSC_VER
28 # include "svnrev.h"
29 #endif
30
31 SysPluginBindings SysPlugins;
32
33 bool SysPluginBindings::McdIsPresent( uint port, uint slot )
34 {
35 return !!Mcd->McdIsPresent( (PS2E_THISPTR) Mcd, port, slot );
36 }
37
38 void SysPluginBindings::McdGetSizeInfo( uint port, uint slot, PS2E_McdSizeInfo& outways )
39 {
40 if( Mcd->McdGetSizeInfo )
41 Mcd->McdGetSizeInfo( (PS2E_THISPTR) Mcd, port, slot, &outways );
42 }
43
44 void SysPluginBindings::McdRead( uint port, uint slot, u8 *dest, u32 adr, int size )
45 {
46 Mcd->McdRead( (PS2E_THISPTR) Mcd, port, slot, dest, adr, size );
47 }
48
49 void SysPluginBindings::McdSave( uint port, uint slot, const u8 *src, u32 adr, int size )
50 {
51 Mcd->McdSave( (PS2E_THISPTR) Mcd, port, slot, src, adr, size );
52 }
53
54 void SysPluginBindings::McdEraseBlock( uint port, uint slot, u32 adr )
55 {
56 Mcd->McdEraseBlock( (PS2E_THISPTR) Mcd, port, slot, adr );
57 }
58
59 u64 SysPluginBindings::McdGetCRC( uint port, uint slot )
60 {
61 return Mcd->McdGetCRC( (PS2E_THISPTR) Mcd, port, slot );
62 }
63
64
65 // ----------------------------------------------------------------------------
66 // Yay, order of this array shouldn't be important. :)
67 //
68 const PluginInfo tbl_PluginInfo[] =
69 {
70 { "GS", PluginId_GS, PS2E_LT_GS, PS2E_GS_VERSION },
71 { "PAD", PluginId_PAD, PS2E_LT_PAD, PS2E_PAD_VERSION },
72 { "SPU2", PluginId_SPU2, PS2E_LT_SPU2, PS2E_SPU2_VERSION },
73 { "CDVD", PluginId_CDVD, PS2E_LT_CDVD, PS2E_CDVD_VERSION },
74 { "USB", PluginId_USB, PS2E_LT_USB, PS2E_USB_VERSION },
75 { "FW", PluginId_FW, PS2E_LT_FW, PS2E_FW_VERSION },
76 { "DEV9", PluginId_DEV9, PS2E_LT_DEV9, PS2E_DEV9_VERSION },
77
78 { NULL },
79
80 // See PluginEnums_t for details on the MemoryCard plugin hack.
81 { "Mcd", PluginId_Mcd, 0, 0 },
82 };
83
84 typedef void CALLBACK VoidMethod();
85 typedef void CALLBACK vMeth(); // shorthand for VoidMethod
86
87 // ----------------------------------------------------------------------------
88 struct LegacyApi_CommonMethod
89 {
90 const char* MethodName;
91
92 // fallback is used if the method is null. If the method is null and fallback is null
93 // also, the plugin is considered incomplete or invalid, and an error is generated.
94 VoidMethod* Fallback;
95
96 // returns the method name as a wxString, converted from UTF8.
97 wxString GetMethodName( PluginsEnum_t pid ) const
98 {
99 return tbl_PluginInfo[pid].GetShortname() + fromUTF8( MethodName );
100 }
101 };
102
103 // ----------------------------------------------------------------------------
104 struct LegacyApi_ReqMethod
105 {
106 const char* MethodName;
107 VoidMethod** Dest; // Target function where the binding is saved.
108
109 // fallback is used if the method is null. If the method is null and fallback is null
110 // also, the plugin is considered incomplete or invalid, and an error is generated.
111 VoidMethod* Fallback;
112
113 // returns the method name as a wxString, converted from UTF8.
114 wxString GetMethodName( ) const
115 {
116 return fromUTF8( MethodName );
117 }
118 };
119
120 // ----------------------------------------------------------------------------
121 struct LegacyApi_OptMethod
122 {
123 const char* MethodName;
124 VoidMethod** Dest; // Target function where the binding is saved.
125
126 // returns the method name as a wxString, converted from UTF8.
127 wxString GetMethodName() const { return fromUTF8( MethodName ); }
128 };
129
130
131 static s32 CALLBACK fallback_freeze(int mode, freezeData *data)
132 {
133 if( mode == FREEZE_SIZE ) data->size = 0;
134 return 0;
135 }
136
137 static void CALLBACK fallback_keyEvent(keyEvent *ev) {}
138 static void CALLBACK fallback_setSettingsDir(const char* dir) {}
139 static void CALLBACK fallback_setLogDir(const char* dir) {}
140 static void CALLBACK fallback_configure() {}
141 static void CALLBACK fallback_about() {}
142 static s32 CALLBACK fallback_test() { return 0; }
143
144 _GSvsync GSvsync;
145 _GSopen GSopen;
146 _GSopen2 GSopen2;
147 _GSgifTransfer GSgifTransfer;
148 _GSgifTransfer1 GSgifTransfer1;
149 _GSgifTransfer2 GSgifTransfer2;
150 _GSgifTransfer3 GSgifTransfer3;
151 _GSgifSoftReset GSgifSoftReset;
152 _GSreadFIFO GSreadFIFO;
153 _GSreadFIFO2 GSreadFIFO2;
154 _GSchangeSaveState GSchangeSaveState;
155 _GSgetTitleInfo2 GSgetTitleInfo2;
156 _GSmakeSnapshot GSmakeSnapshot;
157 _GSmakeSnapshot2 GSmakeSnapshot2;
158 _GSirqCallback GSirqCallback;
159 _GSprintf GSprintf;
160 _GSsetBaseMem GSsetBaseMem;
161 _GSsetGameCRC GSsetGameCRC;
162 _GSsetFrameSkip GSsetFrameSkip;
163 _GSsetVsync GSsetVsync;
164 _GSsetExclusive GSsetExclusive;
165 _GSsetupRecording GSsetupRecording;
166 _GSreset GSreset;
167 _GSwriteCSR GSwriteCSR;
168
169 static void CALLBACK GS_makeSnapshot(const char *path) {}
170 static void CALLBACK GS_setGameCRC(u32 crc, int gameopts) {}
171 static void CALLBACK GS_irqCallback(void (*callback)()) {}
172 static void CALLBACK GS_setFrameSkip(int frameskip) {}
173 static void CALLBACK GS_setVsync(int enabled) {}
174 static void CALLBACK GS_setExclusive(int isExcl) {}
175 static void CALLBACK GS_changeSaveState( int, const char* filename ) {}
176 static void CALLBACK GS_printf(int timeout, char *fmt, ...)
177 {
178 va_list list;
179 char msg[512];
180
181 va_start(list, fmt);
182 vsprintf(msg, fmt, list);
183 va_end(list);
184
185 Console.WriteLn(msg);
186 }
187
188 void CALLBACK GS_getTitleInfo2( char* dest, size_t length )
189 {
190 // Just return a generic "GS" title -- a plugin actually implementing this feature
191 // should return a title such as "GSdx" or "ZZogl" instead. --air
192
193 dest[0] = 'G';
194 dest[1] = 'S';
195 dest[2] = 0;
196 }
197
198 // This legacy passthrough function is needed because the old GS plugins tended to assume that
199 // a PATH1 transfer that didn't EOP needed an automatic EOP (which was needed to avoid a crash
200 // in the BIOS when it starts an XGKICK prior to having an EOP written to VU1 memory). The new
201 // MTGS wraps data around the end of the MTGS buffer, so it often splits PATH1 data into two
202 // transfers now.
203 static void CALLBACK GS_gifTransferLegacy( const u32* src, u32 data )
204 {
205 static __aligned16 u128 path1queue[0x400];
206 static uint path1size = 0;
207
208 const u128* src128 = (u128*)src;
209
210 if( (src128 + data) >= &RingBuffer.m_Ring[RingBufferSize] )
211 {
212 // the transfer is most likely wrapped/partial. We need to queue it into a linear buffer
213 // and then send it on its way on the next copy.
214
215 memcpy_qwc( path1queue, src128, data );
216 path1size = data;
217 }
218 else
219 {
220 if (path1size != 0)
221 {
222 // Previous transfer check. *Most* likely this one should be added to it, but to know for
223 // sure we need to check to see if src points to the head of RingBuffer. If its pointing
224 // to like Ringbuffer[1] instead it means the last transfer finished and this transfer is
225 // a new one.
226
227 if (src128 == RingBuffer.m_Ring)
228 {
229 pxAssume( (data+path1size) <= 0x400 );
230 memcpy_qwc( &path1queue[path1size], src128, data );
231 path1size += data;
232 }
233 GSgifTransfer1( (u32*)path1queue, 0 );
234 path1size = 0;
235 }
236 else
237 {
238 GSgifTransfer1( (u32*)src128, 0 );
239 }
240 }
241 }
242
243
244 // PAD
245 _PADinit PADinit;
246 _PADopen PADopen;
247 _PADstartPoll PADstartPoll;
248 _PADpoll PADpoll;
249 _PADquery PADquery;
250 _PADupdate PADupdate;
251 _PADkeyEvent PADkeyEvent;
252 _PADsetSlot PADsetSlot;
253 _PADqueryMtap PADqueryMtap;
254
255 static void PAD_update( u32 padslot ) { }
256
257 // SPU2
258 _SPU2open SPU2open;
259 _SPU2write SPU2write;
260 _SPU2reset SPU2reset;
261 _SPU2read SPU2read;
262 #ifdef ENABLE_NEW_IOPDMA_SPU2
263 _SPU2dmaRead SPU2dmaRead;
264 _SPU2dmaWrite SPU2dmaWrite;
265 _SPU2dmaInterrupt SPU2dmaInterrupt;
266 #else
267 _SPU2readDMA4Mem SPU2readDMA4Mem;
268 _SPU2writeDMA4Mem SPU2writeDMA4Mem;
269 _SPU2interruptDMA4 SPU2interruptDMA4;
270 _SPU2readDMA7Mem SPU2readDMA7Mem;
271 _SPU2writeDMA7Mem SPU2writeDMA7Mem;
272 _SPU2setDMABaseAddr SPU2setDMABaseAddr;
273 _SPU2interruptDMA7 SPU2interruptDMA7;
274 _SPU2ReadMemAddr SPU2ReadMemAddr;
275 _SPU2WriteMemAddr SPU2WriteMemAddr;
276 #endif
277 _SPU2setupRecording SPU2setupRecording;
278 _SPU2irqCallback SPU2irqCallback;
279
280 _SPU2setClockPtr SPU2setClockPtr;
281 _SPU2async SPU2async;
282
283
284 // DEV9
285 _DEV9open DEV9open;
286 _DEV9read8 DEV9read8;
287 _DEV9read16 DEV9read16;
288 _DEV9read32 DEV9read32;
289 _DEV9write8 DEV9write8;
290 _DEV9write16 DEV9write16;
291 _DEV9write32 DEV9write32;
292 #ifdef ENABLE_NEW_IOPDMA_DEV9
293 _DEV9dmaRead DEV9dmaRead;
294 _DEV9dmaWrite DEV9dmaWrite;
295 _DEV9dmaInterrupt DEV9dmaInterrupt;
296 #else
297 _DEV9readDMA8Mem DEV9readDMA8Mem;
298 _DEV9writeDMA8Mem DEV9writeDMA8Mem;
299 #endif
300 _DEV9irqCallback DEV9irqCallback;
301 _DEV9irqHandler DEV9irqHandler;
302
303 // USB
304 _USBopen USBopen;
305 _USBread8 USBread8;
306 _USBread16 USBread16;
307 _USBread32 USBread32;
308 _USBwrite8 USBwrite8;
309 _USBwrite16 USBwrite16;
310 _USBwrite32 USBwrite32;
311 _USBasync USBasync;
312
313 _USBirqCallback USBirqCallback;
314 _USBirqHandler USBirqHandler;
315 _USBsetRAM USBsetRAM;
316
317 // FW
318 _FWopen FWopen;
319 _FWread32 FWread32;
320 _FWwrite32 FWwrite32;
321 _FWirqCallback FWirqCallback;
322
323 DEV9handler dev9Handler;
324 USBhandler usbHandler;
325 uptr pDsp;
326
327 static s32 CALLBACK _hack_PADinit()
328 {
329 return PADinit( 3 );
330 }
331
332 // ----------------------------------------------------------------------------
333 // Important: Contents of this array must match the order of the contents of the
334 // LegacyPluginAPI_Common structure defined in Plugins.h.
335 //
336 static const LegacyApi_CommonMethod s_MethMessCommon[] =
337 {
338 { "init", NULL },
339 { "close", NULL },
340 { "shutdown", NULL },
341
342 { "keyEvent", (vMeth*)fallback_keyEvent },
343 { "setSettingsDir", (vMeth*)fallback_setSettingsDir },
344 { "setLogDir", (vMeth*)fallback_setLogDir },
345
346 { "freeze", (vMeth*)fallback_freeze },
347 { "test", (vMeth*)fallback_test },
348 { "configure", fallback_configure },
349 { "about", fallback_about },
350
351 { NULL }
352
353 };
354
355 // ----------------------------------------------------------------------------
356 // GS Mess!
357 // ----------------------------------------------------------------------------
358 static const LegacyApi_ReqMethod s_MethMessReq_GS[] =
359 {
360 { "GSopen", (vMeth**)&GSopen, NULL },
361 { "GSvsync", (vMeth**)&GSvsync, NULL },
362 { "GSgifTransfer", (vMeth**)&GSgifTransfer, (vMeth*)GS_gifTransferLegacy },
363 { "GSgifTransfer2", (vMeth**)&GSgifTransfer2, NULL },
364 { "GSgifTransfer3", (vMeth**)&GSgifTransfer3, NULL },
365 { "GSreadFIFO2", (vMeth**)&GSreadFIFO2, NULL },
366
367 { "GSmakeSnapshot", (vMeth**)&GSmakeSnapshot, (vMeth*)GS_makeSnapshot },
368 { "GSirqCallback", (vMeth**)&GSirqCallback, (vMeth*)GS_irqCallback },
369 { "GSprintf", (vMeth**)&GSprintf, (vMeth*)GS_printf },
370 { "GSsetBaseMem", (vMeth**)&GSsetBaseMem, NULL },
371 { "GSwriteCSR", (vMeth**)&GSwriteCSR, NULL },
372 { "GSsetGameCRC", (vMeth**)&GSsetGameCRC, (vMeth*)GS_setGameCRC },
373
374 { "GSsetFrameSkip", (vMeth**)&GSsetFrameSkip, (vMeth*)GS_setFrameSkip },
375 { "GSsetVsync", (vMeth**)&GSsetVsync, (vMeth*)GS_setVsync },
376 { "GSsetExclusive", (vMeth**)&GSsetExclusive, (vMeth*)GS_setExclusive },
377 { "GSchangeSaveState",(vMeth**)&GSchangeSaveState,(vMeth*)GS_changeSaveState },
378 { "GSgetTitleInfo2", (vMeth**)&GSgetTitleInfo2, (vMeth*)GS_getTitleInfo2 },
379 { NULL }
380 };
381
382 static const LegacyApi_OptMethod s_MethMessOpt_GS[] =
383 {
384 { "GSopen2", (vMeth**)&GSopen2 },
385 { "GSreset", (vMeth**)&GSreset },
386 { "GSsetupRecording", (vMeth**)&GSsetupRecording },
387 { "GSmakeSnapshot2", (vMeth**)&GSmakeSnapshot2 },
388 { "GSgifSoftReset", (vMeth**)&GSgifSoftReset },
389 { "GSreadFIFO", (vMeth**)&GSreadFIFO },
390 { "GSgifTransfer1", (vMeth**)&GSgifTransfer1 },
391 { NULL }
392 };
393
394 // ----------------------------------------------------------------------------
395 // PAD Mess!
396 // ----------------------------------------------------------------------------
397 static s32 CALLBACK PAD_queryMtap( u8 slot ) { return 0; }
398 static s32 CALLBACK PAD_setSlot(u8 port, u8 slot) { return 0; }
399
400 static const LegacyApi_ReqMethod s_MethMessReq_PAD[] =
401 {
402 { "PADopen", (vMeth**)&PADopen, NULL },
403 { "PADstartPoll", (vMeth**)&PADstartPoll, NULL },
404 { "PADpoll", (vMeth**)&PADpoll, NULL },
405 { "PADquery", (vMeth**)&PADquery, NULL },
406 { "PADkeyEvent", (vMeth**)&PADkeyEvent, NULL },
407
408 // fixme - Following functions are new as of some revison post-0.9.6, and
409 // are for multitap support only. They should either be optional or offer
410 // NOP fallbacks, to allow older plugins to retain functionality.
411 { "PADsetSlot", (vMeth**)&PADsetSlot, (vMeth*)PAD_setSlot },
412 { "PADqueryMtap", (vMeth**)&PADqueryMtap, (vMeth*)PAD_queryMtap },
413 { NULL },
414 };
415
416 static const LegacyApi_OptMethod s_MethMessOpt_PAD[] =
417 {
418 { "PADupdate", (vMeth**)&PADupdate },
419 { NULL },
420 };
421
422 // ----------------------------------------------------------------------------
423 // CDVD Mess!
424 // ----------------------------------------------------------------------------
425 void CALLBACK CDVD_newDiskCB(void (*callback)()) {}
426
427 extern int lastReadSize, lastLSN;
428 static s32 CALLBACK CDVD_getBuffer2(u8* buffer)
429 {
430 // TEMP: until I fix all the plugins to use this function style
431 u8* pb = CDVD->getBuffer();
432 if(pb == NULL) return -2;
433
434 memcpy_fast( buffer, pb, lastReadSize );
435 return 0;
436 }
437
438 static s32 CALLBACK CDVD_readSector(u8* buffer, u32 lsn, int mode)
439 {
440 if(CDVD->readTrack(lsn,mode) < 0)
441 return -1;
442
443 // TEMP: until all the plugins use the new CDVDgetBuffer style
444 switch (mode)
445 {
446 case CDVD_MODE_2352:
447 lastReadSize = 2352;
448 break;
449 case CDVD_MODE_2340:
450 lastReadSize = 2340;
451 break;
452 case CDVD_MODE_2328:
453 lastReadSize = 2328;
454 break;
455 case CDVD_MODE_2048:
456 lastReadSize = 2048;
457 break;
458 }
459
460 lastLSN = lsn;
461 return CDVD->getBuffer2(buffer);
462 }
463
464 static s32 CALLBACK CDVD_getDualInfo(s32* dualType, u32* layer1Start)
465 {
466 u8 toc[2064];
467
468 // if error getting toc, settle for single layer disc ;)
469 if(CDVD->getTOC(toc))
470 return 0;
471
472 if(toc[14] & 0x60)
473 {
474 if(toc[14] & 0x10)
475 {
476 // otp dvd
477 *dualType = 2;
478 *layer1Start = (toc[25]<<16) + (toc[26]<<8) + (toc[27]) - 0x30000 + 1;
479 }
480 else
481 {
482 // ptp dvd
483 *dualType = 1;
484 *layer1Start = (toc[21]<<16) + (toc[22]<<8) + (toc[23]) - 0x30000 + 1;
485 }
486 }
487 else
488 {
489 // single layer dvd
490 *dualType = 0;
491 *layer1Start = (toc[21]<<16) + (toc[22]<<8) + (toc[23]) - 0x30000 + 1;
492 }
493
494 return 1;
495 }
496
497 CDVD_API CDVDapi_Plugin =
498 {
499 // All of these are filled by the plugin manager
500 NULL
501 };
502
503 CDVD_API* CDVD = NULL;
504
505 static const LegacyApi_ReqMethod s_MethMessReq_CDVD[] =
506 {
507 { "CDVDopen", (vMeth**)&CDVDapi_Plugin.open, NULL },
508 { "CDVDclose", (vMeth**)&CDVDapi_Plugin.close, NULL },
509 { "CDVDreadTrack", (vMeth**)&CDVDapi_Plugin.readTrack, NULL },
510 { "CDVDgetBuffer", (vMeth**)&CDVDapi_Plugin.getBuffer, NULL },
511 { "CDVDreadSubQ", (vMeth**)&CDVDapi_Plugin.readSubQ, NULL },
512 { "CDVDgetTN", (vMeth**)&CDVDapi_Plugin.getTN, NULL },
513 { "CDVDgetTD", (vMeth**)&CDVDapi_Plugin.getTD, NULL },
514 { "CDVDgetTOC", (vMeth**)&CDVDapi_Plugin.getTOC, NULL },
515 { "CDVDgetDiskType", (vMeth**)&CDVDapi_Plugin.getDiskType, NULL },
516 { "CDVDgetTrayStatus",(vMeth**)&CDVDapi_Plugin.getTrayStatus, NULL },
517 { "CDVDctrlTrayOpen", (vMeth**)&CDVDapi_Plugin.ctrlTrayOpen, NULL },
518 { "CDVDctrlTrayClose",(vMeth**)&CDVDapi_Plugin.ctrlTrayClose, NULL },
519 { "CDVDnewDiskCB", (vMeth**)&CDVDapi_Plugin.newDiskCB, (vMeth*)CDVD_newDiskCB },
520
521 { "CDVDreadSector", (vMeth**)&CDVDapi_Plugin.readSector, (vMeth*)CDVD_readSector },
522 { "CDVDgetBuffer2", (vMeth**)&CDVDapi_Plugin.getBuffer2, (vMeth*)CDVD_getBuffer2 },
523 { "CDVDgetDualInfo", (vMeth**)&CDVDapi_Plugin.getDualInfo, (vMeth*)CDVD_getDualInfo },
524
525 { NULL }
526 };
527
528 static const LegacyApi_OptMethod s_MethMessOpt_CDVD[] =
529 {
530 { NULL }
531 };
532
533 // ----------------------------------------------------------------------------
534 // SPU2 Mess!
535 // ----------------------------------------------------------------------------
536
537 // manualized reset that writes core reset registers of the SPU2 plugin:
538 static void CALLBACK SPU2_Reset()
539 {
540 SPU2write( 0x1f90019A, 1<<15 ); // core 0
541 SPU2write( 0x1f90059A, 1<<15 ); // core 1
542 }
543
544 static const LegacyApi_ReqMethod s_MethMessReq_SPU2[] =
545 {
546 { "SPU2open", (vMeth**)&SPU2open, NULL },
547 { "SPU2reset", (vMeth**)&SPU2reset, SPU2_Reset },
548 { "SPU2write", (vMeth**)&SPU2write, NULL },
549 { "SPU2read", (vMeth**)&SPU2read, NULL },
550 #ifdef ENABLE_NEW_IOPDMA_SPU2
551 { "SPU2dmaRead", (vMeth**)&SPU2dmaRead, NULL },
552 { "SPU2dmaWrite", (vMeth**)&SPU2dmaWrite, NULL },
553 { "SPU2dmaInterrupt", (vMeth**)&SPU2dmaInterrupt, NULL },
554 #else
555 { "SPU2readDMA4Mem", (vMeth**)&SPU2readDMA4Mem, NULL },
556 { "SPU2readDMA7Mem", (vMeth**)&SPU2readDMA7Mem, NULL },
557 { "SPU2writeDMA4Mem", (vMeth**)&SPU2writeDMA4Mem, NULL },
558 { "SPU2writeDMA7Mem", (vMeth**)&SPU2writeDMA7Mem, NULL },
559 { "SPU2interruptDMA4", (vMeth**)&SPU2interruptDMA4,NULL },
560 { "SPU2interruptDMA7", (vMeth**)&SPU2interruptDMA7,NULL },
561 { "SPU2ReadMemAddr", (vMeth**)&SPU2ReadMemAddr, NULL },
562 #endif
563 { "SPU2irqCallback", (vMeth**)&SPU2irqCallback, NULL },
564
565 { NULL }
566 };
567
568 static const LegacyApi_OptMethod s_MethMessOpt_SPU2[] =
569 {
570 { "SPU2setClockPtr", (vMeth**)&SPU2setClockPtr },
571 { "SPU2async", (vMeth**)&SPU2async },
572 #ifndef ENABLE_NEW_IOPDMA_SPU2
573 { "SPU2WriteMemAddr", (vMeth**)&SPU2WriteMemAddr },
574 { "SPU2setDMABaseAddr", (vMeth**)&SPU2setDMABaseAddr},
575 #endif
576 { "SPU2setupRecording", (vMeth**)&SPU2setupRecording},
577
578 { NULL }
579 };
580
581 // ----------------------------------------------------------------------------
582 // DEV9 Mess!
583 // ----------------------------------------------------------------------------
584 static const LegacyApi_ReqMethod s_MethMessReq_DEV9[] =
585 {
586 { "DEV9open", (vMeth**)&DEV9open, NULL },
587 { "DEV9read8", (vMeth**)&DEV9read8, NULL },
588 { "DEV9read16", (vMeth**)&DEV9read16, NULL },
589 { "DEV9read32", (vMeth**)&DEV9read32, NULL },
590 { "DEV9write8", (vMeth**)&DEV9write8, NULL },
591 { "DEV9write16", (vMeth**)&DEV9write16, NULL },
592 { "DEV9write32", (vMeth**)&DEV9write32, NULL },
593 #ifdef ENABLE_NEW_IOPDMA_DEV9
594 { "DEV9dmaRead", (vMeth**)&DEV9dmaRead, NULL },
595 { "DEV9dmaWrite", (vMeth**)&DEV9dmaWrite, NULL },
596 { "DEV9dmaInterrupt", (vMeth**)&DEV9dmaInterrupt, NULL },
597 #else
598 { "DEV9readDMA8Mem", (vMeth**)&DEV9readDMA8Mem, NULL },
599 { "DEV9writeDMA8Mem", (vMeth**)&DEV9writeDMA8Mem, NULL },
600 #endif
601 { "DEV9irqCallback", (vMeth**)&DEV9irqCallback, NULL },
602 { "DEV9irqHandler", (vMeth**)&DEV9irqHandler, NULL },
603
604 { NULL }
605 };
606
607 static const LegacyApi_OptMethod s_MethMessOpt_DEV9[] =
608 {
609 { NULL }
610 };
611
612 // ----------------------------------------------------------------------------
613 // USB Mess!
614 // ----------------------------------------------------------------------------
615 static const LegacyApi_ReqMethod s_MethMessReq_USB[] =
616 {
617 { "USBopen", (vMeth**)&USBopen, NULL },
618 { "USBread8", (vMeth**)&USBread8, NULL },
619 { "USBread16", (vMeth**)&USBread16, NULL },
620 { "USBread32", (vMeth**)&USBread32, NULL },
621 { "USBwrite8", (vMeth**)&USBwrite8, NULL },
622 { "USBwrite16", (vMeth**)&USBwrite16, NULL },
623 { "USBwrite32", (vMeth**)&USBwrite32, NULL },
624 { "USBirqCallback", (vMeth**)&USBirqCallback, NULL },
625 { "USBirqHandler", (vMeth**)&USBirqHandler, NULL },
626 { NULL }
627 };
628
629 static const LegacyApi_OptMethod s_MethMessOpt_USB[] =
630 {
631 { "USBasync", (vMeth**)&USBasync },
632 { NULL }
633 };
634
635 // ----------------------------------------------------------------------------
636 // FW Mess!
637 // ----------------------------------------------------------------------------
638 static const LegacyApi_ReqMethod s_MethMessReq_FW[] =
639 {
640 { "FWopen", (vMeth**)&FWopen, NULL },
641 { "FWread32", (vMeth**)&FWread32, NULL },
642 { "FWwrite32", (vMeth**)&FWwrite32, NULL },
643 { "FWirqCallback", (vMeth**)&FWirqCallback, NULL },
644 { NULL }
645 };
646
647 static const LegacyApi_OptMethod s_MethMessOpt_FW[] =
648 {
649 { NULL }
650 };
651
652 static const LegacyApi_ReqMethod* const s_MethMessReq[] =
653 {
654 s_MethMessReq_GS,
655 s_MethMessReq_PAD,
656 s_MethMessReq_SPU2,
657 s_MethMessReq_CDVD,
658 s_MethMessReq_USB,
659 s_MethMessReq_FW,
660 s_MethMessReq_DEV9
661 };
662
663 static const LegacyApi_OptMethod* const s_MethMessOpt[] =
664 {
665 s_MethMessOpt_GS,
666 s_MethMessOpt_PAD,
667 s_MethMessOpt_SPU2,
668 s_MethMessOpt_CDVD,
669 s_MethMessOpt_USB,
670 s_MethMessOpt_FW,
671 s_MethMessOpt_DEV9
672 };
673
674 SysCorePlugins *g_plugins = NULL;
675
676 // ---------------------------------------------------------------------------------
677 // Plugin-related Exception Implementations
678 // ---------------------------------------------------------------------------------
679
680 wxString Exception::SaveStateLoadError::FormatDiagnosticMessage() const
681 {
682 FastFormatUnicode retval;
683 retval.Write("Savestate is corrupt or incomplete!");
684 _formatDiagMsg(retval);
685 return retval;
686 }
687
688 wxString Exception::SaveStateLoadError::FormatDisplayMessage() const
689 {
690 FastFormatUnicode retval;
691 retval.Write(_("The savestate cannot be loaded, as it appears to be corrupt or incomplete."));
692 _formatUserMsg(retval);
693 return retval;
694 }
695
696 Exception::PluginOpenError::PluginOpenError( PluginsEnum_t pid )
697 {
698 PluginId = pid;
699 m_message_diag = L"%s plugin failed to open!";
700 m_message_user = _("%s plugin failed to open. Your computer may have insufficient resources, or incompatible hardware/drivers.");
701 }
702
703 Exception::PluginInitError::PluginInitError( PluginsEnum_t pid )
704 {
705 PluginId = pid;
706 m_message_diag = L"%s plugin initialization failed!";
707 m_message_user = _("%s plugin failed to initialize. Your system may have insufficient memory or resources needed.");
708 }
709
710 Exception::PluginLoadError::PluginLoadError( PluginsEnum_t pid )
711 {
712 PluginId = pid;
713 }
714
715 wxString Exception::PluginLoadError::FormatDiagnosticMessage() const
716 {
717 return pxsFmt( m_message_diag, tbl_PluginInfo[PluginId].GetShortname().c_str() ) +
718 L"\n\n" + StreamName;
719 }
720
721 wxString Exception::PluginLoadError::FormatDisplayMessage() const
722 {
723 return pxsFmt( m_message_user, tbl_PluginInfo[PluginId].GetShortname().c_str() ) +
724 L"\n\n" + StreamName;
725 }
726
727 wxString Exception::PluginError::FormatDiagnosticMessage() const
728 {
729 return pxsFmt( m_message_diag, tbl_PluginInfo[PluginId].GetShortname().c_str() );
730 }
731
732 wxString Exception::PluginError::FormatDisplayMessage() const
733 {
734 return pxsFmt( m_message_user, tbl_PluginInfo[PluginId].GetShortname().c_str() );
735 }
736
737 wxString Exception::FreezePluginFailure::FormatDiagnosticMessage() const
738 {
739 return pxsFmt(
740 L"%s plugin returned an error while saving the state.\n\n",
741 tbl_PluginInfo[PluginId].shortname
742 );
743 }
744
745 wxString Exception::FreezePluginFailure::FormatDisplayMessage() const
746 {
747 // [TODO]
748 return m_message_user;
749 }
750
751 wxString Exception::ThawPluginFailure::FormatDiagnosticMessage() const
752 {
753 return pxsFmt(
754 L"%s plugin returned an error while loading the state.\n\n",
755 tbl_PluginInfo[PluginId].shortname
756 );
757 }
758
759 wxString Exception::ThawPluginFailure::FormatDisplayMessage() const
760 {
761 // [TODO]
762 return m_message_user;
763 }
764
765 // --------------------------------------------------------------------------------------
766 // PCSX2 Callbacks passed to Plugins
767 // --------------------------------------------------------------------------------------
768 // This is currently unimplemented, and should be provided by the AppHost (gui) rather
769 // than the EmuCore. But as a quickhackfix until the new plugin API is fleshed out, this
770 // will suit our needs nicely. :)
771
772 static BOOL PS2E_CALLBACK pcsx2_GetInt( const char* name, int* dest )
773 {
774 return FALSE; // not implemented...
775 }
776
777 static BOOL PS2E_CALLBACK pcsx2_GetBoolean( const char* name, BOOL* result )
778 {
779 return FALSE; // not implemented...
780 }
781
782 static BOOL PS2E_CALLBACK pcsx2_GetString( const char* name, char* dest, int maxlen )
783 {
784 return FALSE; // not implemented...
785 }
786
787 static char* PS2E_CALLBACK pcsx2_GetStringAlloc( const char* name, void* (PS2E_CALLBACK* allocator)(int size) )
788 {
789 return FALSE; // not implemented...
790 }
791
792 static void PS2E_CALLBACK pcsx2_OSD_WriteLn( int icon, const char* msg )
793 {
794 return; // not implemented...
795 }
796
797 // ---------------------------------------------------------------------------------
798 // PluginStatus_t Implementations
799 // ---------------------------------------------------------------------------------
800 SysCorePlugins::PluginStatus_t::PluginStatus_t( PluginsEnum_t _pid, const wxString& srcfile )
801 : Filename( srcfile )
802 {
803 pid = _pid;
804
805 IsInitialized = false;
806 IsOpened = false;
807
808 if( Filename.IsEmpty() )
809 throw Exception::PluginInitError( pid ).SetDiagMsg( L"Empty plugin filename" );
810
811 if( !wxFile::Exists( Filename ) )
812 throw Exception::PluginLoadError( pid ).SetStreamName(srcfile)
813 .SetBothMsgs(wxLt("The configured %s plugin file was not found"));
814
815 if( !Lib.Load( Filename ) )
816 throw Exception::PluginLoadError( pid ).SetStreamName(Filename)
817 .SetBothMsgs(wxLt("The configured %s plugin file is not a valid dynamic library"));
818
819
820 // Try to enumerate the new v2.0 plugin interface first.
821 // If that fails, fall back on the old style interface.
822
823 //m_libs[i].GetSymbol( L"PS2E_InitAPI" ); // on the TODO list!
824
825
826 // 2.0 API Failed; Enumerate the Old Stuff! -->
827
828 _PS2EgetLibName GetLibName = (_PS2EgetLibName) Lib.GetSymbol( L"PS2EgetLibName" );
829 _PS2EgetLibVersion2 GetLibVersion2 = (_PS2EgetLibVersion2) Lib.GetSymbol( L"PS2EgetLibVersion2" );
830 _PS2EsetEmuVersion SetEmuVersion = (_PS2EsetEmuVersion) Lib.GetSymbol( L"PS2EsetEmuVersion" );
831
832 if( GetLibName == NULL || GetLibVersion2 == NULL )
833 throw Exception::PluginLoadError( pid ).SetStreamName(Filename)
834 .SetDiagMsg(L"%s plugin init failed: Method binding failure on GetLibName or GetLibVersion2.")
835 .SetUserMsg(_( "The configured %s plugin is not a PCSX2 plugin, or is for an older unsupported version of PCSX2."));
836
837 if( SetEmuVersion != NULL )
838 SetEmuVersion( "PCSX2", (0ul << 24) | (9ul<<16) | (7ul<<8) | 0 );
839
840 Name = fromUTF8( GetLibName() );
841 int version = GetLibVersion2( tbl_PluginInfo[pid].typemask );
842 Version.Printf( L"%d.%d.%d", (version>>8)&0xff, version&0xff, (version>>24)&0xff );
843
844
845 // Bind Required Functions
846 // (generate critical error if binding fails)
847
848 BindCommon( pid );
849 BindRequired( pid );
850 BindOptional( pid );
851
852 // Run Plugin's Functionality Test.
853 // A lot of plugins don't bother to implement this function and return 0 (success)
854 // regardless, but some do so let's go ahead and check it. I mean, we're supposed to. :)
855
856 int testres = CommonBindings.Test();
857 if( testres != 0 )
858 throw Exception::PluginLoadError( pid ).SetStreamName(Filename)
859 .SetDiagMsg(wxsFormat( L"Plugin Test failure, return code: %d", testres ))
860 .SetUserMsg(_("The plugin reports that your hardware or software/drivers are not supported."));
861 }
862
863 void SysCorePlugins::PluginStatus_t::BindCommon( PluginsEnum_t pid )
864 {
865 const LegacyApi_CommonMethod* current = s_MethMessCommon;
866 VoidMethod** target = (VoidMethod**)&CommonBindings;
867
868 wxDoNotLogInThisScope please;
869
870 while( current->MethodName != NULL )
871 {
872 *target = (VoidMethod*)Lib.GetSymbol( current->GetMethodName( pid ) );
873
874 if( *target == NULL )
875 *target = current->Fallback;
876
877 if( *target == NULL )
878 {
879 throw Exception::PluginLoadError( pid ).SetStreamName(Filename)
880 .SetDiagMsg(wxsFormat( L"\nMethod binding failure on: %s\n", current->GetMethodName( pid ).c_str() ))
881 .SetUserMsg(_("Configured plugin is not a PCSX2 plugin, or is for an older unsupported version of PCSX2."));
882 }
883
884 target++;
885 current++;
886 }
887 }
888
889 void SysCorePlugins::PluginStatus_t::BindRequired( PluginsEnum_t pid )
890 {
891 const LegacyApi_ReqMethod* current = s_MethMessReq[pid];
892 const wxDynamicLibrary& lib = Lib;
893
894 wxDoNotLogInThisScope please;
895
896 while( current->MethodName != NULL )
897 {
898 *(current->Dest) = (VoidMethod*)lib.GetSymbol( current->GetMethodName() );
899
900 if( *(current->Dest) == NULL )
901 *(current->Dest) = current->Fallback;
902
903 if( *(current->Dest) == NULL )
904 {
905 throw Exception::PluginLoadError( pid ).SetStreamName(Filename)
906 .SetDiagMsg(wxsFormat( L"\n%s plugin init error; Method binding failed: %s\n", current->GetMethodName().c_str() ))
907 .SetUserMsg(_( "Configured %s plugin is not a valid PCSX2 plugin, or is for an older unsupported version of PCSX2."));
908 }
909
910 current++;
911 }
912 }
913
914 void SysCorePlugins::PluginStatus_t::BindOptional( PluginsEnum_t pid )
915 {
916 const LegacyApi_OptMethod* current = s_MethMessOpt[pid];
917 const wxDynamicLibrary& lib = Lib;
918
919 wxDoNotLogInThisScope please;
920
921 while( current->MethodName != NULL )
922 {
923 *(current->Dest) = (VoidMethod*)lib.GetSymbol( current->GetMethodName() );
924 current++;
925 }
926 }
927
928 // =====================================================================================
929 // SysCorePlugins Implementations
930 // =====================================================================================
931
932 SysCorePlugins::SysCorePlugins()
933 {
934 }
935
936 SysCorePlugins::~SysCorePlugins() throw()
937 {
938 try
939 {
940 Unload();
941 }
942 DESTRUCTOR_CATCHALL
943
944 // All library unloading done automatically by wx.
945 }
946
947 void SysCorePlugins::Load( PluginsEnum_t pid, const wxString& srcfile )
948 {
949 ScopedLock lock( m_mtx_PluginStatus );
950 pxAssume( (uint)pid < PluginId_Count );
951 Console.Indent().WriteLn( L"Binding %s\t: %s ", tbl_PluginInfo[pid].GetShortname().c_str(), srcfile.c_str() );
952 m_info[pid] = new PluginStatus_t( pid, srcfile );
953 }
954
955 void SysCorePlugins::Load( const wxString (&folders)[PluginId_Count] )
956 {
957 if( !NeedsLoad() ) return;
958
959 wxDoNotLogInThisScope please;
960
961 Console.WriteLn( Color_StrongBlue, "\nLoading plugins..." );
962
963 ConsoleIndentScope indent;
964 const PluginInfo* pi = tbl_PluginInfo; do
965 {
966 Load( pi->id, folders[pi->id] );
967 pxYield( 2 );
968
969 } while( ++pi, pi->shortname != NULL );
970 indent.LeaveScope();
971
972 CDVDapi_Plugin.newDiskCB( cdvdNewDiskCB );
973
974 // Hack for PAD's stupid parameter passed on Init
975 PADinit = (_PADinit)m_info[PluginId_PAD]->CommonBindings.Init;
976 m_info[PluginId_PAD]->CommonBindings.Init = _hack_PADinit;
977
978 Console.WriteLn( Color_StrongBlue, "Plugins loaded successfully.\n" );
979
980 // HACK! Manually bind the Internal MemoryCard plugin for now, until
981 // we get things more completed in the new plugin api.
982
983 static const PS2E_EmulatorInfo myself =
984 {
985 "PCSX2",
986
987 { 0, PCSX2_VersionHi, PCSX2_VersionLo, SVN_REV },
988
989 x86caps.PhysicalCores,
990 x86caps.LogicalCores,
991 sizeof(wchar_t),
992
993 0,0,0,0,0,0,
994
995 pcsx2_GetInt,
996 pcsx2_GetBoolean,
997 pcsx2_GetString,
998 pcsx2_GetStringAlloc,
999 pcsx2_OSD_WriteLn
1000 };
1001
1002 m_mcdPlugin = FileMcd_InitAPI( &myself );
1003 if( m_mcdPlugin == NULL )
1004 {
1005 // fixme: use plugin's GetLastError (not implemented yet!)
1006 throw Exception::PluginLoadError( PluginId_Mcd ).SetDiagMsg(L"Internal Memorycard Plugin failed to load.");
1007 }
1008
1009 SendLogFolder();
1010 SendSettingsFolder();
1011 }
1012
1013 void SysCorePlugins::Unload(PluginsEnum_t pid)
1014 {
1015 ScopedLock lock( m_mtx_PluginStatus );
1016 pxAssume( (uint)pid < PluginId_Count );
1017 m_info[pid].Delete();
1018 }
1019
1020 void SysCorePlugins::Unload()
1021 {
1022 if( NeedsShutdown() )
1023 Console.Warning( "(SysCorePlugins) Warning: Unloading plugins prior to shutdown!" );
1024
1025 //Shutdown();
1026
1027 if( !NeedsUnload() ) return;
1028
1029 DbgCon.WriteLn( Color_StrongBlue, "Unloading plugins..." );
1030
1031 for( int i=PluginId_Count-1; i>=0; --i )
1032 Unload( tbl_PluginInfo[i].id );
1033
1034 DbgCon.WriteLn( Color_StrongBlue, "Plugins unloaded successfully." );
1035 }
1036
1037 // Exceptions:
1038 // FileNotFound - Thrown if one of the configured plugins doesn't exist.
1039 // NotPcsxPlugin - Thrown if one of the configured plugins is an invalid or unsupported DLL
1040
1041 extern bool renderswitch;
1042 extern void spu2DMA4Irq();
1043 extern void spu2DMA7Irq();
1044 extern void spu2Irq();
1045
1046 bool SysCorePlugins::OpenPlugin_CDVD()
1047 {
1048 return DoCDVDopen();
1049 }
1050
1051 bool SysCorePlugins::OpenPlugin_GS()
1052 {
1053 GetMTGS().Resume();
1054 return true;
1055 }
1056
1057 bool SysCorePlugins::OpenPlugin_PAD()
1058 {
1059 return !PADopen( (void*)&pDsp );
1060 }
1061
1062 bool SysCorePlugins::OpenPlugin_SPU2()
1063 {
1064 if( SPU2open((void*)&pDsp) ) return false;
1065
1066 #ifdef ENABLE_NEW_IOPDMA_SPU2
1067 SPU2irqCallback( spu2Irq );
1068 #else
1069 SPU2irqCallback( spu2Irq, spu2DMA4Irq, spu2DMA7Irq );
1070 if( SPU2setDMABaseAddr != NULL ) SPU2setDMABaseAddr((uptr)iopMem->Main);
1071 #endif
1072 if( SPU2setClockPtr != NULL ) SPU2setClockPtr(&psxRegs.cycle);
1073 return true;
1074 }
1075
1076 bool SysCorePlugins::OpenPlugin_DEV9()
1077 {
1078 dev9Handler = NULL;
1079
1080 if( DEV9open( (void*)&pDsp ) ) return false;
1081 DEV9irqCallback( dev9Irq );
1082 dev9Handler = DEV9irqHandler();
1083 return true;
1084 }
1085
1086 bool SysCorePlugins::OpenPlugin_USB()
1087 {
1088 usbHandler = NULL;
1089
1090 if( USBopen((void*)&pDsp) ) return false;
1091 USBirqCallback( usbIrq );
1092 usbHandler = USBirqHandler();
1093 if( USBsetRAM != NULL )
1094 USBsetRAM(iopMem->Main);
1095 return true;
1096 }
1097
1098 bool SysCorePlugins::OpenPlugin_FW()
1099 {
1100 if( FWopen((void*)&pDsp) ) return false;
1101 FWirqCallback( fwIrq );
1102 return true;
1103 }
1104
1105 bool SysCorePlugins::OpenPlugin_Mcd()
1106 {
1107 ScopedLock lock( m_mtx_PluginStatus );
1108
1109 // [TODO] Fix up and implement PS2E_SessionInfo here!! (the currently NULL parameter)
1110 if( SysPlugins.Mcd )
1111 SysPlugins.Mcd->Base.EmuOpen( (PS2E_THISPTR) SysPlugins.Mcd, NULL );
1112
1113 return true;
1114 }
1115
1116 void SysCorePlugins::Open( PluginsEnum_t pid )
1117 {
1118 pxAssume( (uint)pid < PluginId_Count );
1119 if( IsOpen(pid) ) return;
1120
1121 Console.Indent().WriteLn( "Opening %s", tbl_PluginInfo[pid].shortname );
1122
1123 // Each Open needs to be called explicitly. >_<
1124
1125 bool result = true;
1126 switch( pid )
1127 {
1128 case PluginId_GS: result = OpenPlugin_GS(); break;
1129 case PluginId_PAD: result = OpenPlugin_PAD(); break;
1130 case PluginId_CDVD: result = OpenPlugin_CDVD(); break;
1131 case PluginId_SPU2: result = OpenPlugin_SPU2(); break;
1132 case PluginId_USB: result = OpenPlugin_USB(); break;
1133 case PluginId_FW: result = OpenPlugin_FW(); break;
1134 case PluginId_DEV9: result = OpenPlugin_DEV9(); break;
1135
1136 jNO_DEFAULT;
1137 }
1138 if( !result )
1139 throw Exception::PluginOpenError( pid );
1140
1141 ScopedLock lock( m_mtx_PluginStatus );
1142 if( m_info[pid] ) m_info[pid]->IsOpened = true;
1143 }
1144
1145 void SysCorePlugins::Open()
1146 {
1147 Init();
1148
1149 if( !NeedsOpen() ) return; // Spam stopper: returns before writing any logs. >_<
1150
1151 Console.WriteLn( Color_StrongBlue, "Opening plugins..." );
1152
1153 SendSettingsFolder();
1154
1155 const PluginInfo* pi = tbl_PluginInfo; do {
1156 Open( pi->id );
1157 // If GS doesn't support GSopen2, need to wait until call to GSopen
1158 // returns to populate pDsp. If it does, can initialize other plugins
1159 // at same time as GS, as long as GSopen2 does not subclass its window.
1160 if (pi->id == PluginId_GS && !GSopen2) GetMTGS().WaitForOpen();
1161 } while( ++pi, pi->shortname != NULL );
1162
1163 if (GSopen2) GetMTGS().WaitForOpen();
1164
1165 if( !AtomicExchange( m_mcdOpen, true ) )
1166 {
1167 DbgCon.Indent().WriteLn( "Opening Memorycards");
1168 OpenPlugin_Mcd();
1169 }
1170
1171 Console.WriteLn( Color_StrongBlue, "Plugins opened successfully." );
1172 }
1173
1174 void SysCorePlugins::_generalclose( PluginsEnum_t pid )
1175 {
1176 ScopedLock lock( m_mtx_PluginStatus );
1177 if( m_info[pid] ) m_info[pid]->CommonBindings.Close();
1178 }
1179
1180 void SysCorePlugins::ClosePlugin_GS()
1181 {
1182 // old-skool: force-close PAD before GS, because the PAD depends on the GS window.
1183
1184 if( GetMTGS().IsSelf() )
1185 _generalclose( PluginId_GS );
1186 else
1187 {
1188 if( !GSopen2 ) Close( PluginId_PAD );
1189 GetMTGS().Suspend();
1190 }
1191 }
1192
1193 void SysCorePlugins::ClosePlugin_CDVD()
1194 {
1195 DoCDVDclose();
1196 }
1197
1198 void SysCorePlugins::ClosePlugin_PAD()
1199 {
1200 _generalclose( PluginId_PAD );
1201 }
1202
1203 void SysCorePlugins::ClosePlugin_SPU2()
1204 {
1205 _generalclose( PluginId_SPU2 );
1206 }
1207
1208 void SysCorePlugins::ClosePlugin_DEV9()
1209 {
1210 _generalclose( PluginId_DEV9 );
1211 }
1212
1213 void SysCorePlugins::ClosePlugin_USB()
1214 {
1215 _generalclose( PluginId_USB );
1216 }
1217
1218 void SysCorePlugins::ClosePlugin_FW()
1219 {
1220 _generalclose( PluginId_FW );
1221 }
1222
1223 void SysCorePlugins::ClosePlugin_Mcd()
1224 {
1225 ScopedLock lock( m_mtx_PluginStatus );
1226 if( SysPlugins.Mcd ) SysPlugins.Mcd->Base.EmuClose( (PS2E_THISPTR) SysPlugins.Mcd );
1227 }
1228
1229 void SysCorePlugins::Close( PluginsEnum_t pid )
1230 {
1231 pxAssume( (uint)pid < PluginId_Count );
1232
1233 if( !IsOpen(pid) ) return;
1234
1235 if( !GetMTGS().IsSelf() ) // stop the spam!
1236 Console.Indent().WriteLn( "Closing %s", tbl_PluginInfo[pid].shortname );
1237
1238 switch( pid )
1239 {
1240 case PluginId_GS: ClosePlugin_GS(); break;
1241 case PluginId_PAD: ClosePlugin_PAD(); break;
1242 case PluginId_CDVD: ClosePlugin_CDVD(); break;
1243 case PluginId_SPU2: ClosePlugin_SPU2(); break;
1244 case PluginId_USB: ClosePlugin_USB(); break;
1245 case PluginId_FW: ClosePlugin_FW(); break;
1246 case PluginId_DEV9: ClosePlugin_DEV9(); break;
1247 case PluginId_Mcd: ClosePlugin_Mcd(); break;
1248
1249 jNO_DEFAULT;
1250 }
1251
1252 ScopedLock lock( m_mtx_PluginStatus );
1253 if( m_info[pid] ) m_info[pid]->IsOpened = false;
1254 }
1255
1256 void SysCorePlugins::Close()
1257 {
1258 if( !NeedsClose() ) return; // Spam stopper; returns before writing any logs. >_<
1259
1260 // Close plugins in reverse order of the initialization procedure, which
1261 // ensures the GS gets closed last.
1262
1263 Console.WriteLn( Color_StrongBlue, "Closing plugins..." );
1264
1265 if( AtomicExchange( m_mcdOpen, false ) )
1266 {
1267 DbgCon.Indent().WriteLn( "Closing Memorycards");
1268 ClosePlugin_Mcd();
1269 }
1270
1271 for( int i=PluginId_Count-1; i>=0; --i )
1272 Close( tbl_PluginInfo[i].id );
1273
1274 Console.WriteLn( Color_StrongBlue, "Plugins closed successfully." );
1275 }
1276
1277 void SysCorePlugins::Init( PluginsEnum_t pid )
1278 {
1279 ScopedLock lock( m_mtx_PluginStatus );
1280
1281 if( !m_info[pid] || m_info[pid]->IsInitialized ) return;
1282
1283 Console.Indent().WriteLn( "Init %s", tbl_PluginInfo[pid].shortname );
1284 if( 0 != m_info[pid]->CommonBindings.Init() )
1285 throw Exception::PluginInitError( pid );
1286
1287 m_info[pid]->IsInitialized = true;
1288 }
1289
1290 void SysCorePlugins::Shutdown( PluginsEnum_t pid )
1291 {
1292 ScopedLock lock( m_mtx_PluginStatus );
1293
1294 if( !m_info[pid] || !m_info[pid]->IsInitialized ) return;
1295 DevCon.Indent().WriteLn( "Shutdown %s", tbl_PluginInfo[pid].shortname );
1296 m_info[pid]->IsInitialized = false;
1297 m_info[pid]->CommonBindings.Shutdown();
1298 }
1299
1300 // Initializes all plugins. Plugin initialization should be done once for every new emulation
1301 // session. During a session emulation can be paused/resumed using Open/Close, and should be
1302 // terminated using Shutdown().
1303 //
1304 // Returns TRUE if an init was performed for any (or all) plugins. Returns FALSE if all
1305 // plugins were already in an initialized state (no action taken).
1306 //
1307 // In a purist emulation sense, Init() and Shutdown() should only ever need be called for when
1308 // the PS2's hardware has received a *full* hard reset. Soft resets typically should rely on
1309 // the PS2's bios/kernel to re-initialize hardware on the fly.
1310 //
1311 bool SysCorePlugins::Init()
1312 {
1313 if( !NeedsInit() ) return false;
1314
1315 Console.WriteLn( Color_StrongBlue, "\nInitializing plugins..." );
1316 const PluginInfo* pi = tbl_PluginInfo; do {
1317 Init( pi->id );
1318 } while( ++pi, pi->shortname != NULL );
1319
1320 if( SysPlugins.Mcd == NULL )
1321 {
1322 SysPlugins.Mcd = (PS2E_ComponentAPI_Mcd*)m_mcdPlugin->NewComponentInstance( PS2E_TYPE_Mcd );
1323 if( SysPlugins.Mcd == NULL )
1324 {
1325 // fixme: use plugin's GetLastError (not implemented yet!)
1326 throw Exception::PluginInitError( PluginId_Mcd )
1327 .SetBothMsgs(wxLt("Internal Memorycard Plugin failed to initialize."));
1328 }
1329 }
1330
1331 Console.WriteLn( Color_StrongBlue, "Plugins initialized successfully.\n" );
1332
1333 return true;
1334 }
1335
1336
1337 // Shuts down all plugins. Plugins are closed first, if necessary.
1338 // Returns TRUE if a shutdown was performed for any (or all) plugins. Returns FALSE if all
1339 // plugins were already in shutdown state (no action taken).
1340 //
1341 // In a purist emulation sense, Init() and Shutdown() should only ever need be called for when
1342 // the PS2's hardware has received a *full* hard reset. Soft resets typically should rely on
1343 // the PS2's bios/kernel to re-initialize hardware on the fly.
1344 //
1345 bool SysCorePlugins::Shutdown()
1346 {
1347 if( !NeedsShutdown() ) return false;
1348
1349 pxAssertDev( !NeedsClose(), "Cannot shut down plugins prior to Close()" );
1350
1351 GetMTGS().Cancel(); // cancel it for speedier shutdown!
1352
1353 Console.WriteLn( Color_StrongGreen, "Shutting down plugins..." );
1354
1355 // Shutdown plugins in reverse order (probably doesn't matter...
1356 // ... but what the heck, right?)
1357
1358 for( int i=PluginId_Count-1; i>=0; --i )
1359 {
1360 Shutdown( tbl_PluginInfo[i].id );
1361 }
1362
1363 // More memorycard hacks!!
1364
1365 if( (SysPlugins.Mcd != NULL) && (m_mcdPlugin != NULL) )
1366 {
1367 m_mcdPlugin->DeleteComponentInstance( (PS2E_THISPTR)SysPlugins.Mcd );
1368 SysPlugins.Mcd = NULL;
1369 }
1370
1371 Console.WriteLn( Color_StrongGreen, "Plugins shutdown successfully." );
1372
1373 return true;
1374 }
1375
1376 // For internal use only, unless you're the MTGS. Then it's for you too!
1377 // Returns false if the plugin returned an error.
1378 bool SysCorePlugins::DoFreeze( PluginsEnum_t pid, int mode, freezeData* data )
1379 {
1380 if( (pid == PluginId_GS) && !GetMTGS().IsSelf() )
1381 {
1382 // GS needs some thread safety love...
1383
1384 MTGS_FreezeData woot = { data, 0 };
1385 GetMTGS().Freeze( mode, woot );
1386 return woot.retval != -1;
1387 }
1388 else
1389 {
1390 ScopedLock lock( m_mtx_PluginStatus );
1391 return !m_info[pid] || m_info[pid]->CommonBindings.Freeze( mode, data ) != -1;
1392 }
1393 }
1394
1395 // Thread Safety:
1396 // This function should only be called by the Main GUI thread and the GS thread (for GS states only),
1397 // as it has special handlers to ensure that GS freeze commands are executed appropriately on the
1398 // GS thread.
1399 //
1400 void SysCorePlugins::Freeze( PluginsEnum_t pid, SaveStateBase& state )
1401 {
1402 // No locking leeded -- DoFreeze locks as needed, and this avoids MTGS deadlock.
1403 //ScopedLock lock( m_mtx_PluginStatus );
1404
1405 Console.Indent().WriteLn( "%s %s", state.IsSaving() ? "Saving" : "Loading",
1406 tbl_PluginInfo[pid].shortname );
1407
1408 freezeData fP = { 0, NULL };
1409 if( !DoFreeze( pid, FREEZE_SIZE, &fP ) )
1410 fP.size = 0;
1411
1412 int fsize = fP.size;
1413 state.Freeze( fsize );
1414
1415 if( state.IsLoading() && (fsize == 0) )
1416 {
1417 // no state data to read, but the plugin expects some state data.
1418 // Issue a warning to console...
1419 if( fP.size != 0 )
1420 Console.Indent().Warning( "Warning: No data for this plugin was found. Plugin status may be unpredictable." );
1421 return;
1422
1423 // Note: Size mismatch check could also be done here on loading, but
1424 // some plugins may have built-in version support for non-native formats or
1425 // older versions of a different size... or could give different sizes depending
1426 // on the status of the plugin when loading, so let's ignore it.
1427 }
1428
1429 fP.size = fsize;
1430 if( fP.size == 0 ) return;
1431
1432 state.PrepBlock( fP.size );
1433 fP.data = (s8*)state.GetBlockPtr();
1434
1435 if( state.IsSaving() )
1436 {
1437 if( !DoFreeze(pid, FREEZE_SAVE, &fP) )
1438 throw Exception::FreezePluginFailure( pid );
1439 }
1440 else
1441 {
1442 if( !DoFreeze(pid, FREEZE_LOAD, &fP) )
1443 throw Exception::ThawPluginFailure( pid );
1444 }
1445
1446 state.CommitBlock( fP.size );
1447 }
1448
1449 bool SysCorePlugins::KeyEvent( const keyEvent& evt )
1450 {
1451 ScopedLock lock( m_mtx_PluginStatus );
1452
1453 // [TODO] : The plan here is to give plugins "first chance" handling of keys.
1454 // Handling order will be fixed (GS, SPU2, PAD, etc), and the first plugin to
1455 // pick up the key and return "true" (for handled) will cause the loop to break.
1456 // The current version of PS2E doesn't support it yet, though.
1457
1458 const PluginInfo* pi = tbl_PluginInfo; do {
1459 if( pi->id != PluginId_PAD && m_info[pi->id] )
1460 m_info[pi->id]->CommonBindings.KeyEvent( const_cast<keyEvent*>(&evt) );
1461 } while( ++pi, pi->shortname != NULL );
1462
1463 return false;
1464 }
1465
1466 void SysCorePlugins::SendSettingsFolder()
1467 {
1468 ScopedLock lock( m_mtx_PluginStatus );
1469 if( m_SettingsFolder.IsEmpty() ) return;
1470
1471 pxToUTF8 utf8buffer( m_SettingsFolder );
1472
1473 const PluginInfo* pi = tbl_PluginInfo; do {
1474 if( m_info[pi->id] ) m_info[pi->id]->CommonBindings.SetSettingsDir( utf8buffer );
1475 } while( ++pi, pi->shortname != NULL );
1476 }
1477
1478 void SysCorePlugins::SetSettingsFolder( const wxString& folder )
1479 {
1480 ScopedLock lock( m_mtx_PluginStatus );
1481
1482 wxString fixedfolder( folder );
1483 if( !fixedfolder.IsEmpty() && (fixedfolder[fixedfolder.length()-1] != wxFileName::GetPathSeparator() ) )
1484 {
1485 fixedfolder += wxFileName::GetPathSeparator();
1486 }
1487
1488 if( m_SettingsFolder == fixedfolder ) return;
1489 m_SettingsFolder = fixedfolder;
1490 }
1491
1492 void SysCorePlugins::SendLogFolder()
1493 {
1494 ScopedLock lock( m_mtx_PluginStatus );
1495 if( m_LogFolder.IsEmpty() ) return;
1496
1497 pxToUTF8 utf8buffer( m_LogFolder );
1498
1499 const PluginInfo* pi = tbl_PluginInfo; do {
1500 if( m_info[pi->id] ) m_info[pi->id]->CommonBindings.SetLogDir( utf8buffer );
1501 } while( ++pi, pi->shortname != NULL );
1502 }
1503
1504 void SysCorePlugins::SetLogFolder( const wxString& folder )
1505 {
1506 ScopedLock lock( m_mtx_PluginStatus );
1507
1508 wxString fixedfolder( folder );
1509 if( !fixedfolder.IsEmpty() && (fixedfolder[fixedfolder.length()-1] != wxFileName::GetPathSeparator() ) )
1510 {
1511 fixedfolder += wxFileName::GetPathSeparator();
1512 }
1513
1514 if( m_LogFolder == fixedfolder ) return;
1515 m_LogFolder = fixedfolder;
1516 }
1517
1518 void SysCorePlugins::Configure( PluginsEnum_t pid )
1519 {
1520 ScopedLock lock( m_mtx_PluginStatus );
1521 if( m_info[pid] ) m_info[pid]->CommonBindings.Configure();
1522 }
1523
1524 bool SysCorePlugins::AreLoaded() const
1525 {
1526 ScopedLock lock( m_mtx_PluginStatus );
1527 for( int i=0; i<PluginId_Count; ++i )
1528 {
1529 if( !m_info[i] ) return false;
1530 }
1531
1532 return true;
1533 }
1534
1535 bool SysCorePlugins::AreOpen() const
1536 {
1537 ScopedLock lock( m_mtx_PluginStatus );
1538 const PluginInfo* pi = tbl_PluginInfo; do {
1539 if( !IsOpen(pi->id) ) return false;
1540 } while( ++pi, pi->shortname != NULL );
1541
1542 return true;
1543 }
1544
1545 bool SysCorePlugins::AreAnyLoaded() const
1546 {
1547 ScopedLock lock( m_mtx_PluginStatus );
1548 for( int i=0; i<PluginId_Count; ++i )
1549 {
1550 if( m_info[i] ) return true;
1551 }
1552
1553 return false;
1554 }
1555
1556 bool SysCorePlugins::AreAnyInitialized() const
1557 {
1558 ScopedLock lock( m_mtx_PluginStatus );
1559 const PluginInfo* pi = tbl_PluginInfo; do {
1560 if( IsInitialized(pi->id) ) return true;
1561 } while( ++pi, pi->shortname != NULL );
1562
1563 return false;
1564 }
1565
1566 bool SysCorePlugins::IsOpen( PluginsEnum_t pid ) const
1567 {
1568 pxAssume( (uint)pid < PluginId_Count );
1569 ScopedLock lock( m_mtx_PluginStatus );
1570 return m_info[pid] && m_info[pid]->IsInitialized && m_info[pid]->IsOpened;
1571 }
1572
1573 bool SysCorePlugins::IsInitialized( PluginsEnum_t pid ) const
1574 {
1575 pxAssume( (uint)pid < PluginId_Count );
1576 ScopedLock lock( m_mtx_PluginStatus );
1577 return m_info[pid] && m_info[pid]->IsInitialized;
1578 }
1579
1580 bool SysCorePlugins::IsLoaded( PluginsEnum_t pid ) const
1581 {
1582 pxAssume( (uint)pid < PluginId_Count );
1583 return !!m_info[pid];
1584 }
1585
1586 bool SysCorePlugins::NeedsLoad() const
1587 {
1588 const PluginInfo* pi = tbl_PluginInfo; do {
1589 if( !IsLoaded(pi->id) ) return true;
1590 } while( ++pi, pi->shortname != NULL );
1591
1592 return false;
1593 }
1594
1595 bool SysCorePlugins::NeedsUnload() const
1596 {
1597 const PluginInfo* pi = tbl_PluginInfo; do {
1598 if( IsLoaded(pi->id) ) return true;
1599 } while( ++pi, pi->shortname != NULL );
1600
1601 return false;
1602 }
1603
1604 bool SysCorePlugins::NeedsInit() const
1605 {
1606 ScopedLock lock( m_mtx_PluginStatus );
1607
1608 const PluginInfo* pi = tbl_PluginInfo; do {
1609 if( !IsInitialized(pi->id) ) return true;
1610 } while( ++pi, pi->shortname != NULL );
1611
1612 return false;
1613 }
1614
1615 bool SysCorePlugins::NeedsShutdown() const
1616 {
1617 ScopedLock lock( m_mtx_PluginStatus );
1618
1619 const PluginInfo* pi = tbl_PluginInfo; do {
1620 if( IsInitialized(pi->id) ) return true;
1621 } while( ++pi, pi->shortname != NULL );
1622
1623 return false;
1624 }
1625
1626 bool SysCorePlugins::NeedsOpen() const
1627 {
1628 const PluginInfo* pi = tbl_PluginInfo; do {
1629 if( !IsOpen(pi->id) ) return true;
1630 } while( ++pi, pi->shortname != NULL );
1631
1632 return false;
1633 }
1634
1635 bool SysCorePlugins::NeedsClose() const
1636 {
1637 const PluginInfo* pi = tbl_PluginInfo; do {
1638 if( IsOpen(pi->id) ) return true;
1639 } while( ++pi, pi->shortname != NULL );
1640
1641 return false;
1642 }
1643
1644 const wxString SysCorePlugins::GetName( PluginsEnum_t pid ) const
1645 {
1646 ScopedLock lock( m_mtx_PluginStatus );
1647 pxAssume( (uint)pid < PluginId_Count );
1648 return m_info[pid] ? m_info[pid]->Name : (wxString)_("Unloaded Plugin");
1649 }
1650
1651 const wxString SysCorePlugins::GetVersion( PluginsEnum_t pid ) const
1652 {
1653 ScopedLock lock( m_mtx_PluginStatus );
1654 pxAssume( (uint)pid < PluginId_Count );
1655 return m_info[pid] ? m_info[pid]->Version : L"0.0";
1656 }

  ViewVC Help
Powered by ViewVC 1.1.22