24e1f12a83eb3bb7e67a11c622622b840fa19ca2
[pcsx_rearmed.git] / frontend / main.c
1 /*
2  * (C) notaz, 2010-2011
3  *
4  * This work is licensed under the terms of the GNU GPLv2 or later.
5  * See the COPYING file in the top-level directory.
6  */
7
8 #include <stdio.h>
9 #include <string.h>
10 #include <stdarg.h>
11 #include <dlfcn.h>
12 #include <sys/stat.h>
13 #include <sys/types.h>
14 #include <unistd.h>
15 #include <signal.h>
16 #include <time.h>
17
18 #include "main.h"
19 #include "plugin.h"
20 #include "plugin_lib.h"
21 #include "pcnt.h"
22 #include "menu.h"
23 #include "plat.h"
24 #include "../libpcsxcore/misc.h"
25 #include "../libpcsxcore/cheat.h"
26 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
27 #include "../plugins/cdrcimg/cdrcimg.h"
28 #include "revision.h"
29
30 #ifndef NO_FRONTEND
31 #include "libpicofe/input.h"
32 #include "libpicofe/plat.h"
33 #include "libpicofe/readpng.h"
34 #endif
35
36 // don't include debug.h - it breaks ARM build (R1 redefined)
37 void StartDebugger();
38 void StopDebugger();
39
40 // sound plugin
41 extern int iUseReverb;
42 extern int iUseInterpolation;
43 extern int iXAPitch;
44 extern int iVolume;
45
46 int ready_to_go;
47 unsigned long gpuDisp;
48 char cfgfile_basename[MAXPATHLEN];
49 int state_slot;
50 enum sched_action emu_action, emu_action_old;
51 char hud_msg[64];
52 int hud_new_msg;
53
54 static void make_path(char *buf, size_t size, const char *dir, const char *fname)
55 {
56         if (fname)
57                 snprintf(buf, size, ".%s%s", dir, fname);
58         else
59                 snprintf(buf, size, ".%s", dir);
60 }
61 #define MAKE_PATH(buf, dir, fname) \
62         make_path(buf, sizeof(buf), dir, fname)
63
64 static void create_profile_dir(const char *directory) {
65         char path[MAXPATHLEN];
66
67         MAKE_PATH(path, directory, NULL);
68         mkdir(path, S_IRWXU | S_IRWXG);
69 }
70
71 static void CheckSubDir() {
72         // make sure that ~/.pcsx exists
73         create_profile_dir(PCSX_DOT_DIR);
74
75         create_profile_dir(BIOS_DIR);
76         create_profile_dir(MEMCARD_DIR);
77         create_profile_dir(STATES_DIR);
78         create_profile_dir(PLUGINS_DIR);
79         create_profile_dir(PLUGINS_CFG_DIR);
80         create_profile_dir(CHEATS_DIR);
81         create_profile_dir(PATCHES_DIR);
82         create_profile_dir(PCSX_DOT_DIR "cfg");
83         create_profile_dir("/screenshots/");
84 }
85
86 static int get_gameid_filename(char *buf, int size, const char *fmt, int i) {
87         char trimlabel[33];
88         int j;
89
90         strncpy(trimlabel, CdromLabel, 32);
91         trimlabel[32] = 0;
92         for (j = 31; j >= 0; j--)
93                 if (trimlabel[j] == ' ')
94                         trimlabel[j] = 0;
95                 else
96                         continue;
97
98         snprintf(buf, size, fmt, trimlabel, CdromId, i);
99
100         return 0;
101 }
102
103 void set_cd_image(const char *fname)
104 {
105         const char *ext = NULL;
106         
107         if (fname != NULL)
108                 ext = strrchr(fname, '.');
109
110         if (ext && (
111             strcasecmp(ext, ".z") == 0 || strcasecmp(ext, ".bz") == 0 ||
112             strcasecmp(ext, ".znx") == 0 /*|| strcasecmp(ext, ".pbp") == 0*/)) {
113                 SetIsoFile(NULL);
114                 cdrcimg_set_fname(fname);
115                 strcpy(Config.Cdr, "builtin_cdrcimg");
116         } else {
117                 SetIsoFile(fname);
118                 strcpy(Config.Cdr, "builtin_cdr");
119         }
120 }
121
122 static void set_default_paths(void)
123 {
124         MAKE_PATH(Config.Mcd1, MEMCARD_DIR, "card1.mcd");
125         MAKE_PATH(Config.Mcd2, MEMCARD_DIR, "card2.mcd");
126         strcpy(Config.BiosDir, "bios");
127
128         strcpy(Config.PluginsDir, "plugins");
129         strcpy(Config.Gpu, "builtin_gpu");
130         strcpy(Config.Spu, "builtin_spu");
131         strcpy(Config.Cdr, "builtin_cdr");
132         strcpy(Config.Pad1, "builtin_pad");
133         strcpy(Config.Pad2, "builtin_pad");
134         strcpy(Config.Net, "Disabled");
135
136         snprintf(Config.PatchesDir, sizeof(Config.PatchesDir), "." PATCHES_DIR);
137 }
138
139 void emu_set_default_config(void)
140 {
141         // try to set sane config on which most games work
142         Config.Xa = Config.Cdda = Config.Sio =
143         Config.SpuIrq = Config.RCntFix = Config.VSyncWA = 0;
144         Config.CdrReschedule = 0;
145         Config.PsxAuto = 1;
146
147         pl_rearmed_cbs.gpu_neon.allow_interlace = 2; // auto
148         pl_rearmed_cbs.gpu_neon.enhancement_enable =
149         pl_rearmed_cbs.gpu_neon.enhancement_no_main = 0;
150         pl_rearmed_cbs.gpu_peops.iUseDither = 0;
151         pl_rearmed_cbs.gpu_peops.dwActFixes = 1<<7;
152         pl_rearmed_cbs.gpu_unai.abe_hack =
153         pl_rearmed_cbs.gpu_unai.no_light =
154         pl_rearmed_cbs.gpu_unai.no_blend = 0;
155         memset(&pl_rearmed_cbs.gpu_peopsgl, 0, sizeof(pl_rearmed_cbs.gpu_peopsgl));
156         pl_rearmed_cbs.gpu_peopsgl.iVRamSize = 64;
157         pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection = 1;
158
159         iUseReverb = 2;
160         iUseInterpolation = 1;
161         iXAPitch = 0;
162         iVolume = 768;
163 #ifndef __ARM_ARCH_7A__ /* XXX */
164         iUseReverb = 0;
165         iUseInterpolation = 0;
166 #endif
167         new_dynarec_hacks = 0;
168         cycle_multiplier = 200;
169
170         in_type1 = PSE_PAD_TYPE_STANDARD;
171         in_type2 = PSE_PAD_TYPE_STANDARD;
172 }
173
174 static void check_memcards(void)
175 {
176         char buf[MAXPATHLEN];
177         FILE *f;
178         int i;
179
180         for (i = 1; i <= 9; i++) {
181                 snprintf(buf, sizeof(buf), ".%scard%d.mcd", MEMCARD_DIR, i);
182
183                 f = fopen(buf, "rb");
184                 if (f == NULL) {
185                         printf("Creating memcard: %s\n", buf);
186                         CreateMcd(buf);
187                 }
188                 else
189                         fclose(f);
190         }
191 }
192
193 void do_emu_action(void)
194 {
195         int ret;
196
197         emu_action_old = emu_action;
198
199         switch (emu_action) {
200         case SACTION_LOAD_STATE:
201                 ret = emu_load_state(state_slot);
202                 snprintf(hud_msg, sizeof(hud_msg), ret == 0 ? "LOADED" : "FAIL!");
203                 break;
204         case SACTION_SAVE_STATE:
205                 ret = emu_save_state(state_slot);
206                 snprintf(hud_msg, sizeof(hud_msg), ret == 0 ? "SAVED" : "FAIL!");
207                 break;
208 #ifndef NO_FRONTEND
209         case SACTION_ENTER_MENU:
210                 menu_loop();
211                 return;
212         case SACTION_NEXT_SSLOT:
213                 state_slot++;
214                 if (state_slot > 9)
215                         state_slot = 0;
216                 goto do_state_slot;
217         case SACTION_PREV_SSLOT:
218                 state_slot--;
219                 if (state_slot < 0)
220                         state_slot = 9;
221 do_state_slot:
222                 snprintf(hud_msg, sizeof(hud_msg), "STATE SLOT %d [%s]", state_slot,
223                         emu_check_state(state_slot) == 0 ? "USED" : "FREE");
224                 hud_new_msg = 3;
225                 printf("* %s\n", hud_msg);
226                 break;
227         case SACTION_TOGGLE_FSKIP:
228                 pl_rearmed_cbs.fskip_advice = 0;
229                 pl_rearmed_cbs.frameskip++;
230                 if (pl_rearmed_cbs.frameskip > 1)
231                         pl_rearmed_cbs.frameskip = -1;
232                 snprintf(hud_msg, sizeof(hud_msg), "FRAMESKIP: %s",
233                         pl_rearmed_cbs.frameskip == -1 ? "AUTO" :
234                         pl_rearmed_cbs.frameskip == 0 ? "OFF" : "1" );
235                 plugin_call_rearmed_cbs();
236                 break;
237         case SACTION_SWITCH_DISPMODE:
238                 pl_switch_dispmode();
239                 plugin_call_rearmed_cbs();
240                 if (GPU_open != NULL && GPU_close != NULL) {
241                         GPU_close();
242                         GPU_open(&gpuDisp, "PCSX", NULL);
243                 }
244                 break;
245         case SACTION_SCREENSHOT:
246                 {
247                         char buf[MAXPATHLEN];
248                         void *scrbuf;
249                         int w, h, bpp;
250                         time_t t = time(NULL);
251                         struct tm *tb = localtime(&t);
252                         int ti = tb->tm_yday * 1000000 + tb->tm_hour * 10000 +
253                                 tb->tm_min * 100 + tb->tm_sec;
254
255                         scrbuf = pl_prepare_screenshot(&w, &h, &bpp);
256                         get_gameid_filename(buf, sizeof(buf),
257                                 "screenshots/%.32s-%.9s.%d.png", ti);
258                         ret = -1;
259                         if (scrbuf != 0 && bpp == 16)
260                                 ret = writepng(buf, scrbuf, w, h);
261                         if (ret == 0)
262                                 snprintf(hud_msg, sizeof(hud_msg), "SCREENSHOT TAKEN");
263                         break;
264                 }
265         case SACTION_VOLUME_UP:
266         case SACTION_VOLUME_DOWN:
267                 plat_target_step_volume(emu_action == SACTION_VOLUME_UP);
268                 return;
269         case SACTION_MINIMIZE:
270                 if (GPU_close != NULL)
271                         GPU_close();
272
273                 plat_minimize();
274
275                 if (GPU_open != NULL) {
276                         ret = GPU_open(&gpuDisp, "PCSX", NULL);
277                         if (ret)
278                                 fprintf(stderr, "GPU_open returned %d\n", ret);
279                 }
280                 return;
281 #endif
282         default:
283                 return;
284         }
285
286         hud_new_msg = 3;
287 }
288
289 static int cdidcmp(const char *id1, const char *id2)
290 {
291         while (*id1 != 0 && *id2 != 0) {
292                 if (*id1 == '_') { id1++; continue; }
293                 if (*id2 == '_') { id2++; continue; }
294                 if (*id1 != *id2)
295                         break;
296                 id1++;
297                 id2++;
298         }
299
300         return *id1 - *id2;
301 }
302
303 static void parse_cwcheat(void)
304 {
305         char line[256], buf[64], name[64], *p;
306         int newcheat = 1;
307         u32 a, v;
308         FILE *f;
309
310         f = fopen("cheatpops.db", "r");
311         if (f == NULL)
312                 return;
313
314         /* find the game */
315         while (fgets(line, sizeof(line), f)) {
316                 if (sscanf(line, "_S %63s", buf) != 1)
317                         continue;
318                 if (cdidcmp(buf, CdromId) == 0)
319                         break;
320         }
321
322         if (feof(f))
323                 goto out;
324
325         printf("cwcheat section found for %s\n", CdromId);
326         while (fgets(line, sizeof(line), f))
327         {
328                 p = line + strlen(line);
329                 for (p--; p >= line && (*p == '\r' || *p == '\n' || *p == ' '); p--)
330                         *p = 0;
331                 if (*p == 0 || *p == '#' || *p == ';')
332                         continue;
333
334                 if (strncmp(line, "_S", 2) == 0)
335                         break;
336                 if (strncmp(line, "_G", 2) == 0) {
337                         printf("  cwcheat game name: '%s'\n", line + 3);
338                         continue;
339                 }
340                 if (strncmp(line, "_C0", 3) == 0) {
341                         if (!newcheat && Cheats[NumCheats - 1].n == 0) {
342                                 printf("cheat '%s' failed to parse\n", name);
343                                 free(Cheats[NumCheats - 1].Descr);
344                                 NumCheats--;
345                         }
346                         snprintf(name, sizeof(name), "%s", line + 4);
347                         newcheat = 1;
348                         continue;
349                 }
350                 if (sscanf(line, "_L %x %x", &a, &v) != 2) {
351                         printf("line failed to parse: '%s'\n", line);
352                         continue;
353                 }
354
355                 if (newcheat) {
356                         if (NumCheats >= NumCheatsAllocated) {
357                                 NumCheatsAllocated += 16;
358                                 Cheats = realloc(Cheats, sizeof(Cheat) *
359                                                 NumCheatsAllocated);
360                                 if (Cheats == NULL)
361                                         break;
362                         }
363                         Cheats[NumCheats].Descr = strdup(name);
364                         Cheats[NumCheats].Enabled = 0;
365                         Cheats[NumCheats].WasEnabled = 0;
366                         Cheats[NumCheats].First = NumCodes;
367                         Cheats[NumCheats].n = 0;
368                         NumCheats++;
369                         newcheat = 0;
370                 }
371
372                 if (NumCodes >= NumCodesAllocated) {
373                         NumCodesAllocated += 16;
374                         CheatCodes = realloc(CheatCodes, sizeof(CheatCode) *
375                                 NumCodesAllocated);
376                         if (CheatCodes == NULL)
377                                 break;
378                 }
379                 CheatCodes[NumCodes].Addr = a;
380                 CheatCodes[NumCodes].Val = v;
381                 NumCodes++;
382                 Cheats[NumCheats - 1].n++;
383         }
384
385 out:
386         fclose(f);
387 }
388
389 void emu_on_new_cd(void)
390 {
391         ClearAllCheats();
392         parse_cwcheat();
393
394         if (Config.HLE) {
395                 printf("note: running with HLE BIOS, expect compatibility problems\n");
396                 printf("----------------------------------------------------------\n");
397         }
398
399         snprintf(hud_msg, sizeof(hud_msg), "Booting up...");
400         hud_new_msg = 2;
401 }
402
403 int emu_core_preinit(void)
404 {
405         // what is the name of the config file?
406         // it may be redefined by -cfg on the command line
407         strcpy(cfgfile_basename, "pcsx.cfg");
408
409         emuLog = stdout;
410         SetIsoFile(NULL);
411
412         memset(&Config, 0, sizeof(Config));
413
414         set_default_paths();
415         emu_set_default_config();
416         strcpy(Config.Bios, "HLE");
417
418         return 0;
419 }
420
421 int emu_core_init(void)
422 {
423         CheckSubDir();
424         check_memcards();
425
426         if (EmuInit() == -1) {
427                 printf("PSX emulator couldn't be initialized.\n");
428                 return -1;
429         }
430
431         LoadMcds(Config.Mcd1, Config.Mcd2);
432
433         if (Config.Debug) {
434                 StartDebugger();
435         }
436
437         return 0;
438 }
439
440 #ifndef NO_FRONTEND
441 int main(int argc, char *argv[])
442 {
443         char file[MAXPATHLEN] = "";
444         char path[MAXPATHLEN];
445         const char *cdfile = NULL;
446         const char *loadst_f = NULL;
447         int psxout = 0;
448         int loadst = 0;
449         int i;
450
451         emu_core_preinit();
452
453         // read command line options
454         for (i = 1; i < argc; i++) {
455                      if (!strcmp(argv[i], "-psxout")) psxout = 1;
456                 else if (!strcmp(argv[i], "-load")) loadst = atol(argv[++i]);
457                 else if (!strcmp(argv[i], "-cfg")) {
458                         if (i+1 >= argc) break;
459                         strncpy(cfgfile_basename, argv[++i], MAXPATHLEN-100);   /* TODO buffer overruns */
460                         printf("Using config file %s.\n", cfgfile_basename);
461                 }
462                 else if (!strcmp(argv[i], "-cdfile")) {
463                         char isofilename[MAXPATHLEN];
464
465                         if (i+1 >= argc) break;
466                         strncpy(isofilename, argv[++i], MAXPATHLEN);
467                         if (isofilename[0] != '/') {
468                                 getcwd(path, MAXPATHLEN);
469                                 if (strlen(path) + strlen(isofilename) + 1 < MAXPATHLEN) {
470                                         strcat(path, "/");
471                                         strcat(path, isofilename);
472                                         strcpy(isofilename, path);
473                                 } else
474                                         isofilename[0] = 0;
475                         }
476
477                         cdfile = isofilename;
478                 }
479                 else if (!strcmp(argv[i], "-loadf")) {
480                         if (i+1 >= argc) break;
481                         loadst_f = argv[++i];
482                 }
483                 else if (!strcmp(argv[i], "-h") ||
484                          !strcmp(argv[i], "-help") ||
485                          !strcmp(argv[i], "--help")) {
486                          printf("PCSX-ReARMed " REV "\n");
487                          printf("%s\n", _(
488                                                         " pcsx [options] [file]\n"
489                                                         "\toptions:\n"
490                                                         "\t-cdfile FILE\tRuns a CD image file\n"
491                                                         "\t-cfg FILE\tLoads desired configuration file (default: ~/.pcsx/pcsx.cfg)\n"
492                                                         "\t-psxout\t\tEnable PSX output\n"
493                                                         "\t-load STATENUM\tLoads savestate STATENUM (1-5)\n"
494                                                         "\t-h -help\tDisplay this message\n"
495                                                         "\tfile\t\tLoads a PSX EXE file\n"));
496                          return 0;
497                 } else {
498                         strncpy(file, argv[i], MAXPATHLEN);
499                         if (file[0] != '/') {
500                                 getcwd(path, MAXPATHLEN);
501                                 if (strlen(path) + strlen(file) + 1 < MAXPATHLEN) {
502                                         strcat(path, "/");
503                                         strcat(path, file);
504                                         strcpy(file, path);
505                                 } else
506                                         file[0] = 0;
507                         }
508                 }
509         }
510
511         if (cdfile)
512                 set_cd_image(cdfile);
513
514         // frontend stuff
515         // init input but leave probing to platform code,
516         // they add input drivers and may need to modify them after probe
517         in_init();
518         pl_init();
519         plat_init();
520         menu_init(); // loads config
521
522         emu_core_init();
523
524         if (psxout)
525                 Config.PsxOut = 1;
526
527         if (LoadPlugins() == -1) {
528                 // FIXME: this recovery doesn't work, just delete bad config and bail out
529                 // SysMessage("could not load plugins, retrying with defaults\n");
530                 set_default_paths();
531                 snprintf(path, sizeof(path), "." PCSX_DOT_DIR "%s", cfgfile_basename);
532                 remove(path);
533                 SysMessage("Failed loading plugins!");
534                 return 1;
535         }
536         pcnt_hook_plugins();
537
538         if (OpenPlugins() == -1) {
539                 return 1;
540         }
541         plugin_call_rearmed_cbs();
542
543         CheckCdrom();
544         SysReset();
545
546         if (file[0] != '\0') {
547                 if (Load(file) != -1)
548                         ready_to_go = 1;
549         } else {
550                 if (cdfile) {
551                         if (LoadCdrom() == -1) {
552                                 ClosePlugins();
553                                 printf(_("Could not load CD-ROM!\n"));
554                                 return -1;
555                         }
556                         emu_on_new_cd();
557                         ready_to_go = 1;
558                 }
559         }
560
561         if (ready_to_go) {
562                 menu_prepare_emu();
563
564                 // If a state has been specified, then load that
565                 if (loadst) {
566                         int ret = emu_load_state(loadst - 1);
567                         printf("%s state %d\n", ret ? "failed to load" : "loaded", loadst);
568                 }
569                 if (loadst_f) {
570                         int ret = LoadState(loadst_f);
571                         printf("%s state file: %s\n", ret ? "failed to load" : "loaded", loadst_f);
572                 }
573         }
574         else
575                 menu_loop();
576
577         pl_start_watchdog();
578
579         while (1)
580         {
581                 stop = 0;
582                 emu_action = SACTION_NONE;
583
584                 psxCpu->Execute();
585                 if (emu_action != SACTION_NONE)
586                         do_emu_action();
587         }
588
589         return 0;
590 }
591 #endif
592
593 void SysRunGui() {
594         printf("SysRunGui\n");
595 }
596
597 static void dummy_lace()
598 {
599 }
600
601 void SysReset() {
602         // rearmed hack: EmuReset() runs some code when real BIOS is used,
603         // but we usually do reset from menu while GPU is not open yet,
604         // so we need to prevent updateLace() call..
605         void *real_lace = GPU_updateLace;
606         GPU_updateLace = dummy_lace;
607
608         // reset can run code, timing must be set
609         pl_timing_prepare(Config.PsxType);
610
611         EmuReset();
612
613         // hmh core forgets this
614         CDR_stop();
615
616         GPU_updateLace = real_lace;
617 }
618
619 void SysClose() {
620         EmuShutdown();
621         ReleasePlugins();
622
623         StopDebugger();
624
625         if (emuLog != NULL) fclose(emuLog);
626 }
627
628 void SysUpdate() {
629 }
630
631 void OnFile_Exit() {
632         printf("OnFile_Exit\n");
633         SysClose();
634 #ifndef NO_FRONTEND
635         menu_finish();
636         plat_finish();
637         exit(0);
638 #endif
639 }
640
641 int get_state_filename(char *buf, int size, int i) {
642         return get_gameid_filename(buf, size,
643                 "." STATES_DIR "%.32s-%.9s.%3.3d", i);
644 }
645
646 int emu_check_state(int slot)
647 {
648         char fname[MAXPATHLEN];
649         int ret;
650
651         ret = get_state_filename(fname, sizeof(fname), slot);
652         if (ret != 0)
653                 return ret;
654
655         return CheckState(fname);
656 }
657
658 int emu_save_state(int slot)
659 {
660         char fname[MAXPATHLEN];
661         int ret;
662
663         ret = get_state_filename(fname, sizeof(fname), slot);
664         if (ret != 0)
665                 return ret;
666
667         ret = SaveState(fname);
668 #ifndef __ARM_ARCH_7A__ /* XXX */
669         sync();
670 #endif
671         printf("* %s \"%s\" [%d]\n", ret == 0 ? "saved" : "failed to save", fname, slot);
672         return ret;
673 }
674
675 int emu_load_state(int slot)
676 {
677         char fname[MAXPATHLEN];
678         int ret;
679
680         ret = get_state_filename(fname, sizeof(fname), slot);
681         if (ret != 0)
682                 return ret;
683
684         return LoadState(fname);
685 }
686
687 void SysPrintf(const char *fmt, ...) {
688         va_list list;
689         char msg[512];
690
691         va_start(list, fmt);
692         vsprintf(msg, fmt, list);
693         va_end(list);
694
695         fprintf(emuLog, "%s", msg);
696 }
697
698 void SysMessage(const char *fmt, ...) {
699         va_list list;
700         char msg[512];
701
702         va_start(list, fmt);
703         vsprintf(msg, fmt, list);
704         va_end(list);
705
706         if (msg[strlen(msg) - 1] == '\n')
707                 msg[strlen(msg) - 1] = 0;
708
709         fprintf(stderr, "%s\n", msg);
710 }
711
712 static void SignalExit(int sig) {
713         ClosePlugins();
714         OnFile_Exit();
715 }
716
717 #define PARSEPATH(dst, src) \
718         ptr = src + strlen(src); \
719         while (*ptr != '\\' && ptr != src) ptr--; \
720         if (ptr != src) { \
721                 strcpy(dst, ptr+1); \
722         }
723
724 static int _OpenPlugins(void) {
725         int ret;
726
727         signal(SIGINT, SignalExit);
728         signal(SIGPIPE, SignalExit);
729
730         GPU_clearDynarec(clearDynarec);
731
732         ret = CDR_open();
733         if (ret < 0) { SysMessage(_("Error opening CD-ROM plugin!")); return -1; }
734         ret = SPU_open();
735         if (ret < 0) { SysMessage(_("Error opening SPU plugin!")); return -1; }
736         SPU_registerCallback(SPUirq);
737         // pcsx-rearmed: we handle gpu elsewhere
738         //ret = GPU_open(&gpuDisp, "PCSX", NULL);
739         //if (ret < 0) { SysMessage(_("Error opening GPU plugin!")); return -1; }
740         ret = PAD1_open(&gpuDisp);
741         if (ret < 0) { SysMessage(_("Error opening Controller 1 plugin!")); return -1; }
742         ret = PAD2_open(&gpuDisp);
743         if (ret < 0) { SysMessage(_("Error opening Controller 2 plugin!")); return -1; }
744
745         if (Config.UseNet && !NetOpened) {
746                 netInfo info;
747                 char path[MAXPATHLEN];
748                 char dotdir[MAXPATHLEN];
749
750                 MAKE_PATH(dotdir, "/.pcsx/plugins/", NULL);
751
752                 strcpy(info.EmuName, "PCSX");
753                 strncpy(info.CdromID, CdromId, 9);
754                 strncpy(info.CdromLabel, CdromLabel, 9);
755                 info.psxMem = psxM;
756                 info.GPU_showScreenPic = GPU_showScreenPic;
757                 info.GPU_displayText = GPU_displayText;
758                 info.GPU_showScreenPic = GPU_showScreenPic;
759                 info.PAD_setSensitive = PAD1_setSensitive;
760                 sprintf(path, "%s%s", Config.BiosDir, Config.Bios);
761                 strcpy(info.BIOSpath, path);
762                 strcpy(info.MCD1path, Config.Mcd1);
763                 strcpy(info.MCD2path, Config.Mcd2);
764                 sprintf(path, "%s%s", dotdir, Config.Gpu);
765                 strcpy(info.GPUpath, path);
766                 sprintf(path, "%s%s", dotdir, Config.Spu);
767                 strcpy(info.SPUpath, path);
768                 sprintf(path, "%s%s", dotdir, Config.Cdr);
769                 strcpy(info.CDRpath, path);
770                 NET_setInfo(&info);
771
772                 ret = NET_open(&gpuDisp);
773                 if (ret < 0) {
774                         if (ret == -2) {
775                                 // -2 is returned when something in the info
776                                 // changed and needs to be synced
777                                 char *ptr;
778
779                                 PARSEPATH(Config.Bios, info.BIOSpath);
780                                 PARSEPATH(Config.Gpu,  info.GPUpath);
781                                 PARSEPATH(Config.Spu,  info.SPUpath);
782                                 PARSEPATH(Config.Cdr,  info.CDRpath);
783
784                                 strcpy(Config.Mcd1, info.MCD1path);
785                                 strcpy(Config.Mcd2, info.MCD2path);
786                                 return -2;
787                         } else {
788                                 Config.UseNet = FALSE;
789                         }
790                 } else {
791                         if (NET_queryPlayer() == 1) {
792                                 if (SendPcsxInfo() == -1) Config.UseNet = FALSE;
793                         } else {
794                                 if (RecvPcsxInfo() == -1) Config.UseNet = FALSE;
795                         }
796                 }
797                 NetOpened = TRUE;
798         } else if (Config.UseNet) {
799                 NET_resume();
800         }
801
802         return 0;
803 }
804
805 int OpenPlugins() {
806         int ret;
807
808         while ((ret = _OpenPlugins()) == -2) {
809                 ReleasePlugins();
810                 LoadMcds(Config.Mcd1, Config.Mcd2);
811                 if (LoadPlugins() == -1) return -1;
812         }
813         return ret;
814 }
815
816 void ClosePlugins() {
817         int ret;
818
819         signal(SIGINT, SIG_DFL);
820         signal(SIGPIPE, SIG_DFL);
821         ret = CDR_close();
822         if (ret < 0) { SysMessage(_("Error closing CD-ROM plugin!")); return; }
823         ret = SPU_close();
824         if (ret < 0) { SysMessage(_("Error closing SPU plugin!")); return; }
825         ret = PAD1_close();
826         if (ret < 0) { SysMessage(_("Error closing Controller 1 Plugin!")); return; }
827         ret = PAD2_close();
828         if (ret < 0) { SysMessage(_("Error closing Controller 2 plugin!")); return; }
829         // pcsx-rearmed: we handle gpu elsewhere
830         //ret = GPU_close();
831         //if (ret < 0) { SysMessage(_("Error closing GPU plugin!")); return; }
832
833         if (Config.UseNet) {
834                 NET_pause();
835         }
836 }
837
838 /* we hook statically linked plugins here */
839 static const char *builtin_plugins[] = {
840         "builtin_gpu", "builtin_spu", "builtin_cdr", "builtin_pad",
841         "builtin_cdrcimg",
842 };
843
844 static const int builtin_plugin_ids[] = {
845         PLUGIN_GPU, PLUGIN_SPU, PLUGIN_CDR, PLUGIN_PAD,
846         PLUGIN_CDRCIMG,
847 };
848
849 void *SysLoadLibrary(const char *lib) {
850         const char *tmp = strrchr(lib, '/');
851         void *ret;
852         int i;
853
854         printf("plugin: %s\n", lib);
855
856         if (tmp != NULL) {
857                 tmp++;
858                 for (i = 0; i < ARRAY_SIZE(builtin_plugins); i++)
859                         if (strcmp(tmp, builtin_plugins[i]) == 0)
860                                 return (void *)(long)(PLUGIN_DL_BASE + builtin_plugin_ids[i]);
861         }
862
863 #if defined(__x86_64__) || defined(__i386__)
864         // convenience hack
865         if (strstr(lib, ".x86") == NULL) {
866                 char name[MAXPATHLEN];
867                 snprintf(name, sizeof(name), "%s.x86_64", lib);
868                 lib = name;
869         }
870 #endif
871
872         ret = dlopen(lib, RTLD_NOW);
873         if (ret == NULL)
874                 fprintf(stderr, "dlopen: %s\n", dlerror());
875         return ret;
876 }
877
878 void *SysLoadSym(void *lib, const char *sym) {
879         unsigned int plugid = (unsigned int)(long)lib;
880
881         if (PLUGIN_DL_BASE <= plugid && plugid < PLUGIN_DL_BASE + ARRAY_SIZE(builtin_plugins))
882                 return plugin_link(plugid - PLUGIN_DL_BASE, sym);
883
884         return dlsym(lib, sym);
885 }
886
887 const char *SysLibError() {
888         return dlerror();
889 }
890
891 void SysCloseLibrary(void *lib) {
892         unsigned int plugid = (unsigned int)(long)lib;
893
894         if (PLUGIN_DL_BASE <= plugid && plugid < PLUGIN_DL_BASE + ARRAY_SIZE(builtin_plugins))
895                 return;
896
897         dlclose(lib);
898 }
899