misc: make error message remind about common mistake
[pcsx_rearmed.git] / libpcsxcore / misc.c
CommitLineData
ef79bbde
P
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"
ddbaf678 27#include "gpu.h"
ef79bbde
P
28#include "ppf.h"
29
30char CdromId[10] = "";
31char 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
41struct 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
55void mmssdd( char *b, char *p )
56{
57 int m, s, d;
507aaf98 58#if defined(__arm__)
59 int block = (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0];
60#elif defined(__BIGENDIAN__)
ef79bbde
P
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; \
305c8c93 96 buf = (void *)CDR_getBuffer(); \
97 if (buf == NULL) return -1; \
98 else CheckPPFCache((u8 *)buf, time[0], time[1], time[2]);
ef79bbde
P
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
305c8c93 108int GetCdromFile(u8 *mdir, u8 *time, char *filename) {
ef79bbde 109 struct iso_directory_record *dir;
305c8c93 110 u8 ddir[4096];
ef79bbde
P
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
f3a78e7e 146static const unsigned int gpu_ctl_def[] = {
147 0x00000000, 0x01000000, 0x03000000, 0x04000000,
148 0x05000800, 0x06c60260, 0x0703fc10, 0x08000027,
149};
150
151static const unsigned int gpu_data_def[] = {
152 0xe100360b, 0xe2000000, 0xe3000800, 0xe4077e7f,
153 0xe5001000, 0xe6000000,
154 0x02000000, 0x00000000, 0x01ff03ff,
155};
156
157static 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
ef79bbde
P
168int LoadCdrom() {
169 EXE_HEADER tmpHead;
170 struct iso_directory_record *dir;
171 u8 time[4], *buf;
172 u8 mdir[4096];
305c8c93 173 char exename[256];
ef79bbde 174
f3a78e7e 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
ef79bbde 179 if (!Config.HLE) {
f3a78e7e 180 // skip BIOS logos
ef79bbde
P
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) {
305c8c93 211 char *ptr = strstr((char *)buf + 12, "cdrom:");
ef79bbde
P
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
ebe6ff2b 241 psxCpu->Clear(tmpHead.t_addr, tmpHead.t_size / 4);
242
ef79bbde 243 // Read the rest of the main executable
ebe6ff2b 244 while (tmpHead.t_size & ~2047) {
ef79bbde
P
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
259int LoadCdromFile(const char *filename, EXE_HEADER *head) {
260 struct iso_directory_record *dir;
261 u8 time[4],*buf;
305c8c93 262 u8 mdir[4096];
263 char exename[256];
ef79bbde 264 u32 size, addr;
305c8c93 265 void *mem;
ef79bbde
P
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
ebe6ff2b 288 psxCpu->Clear(addr, size / 4);
289
290 while (size & ~2047) {
ef79bbde
P
291 incTime();
292 READTRACK();
293
305c8c93 294 mem = PSXM(addr);
295 if (mem)
296 memcpy(mem, buf + 12, 2048);
ef79bbde
P
297
298 size -= 2048;
299 addr += 2048;
300 }
301
302 return 0;
303}
304
305int CheckCdrom() {
306 struct iso_directory_record *dir;
305c8c93 307 unsigned char time[4];
308 char *buf;
ef79bbde
P
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
305c8c93 336 sscanf(buf + 12, "BOOT = cdrom:\\%256s", exename);
ef79bbde 337 if (GetCdromFile(mdir, time, exename) == -1) {
305c8c93 338 sscanf(buf + 12, "BOOT = cdrom:%256s", exename);
ef79bbde
P
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
0e2e3f49 373 if (CdromId[0] == '\0')
374 strcpy(CdromId, "SLUS99999");
375
ef79bbde 376 if (Config.PsxAuto) { // autodetect system (pal or ntsc)
a1dbab20 377 if (CdromId[2] == 'e' || CdromId[2] == 'E')
ef79bbde
P
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
393static 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
96bef96f 418// temporary pandora workaround..
419// FIXME: remove
420size_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
ef79bbde
P
434int 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;
ebe6ff2b 441 void *mem;
ef79bbde
P
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);
ebe6ff2b 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);
96bef96f 460 fread_to_ram(mem, section_size, 1, tmpFile);
ebe6ff2b 461 psxCpu->Clear(section_address, section_size / 4);
462 }
ef79bbde
P
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
ebe6ff2b 484 mem = PSXM(section_address);
485 if (mem != NULL) {
96bef96f 486 fread_to_ram(mem, section_size, 1, tmpFile);
ebe6ff2b 487 psxCpu->Clear(section_address, section_size / 4);
488 }
ef79bbde
P
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:
8f00f96c 509 SysPrintf(_("This file does not appear to be a valid PSX EXE file.\n"));
510 SysPrintf(_("(did you forget -cdfile ?)\n"));
ef79bbde
P
511 retval = -1;
512 break;
513 }
514 }
515
516 if (retval != 0) {
517 CdromId[0] = '\0';
518 CdromLabel[0] = '\0';
519 }
520
521 return retval;
522}
523
524// STATES
525
526static const char PcsxHeader[32] = "STv4 PCSX v" PACKAGE_VERSION;
527
528// Savestate Versioning!
529// If you make changes to the savestate version, please increment the value below.
df656dde 530static const u32 SaveVersion = 0x8b410006;
ef79bbde
P
531
532int SaveState(const char *file) {
533 gzFile f;
534 GPUFreeze_t *gpufP;
535 SPUFreeze_t *spufP;
536 int Size;
537 unsigned char *pMem;
538
539 f = gzopen(file, "wb");
540 if (f == NULL) return -1;
541
52082bc1 542 new_dyna_save();
543
ef79bbde
P
544 gzwrite(f, (void *)PcsxHeader, 32);
545 gzwrite(f, (void *)&SaveVersion, sizeof(u32));
546 gzwrite(f, (void *)&Config.HLE, sizeof(boolean));
547
548 pMem = (unsigned char *)malloc(128 * 96 * 3);
549 if (pMem == NULL) return -1;
550 GPU_getScreenPic(pMem);
551 gzwrite(f, pMem, 128 * 96 * 3);
552 free(pMem);
553
554 if (Config.HLE)
555 psxBiosFreeze(1);
556
557 gzwrite(f, psxM, 0x00200000);
558 gzwrite(f, psxR, 0x00080000);
559 gzwrite(f, psxH, 0x00010000);
560 gzwrite(f, (void *)&psxRegs, sizeof(psxRegs));
561
562 // gpu
563 gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
564 gpufP->ulFreezeVersion = 1;
565 GPU_freeze(1, gpufP);
566 gzwrite(f, gpufP, sizeof(GPUFreeze_t));
567 free(gpufP);
568
569 // spu
570 spufP = (SPUFreeze_t *) malloc(16);
571 SPU_freeze(2, spufP);
572 Size = spufP->Size; gzwrite(f, &Size, 4);
573 free(spufP);
574 spufP = (SPUFreeze_t *) malloc(Size);
575 SPU_freeze(1, spufP);
576 gzwrite(f, spufP, Size);
577 free(spufP);
578
579 sioFreeze(f, 1);
580 cdrFreeze(f, 1);
581 psxHwFreeze(f, 1);
582 psxRcntFreeze(f, 1);
583 mdecFreeze(f, 1);
584
585 gzclose(f);
586
5b8c000f 587 new_dyna_after_save();
588
ef79bbde
P
589 return 0;
590}
591
592int LoadState(const char *file) {
593 gzFile f;
594 GPUFreeze_t *gpufP;
595 SPUFreeze_t *spufP;
596 int Size;
597 char header[32];
598 u32 version;
599 boolean hle;
600
601 f = gzopen(file, "rb");
602 if (f == NULL) return -1;
603
604 gzread(f, header, sizeof(header));
605 gzread(f, &version, sizeof(u32));
606 gzread(f, &hle, sizeof(boolean));
607
33f56da1 608 if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion) {
ef79bbde
P
609 gzclose(f);
610 return -1;
611 }
33f56da1 612 Config.HLE = hle;
613
614 if (Config.HLE)
615 psxBiosInit();
ef79bbde
P
616
617 psxCpu->Reset();
618 gzseek(f, 128 * 96 * 3, SEEK_CUR);
619
620 gzread(f, psxM, 0x00200000);
621 gzread(f, psxR, 0x00080000);
622 gzread(f, psxH, 0x00010000);
623 gzread(f, (void *)&psxRegs, sizeof(psxRegs));
624
625 if (Config.HLE)
626 psxBiosFreeze(0);
627
628 // gpu
629 gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
630 gzread(f, gpufP, sizeof(GPUFreeze_t));
631 GPU_freeze(0, gpufP);
632 free(gpufP);
ddbaf678 633 if (HW_GPU_STATUS == 0)
634 HW_GPU_STATUS = GPU_readStatus();
ef79bbde
P
635
636 // spu
637 gzread(f, &Size, 4);
638 spufP = (SPUFreeze_t *)malloc(Size);
639 gzread(f, spufP, Size);
640 SPU_freeze(0, spufP);
641 free(spufP);
642
643 sioFreeze(f, 0);
644 cdrFreeze(f, 0);
645 psxHwFreeze(f, 0);
646 psxRcntFreeze(f, 0);
647 mdecFreeze(f, 0);
648
649 gzclose(f);
52082bc1 650 new_dyna_restore();
ef79bbde
P
651
652 return 0;
653}
654
655int CheckState(const char *file) {
656 gzFile f;
657 char header[32];
658 u32 version;
659 boolean hle;
660
661 f = gzopen(file, "rb");
662 if (f == NULL) return -1;
663
664 gzread(f, header, sizeof(header));
665 gzread(f, &version, sizeof(u32));
666 gzread(f, &hle, sizeof(boolean));
667
668 gzclose(f);
669
33f56da1 670 if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion)
ef79bbde
P
671 return -1;
672
673 return 0;
674}
675
676// NET Function Helpers
677
678int SendPcsxInfo() {
679 if (NET_recvData == NULL || NET_sendData == NULL)
680 return 0;
681
682 NET_sendData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
683 NET_sendData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
684 NET_sendData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
685 NET_sendData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
686 NET_sendData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
687 NET_sendData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
688
689 return 0;
690}
691
692int RecvPcsxInfo() {
693 int tmp;
694
695 if (NET_recvData == NULL || NET_sendData == NULL)
696 return 0;
697
698 NET_recvData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
699 NET_recvData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
700 NET_recvData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
701 NET_recvData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
702 NET_recvData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
703
704 SysUpdate();
705
706 tmp = Config.Cpu;
707 NET_recvData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
708 if (tmp != Config.Cpu) {
709 psxCpu->Shutdown();
710#ifdef PSXREC
711 if (Config.Cpu == CPU_INTERPRETER) psxCpu = &psxInt;
712 else psxCpu = &psxRec;
713#else
714 psxCpu = &psxInt;
715#endif
716 if (psxCpu->Init() == -1) {
717 SysClose(); return -1;
718 }
719 psxCpu->Reset();
720 }
721
722 return 0;
723}
724
725// remove the leading and trailing spaces in a string
726void trim(char *str) {
727 int pos = 0;
728 char *dest = str;
729
730 // skip leading blanks
731 while (str[pos] <= ' ' && str[pos] > 0)
732 pos++;
733
734 while (str[pos]) {
735 *(dest++) = str[pos];
736 pos++;
737 }
738
739 *(dest--) = '\0'; // store the null
740
741 // remove trailing blanks
742 while (dest >= str && *dest <= ' ' && *dest > 0)
743 *(dest--) = '\0';
744}
745
746// lookup table for crc calculation
747static unsigned short crctab[256] = {
748 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
749 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
750 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
751 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
752 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
753 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
754 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
755 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
756 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
757 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
758 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
759 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
760 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
761 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
762 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
763 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
764 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
765 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
766 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
767 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
768 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
769 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
770 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
771 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
772 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
773 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
774 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
775 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
776 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
777};
778
779u16 calcCrc(u8 *d, int len) {
780 u16 crc = 0;
781 int i;
782
783 for (i = 0; i < len; i++) {
784 crc = crctab[(crc >> 8) ^ d[i]] ^ (crc << 8);
785 }
786
787 return ~crc;
788}