workaround pandora hugetlb bug, revert this later
[pcsx_rearmed.git] / libpcsxcore / misc.c
1 /***************************************************************************
2  *   Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team              *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
18  ***************************************************************************/
19
20 /*
21 * Miscellaneous functions, including savestates and CD-ROM loading.
22 */
23
24 #include "misc.h"
25 #include "cdrom.h"
26 #include "mdec.h"
27 #include "gpu.h"
28 #include "ppf.h"
29
30 char CdromId[10] = "";
31 char CdromLabel[33] = "";
32
33 // PSX Executable types
34 #define PSX_EXE     1
35 #define CPE_EXE     2
36 #define COFF_EXE    3
37 #define INVALID_EXE 4
38
39 #define ISODCL(from, to) (to - from + 1)
40
41 struct iso_directory_record {
42         char length                     [ISODCL (1, 1)]; /* 711 */
43         char ext_attr_length            [ISODCL (2, 2)]; /* 711 */
44         char extent                     [ISODCL (3, 10)]; /* 733 */
45         char size                       [ISODCL (11, 18)]; /* 733 */
46         char date                       [ISODCL (19, 25)]; /* 7 by 711 */
47         char flags                      [ISODCL (26, 26)];
48         char file_unit_size             [ISODCL (27, 27)]; /* 711 */
49         char interleave                 [ISODCL (28, 28)]; /* 711 */
50         char volume_sequence_number     [ISODCL (29, 32)]; /* 723 */
51         unsigned char name_len          [ISODCL (33, 33)]; /* 711 */
52         char name                       [1];
53 };
54
55 void mmssdd( char *b, char *p )
56 {
57         int m, s, d;
58 #if defined(__arm__)
59         int block = (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0];
60 #elif defined(__BIGENDIAN__)
61         int block = (b[0] & 0xff) | ((b[1] & 0xff) << 8) | ((b[2] & 0xff) << 16) | (b[3] << 24);
62 #else
63         int block = *((int*)b);
64 #endif
65
66         block += 150;
67         m = block / 4500;                       // minutes
68         block = block - m * 4500;       // minutes rest
69         s = block / 75;                         // seconds
70         d = block - s * 75;                     // seconds rest
71
72         m = ((m / 10) << 4) | m % 10;
73         s = ((s / 10) << 4) | s % 10;
74         d = ((d / 10) << 4) | d % 10;   
75
76         p[0] = m;
77         p[1] = s;
78         p[2] = d;
79 }
80
81 #define incTime() \
82         time[0] = btoi(time[0]); time[1] = btoi(time[1]); time[2] = btoi(time[2]); \
83         time[2]++; \
84         if(time[2] == 75) { \
85                 time[2] = 0; \
86                 time[1]++; \
87                 if (time[1] == 60) { \
88                         time[1] = 0; \
89                         time[0]++; \
90                 } \
91         } \
92         time[0] = itob(time[0]); time[1] = itob(time[1]); time[2] = itob(time[2]);
93
94 #define READTRACK() \
95         if (CDR_readTrack(time) == -1) return -1; \
96         buf = CDR_getBuffer(); \
97         if (buf == NULL) return -1; else CheckPPFCache(buf, time[0], time[1], time[2]);
98
99 #define READDIR(_dir) \
100         READTRACK(); \
101         memcpy(_dir, buf + 12, 2048); \
102  \
103         incTime(); \
104         READTRACK(); \
105         memcpy(_dir + 2048, buf + 12, 2048);
106
107 int GetCdromFile(u8 *mdir, u8 *time, s8 *filename) {
108         struct iso_directory_record *dir;
109         char ddir[4096];
110         u8 *buf;
111         int i;
112
113         // only try to scan if a filename is given
114         if (!strlen(filename)) return -1;
115
116         i = 0;
117         while (i < 4096) {
118                 dir = (struct iso_directory_record*) &mdir[i];
119                 if (dir->length[0] == 0) {
120                         return -1;
121                 }
122                 i += dir->length[0];
123
124                 if (dir->flags[0] & 0x2) { // it's a dir
125                         if (!strnicmp((char *)&dir->name[0], filename, dir->name_len[0])) {
126                                 if (filename[dir->name_len[0]] != '\\') continue;
127
128                                 filename += dir->name_len[0] + 1;
129
130                                 mmssdd(dir->extent, (char *)time);
131                                 READDIR(ddir);
132                                 i = 0;
133                                 mdir = ddir;
134                         }
135                 } else {
136                         if (!strnicmp((char *)&dir->name[0], filename, strlen(filename))) {
137                                 mmssdd(dir->extent, (char *)time);
138                                 break;
139                         }
140                 }
141         }
142         return 0;
143 }
144
145 static const unsigned int gpu_ctl_def[] = {
146         0x00000000, 0x01000000, 0x03000000, 0x04000000,
147         0x05000800, 0x06c60260, 0x0703fc10, 0x08000027,
148 };
149
150 static const unsigned int gpu_data_def[] = {
151         0xe100360b, 0xe2000000, 0xe3000800, 0xe4077e7f,
152         0xe5001000, 0xe6000000,
153         0x02000000, 0x00000000, 0x01ff03ff,
154 };
155
156 static void fake_bios_gpu_setup(void)
157 {
158         int i;
159
160         for (i = 0; i < sizeof(gpu_ctl_def) / sizeof(gpu_ctl_def[0]); i++)
161                 GPU_writeStatus(gpu_ctl_def[i]);
162
163         for (i = 0; i < sizeof(gpu_data_def) / sizeof(gpu_data_def[0]); i++)
164                 GPU_writeData(gpu_data_def[i]);
165 }
166
167 int LoadCdrom() {
168         EXE_HEADER tmpHead;
169         struct iso_directory_record *dir;
170         u8 time[4], *buf;
171         u8 mdir[4096];
172         s8 exename[256];
173
174         // not the best place to do it, but since BIOS boot logo killer
175         // is just below, do it here
176         fake_bios_gpu_setup();
177
178         if (!Config.HLE) {
179                 // skip BIOS logos
180                 psxRegs.pc = psxRegs.GPR.n.ra;
181                 return 0;
182         }
183
184         time[0] = itob(0); time[1] = itob(2); time[2] = itob(0x10);
185
186         READTRACK();
187
188         // skip head and sub, and go to the root directory record
189         dir = (struct iso_directory_record*) &buf[12+156]; 
190
191         mmssdd(dir->extent, (char*)time);
192
193         READDIR(mdir);
194
195         // Load SYSTEM.CNF and scan for the main executable
196         if (GetCdromFile(mdir, time, "SYSTEM.CNF;1") == -1) {
197                 // if SYSTEM.CNF is missing, start an existing PSX.EXE
198                 if (GetCdromFile(mdir, time, "PSX.EXE;1") == -1) return -1;
199
200                 READTRACK();
201         }
202         else {
203                 // read the SYSTEM.CNF
204                 READTRACK();
205
206                 sscanf((char *)buf + 12, "BOOT = cdrom:\\%256s", exename);
207                 if (GetCdromFile(mdir, time, exename) == -1) {
208                         sscanf((char *)buf + 12, "BOOT = cdrom:%256s", exename);
209                         if (GetCdromFile(mdir, time, exename) == -1) {
210                                 char *ptr = strstr(buf + 12, "cdrom:");
211                                 if (ptr != NULL) {
212                                         ptr += 6;
213                                         while (*ptr == '\\' || *ptr == '/') ptr++;
214                                         strncpy(exename, ptr, 255);
215                                         exename[255] = '\0';
216                                         ptr = exename;
217                                         while (*ptr != '\0' && *ptr != '\r' && *ptr != '\n') ptr++;
218                                         *ptr = '\0';
219                                         if (GetCdromFile(mdir, time, exename) == -1)
220                                                 return -1;
221                                 } else
222                                         return -1;
223                         }
224                 }
225
226                 // Read the EXE-Header
227                 READTRACK();
228         }
229
230         memcpy(&tmpHead, buf + 12, sizeof(EXE_HEADER));
231
232         psxRegs.pc = SWAP32(tmpHead.pc0);
233         psxRegs.GPR.n.gp = SWAP32(tmpHead.gp0);
234         psxRegs.GPR.n.sp = SWAP32(tmpHead.s_addr); 
235         if (psxRegs.GPR.n.sp == 0) psxRegs.GPR.n.sp = 0x801fff00;
236
237         tmpHead.t_size = SWAP32(tmpHead.t_size);
238         tmpHead.t_addr = SWAP32(tmpHead.t_addr);
239
240         psxCpu->Clear(tmpHead.t_addr, tmpHead.t_size / 4);
241
242         // Read the rest of the main executable
243         while (tmpHead.t_size & ~2047) {
244                 void *ptr = (void *)PSXM(tmpHead.t_addr);
245
246                 incTime();
247                 READTRACK();
248
249                 if (ptr != NULL) memcpy(ptr, buf+12, 2048);
250
251                 tmpHead.t_size -= 2048;
252                 tmpHead.t_addr += 2048;
253         }
254
255         return 0;
256 }
257
258 int LoadCdromFile(const char *filename, EXE_HEADER *head) {
259         struct iso_directory_record *dir;
260         u8 time[4],*buf;
261         u8 mdir[4096], exename[256];
262         u32 size, addr;
263
264         sscanf(filename, "cdrom:\\%256s", exename);
265
266         time[0] = itob(0); time[1] = itob(2); time[2] = itob(0x10);
267
268         READTRACK();
269
270         // skip head and sub, and go to the root directory record
271         dir = (struct iso_directory_record *)&buf[12 + 156]; 
272
273         mmssdd(dir->extent, (char*)time);
274
275         READDIR(mdir);
276
277         if (GetCdromFile(mdir, time, exename) == -1) return -1;
278
279         READTRACK();
280
281         memcpy(head, buf + 12, sizeof(EXE_HEADER));
282         size = head->t_size;
283         addr = head->t_addr;
284
285         psxCpu->Clear(addr, size / 4);
286
287         while (size & ~2047) {
288                 incTime();
289                 READTRACK();
290
291                 memcpy((void *)PSXM(addr), buf + 12, 2048);
292
293                 size -= 2048;
294                 addr += 2048;
295         }
296
297         return 0;
298 }
299
300 int CheckCdrom() {
301         struct iso_directory_record *dir;
302         unsigned char time[4], *buf;
303         unsigned char mdir[4096];
304         char exename[256];
305         int i, c;
306
307         FreePPFCache();
308
309         time[0] = itob(0);
310         time[1] = itob(2);
311         time[2] = itob(0x10);
312
313         READTRACK();
314
315         CdromLabel[0] = '\0';
316         CdromId[0] = '\0';
317
318         strncpy(CdromLabel, buf + 52, 32);
319
320         // skip head and sub, and go to the root directory record
321         dir = (struct iso_directory_record *)&buf[12 + 156]; 
322
323         mmssdd(dir->extent, (char *)time);
324
325         READDIR(mdir);
326
327         if (GetCdromFile(mdir, time, "SYSTEM.CNF;1") != -1) {
328                 READTRACK();
329
330                 sscanf((char *)buf + 12, "BOOT = cdrom:\\%256s", exename);
331                 if (GetCdromFile(mdir, time, exename) == -1) {
332                         sscanf((char *)buf + 12, "BOOT = cdrom:%256s", exename);
333                         if (GetCdromFile(mdir, time, exename) == -1) {
334                                 char *ptr = strstr(buf + 12, "cdrom:");                 // possibly the executable is in some subdir
335                                 if (ptr != NULL) {
336                                         ptr += 6;
337                                         while (*ptr == '\\' || *ptr == '/') ptr++;
338                                         strncpy(exename, ptr, 255);
339                                         exename[255] = '\0';
340                                         ptr = exename;
341                                         while (*ptr != '\0' && *ptr != '\r' && *ptr != '\n') ptr++;
342                                         *ptr = '\0';
343                                         if (GetCdromFile(mdir, time, exename) == -1)
344                                                 return -1;              // main executable not found
345                                 } else
346                                         return -1;
347                         }
348                 }
349         } else if (GetCdromFile(mdir, time, "PSX.EXE;1") != -1) {
350                 strcpy(exename, "PSX.EXE;1");
351                 strcpy(CdromId, "SLUS99999");
352         } else
353                 return -1;              // SYSTEM.CNF and PSX.EXE not found
354
355         if (CdromId[0] == '\0') {
356                 i = strlen(exename);
357                 if (i >= 2) {
358                         if (exename[i - 2] == ';') i-= 2;
359                         c = 8; i--;
360                         while (i >= 0 && c >= 0) {
361                                 if (isalnum(exename[i])) CdromId[c--] = exename[i];
362                                 i--;
363                         }
364                 }
365         }
366
367         if (CdromId[0] == '\0')
368                 strcpy(CdromId, "SLUS99999");
369
370         if (Config.PsxAuto) { // autodetect system (pal or ntsc)
371                 if (CdromId[2] == 'e' || CdromId[2] == 'E')
372                         Config.PsxType = PSX_TYPE_PAL; // pal
373                 else Config.PsxType = PSX_TYPE_NTSC; // ntsc
374         }
375
376         if (CdromLabel[0] == ' ') {
377                 strncpy(CdromLabel, CdromId, 9);
378         }
379         SysPrintf(_("CD-ROM Label: %.32s\n"), CdromLabel);
380         SysPrintf(_("CD-ROM ID: %.9s\n"), CdromId);
381
382         BuildPPFCache();
383
384         return 0;
385 }
386
387 static int PSXGetFileType(FILE *f) {
388         unsigned long current;
389         u8 mybuf[2048];
390         EXE_HEADER *exe_hdr;
391         FILHDR *coff_hdr;
392
393         current = ftell(f);
394         fseek(f, 0L, SEEK_SET);
395         fread(mybuf, 2048, 1, f);
396         fseek(f, current, SEEK_SET);
397
398         exe_hdr = (EXE_HEADER *)mybuf;
399         if (memcmp(exe_hdr->id, "PS-X EXE", 8) == 0)
400                 return PSX_EXE;
401
402         if (mybuf[0] == 'C' && mybuf[1] == 'P' && mybuf[2] == 'E')
403                 return CPE_EXE;
404
405         coff_hdr = (FILHDR *)mybuf;
406         if (SWAPu16(coff_hdr->f_magic) == 0x0162)
407                 return COFF_EXE;
408
409         return INVALID_EXE;
410 }
411
412 // temporary pandora workaround..
413 // FIXME: remove
414 size_t fread_to_ram(void *ptr, size_t size, size_t nmemb, FILE *stream)
415 {
416         void *tmp;
417         size_t ret = 0;
418         
419         tmp = malloc(size * nmemb);
420         if (tmp) {
421                 ret = fread(tmp, size, nmemb, stream);
422                 memcpy(ptr, tmp, size * nmemb);
423                 free(tmp);
424         }
425         return ret;
426 }
427
428 int Load(const char *ExePath) {
429         FILE *tmpFile;
430         EXE_HEADER tmpHead;
431         int type;
432         int retval = 0;
433         u8 opcode;
434         u32 section_address, section_size;
435         void *mem;
436
437         strncpy(CdromId, "SLUS99999", 9);
438         strncpy(CdromLabel, "SLUS_999.99", 11);
439
440         tmpFile = fopen(ExePath, "rb");
441         if (tmpFile == NULL) {
442                 SysPrintf(_("Error opening file: %s.\n"), ExePath);
443                 retval = -1;
444         } else {
445                 type = PSXGetFileType(tmpFile);
446                 switch (type) {
447                         case PSX_EXE:
448                                 fread(&tmpHead,sizeof(EXE_HEADER),1,tmpFile);
449                                 section_address = SWAP32(tmpHead.t_addr);
450                                 section_size = SWAP32(tmpHead.t_size);
451                                 mem = PSXM(section_address);
452                                 if (mem != NULL) {
453                                         fseek(tmpFile, 0x800, SEEK_SET);                
454                                         fread_to_ram(mem, section_size, 1, tmpFile);
455                                         psxCpu->Clear(section_address, section_size / 4);
456                                 }
457                                 fclose(tmpFile);
458                                 psxRegs.pc = SWAP32(tmpHead.pc0);
459                                 psxRegs.GPR.n.gp = SWAP32(tmpHead.gp0);
460                                 psxRegs.GPR.n.sp = SWAP32(tmpHead.s_addr); 
461                                 if (psxRegs.GPR.n.sp == 0)
462                                         psxRegs.GPR.n.sp = 0x801fff00;
463                                 retval = 0;
464                                 break;
465                         case CPE_EXE:
466                                 fseek(tmpFile, 6, SEEK_SET); /* Something tells me we should go to 4 and read the "08 00" here... */
467                                 do {
468                                         fread(&opcode, 1, 1, tmpFile);
469                                         switch (opcode) {
470                                                 case 1: /* Section loading */
471                                                         fread(&section_address, 4, 1, tmpFile);
472                                                         fread(&section_size, 4, 1, tmpFile);
473                                                         section_address = SWAPu32(section_address);
474                                                         section_size = SWAPu32(section_size);
475 #ifdef EMU_LOG
476                                                         EMU_LOG("Loading %08X bytes from %08X to %08X\n", section_size, ftell(tmpFile), section_address);
477 #endif
478                                                         mem = PSXM(section_address);
479                                                         if (mem != NULL) {
480                                                                 fread_to_ram(mem, section_size, 1, tmpFile);
481                                                                 psxCpu->Clear(section_address, section_size / 4);
482                                                         }
483                                                         break;
484                                                 case 3: /* register loading (PC only?) */
485                                                         fseek(tmpFile, 2, SEEK_CUR); /* unknown field */
486                                                         fread(&psxRegs.pc, 4, 1, tmpFile);
487                                                         psxRegs.pc = SWAPu32(psxRegs.pc);
488                                                         break;
489                                                 case 0: /* End of file */
490                                                         break;
491                                                 default:
492                                                         SysPrintf(_("Unknown CPE opcode %02x at position %08x.\n"), opcode, ftell(tmpFile) - 1);
493                                                         retval = -1;
494                                                         break;
495                                         }
496                                 } while (opcode != 0 && retval == 0);
497                                 break;
498                         case COFF_EXE:
499                                 SysPrintf(_("COFF files not supported.\n"));
500                                 retval = -1;
501                                 break;
502                         case INVALID_EXE:
503                                 SysPrintf(_("This file does not appear to be a valid PSX file.\n"));
504                                 retval = -1;
505                                 break;
506                 }
507         }
508
509         if (retval != 0) {
510                 CdromId[0] = '\0';
511                 CdromLabel[0] = '\0';
512         }
513
514         return retval;
515 }
516
517 // STATES
518
519 static const char PcsxHeader[32] = "STv4 PCSX v" PACKAGE_VERSION;
520
521 // Savestate Versioning!
522 // If you make changes to the savestate version, please increment the value below.
523 static const u32 SaveVersion = 0x8b410006;
524
525 int SaveState(const char *file) {
526         gzFile f;
527         GPUFreeze_t *gpufP;
528         SPUFreeze_t *spufP;
529         int Size;
530         unsigned char *pMem;
531
532         f = gzopen(file, "wb");
533         if (f == NULL) return -1;
534
535         new_dyna_save();
536
537         gzwrite(f, (void *)PcsxHeader, 32);
538         gzwrite(f, (void *)&SaveVersion, sizeof(u32));
539         gzwrite(f, (void *)&Config.HLE, sizeof(boolean));
540
541         pMem = (unsigned char *)malloc(128 * 96 * 3);
542         if (pMem == NULL) return -1;
543         GPU_getScreenPic(pMem);
544         gzwrite(f, pMem, 128 * 96 * 3);
545         free(pMem);
546
547         if (Config.HLE)
548                 psxBiosFreeze(1);
549
550         gzwrite(f, psxM, 0x00200000);
551         gzwrite(f, psxR, 0x00080000);
552         gzwrite(f, psxH, 0x00010000);
553         gzwrite(f, (void *)&psxRegs, sizeof(psxRegs));
554
555         // gpu
556         gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
557         gpufP->ulFreezeVersion = 1;
558         GPU_freeze(1, gpufP);
559         gzwrite(f, gpufP, sizeof(GPUFreeze_t));
560         free(gpufP);
561
562         // spu
563         spufP = (SPUFreeze_t *) malloc(16);
564         SPU_freeze(2, spufP);
565         Size = spufP->Size; gzwrite(f, &Size, 4);
566         free(spufP);
567         spufP = (SPUFreeze_t *) malloc(Size);
568         SPU_freeze(1, spufP);
569         gzwrite(f, spufP, Size);
570         free(spufP);
571
572         sioFreeze(f, 1);
573         cdrFreeze(f, 1);
574         psxHwFreeze(f, 1);
575         psxRcntFreeze(f, 1);
576         mdecFreeze(f, 1);
577
578         gzclose(f);
579
580         new_dyna_after_save();
581
582         return 0;
583 }
584
585 int LoadState(const char *file) {
586         gzFile f;
587         GPUFreeze_t *gpufP;
588         SPUFreeze_t *spufP;
589         int Size;
590         char header[32];
591         u32 version;
592         boolean hle;
593
594         f = gzopen(file, "rb");
595         if (f == NULL) return -1;
596
597         gzread(f, header, sizeof(header));
598         gzread(f, &version, sizeof(u32));
599         gzread(f, &hle, sizeof(boolean));
600
601         if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion) {
602                 gzclose(f);
603                 return -1;
604         }
605         Config.HLE = hle;
606
607         if (Config.HLE)
608                 psxBiosInit();
609
610         psxCpu->Reset();
611         gzseek(f, 128 * 96 * 3, SEEK_CUR);
612
613         gzread(f, psxM, 0x00200000);
614         gzread(f, psxR, 0x00080000);
615         gzread(f, psxH, 0x00010000);
616         gzread(f, (void *)&psxRegs, sizeof(psxRegs));
617
618         if (Config.HLE)
619                 psxBiosFreeze(0);
620
621         // gpu
622         gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
623         gzread(f, gpufP, sizeof(GPUFreeze_t));
624         GPU_freeze(0, gpufP);
625         free(gpufP);
626         if (HW_GPU_STATUS == 0)
627                 HW_GPU_STATUS = GPU_readStatus();
628
629         // spu
630         gzread(f, &Size, 4);
631         spufP = (SPUFreeze_t *)malloc(Size);
632         gzread(f, spufP, Size);
633         SPU_freeze(0, spufP);
634         free(spufP);
635
636         sioFreeze(f, 0);
637         cdrFreeze(f, 0);
638         psxHwFreeze(f, 0);
639         psxRcntFreeze(f, 0);
640         mdecFreeze(f, 0);
641
642         gzclose(f);
643         new_dyna_restore();
644
645         return 0;
646 }
647
648 int CheckState(const char *file) {
649         gzFile f;
650         char header[32];
651         u32 version;
652         boolean hle;
653
654         f = gzopen(file, "rb");
655         if (f == NULL) return -1;
656
657         gzread(f, header, sizeof(header));
658         gzread(f, &version, sizeof(u32));
659         gzread(f, &hle, sizeof(boolean));
660
661         gzclose(f);
662
663         if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion)
664                 return -1;
665
666         return 0;
667 }
668
669 // NET Function Helpers
670
671 int SendPcsxInfo() {
672         if (NET_recvData == NULL || NET_sendData == NULL)
673                 return 0;
674
675         NET_sendData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
676         NET_sendData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
677         NET_sendData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
678         NET_sendData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
679         NET_sendData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
680         NET_sendData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
681
682         return 0;
683 }
684
685 int RecvPcsxInfo() {
686         int tmp;
687
688         if (NET_recvData == NULL || NET_sendData == NULL)
689                 return 0;
690
691         NET_recvData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
692         NET_recvData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
693         NET_recvData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
694         NET_recvData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
695         NET_recvData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
696
697         SysUpdate();
698
699         tmp = Config.Cpu;
700         NET_recvData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
701         if (tmp != Config.Cpu) {
702                 psxCpu->Shutdown();
703 #ifdef PSXREC
704                 if (Config.Cpu == CPU_INTERPRETER) psxCpu = &psxInt;
705                 else psxCpu = &psxRec;
706 #else
707                 psxCpu = &psxInt;
708 #endif
709                 if (psxCpu->Init() == -1) {
710                         SysClose(); return -1;
711                 }
712                 psxCpu->Reset();
713         }
714
715         return 0;
716 }
717
718 // remove the leading and trailing spaces in a string
719 void trim(char *str) {
720         int pos = 0;
721         char *dest = str;
722
723         // skip leading blanks
724         while (str[pos] <= ' ' && str[pos] > 0)
725                 pos++;
726
727         while (str[pos]) {
728                 *(dest++) = str[pos];
729                 pos++;
730         }
731
732         *(dest--) = '\0'; // store the null
733
734         // remove trailing blanks
735         while (dest >= str && *dest <= ' ' && *dest > 0)
736                 *(dest--) = '\0';
737 }
738
739 // lookup table for crc calculation
740 static unsigned short crctab[256] = {
741         0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
742         0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
743         0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
744         0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
745         0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
746         0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
747         0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
748         0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
749         0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
750         0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
751         0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
752         0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
753         0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
754         0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
755         0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
756         0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
757         0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
758         0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
759         0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
760         0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
761         0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
762         0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
763         0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
764         0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
765         0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
766         0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
767         0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
768         0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
769         0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
770 };
771
772 u16 calcCrc(u8 *d, int len) {
773         u16 crc = 0;
774         int i;
775
776         for (i = 0; i < len; i++) {
777                 crc = crctab[(crc >> 8) ^ d[i]] ^ (crc << 8);
778         }
779
780         return ~crc;
781 }