File:  [RetroPC.NET] / xmil / fdd / fdd_d88.c
Revision 1.16: download - view: text, annotated - select for diffs
Tue Jun 3 05:07:31 2008 JST (17 years, 4 months ago) by yui
Branches: MAIN
CVS tags: HEAD
change to c style comment

#include	"compiler.h"
#include	"dosio.h"
#include	"pccore.h"
#include	"fddfile.h"
#include	"fdd_d88.h"
#include	"fdd_mtr.h"


enum {
	D88BUFSIZE		= 0x4000
};

typedef struct {
	FDDFILE	fdd;
	UINT8	media;
	UINT8	write;
	UINT8	padding[2];
	UINT	track;
	long	fptr;
	UINT	size;
	UINT	sectors;
	UINT8	buf[D88BUFSIZE];
} _D88TRK, *D88TRK;

static	_D88TRK		d88trk;


static UINT32 nexttrackptr(FDDFILE fdd, UINT32 fptr, UINT32 last) {

	UINT	t;
	UINT32	cur;

	for (t=0; t<164; t++) {
		cur = fdd->inf.d88.ptr[t];
		if ((cur > fptr) && (cur < last)) {
			last = cur;
		}
	}
	return(last);
}

static BRESULT trackflush(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 D88TRK trackread(D88TRK trk, FDDFILE fdd, REG8 media, UINT track) {

	FILEH		fh;
	UINT32		fptr;
	UINT		size;
const _D88SEC	*sec;
	UINT		rem;
	UINT		maxsectors;
	UINT		sectors;
	UINT		secsize;

	trackflush(trk);
	if (media != (REG8)((fdd->inf.d88.head.fd_type >> 4))) {
		goto dtrd_err1;
	}
	if (track >= 164) {
		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->media = media;
	trk->write = FALSE;
	trk->track = track;
	trk->fptr = fptr;
	trk->size = size;

	/* セクタ数チェック */
	sec = (D88SEC)trk->buf;
	rem = size;
	maxsectors = 0;
	if (rem >= sizeof(_D88SEC)) {
		maxsectors = LOADINTELWORD(sec->sectors);
	}
	sectors = 0;
	while(sectors < maxsectors) {
		secsize = LOADINTELWORD(sec->size);
		secsize += sizeof(_D88SEC);
		if (rem < secsize) {
			break;
		}
		rem -= secsize;
		maxsectors = LOADINTELWORD(sec->sectors);
		sec = (D88SEC)(((UINT8 *)sec) + secsize);
		sectors++;
	}
	trk->sectors = sectors;
	return(trk);

dtrd_err2:
	file_close(fh);

dtrd_err1:
	return(NULL);
}

static void drvflush(FDDFILE fdd) {

	D88TRK	trk;

	trk = &d88trk;
	if (trk->fdd == fdd) {
		trackflush(trk);
	}
}

static D88TRK trackseek(FDDFILE fdd, REG8 media, UINT track) {

	D88TRK	trk;

	trk = &d88trk;
	if ((trk->fdd != fdd) || (trk->media != media) || (trk->track != track)) {
		trk = trackread(trk, fdd, media, track);
	}
	return(trk);
}

static D88SEC sectorseek(const _D88TRK *trk, REG8 r) {

const _D88SEC	*sec;
	UINT		sectors;
	UINT		size;

	sec = (D88SEC)trk->buf;
	sectors = trk->sectors;
	while(sectors) {
		sectors--;
		if (sec->r == r) {
			return((D88SEC)sec);
		}
		size = LOADINTELWORD(sec->size);
		size += sizeof(_D88SEC);
		sec = (D88SEC)(((UINT8 *)sec) + size);
	}
	return(NULL);
}


/* ---- */

static BRESULT fileappend(FILEH fh, UINT32 ptr, UINT size) {

	UINT	filesize;
	UINT	r;
	UINT8	work[0x400];

	filesize = file_getsize(fh);
	if (filesize < ptr) {
		return(FAILURE);
	}
	filesize -= ptr;
	while(filesize) {
		r = min(filesize, sizeof(work));
		filesize -= r;
		file_seek(fh, ptr + filesize, FSEEK_SET);
		r = file_read(fh, work, r);
		file_seek(fh, ptr + filesize + size, FSEEK_SET);
		file_write(fh, work, r);
	}
	return(SUCCESS);
}

static BRESULT writetrack(FDDFILE fdd, REG8 media, UINT track,
													UINT8 *buf, UINT size) {

	FILEH	fh;
	UINT	i;
	UINT32	curptr;
	UINT32	nextptr;
	UINT	cursize;
	UINT	addsize;
	UINT32	cur;
	UINT8	ptr[D88_TRACKMAX][4];

	if ((track >= D88_TRACKMAX) || (size == 0)) {
		return(FAILURE);
	}

	fh = file_open(fdd->fname);
	if (fh == FILEH_INVALID) {
		return(FAILURE);
	}
	curptr = fdd->inf.d88.ptr[track];
	if (curptr == 0) {
		for (i=track; i>0;) {				/* 新規トラック */
			curptr = fdd->inf.d88.ptr[--i];
			if (curptr) {
				break;
			}
		}
		if (curptr) {						/* ヒットした */
			curptr = nexttrackptr(fdd, curptr, fdd->inf.d88.fd_size);
		}
		else {
			curptr = D88_HEADERSIZE;
		}
		nextptr = curptr;
	}
	else {									/* トラックデータは既にある */
		nextptr = nexttrackptr(fdd, curptr, fdd->inf.d88.fd_size);
	}
	cursize = nextptr - curptr;
	if (size > cursize) {
		addsize = size - cursize;
		fileappend(fh, curptr, addsize);
		fdd->inf.d88.fd_size += addsize;
		for (i=0; i<D88_TRACKMAX; i++) {
			cur = fdd->inf.d88.ptr[i];
			if ((cur) && (cur >= curptr)) {
				fdd->inf.d88.ptr[i] = cur + addsize;
			}
		}
	}
	STOREINTELDWORD(fdd->inf.d88.head.fd_size, fdd->inf.d88.fd_size);
	fdd->inf.d88.ptr[track] = curptr;
	for (i=0; i<D88_TRACKMAX; i++) {
		STOREINTELDWORD(ptr[i], fdd->inf.d88.ptr[i]);
	}
	file_seek(fh, 0, FSEEK_SET);
	file_write(fh, &fdd->inf.d88.head, sizeof(fdd->inf.d88.head));
	file_write(fh, ptr, sizeof(ptr));
	file_seek(fh, curptr, FSEEK_SET);
	file_write(fh, buf, size);
	file_close(fh);
	return(SUCCESS);
}


/* ---- */

static REG8 fddd88_seek(FDDFILE fdd, REG8 media, UINT track) {

	if (trackseek(fdd, media, track) != NULL) {
		return(0x00);
	}
	else {
		return(FDDSTAT_SEEKERR);
	}
}

static REG8 fddd88_read(FDDFILE fdd, REG8 media, UINT track, REG8 sc,
												UINT8 *ptr, UINT *size) {

const _D88TRK	*trk;
const _D88SEC	*sec;
	UINT		secsize;
	REG8		ret;

	TRACEOUT(("d88 read %d:%.2x", track, sc));
	trk = trackseek(fdd, media, track);
	if (trk == NULL) {
		goto fd8r_err;
	}
	sec = sectorseek(trk, sc);
	if (sec == NULL) {
		goto fd8r_err;
	}
	ret = 0x00;
	if (sec->del_flg) {
		ret |= FDDSTAT_RECTYPE;
	}
	if (sec->stat) {
		ret |= FDDSTAT_CRCERR;
	}
	secsize = LOADINTELWORD(sec->size);
	secsize = min(secsize, *size);
	if ((ptr) && (secsize)) {
		CopyMemory(ptr, sec + 1, secsize);
	}
	*size = secsize;
	return(ret);

fd8r_err:
	return(FDDSTAT_RECNFND);
}

static REG8 fddd88_write(FDDFILE fdd, REG8 media, UINT track, REG8 sc,
												const UINT8 *ptr, UINT size) {

	D88TRK	trk;
	D88SEC	sec;
	UINT	secsize;

	TRACEOUT(("d88 write %d:%.2x", track, sc));
	trk = trackseek(fdd, media, track);
	if (trk == NULL) {
		goto fd8w_err;
	}
	sec = sectorseek(trk, sc);
	if (sec == NULL) {
		goto fd8w_err;
	}
	secsize = LOADINTELWORD(sec->size);
	size = min(size, secsize);
	if (size) {
		CopyMemory(sec + 1, ptr, size);
		trk->write = TRUE;
	}
	return(0x00);

fd8w_err:
	return(FDDSTAT_RECNFND | FDDSTAT_WRITEFAULT);
}

static REG8 fddd88_wrtrk(FDDFILE fdd, REG8 media, UINT track, REG8 sc,
												const UINT8 *ptr, UINT size) {

	UINT	pos;
	UINT	i;
	UINT	datsize;
	D88SEC	dst;

	trackflush(&d88trk);

	/* データ作る */
	ZeroMemory(d88trk.buf, sizeof(d88trk.buf));
	pos = 0;
	for (i=0; i<sc; i++) {
		dst = (D88SEC)(d88trk.buf + pos);
		datsize = LOADINTELWORD(((TAOSEC *)ptr)->size);
		pos += sizeof(_D88SEC) + datsize;
		if (pos > D88BUFSIZE) {
			goto fd8wt_err;
		}
		dst->c = ((TAOSEC *)ptr)->c;
		dst->h = ((TAOSEC *)ptr)->h;
		dst->r = ((TAOSEC *)ptr)->r;
		dst->n = ((TAOSEC *)ptr)->n;
		dst->sectors[0] = sc;
		STOREINTELWORD(dst->size, datsize);
		CopyMemory((dst + 1), ptr + sizeof(TAOSEC), datsize);
		ptr += sizeof(TAOSEC) + datsize;
	}
	if (writetrack(fdd, media, track, d88trk.buf, pos) != SUCCESS) {
		goto fd8wt_err;
	}
	return(0);

fd8wt_err:
	return(FDDSTAT_RECNFND | FDDSTAT_WRITEFAULT);
}

static REG8 fddd88_crc(FDDFILE fdd, REG8 media, UINT track, UINT num,
												UINT8 *ptr) {

const _D88TRK	*trk;
const _D88SEC	*sec;
	UINT		sectors;
	UINT		size;

	trk = trackseek(fdd, media, track);
	if (trk == NULL) {
		return(FDDSTAT_RECNFND);
	}
	sec = (D88SEC)trk->buf;
	sectors = trk->sectors;
	if (num >= sectors) {
		return(FDDSTAT_RECNFND);
	}
	while(num) {
		num--;
		size = LOADINTELWORD(sec->size);
		size += sizeof(_D88SEC);
		sec = (D88SEC)(((UINT8 *)sec) + size);
	}
	ptr[0] = sec->c;
	ptr[1] = sec->h;
	ptr[2] = sec->r;
	ptr[3] = sec->n;
	ptr[4] = 0;
	ptr[5] = 0;
#if 0
	fdc.s.rreg = sec->c; 							/* メルヘンヴェール */
#endif	/* 0 */
	if (sec->stat) {
		return(FDDSTAT_CRCERR);
	}
	return(0x00);
}

#if defined(SUPPORT_DISKEXT)
static UINT32 fddd88_sec(FDDFILE fdd, REG8 media, UINT track, REG8 sc) {

const _D88TRK	*trk;
const _D88SEC	*sec;
	UINT		sectors;
	UINT		num;
	UINT		size;

	trk = trackseek(fdd, media, track);
	if (trk == NULL) {
		return(0);
	}
	sec = (D88SEC)trk->buf;
	sectors = trk->sectors;
	num = 0;
	while(num < sectors) {
		if (sec->r == sc) {
			break;
		}
		size = LOADINTELWORD(sec->size);
		size += sizeof(_D88SEC);
		sec = (D88SEC)(((UINT8 *)sec) + size);
		num++;
	}
	return((UINT32)(sectors << 16) + num);
}
#endif


/* ---- */

BRESULT fddd88_set(FDDFILE fdd, const OEMCHAR *fname) {

	short	attr;
	FILEH	fh;
	BRESULT	r;
	UINT8	ptr[D88_TRACKMAX][4];
	UINT	i;

	attr = file_attr(fname);
	if (attr & 0x18) {
		goto fdst_err;
	}
	fh = file_open_rb(fname);
	if (fh == FILEH_INVALID) {
		goto fdst_err;
	}
	r = (file_read(fh, &fdd->inf.d88.head, sizeof(fdd->inf.d88.head))
											!= sizeof(fdd->inf.d88.head)) ||
		(file_read(fh, ptr, sizeof(ptr)) != sizeof(ptr));
	file_close(fh);
	if (r) {
		goto fdst_err;
	}
	fdd->inf.d88.fd_size = LOADINTELDWORD(fdd->inf.d88.head.fd_size);
	for (i=0; i<D88_TRACKMAX; i++) {
		fdd->inf.d88.ptr[i] = LOADINTELDWORD(ptr[i]);
	}
	if (fdd->inf.d88.head.protect & 0x10) {
		attr |= 1;
	}
	fdd->type = DISKTYPE_D88;
	fdd->protect = (UINT8)(attr & 1);
	fdd->seek = fddd88_seek;
	fdd->read = fddd88_read;
	fdd->write = fddd88_write;
	fdd->wrtrk = fddd88_wrtrk;
	fdd->crc = fddd88_crc;
#if defined(SUPPORT_DISKEXT)
	fdd->sec = fddd88_sec;
#endif
	return(SUCCESS);

fdst_err:
	return(FAILURE);
}

void fddd88_eject(FDDFILE fdd) {

	drvflush(fdd);
}


RetroPC.NET-CVS <cvs@retropc.net>