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 >
Wrap
C/C++ Source or Header
|
1993-08-05
|
17KB
|
488 lines
/*
This is FastFlop, which speeds up your Atari ST's floppy disks
Copyright (C) 1989 by Robert Fischer
This program costs no money; you can redistribute it and/or modify it
under the terms of the Lynxware General License as published by Robert
Fischer; either version 1, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Lynxware General License for more details.
You should have received a copy of the Lynxware General License
along with this program; if not, write to the author.
To contact the author, call or write:
Robert Fischer
80 Killdeer Road
Hamden, CT 06517
(203) 288-9599
E-mail: fischer-robert@cs.yale.edu
*/
/* FastFlop version 3.2 */
#define VERSION "3.2"
long _stksize = 400L;
#include "stddef.h"
#include <basepage.h>
/* ================= Stuff from Include Files =============== */
extern long bios();
extern long xbios();
extern long gemdos();
#define HDV_BPB *( (func **)0x472L )
#define HDV_RW *( (func **)0x476L )
#define HDV_BOOT *( (func **)0x47AL )
#define HDV_MEDIACH *( (func **)0x47EL )
typedef struct os_header {
unsigned bra; /* (0x0) branch to reset handler */
unsigned version; /* (0x2) TOS version number */
char *reset_handler; /* (0x4) pointer to reset handler */
struct os_header *sysbase;/* (0x8) pointer to this block */
char *osram_end; /* (0xc) pointer to end of os ram */
long junk1; /* (0x10) (unused) */
char *magic; /* (0x14) pointer to GEM mem usage block */
long build_date; /* (0x18) system build date */
unsigned os_config; /* (0x1c) OS configuration bits */
unsigned tos_date; /* (0x1e) TOS system build date */
char *root; /* (0x20) pointer to OS pool */
unsigned *kbshift; /* (0x24) pointer to keyboard shift word */
BASEPAGE **run; /* (0x28) pointer to current process ptr */
} OS_HEADER;
#define SYSBASE (*( (OS_HEADER **)0x4F2L ))
#define Pterm0() gemdos(0x0)
#define Cconout(a) gemdos(0x2,a)
#define Cconws(a) gemdos(0x9,a)
#define Super(a) gemdos(0x20,(LONG)(a))
#define Ptermres(a,b) gemdos(0x31,(LONG)(a),b)
#define Malloc(a) (char *)gemdos(0x48,(LONG)a)
#define Bconin(a) bios(2,a)
#define Floprd(a,b,c,d,e,f,g) (int) xbios(8,(LONG)(a),(LONG)(b),c,d,e,f,g)
#define Flopwr(a,b,c,d,e,f,g) (int) xbios(9,(LONG)(a),(LONG)(b),c,d,e,f,g)
/* ========================================================== */
/* Constants */
#define COPYRIGHT 0xbd /* circle-C copyright character */
#define READ 0
#define WRITE 1
#define RW_OFFSET 2 /* # sectors passed while switching tracks */
#define VER_OFFSET 3
#define MAXSPT 10 /* physical # sectors that will fit on a track */
#define CRITICAL_RETRY 0x00010000L
#define OK 0
#define ERROR (-1)
#define DRIVE_NOT_READY (-2)
#define UNKNOWN_CMD (-3)
#define CRC_ERROR (-4)
#define BAD_REQUEST (-5)
#define SEEK_ERROR (-6)
#define UNKNOWN_MEDIA (-7)
#define SECTOR_NOT_FOUND (-8)
#define NO_PAPER (-9)
#define WRITE_FAULT (-10)
#define READ_FAULT (-11)
#define GENERAL_MISHAP (-12)
#define WRITE_PROTECT (-13)
#define MEDIA_CHANGE (-14)
#define UNKNOWN_DEVICE (-15)
#define BAD_SECTORS (-16)
#define INSERT_DISK (-17)
#define WRONG_DISK_DUMMY (-18)
#define SAFE 0
#define UNSURE 1
#define CHANGED 2
/* ---------------------------------------------------------- */
typedef struct {
LONG version; /* The composite version # for this record */
LONG base_adr; /* Base address for this version of TOS */
unsigned length; /* Length of floppy code */
int floprd; /* Location of floprd() */
int flopwr; /* Location of flopwr() */
int flopver; /* Location of flopver() */
int patch_place;/* Place to patch in jmp... */
int ctrack; /* Place to find CTRACK.w */
int flop_cmds_offbase; /* Base address for computing flop_cmds() */
int criterr_patch; /* Place to patch the jmp to the critical error handler */
} offset_rec;
lfunc *flopwr_vec, *floprd_vec; /* flop + offsets->flopw, flop + offsets->floprd */
/* ---------------------------------------------------------- */
/* Stuff about magic ROM locations */
#define NUM_ROMS 4 /* The # of ROM versions supported, i.e. length of loc[] */
offset_rec loc[] = {
/* Here are offsets for the first ROMs (TOS 1.0, 11-20-85) */
0x01000B74L, 0xfc1556L, 0x7D8 /* estimate */,
/* 0xfc159e, 0xfc167c, 0xfc18ce, 0xfc1b90, 0xfc1b88, 0xfc1ba4, 0xfc1cd4 */
0x48, 0x126, 0x378, 0x63a, 0x632, 0x64e, 0x77e,
/* With the introduction of the Mega ROMs, the floppy code changed to
incorporate twisted formatting (and maybe other things, too.) The
following offsets are for the floppy code in TOS 1.2 (Mega ROMs) and
TOS 1.4 in RAM. The bases of the floppy code for those TOSs are:
1.2 ( 4-22-87) : FC173A
1.4 RAM ( 8- 8-88) : 00B95C
The addresses in parentheses are the absolute positions of these
offsets in TOS 1.4, RAM. */
0x01020E96L, 0xFC173AL, 0x7D8,
0x048 /* 0xB9A4 */, 0x11e /* 0xBA7A */, 0x3a8 /* 0xBD04 */,
0x656 /* 0xBFB2 */, 0x64e /* 0xBFAA */, 0x658 /* 0xBFB4 */,
0x782 /* 0xC0De */, /* This is only a guess, based on TOS 1.4 RAM */
/* I haven't verified it. */
0x01041108L, 0xB95CL, 0x7D8,
0x048 /* 0xB9A4 */, 0x11e /* 0xBA7A */, 0x3a8 /* 0xBD04 */,
0x656 /* 0xBFB2 */, 0x64e /* 0xBFAA */, 0x658 /* 0xBFB4 */,
0x782 /* 0xC0De */,
/* The floppy code changes with TOS 1.4, ROM. Without getting
specific, I think that some of the mediach and error handling was
improved. Here are the offsets for the code in TOS 1.4 in ROM, with
the addresses again being absolute addresses for TOS 1.4, ROM. So
far, only one version of TOS has these offsets, and here is its base
address:
1.4, ROM (4-6-89) : FC0EF0
*/
0x01041286L, 0xFC0EF0L, 0x850 /* probably 0x842 */,
/* FLOPRD_C */ 0x048, /* FC0F38 */
/* FLOPWR_C */ 0x11A, /* FC100A */
/* FLOPVER_C */ 0x396, /* FC1286 */
/* PATCH_PLACE_C */ 0x628, /* FC1518 */
/* CTRACK_C */ 0x620, /* FC1510 */
/* FLOP_CMDS_OFFBASE_C */ 0x63C, /* FC152C */
/* Critical error patch */ 0x766 /* FC1656 */
};
/* ---------------------------------------------------------- */
extern BYTE go2tr_patch[]; /* Our patch to the OS */
extern BYTE change_patch[]; /* Second patch to OS */
extern BYTE cpatch_jmp[]; /* jmp command in change_patch to relocate */
BYTE *flop; /* Buffer for floppy code */
offset_rec *offsets; /* The offsets to use */
/* ---------------------------------------------------------- */
struct bpb {
WORD recsiz,
clsiz,
clsizb,
rdlen,
fsiz,
fatrec,
datrec,
numcl,
bflags;
};
struct dsb{
struct bpb b;
WORD dntracks,
dnsides,
dspc,
dspt,
dhidden;
char dserial[3];
} *dsbtabp[2] = {NULL, NULL};
/* ---------------------------------------------------------- */
/* Global variables */
static WORD startsect[] = {1, 1}; /* Sector to start track operation at */
char diskbuf[1024]; /* buffer for verify and odd address calls */
LONG (*orwabs_p)(); /* Old rwabs chain */
LONG (*oxbios_p)(); /* Old Xbios chain */
/* External variables */
#define xbios_vec *( (func **)0xB8L ) /* Xbios vector */
#define hdv_rw (* ( LONG (**)() ) 0x476L) /* rwabs chain pointer */
#define fverify (* (WORD *) 0x444L) /* verify flag */
#define romversion *((WORD *)(SYSBASE + 2))
#define romdate *((WORD *)(SYSBASE + 0x1e))
/* ---------------------------------------------------------- */
/* Functions */
extern LONG critic();
extern VOID fastcpy();
#define orwabs (*orwabs_p)
#define mediach(a) bios(9, a)
#define getbpb(a) bios(7, a)
#define low8bits(x) ((x)&0xff)
/* ---------------------------------------------------------- */
LONG rwabs(rw, buf, count, recno, dev)
WORD rw;
LONG buf;
WORD count, recno, dev;
{
register WORD dv;
LONG ret;
LONG floprw();
dv = dev;
if (dv >= 2 || buf == 0) /* let old rwabs handle */
return orwabs(rw, buf, count, recno, dev);
ret = orwabs(rw, buf, 0, 0, dev); /* try a practice read */
if (ret != OK) return ret; /* give up if things not okay */
if (rw > 1) rw -= 2; /* prepare for the real thing */
return floprw(rw, buf, recno, dv, count); /* do it */
}
/* ------------------------------------------------------ */
LONG floprw(rw, buf, recno, dev, count)
WORD rw;
LONG buf;
WORD recno, dev, count;
{
int u2i();
register struct dsb *p;
register LONG ret;
WORD track, side;
WORD sect, cnt;
WORD end;
WORD sect1, cnt1;
WORD sect2, cnt2;
WORD ss;
LONG bf, bf1, bf2;
WORD oddflag;
p = dsbtabp[dev];
if (p == NULL) { /* Read the BPB if we haven't initted it yet */
p = dsbtabp[dev] = (struct dsb *) getbpb(dev);
}
oddflag = ((buf & 1) == 1);
if (!p->dspc)
p->dspt = p->dspc = 9;
while (count)
{
bf = oddflag ? (LONG) diskbuf : buf;
track = recno / p->dspc;
sect = recno % p->dspc;
if (sect < p->dspt)
side = 0;
else
{
side = 1;
sect -= p->dspt;
}
if (oddflag) cnt = 1;
else if ((p->dspt - sect) < count)
cnt = p->dspt - sect;
else cnt = count;
++sect;
/* try to write track in two pieces for efficiency */
end = sect + cnt;
ss = startsect[dev] + RW_OFFSET;
if (ss > MAXSPT) ss -= MAXSPT;
if (end <= ss || sect >= ss) {
sect1 = sect; /* single piece */
cnt1 = cnt;
cnt2 = 0;
bf1 = bf;
startsect[dev] = end;
}
else { /* split into two pieces */
sect1 = ss;
cnt1 = end - sect1;
sect2 = sect;
cnt2 = sect1 - sect2;
bf1 = bf + ((long)cnt2 << 9);
bf2 = bf;
startsect[dev] = ss;
}
do {
if (rw)
{
if (bf != buf) fastcpy (buf, bf);
ret = (*flopwr_vec)(bf1, 0L, dev, sect1, track, side, cnt1);
if (!ret && cnt2 > 0) {
ret = (*flopwr_vec)(bf2, 0L, dev, sect2, track, side, cnt2);
}
if ((!ret) && (fverify))
{ /* resplit for verify */
end = sect + cnt;
ss = startsect[dev] + VER_OFFSET;
if (ss > MAXSPT) ss -= MAXSPT;
if (end <= ss || sect >= ss) {
sect1 = sect; /* single piece */
cnt1 = cnt;
cnt2 = 0;
startsect[dev] = end;
}
else { /* split into two pieces */
sect1 = ss;
cnt1 = end - sect1;
sect2 = sect;
cnt2 = sect1 - sect2;
startsect[dev] = ss;
}
ret = (*(lfunc *)(flop + offsets->flopver))(diskbuf, 0L, dev, sect1, track, side, cnt1);
if (!ret && !u2i(diskbuf) && cnt2 > 0) {
ret =
(*(lfunc *)(flop + offsets->flopver))(diskbuf, 0L, dev, sect2, track, side, cnt2);
}
if (!ret && u2i(diskbuf))
ret = BAD_SECTORS;
}
}
else
{
ret = (*floprd_vec)(bf1, 0L, dev, sect1, track, side, cnt1);
if (!ret && cnt2 > 0) {
ret = (*floprd_vec)(bf2, 0L, dev, sect2, track, side, cnt2);
}
if (bf != buf) fastcpy(bf, buf);
}
if (ret != 0)
ret = critic((WORD)ret, dev);
} while (ret == CRITICAL_RETRY);
if (ret != 0) return ret;
buf += ((long)cnt << 9);
recno += cnt;
count -= cnt;
}
return OK;
}
/* Byte-swap the integer */
int u2i(loc)
char *loc;
{
return (low8bits(*(loc+1)) << 8) | low8bits(*loc);
}
/* ---------------------------------------------------------- */
/* Install fast rwabs into system */
main()
{
LONG flop_cmds; /* Absolute address of FLOP_CMDS inside of flop[] */
WORD ctrack; /* Value of flop[CTRACK] */
LONG usp;
LONG version; /* The ROM version plus date */
int i;
extern LONG nxbios();
static char address[] = "\
80 Killdeer Road\r\n\
Hamden, CT 06517 USA\r\n\
(203) 288-9599\r\n";
Cconws("FastFlop " VERSION " Copyright \275 1989 by Robert Fischer\r\n");
Cconws(address);
Cconws("FastFlop comes with ABSOLUTELY NO WARRANTY.\r\n"
"This program is Lynxware and is subject to the terms of the Lynxware\r\n"
"General License; either version 1, or (at your option) any later version.\r\n\n"
"You should have received a copy of the Lynxware General License\r\n"
"along with this program; if not, write to the the author\r\n"
);
/* Copy the ROMs */
usp = Super(0);
version = SYSBASE->version;
version <<= 16;
version |= SYSBASE->tos_date;
Super(usp);
i = 0;
for (; ;) {
if (i == NUM_ROMS) {
Cconws("\007*** FastFlop " VERSION " won't work with this ROM\r\n");
Cconws("For help, please write or call:\r\n");
Cconws(address);
Cconws("DO NOT CALL ATARI!!\r\n");
Cconws("Press any key to continue....\r\n");
Bconin(2);
Pterm0();
}
if (loc[i].version == version) {
offsets = &loc[i];
break;
}
i++;
}
flop = Malloc((LONG)offsets->length);
if (flop == NULL) {
Cconws("\007*** Insufficient memory\r\n");
Cconws("Press any key to continue....\r\n");
Bconin(2);
Pterm0();
}
/* Patch the ROM */
memcpy(flop, offsets->base_adr, offsets->length);
/* Pull out the magic locations */
ctrack = *(WORD *)(flop + offsets->ctrack);
flop_cmds = (LONG)&flop[offsets->flop_cmds_offbase + flop[offsets->flop_cmds_offbase-1]];
/* ^^^^^^^^^^^^^^^^^ First patch */
/* Patch our go2track code */
*((WORD *)(go2tr_patch + 0x2)) = ctrack;
*((WORD *)(go2tr_patch + 0x1c)) = ctrack;
*((LONG *)(go2tr_patch + 0x12)) = flop_cmds;
/* Patch in a jmp to our code */
*((WORD *)(flop + offsets->patch_place)) = 0x4EF9; /* jmp */
*((BYTE **)(flop + offsets->patch_place + 2)) = go2tr_patch;
/* Patch in jump to the critical error handler */
*((WORD *)(flop + offsets->criterr_patch)) = 0x4EF9; /* jmp op-code */
*((BYTE **)(flop + offsets->criterr_patch + 2)) = change_patch;
/* Patch cpatch_jmp code to jump back */
*((BYTE **)(cpatch_jmp + 2)) = (flop + offsets->criterr_patch + 10); /* 0x770, TOS 1.4 ROM */
/* Set up the new vectors */
flopwr_vec = (lfunc *)(flop + offsets->flopwr);
floprd_vec = (lfunc *)(flop + offsets->floprd);
/* Install the driver, exit */
usp = Super(0);
oxbios_p = xbios_vec;
/* xbios_vec = nxbios; /* This doesn't work!!!!! */
orwabs_p = hdv_rw;
hdv_rw = rwabs;
Super(usp);
Ptermres(BP->p_hitpa - BP->p_lowtpa, 0); /* term & stay resident */
}