1 /*
2 smc.c - Super Magic Card support for uCON64
3 
4 Copyright (c) 2003, 2019 - 2020 dbjh
5 
6 
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21 #ifdef  HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 #ifdef  _MSC_VER
25 #pragma warning(push)
26 #pragma warning(disable: 4668) // 'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives'
27 #endif
28 #include <stdlib.h>
29 #ifdef  _MSC_VER
30 #pragma warning(pop)
31 #endif
32 #include <string.h>
33 #include "misc/archive.h"
34 #include "misc/file.h"
35 #include "ucon64.h"
36 #include "ucon64_misc.h"
37 #include "backup/ffe.h"
38 #include "backup/smc.h"
39 
40 
41 #ifdef  USE_PARALLEL
42 static st_ucon64_obj_t smc_obj[] =
43   {
44     {UCON64_NES, WF_DEFAULT | WF_STOP | WF_NO_SPLIT},
45     {UCON64_NES, WF_STOP | WF_NO_ROM}
46   };
47 #endif
48 
49 const st_getopt2_t smc_usage[] =
50   {
51     {
52       NULL, 0, 0, 0,
53       NULL, "Super Magic Card"/*"1993/1994/1995/19XX Front Far East/FFE http://www.front.com.tw"*/,
54       NULL
55     },
56 #ifdef  USE_PARALLEL
57     {
58       "xsmc", 0, 0, UCON64_XSMC, // send only
59       NULL, "send ROM (in FFE format) to Super Magic Card; " OPTION_LONG_S "port" OPTARG_S "PORT",
60       &smc_obj[0]
61     },
62     {
63       "xsmcr", 0, 0, UCON64_XSMCR,
64       NULL, "send/receive RTS data to/from Super Magic Card; " OPTION_LONG_S "port" OPTARG_S "PORT\n"
65       "receives automatically when RTS file does not exist",
66       &smc_obj[1]
67     },
68 #endif
69     {NULL, 0, 0, 0, NULL, NULL, NULL}
70   };
71 
72 
73 #ifdef USE_PARALLEL
74 
75 #define BUFFERSIZE 8192
76 
77 
78 static unsigned int get_blocks1 (unsigned char *header);
79 static unsigned int get_blocks2 (unsigned char *header);
80 static unsigned int get_blocks3 (unsigned char *header);
81 
82 
83 unsigned int
get_blocks1(unsigned char * header)84 get_blocks1 (unsigned char *header)
85 {
86   if (header[7] == 0xaa)
87     return header[3];
88   if (header[0] & 0x30)
89     return header[0] & 0x20 ? 32 : 16;          // 0x10 => 16; 0x20/0x30 => 32
90   else
91     switch (header[1] >> 5)
92       {
93       case 0:
94       case 4:
95         return 16;
96       case 1:
97       case 2:
98       case 3:
99         return 32;
100       default:                                  // 5/6/7
101         return 4;
102       }
103 }
104 
105 
106 unsigned int
get_blocks2(unsigned char * header)107 get_blocks2 (unsigned char *header)
108 {
109   if (header[0] & 0x30)
110     return header[0] & 0x10 ? 32 : 16;          // 0x10/0x30 => 32; 0x20 => 16
111   else
112     return 0;
113 }
114 
115 
116 unsigned int
get_blocks3(unsigned char * header)117 get_blocks3 (unsigned char *header)
118 {
119   if (header[7] == 0xaa)
120     return header[4];
121   if (header[0] & 0x30)
122     return 0;
123   else
124     switch (header[1] >> 5)
125       {
126       default:                                  // 0/1/2/3
127         return 0;
128       case 4:
129       case 5:
130         return 4;
131       case 6:
132         return 2;
133       case 7:
134         return 1;
135       }
136 }
137 
138 
139 int
smc_write_rom(const char * filename,unsigned short parport)140 smc_write_rom (const char *filename, unsigned short parport)
141 {
142   FILE *file;
143   unsigned char *buffer;
144   size_t bytesread, bytessent;
145   unsigned int size, offset, n_blocks1, n_blocks2, n_blocks3, n;
146   time_t starttime;
147 
148   ffe_init_io (parport);
149 
150   if ((file = fopen (filename, "rb")) == NULL)
151     {
152       fprintf (stderr, ucon64_msg[OPEN_READ_ERROR], filename);
153       exit (1);
154     }
155   if ((buffer = (unsigned char *) malloc (BUFFERSIZE)) == NULL)
156     {
157       fprintf (stderr, ucon64_msg[FILE_BUFFER_ERROR], BUFFERSIZE);
158       exit (1);
159     }
160 
161   ffe_send_command0 (0x4500, 2);
162   ffe_send_command0 (0x42fd, 0x20);
163   ffe_send_command0 (0x43fc, 0);
164 
165   fread_checked (buffer, 1, SMC_HEADER_LEN, file);
166 
167   n_blocks1 = get_blocks1 (buffer);
168   n_blocks2 = get_blocks2 (buffer);
169   n_blocks3 = get_blocks3 (buffer);
170 
171   size = (n_blocks1 + n_blocks2 + n_blocks3) * 8 * 1024 + 8 +
172          (buffer[0] & SMC_TRAINER ? 512 : 0);
173   printf ("Send: %u Bytes (%.4f Mb)\n", size, (float) size / MBIT);
174 
175   ffe_send_block (0x5020, buffer, 8);           // send "file control block"
176   bytessent = 8;
177 
178   if (buffer[1] >> 5 > 4)
179     offset = 12;
180   else
181     offset = 0;
182 
183   if (buffer[0] & SMC_TRAINER)                  // send trainer if present
184     {
185       fread_checked (buffer, 1, 512, file);
186       ffe_send_block (0x600, buffer, 512);
187       bytessent += 512;
188     }
189 
190   puts ("Press q to abort\n");
191   starttime = time (NULL);
192 
193   for (n = 0; n < n_blocks1; n++)
194     {
195       ffe_send_command0 (0x4507, (unsigned char) (n + offset));
196       if ((bytesread = fread (buffer, 1, BUFFERSIZE, file)) == 0)
197         break;
198       ffe_send_block (0x6000, buffer, (unsigned short) bytesread);
199 
200       bytessent += bytesread;
201       ucon64_gauge (starttime, bytessent, size);
202       ffe_checkabort (2);
203     }
204 
205   for (n = 0; n < n_blocks2; n++)
206     {
207       ffe_send_command0 (0x4507, (unsigned char) (n + 32));
208       if ((bytesread = fread (buffer, 1, BUFFERSIZE, file)) == 0)
209         break;
210       ffe_send_block (0x6000, buffer, (unsigned short) bytesread);
211 
212       bytessent += bytesread;
213       ucon64_gauge (starttime, bytessent, size);
214       ffe_checkabort (2);
215     }
216 
217   ffe_send_command0 (0x2001, 0);
218 
219   for (n = 0; n < n_blocks3; n++)
220     {
221       if (n == 0)
222         {
223           ffe_send_command0 (0x4500, 0x22);
224           ffe_send_command0 (0x42ff, 0x30);
225           if ((bytesread = fread (buffer, 1, BUFFERSIZE, file)) == 0)
226             break;
227           ffe_send_block (0x6000, buffer, (unsigned short) bytesread);
228         }
229       else
230         {
231           int m;
232 
233           ffe_send_command0 (0x4500, 7);
234           for (m = 0; m < 8; m++)
235             ffe_send_command0 ((unsigned short) (0x4510 + m), (unsigned char) (n * 8 + m));
236           if ((bytesread = fread (buffer, 1, BUFFERSIZE, file)) == 0)
237             break;
238           ffe_send_block2 (0, buffer, (unsigned short) bytesread);
239         }
240 
241       bytessent += bytesread;
242       ucon64_gauge (starttime, bytessent, size);
243       ffe_checkabort (2);
244     }
245 
246   for (n = 0x4504; n < 0x4508; n++)
247     ffe_send_command0 ((unsigned short) n, 0);
248   for (n = 0x4510; n < 0x451c; n++)
249     ffe_send_command0 ((unsigned short) n, 0);
250 
251   ffe_send_command (5, 1, 0);
252 
253   free (buffer);
254   fclose (file);
255 
256   return 0;
257 }
258 
259 
260 int
smc_read_rts(const char * filename,unsigned short parport)261 smc_read_rts (const char *filename, unsigned short parport)
262 {
263   FILE *file;
264   unsigned char *buffer;
265   unsigned int bytesreceived = 0, size, n;
266   time_t starttime;
267 
268   ffe_init_io (parport);
269 
270   if ((file = fopen (filename, "wb")) == NULL)
271     {
272       fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], filename);
273       exit (1);
274     }
275   if ((buffer = (unsigned char *) malloc (BUFFERSIZE)) == NULL)
276     {
277       fprintf (stderr, ucon64_msg[FILE_BUFFER_ERROR], BUFFERSIZE);
278       exit (1);
279     }
280 
281   size = 0x68 + 4 * 1024 + 5 * 8 * 1024;
282   printf ("Receive: %u Bytes\n", size);
283   memset (buffer, 0, SMC_HEADER_LEN);
284   buffer[8] = 0xaa;
285   buffer[9] = 0xbb;
286   buffer[10] = 1;
287 
288   puts ("Press q to abort\n");
289   starttime = time (NULL);
290 
291   ffe_send_command (5, 3, 0);
292   ffe_receive_block (0x5840, buffer + 0x100, 0x68);
293   fwrite (buffer, 1, SMC_HEADER_LEN, file);
294   bytesreceived += 0x68;
295 
296   ffe_send_command0 (0x4500, 0x32);
297   ffe_send_command0 (0x42ff, 0x30);
298   ffe_receive_block (0x6000, buffer, BUFFERSIZE / 2); // 0x1000
299   fwrite (buffer, 1, BUFFERSIZE / 2, file);
300 
301   bytesreceived += BUFFERSIZE / 2;
302   ucon64_gauge (starttime, bytesreceived, size);
303   ffe_checkabort (2);
304 
305   for (n = 2; n <= 0x22; n += 0x20)
306     {
307       ffe_send_command0 (0x4500, (unsigned char) n);
308       ffe_receive_block (0x6000, buffer, BUFFERSIZE); // 0x2000
309       fwrite (buffer, 1, BUFFERSIZE, file);
310 
311       bytesreceived += BUFFERSIZE;
312       ucon64_gauge (starttime, bytesreceived, size);
313       ffe_checkabort (2);
314     }
315 
316   for (n = 1; n <= 3; n++)
317     {
318       ffe_send_command0 (0x43fc, (unsigned char) n);
319       if (n == 1)
320         ffe_send_command0 (0x2001, 0);
321       ffe_receive_block2 (0, buffer, BUFFERSIZE); // 0x2000
322       fwrite (buffer, 1, BUFFERSIZE, file);
323 
324       bytesreceived += BUFFERSIZE;
325       ucon64_gauge (starttime, bytesreceived, size);
326       ffe_checkabort (2);
327     }
328 
329   ffe_send_command0 (0x43fc, 0);
330   ffe_send_command0 (0x2001, 0x6b);
331 
332   free (buffer);
333   fclose (file);
334 
335   return 0;
336 }
337 
338 
339 int
smc_write_rts(const char * filename,unsigned short parport)340 smc_write_rts (const char *filename, unsigned short parport)
341 {
342   FILE *file;
343   unsigned char *buffer;
344   unsigned int bytessent = 0, size, n;
345   time_t starttime;
346 
347   ffe_init_io (parport);
348 
349   if ((file = fopen (filename, "rb")) == NULL)
350     {
351       fprintf (stderr, ucon64_msg[OPEN_READ_ERROR], filename);
352       exit (1);
353     }
354   if ((buffer = (unsigned char *) malloc (BUFFERSIZE)) == NULL)
355     {
356       fprintf (stderr, ucon64_msg[FILE_BUFFER_ERROR], BUFFERSIZE);
357       exit (1);
358     }
359 
360   size = 0x68 + 4 * 1024 + 5 * 8 * 1024;
361   printf ("Send: %u Bytes\n", size);
362   fread_checked (buffer, 1, SMC_HEADER_LEN, file);
363 
364   puts ("Press q to abort\n");
365   starttime = time (NULL);
366 
367   ffe_send_command (5, 3, 0);
368   ffe_send_block (0x5840, buffer + 0x100, 0x68);
369   bytessent += 0x68;
370 
371   ffe_send_command0 (0x4500, 0x32);
372   ffe_send_command0 (0x42ff, 0x30);
373   fread_checked (buffer, 1, BUFFERSIZE / 2, file);
374   ffe_send_block (0x6000, buffer, BUFFERSIZE / 2); // 0x1000
375 
376   bytessent += BUFFERSIZE / 2;
377   ucon64_gauge (starttime, bytessent, size);
378   ffe_checkabort (2);
379 
380   for (n = 2; n <= 0x22; n += 0x20)
381     {
382       ffe_send_command0 (0x4500, (unsigned char) n);
383       fread_checked (buffer, 1, BUFFERSIZE, file);
384       ffe_send_block (0x6000, buffer, BUFFERSIZE); // 0x2000
385 
386       bytessent += BUFFERSIZE;
387       ucon64_gauge (starttime, bytessent, size);
388       ffe_checkabort (2);
389     }
390 
391   for (n = 1; n <= 3; n++)
392     {
393       ffe_send_command0 (0x43fc, (unsigned char) n);
394       if (n == 1)
395         ffe_send_command0 (0x2001, 0);
396       fread_checked (buffer, 1, BUFFERSIZE, file);
397       ffe_send_block2 (0, buffer, BUFFERSIZE); // 0x2000
398 
399       bytessent += BUFFERSIZE;
400       ucon64_gauge (starttime, bytessent, size);
401       ffe_checkabort (2);
402     }
403 
404   ffe_send_command0 (0x43fc, 0);
405   ffe_send_command0 (0x2001, 0x6b);
406 
407   free (buffer);
408   fclose (file);
409 
410   return 0;
411 }
412 
413 #endif // USE_PARALLEL
414