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