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