misc: invaliadte dynarec on HLE file loads
[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 "ppf.h"
28
29 char CdromId[10] = "";
30 char 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
40 struct 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
54 void mmssdd( char *b, char *p )
55 {
56         int m, s, d;
57 #if defined(__arm__)
58         int block = (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0];
59 #elif defined(__BIGENDIAN__)
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
106 int 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
144 int 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
212         psxCpu->Clear(tmpHead.t_addr, tmpHead.t_size / 4);
213
214         // Read the rest of the main executable
215         while (tmpHead.t_size & ~2047) {
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
230 int 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
257         psxCpu->Clear(addr, size / 4);
258
259         while (size & ~2047) {
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
272 int 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)
340                 if (CdromId[2] == 'e' || CdromId[2] == 'E')
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
356 static 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
381 int 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;
388         void *mem;
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);
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                                 }
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
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                                                         }
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
472 static 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.
476 static const u32 SaveVersion = 0x8b410006;
477
478 int 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
488         new_dyna_save();
489
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
533         return 0;
534 }
535
536 int LoadState(const char *file) {
537         gzFile f;
538         GPUFreeze_t *gpufP;
539         SPUFreeze_t *spufP;
540         int Size;
541         char header[32];
542         u32 version;
543         boolean hle;
544
545         f = gzopen(file, "rb");
546         if (f == NULL) return -1;
547
548         gzread(f, header, sizeof(header));
549         gzread(f, &version, sizeof(u32));
550         gzread(f, &hle, sizeof(boolean));
551
552         if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion) {
553                 gzclose(f);
554                 return -1;
555         }
556         Config.HLE = hle;
557
558         if (Config.HLE)
559                 psxBiosInit();
560
561         psxCpu->Reset();
562         gzseek(f, 128 * 96 * 3, SEEK_CUR);
563
564         gzread(f, psxM, 0x00200000);
565         gzread(f, psxR, 0x00080000);
566         gzread(f, psxH, 0x00010000);
567         gzread(f, (void *)&psxRegs, sizeof(psxRegs));
568
569         if (Config.HLE)
570                 psxBiosFreeze(0);
571
572         // gpu
573         gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
574         gzread(f, gpufP, sizeof(GPUFreeze_t));
575         GPU_freeze(0, gpufP);
576         free(gpufP);
577
578         // spu
579         gzread(f, &Size, 4);
580         spufP = (SPUFreeze_t *)malloc(Size);
581         gzread(f, spufP, Size);
582         SPU_freeze(0, spufP);
583         free(spufP);
584
585         sioFreeze(f, 0);
586         cdrFreeze(f, 0);
587         psxHwFreeze(f, 0);
588         psxRcntFreeze(f, 0);
589         mdecFreeze(f, 0);
590
591         gzclose(f);
592         new_dyna_restore();
593
594         return 0;
595 }
596
597 int CheckState(const char *file) {
598         gzFile f;
599         char header[32];
600         u32 version;
601         boolean hle;
602
603         f = gzopen(file, "rb");
604         if (f == NULL) return -1;
605
606         gzread(f, header, sizeof(header));
607         gzread(f, &version, sizeof(u32));
608         gzread(f, &hle, sizeof(boolean));
609
610         gzclose(f);
611
612         if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion)
613                 return -1;
614
615         return 0;
616 }
617
618 // NET Function Helpers
619
620 int SendPcsxInfo() {
621         if (NET_recvData == NULL || NET_sendData == NULL)
622                 return 0;
623
624         NET_sendData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
625         NET_sendData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
626         NET_sendData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
627         NET_sendData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
628         NET_sendData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
629         NET_sendData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
630
631         return 0;
632 }
633
634 int RecvPcsxInfo() {
635         int tmp;
636
637         if (NET_recvData == NULL || NET_sendData == NULL)
638                 return 0;
639
640         NET_recvData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
641         NET_recvData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
642         NET_recvData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
643         NET_recvData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
644         NET_recvData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
645
646         SysUpdate();
647
648         tmp = Config.Cpu;
649         NET_recvData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
650         if (tmp != Config.Cpu) {
651                 psxCpu->Shutdown();
652 #ifdef PSXREC
653                 if (Config.Cpu == CPU_INTERPRETER) psxCpu = &psxInt;
654                 else psxCpu = &psxRec;
655 #else
656                 psxCpu = &psxInt;
657 #endif
658                 if (psxCpu->Init() == -1) {
659                         SysClose(); return -1;
660                 }
661                 psxCpu->Reset();
662         }
663
664         return 0;
665 }
666
667 // remove the leading and trailing spaces in a string
668 void trim(char *str) {
669         int pos = 0;
670         char *dest = str;
671
672         // skip leading blanks
673         while (str[pos] <= ' ' && str[pos] > 0)
674                 pos++;
675
676         while (str[pos]) {
677                 *(dest++) = str[pos];
678                 pos++;
679         }
680
681         *(dest--) = '\0'; // store the null
682
683         // remove trailing blanks
684         while (dest >= str && *dest <= ' ' && *dest > 0)
685                 *(dest--) = '\0';
686 }
687
688 // lookup table for crc calculation
689 static unsigned short crctab[256] = {
690         0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
691         0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
692         0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
693         0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
694         0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
695         0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
696         0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
697         0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
698         0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
699         0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
700         0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
701         0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
702         0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
703         0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
704         0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
705         0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
706         0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
707         0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
708         0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
709         0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
710         0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
711         0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
712         0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
713         0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
714         0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
715         0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
716         0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
717         0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
718         0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
719 };
720
721 u16 calcCrc(u8 *d, int len) {
722         u16 crc = 0;
723         int i;
724
725         for (i = 0; i < len; i++) {
726                 crc = crctab[(crc >> 8) ^ d[i]] ^ (crc << 8);
727         }
728
729         return ~crc;
730 }