doctor64.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. /*
  2. doctor64.c - Bung Doctor V64 support for uCON64
  3. Copyright (c) 1999 - 2001 NoisyB
  4. Copyright (c) 2015 dbjh
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  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. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. */
  17. #ifdef HAVE_CONFIG_H
  18. #include "config.h"
  19. #endif
  20. #include <ctype.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include "misc/archive.h"
  24. #include "misc/file.h"
  25. #include "misc/parallel.h"
  26. #include "ucon64.h"
  27. #include "ucon64_misc.h"
  28. #include "backup/doctor64.h"
  29. #ifdef USE_PARALLEL
  30. static st_ucon64_obj_t doctor64_obj[] =
  31. {
  32. {UCON64_N64, WF_DEFAULT | WF_STOP | WF_NO_ROM}
  33. };
  34. #endif
  35. const st_getopt2_t doctor64_usage[] =
  36. {
  37. {
  38. NULL, 0, 0, 0,
  39. NULL, "Doctor V64"/*"19XX Bung Enterprises Ltd http://www.bung.com.hk"*/,
  40. NULL
  41. },
  42. #ifdef USE_PARALLEL
  43. {
  44. "xv64", 0, 0, UCON64_XV64,
  45. NULL, "send/receive ROM to/from Doctor V64; " OPTION_LONG_S "port=PORT\n"
  46. "receives automatically when ROM does not exist",
  47. &doctor64_obj[0]
  48. },
  49. #endif
  50. {NULL, 0, 0, 0, NULL, NULL, NULL}
  51. };
  52. #ifdef USE_PARALLEL
  53. #define SYNC_MAX_CNT 8192
  54. #define SYNC_MAX_TRY 32
  55. #define SEND_MAX_WAIT 0x300000
  56. #define REC_HIGH_NIBBLE 0x80
  57. #define REC_LOW_NIBBLE 0x00
  58. #define REC_MAX_WAIT SEND_MAX_WAIT
  59. static int
  60. parport_write (char src[], int len, unsigned short parport)
  61. {
  62. int maxwait, i;
  63. for (i = 0; i < len; i++)
  64. {
  65. maxwait = SEND_MAX_WAIT;
  66. if ((inportb (parport + 2) & 1) == 0) // check ~strobe
  67. {
  68. while (((inportb (parport + 2) & 2) != 0) && maxwait--)
  69. ; // wait for
  70. if (maxwait <= 0)
  71. return 1; // auto feed == 0
  72. outportb (parport, src[i]); // write data
  73. outportb (parport + 2, 5); // ~strobe = 1
  74. }
  75. else
  76. {
  77. while (((inportb (parport + 2) & 2) == 0) && maxwait--)
  78. ; // wait for
  79. if (maxwait <= 0)
  80. return 1; // auto feed == 1
  81. outportb (parport, src[i]); // write data
  82. outportb (parport + 2, 4); // ~strobe = 0
  83. }
  84. }
  85. return 0;
  86. }
  87. static int
  88. parport_read (char dest[], int len, unsigned short parport)
  89. {
  90. int i, maxwait;
  91. unsigned char c;
  92. for (i = 0; i < len; i++)
  93. {
  94. outportb (parport, REC_HIGH_NIBBLE);
  95. maxwait = REC_MAX_WAIT;
  96. while (((inportb (parport + 1) & 0x80) == 0) && maxwait--)
  97. ; // wait for ~busy=1
  98. if (maxwait <= 0)
  99. return len - i;
  100. c = (inportb (parport + 1) >> 3) & 0x0f; // ~ack, pe, slct, ~error
  101. outportb (parport, REC_LOW_NIBBLE);
  102. maxwait = REC_MAX_WAIT;
  103. while (((inportb (parport + 1) & 0x80) != 0) && maxwait--)
  104. ; // wait for ~busy=0
  105. if (maxwait <= 0)
  106. return len - i;
  107. c |= (inportb (parport + 1) << 1) & 0xf0; // ~ack, pe, slct, ~error
  108. dest[i] = c;
  109. }
  110. outportb (parport, REC_HIGH_NIBBLE);
  111. return 0;
  112. }
  113. int
  114. syncHeader (unsigned short baseport)
  115. {
  116. int i = 0;
  117. outportb (baseport, 0); // data = 00000000
  118. outportb (baseport + 2, 4); // ~strobe=0
  119. while (i < SYNC_MAX_CNT)
  120. {
  121. if ((inportb (baseport + 2) & 8) == 0) // wait for select=0
  122. {
  123. outportb (baseport, 0xaa); // data = 10101010
  124. outportb (baseport + 2, 0); // ~strobe=0, ~init=0
  125. while (i < SYNC_MAX_CNT)
  126. {
  127. if ((inportb (baseport + 2) & 8) != 0) // wait for select=1
  128. {
  129. outportb (baseport + 2, 4); // ~strobe=0
  130. while (i < SYNC_MAX_CNT)
  131. {
  132. if ((inportb (baseport + 2) & 8) == 0) // w for select=0
  133. {
  134. outportb (baseport, 0x55); // data = 01010101
  135. outportb (baseport + 2, 0); // ~strobe=0, ~init=0
  136. while (i < SYNC_MAX_CNT)
  137. {
  138. if ((inportb (baseport + 2) & 8) != 0) // w select=1
  139. {
  140. outportb (baseport + 2, 4); // ~strobe=0
  141. while (i < SYNC_MAX_CNT)
  142. {
  143. if ((inportb (baseport + 2) & 8) == 0) // select=0
  144. return 0;
  145. i++;
  146. }
  147. }
  148. i++;
  149. }
  150. }
  151. i++;
  152. }
  153. }
  154. i++;
  155. }
  156. i++;
  157. }
  158. i++;
  159. }
  160. outportb (baseport + 2, 4);
  161. return 1;
  162. }
  163. int
  164. initCommunication (unsigned short port)
  165. {
  166. int i;
  167. for (i = 0; i < SYNC_MAX_TRY; i++)
  168. {
  169. if (syncHeader (port) == 0)
  170. break;
  171. }
  172. if (i >= SYNC_MAX_TRY)
  173. return -1;
  174. return 0;
  175. }
  176. int
  177. checkSync (unsigned short baseport)
  178. {
  179. int i, j;
  180. for (i = 0; i < SYNC_MAX_CNT; i++)
  181. {
  182. if (((inportb (baseport + 2) & 3) == 3)
  183. || ((inportb (baseport + 2) & 3) == 0))
  184. {
  185. outportb (baseport, 0); // ~strobe, auto feed
  186. for (j = 0; j < SYNC_MAX_CNT; j++)
  187. {
  188. if ((inportb (baseport + 1) & 0x80) == 0) // wait for ~busy=0
  189. {
  190. return 0;
  191. }
  192. }
  193. return 1;
  194. }
  195. }
  196. return 1;
  197. }
  198. int
  199. sendFilename (unsigned short baseport, char name[])
  200. {
  201. int i;
  202. char *c, mname[12];
  203. memset (mname, ' ', 11);
  204. c = (strrchr (name, DIR_SEPARATOR));
  205. if (c == NULL)
  206. {
  207. c = name;
  208. }
  209. else
  210. {
  211. c++;
  212. }
  213. for (i = 0; i < 8 && *c != '.' && *c != '\0'; i++, c++)
  214. mname[i] = (char) toupper ((int) *c);
  215. c = strrchr (c, '.');
  216. if (c != NULL)
  217. {
  218. c++;
  219. for (i = 8; i < 11 && *c != '\0'; i++, c++)
  220. mname[i] = (char) toupper ((int) *c);
  221. }
  222. return parport_write (mname, 11, baseport);
  223. }
  224. int
  225. sendUploadHeader (unsigned short baseport, char name[], int len)
  226. {
  227. char mname[12], lenbuffer[4];
  228. static char protocolId[] = "GD6R\1";
  229. if (parport_write (protocolId, strlen (protocolId), baseport) != 0)
  230. return 1;
  231. lenbuffer[0] = (char) len;
  232. lenbuffer[1] = (char) (len >> 8);
  233. lenbuffer[2] = (char) (len >> 16);
  234. lenbuffer[3] = (char) (len >> 24);
  235. if (parport_write (lenbuffer, 4, baseport) != 0)
  236. return 1;
  237. memset (mname, ' ', 11);
  238. if (sendFilename (baseport, name) != 0)
  239. return 1;
  240. return 0;
  241. }
  242. int
  243. sendDownloadHeader (unsigned short baseport, int *len)
  244. {
  245. char mname[12];
  246. static char protocolId[] = "GD6W";
  247. unsigned char recbuffer[15];
  248. if (parport_write (protocolId, strlen (protocolId), baseport) != 0)
  249. return 1;
  250. memset (mname, ' ', 11);
  251. if (parport_write (mname, 11, baseport) != 0)
  252. return 1;
  253. if (checkSync (baseport) != 0)
  254. return 1;
  255. if (parport_read ((char *) recbuffer, 1, baseport) != 0)
  256. return 1;
  257. if (recbuffer[0] != 1)
  258. return -1;
  259. if (parport_read ((char *) recbuffer, 15, baseport) != 0)
  260. return 1;
  261. *len = (int) recbuffer[0] |
  262. ((int) recbuffer[1] << 8) |
  263. ((int) recbuffer[2] << 16) |
  264. ((int) recbuffer[3] << 24);
  265. return 0;
  266. }
  267. int
  268. doctor64_read (const char *filename, unsigned short parport)
  269. {
  270. char buf[MAXBUFSIZE];
  271. FILE *fh;
  272. int size, bytesreceived = 0;
  273. time_t init_time;
  274. parport_print_info ();
  275. if (initCommunication (parport) == -1)
  276. {
  277. fprintf (stderr, ucon64_msg[PARPORT_ERROR]);
  278. exit (1);
  279. }
  280. init_time = time (0);
  281. if (sendDownloadHeader (parport, &size) != 0)
  282. {
  283. fprintf (stderr, ucon64_msg[PARPORT_ERROR]);
  284. exit (1);
  285. }
  286. if ((fh = fopen (filename, "wb")) == NULL)
  287. {
  288. fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], filename);
  289. exit (1);
  290. }
  291. printf ("Receive: %d Bytes (%.4f Mb)\n\n", size, (float) size / MBIT);
  292. for (;;)
  293. {
  294. if (parport_read (buf, sizeof buf, parport) != 0)
  295. break;
  296. bytesreceived += sizeof buf;
  297. fwrite (buf, 1, sizeof buf, fh);
  298. ucon64_gauge (init_time, bytesreceived, size);
  299. }
  300. fclose (fh);
  301. return 0;
  302. }
  303. int
  304. doctor64_write (const char *filename, int start, int len, unsigned short parport)
  305. {
  306. char buf[MAXBUFSIZE];
  307. FILE *fh;
  308. unsigned int size, pos, bytessent = 0;
  309. time_t init_time;
  310. parport_print_info ();
  311. size = len - start;
  312. if (initCommunication (parport) == -1)
  313. {
  314. fprintf (stderr, ucon64_msg[PARPORT_ERROR]);
  315. exit (1);
  316. }
  317. init_time = time (0);
  318. strcpy (buf, filename);
  319. if (sendUploadHeader (parport, buf, size) != 0)
  320. {
  321. fprintf (stderr, ucon64_msg[PARPORT_ERROR]);
  322. exit (1);
  323. }
  324. if ((fh = fopen (filename, "rb")) == NULL)
  325. {
  326. fprintf (stderr, ucon64_msg[OPEN_READ_ERROR], filename);
  327. exit (1);
  328. }
  329. printf ("Send: %d Bytes (%.4f Mb)\n\n", size, (float) size / MBIT);
  330. for (;;)
  331. {
  332. if ((pos = fread (buf, 1, sizeof buf, fh)) == 0)
  333. break;
  334. if (parport_write (buf, pos, parport) != 0)
  335. break;
  336. bytessent += sizeof buf;
  337. ucon64_gauge (init_time, bytessent, size);
  338. }
  339. fclose (fh);
  340. return 0;
  341. }
  342. #endif // USE_PARALLEL