home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / diskutil / ff32src / fflop.c < prev    next >
C/C++ Source or Header  |  1993-08-05  |  17KB  |  488 lines

  1. /*
  2.     This is FastFlop, which speeds up your Atari ST's floppy disks
  3.     Copyright (C) 1989  by Robert Fischer
  4.  
  5.     This program costs no money; you can redistribute it and/or modify it
  6.     under the terms of the Lynxware General License as published by Robert
  7.     Fischer; either version 1, or (at your option) any later version. 
  8.  
  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.     Lynxware General License for more details.
  13.  
  14.     You should have received a copy of the Lynxware General License
  15.     along with this program; if not, write to the author.
  16.  
  17.     To contact the author, call or write:
  18.         Robert Fischer
  19.         80 Killdeer Road
  20.         Hamden, CT    06517
  21.         (203) 288-9599
  22.         E-mail: fischer-robert@cs.yale.edu
  23. */
  24. /* FastFlop version 3.2 */
  25. #define VERSION "3.2"
  26. long _stksize = 400L;
  27.  
  28. #include "stddef.h"
  29. #include <basepage.h>
  30. /* ================= Stuff from Include Files =============== */
  31. extern long bios();
  32. extern long xbios();
  33. extern long gemdos();
  34.  
  35. #define HDV_BPB         *( (func **)0x472L )
  36. #define HDV_RW          *( (func **)0x476L )
  37. #define HDV_BOOT        *( (func **)0x47AL )
  38. #define HDV_MEDIACH     *( (func **)0x47EL )
  39.  
  40. typedef struct os_header {
  41.     unsigned bra;             /* (0x0)  branch to reset handler */  
  42.     unsigned version;         /* (0x2) TOS version number       */
  43.     char *reset_handler;      /* (0x4) pointer to reset handler */
  44.     struct os_header *sysbase;/* (0x8) pointer to this block    */
  45.     char *osram_end;          /* (0xc) pointer to end of os ram */
  46.     long junk1;           /* (0x10) (unused)               */
  47.     char *magic;          /* (0x14) pointer to GEM mem usage block */
  48.     long build_date;      /* (0x18) system build date              */
  49.     unsigned os_config;   /* (0x1c) OS configuration bits      */
  50.     unsigned tos_date;    /* (0x1e) TOS system build date      */
  51.     char *root;           /* (0x20) pointer to OS pool         */
  52.     unsigned *kbshift;    /* (0x24) pointer to keyboard shift word */
  53.     BASEPAGE **run;       /* (0x28) pointer to current process ptr */
  54. } OS_HEADER;
  55. #define SYSBASE         (*( (OS_HEADER **)0x4F2L ))
  56.  
  57. #define Pterm0()        gemdos(0x0)
  58. #define Cconout(a)      gemdos(0x2,a)
  59. #define Cconws(a)       gemdos(0x9,a)
  60. #define Super(a)        gemdos(0x20,(LONG)(a))
  61. #define Ptermres(a,b)   gemdos(0x31,(LONG)(a),b)
  62. #define Malloc(a)       (char *)gemdos(0x48,(LONG)a)
  63.  
  64. #define Bconin(a)       bios(2,a)
  65.  
  66. #define Floprd(a,b,c,d,e,f,g)   (int) xbios(8,(LONG)(a),(LONG)(b),c,d,e,f,g)
  67. #define Flopwr(a,b,c,d,e,f,g)   (int) xbios(9,(LONG)(a),(LONG)(b),c,d,e,f,g)
  68.  
  69. /* ========================================================== */
  70. /* Constants */
  71.  
  72. #define COPYRIGHT 0xbd  /* circle-C copyright character */
  73.  
  74. #define READ    0
  75. #define WRITE   1
  76.  
  77. #define RW_OFFSET  2    /* # sectors passed while switching tracks */
  78. #define VER_OFFSET 3
  79.  
  80. #define MAXSPT 10       /* physical # sectors that will fit on a track */
  81.  
  82. #define CRITICAL_RETRY          0x00010000L
  83. #define OK                      0
  84. #define ERROR                   (-1)
  85. #define DRIVE_NOT_READY         (-2)
  86. #define UNKNOWN_CMD             (-3)
  87. #define CRC_ERROR               (-4)
  88. #define BAD_REQUEST             (-5)
  89. #define SEEK_ERROR              (-6)
  90. #define UNKNOWN_MEDIA           (-7)
  91. #define SECTOR_NOT_FOUND        (-8)
  92. #define NO_PAPER                (-9)
  93. #define WRITE_FAULT             (-10)
  94. #define READ_FAULT              (-11)
  95. #define GENERAL_MISHAP          (-12)
  96. #define WRITE_PROTECT           (-13)
  97. #define MEDIA_CHANGE            (-14)
  98. #define UNKNOWN_DEVICE          (-15)
  99. #define BAD_SECTORS             (-16)
  100. #define INSERT_DISK             (-17)
  101. #define WRONG_DISK_DUMMY        (-18)
  102.  
  103. #define SAFE    0
  104. #define UNSURE  1
  105. #define CHANGED 2
  106.  
  107. /* ---------------------------------------------------------- */
  108. typedef struct {
  109.     LONG version;   /* The composite version # for this record */
  110.     LONG base_adr;  /* Base address for this version of TOS */
  111.     unsigned length;    /* Length of floppy code */
  112.  
  113.     int floprd;     /* Location of floprd() */
  114.     int flopwr;     /* Location of flopwr() */
  115.     int flopver;    /* Location of flopver() */
  116.     int patch_place;/* Place to patch in jmp... */
  117.  
  118.     int ctrack;            /* Place to find CTRACK.w */
  119.     int flop_cmds_offbase; /* Base address for computing flop_cmds() */
  120.     int criterr_patch;        /* Place to patch the jmp to the critical error handler */
  121. } offset_rec;
  122. lfunc *flopwr_vec, *floprd_vec;    /* flop + offsets->flopw, flop + offsets->floprd */
  123. /* ---------------------------------------------------------- */
  124. /* Stuff about magic ROM locations */
  125. #define NUM_ROMS 4  /* The # of ROM versions supported, i.e. length of loc[] */
  126.  
  127. offset_rec loc[] = {
  128. /* Here are offsets for the first ROMs (TOS 1.0, 11-20-85) */
  129. 0x01000B74L, 0xfc1556L, 0x7D8 /* estimate */,
  130. /* 0xfc159e, 0xfc167c, 0xfc18ce, 0xfc1b90, 0xfc1b88, 0xfc1ba4, 0xfc1cd4 */
  131.    0x48,     0x126,    0x378,    0x63a,    0x632,    0x64e,    0x77e,
  132.  
  133. /* With the introduction of the Mega ROMs, the floppy code changed to
  134. incorporate twisted formatting (and maybe other things, too.) The
  135. following offsets are for the floppy code in TOS 1.2 (Mega ROMs) and
  136. TOS 1.4 in RAM.  The bases of the floppy code for those TOSs are:
  137.  
  138.     1.2     ( 4-22-87) : FC173A
  139.     1.4 RAM ( 8- 8-88) : 00B95C
  140.  
  141. The addresses in parentheses are the absolute positions of these
  142. offsets in TOS 1.4, RAM. */
  143.  
  144. 0x01020E96L, 0xFC173AL, 0x7D8,
  145. 0x048 /* 0xB9A4 */, 0x11e /* 0xBA7A */, 0x3a8 /* 0xBD04 */,
  146. 0x656 /* 0xBFB2 */, 0x64e /* 0xBFAA */, 0x658 /* 0xBFB4 */,
  147. 0x782 /* 0xC0De */,       /* This is only a guess, based on TOS 1.4 RAM */
  148.         /* I haven't verified it. */
  149.  
  150. 0x01041108L, 0xB95CL, 0x7D8,
  151. 0x048 /* 0xB9A4 */, 0x11e /* 0xBA7A */, 0x3a8 /* 0xBD04 */,
  152. 0x656 /* 0xBFB2 */, 0x64e /* 0xBFAA */, 0x658 /* 0xBFB4 */,
  153. 0x782 /* 0xC0De */,
  154.  
  155. /* The floppy code changes with TOS 1.4, ROM.  Without getting
  156. specific, I think that some of the mediach and error handling was
  157. improved.  Here are the offsets for the code in TOS 1.4 in ROM, with
  158. the addresses again being absolute addresses for TOS 1.4, ROM.  So
  159. far, only one version of TOS has these offsets, and here is its base
  160. address:
  161.  
  162.     1.4, ROM (4-6-89) : FC0EF0
  163. */
  164.  
  165. 0x01041286L, 0xFC0EF0L, 0x850 /* probably 0x842 */,
  166.  
  167. /* FLOPRD_C             */ 0x048,   /* FC0F38 */
  168. /* FLOPWR_C             */ 0x11A,   /* FC100A */
  169. /* FLOPVER_C            */ 0x396,   /* FC1286 */
  170. /* PATCH_PLACE_C        */ 0x628,   /* FC1518 */
  171.  
  172. /* CTRACK_C             */ 0x620,   /* FC1510 */
  173. /* FLOP_CMDS_OFFBASE_C  */ 0x63C,   /* FC152C */
  174. /* Critical error patch */ 0x766    /* FC1656 */
  175. };
  176.  
  177. /* ---------------------------------------------------------- */
  178. extern BYTE go2tr_patch[];      /* Our patch to the OS */
  179. extern BYTE change_patch[];        /* Second patch to OS */
  180. extern BYTE cpatch_jmp[];        /* jmp command in change_patch to relocate */
  181. BYTE *flop;                     /* Buffer for floppy code */
  182. offset_rec *offsets;            /* The offsets to use */
  183. /* ---------------------------------------------------------- */
  184. struct bpb {
  185.         WORD    recsiz,
  186.                 clsiz,
  187.                 clsizb,
  188.                 rdlen,
  189.                 fsiz,
  190.                 fatrec,
  191.                 datrec,
  192.                 numcl,
  193.                 bflags;
  194. };
  195.  
  196.  
  197. struct dsb{
  198.         struct bpb b;
  199.         WORD    dntracks,
  200.                 dnsides,
  201.                 dspc,
  202.                 dspt,
  203.                 dhidden;
  204.         char    dserial[3];
  205. } *dsbtabp[2] = {NULL, NULL};
  206.  
  207. /* ---------------------------------------------------------- */
  208. /* Global variables */
  209.  
  210. static WORD startsect[] = {1, 1}; /* Sector to start track operation at */
  211. char diskbuf[1024];               /* buffer for verify and odd address calls */
  212. LONG (*orwabs_p)();               /* Old rwabs chain */
  213. LONG (*oxbios_p)();                /* Old Xbios chain */
  214.  
  215. /* External variables */
  216.  
  217. #define xbios_vec       *( (func **)0xB8L )    /* Xbios vector */
  218. #define hdv_rw  (* ( LONG (**)() ) 0x476L)  /* rwabs chain pointer */
  219. #define fverify (* (WORD *) 0x444L)         /* verify flag */
  220. #define romversion *((WORD *)(SYSBASE + 2))
  221. #define romdate *((WORD *)(SYSBASE + 0x1e))
  222. /* ---------------------------------------------------------- */
  223. /* Functions */
  224.  
  225. extern LONG critic();
  226. extern VOID fastcpy();
  227.  
  228. #define orwabs          (*orwabs_p)
  229. #define mediach(a)      bios(9, a)
  230. #define getbpb(a)       bios(7, a)
  231. #define low8bits(x)     ((x)&0xff)
  232.  
  233. /* ---------------------------------------------------------- */
  234. LONG rwabs(rw, buf, count, recno, dev)
  235. WORD rw;
  236. LONG buf;
  237. WORD count, recno, dev;
  238. {
  239.     register WORD dv;
  240.     LONG ret;
  241.  
  242.     LONG floprw();
  243.  
  244.     dv = dev;
  245.     if (dv >= 2 || buf == 0)    /* let old rwabs handle */
  246.         return orwabs(rw, buf, count, recno, dev);
  247.  
  248.     ret = orwabs(rw, buf, 0, 0, dev);    /* try a practice read */
  249.     if (ret != OK) return ret;              /* give up if things not okay */
  250.     if (rw > 1) rw -= 2;                    /* prepare for the real thing */
  251.     return floprw(rw, buf, recno, dv, count);   /* do it */
  252. }
  253. /* ------------------------------------------------------ */
  254. LONG floprw(rw, buf, recno, dev, count)
  255. WORD rw;
  256. LONG buf;
  257. WORD recno, dev, count;
  258. {
  259. int u2i();
  260. register struct dsb *p;
  261. register LONG ret;
  262.  
  263. WORD track, side;
  264. WORD sect, cnt;
  265. WORD end;
  266. WORD sect1, cnt1;
  267. WORD sect2, cnt2;
  268. WORD ss;
  269. LONG bf, bf1, bf2;
  270. WORD oddflag;
  271.  
  272.     p = dsbtabp[dev];
  273.     if (p == NULL) {    /* Read the BPB if we haven't initted it yet */
  274.         p = dsbtabp[dev] = (struct dsb *) getbpb(dev);
  275.     }
  276.  
  277.     oddflag = ((buf & 1) == 1);
  278.     if (!p->dspc)
  279.         p->dspt = p->dspc = 9;
  280.  
  281.     while (count)
  282.     {
  283.         bf = oddflag ? (LONG) diskbuf : buf;
  284.         track = recno / p->dspc;
  285.         sect = recno % p->dspc;
  286.         if (sect < p->dspt)
  287.             side = 0;
  288.         else
  289.         {
  290.             side = 1;
  291.             sect -= p->dspt;
  292.         }
  293.         if (oddflag) cnt = 1;
  294.         else if ((p->dspt - sect) < count)
  295.             cnt = p->dspt - sect;
  296.         else cnt = count;
  297.  
  298.         ++sect;
  299.  
  300.         /* try to write track in two pieces for efficiency */
  301.  
  302.         end = sect + cnt;
  303.         ss = startsect[dev] + RW_OFFSET;
  304.         if (ss > MAXSPT) ss -= MAXSPT;
  305.         if (end <= ss || sect >= ss) {
  306.             sect1 = sect;       /* single piece */
  307.             cnt1 = cnt;
  308.             cnt2 = 0;
  309.             bf1 = bf;
  310.             startsect[dev] = end;
  311.         }
  312.         else {                  /* split into two pieces */
  313.             sect1 = ss;
  314.             cnt1 = end - sect1;
  315.             sect2 = sect;
  316.             cnt2 = sect1 - sect2;
  317.             bf1 = bf + ((long)cnt2 << 9);
  318.             bf2 = bf;
  319.             startsect[dev] = ss;
  320.         }
  321.  
  322.         do {
  323.             if (rw)
  324.             {
  325.                 if (bf != buf) fastcpy (buf, bf);
  326.                 ret = (*flopwr_vec)(bf1, 0L, dev, sect1, track, side, cnt1);
  327.                 if (!ret && cnt2 > 0) {
  328.                     ret = (*flopwr_vec)(bf2, 0L, dev, sect2, track, side, cnt2);
  329.                 }
  330.  
  331.                 if ((!ret) && (fverify))
  332.  
  333.                 {   /* resplit for verify */
  334.  
  335.                     end = sect + cnt;
  336.                     ss = startsect[dev] + VER_OFFSET;
  337.                     if (ss > MAXSPT) ss -= MAXSPT;
  338.                     if (end <= ss || sect >= ss) {
  339.                         sect1 = sect;        /* single piece */
  340.                         cnt1 = cnt;
  341.                         cnt2 = 0;
  342.                         startsect[dev] = end;
  343.                     }
  344.                     else {                        /* split into two pieces */
  345.                         sect1 = ss;
  346.                         cnt1 = end - sect1;
  347.                         sect2 = sect;
  348.                         cnt2 = sect1 - sect2;
  349.                         startsect[dev] = ss;
  350.                     }
  351.  
  352.                     ret = (*(lfunc *)(flop + offsets->flopver))(diskbuf, 0L, dev, sect1, track, side, cnt1);
  353.                     if (!ret && !u2i(diskbuf) && cnt2 > 0) {
  354.                         ret = 
  355.                           (*(lfunc *)(flop + offsets->flopver))(diskbuf, 0L, dev, sect2, track, side, cnt2);
  356.                     }
  357.                     if (!ret && u2i(diskbuf))
  358.                         ret = BAD_SECTORS;
  359.                 }
  360.             }
  361.             else
  362.             {
  363.                 ret = (*floprd_vec)(bf1, 0L, dev, sect1, track, side, cnt1);
  364.                 if (!ret && cnt2 > 0) {
  365.                     ret = (*floprd_vec)(bf2, 0L, dev, sect2, track, side, cnt2);
  366.                 }
  367.                 if (bf != buf) fastcpy(bf, buf);
  368.             }
  369.  
  370.             if (ret != 0)
  371.                 ret = critic((WORD)ret, dev);
  372.         } while (ret == CRITICAL_RETRY);
  373.         if (ret != 0) return ret;
  374.  
  375.         buf += ((long)cnt << 9);
  376.         recno += cnt;
  377.         count -= cnt;
  378.     }
  379.     return OK;
  380. }
  381.  
  382.  
  383. /* Byte-swap the integer */
  384. int u2i(loc)
  385. char *loc;
  386. {
  387.         return (low8bits(*(loc+1)) << 8) | low8bits(*loc);
  388. }
  389.  
  390. /* ---------------------------------------------------------- */
  391. /* Install fast rwabs into system */
  392. main()
  393. {
  394. LONG flop_cmds;         /* Absolute address of FLOP_CMDS inside of flop[] */
  395. WORD ctrack;            /* Value of flop[CTRACK] */
  396. LONG usp;
  397. LONG version;           /* The ROM version plus date */
  398. int i;
  399. extern LONG nxbios();
  400.  
  401. static char address[] = "\
  402.                   80 Killdeer Road\r\n\
  403.                   Hamden, CT  06517  USA\r\n\
  404.                   (203) 288-9599\r\n";
  405.  
  406.         Cconws("FastFlop " VERSION " Copyright \275 1989 by Robert Fischer\r\n");
  407.         Cconws(address);
  408.         Cconws("FastFlop comes with ABSOLUTELY NO WARRANTY.\r\n"
  409.     "This program is Lynxware and is subject to the terms of the Lynxware\r\n"
  410.     "General License; either version 1, or (at your option) any later version.\r\n\n"
  411.  
  412.     "You should have received a copy of the Lynxware General License\r\n"
  413.     "along with this program; if not, write to the the author\r\n"
  414.     );
  415.  
  416.         /* Copy the ROMs */
  417.         usp = Super(0);
  418.         version = SYSBASE->version;
  419.         version <<= 16;
  420.         version |= SYSBASE->tos_date;
  421.         Super(usp);
  422.  
  423.         i = 0;
  424.         for (; ;) {
  425.             if (i == NUM_ROMS) {
  426.                 Cconws("\007*** FastFlop " VERSION " won't work with this ROM\r\n");
  427.                 Cconws("For help, please write or call:\r\n");
  428.                 Cconws(address);
  429.                 Cconws("DO NOT CALL ATARI!!\r\n");
  430.                 Cconws("Press any key to continue....\r\n");
  431.                 Bconin(2);
  432.                 Pterm0();
  433.             }
  434.             if (loc[i].version == version) {
  435.                 offsets = &loc[i];
  436.                 break;
  437.             }
  438.             i++;
  439.         }
  440.  
  441.         flop = Malloc((LONG)offsets->length);
  442.         if (flop == NULL) {
  443.             Cconws("\007*** Insufficient memory\r\n");
  444.             Cconws("Press any key to continue....\r\n");
  445.             Bconin(2);
  446.             Pterm0();
  447.         }
  448.  
  449.         /* Patch the ROM */
  450.         memcpy(flop, offsets->base_adr, offsets->length);
  451.  
  452.         /* Pull out the magic locations */
  453.         ctrack = *(WORD *)(flop + offsets->ctrack);
  454.         flop_cmds = (LONG)&flop[offsets->flop_cmds_offbase + flop[offsets->flop_cmds_offbase-1]];
  455.  
  456.  
  457.         /* ^^^^^^^^^^^^^^^^^ First patch */
  458.         /* Patch our go2track code */
  459.         *((WORD *)(go2tr_patch + 0x2)) = ctrack;
  460.         *((WORD *)(go2tr_patch + 0x1c)) = ctrack;
  461.         *((LONG *)(go2tr_patch + 0x12)) = flop_cmds;
  462.  
  463.         /* Patch in a jmp to our code */
  464.         *((WORD *)(flop + offsets->patch_place)) = 0x4EF9;               /* jmp */
  465.         *((BYTE **)(flop + offsets->patch_place + 2)) = go2tr_patch;
  466.  
  467.         /* Patch in jump to the critical error handler */
  468.         *((WORD *)(flop + offsets->criterr_patch)) = 0x4EF9;  /* jmp op-code */
  469.         *((BYTE **)(flop + offsets->criterr_patch + 2)) = change_patch;
  470.  
  471.         /* Patch cpatch_jmp code to jump back */
  472.         *((BYTE **)(cpatch_jmp + 2)) = (flop + offsets->criterr_patch + 10);    /* 0x770, TOS 1.4 ROM */
  473.  
  474.         /* Set up the new vectors */
  475.         flopwr_vec = (lfunc *)(flop + offsets->flopwr);
  476.         floprd_vec = (lfunc *)(flop + offsets->floprd);
  477.  
  478.         /* Install the driver, exit */
  479.         usp = Super(0);
  480.         oxbios_p = xbios_vec;
  481. /*        xbios_vec = nxbios;            /* This doesn't work!!!!! */
  482.         orwabs_p = hdv_rw;
  483.         hdv_rw = rwabs;
  484.         Super(usp);
  485.  
  486.         Ptermres(BP->p_hitpa - BP->p_lowtpa, 0);        /* term & stay resident */
  487. }
  488.