Main Page | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

cbmctrl.c

00001 /*
00002  *      This program is free software; you can redistribute it and/or
00003  *      modify it under the terms of the GNU General Public License
00004  *      as published by the Free Software Foundation; either version
00005  *      2 of the License, or (at your option) any later version.
00006  *
00007  *  Copyright 1999-2004 Michael Klein <michael(dot)klein(at)puffin(dot)lb(dot)shuttle(dot)de>
00008  *  Modifications for cbm4win and general rework Copyright 2001-2006 Spiro Trikaliotis
00009  *  Additions Copyright 2006 Wolfgang Moser <cbm(a)d81(o)de>
00010  */
00011 
00012 #ifdef SAVE_RCSID
00013 static char *rcsid =
00014     "@(#) $Id: cbmctrl.c,v 1.48 2006/04/13 11:40:05 trikalio Exp $";
00015 #endif
00016 
00017 #include "opencbm.h"
00018 
00019 #include <stdio.h>
00020 #include <stdlib.h>
00021 #include <string.h>
00022  
00023 typedef int (*mainfunc)(CBM_FILE fd, char *argv[]);
00024 
00025 #include "arch.h"
00026 
00027 static const unsigned char prog_tdchange[] = {
00028 #include "tdchange.inc"
00029 };
00030 
00031 
00032 static int do_help(CBM_FILE fd, char *argv[]);
00033 
00034 /*
00035  * Output version information
00036  */
00037 static int do_version(CBM_FILE fd, char *argv[])
00038 {
00039     printf("cbmctrl version " OPENCBM_VERSION ", built on " __DATE__ " at " __TIME__ "\n");
00040 
00041     return 0;
00042 }
00043 
00044 /*
00045  * Simple wrapper for lock
00046  */
00047 static int do_lock(CBM_FILE fd, char *argv[])
00048 {
00049     cbm_lock(fd);
00050     return 0;
00051 }
00052 
00053 /*
00054  * Simple wrapper for unlock
00055  */
00056 static int do_unlock(CBM_FILE fd, char *argv[])
00057 {
00058     cbm_unlock(fd);
00059     return 0;
00060 }
00061 
00062 /*
00063  * Simple wrapper for reset
00064  */
00065 static int do_reset(CBM_FILE fd, char *argv[])
00066 {
00067     return cbm_reset(fd);
00068 }
00069 
00070 /*
00071  * Simple wrapper for listen
00072  */
00073 static int do_listen(CBM_FILE fd, char *argv[])
00074 {
00075     return cbm_listen(fd, arch_atoc(argv[0]), arch_atoc(argv[1]));
00076 }
00077 
00078 /*
00079  * Simple wrapper for talk
00080  */
00081 static int do_talk(CBM_FILE fd, char *argv[])
00082 {
00083     return cbm_talk(fd, arch_atoc(argv[0]), arch_atoc(argv[1]));
00084 }
00085 
00086 /*
00087  * Simple wrapper for unlisten
00088  */
00089 static int do_unlisten(CBM_FILE fd, char *argv[])
00090 {
00091     return cbm_unlisten(fd);
00092 }
00093 
00094 /*
00095  * Simple wrapper for untalk
00096  */
00097 static int do_untalk(CBM_FILE fd, char *argv[])
00098 {
00099     return cbm_untalk(fd);
00100 }
00101 
00102 /*
00103  * Simple wrapper for open
00104  */
00105 static int do_open(CBM_FILE fd, char *argv[])
00106 {
00107     return cbm_open(fd, arch_atoc(argv[0]), arch_atoc(argv[1]), argv[2], strlen(argv[2]));
00108 }
00109 
00110 /*
00111  * Simple wrapper for open, but convert from ASCII to PETSCII before doing so.
00112  */
00113 static int do_open_p(CBM_FILE fd, char *argv[])
00114 {
00115     cbm_ascii2petscii(argv[2]);
00116     return do_open(fd, argv);
00117 }
00118 
00119 /*
00120  * Simple wrapper for close
00121  */
00122 static int do_close(CBM_FILE fd, char *argv[])
00123 {
00124     return cbm_close(fd, arch_atoc(argv[0]), arch_atoc(argv[1]));
00125 }
00126 
00127 /*
00128  * read raw data from the IEC bus
00129  */
00130 static int do_read(CBM_FILE fd, char *argv[])
00131 {
00132     int size, rv = 0;
00133     unsigned char buf[2048];
00134     FILE *f;
00135 
00136     if(argv[0] && strcmp(argv[0],"-") != 0)
00137     {
00138         /* a filename (other than simply "-") was given, open that file */
00139 
00140         f = fopen(argv[0], "wb");
00141     }
00142     else
00143     {
00144         /* no filename was given, open stdout in binary mode */
00145 
00146         f = arch_fdopen(arch_fileno(stdout), "wb");
00147 
00148         /* set binary mode for output stream */
00149 
00150         arch_setbinmode(arch_fileno(stdout));
00151     }
00152 
00153     if(!f)
00154     {
00155         arch_error(0, arch_get_errno(), "could not open output file: %s",
00156               (argv[0] && strcmp(argv[0], "-") != 0) ? argv[0] : "stdout");
00157         return 1;
00158     }
00159 
00160         /* fill a buffer with up to 64k of bytes from the IEC bus */
00161     while(0 < (size = cbm_raw_read(fd, buf, sizeof(buf))))
00162     {
00163             /* write that to the file */
00164         if(size != (int) fwrite(buf, 1, size, f))
00165         {
00166             rv=1;   /* error condition from cbm_raw_read */
00167             break;  /* do fclose(f) before exiting       */
00168         }
00169         /* if nobody complained, repeat filling the buffer */
00170     }
00171 
00172     if(size < 0) rv=1; /* error condition from cbm_raw_read */
00173 
00174     fclose(f);
00175     return rv;
00176 }
00177 
00178 /*
00179  * write raw data to the IEC bus
00180  */
00181 static int do_write(CBM_FILE fd, char *argv[])
00182 {
00183     char *fn;
00184     int size;
00185     unsigned char buf[2048];
00186     FILE *f;
00187 
00188     if(!argv[0] || strcmp(argv[0], "-") == 0 || strcmp(argv[0], "") == 0)
00189     {
00190         fn = "(stdin)";
00191         f = stdin;
00192 
00193         // set binary mode for input stream
00194 
00195         arch_setbinmode(arch_fileno(stdin));
00196     }
00197     else
00198     {
00199         off_t filesize;
00200 
00201         fn = argv[0];
00202         f = fopen(argv[0], "rb");
00203         if(f == NULL)
00204         {
00205             arch_error(0, arch_get_errno(), "could not open %s", fn);
00206             return 1;
00207         }
00208         if(arch_filesize(argv[0], &filesize))
00209         {
00210             arch_error(0, arch_get_errno(), "could not stat %s", fn);
00211             return 1;
00212         }
00213     }
00214 
00215         /* fill a buffer with up to 64k of bytes from file/console */
00216     size = fread(buf, 1, sizeof(buf), f);
00217         /* do this test only on the very first run */
00218     if(size == 0 && feof(f))
00219     {
00220         arch_error(0, 0, "no data: %s", fn);
00221         if(f != stdin) fclose(f);
00222         return 1;
00223     }
00224     
00225         /* as long as no error occurred */
00226     while( ! ferror(f))
00227     {
00228             /* write that to the the IEC bus */
00229         if(size != cbm_raw_write(fd, buf, size))
00230         {
00231                 /* exit the loop with another error condition */
00232             break;
00233         }
00234 
00235             /* fill a buffer with up to 64k of bytes from file/console */
00236         size = fread(buf, 1, sizeof(buf), f);
00237         if(size == 0 && feof(f))
00238         {
00239                 /* nothing more to read */
00240             if(f != stdin) fclose(f);
00241             return 0;
00242         }
00243     }
00244         /* the loop has exited, because of an error, check, which one */
00245     if(ferror(f))
00246     {
00247         arch_error(0, 0, "could not read %s", fn);
00248     }
00249     /* else : size number of bytes could not be written to IEC bus */
00250     
00251     if(f != stdin) fclose(f);
00252     return 1;
00253 }
00254 
00255 /*
00256  * display device status w/ PetSCII conversion
00257  */
00258 static int do_status(CBM_FILE fd, char *argv[])
00259 {
00260     char buf[40];
00261     char unit;
00262     int rv;
00263 
00264     unit = arch_atoc(argv[0]);
00265 
00266     rv = cbm_device_status(fd, unit, buf, sizeof(buf));
00267     printf("%s", cbm_petscii2ascii(buf));
00268 
00269     return (rv == 99) ? 1 : 0;
00270 }
00271 
00272 /*
00273  * send device command
00274  */
00275 static int do_command(CBM_FILE fd, char *argv[])
00276 {
00277     int  rv;
00278 
00279     rv = cbm_listen(fd, arch_atoc(argv[0]), 15);
00280     if(rv == 0)
00281     {
00282         cbm_raw_write(fd, argv[1], strlen(argv[1]));
00283         rv = cbm_unlisten(fd);
00284     }
00285     return rv;
00286 }
00287 
00288 /*
00289  * send device command, but convert from ASCII to PETSCII before doing so.
00290  */
00291 static int do_command_p(CBM_FILE fd, char *argv[])
00292 {
00293     cbm_ascii2petscii(argv[1]);
00294     return do_command(fd, argv);
00295 }
00296 
00297 /*
00298  * display directory
00299  */
00300 static int do_dir(CBM_FILE fd, char *argv[])
00301 {
00302     char c, buf[40];
00303     int rv;
00304     char unit;
00305 
00306     unit = arch_atoc(argv[0]);
00307     rv = cbm_open(fd, unit, 0, "$", strlen("$"));
00308     if(rv == 0)
00309     {
00310         if(cbm_device_status(fd, unit, buf, sizeof(buf)) == 0)
00311         {
00312             cbm_talk(fd, unit, 0);
00313             if(cbm_raw_read(fd, buf, 2) == 2)
00314             {
00315                 while(cbm_raw_read(fd, buf, 2) == 2)
00316                 {
00317                     if(cbm_raw_read(fd, buf, 2) == 2)
00318                     {
00319                         printf("%u ", (unsigned char)buf[0] | (unsigned char)buf[1] << 8 );
00320                         while((cbm_raw_read(fd, &c, 1) == 1) && c)
00321                         {
00322                             putchar(cbm_petscii2ascii_c(c));
00323                         }
00324                         putchar('\n');
00325                     }
00326                 }
00327                 cbm_untalk(fd);
00328                 cbm_device_status(fd, unit, buf, sizeof(buf));
00329                 printf("%s", cbm_petscii2ascii(buf));
00330             }
00331             else
00332             {
00333                 cbm_untalk(fd);
00334             }
00335 
00336         }
00337         else
00338         {
00339             printf("%s", cbm_petscii2ascii(buf));
00340         }
00341         cbm_close(fd, unit, 0);
00342     }
00343     return rv;
00344 }
00345 
00346 /*
00347  * read device memory, dump to stdout or a file
00348  */
00349 static int do_download(CBM_FILE fd, char *argv[])
00350 {
00351     unsigned char unit;
00352     unsigned short c;
00353     int addr, count, i, rv = 0;
00354     char *tail, buf[32], cmd[7];
00355     FILE *f;
00356 
00357     unit = arch_atoc(argv[0]);
00358 
00359     addr = strtol(argv[1], &tail, 0);
00360     if(addr < 0 || addr > 0xffff || *tail)
00361     {
00362         arch_error(0, 0, "invalid address: %s", argv[1]);
00363         return 1;
00364     }
00365 
00366     count = strtol(argv[2], &tail, 0);
00367     if((count + addr) > 0x10000 || *tail)
00368     {
00369         arch_error(0, arch_get_errno(), "invalid byte count %s", argv[2]);
00370         return 1;
00371     }
00372 
00373     if(argv[3] && strcmp(argv[3],"-") != 0)
00374     {
00375         /* a filename (other than simply "-") was given, open that file */
00376 
00377         f = fopen(argv[3], "wb");
00378     }
00379     else
00380     {
00381         /* no filename was given, open stdout in binary mode */
00382 
00383         f = arch_fdopen(arch_fileno(stdout), "wb");
00384 
00385         /* set binary mode for output stream */
00386 
00387         arch_setbinmode(arch_fileno(stdout));
00388     }
00389 
00390     if(!f)
00391     {
00392         arch_error(0, arch_get_errno(), "could not open output file: %s",
00393               (argv[3] && strcmp(argv[3], "-") != 0) ? argv[3] : "stdout");
00394         return 1;
00395     }
00396 
00397     for(i = 0; (rv == 0) && (i < count); i+=32)
00398     {
00399         c = count - i;
00400         if(c > 32) 
00401         {
00402             c = 32;
00403         }
00404         sprintf(cmd, "M-R%c%c%c", addr%256, addr/256, c);
00405         cbm_listen(fd, unit, 15);
00406         rv = cbm_raw_write(fd, cmd, 6) == 6 ? 0 : 1;
00407         cbm_unlisten(fd);
00408         if(rv == 0)
00409         {
00410             addr += c;
00411             cbm_talk(fd, unit, 15);
00412             rv = cbm_raw_read(fd, buf, c) == c ? 0 : 1;
00413             cbm_untalk(fd);
00414             if(rv == 0)
00415             {
00416                 fwrite(buf, 1, c, f);
00417             }
00418         }
00419     }
00420     fclose(f);
00421     return rv;
00422 }
00423 
00424 /*
00425  * load binary data from file into device memory
00426  */
00427 static int do_upload(CBM_FILE fd, char *argv[])
00428 {
00429     unsigned char unit;
00430     int addr;
00431     int rv;
00432     size_t size;
00433     char *tail, *fn;
00434     unsigned char addr_buf[2];
00435     unsigned int buflen = 65537;
00436     unsigned char *buf;
00437     FILE *f;
00438 
00439     buf = malloc(buflen);
00440     if (!buf)
00441     {
00442         fprintf(stderr, "Not enough memory for buffer.\n");
00443         return 1;
00444     }
00445 
00446     unit = arch_atoc(argv[0]);
00447 
00448     addr = strtoul(argv[1], &tail, 0);
00449     if(addr < -1 || addr > 0xffff || *tail)
00450     {
00451         arch_error(0, 0, "invalid address: %s", argv[1]);
00452         free(buf);
00453         return 1;
00454     }
00455 
00456     if(!argv[2] || strcmp(argv[2], "-") == 0 || strcmp(argv[2], "") == 0)
00457     {
00458         fn = "(stdin)";
00459         f = stdin;
00460 
00461         // set binary mode for input stream
00462 
00463         arch_setbinmode(arch_fileno(stdin));
00464     }
00465     else
00466     {
00467         off_t filesize;
00468 
00469         fn = argv[2];
00470         f = fopen(argv[2], "rb");
00471         if(f == NULL)
00472         {
00473             arch_error(0, arch_get_errno(), "could not open %s", fn);
00474             free(buf);
00475             return 1;
00476         }
00477         if(arch_filesize(argv[2], &filesize))
00478         {
00479             arch_error(0, arch_get_errno(), "could not stat %s", fn);
00480             free(buf);
00481             return 1;
00482         }
00483     }
00484 
00485     if(addr == -1)
00486     {
00487         /* read address from file */
00488         if(fread(addr_buf, 2, 1, f) != 1)
00489         {
00490             arch_error(0, arch_get_errno(), "could not read %s", fn);
00491             if(f != stdin) fclose(f);
00492             free(buf);
00493             return 1;
00494         }
00495 
00496         /* don't assume a particular endianess, although the cbm4linux
00497          * package is only i386 for now  */
00498         addr = addr_buf[0] | (addr_buf[1] << 8);
00499     }
00500 
00501     size = fread(buf, 1, buflen, f);
00502     if(ferror(f))
00503     {
00504         arch_error(0, 0, "could not read %s", fn);
00505         if(f != stdin) fclose(f);
00506         free(buf);
00507         return 1;
00508     }
00509     else if(size == 0 && feof(f))
00510     {
00511         arch_error(0, 0, "no data: %s", fn);
00512         if(f != stdin) fclose(f);
00513         free(buf);
00514         return 1;
00515     }
00516 
00517     if(addr + size > 0x10000)
00518     {
00519         arch_error(0, 0, "program too big: %s", fn);
00520         if (f != stdin) fclose(f);
00521         free(buf);
00522         return 1;
00523     }
00524 
00525     if(f != stdin) fclose(f);
00526 
00527     rv = (cbm_upload(fd, unit, addr, buf, size) == (int)size) ? 0 : 1;
00528 
00529     free(buf);
00530 
00531     return rv;
00532 }
00533 
00534 /*
00535  * identify connected devices
00536  */
00537 static int do_detect(CBM_FILE fd, char *argv[])
00538 {
00539     unsigned int num_devices;
00540     unsigned char device;
00541     const char *type_str;
00542 
00543     num_devices = 0;
00544 
00545     for( device = 8; device < 16; device++ )
00546     {
00547         enum cbm_device_type_e device_type;
00548         if( cbm_identify( fd, device, &device_type, &type_str ) == 0 )
00549         {
00550             enum cbm_cable_type_e cable_type;
00551             const char *cable_str = "(cannot determine cable type)";
00552  
00553             num_devices++;
00554 
00555             if ( cbm_identify_xp1541( fd, device, &device_type, &cable_type ) == 0 )
00556             {
00557                 switch (cable_type)
00558                 {
00559                 case cbm_ct_none:
00560                     cable_str = "";
00561                     break;
00562 
00563                 case cbm_ct_xp1541:
00564                     cable_str = "(XP1541)";
00565                     break;
00566 
00567                 case cbm_ct_unknown:
00568                 default:
00569                     break;
00570                 }
00571             }
00572             printf( "%2d: %s %s\n", device, type_str, cable_str );
00573         }
00574     }
00575     arch_set_errno(0);
00576     return num_devices > 0 ? 0 : 1;
00577 }
00578 
00579 /*
00580  * wait until user changes the disk
00581  */
00582 static int do_change(CBM_FILE fd, char *argv[])
00583 {
00584     unsigned char unit;
00585     int rv;
00586 
00587     unit = arch_atoc(argv[0]);
00588 
00589     do
00590     {
00591         /*
00592          * Determine if we have a supported drive type.
00593          * Note: As we do not recognize all drives reliably,
00594          *       we only block a 1581. If we cannot determine
00595          *       the drive type, just allow using it!
00596          * \todo: Fix this!
00597          */
00598 
00599         enum cbm_device_type_e device_type;
00600 
00601         if (cbm_identify(fd, unit, &device_type, NULL) == 0)
00602         {
00603             if (device_type == cbm_dt_cbm1581)
00604             {
00605                 fprintf(stderr, "Drive %u is a 1581, which is not supported (yet).\n", unit);
00606                 rv = 1;
00607                 break;
00608             }
00609         }
00610 
00611         /*
00612          * Make sure the drive is on track 18
00613          */
00614         if (cbm_exec_command(fd, unit, "I0:", 0) != 0)
00615         {
00616             /*
00617              * The drive did not react; most probably, there is none,
00618              * thus quit.
00619              */
00620             rv = 1;
00621             break;
00622         }
00623 
00624         rv = cbm_upload(fd, unit, 0x500, prog_tdchange, sizeof(prog_tdchange));
00625     
00626         if (rv != sizeof(prog_tdchange))
00627         {
00628             rv = 1;
00629             break;
00630         }
00631 
00632         cbm_exec_command(fd, unit, "U3:", 0);
00633         cbm_iec_release(fd, IEC_ATN | IEC_DATA | IEC_CLOCK | IEC_RESET);
00634 
00635         /*
00636          * Now, wait for the drive routine to signal its starting
00637          */
00638         cbm_iec_wait(fd, IEC_DATA, 1);
00639 
00640         /*
00641          * Now, wait until CLOCK is high, too, which tells us that
00642          * a new disk has been successfully read.
00643          */
00644         cbm_iec_wait(fd, IEC_CLOCK, 1);
00645 
00646         /*
00647          * Signal: We recognized this
00648          */
00649         cbm_iec_set(fd, IEC_ATN);
00650 
00651         /*
00652          * Wait for routine ending.
00653          */
00654         cbm_iec_wait(fd, IEC_CLOCK, 0);
00655 
00656         /*
00657          * Release ATN again
00658          */
00659         cbm_iec_release(fd, IEC_ATN);
00660 
00661     } while (0);
00662 
00663     return rv;
00664 }
00665 
00666 struct prog
00667 {
00668     int      need_driver;
00669     char    *name;
00670     mainfunc prog;
00671     int      req_args_min;
00672     int      req_args_max;
00673     char    *arglist;
00674     char    *shorthelp_text;
00675     char    *help_text;
00676 };
00677 
00678 static struct prog prog_table[] =
00679 {
00680     {0, "--help"  , do_help    , 0, 1, "[<command>]",
00681         "output this help screen",
00682         "This command outputs some help information for cbmctrl.\n\n"
00683         "<command> is the (optional) command to get information about.\n\n"
00684         "If you use it without parameter, it outputs a list of all\n"
00685         "available commands." },
00686 
00687     {0, "-h"      , do_help    , 0, 1, "",
00688         "same as --help",
00689         "for more info, use \"cbmctrl --help --help\"." },
00690 
00691     {0, "--version",do_version , 0, 0, "",
00692         "output version information",
00693         "This command just outputs the version number and\n"
00694         "build date of cbmctrl." },
00695 
00696     {0, "-V"      , do_version , 0, 0, "",
00697         "same as --version",
00698         "for more info, use \"cbmctrl --help --version\"." },
00699 
00700     {1, "lock"    , do_lock    , 0, 0, "",
00701         "Lock the parallel port for the use by cbm4win/cbm4linux.",
00702         "This command locks the parallel port for the use by cbm4win/cbm4linux,\n"
00703         "so that sequences of e.g. talk/read/untalk commands are not broken by\n"
00704         "concurrent processes wanting to access the parallel port." },
00705 
00706     {1, "unlock"  , do_unlock  , 0, 0, "",
00707         "Unlock the parallel port for the use by cbm4win/cbm4linux.",
00708         "This command unlocks the parallel port again so that other processes\n"
00709         "get a chance to access the parallel port." },
00710 
00711     {1, "listen"  , do_listen  , 2, 2, "<device> <secadr>",
00712         "perform a listen on the IEC bus",
00713         "Output a listen command on the IEC bus.\n"
00714         "<device> is the device number,\n"
00715         "<secadr> the secondary address to use for this.\n\n"
00716         "This has to be undone later with an unlisten command." },
00717 
00718     {1, "talk"    , do_talk    , 2, 2, "<device> <secadr>",
00719         "perform a talk on the IEC bus",
00720         "Output a talk command on the IEC bus.\n"
00721         "<device> is the device number,\n"
00722         "<secadr> the secondary address to use for this.\n\n"
00723         "This has to be undone later with an untalk command." },
00724 
00725     {1, "unlisten", do_unlisten, 0, 0, "",
00726         "perform an unlisten on the IEC bus",
00727         "Undo one or more previous listen commands.\n"
00728         "This affects all drives." },
00729 
00730     {1, "untalk"  , do_untalk  , 0, 0, "",
00731         "perform an untalk on the IEC bus",
00732         "Undo one or more previous talk commands.\n"
00733         "This affects all drives." },
00734 
00735     {1, "open"    , do_open    , 3, 3, "<device> <secadr> <filename>",
00736         "perform an open on the IEC bus",
00737         "Output an open command on the IEC bus.\n"
00738         "<device> is the device number,\n"
00739         "<secadr> the secondary address to use for this.\n"
00740         "<filename> is the name of the file to be opened.\n\n"
00741         "This has to be undone later with a close command.\n\n"
00742         "NOTE: You cannot do an open without a filename.\n"
00743         "      Although a CBM machine (i.e., a C64) allows this,\n"
00744         "      this is an internal operation to the computer only." },
00745 
00746     {1, "popen"   , do_open_p  , 3, 3, "<device> <secadr> <filename>",
00747         "same as open, but convert the filename from ASCII to PETSCII.",
00748         "Output an open command on the IEC bus.\n"
00749         "<device> is the device number,\n"
00750         "<secadr> the secondary address to use for this.\n"
00751         "<filename> is the name of the file to be opened.\n\n"
00752         "This has to be undone later with a close command.\n\n"
00753         "NOTE: You cannot do an open without a filename.\n"
00754         "      Although a CBM machine (i.e., a C64) allows this,\n"
00755         "      this is an internal operation to the computer only." },
00756 
00757     {1, "close"   , do_close   , 2, 2, "<device> <secadr>",
00758         "perform a close on the IEC bus",
00759         "Undo a previous open command." },
00760 
00761     {1, "read"    , do_read    , 0, 1, "[<file>]",
00762         "read raw data from the IEC bus",
00763         "With this command, you can read raw data from the IEC bus.\n"
00764         "<file>   (optional) file name of a file to write the contents to.\n"
00765         "         If this name is not given or it is a dash ('-'), the\n"
00766         "         contents will be written to stdout, normally the console." },
00767 
00768     {1, "write"   , do_write   , 0, 1, "[<file>]",
00769         "write raw data to the IEC bus",
00770         "With this command, you can write raw data to the IEC bus.\n"
00771         "<file>   (optional) file name of a file to read the values from.\n"
00772         "         If this name is not given or it is a dash ('-'), the\n"
00773         "         contents will be read from stdin, normally the console." },
00774 
00775     {1, "status"  , do_status  , 1, 1, "<device>",
00776         "give the status of the specified drive",
00777         "This command gets the status (the so-called 'error channel')"
00778         "of the given drive and outputs it on the screen.\n"
00779         "<device> is the device number of the drive." },
00780 
00781     {1, "command" , do_command , 2, 2, "<device> <cmdstr>",
00782         "issue a command to the specified drive",
00783         "This command issues a command to a specific drive.\n"
00784         "This command is a command that you normally give to\n"
00785         "channel 15 (i.e., N: to format a drive, V: to validate, etc.).\n\n"
00786         "<device> is the device number of the drive.\n\n"
00787         "<cmdstr> is the command to execute in the drive.\n"
00788         "NOTE: You have to give the commands in upper-case letters.\n"
00789         "      Lower case will NOT work!" },
00790 
00791     {1, "pcommand", do_command_p, 2, 2, "<device> <cmdstr>",
00792         "same as command, but convert the cmdstr from ASCII to PETSCII.",
00793         "This command issues a command to a specific drive.\n"
00794         "This command is a command that you normally give to\n"
00795         "channel 15 (i.e., n: to format a drive, v: to validate, etc.).\n\n"
00796         "<device> is the device number of the drive.\n\n"
00797         "<cmdstr> is the command to execute in the drive.\n"
00798         "NOTE: You have to give the commands in lower-case letters.\n"
00799         "      Upper case will NOT work!" },
00800 
00801     {1, "dir"     , do_dir     , 1, 1, "<device>",
00802         "output the directory of the disk in the specified drive",
00803         "This command gets the directory of the disk in the drive.\n\n"
00804         "<device> is the device number of the drive." },
00805 
00806     {1, "download", do_download, 3, 4, "<device> <adr> <count> [<file>]",
00807         "download memory contents from the floppy drive",
00808         "With this command, you can get data from the floppy drive memory.\n"
00809         "<device> is the device number of the drive.\n"
00810         "<adr>    is the starting address of the memory region to get.\n"
00811         "         it can be given in decimal or in hex (with a 0x prefix).\n"
00812         "<count>  is the number of bytes to read.\n"
00813         "         it can be given in decimal or in hex (with a 0x prefix).\n"
00814         "<file>   (optional) file name of a file to write the contents to.\n"
00815         "         If this name is not given or it is a dash ('-'), the\n"
00816         "         contents will be written to stdout, normally the console.\n\n" 
00817         "Example:\n"
00818         " cbmctrl download 8 0xc000 0x4000 1541ROM.BIN\n"
00819         " * reads the 1541 ROM (from $C000 to $FFFF) from drive 8 into 1541ROM.BIN" },
00820 
00821     {1, "upload"  , do_upload  , 2, 3, "<device> <adr> [<file>]",
00822         "upload memory contents to the floppy drive",
00823         "With this command, you can write data to the floppy drive memory.\n"
00824         "<device> is the device number of the drive.\n"
00825         "<adr>    is the starting address of the memory region to write to.\n"
00826         "         it can be given in decimal or in hex (with a 0x prefix).\n"
00827         "<file>   (optional) file name of a file to read the values from.\n"
00828         "         If this name is not given or it is a dash ('-'), the\n"
00829         "         contents will be read from stdin, normally the console."
00830         "Example:\n"
00831         " cbmctrl upload 8 0x500 BUFFER2.BIN\n"
00832         " * writes the file BUFFER2.BIN to drive 8, address $500." },
00833 
00834     {1, "reset"   , do_reset   , 0, 0, "",
00835         "reset all drives on the IEC bus",
00836         "This command performs a (physical) reset of all drives on the IEC bus." },
00837 
00838     {1, "detect"  , do_detect  , 0, 0, "",
00839         "detect all drives on the IEC bus",
00840         "This command tries to detect all drives on the IEC bus.\n"
00841         "For this, this command access all possible drives and tries to read\n"
00842         "some bytes from its memory. If a drive is detected, its name is output.\n"
00843         "Additionally, this routine determines if the drive is connected via a\n"
00844         "parallel cable (XP1541 companion cable)." },
00845 
00846     {1, "change"  , do_change  , 1, 1, "<device>",
00847         "wait for a disk to be changed in the specified drive",
00848         "This command waits for a disk to be changed in the specified drive.\n\n"
00849         "For this, it makes the following assumptions:\n\n"
00850         "* there is already a disk in the drive.\n"
00851         "* that disk will be removed and replaced by another disk.\n"
00852         "* we do not want to return from this command until the disk is completely\n"
00853         "  inserted and ready to be read/written.\n\n"
00854         "Because of this, just opening the drive and closing it again (without\n"
00855         "actually removing the disk) will not work in most cases." },
00856 
00857     {0, NULL,NULL}
00858 };
00859 
00860 static struct prog *find_main(char *name)
00861 {
00862     int i;
00863 
00864     for(i=0; prog_table[i].name; i++)
00865     {
00866         if(strcmp(name, prog_table[i].name) == 0)
00867         {
00868             return &prog_table[i];
00869         }
00870     }
00871     return NULL;
00872 }
00873 
00874 /*
00875  * Output a help screen
00876  */
00877 static int do_help(CBM_FILE fd, char *argv[])
00878 {
00879     int i;
00880 
00881     do_version(fd, argv);
00882 
00883     printf("\n");
00884 
00885     if (*argv == 0)
00886     {
00887         for(i=0; prog_table[i].prog; i++)
00888         {
00889             printf("  %-9s %s\n", prog_table[i].name, prog_table[i].shorthelp_text);
00890         }
00891 
00892         printf("\nFor more information on a specific command, try --help <COMMAND>.\n");
00893 
00894     }
00895     else
00896     {
00897         struct prog *p;
00898 
00899         p = find_main(argv[0]);
00900 
00901         if (p)
00902         {
00903             printf(" cbmctrl %s %s\n\n  %s\n\n%s\n", p->name, p->arglist, p->shorthelp_text, p->help_text);
00904         }
00905         else
00906         {
00907             printf(" Nothing known about \"cbmctrl %s\".\n", argv[0]);
00908         }
00909     }
00910 
00911 
00912     return 0;
00913 }
00914 
00915 int ARCH_MAINDECL main(int argc, char *argv[])
00916 {
00917     struct prog *p;
00918 
00919     p = argc < 2 ? NULL : find_main(argv[1]);
00920     if(p)
00921     {
00922         if((p->req_args_min <= argc-2) && (p->req_args_max >= argc-2))
00923         {
00924             CBM_FILE fd;
00925             int rv;
00926 
00927             if(p->need_driver)
00928                 rv = cbm_driver_open(&fd, 0);
00929             else
00930                 rv = 0;
00931 
00932             if(rv == 0)
00933             {
00934                 rv = p->prog(fd, &argv[2]) != 0;
00935                 if(rv && arch_get_errno())
00936                 {
00937                     arch_error(0, arch_get_errno(), "%s", argv[1]);
00938                 }
00939 
00940                 if(p->need_driver)
00941                     cbm_driver_close(fd);
00942             }
00943             else
00944             {
00945                 if(arch_get_errno())
00946                 {
00947                     arch_error(0, arch_get_errno(), "%s", cbm_get_driver_name(0));
00948                 }
00949                 rv = 1;
00950             }
00951             return rv;
00952         }
00953         else
00954         {
00955             fprintf(stderr, "wrong number of arguments:\n\n  %s %s %s\n",
00956                         argv[0], argv[1], p->arglist);
00957         }
00958     }
00959     else
00960     {
00961         printf("invalid command. For info on possible commands, try the --help parameter.\n\n");
00962     }
00963     return 2;
00964 }

Generated on Sun Apr 30 18:45:44 2006 for opencbm by  doxygen 1.4.2