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