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