00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #ifdef SAVE_RCSID
00011 static char *rcsid =
00012 "@(#) $Id: cbmcopy.c,v 1.18 2006/04/18 08:04:48 trikalio Exp $";
00013 #endif
00014
00015 #include <stdio.h>
00016 #include <stdlib.h>
00017 #include <string.h>
00018 #include <assert.h>
00019 #include "opencbm.h"
00020 #include "cbmcopy.h"
00021
00022 #include "cbmcopy_int.h"
00023
00024 #include "arch.h"
00025
00026 static const unsigned char turboread1541[] = {
00027 #include "turboread1541.inc"
00028 };
00029
00030 static const unsigned char turboread1571[] = {
00031 #include "turboread1571.inc"
00032 };
00033
00034 static const unsigned char turboread1581[] = {
00035 #include "turboread1581.inc"
00036 };
00037
00038 static const unsigned char turbowrite1541[] = {
00039 #include "turbowrite1541.inc"
00040 };
00041
00042 static const unsigned char turbowrite1571[] = {
00043 #include "turbowrite1571.inc"
00044 };
00045
00046 static const unsigned char turbowrite1581[] = {
00047 #include "turbowrite1581.inc"
00048 };
00049
00050 extern transfer_funcs cbmcopy_s1_transfer,
00051 cbmcopy_s2_transfer,
00052 cbmcopy_pp_transfer;
00053
00054 static struct _transfers
00055 {
00056 const transfer_funcs *trf;
00057 const char *name, *abbrev;
00058 }
00059 transfers[] =
00060 {
00061 { &cbmcopy_s1_transfer, "auto", "a%1" },
00062 { &cbmcopy_s1_transfer, "serial1", "s1" },
00063 { &cbmcopy_s2_transfer, "serial2", "s2" },
00064 { &cbmcopy_pp_transfer, "parallel", "p%" },
00065 { NULL, NULL, NULL }
00066 };
00067
00068 #ifdef CBMCOPY_DEBUG
00069 signed int debugLineNumber=0, debugBlockCount=0, debugByteCount=0;
00070
00071 # define SETSTATEDEBUG(_x) \
00072 debugLineNumber=__LINE__; \
00073 (_x)
00074
00075 void printDebugCounters(cbmcopy_message_cb msg_cb)
00076 {
00077 msg_cb( sev_info, "file: " __FILE__
00078 "\n\tversion: " OPENCBM_VERSION ", built: " __DATE__ " " __TIME__
00079 "\n\tlineNumber=%d, blockCount=%d, byteCount=%d\n",
00080 debugLineNumber, debugBlockCount, debugByteCount);
00081 }
00082 #else
00083 # define SETSTATEDEBUG(_x) (void)0
00084 #endif
00085
00086 static int check_drive_type(CBM_FILE fd, unsigned char drive,
00087 cbmcopy_settings *settings,
00088 cbmcopy_message_cb msg_cb)
00089 {
00090 const char *type_str;
00091
00092 if( settings->drive_type == cbm_dt_unknown )
00093 {
00094 if(cbm_identify( fd, drive, &settings->drive_type, &type_str ))
00095 {
00096 msg_cb( sev_warning, "could not identify drive, using 1541 turbo" );
00097 settings->drive_type = cbm_dt_cbm1541;
00098 }
00099 else
00100 {
00101 msg_cb( sev_info, "identified a %s drive", type_str );
00102 }
00103 }
00104 return 0;
00105 }
00106
00107
00108 static int send_turbo(CBM_FILE fd, unsigned char drive, int write,
00109 const cbmcopy_settings *settings,
00110 const unsigned char *turbo, size_t turbo_size,
00111 const unsigned char *start_cmd, size_t cmd_len,
00112 cbmcopy_message_cb msg_cb)
00113 {
00114 const transfer_funcs *trf;
00115
00116 trf = transfers[settings->transfer_mode].trf;
00117 cbm_upload( fd, drive, 0x500, turbo, turbo_size );
00118 msg_cb( sev_debug, "uploading %d bytes turbo code", turbo_size );
00119 if(trf->upload_turbo(fd, drive, settings->drive_type, write) == 0)
00120 {
00121 cbm_exec_command( fd, drive, start_cmd, cmd_len );
00122 msg_cb( sev_debug, "initializing transfer code" );
00123 if(trf->start_turbo(fd, write) == 0)
00124 {
00125 msg_cb( sev_debug, "done" );
00126 return 0;
00127 }
00128 else
00129 {
00130 msg_cb( sev_fatal, "could not start turbo" );
00131 }
00132 }
00133 else
00134 {
00135 msg_cb( sev_fatal, "Unsupported transfer mode for this device" );
00136 }
00137 return -1;
00138 }
00139
00140
00141 static int cbmcopy_read(CBM_FILE fd,
00142 cbmcopy_settings *settings,
00143 unsigned char drive,
00144 int track, int sector,
00145 const char *cbmname,
00146 int cbmname_len,
00147 unsigned char **filedata,
00148 size_t *filedata_size,
00149 cbmcopy_message_cb msg_cb,
00150 cbmcopy_status_cb status_cb)
00151 {
00152 int rv;
00153 int i;
00154 int turbo_size;
00155 int error;
00156 unsigned char c;
00157 unsigned char *cptr;
00158 unsigned char buf[48];
00159 const unsigned char *turbo;
00160 const transfer_funcs *trf;
00161 int blocks_read;
00162
00163 *filedata = NULL;
00164 *filedata_size = 0;
00165
00166 msg_cb( sev_debug, "using transfer mode `%sī",
00167 transfers[settings->transfer_mode].name);
00168 trf = transfers[settings->transfer_mode].trf;
00169
00170 if(check_drive_type( fd, drive, settings, msg_cb ))
00171 {
00172 return -1;
00173 }
00174
00175 switch(settings->drive_type)
00176 {
00177 case cbm_dt_cbm1541:
00178 turbo = turboread1541;
00179 turbo_size = sizeof(turboread1541);
00180 break;
00181 case cbm_dt_cbm1570:
00182 case cbm_dt_cbm1571:
00183 cbm_exec_command( fd, drive, "U0>M1", 0 );
00184 turbo = turboread1571;
00185 turbo_size = sizeof(turboread1571);
00186 break;
00187 case cbm_dt_cbm1581:
00188 turbo = turboread1581;
00189 turbo_size = sizeof(turboread1581);
00190 break;
00191 default:
00192 return -1;
00193 }
00194
00195 if(cbmname)
00196 {
00197
00198 track = 0;
00199 sector = 0;
00200 cbm_open( fd, drive, 0, NULL, 0 );
00201 if(cbmname_len == 0) cbmname_len = strlen( cbmname );
00202 cbm_raw_write( fd, cbmname, cbmname_len );
00203 cbm_unlisten( fd );
00204 }
00205 else
00206 {
00207
00208 cbm_open( fd, drive, 0, "#", 1 );
00209 }
00210 rv = cbm_device_status( fd, drive, (char*)buf, sizeof(buf) );
00211
00212 if(rv)
00213 {
00214 msg_cb( sev_fatal, "could not open file for reading: %s", buf );
00215 cbm_driver_close(fd);
00216 return rv;
00217 }
00218
00219 blocks_read = 0;
00220 error = 0;
00221
00222 if(track)
00223 {
00224 msg_cb( sev_debug, "start read at %d/%d", track, sector );
00225 }
00226 sprintf( (char*)buf, "U4:%c%c", (unsigned char)track, (unsigned char)sector );
00227
00228 SETSTATEDEBUG((void)0);
00229 if(send_turbo(fd, drive, 0, settings,
00230 turbo, turbo_size, buf, 5, msg_cb) == 0)
00231 {
00232 msg_cb( sev_debug, "start of copy" );
00233 status_cb( blocks_read );
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243 arch_usleep(1000);
00244
00245 SETSTATEDEBUG(debugBlockCount=0);
00246
00247 for(c = 0xff;
00248 c == 0xff && (error = trf->check_error(fd, 0)) == 0;
00249 )
00250 {
00251 SETSTATEDEBUG((void)0);
00252
00253 c = trf->read_byte( fd );
00254
00255 SETSTATEDEBUG((void)0);
00256
00257 i = (c == 0xff) ? 0xfe : c;
00258 *filedata_size += i;
00259
00260 SETSTATEDEBUG(debugBlockCount++);
00261
00262
00263
00264
00265
00266
00267 *filedata = realloc(*filedata, *filedata_size);
00268
00269 SETSTATEDEBUG((void)0);
00270 if(*filedata)
00271 {
00272 SETSTATEDEBUG(debugByteCount=0);
00273 #ifdef CBMCOPY_DEBUG
00274 msg_cb( sev_debug, "receive block data (%d)", c );
00275 #endif
00276 for(cptr = (*filedata) + blocks_read * 254; i; i--)
00277 {
00278 SETSTATEDEBUG(debugByteCount++);
00279 *(cptr++) = trf->read_byte( fd );
00280 }
00281
00282 SETSTATEDEBUG((void)0);
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295 arch_usleep(1000);
00296
00297 SETSTATEDEBUG((void)0);
00298 status_cb( ++blocks_read );
00299 }
00300 else
00301 {
00302
00303 }
00304
00305 SETSTATEDEBUG((void)0);
00306 }
00307 msg_cb( sev_debug, "done" );
00308 SETSTATEDEBUG((void)0);
00309 trf->exit_turbo( fd, 0 );
00310 SETSTATEDEBUG((void)0);
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321 cbm_listen(fd, drive, 0);
00322 cbm_unlisten(fd);
00323 SETSTATEDEBUG((void)0);
00324 }
00325
00326 return rv;
00327 }
00328
00329
00330 char *cbmcopy_get_transfer_modes()
00331 {
00332 const struct _transfers *t;
00333 int size;
00334 char *buf;
00335 char *dst;
00336
00337 size = 1;
00338 for(t = transfers; t->name; t++)
00339 {
00340 size += (strlen(t->name) + 1);
00341 }
00342
00343 buf = malloc(size);
00344
00345 if(buf)
00346 {
00347 dst = buf;
00348 for(t = transfers; t->name; t++)
00349 {
00350 strcpy(dst, t->name);
00351 dst += (strlen(t->name) + 1);
00352 }
00353 *dst = '\0';
00354 }
00355
00356 return buf;
00357 }
00358
00359
00360 int cbmcopy_get_transfer_mode_index(const char *name)
00361 {
00362 const struct _transfers *t;
00363 int i;
00364 int abbrev_len;
00365 int tm_len;
00366
00367 if(NULL == name)
00368 {
00369
00370 return 0;
00371 }
00372
00373 tm_len = strlen(name);
00374 for(i = 0, t = transfers; t->name; i++, t++)
00375 {
00376 if(strcmp(name, t->name) == 0)
00377 {
00378
00379 return i;
00380 }
00381 if(t->abbrev[strlen(t->abbrev)-1] == '%')
00382 {
00383 abbrev_len = strlen(t->abbrev) - 1;
00384 if(abbrev_len <= tm_len && strncmp(t->name, name, tm_len) == 0)
00385 {
00386 return i;
00387 }
00388 }
00389 else
00390 {
00391 if(strcmp(name, t->abbrev) == 0)
00392 {
00393 return i;
00394 }
00395 }
00396 }
00397 return -1;
00398 }
00399
00400 int cbmcopy_check_auto_transfer_mode(CBM_FILE cbm_fd, int auto_transfermode, int drive)
00401 {
00402 int transfermode = auto_transfermode;
00403
00404
00405 assert(strcmp(transfers[0].name, "auto") == 0);
00406
00407 if (auto_transfermode == 0)
00408 {
00409 do {
00410 enum cbm_cable_type_e cable_type;
00411 unsigned char testdrive;
00412
00413
00414
00415
00416
00417 if (cbm_identify_xp1541(cbm_fd, (unsigned char)drive, NULL, &cable_type) == 0)
00418 {
00419 if (cable_type == cbm_ct_xp1541)
00420 {
00421
00422
00423
00424 transfermode = cbmcopy_get_transfer_mode_index("parallel");
00425 break;
00426 }
00427 }
00428
00429
00430
00431
00432
00433
00434 for (testdrive = 4; testdrive < 31; ++testdrive)
00435 {
00436 enum cbm_device_type_e device_type;
00437
00438
00439 if (testdrive == drive)
00440 continue;
00441
00442 if (cbm_identify(cbm_fd, testdrive, &device_type, NULL) == 0)
00443 {
00444
00445
00446
00447 transfermode = cbmcopy_get_transfer_mode_index("serial1");
00448 break;
00449 }
00450 }
00451
00452
00453
00454
00455
00456 if (transfermode == 0)
00457 transfermode = cbmcopy_get_transfer_mode_index("serial2");
00458
00459 } while (0);
00460 }
00461
00462 return transfermode;
00463 }
00464
00465 cbmcopy_settings *cbmcopy_get_default_settings(void)
00466 {
00467 cbmcopy_settings *settings;
00468
00469 settings = malloc(sizeof(cbmcopy_settings));
00470
00471 if(NULL != settings)
00472 {
00473 settings->drive_type = cbm_dt_unknown;
00474 settings->transfer_mode = 0;
00475 }
00476 return settings;
00477 }
00478
00479
00480
00481 int cbmcopy_write_file(CBM_FILE fd,
00482 cbmcopy_settings *settings,
00483 int drivei,
00484 const char *cbmname,
00485 int cbmname_len,
00486 const unsigned char *filedata,
00487 int filedata_size,
00488 cbmcopy_message_cb msg_cb,
00489 cbmcopy_status_cb status_cb)
00490 {
00491 int rv;
00492 int i;
00493 int turbo_size;
00494 unsigned char drive = (unsigned char) drivei;
00495 int error;
00496 unsigned char c;
00497 unsigned char buf[48];
00498 const unsigned char *turbo;
00499 const transfer_funcs *trf;
00500 int blocks_written;
00501
00502 msg_cb( sev_debug, "using transfer mode `%sī",
00503 transfers[settings->transfer_mode].name);
00504 trf = transfers[settings->transfer_mode].trf;
00505
00506 if(check_drive_type( fd, drive, settings, msg_cb ))
00507 {
00508 return -1;
00509 }
00510
00511 switch(settings->drive_type)
00512 {
00513 case cbm_dt_cbm1541:
00514 turbo = turbowrite1541;
00515 turbo_size = sizeof(turbowrite1541);
00516 break;
00517 case cbm_dt_cbm1570:
00518 case cbm_dt_cbm1571:
00519 cbm_exec_command( fd, drive, "U0>M1", 0 );
00520 turbo = turbowrite1571;
00521 turbo_size = sizeof(turbowrite1571);
00522 break;
00523 case cbm_dt_cbm1581:
00524 turbo = turbowrite1581;
00525 turbo_size = sizeof(turbowrite1581);
00526 break;
00527 default:
00528 return -1;
00529 }
00530
00531 cbm_open( fd, drive, 1, NULL, 0 );
00532 if(cbmname_len == 0) cbmname_len = strlen( cbmname );
00533 cbm_raw_write( fd, cbmname, cbmname_len );
00534 cbm_unlisten( fd );
00535 rv = cbm_device_status( fd, drive, buf, sizeof(buf) );
00536
00537 if(rv)
00538 {
00539 msg_cb( sev_fatal, "could not open file for writing: %s", buf );
00540 cbm_driver_close(fd);
00541 return rv;
00542 }
00543
00544 blocks_written = 0;
00545 error = 0;
00546
00547 SETSTATEDEBUG((void)0);
00548 if(send_turbo(fd, drive, 1, settings,
00549 turbo, turbo_size, (unsigned char*)"U4:", 3, msg_cb) == 0)
00550 {
00551 msg_cb( sev_debug, "start of copy" );
00552 status_cb( blocks_written );
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562 arch_usleep(1000);
00563
00564 SETSTATEDEBUG(debugBlockCount=0);
00565
00566 for(i = 0;
00567 (i == 0) || (i < filedata_size && !error );
00568 i+=254)
00569 {
00570 if( filedata_size - i <= 254 )
00571 {
00572 c = filedata_size - i;
00573 }
00574 else
00575 {
00576 c = 255;
00577 }
00578 SETSTATEDEBUG(debugBlockCount++);
00579 #ifdef CBMCOPY_DEBUG
00580 msg_cb( sev_debug, "send byte count: %d", c );
00581 #endif
00582 trf->write_byte( fd, c );
00583 SETSTATEDEBUG((void)0);
00584
00585 if(c)
00586 {
00587 SETSTATEDEBUG(debugByteCount=0);
00588 #ifdef CBMCOPY_DEBUG
00589 msg_cb( sev_debug, "send block data" );
00590 #endif
00591 if( c == 0xff ) c = 0xfe;
00592 while(c)
00593 {
00594 SETSTATEDEBUG(debugByteCount++);
00595 trf->write_byte( fd, *(filedata++) );
00596 c--;
00597 }
00598
00599
00600
00601 SETSTATEDEBUG((void)0);
00602 }
00603 error = trf->check_error( fd, 1 );
00604 SETSTATEDEBUG((void)0);
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617 arch_usleep(1000);
00618
00619 if(!error)
00620 {
00621 status_cb( ++blocks_written );
00622 }
00623 SETSTATEDEBUG((void)0);
00624 }
00625 msg_cb( sev_debug, "done" );
00626
00627 SETSTATEDEBUG((void)0);
00628 trf->exit_turbo( fd, 1 );
00629 SETSTATEDEBUG((void)0);
00630 }
00631 return rv;
00632 }
00633
00634
00635
00636 int cbmcopy_read_file_ts(CBM_FILE fd,
00637 cbmcopy_settings *settings,
00638 int drive,
00639 int track, int sector,
00640 unsigned char **filedata,
00641 size_t *filedata_size,
00642 cbmcopy_message_cb msg_cb,
00643 cbmcopy_status_cb status_cb)
00644 {
00645 return cbmcopy_read(fd, settings, (unsigned char) drive,
00646 track, sector,
00647 NULL, 0,
00648 filedata, filedata_size,
00649 msg_cb, status_cb);
00650 }
00651
00652
00653
00654 int cbmcopy_read_file(CBM_FILE fd,
00655 cbmcopy_settings *settings,
00656 int drive,
00657 const char *cbmname,
00658 int cbmname_len,
00659 unsigned char **filedata,
00660 size_t *filedata_size,
00661 cbmcopy_message_cb msg_cb,
00662 cbmcopy_status_cb status_cb)
00663 {
00664 return cbmcopy_read(fd, settings, (unsigned char) drive,
00665 0, 0,
00666 cbmname, cbmname_len,
00667 filedata, filedata_size,
00668 msg_cb, status_cb);
00669 }