#include "compiler.h"
#include "dosio.h"
#include "pccore.h"
#include "iocore.h"
#include "fddfile.h"
#include "fdd_d88.h"
#define D88BUFSIZE 0x6000
#define D88TRACKMAX 10600
static UINT32 nexttrackptr(FDDFILE fdd, UINT32 fptr, UINT32 last) {
int t;
UINT32 cur;
for (t=0; t<164; t++) {
cur = fdd->inf.d88.ptr[t];
if ((cur > fptr) && (cur < last)) {
last = cur;
}
}
return(last);
}
// ----
typedef struct {
FDDFILE fdd;
UINT track;
UINT type;
long fptr;
UINT size;
BOOL write;
UINT8 buf[D88BUFSIZE];
} _D88TRK, *D88TRK;
static _D88TRK d88trk;
static BRESULT d88trk_flushdata(D88TRK trk) {
FDDFILE fdd;
FILEH fh;
fdd = trk->fdd;
trk->fdd = NULL;
if ((fdd == NULL) || (trk->size == 0) || (!trk->write)) {
goto dtfd_exit;
}
fh = file_open(fdd->fname);
if (fh == FILEH_INVALID) {
goto dtfd_err1;
}
if ((file_seek(fh, trk->fptr, FSEEK_SET) != trk->fptr) ||
(file_write(fh, trk->buf, trk->size) != trk->size)) {
goto dtfd_err2;
}
file_close(fh);
trk->write = FALSE;
dtfd_exit:
return(SUCCESS);
dtfd_err2:
file_close(fh);
dtfd_err1:
return(FAILURE);
}
static BRESULT d88trk_read(D88TRK trk, FDDFILE fdd, UINT track, UINT type) {
UINT8 rpm;
FILEH fh;
UINT32 fptr;
UINT32 size;
d88trk_flushdata(trk);
if (track >= 164) {
goto dtrd_err1;
}
rpm = fdc.rpm[fdc.us];
switch(fdd->inf.d88.fdtype_major) {
case DISKTYPE_2D:
TRACEOUT(("DISKTYPE_2D"));
if ((rpm) || (type != DISKTYPE_2DD) || (track & 2)) {
goto dtrd_err1;
}
track = ((track >> 1) & 0xfe) | (track & 1);
break;
case DISKTYPE_2DD:
if ((rpm) || (type != DISKTYPE_2DD)) {
goto dtrd_err1;
}
break;
case DISKTYPE_2HD:
if (CTRL_FDMEDIA != DISKTYPE_2HD) {
goto dtrd_err1;
}
if ((fdd->inf.d88.fdtype_minor == 0) && (rpm)) {
goto dtrd_err1;
}
break;
default:
goto dtrd_err1;
}
fptr = fdd->inf.d88.ptr[track];
if (fptr == 0) {
goto dtrd_err1;
}
size = nexttrackptr(fdd, fptr, fdd->inf.d88.fd_size) - fptr;
if (size > D88BUFSIZE) {
size = D88BUFSIZE;
}
fh = file_open_rb(fdd->fname);
if (fh == FILEH_INVALID) {
goto dtrd_err1;
}
if ((file_seek(fh, (long)fptr, FSEEK_SET) != (long)fptr) ||
(file_read(fh, trk->buf, size) != size)) {
goto dtrd_err2;
}
file_close(fh);
trk->fdd = fdd;
trk->track = track;
trk->type = type;
trk->fptr = fptr;
trk->size = size;
trk->write = FALSE;
return(SUCCESS);
dtrd_err2:
file_close(fh);
dtrd_err1:
return(FAILURE);
}
static BRESULT rpmcheck(D88SEC sec) {
FDDFILE fdd = fddfile + fdc.us;
UINT8 rpm;
rpm = fdc.rpm[fdc.us];
switch(fdd->inf.d88.fdtype_major) {
case DISKTYPE_2D:
case DISKTYPE_2DD:
if (rpm) {
return(FAILURE);
}
break;
case DISKTYPE_2HD:
if (fdd->inf.d88.fdtype_minor == 0) {
if (rpm) {
return(FAILURE);
}
}
else {
if (sec->rpm_flg != rpm) {
return(FAILURE);
}
}
break;
default:
return(FAILURE);
}
return(SUCCESS);
}
// ----
static void drvflush(FDDFILE fdd) {
D88TRK trk;
trk = &d88trk;
if (trk->fdd == fdd) {
d88trk_flushdata(trk);
trk->fdd = NULL;
}
}
static BRESULT trkseek(FDDFILE fdd, UINT track) {
D88TRK trk;
BOOL r;
trk = &d88trk;
if ((trk->fdd == fdd) && (trk->track == track) &&
(trk->type == CTRL_FDMEDIA)) {
r = SUCCESS;
}
else {
r = d88trk_read(trk, fdd, track, CTRL_FDMEDIA);
}
return(r);
}
static D88SEC searchsector_d88(BOOL check) { // ver0.29
UINT8 *p;
UINT sec;
UINT pos = 0;
UINT nsize;
UINT sectors;
UINT secsize;
if (fdc.N < 8) {
nsize = 128 << fdc.N;
}
else {
nsize = 128 << 8;
}
p = d88trk.buf;
for (sec=0; sec<40; ) {
if ((pos + nsize + sizeof(_D88SEC)) > D88BUFSIZE) {
break;
}
if ((((D88SEC)p)->c == fdc.C) &&
(((D88SEC)p)->h == fdc.H) &&
(((D88SEC)p)->r == fdc.R) &&
(((D88SEC)p)->n == fdc.N) &&
(!rpmcheck((D88SEC)p))) {
// ver0.29
if (check) {
if ((fdc.mf != 0xff) &&
!((fdc.mf ^ (((D88SEC)p)->mfm_flg)) & 0x40)) {
break;
}
}
return((D88SEC)p);
}
sectors = LOADINTELWORD(((D88SEC)p)->sectors);
if (++sec >= sectors) {
break;
}
secsize = LOADINTELWORD(((D88SEC)p)->size);
secsize += sizeof(_D88SEC);
pos += secsize;
p += secsize;
}
return(NULL);
}
// ----
BRESULT fddd88_set(FDDFILE fdd, const OEMCHAR *fname, int ro) {
short attr;
FILEH fh;
UINT rsize;
int i;
fddd88_eject(fdd);
attr = file_attr(fname);
if (attr & 0x18) {
goto fdst_err;
}
fh = file_open(fname);
if (fh == FILEH_INVALID) {
goto fdst_err;
}
rsize = file_read(fh, &fdd->inf.d88.head, sizeof(fdd->inf.d88.head));
file_close(fh);
if (rsize != sizeof(fdd->inf.d88.head)) {
goto fdst_err;
}
fdd->type = DISKTYPE_D88;
fdd->protect = ((attr & 1) || (fdd->inf.d88.head.protect & 0x10) ||
(ro))?TRUE:FALSE;
fdd->inf.d88.fdtype_major = fdd->inf.d88.head.fd_type >> 4;
fdd->inf.d88.fdtype_minor = fdd->inf.d88.head.fd_type & 0x0f;
fdd->inf.d88.fd_size = LOADINTELDWORD(fdd->inf.d88.head.fd_size);
for (i=0; i<164; i++) {
fdd->inf.d88.ptr[i] = LOADINTELDWORD(fdd->inf.d88.head.trackp[i]);
}
return(SUCCESS);
fdst_err:
return(FAILURE);
}
BRESULT fddd88_eject(FDDFILE fdd) {
drvflush(fdd);
fdd->fname[0] = '\0';
fdd->type = DISKTYPE_NOTREADY;
ZeroMemory(&fdd->inf.d88.head, sizeof(fdd->inf.d88.head));
return(SUCCESS);
}
BRESULT fdd_diskaccess_d88(void) { // ver0.31
FDDFILE fdd = fddfile + fdc.us;
UINT8 rpm;
rpm = fdc.rpm[fdc.us];
switch(fdd->inf.d88.fdtype_major) {
case DISKTYPE_2D:
case DISKTYPE_2DD:
if ((rpm) || (CTRL_FDMEDIA != DISKTYPE_2DD)) {
return(FAILURE);
}
break;
case DISKTYPE_2HD:
if (CTRL_FDMEDIA != DISKTYPE_2HD) {
return(FAILURE);
}
if ((fdd->inf.d88.fdtype_minor == 0) && (rpm)) {
return(FAILURE);
}
break;
default:
return(FAILURE);
}
return(SUCCESS);
}
BRESULT fdd_seek_d88(void) {
FDDFILE fdd = fddfile + fdc.us;
return(trkseek(fdd, (fdc.ncn << 1) + fdc.hd));
}
BRESULT fdd_seeksector_d88(void) {
FDDFILE fdd = fddfile + fdc.us;
if (trkseek(fdd, (fdc.treg[fdc.us] << 1) + fdc.hd)) {
return(FAILURE);
}
if (!searchsector_d88(FALSE)) {
return(FAILURE);
}
return(SUCCESS);
}
BRESULT fdd_read_d88(void) {
FDDFILE fdd = fddfile + fdc.us;
D88SEC p;
UINT size;
UINT secsize;
fddlasterror = 0x00;
if (trkseek(fdd, (fdc.treg[fdc.us] << 1) + fdc.hd)) {
fddlasterror = 0xe0;
return(FAILURE);
}
p = searchsector_d88(TRUE);
if (!p) {
fddlasterror = 0xc0;
return(FAILURE);
}
if (fdc.N < 8) {
size = 128 << fdc.N;
}
else {
size = 128 << 8;
}
fdc.bufcnt = size;
ZeroMemory(fdc.buf, size);
secsize = LOADINTELWORD(p->size);
if (size > secsize) {
size = secsize;
}
if (size) {
CopyMemory(fdc.buf, p+1, size);
}
fddlasterror = p->stat;
return(SUCCESS);
}
BRESULT fdd_write_d88(void) {
FDDFILE fdd = fddfile + fdc.us;
D88SEC p;
UINT size;
UINT secsize;
fddlasterror = 0x00;
if (trkseek(fdd, (fdc.treg[fdc.us] << 1) + fdc.hd)) {
fddlasterror = 0xe0;
return(FAILURE);
}
p = searchsector_d88(FALSE);
if (!p) {
fddlasterror = 0xc0;
return(FAILURE);
}
if (fdc.N < 8) {
size = 128 << fdc.N;
}
else {
size = 128 << 8;
}
secsize = LOADINTELWORD(p->size);
if (size > secsize) {
size = secsize;
}
if (size) {
CopyMemory(p+1, fdc.buf, size);
d88trk.write = TRUE;
}
fddlasterror = 0x00;
return(SUCCESS);
}
BRESULT fdd_readid_d88(void) {
FDDFILE fdd = fddfile + fdc.us;
UINT8 *p;
UINT sec;
UINT pos = 0;
UINT sectors;
UINT secsize;
fddlasterror = 0x00;
if (trkseek(fdd, (fdc.treg[fdc.us] << 1) + fdc.hd)) {
fddlasterror = 0xe0;
return(FAILURE);
}
p = d88trk.buf;
for (sec=0; sec<40; ) {
if (pos > (D88BUFSIZE - sizeof(_D88SEC))) {
break;
}
sectors = LOADINTELWORD(((D88SEC)p)->sectors);
if ((sec == fdc.crcn) && (!rpmcheck((D88SEC)p))) { // ver0.31
fdc.C = ((D88SEC)p)->c;
fdc.H = ((D88SEC)p)->h;
fdc.R = ((D88SEC)p)->r;
fdc.N = ((D88SEC)p)->n;
fdc.crcn++;
if (fdc.crcn >= sectors) {
fdc.crcn = 0;
}
if ((fdc.mf == 0xff) ||
((fdc.mf ^ (((D88SEC)p)->mfm_flg)) & 0x40)) {
fddlasterror = 0x00;
return(SUCCESS);
}
}
if (++sec >= sectors) {
break;
}
secsize = LOADINTELWORD(((D88SEC)p)->size);
secsize += sizeof(_D88SEC);
pos += secsize;
p += secsize;
}
fdc.crcn = 0x00;
fddlasterror = 0xe0; // ver0.31
return(FAILURE);
}
// --------------------------------------------------------------------------
// えーと…こんなところにあって大丈夫?
static BOOL formating = FALSE;
static UINT8 formatsec = 0;
static UINT8 formatwrt = 0;
static UINT formatpos = 0;
static int fileappend(FILEH hdl, FDDFILE fdd,
UINT32 ptr, long last, long apsize) {
long length;
UINT size;
UINT rsize;
int t;
UINT8 tmp[0x400]; // Stack 0x1000->0x400
UINT32 cur;
if ((length = last - ptr) <= 0) { // 書き換える必要なし
return(0);
}
while(length) {
if (length >= (long)(sizeof(tmp))) {
size = sizeof(tmp);
}
else {
size = length;
}
length -= size;
file_seek(hdl, ptr + length, 0);
rsize = file_read(hdl, tmp, size);
file_seek(hdl, ptr + length + apsize, 0);
file_write(hdl, tmp, rsize);
}
for (t=0; t<164; t++) {
cur = fdd->inf.d88.ptr[t];
if ((cur != 0) && (cur >= ptr)) {
cur += apsize;
fdd->inf.d88.ptr[t] = cur;
STOREINTELDWORD(fdd->inf.d88.head.trackp[t], cur);
}
}
return(0);
}
static void endoftrack(UINT fmtsize, UINT8 sectors) {
FDDFILE fdd = fddfile + fdc.us;
D88SEC d88sec;
FILEH hdl;
int i;
UINT trk;
long fpointer;
long endpointer;
long lastpointer;
long trksize;
int ptr;
long apsize;
trk = (fdc.treg[fdc.us] << 1) + fdc.hd;
ptr = 0;
for (i=0; i<(int)sectors; i++) {
d88sec = (D88SEC)(d88trk.buf + ptr);
STOREINTELWORD(d88sec->sectors, sectors);
ptr += LOADINTELWORD(d88sec->size);
ptr += sizeof(_D88SEC);
}
hdl = file_open(fddfile[fdc.us].fname);
if (hdl == FILEH_INVALID) {
return;
}
lastpointer = file_seek(hdl, 0, FSEEK_END);
fpointer = fdd->inf.d88.ptr[trk];
if (fpointer == 0) {
for (i=trk; i>=0; i--) { // 新規トラック
fpointer = fdd->inf.d88.ptr[i];
if (fpointer) {
break;
}
}
if (fpointer) { // ヒットした
fpointer = nexttrackptr(fdd, fpointer, lastpointer);
}
else {
fpointer = sizeof(_D88HEAD);
}
endpointer = fpointer;
}
else { // トラックデータは既にある
endpointer = nexttrackptr(fdd, fpointer, lastpointer);
}
trksize = endpointer - fpointer;
if ((apsize = (long)fmtsize - trksize) > 0) {
// 書き込むデータのほーが大きい
fileappend(hdl, fdd, endpointer, lastpointer, apsize);
fdd->inf.d88.fd_size += apsize;
STOREINTELDWORD(fdd->inf.d88.head.fd_size, fdd->inf.d88.fd_size);
}
fdd->inf.d88.ptr[trk] = fpointer;
STOREINTELDWORD(fdd->inf.d88.head.trackp[trk], fpointer);
file_seek(hdl, fpointer, 0);
file_write(hdl, d88trk.buf, fmtsize);
file_seek(hdl, 0, FSEEK_SET);
file_write(hdl, &fdd->inf.d88.head, sizeof(fdd->inf.d88.head));
file_close(hdl);
// TRACEOUT(("fmt %d %d", fpointer, fmtsize));
}
BRESULT fdd_formatinit_d88(void) {
if (fdc.treg[fdc.us] < 82) {
formating = TRUE;
formatsec = 0;
formatpos = 0;
formatwrt = 0;
drvflush(fddfile + fdc.us);
return(SUCCESS);
}
return(FAILURE);
}
// todo アンフォーマットとか ディスク1周した時の切り捨てとか…
BRESULT fdd_formating_d88(const UINT8 *ID) {
FDDFILE fdd = fddfile + fdc.us;
UINT size;
D88SEC d88sec;
if (!formating) {
return(FAILURE);
}
if (fdc.N < 8) {
size = 128 << fdc.N;
}
else {
size = 128 << 8;
}
if ((formatpos + sizeof(_D88SEC) + size) < D88TRACKMAX) {
d88sec = (D88SEC)(d88trk.buf + formatpos);
ZeroMemory(d88sec, sizeof(_D88SEC));
d88sec->c = ID[0];
d88sec->h = ID[1];
d88sec->r = ID[2];
d88sec->n = ID[3];
STOREINTELWORD(d88sec->size, size);
if ((fdd->inf.d88.fdtype_major == DISKTYPE_2HD) &&
(fdd->inf.d88.fdtype_minor != 0)) {
d88sec->rpm_flg = fdc.rpm[fdc.us];
}
FillMemory(d88sec + 1, size, fdc.d);
formatpos += sizeof(_D88SEC);
formatpos += size;
formatwrt++;
}
formatsec++;
// TRACE_("format sec", formatsec);
// TRACE_("format wrt", formatwrt);
// TRACE_("format max", fdc.sc);
// TRACE_("format pos", formatpos);
if (formatsec >= fdc.sc) {
endoftrack(formatpos, formatwrt);
formating = FALSE;
}
return(SUCCESS);
}
BOOL fdd_isformating_d88(void) {
return(formating);
}
RetroPC.NET-CVS <cvs@retropc.net>