OpenCBM
d64copy.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version
5  * 2 of the License, or (at your option) any later version.
6  *
7  * Copyright 1999-2001 Michael Klein <michael(dot)klein(at)puffin(dot)lb(dot)shuttle(dot)de>
8  * Modifications for cbm4win Copyright 2001-2004 Spiro Trikaliotis
9 */
10 
11 #include "d64copy_int.h"
12 #include <stdlib.h>
13 #include <string.h>
14 #include <assert.h>
15 
16 #include "arch.h"
17 
18 
19 static const char d64_sector_map[MAX_TRACKS+1] =
20 { 0,
21  21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
22  21, 21, 21, 21, 21, 21, 21, 19, 19, 19,
23  19, 19, 19, 19, 18, 18, 18, 18, 18, 18,
24  17, 17, 17, 17, 17,
25  17, 17, 17, 17, 17, 17, 17
26 };
27 
28 static const char d71_sector_map[D71_TRACKS+1] =
29 { 0,
30  21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
31  21, 21, 21, 21, 21, 21, 21, 19, 19, 19,
32  19, 19, 19, 19, 18, 18, 18, 18, 18, 18,
33  17, 17, 17, 17, 17,
34  21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
35  21, 21, 21, 21, 21, 21, 21, 19, 19, 19,
36  19, 19, 19, 19, 18, 18, 18, 18, 18, 18,
37  17, 17, 17, 17, 17,
38 };
39 
40 static const unsigned char warp_read_1541[] =
41 {
42 #include "warpread1541.inc"
43 };
44 
45 static const unsigned char warp_write_1541[] =
46 {
47 #include "warpwrite1541.inc"
48 };
49 
50 static const unsigned char warp_read_1571[] =
51 {
52 #include "warpread1571.inc"
53 };
54 
55 static const unsigned char warp_write_1571[] =
56 {
57 #include "warpwrite1571.inc"
58 };
59 
60 static const unsigned char turbo_read_1541[] =
61 {
62 #include "turboread1541.inc"
63 };
64 
65 static const unsigned char turbo_write_1541[] =
66 {
67 #include "turbowrite1541.inc"
68 };
69 
70 static const unsigned char turbo_read_1571[] =
71 {
72 #include "turboread1571.inc"
73 };
74 
75 static const unsigned char turbo_write_1571[] =
76 {
77 #include "turbowrite1571.inc"
78 };
79 
80 static const struct drive_prog
81 {
82  int size;
83  const unsigned char *prog;
84 } drive_progs[] =
85 {
86  {sizeof(turbo_read_1541), turbo_read_1541},
87  {sizeof(turbo_write_1541), turbo_write_1541},
88  {sizeof(warp_read_1541), warp_read_1541},
89  {sizeof(warp_write_1541), warp_write_1541},
90  {sizeof(turbo_read_1571), turbo_read_1571},
91  {sizeof(turbo_write_1571), turbo_write_1571},
92  {sizeof(warp_read_1571), warp_read_1571},
93  {sizeof(warp_write_1571), warp_write_1571}
94 };
95 
96 
97 static const int default_interleave[] = { -1, 17, 4, 13, 7, -1 };
98 static const int warp_write_interleave[] = { -1, 0, 6, 12, 4, -1 };
99 
100 
101 /*
102  * Variables to make sure writing a block is an atomary process
103  */
104 static int atom_mustcleanup = 0;
105 static const transfer_funcs *atom_dst;
106 
107 
108 #ifdef LIBD64COPY_DEBUG
109  volatile signed int DebugLineNumber=-1, DebugBlockCount=-1,
110  DebugByteCount=-1, DebugBitCount=-1;
111  volatile char * DebugFileName = "";
112 
113  void printDebugLibD64Counters(d64copy_message_cb msg_cb)
114  {
115  msg_cb( sev_info, "file: %s"
116  "\n\tversion: " OPENCBM_VERSION ", built: " __DATE__ " " __TIME__
117  "\n\tline=%d, blocks=%d, bytes=%d, bits=%d\n",
118  DebugFileName, DebugLineNumber,
119  DebugBlockCount, DebugByteCount,
120  DebugBitCount);
121  }
122 #endif
123 
124 static int send_turbo(CBM_FILE fd, unsigned char drv, int write, int warp, int drv_type)
125 {
126  const struct drive_prog *prog;
127 
128  prog = &drive_progs[drv_type * 4 + warp * 2 + write];
129 
130  SETSTATEDEBUG((void)0);
131  return cbm_upload(fd, drv, 0x500, prog->prog, prog->size);
132 }
133 
134 extern transfer_funcs d64copy_fs_transfer,
135  d64copy_std_transfer,
136  d64copy_pp_transfer,
137  d64copy_s1_transfer,
138  d64copy_s2_transfer;
139 
140 static d64copy_message_cb message_cb;
141 static d64copy_status_cb status_cb;
142 
143 int d64copy_sector_count(int two_sided, int track)
144 {
145  if(two_sided)
146  {
147  if(track >= 1 && track <= D71_TRACKS)
148  {
149  return d71_sector_map[track];
150  }
151  }
152  else
153  {
154  if(track >= 1 && track <= TOT_TRACKS)
155  {
156  return d64_sector_map[track];
157  }
158  }
159  return -1;
160 }
161 
162 d64copy_settings *d64copy_get_default_settings(void)
163 {
164  d64copy_settings *settings;
165 
166  settings = malloc(sizeof(d64copy_settings));
167 
168  if(NULL != settings)
169  {
170  settings->warp = -1;
171  settings->retries = 0;
172  settings->bam_mode = bm_ignore;
173  settings->interleave = -1; /* set later on */
174  settings->start_track = 1;
175  settings->end_track = -1; /* set later on */
176  settings->drive_type = cbm_dt_unknown; /* auto detect later on */
177  settings->two_sided = 0;
178  settings->error_mode = em_on_error;
179  }
180  return settings;
181 }
182 
183 
184 static int start_turbo(CBM_FILE fd, unsigned char drive)
185 {
186  SETSTATEDEBUG((void)0);
187  return cbm_exec_command(fd, drive, "U4:", 3);
188 }
189 
190 
191 static int copy_disk(CBM_FILE fd_cbm, d64copy_settings *settings,
192  const transfer_funcs *src, const void *src_arg,
193  const transfer_funcs *dst, const void *dst_arg, unsigned char cbm_drive)
194 {
195  unsigned char tr = 0;
196  unsigned char se = 0;
197  int st;
198  int cnt = 0;
199  unsigned char scnt = 0;
200  unsigned char errors;
201  int retry_count;
202  int resend_trackmap;
203  int max_tracks;
204  char trackmap[MAX_SECTORS+1];
205  char buf[40];
206  unsigned const char *bam_ptr;
207  unsigned char bam[BLOCKSIZE];
208  unsigned char bam2[BLOCKSIZE];
209  unsigned char block[BLOCKSIZE];
210  unsigned char gcr[GCRBUFSIZE];
211  const transfer_funcs *cbm_transf = NULL;
212  d64copy_status status;
213  const char *sector_map;
214  const char *type_str = "*unknown*";
215 
216  if(settings->two_sided)
217  {
218  max_tracks = D71_TRACKS;
219  }
220  else
221  {
222  max_tracks = TOT_TRACKS;
223  }
224 
225  if(settings->interleave != -1 &&
226  (settings->interleave < 1 || settings->interleave > 17))
227  {
228  message_cb(0,
229  "invalid value (%d) for interleave", settings->interleave);
230  return -1;
231  }
232 
233  if(settings->start_track < 1 || settings->start_track > max_tracks)
234  {
235  message_cb(0,
236  "invalid value (%d) for start track", settings->start_track);
237  return -1;
238  }
239 
240  if(settings->end_track != -1 &&
241  (settings->end_track < settings->start_track ||
242  settings->end_track > max_tracks))
243  {
244  message_cb(0,
245  "invalid value (%d) for end track", settings->end_track);
246  return -1;
247  }
248 
249  if(settings->interleave == -1)
250  {
251  settings->interleave = (dst->is_cbm_drive && settings->warp) ?
252  warp_write_interleave[settings->transfer_mode] :
253  default_interleave[settings->transfer_mode];
254 
255  assert(settings->interleave >= 0);
256  }
257 
258 
259  if(settings->drive_type == cbm_dt_unknown )
260  {
261  message_cb( 2, "Trying to identify drive type" );
262  if( cbm_identify( fd_cbm, cbm_drive, &settings->drive_type, NULL ) )
263  {
264  message_cb( 0, "could not identify device" );
265  }
266 
267  switch( settings->drive_type )
268  {
269  case cbm_dt_cbm1541:
270  case cbm_dt_cbm1570:
271  case cbm_dt_cbm1571:
272  /* fine */
273  break;
274  case cbm_dt_cbm1581:
275  message_cb( 0, "1581 drives are not supported" );
276  return -1;
277  default:
278  message_cb( 1, "Unknown drive, assuming 1541" );
279  settings->drive_type = cbm_dt_cbm1541;
280  break;
281  }
282  }
283 
284  sector_map = settings->two_sided ? d71_sector_map : d64_sector_map;
285 
286  SETSTATEDEBUG((void)0);
287  cbm_exec_command(fd_cbm, cbm_drive, "I0:", 0);
288  SETSTATEDEBUG((void)0);
289  cnt = cbm_device_status(fd_cbm, cbm_drive, buf, sizeof(buf));
290  SETSTATEDEBUG((void)0);
291 
292  switch( settings->drive_type )
293  {
294  case cbm_dt_cbm1541: type_str = "1541"; break;
295  case cbm_dt_cbm1570: type_str = "1570"; break;
296  case cbm_dt_cbm1571: type_str = "1571"; break;
297  default: /* impossible */ break;
298  }
299 
300  message_cb(cnt != 0 ? 0 : 2, "drive %02d (%s): %s",
301  cbm_drive, type_str, buf );
302 
303  if(cnt)
304  {
305  return -1;
306  }
307 
308  if(settings->two_sided)
309  {
310  if(settings->drive_type != cbm_dt_cbm1571)
311  {
312  message_cb(0, ".d71 transfer requires a 1571 drive");
313  return -1;
314  }
315  if(settings->warp)
316  {
317  if(settings->warp>0)
318  message_cb(1, "`-w' for .d71 transfer in warp mode ignored");
319  settings->warp = 0;
320  }
321  SETSTATEDEBUG((void)0);
322  cbm_exec_command(fd_cbm, cbm_drive, "U0>M1", 0);
323  }
324 
325  SETSTATEDEBUG((void)0);
326  cbm_transf = src->is_cbm_drive ? src : dst;
327 
328  if(settings->warp && (cbm_transf->read_gcr_block == NULL))
329  {
330  if(settings->warp>0)
331  message_cb(1, "`-w' for this transfer mode ignored");
332  settings->warp = 0;
333  }
334 
335  settings->warp = settings->warp ? 1 : 0;
336 
337  if(cbm_transf->needs_turbo)
338  {
339  SETSTATEDEBUG((void)0);
340  send_turbo(fd_cbm, cbm_drive, dst->is_cbm_drive, settings->warp,
341  settings->drive_type == cbm_dt_cbm1541 ? 0 : 1);
342  }
343 
344  SETSTATEDEBUG((void)0);
345  if(src->open_disk(fd_cbm, settings, src_arg, 0,
346  start_turbo, message_cb) == 0)
347  {
348  if(settings->end_track == -1)
349  {
350  settings->end_track =
351  settings->two_sided ? D71_TRACKS : STD_TRACKS;
352  }
353  SETSTATEDEBUG((void)0);
354  if(dst->open_disk(fd_cbm, settings, dst_arg, 1,
355  start_turbo, message_cb) != 0)
356  {
357  message_cb(0, "can't open destination");
358  return -1;
359  }
360  }
361  else
362  {
363  message_cb(0, "can't open source");
364  return -1;
365  }
366 
367  memset(status.bam, bs_invalid, MAX_TRACKS * MAX_SECTORS);
368 
369  if(settings->bam_mode != bm_ignore)
370  {
371  if(settings->warp && src->is_cbm_drive)
372  {
373  memset(trackmap, bs_dont_copy, sector_map[18]);
374  trackmap[0] = bs_must_copy;
375  scnt = 1;
376  SETSTATEDEBUG((void)0);
377  src->send_track_map(18, trackmap, scnt);
378  SETSTATEDEBUG(DebugBlockCount=0);
379  st = src->read_gcr_block(&se, gcr);
380  SETSTATEDEBUG(DebugBlockCount=-1);
381  if(st == 0) st = gcr_decode(gcr, bam);
382  }
383  else
384  {
385  SETSTATEDEBUG(DebugBlockCount=0);
386  st = src->read_block(18, 0, bam);
387  if(settings->two_sided && (st == 0))
388  {
389  SETSTATEDEBUG(DebugBlockCount=1);
390  st = src->read_block(53, 0, bam2);
391  }
392  SETSTATEDEBUG(DebugBlockCount=-1);
393  }
394  if(st)
395  {
396  message_cb(1, "failed to read BAM (%d)", st);
397  settings->bam_mode = bm_ignore;
398  }
399  }
400  SETSTATEDEBUG((void)0);
401 
402  memset(&status, 0, sizeof(status));
403 
404  /* setup BAM */
405  for(tr = 1; tr <= max_tracks; tr++)
406  {
407  if(tr < settings->start_track || tr > settings->end_track)
408  {
409  memset(status.bam[tr-1], bs_dont_copy, sector_map[tr]);
410  }
411  else if(settings->bam_mode == bm_allocated ||
412  (settings->bam_mode == bm_save && (tr % 35 != 18)))
413  {
414  for(se = 0; se < sector_map[tr]; se++)
415  {
416  if(settings->two_sided && tr > STD_TRACKS)
417  {
418  bam_ptr = &bam2[3*(tr - STD_TRACKS - 1)];
419  }
420  else
421  {
422  bam_ptr = &bam[4*tr + 1 + (tr > STD_TRACKS ? 48 : 0)];
423  }
424  if(bam_ptr[se/8]&(1<<(se&0x07)))
425  {
426  status.bam[tr-1][se] = bs_dont_copy;
427  }
428  else
429  {
430  status.bam[tr-1][se] = bs_must_copy;
431  status.total_sectors++;
432  }
433  }
434  }
435  else
436  {
437  status.total_sectors += sector_map[tr];
438  memset(status.bam[tr-1], bs_must_copy, sector_map[tr]);
439  }
440  }
441 
442  status.settings = settings;
443 
444  status_cb(status);
445 
446  message_cb(2, "copying tracks %d-%d (%d sectors)",
447  settings->start_track, settings->end_track, status.total_sectors);
448 
449  SETSTATEDEBUG(DebugBlockCount=0);
450  for(tr = 1; tr <= max_tracks; tr++)
451  {
452  if(tr >= settings->start_track && tr <= settings->end_track)
453  {
454  scnt = sector_map[tr];
455  memcpy(trackmap, status.bam[tr-1], scnt);
456  if(settings->bam_mode != bm_ignore)
457  {
458  for(se = 0; se < sector_map[tr]; se++)
459  {
460  if(trackmap[se] != bs_must_copy)
461  {
462  scnt--;
463  }
464  }
465  }
466 
467  retry_count = settings->retries;
468  do
469  {
470  errors = resend_trackmap = 0;
471  if(scnt && settings->warp && src->is_cbm_drive)
472  {
473  SETSTATEDEBUG((void)0);
474  src->send_track_map(tr, trackmap, scnt);
475  }
476  else
477  {
478  se = 0;
479  }
480  while(scnt && !resend_trackmap)
481  {
482  if(settings->warp && src->is_cbm_drive)
483  {
484  SETSTATEDEBUG((void)0);
485  status.read_result = src->read_gcr_block(&se, gcr);
486  if(status.read_result == 0)
487  {
488  SETSTATEDEBUG((void)0);
489  status.read_result = gcr_decode(gcr, block);
490  }
491  else
492  {
493  /* mark all sectors not received so far */
494  /* ugly */
495  errors = 0;
496  for(scnt = 0; scnt < sector_map[tr]; scnt++)
497  {
498  if(NEED_SECTOR(trackmap[scnt]) && scnt != se)
499  {
500  trackmap[scnt] = bs_error;
501  errors++;
502  }
503  }
504  resend_trackmap = 1;
505  }
506  }
507  else
508  {
509  while(!NEED_SECTOR(trackmap[se]))
510  {
511  if(++se >= sector_map[tr]) se = 0;
512  }
513  SETSTATEDEBUG(DebugBlockCount++);
514  status.read_result = src->read_block(tr, se, block);
515  }
516 
517  if(settings->warp && dst->is_cbm_drive)
518  {
519  SETSTATEDEBUG((void)0);
520  gcr_encode(block, gcr);
521  SETSTATEDEBUG(DebugBlockCount++);
522  status.write_result =
523  dst->write_block(tr, se, gcr, GCRBUFSIZE-1,
524  status.read_result);
525  }
526  else
527  {
528  SETSTATEDEBUG(DebugBlockCount++);
529  status.write_result =
530  dst->write_block(tr, se, block, BLOCKSIZE,
531  status.read_result);
532  }
533  SETSTATEDEBUG((void)0);
534 
535  if(status.read_result)
536  {
537  /* read error */
538  trackmap[se] = bs_error;
539  errors++;
540  if(retry_count == 0)
541  {
542  status.sectors_processed++;
543  /* FIXME: shall we get rid of this? */
544  message_cb( 1, "read error: %02x/%02x: %d",
545  tr, se, status.read_result );
546  }
547  }
548  else
549  {
550  /* successfull read */
551  if(status.write_result)
552  {
553  /* write error */
554  trackmap[se] = bs_error;
555  errors++;
556  if(retry_count == 0)
557  {
558  status.sectors_processed++;
559  /* FIXME: shall we get rid of this? */
560  message_cb(1, "write error: %02x/%02x: %d",
561  tr, se, status.write_result);
562  }
563  }
564  else
565  {
566  /* successfull read and write, mark sector */
567  trackmap[se] = bs_copied;
568  cnt++;
569  status.sectors_processed++;
570  }
571  }
572  /* remaining sectors on this track */
573  if(!resend_trackmap)
574  {
575  scnt--;
576  }
577 
578  status.track = tr;
579  status.sector= se;
580 
581  status_cb(status);
582 
583  if(dst->is_cbm_drive || !settings->warp)
584  {
585  se += (unsigned char) settings->interleave;
586  if(se >= sector_map[tr]) se -= sector_map[tr];
587  }
588  }
589  if(errors > 0 && settings->retries >= 0)
590  {
591  retry_count--;
592  scnt = errors;
593  }
594  }
595  while(retry_count >= 0 && errors > 0);
596  if(errors)
597  {
598  message_cb(1, "giving up...");
599  }
600  }
601  if(settings->two_sided)
602  {
603  if(tr <= STD_TRACKS)
604  {
605  if(tr + STD_TRACKS <= D71_TRACKS)
606  {
607  tr += (STD_TRACKS - 1);
608  }
609  }
610  else if(tr != D71_TRACKS)
611  {
612  tr -= STD_TRACKS;
613  }
614  }
615  }
616  SETSTATEDEBUG(DebugBlockCount=-1);
617 
618  dst->close_disk();
619  SETSTATEDEBUG((void)0);
620  src->close_disk();
621 
622  SETSTATEDEBUG((void)0);
623  return cnt;
624 }
625 
626 
627 static struct _transfers
628 {
629  const transfer_funcs *trf;
630  const char *name, *abbrev;
631 }
632 transfers[] =
633 {
634  { &d64copy_std_transfer, "auto", "a%" },
635  { &d64copy_std_transfer, "original", "o%" },
636  { &d64copy_s1_transfer, "serial1", "s1" },
637  { &d64copy_s2_transfer, "serial2", "s2" },
638  { &d64copy_pp_transfer, "parallel", "p%" },
639  { NULL, NULL, NULL }
640 };
641 
642 char *d64copy_get_transfer_modes()
643 {
644  const struct _transfers *t;
645  int size;
646  char *buf;
647  char *dst;
648 
649  size = 1; /* for terminating '\0' */
650  for(t = transfers; t->trf; t++)
651  {
652  size += (strlen(t->name) + 1);
653  }
654 
655  buf = malloc(size);
656 
657  if(buf)
658  {
659  dst = buf;
660  for(t = transfers; t->trf; t++)
661  {
662  strcpy(dst, t->name);
663  dst += (strlen(t->name) + 1);
664  }
665  *dst = '\0';
666  }
667 
668  return buf;
669 }
670 
671 
672 int d64copy_get_transfer_mode_index(const char *name)
673 {
674  const struct _transfers *t;
675  int i;
676  int abbrev_len;
677  int tm_len;
678 
679  if(NULL == name)
680  {
681  /* default transfer mode */
682  return 0;
683  }
684 
685  tm_len = strlen(name);
686  for(i = 0, t = transfers; t->trf; i++, t++)
687  {
688  if(arch_strcasecmp(name, t->name) == 0)
689  {
690  /* full match */
691  return i;
692  }
693  if(t->abbrev[strlen(t->abbrev)-1] == '%')
694  {
695  abbrev_len = strlen(t->abbrev) - 1;
696  if(abbrev_len <= tm_len && arch_strncasecmp(t->name, name, tm_len) == 0)
697  {
698  return i;
699  }
700  }
701  else
702  {
703  if(strcmp(name, t->abbrev) == 0)
704  {
705  return i;
706  }
707  }
708  }
709  return -1;
710 }
711 
712 int d64copy_check_auto_transfer_mode(CBM_FILE cbm_fd, int auto_transfermode, int drive)
713 {
714  int transfermode = auto_transfermode;
715 
716  /* We assume auto is the first transfer mode */
717  assert(strcmp(transfers[0].name, "auto") == 0);
718 
719  if (auto_transfermode == 0)
720  {
721  do {
722  enum cbm_cable_type_e cable_type;
723  unsigned char testdrive;
724 
725  /*
726  * Test the cable
727  */
728 
729  SETSTATEDEBUG((void)0);
730  if (cbm_identify_xp1541(cbm_fd, (unsigned char)drive, NULL, &cable_type) == 0)
731  {
732  if (cable_type == cbm_ct_xp1541)
733  {
734  /*
735  * We have a parallel cable, use that
736  */
737  SETSTATEDEBUG((void)0);
738  transfermode = d64copy_get_transfer_mode_index("parallel");
739  break;
740  }
741  }
742 
743  /*
744  * We do not have a parallel cable. Check if we are the only drive
745  * on the bus, so we can use serial2, at least.
746  */
747 
748  for (testdrive = 4; testdrive < 31; ++testdrive)
749  {
750  enum cbm_device_type_e device_type;
751 
752  /* of course, the drive to be transfered to is present! */
753  if (testdrive == drive)
754  continue;
755 
756  SETSTATEDEBUG((void)0);
757  if (cbm_identify(cbm_fd, testdrive, &device_type, NULL) == 0)
758  {
759  /*
760  * My bad, there is another drive -> only use serial1
761  */
762  SETSTATEDEBUG((void)0);
763  transfermode = d64copy_get_transfer_mode_index("serial1");
764  break;
765  }
766  }
767 
768  /*
769  * If we reached here with transfermode 0, we are the only
770  * drive, thus, use serial2.
771  */
772  SETSTATEDEBUG((void)0);
773  if (transfermode == 0)
774  transfermode = d64copy_get_transfer_mode_index("serial2");
775  SETSTATEDEBUG((void)0);
776 
777  } while (0);
778  }
779 
780  SETSTATEDEBUG((void)0);
781  return transfermode;
782 }
783 
784 int d64copy_read_image(CBM_FILE cbm_fd,
785  d64copy_settings *settings,
786  int src_drive,
787  const char *dst_image,
788  d64copy_message_cb msg_cb,
789  d64copy_status_cb stat_cb)
790 {
791  const transfer_funcs *src;
792  const transfer_funcs *dst;
793  int ret;
794 
795  message_cb = msg_cb;
796  status_cb = stat_cb;
797 
798  src = transfers[settings->transfer_mode].trf;
799  dst = &d64copy_fs_transfer;
800 
801  atom_dst = dst;
802  atom_mustcleanup = 1;
803 
804  SETSTATEDEBUG((void)0);
805  ret = copy_disk(cbm_fd, settings,
806  src, (void*)(ULONG_PTR)src_drive, dst, (void*)dst_image, (unsigned char) src_drive);
807 
808  atom_mustcleanup = 0;
809 
810  return ret;
811 }
812 
813 int d64copy_write_image(CBM_FILE cbm_fd,
814  d64copy_settings *settings,
815  const char *src_image,
816  int dst_drive,
817  d64copy_message_cb msg_cb,
818  d64copy_status_cb stat_cb)
819 {
820  const transfer_funcs *src;
821  const transfer_funcs *dst;
822 
823  message_cb = msg_cb;
824  status_cb = stat_cb;
825 
826  src = &d64copy_fs_transfer;
827  dst = transfers[settings->transfer_mode].trf;
828 
829  SETSTATEDEBUG((void)0);
830  return copy_disk(cbm_fd, settings,
831  src, (void*)src_image, dst, (void*)(ULONG_PTR)dst_drive, (unsigned char) dst_drive);
832 }
833 
834 void d64copy_cleanup(void)
835 {
836  /* if we were interrupted writing to the fs, make sure to
837  * write anything that has already been started
838  */
839 
840  if (atom_mustcleanup)
841  {
842  atom_dst->close_disk();
843  atom_mustcleanup = 0;
844  }
845 }
int CBMAPIDECL cbm_identify_xp1541(CBM_FILE HandleDevice, unsigned char DeviceAddress, enum cbm_device_type_e *CbmDeviceType, enum cbm_cable_type_e *CableType)
Identify the cable connected to a specific floppy drive.
Definition: detectxp1541.c:187
int CBMAPIDECL cbm_device_status(CBM_FILE HandleDevice, unsigned char DeviceAddress, void *Buffer, size_t BufferLength)
Read the drive status from a floppy.
Definition: cbm.c:1525
#define CBM_FILE
Definition: opencbm.h:87
Definition: cbmctrl.c:1340
int CBMAPIDECL cbm_exec_command(CBM_FILE HandleDevice, unsigned char DeviceAddress, const void *Command, size_t Size)
Executes a command in the floppy drive.
Definition: cbm.c:1599
cbm_device_type_e
Definition: opencbm.h:114
int CBMAPIDECL cbm_identify(CBM_FILE HandleDevice, unsigned char DeviceAddress, enum cbm_device_type_e *CbmDeviceType, const char **CbmDeviceString)
Identify the connected floppy drive.
Definition: detect.c:66
cbm_cable_type_e
Definition: opencbm.h:132
Define makros and functions which account for differences between the different architectures.
int CBMAPIDECL cbm_upload(CBM_FILE HandleDevice, unsigned char DeviceAddress, int DriveMemAddress, const void *Program, size_t Size)
Upload a program into a floppy's drive memory.
Definition: upload.c:133