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

  ViewVC Help
Powered by ViewVC 1.1.22