00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifdef SAVE_RCSID
00012 static char *rcsid =
00013 "@(#) $Id: d64copy.c,v 1.19 2006/04/11 15:29:15 trikalio Exp $";
00014 #endif
00015
00016 #include "d64copy_int.h"
00017 #include <stdlib.h>
00018 #include <string.h>
00019 #include <assert.h>
00020
00021 #include "arch.h"
00022
00023
00024 static const char d64_sector_map[MAX_TRACKS+1] =
00025 { 0,
00026 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
00027 21, 21, 21, 21, 21, 21, 21, 19, 19, 19,
00028 19, 19, 19, 19, 18, 18, 18, 18, 18, 18,
00029 17, 17, 17, 17, 17,
00030 17, 17, 17, 17, 17, 17, 17
00031 };
00032
00033 static const char d71_sector_map[D71_TRACKS+1] =
00034 { 0,
00035 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
00036 21, 21, 21, 21, 21, 21, 21, 19, 19, 19,
00037 19, 19, 19, 19, 18, 18, 18, 18, 18, 18,
00038 17, 17, 17, 17, 17,
00039 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
00040 21, 21, 21, 21, 21, 21, 21, 19, 19, 19,
00041 19, 19, 19, 19, 18, 18, 18, 18, 18, 18,
00042 17, 17, 17, 17, 17,
00043 };
00044
00045 static const unsigned char warp_read_1541[] =
00046 {
00047 #include "warpread1541.inc"
00048 };
00049
00050 static const unsigned char warp_write_1541[] =
00051 {
00052 #include "warpwrite1541.inc"
00053 };
00054
00055 static const unsigned char warp_read_1571[] =
00056 {
00057 #include "warpread1571.inc"
00058 };
00059
00060 static const unsigned char warp_write_1571[] =
00061 {
00062 #include "warpwrite1571.inc"
00063 };
00064
00065 static const unsigned char turbo_read_1541[] =
00066 {
00067 #include "turboread1541.inc"
00068 };
00069
00070 static const unsigned char turbo_write_1541[] =
00071 {
00072 #include "turbowrite1541.inc"
00073 };
00074
00075 static const unsigned char turbo_read_1571[] =
00076 {
00077 #include "turboread1571.inc"
00078 };
00079
00080 static const unsigned char turbo_write_1571[] =
00081 {
00082 #include "turbowrite1571.inc"
00083 };
00084
00085 static const struct drive_prog
00086 {
00087 int size;
00088 const unsigned char *prog;
00089 } drive_progs[] =
00090 {
00091 {sizeof(turbo_read_1541), turbo_read_1541},
00092 {sizeof(turbo_write_1541), turbo_write_1541},
00093 {sizeof(warp_read_1541), warp_read_1541},
00094 {sizeof(warp_write_1541), warp_write_1541},
00095 {sizeof(turbo_read_1571), turbo_read_1571},
00096 {sizeof(turbo_write_1571), turbo_write_1571},
00097 {sizeof(warp_read_1571), warp_read_1571},
00098 {sizeof(warp_write_1571), warp_write_1571}
00099 };
00100
00101
00102 static const int default_interleave[] = { -1, 17, 4, 13, 7, -1 };
00103 static const int warp_write_interleave[] = { -1, 0, 6, 12, 4, -1 };
00104
00105
00106
00107
00108
00109 static int atom_mustcleanup = 0;
00110 static const transfer_funcs *atom_dst;
00111
00112
00113 static int send_turbo(CBM_FILE fd, unsigned char drv, int write, int warp, int drv_type)
00114 {
00115 const struct drive_prog *prog;
00116
00117 prog = &drive_progs[drv_type * 4 + warp * 2 + write];
00118
00119 return cbm_upload(fd, drv, 0x500, prog->prog, prog->size);
00120 }
00121
00122 extern transfer_funcs d64copy_fs_transfer,
00123 d64copy_std_transfer,
00124 d64copy_pp_transfer,
00125 d64copy_s1_transfer,
00126 d64copy_s2_transfer;
00127
00128 static d64copy_message_cb message_cb;
00129 static d64copy_status_cb status_cb;
00130
00131 int d64copy_sector_count(int two_sided, int track)
00132 {
00133 if(two_sided)
00134 {
00135 if(track >= 1 && track <= D71_TRACKS)
00136 {
00137 return d71_sector_map[track];
00138 }
00139 }
00140 else
00141 {
00142 if(track >= 1 && track <= TOT_TRACKS)
00143 {
00144 return d64_sector_map[track];
00145 }
00146 }
00147 return -1;
00148 }
00149
00150 d64copy_settings *d64copy_get_default_settings(void)
00151 {
00152 d64copy_settings *settings;
00153
00154 settings = malloc(sizeof(d64copy_settings));
00155
00156 if(NULL != settings)
00157 {
00158 settings->warp = -1;
00159 settings->retries = 0;
00160 settings->bam_mode = bm_ignore;
00161 settings->interleave = -1;
00162 settings->start_track = 1;
00163 settings->end_track = -1;
00164 settings->drive_type = cbm_dt_unknown;
00165 settings->two_sided = 0;
00166 settings->error_mode = em_on_error;
00167 }
00168 return settings;
00169 }
00170
00171
00172 static int start_turbo(CBM_FILE fd, unsigned char drive)
00173 {
00174 return cbm_exec_command(fd, drive, "U4:", 3);
00175 }
00176
00177
00178 static int copy_disk(CBM_FILE fd_cbm, d64copy_settings *settings,
00179 const transfer_funcs *src, const void *src_arg,
00180 const transfer_funcs *dst, const void *dst_arg, unsigned char cbm_drive)
00181 {
00182 unsigned char tr = 0;
00183 unsigned char se = 0;
00184 int st;
00185 int cnt = 0;
00186 unsigned char scnt = 0;
00187 unsigned char errors;
00188 int retry_count;
00189 int resend_trackmap;
00190 int max_tracks;
00191 char trackmap[MAX_SECTORS+1];
00192 char buf[40];
00193 unsigned const char *bam_ptr;
00194 unsigned char bam[BLOCKSIZE];
00195 unsigned char bam2[BLOCKSIZE];
00196 unsigned char block[BLOCKSIZE];
00197 unsigned char gcr[GCRBUFSIZE];
00198 const transfer_funcs *cbm_transf = NULL;
00199 d64copy_status status;
00200 const char *sector_map;
00201 const char *type_str = "*unknown*";
00202
00203 if(settings->two_sided)
00204 {
00205 max_tracks = D71_TRACKS;
00206 }
00207 else
00208 {
00209 max_tracks = TOT_TRACKS;
00210 }
00211
00212 if(settings->interleave != -1 &&
00213 (settings->interleave < 1 || settings->interleave > 17))
00214 {
00215 message_cb(0,
00216 "invalid value (%d) for interleave", settings->interleave);
00217 return -1;
00218 }
00219
00220 if(settings->start_track < 1 || settings->start_track > max_tracks)
00221 {
00222 message_cb(0,
00223 "invalid value (%d) for start track", settings->start_track);
00224 return -1;
00225 }
00226
00227 if(settings->end_track != -1 &&
00228 (settings->end_track < settings->start_track ||
00229 settings->end_track > max_tracks))
00230 {
00231 message_cb(0,
00232 "invalid value (%d) for end track", settings->end_track);
00233 return -1;
00234 }
00235
00236 if(settings->interleave == -1)
00237 {
00238 settings->interleave = (dst->is_cbm_drive && settings->warp) ?
00239 warp_write_interleave[settings->transfer_mode] :
00240 default_interleave[settings->transfer_mode];
00241
00242 assert(settings->interleave >= 0);
00243 }
00244
00245
00246 if(settings->drive_type == cbm_dt_unknown )
00247 {
00248 message_cb( 2, "Trying to identify drive type" );
00249 if( cbm_identify( fd_cbm, cbm_drive, &settings->drive_type, NULL ) )
00250 {
00251 message_cb( 0, "could not identify device" );
00252 }
00253
00254 switch( settings->drive_type )
00255 {
00256 case cbm_dt_cbm1541:
00257 case cbm_dt_cbm1570:
00258 case cbm_dt_cbm1571:
00259
00260 break;
00261 case cbm_dt_cbm1581:
00262 message_cb( 0, "1581 drives are not supported" );
00263 return -1;
00264 default:
00265 message_cb( 1, "Unknown drive, assuming 1541" );
00266 settings->drive_type = cbm_dt_cbm1541;
00267 break;
00268 }
00269 }
00270
00271 sector_map = settings->two_sided ? d71_sector_map : d64_sector_map;
00272
00273 cbm_exec_command(fd_cbm, cbm_drive, "I0:", 0);
00274 cnt = cbm_device_status(fd_cbm, cbm_drive, buf, sizeof(buf));
00275
00276 switch( settings->drive_type )
00277 {
00278 case cbm_dt_cbm1541: type_str = "1541"; break;
00279 case cbm_dt_cbm1570: type_str = "1570"; break;
00280 case cbm_dt_cbm1571: type_str = "1571"; break;
00281 default: break;
00282 }
00283
00284 message_cb(cnt != 0 ? 0 : 2, "drive %02d (%s): %s",
00285 cbm_drive, type_str, buf );
00286
00287 if(cnt)
00288 {
00289 return -1;
00290 }
00291
00292 if(settings->two_sided)
00293 {
00294 if(settings->drive_type != cbm_dt_cbm1571)
00295 {
00296 message_cb(0, ".d71 transfer requires a 1571 drive");
00297 return -1;
00298 }
00299 if(settings->warp)
00300 {
00301 if(settings->warp>0)
00302 message_cb(1, "`-w' for .d71 transfer in warp mode ignored");
00303 settings->warp = 0;
00304 }
00305 cbm_exec_command(fd_cbm, cbm_drive, "U0>M1", 0);
00306 }
00307
00308 cbm_transf = src->is_cbm_drive ? src : dst;
00309
00310 if(settings->warp && (cbm_transf->read_gcr_block == NULL))
00311 {
00312 if(settings->warp>0)
00313 message_cb(1, "`-w' for this transfer mode ignored");
00314 settings->warp = 0;
00315 }
00316
00317 settings->warp = settings->warp ? 1 : 0;
00318
00319 if(cbm_transf->needs_turbo)
00320 {
00321 send_turbo(fd_cbm, cbm_drive, dst->is_cbm_drive, settings->warp,
00322 settings->drive_type == cbm_dt_cbm1541 ? 0 : 1);
00323 }
00324
00325 if(src->open_disk(fd_cbm, settings, src_arg, 0,
00326 start_turbo, message_cb) == 0)
00327 {
00328 if(settings->end_track == -1)
00329 {
00330 settings->end_track =
00331 settings->two_sided ? D71_TRACKS : STD_TRACKS;
00332 }
00333 if(dst->open_disk(fd_cbm, settings, dst_arg, 1,
00334 start_turbo, message_cb) != 0)
00335 {
00336 message_cb(0, "can't open destination");
00337 return -1;
00338 }
00339 }
00340 else
00341 {
00342 message_cb(0, "can't open source");
00343 return -1;
00344 }
00345
00346 memset(status.bam, bs_invalid, MAX_TRACKS * MAX_SECTORS);
00347
00348 if(settings->bam_mode != bm_ignore)
00349 {
00350 if(settings->warp && src->is_cbm_drive)
00351 {
00352 memset(trackmap, bs_dont_copy, sector_map[18]);
00353 trackmap[0] = bs_must_copy;
00354 scnt = 1;
00355 src->send_track_map(18, trackmap, scnt);
00356 st = src->read_gcr_block(&se, gcr);
00357 if(st == 0) st = gcr_decode(gcr, bam);
00358 }
00359 else
00360 {
00361 st = src->read_block(18, 0, bam);
00362 if(settings->two_sided && (st == 0))
00363 {
00364 st = src->read_block(53, 0, bam2);
00365 }
00366 }
00367 if(st)
00368 {
00369 message_cb(1, "failed to read BAM (%d)", st);
00370 settings->bam_mode = bm_ignore;
00371 }
00372 }
00373
00374 memset(&status, 0, sizeof(status));
00375
00376
00377 for(tr = 1; tr <= max_tracks; tr++)
00378 {
00379 if(tr < settings->start_track || tr > settings->end_track)
00380 {
00381 memset(status.bam[tr-1], bs_dont_copy, sector_map[tr]);
00382 }
00383 else if(settings->bam_mode == bm_allocated ||
00384 (settings->bam_mode == bm_save && (tr % 35 != 18)))
00385 {
00386 for(se = 0; se < sector_map[tr]; se++)
00387 {
00388 if(settings->two_sided && tr > STD_TRACKS)
00389 {
00390 bam_ptr = &bam2[3*(tr - STD_TRACKS - 1)];
00391 }
00392 else
00393 {
00394 bam_ptr = &bam[4*tr + 1 + (tr > STD_TRACKS ? 48 : 0)];
00395 }
00396 if(bam_ptr[se/8]&(1<<(se&0x07)))
00397 {
00398 status.bam[tr-1][se] = bs_dont_copy;
00399 }
00400 else
00401 {
00402 status.bam[tr-1][se] = bs_must_copy;
00403 status.total_sectors++;
00404 }
00405 }
00406 }
00407 else
00408 {
00409 status.total_sectors += sector_map[tr];
00410 memset(status.bam[tr-1], bs_must_copy, sector_map[tr]);
00411 }
00412 }
00413
00414 status.settings = settings;
00415
00416 status_cb(status);
00417
00418 message_cb(2, "copying tracks %d-%d (%d sectors)",
00419 settings->start_track, settings->end_track, status.total_sectors);
00420
00421 for(tr = 1; tr <= max_tracks; tr++)
00422 {
00423 if(tr >= settings->start_track && tr <= settings->end_track)
00424 {
00425 scnt = sector_map[tr];
00426 memcpy(trackmap, status.bam[tr-1], scnt);
00427 if(settings->bam_mode != bm_ignore)
00428 {
00429 for(se = 0; se < sector_map[tr]; se++)
00430 {
00431 if(trackmap[se] != bs_must_copy)
00432 {
00433 scnt--;
00434 }
00435 }
00436 }
00437
00438 retry_count = settings->retries;
00439 do
00440 {
00441 errors = resend_trackmap = 0;
00442 if(scnt && settings->warp && src->is_cbm_drive)
00443 {
00444 src->send_track_map(tr, trackmap, scnt);
00445 }
00446 else
00447 {
00448 se = 0;
00449 }
00450 while(scnt && !resend_trackmap)
00451 {
00452 if(settings->warp && src->is_cbm_drive)
00453 {
00454 status.read_result = src->read_gcr_block(&se, gcr);
00455 if(status.read_result == 0)
00456 {
00457 status.read_result = gcr_decode(gcr, block);
00458 }
00459 else
00460 {
00461
00462
00463 errors = 0;
00464 for(scnt = 0; scnt < sector_map[tr]; scnt++)
00465 {
00466 if(NEED_SECTOR(trackmap[scnt]) && scnt != se)
00467 {
00468 trackmap[scnt] = bs_error;
00469 errors++;
00470 }
00471 }
00472 resend_trackmap = 1;
00473 }
00474 }
00475 else
00476 {
00477 while(!NEED_SECTOR(trackmap[se]))
00478 {
00479 if(++se >= sector_map[tr]) se = 0;
00480 }
00481 status.read_result = src->read_block(tr, se, block);
00482 }
00483
00484 if(settings->warp && dst->is_cbm_drive)
00485 {
00486 gcr_encode(block, gcr);
00487 status.write_result =
00488 dst->write_block(tr, se, gcr, GCRBUFSIZE-1,
00489 status.read_result);
00490 }
00491 else
00492 {
00493 status.write_result =
00494 dst->write_block(tr, se, block, BLOCKSIZE,
00495 status.read_result);
00496 }
00497
00498 if(status.read_result)
00499 {
00500
00501 trackmap[se] = bs_error;
00502 errors++;
00503 if(retry_count == 0)
00504 {
00505 status.sectors_processed++;
00506
00507 message_cb( 1, "read error: %02x/%02x: %d",
00508 tr, se, status.read_result );
00509 }
00510 }
00511 else
00512 {
00513
00514 if(status.write_result)
00515 {
00516
00517 trackmap[se] = bs_error;
00518 errors++;
00519 if(retry_count == 0)
00520 {
00521 status.sectors_processed++;
00522
00523 message_cb(1, "write error: %02x/%02x: %d",
00524 tr, se, status.write_result);
00525 }
00526 }
00527 else
00528 {
00529
00530 trackmap[se] = bs_copied;
00531 cnt++;
00532 status.sectors_processed++;
00533 }
00534 }
00535
00536 if(!resend_trackmap)
00537 {
00538 scnt--;
00539 }
00540
00541 status.track = tr;
00542 status.sector= se;
00543
00544 status_cb(status);
00545
00546 if(dst->is_cbm_drive || !settings->warp)
00547 {
00548 se += (unsigned char) settings->interleave;
00549 if(se >= sector_map[tr]) se -= sector_map[tr];
00550 }
00551 }
00552 if(errors > 0 && settings->retries >= 0)
00553 {
00554 retry_count--;
00555 scnt = errors;
00556 }
00557 }
00558 while(retry_count >= 0 && errors > 0);
00559 if(errors)
00560 {
00561 message_cb(1, "giving up...");
00562 }
00563 }
00564 if(settings->two_sided)
00565 {
00566 if(tr <= STD_TRACKS)
00567 {
00568 if(tr + STD_TRACKS <= D71_TRACKS)
00569 {
00570 tr += (STD_TRACKS - 1);
00571 }
00572 }
00573 else if(tr != D71_TRACKS)
00574 {
00575 tr -= STD_TRACKS;
00576 }
00577 }
00578 }
00579
00580 dst->close_disk();
00581 src->close_disk();
00582
00583 return cnt;
00584 }
00585
00586
00587 static struct _transfers
00588 {
00589 const transfer_funcs *trf;
00590 const char *name, *abbrev;
00591 }
00592 transfers[] =
00593 {
00594 { &d64copy_std_transfer, "auto", "a%" },
00595 { &d64copy_std_transfer, "original", "o%" },
00596 { &d64copy_s1_transfer, "serial1", "s1" },
00597 { &d64copy_s2_transfer, "serial2", "s2" },
00598 { &d64copy_pp_transfer, "parallel", "p%" },
00599 { NULL, NULL, NULL }
00600 };
00601
00602 char *d64copy_get_transfer_modes()
00603 {
00604 const struct _transfers *t;
00605 int size;
00606 char *buf;
00607 char *dst;
00608
00609 size = 1;
00610 for(t = transfers; t->trf; t++)
00611 {
00612 size += (strlen(t->name) + 1);
00613 }
00614
00615 buf = malloc(size);
00616
00617 if(buf)
00618 {
00619 dst = buf;
00620 for(t = transfers; t->trf; t++)
00621 {
00622 strcpy(dst, t->name);
00623 dst += (strlen(t->name) + 1);
00624 }
00625 *dst = '\0';
00626 }
00627
00628 return buf;
00629 }
00630
00631
00632 int d64copy_get_transfer_mode_index(const char *name)
00633 {
00634 const struct _transfers *t;
00635 int i;
00636 int abbrev_len;
00637 int tm_len;
00638
00639 if(NULL == name)
00640 {
00641
00642 return 0;
00643 }
00644
00645 tm_len = strlen(name);
00646 for(i = 0, t = transfers; t->trf; i++, t++)
00647 {
00648 if(arch_strcasecmp(name, t->name) == 0)
00649 {
00650
00651 return i;
00652 }
00653 if(t->abbrev[strlen(t->abbrev)-1] == '%')
00654 {
00655 abbrev_len = strlen(t->abbrev) - 1;
00656 if(abbrev_len <= tm_len && arch_strncasecmp(t->name, name, tm_len) == 0)
00657 {
00658 return i;
00659 }
00660 }
00661 else
00662 {
00663 if(strcmp(name, t->abbrev) == 0)
00664 {
00665 return i;
00666 }
00667 }
00668 }
00669 return -1;
00670 }
00671
00672 int d64copy_check_auto_transfer_mode(CBM_FILE cbm_fd, int auto_transfermode, int drive)
00673 {
00674 int transfermode = auto_transfermode;
00675
00676
00677 assert(strcmp(transfers[0].name, "auto") == 0);
00678
00679 if (auto_transfermode == 0)
00680 {
00681 do {
00682 enum cbm_cable_type_e cable_type;
00683 unsigned char testdrive;
00684
00685
00686
00687
00688
00689 if (cbm_identify_xp1541(cbm_fd, (unsigned char)drive, NULL, &cable_type) == 0)
00690 {
00691 if (cable_type == cbm_ct_xp1541)
00692 {
00693
00694
00695
00696 transfermode = d64copy_get_transfer_mode_index("parallel");
00697 break;
00698 }
00699 }
00700
00701
00702
00703
00704
00705
00706 for (testdrive = 4; testdrive < 31; ++testdrive)
00707 {
00708 enum cbm_device_type_e device_type;
00709
00710
00711 if (testdrive == drive)
00712 continue;
00713
00714 if (cbm_identify(cbm_fd, testdrive, &device_type, NULL) == 0)
00715 {
00716
00717
00718
00719 transfermode = d64copy_get_transfer_mode_index("serial1");
00720 break;
00721 }
00722 }
00723
00724
00725
00726
00727
00728 if (transfermode == 0)
00729 transfermode = d64copy_get_transfer_mode_index("serial2");
00730
00731 } while (0);
00732 }
00733
00734 return transfermode;
00735 }
00736
00737 int d64copy_read_image(CBM_FILE cbm_fd,
00738 d64copy_settings *settings,
00739 int src_drive,
00740 const char *dst_image,
00741 d64copy_message_cb msg_cb,
00742 d64copy_status_cb stat_cb)
00743 {
00744 const transfer_funcs *src;
00745 const transfer_funcs *dst;
00746 int ret;
00747
00748 message_cb = msg_cb;
00749 status_cb = stat_cb;
00750
00751 src = transfers[settings->transfer_mode].trf;
00752 dst = &d64copy_fs_transfer;
00753
00754 atom_dst = dst;
00755 atom_mustcleanup = 1;
00756
00757 ret = copy_disk(cbm_fd, settings,
00758 src, (void*)(ULONG_PTR)src_drive, dst, (void*)dst_image, (unsigned char) src_drive);
00759
00760 atom_mustcleanup = 0;
00761
00762 return ret;
00763 }
00764
00765 int d64copy_write_image(CBM_FILE cbm_fd,
00766 d64copy_settings *settings,
00767 const char *src_image,
00768 int dst_drive,
00769 d64copy_message_cb msg_cb,
00770 d64copy_status_cb stat_cb)
00771 {
00772 const transfer_funcs *src;
00773 const transfer_funcs *dst;
00774
00775 message_cb = msg_cb;
00776 status_cb = stat_cb;
00777
00778 src = &d64copy_fs_transfer;
00779 dst = transfers[settings->transfer_mode].trf;
00780
00781 return copy_disk(cbm_fd, settings,
00782 src, (void*)src_image, dst, (void*)(ULONG_PTR)dst_drive, (unsigned char) dst_drive);
00783 }
00784
00785 void d64copy_cleanup(void)
00786 {
00787
00788
00789
00790
00791 if (atom_mustcleanup)
00792 {
00793 atom_dst->close_disk();
00794 atom_mustcleanup = 0;
00795 }
00796 }