drc: further hacks, hle handling
[pcsx_rearmed.git] / libpcsxcore / sio.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 * SIO functions.
22 */
23
24 #include "sio.h"
25 #include <sys/stat.h>
26
27 // Status Flags
28 #define TX_RDY          0x0001
29 #define RX_RDY          0x0002
30 #define TX_EMPTY        0x0004
31 #define PARITY_ERR      0x0008
32 #define RX_OVERRUN      0x0010
33 #define FRAMING_ERR     0x0020
34 #define SYNC_DETECT     0x0040
35 #define DSR                     0x0080
36 #define CTS                     0x0100
37 #define IRQ                     0x0200
38
39 // Control Flags
40 #define TX_PERM         0x0001
41 #define DTR                     0x0002
42 #define RX_PERM         0x0004
43 #define BREAK           0x0008
44 #define RESET_ERR       0x0010
45 #define RTS                     0x0020
46 #define SIO_RESET       0x0040
47
48 // *** FOR WORKS ON PADS AND MEMORY CARDS *****
49
50 static unsigned char buf[256];
51 unsigned char cardh[4] = { 0x00, 0x00, 0x5a, 0x5d };
52
53 // Transfer Ready and the Buffer is Empty
54 // static unsigned short StatReg = 0x002b;
55 static unsigned short StatReg = TX_RDY | TX_EMPTY;
56 static unsigned short ModeReg;
57 static unsigned short CtrlReg;
58 static unsigned short BaudReg;
59
60 static unsigned int bufcount;
61 static unsigned int parp;
62 static unsigned int mcdst, rdwr;
63 static unsigned char adrH, adrL;
64 static unsigned int padst;
65
66 char Mcd1Data[MCD_SIZE], Mcd2Data[MCD_SIZE];
67
68 // clk cycle byte
69 // 4us * 8bits = (PSXCLK / 1000000) * 32; (linuzappz)
70 // TODO: add SioModePrescaler and BaudReg
71 static inline void SIO_INT() {
72         if (!Config.Sio) {
73                 psxRegs.interrupt |= 0x80;
74                 psxRegs.intCycle[7 + 1] = 400;
75                 psxRegs.intCycle[7] = psxRegs.cycle;
76         }
77 }
78
79 void sioWrite8(unsigned char value) {
80 #ifdef PAD_LOG
81         PAD_LOG("sio write8 %x\n", value);
82 #endif
83         switch (padst) {
84                 case 1: SIO_INT();
85                         if ((value & 0x40) == 0x40) {
86                                 padst = 2; parp = 1;
87                                 if (!Config.UseNet) {
88                                         switch (CtrlReg & 0x2002) {
89                                                 case 0x0002:
90                                                         buf[parp] = PAD1_poll(value);
91                                                         break;
92                                                 case 0x2002:
93                                                         buf[parp] = PAD2_poll(value);
94                                                         break;
95                                         }
96                                 }/* else {
97 //                                      SysPrintf("%x: %x, %x, %x, %x\n", CtrlReg&0x2002, buf[2], buf[3], buf[4], buf[5]);
98                                 }*/
99
100                                 if (!(buf[parp] & 0x0f)) {
101                                         bufcount = 2 + 32;
102                                 } else {
103                                         bufcount = 2 + (buf[parp] & 0x0f) * 2;
104                                 }
105                                 if (buf[parp] == 0x41) {
106                                         switch (value) {
107                                                 case 0x43:
108                                                         buf[1] = 0x43;
109                                                         break;
110                                                 case 0x45:
111                                                         buf[1] = 0xf3;
112                                                         break;
113                                         }
114                                 }
115                         }
116                         else padst = 0;
117                         return;
118                 case 2:
119                         parp++;
120 /*                      if (buf[1] == 0x45) {
121                                 buf[parp] = 0;
122                                 SIO_INT();
123                                 return;
124                         }*/
125                         if (!Config.UseNet) {
126                                 switch (CtrlReg & 0x2002) {
127                                         case 0x0002: buf[parp] = PAD1_poll(value); break;
128                                         case 0x2002: buf[parp] = PAD2_poll(value); break;
129                                 }
130                         }
131
132                         if (parp == bufcount) { padst = 0; return; }
133                         SIO_INT();
134                         return;
135         }
136
137         switch (mcdst) {
138                 case 1:
139                         SIO_INT();
140                         if (rdwr) { parp++; return; }
141                         parp = 1;
142                         switch (value) {
143                                 case 0x52: rdwr = 1; break;
144                                 case 0x57: rdwr = 2; break;
145                                 default: mcdst = 0;
146                         }
147                         return;
148                 case 2: // address H
149                         SIO_INT();
150                         adrH = value;
151                         *buf = 0;
152                         parp = 0;
153                         bufcount = 1;
154                         mcdst = 3;
155                         return;
156                 case 3: // address L
157                         SIO_INT();
158                         adrL = value;
159                         *buf = adrH;
160                         parp = 0;
161                         bufcount = 1;
162                         mcdst = 4;
163                         return;
164                 case 4:
165                         SIO_INT();
166                         parp = 0;
167                         switch (rdwr) {
168                                 case 1: // read
169                                         buf[0] = 0x5c;
170                                         buf[1] = 0x5d;
171                                         buf[2] = adrH;
172                                         buf[3] = adrL;
173                                         switch (CtrlReg & 0x2002) {
174                                                 case 0x0002:
175                                                         memcpy(&buf[4], Mcd1Data + (adrL | (adrH << 8)) * 128, 128);
176                                                         break;
177                                                 case 0x2002:
178                                                         memcpy(&buf[4], Mcd2Data + (adrL | (adrH << 8)) * 128, 128);
179                                                         break;
180                                         }
181                                         {
182                                         char xor = 0;
183                                         int i;
184                                         for (i = 2; i < 128 + 4; i++)
185                                                 xor ^= buf[i];
186                                         buf[132] = xor;
187                                         }
188                                         buf[133] = 0x47;
189                                         bufcount = 133;
190                                         break;
191                                 case 2: // write
192                                         buf[0] = adrL;
193                                         buf[1] = value;
194                                         buf[129] = 0x5c;
195                                         buf[130] = 0x5d;
196                                         buf[131] = 0x47;
197                                         bufcount = 131;
198                                         break;
199                         }
200                         mcdst = 5;
201                         return;
202                 case 5:
203                         parp++;
204                         if (rdwr == 2) {
205                                 if (parp < 128) buf[parp + 1] = value;
206                         }
207                         SIO_INT();
208                         return;
209         }
210
211         switch (value) {
212                 case 0x01: // start pad
213                         StatReg |= RX_RDY;              // Transfer is Ready
214
215                         if (!Config.UseNet) {
216                                 switch (CtrlReg & 0x2002) {
217                                         case 0x0002: buf[0] = PAD1_startPoll(1); break;
218                                         case 0x2002: buf[0] = PAD2_startPoll(2); break;
219                                 }
220                         } else {
221                                 if ((CtrlReg & 0x2002) == 0x0002) {
222                                         int i, j;
223
224                                         PAD1_startPoll(1);
225                                         buf[0] = 0;
226                                         buf[1] = PAD1_poll(0x42);
227                                         if (!(buf[1] & 0x0f)) {
228                                                 bufcount = 32;
229                                         } else {
230                                                 bufcount = (buf[1] & 0x0f) * 2;
231                                         }
232                                         buf[2] = PAD1_poll(0);
233                                         i = 3;
234                                         j = bufcount;
235                                         while (j--) {
236                                                 buf[i++] = PAD1_poll(0);
237                                         }
238                                         bufcount+= 3;
239
240                                         if (NET_sendPadData(buf, bufcount) == -1)
241                                                 netError();
242
243                                         if (NET_recvPadData(buf, 1) == -1)
244                                                 netError();
245                                         if (NET_recvPadData(buf + 128, 2) == -1)
246                                                 netError();
247                                 } else {
248                                         memcpy(buf, buf + 128, 32);
249                                 }
250                         }
251
252                         bufcount = 2;
253                         parp = 0;
254                         padst = 1;
255                         SIO_INT();
256                         return;
257                 case 0x81: // start memcard
258                         StatReg |= RX_RDY;
259                         memcpy(buf, cardh, 4);
260                         parp = 0;
261                         bufcount = 3;
262                         mcdst = 1;
263                         rdwr = 0;
264                         SIO_INT();
265                         return;
266         }
267 }
268
269 void sioWriteStat16(unsigned short value) {
270 }
271
272 void sioWriteMode16(unsigned short value) {
273         ModeReg = value;
274 }
275
276 void sioWriteCtrl16(unsigned short value) {
277         CtrlReg = value & ~RESET_ERR;
278         if (value & RESET_ERR) StatReg &= ~IRQ;
279         if ((CtrlReg & SIO_RESET) || (!CtrlReg)) {
280                 padst = 0; mcdst = 0; parp = 0;
281                 StatReg = TX_RDY | TX_EMPTY;
282                 psxRegs.interrupt &= ~0x80;
283         }
284 }
285
286 void sioWriteBaud16(unsigned short value) {
287         BaudReg = value;
288 }
289
290 unsigned char sioRead8() {
291         unsigned char ret = 0;
292
293         if ((StatReg & RX_RDY)/* && (CtrlReg & RX_PERM)*/) {
294 //              StatReg &= ~RX_OVERRUN;
295                 ret = buf[parp];
296                 if (parp == bufcount) {
297                         StatReg &= ~RX_RDY;             // Receive is not Ready now
298                         if (mcdst == 5) {
299                                 mcdst = 0;
300                                 if (rdwr == 2) {
301                                         switch (CtrlReg & 0x2002) {
302                                                 case 0x0002:
303                                                         memcpy(Mcd1Data + (adrL | (adrH << 8)) * 128, &buf[1], 128);
304                                                         SaveMcd(Config.Mcd1, Mcd1Data, (adrL | (adrH << 8)) * 128, 128);
305                                                         break;
306                                                 case 0x2002:
307                                                         memcpy(Mcd2Data + (adrL | (adrH << 8)) * 128, &buf[1], 128);
308                                                         SaveMcd(Config.Mcd2, Mcd2Data, (adrL | (adrH << 8)) * 128, 128);
309                                                         break;
310                                         }
311                                 }
312                         }
313                         if (padst == 2) padst = 0;
314                         if (mcdst == 1) {
315                                 mcdst = 2;
316                                 StatReg|= RX_RDY;
317                         }
318                 }
319         }
320
321 #ifdef PAD_LOG
322         PAD_LOG("sio read8 ;ret = %x\n", ret);
323 #endif
324         return ret;
325 }
326
327 unsigned short sioReadStat16() {
328         return StatReg;
329 }
330
331 unsigned short sioReadMode16() {
332         return ModeReg;
333 }
334
335 unsigned short sioReadCtrl16() {
336         return CtrlReg;
337 }
338
339 unsigned short sioReadBaud16() {
340         return BaudReg;
341 }
342
343 void netError() {
344         ClosePlugins();
345         SysMessage(_("Connection closed!\n"));
346
347         CdromId[0] = '\0';
348         CdromLabel[0] = '\0';
349
350         SysRunGui();
351 }
352
353 void sioInterrupt() {
354 #ifdef PAD_LOG
355         PAD_LOG("Sio Interrupt (CP0.Status = %x)\n", psxRegs.CP0.n.Status);
356 #endif
357 //      SysPrintf("Sio Interrupt\n");
358         StatReg |= IRQ;
359         psxHu32ref(0x1070) |= SWAPu32(0x80);
360 }
361
362 void LoadMcd(int mcd, char *str) {
363         FILE *f;
364         char *data = NULL;
365
366         if (mcd == 1) data = Mcd1Data;
367         if (mcd == 2) data = Mcd2Data;
368
369         if (*str == 0) {
370                 sprintf(str, "memcards/card%d.mcd", mcd);
371                 SysPrintf(_("No memory card value was specified - creating a default card %s\n"), str);
372         }
373         f = fopen(str, "rb");
374         if (f == NULL) {
375                 SysPrintf(_("The memory card %s doesn't exist - creating it\n"), str);
376                 CreateMcd(str);
377                 f = fopen(str, "rb");
378                 if (f != NULL) {
379                         struct stat buf;
380
381                         if (stat(str, &buf) != -1) {
382                                 if (buf.st_size == MCD_SIZE + 64)
383                                         fseek(f, 64, SEEK_SET);
384                                 else if(buf.st_size == MCD_SIZE + 3904)
385                                         fseek(f, 3904, SEEK_SET);
386                         }
387                         fread(data, 1, MCD_SIZE, f);
388                         fclose(f);
389                 }
390                 else
391                         SysMessage(_("Memory card %s failed to load!\n"), str);
392         }
393         else {
394                 struct stat buf;
395                 SysPrintf(_("Loading memory card %s\n"), str);
396                 if (stat(str, &buf) != -1) {
397                         if (buf.st_size == MCD_SIZE + 64)
398                                 fseek(f, 64, SEEK_SET);
399                         else if(buf.st_size == MCD_SIZE + 3904)
400                                 fseek(f, 3904, SEEK_SET);
401                 }
402                 fread(data, 1, MCD_SIZE, f);
403                 fclose(f);
404         }
405 }
406
407 void LoadMcds(char *mcd1, char *mcd2) {
408         LoadMcd(1, mcd1);
409         LoadMcd(2, mcd2);
410 }
411
412 void SaveMcd(char *mcd, char *data, uint32_t adr, int size) {
413         FILE *f;
414
415         f = fopen(mcd, "r+b");
416         if (f != NULL) {
417                 struct stat buf;
418
419                 if (stat(mcd, &buf) != -1) {
420                         if (buf.st_size == MCD_SIZE + 64)
421                                 fseek(f, adr + 64, SEEK_SET);
422                         else if (buf.st_size == MCD_SIZE + 3904)
423                                 fseek(f, adr + 3904, SEEK_SET);
424                         else
425                                 fseek(f, adr, SEEK_SET);
426                 } else
427                         fseek(f, adr, SEEK_SET);
428
429                 fwrite(data + adr, 1, size, f);
430                 fclose(f);
431                 return;
432         }
433
434 #if 0
435         // try to create it again if we can't open it
436         f = fopen(mcd, "wb");
437         if (f != NULL) {
438                 fwrite(data, 1, MCD_SIZE, f);
439                 fclose(f);
440         }
441 #endif
442
443         ConvertMcd(mcd, data);
444 }
445
446 void CreateMcd(char *mcd) {
447         FILE *f;
448         struct stat buf;
449         int s = MCD_SIZE;
450         int i = 0, j;
451
452         f = fopen(mcd, "wb");
453         if (f == NULL)
454                 return;
455
456         if (stat(mcd, &buf) != -1) {
457                 if ((buf.st_size == MCD_SIZE + 3904) || strstr(mcd, ".gme")) {
458                         s = s + 3904;
459                         fputc('1', f);
460                         s--;
461                         fputc('2', f);
462                         s--;
463                         fputc('3', f);
464                         s--;
465                         fputc('-', f);
466                         s--;
467                         fputc('4', f);
468                         s--;
469                         fputc('5', f);
470                         s--;
471                         fputc('6', f);
472                         s--;
473                         fputc('-', f);
474                         s--;
475                         fputc('S', f);
476                         s--;
477                         fputc('T', f);
478                         s--;
479                         fputc('D', f);
480                         s--;
481                         for (i = 0; i < 7; i++) {
482                                 fputc(0, f);
483                                 s--;
484                         }
485                         fputc(1, f);
486                         s--;
487                         fputc(0, f);
488                         s--;
489                         fputc(1, f);
490                         s--;
491                         fputc('M', f);
492                         s--;
493                         fputc('Q', f);
494                         s--;
495                         for (i = 0; i < 14; i++) {
496                                 fputc(0xa0, f);
497                                 s--;
498                         }
499                         fputc(0, f);
500                         s--;
501                         fputc(0xff, f);
502                         while (s-- > (MCD_SIZE + 1))
503                                 fputc(0, f);
504                 } else if ((buf.st_size == MCD_SIZE + 64) || strstr(mcd, ".mem") || strstr(mcd, ".vgs")) {
505                         s = s + 64;
506                         fputc('V', f);
507                         s--;
508                         fputc('g', f);
509                         s--;
510                         fputc('s', f);
511                         s--;
512                         fputc('M', f);
513                         s--;
514                         for (i = 0; i < 3; i++) {
515                                 fputc(1, f);
516                                 s--;
517                                 fputc(0, f);
518                                 s--;
519                                 fputc(0, f);
520                                 s--;
521                                 fputc(0, f);
522                                 s--;
523                         }
524                         fputc(0, f);
525                         s--;
526                         fputc(2, f);
527                         while (s-- > (MCD_SIZE + 1))
528                                 fputc(0, f);
529                 }
530         }
531         fputc('M', f);
532         s--;
533         fputc('C', f);
534         s--;
535         while (s-- > (MCD_SIZE - 127))
536                 fputc(0, f);
537         fputc(0xe, f);
538         s--;
539
540         for (i = 0; i < 15; i++) { // 15 blocks
541                 fputc(0xa0, f);
542                 s--;
543                 fputc(0x00, f);
544                 s--;
545                 fputc(0x00, f);
546                 s--;
547                 fputc(0x00, f);
548                 s--;
549                 fputc(0x00, f);
550                 s--;
551                 fputc(0x00, f);
552                 s--;
553                 fputc(0x00, f);
554                 s--;
555                 fputc(0x00, f);
556                 s--;
557                 fputc(0xff, f);
558                 s--;
559                 fputc(0xff, f);
560                 s--;
561                 for (j = 0; j < 117; j++) {
562                         fputc(0x00, f);
563                         s--;
564                 }
565                 fputc(0xa0, f);
566                 s--;
567         }
568
569         for (i = 0; i < 20; i++) {
570                 fputc(0xff, f);
571                 s--;
572                 fputc(0xff, f);
573                 s--;
574                 fputc(0xff, f);
575                 s--;
576                 fputc(0xff, f);
577                 s--;
578                 fputc(0x00, f);
579                 s--;
580                 fputc(0x00, f);
581                 s--;
582                 fputc(0x00, f);
583                 s--;
584                 fputc(0x00, f);
585                 s--;
586                 fputc(0xff, f);
587                 s--;
588                 fputc(0xff, f);
589                 s--;
590                 for (j = 0; j < 118; j++) {
591                         fputc(0x00, f);
592                         s--;
593                 }
594         }
595
596         while ((s--) >= 0)
597                 fputc(0, f);
598
599         fclose(f);
600 }
601
602 void ConvertMcd(char *mcd, char *data) {
603         FILE *f;
604         int i = 0;
605         int s = MCD_SIZE;
606
607         if (strstr(mcd, ".gme")) {
608                 f = fopen(mcd, "wb");
609                 if (f != NULL) {
610                         fwrite(data - 3904, 1, MCD_SIZE + 3904, f);
611                         fclose(f);
612                 }
613                 f = fopen(mcd, "r+");
614                 s = s + 3904;
615                 fputc('1', f); s--;
616                 fputc('2', f); s--;
617                 fputc('3', f); s--;
618                 fputc('-', f); s--;
619                 fputc('4', f); s--;
620                 fputc('5', f); s--;
621                 fputc('6', f); s--;
622                 fputc('-', f); s--;
623                 fputc('S', f); s--;
624                 fputc('T', f); s--;
625                 fputc('D', f); s--;
626                 for (i = 0; i < 7; i++) {
627                         fputc(0, f); s--;
628                 }
629                 fputc(1, f); s--;
630                 fputc(0, f); s--;
631                 fputc(1, f); s--;
632                 fputc('M', f); s--;
633                 fputc('Q', f); s--;
634                 for(i=0;i<14;i++) {
635                         fputc(0xa0, f); s--;
636                 }
637                 fputc(0, f); s--;
638                 fputc(0xff, f);
639                 while (s-- > (MCD_SIZE+1)) fputc(0, f);
640                 fclose(f);
641         } else if(strstr(mcd, ".mem") || strstr(mcd,".vgs")) {
642                 f = fopen(mcd, "wb");
643                 if (f != NULL) {
644                         fwrite(data-64, 1, MCD_SIZE+64, f);
645                         fclose(f);
646                 }
647                 f = fopen(mcd, "r+");
648                 s = s + 64;
649                 fputc('V', f); s--;
650                 fputc('g', f); s--;
651                 fputc('s', f); s--;
652                 fputc('M', f); s--;
653                 for(i=0;i<3;i++) {
654                         fputc(1, f); s--;
655                         fputc(0, f); s--;
656                         fputc(0, f); s--;
657                         fputc(0, f); s--;
658                 }
659                 fputc(0, f); s--;
660                 fputc(2, f);
661                 while (s-- > (MCD_SIZE+1)) fputc(0, f);
662                 fclose(f);
663         } else {
664                 f = fopen(mcd, "wb");
665                 if (f != NULL) {
666                         fwrite(data, 1, MCD_SIZE, f);
667                         fclose(f);
668                 }
669         }
670 }
671
672 void GetMcdBlockInfo(int mcd, int block, McdBlock *Info) {
673         unsigned char *data = NULL, *ptr, *str, *sstr;
674         unsigned short clut[16];
675         unsigned short c;
676         int i, x;
677
678         memset(Info, 0, sizeof(McdBlock));
679
680         if (mcd == 1) data = Mcd1Data;
681         if (mcd == 2) data = Mcd2Data;
682
683         ptr = data + block * 8192 + 2;
684
685         Info->IconCount = *ptr & 0x3;
686
687         ptr += 2;
688
689         x = 0;
690
691         str = Info->Title;
692         sstr = Info->sTitle;
693
694         for (i = 0; i < 48; i++) {
695                 c = *(ptr) << 8;
696                 c |= *(ptr + 1);
697                 if (!c) break;
698
699                 // Convert ASCII characters to half-width
700                 if (c >= 0x8281 && c <= 0x829A)
701                         c = (c - 0x8281) + 'a';
702                 else if (c >= 0x824F && c <= 0x827A)
703                         c = (c - 0x824F) + '0';
704                 else if (c == 0x8140) c = ' ';
705                 else if (c == 0x8143) c = ',';
706                 else if (c == 0x8144) c = '.';
707                 else if (c == 0x8146) c = ':';
708                 else if (c == 0x8147) c = ';';
709                 else if (c == 0x8148) c = '?';
710                 else if (c == 0x8149) c = '!';
711                 else if (c == 0x815E) c = '/';
712                 else if (c == 0x8168) c = '"';
713                 else if (c == 0x8169) c = '(';
714                 else if (c == 0x816A) c = ')';
715                 else if (c == 0x816D) c = '[';
716                 else if (c == 0x816E) c = ']';
717                 else if (c == 0x817C) c = '-';
718                 else {
719                         str[i] = ' ';
720                         sstr[x++] = *ptr++; sstr[x++] = *ptr++;
721                         continue;
722                 }
723
724                 str[i] = sstr[x++] = c;
725                 ptr += 2;
726         }
727
728         trim(str);
729         trim(sstr);
730
731         ptr = data + block * 8192 + 0x60; // icon palette data
732
733         for (i = 0; i < 16; i++) {
734                 clut[i] = *((unsigned short *)ptr);
735                 ptr += 2;
736         }
737
738         for (i = 0; i < Info->IconCount; i++) {
739                 short *icon = &Info->Icon[i * 16 * 16];
740
741                 ptr = data + block * 8192 + 128 + 128 * i; // icon data
742
743                 for (x = 0; x < 16 * 16; x++) {
744                         icon[x++] = clut[*ptr & 0xf];
745                         icon[x] = clut[*ptr >> 4];
746                         ptr++;
747                 }
748         }
749
750         ptr = data + block * 128;
751
752         Info->Flags = *ptr;
753
754         ptr += 0xa;
755         strncpy(Info->ID, ptr, 12);
756         ptr += 12;
757         strncpy(Info->Name, ptr, 16);
758 }
759
760 int sioFreeze(gzFile f, int Mode) {
761         gzfreeze(buf, sizeof(buf));
762         gzfreeze(&StatReg, sizeof(StatReg));
763         gzfreeze(&ModeReg, sizeof(ModeReg));
764         gzfreeze(&CtrlReg, sizeof(CtrlReg));
765         gzfreeze(&BaudReg, sizeof(BaudReg));
766         gzfreeze(&bufcount, sizeof(bufcount));
767         gzfreeze(&parp, sizeof(parp));
768         gzfreeze(&mcdst, sizeof(mcdst));
769         gzfreeze(&rdwr, sizeof(rdwr));
770         gzfreeze(&adrH, sizeof(adrH));
771         gzfreeze(&adrL, sizeof(adrL));
772         gzfreeze(&padst, sizeof(padst));
773
774         return 0;
775 }