home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Fish 1
/
GoldFishApril1994_CD2.img
/
d4xx
/
d447
/
dfc
/
disktask.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-02-02
|
9KB
|
345 lines
#include "DFC5.h"
extern struct MsgPort *TaskPort[6], *MainPort, *TPort;
extern struct IMsg IMsg[6];
static char *TaskBuffer[5]; /* local buffers (for doing I/O) */
static char *Buffer[80]; /* pointers to the 80 buffer chunks */
static long CheckSum[80]; /* checksums of the internal RAM buffer */
struct IOStdReq *IOStdReq[4]; /* our I/O request blocks */
/*
* This routine attempts to allocate 80 buffers. Return 0 on failure, otherwise
* the denominator of the fraction of a disk allocated (1=entire disk, 2=half
* disk, etc. upto 4). Note than when 3 is returned, actually 80/3+1 tracks
* were allocated.
*/
int AllocBuffers(void) {
register int i;
for (i=0; i<80; i++)
if ((Buffer[i]=AllocMem((long)TRACKSIZE, MEMF_PUBLIC))==NULL) {
if (i>=40) {
FreeBuffers(40);
return(2);
}
else if (i>=27) {
FreeBuffers(27);
return(3);
}
else if (i>=20) {
FreeBuffers(20);
return(4);
}
else {
FreeBuffers(0);
return(0);
}
}
return(1);
}
/*
* And this routine lets them go from a defined index.
*/
void FreeBuffers(int i) {
while(i<80) {
if (Buffer[i]) {
FreeMem(Buffer[i], TRACKSIZE);
Buffer[i] = NULL;
}
i++;
}
}
/*
* We attempt to create an I/O request. We allocate memory for it and
* for its port.
*/
struct IOStdReq *CreateIOStdReq(void) {
register struct IOStdReq *IOStdReq;
if (!(IOStdReq = AllocMem(sizeof(struct IOStdReq), MEMF_CLEAR | MEMF_PUBLIC))) return (NULL);
IOStdReq->io_Message.mn_Node.ln_Type = NT_MESSAGE;
IOStdReq->io_Message.mn_Length = sizeof(struct IOStdReq)-sizeof(struct Message);
if ((IOStdReq->io_Message.mn_ReplyPort = CreatePort(NULL,0))==NULL) {
FreeMem(IOStdReq, sizeof(struct IOStdReq));
return(NULL);
}
return(IOStdReq);
}
/*
* This routine frees an I/O request.
*/
void DeleteIOStdReq(struct IOStdReq *IOStdReq) {
DeletePort(IOStdReq->io_Message.mn_ReplyPort);
FreeMem(IOStdReq, sizeof(struct IOStdReq));
}
/*
* This routine recalculates the checksum for a block, and updates it in
* word 5. The sum of all the words in a block must be 0.
*/
void ReCheck(long *w) {
register int i;
register long CheckSum;
CheckSum = 0;
for (i=0; i<128; i++)
CheckSum += w[i];
w[5] -= CheckSum;
}
/*
* This routine checksums a track of the internal RAM buffer.
*/
long Check(long *Track) {
register int i;
register long CheckSum = 0;
for (i=0; i<(TRACKSIZE/sizeof(long)); i++) CheckSum += Track[i];
return(CheckSum);
}
/*
* We simply DateStamp the creation date, modification date, and
* rechecksum the block. A random factor is added because of multiple
* async accesses.
*/
void UpdateRootBlock(char *b) {
static unsigned char Rand;
Rand += 7;
DateStamp((void *)(b + 420));
DateStamp((void *)(b + 484));
((struct DateStamp *)(b + 420))->ds_Tick = (((struct DateStamp *)(b + 420))->ds_Tick+Rand)%3000;
((struct DateStamp *)(b + 484))->ds_Tick = (((struct DateStamp *)(b + 484))->ds_Tick+Rand)%3000;
ReCheck((void *)b);
}
/*
* This routine creates data for the format option. Note the clever
* way the data is built up; this routine should build a disk exactly
* the same way the standard AmigaDOS format does. If we are on track
* 40, some additional work must be done to create a root block and
* bitmap, but it's not too bad. I don't know if this is the right
* way to do under FFS, but since it works . . .
*/
void MakeFormatData(int Track, char *b, int UseFFS) {
register long *p;
register long cs;
register long i;
register unsigned char *q;
p = (long *)b;
cs = (((ULONG)('D') << 24) | ((ULONG)('O') << 16) | ((ULONG)('S') << 8) | (UseFFS ? '\1' : '\0')) + (((long)Track & 48) << 16);
for (i=0; i<TRACKSIZE/4; i++)
*p++ = cs + (i & 3327);
if (Track != 40)
return;
p = (long *)b;
for (i=0; i<256; i++)
*p++ = 0;
p = (long *)b;
p[0] = 2;
p[3] = 0x48;
p[78] = 1;
p[79] = 0x371;
q = (unsigned char *)(p + 108);
strcpy(q+1, "Empty");
*q = strlen(q+1);
p[127] = 1;
p += 128;
for (i=1; i<55; i++)
p[i] = 0xffffffff;
p[0] = 0xc000c037;
p[28] = 0xffff3fff;
p[55] = 0x3fffffff;
}
/*
* This routine moves the data to write in the suitable buffer. Track is
* useful only in Unit==4---in this case we write directly in the RAM buffer.
*/
void CopyBuffer(void *p, int Unit, int Track) {
if (Unit<4) fcpy(p, TaskBuffer[Unit]);
else if (Track>=0) {
fcpy(p, Buffer[Track]);
CheckSum[Track] = Check((long *)Buffer[Track]);
}
}
/*
* Now we try to allocate a disk. First, we attempt to allocate an
* I/O request, and then we actually open the device. If either of
* these fail, we return 0. This can occur if a drive is opened that
* doesn't exist.
*/
int OpenDisk(int Unit) {
register struct IOStdReq **p = &IOStdReq[Unit];
if (*p) return(1);
if ((*p = CreateIOStdReq()) && OpenDevice(TD_NAME, Unit, (void *)*p, 0) == 0) return(1);
else {
if (*p) {
DeleteIOStdReq(*p);
*p = NULL;
}
return(0);
}
}
/*
* Here we release a disk. We check that we have it first! Then, we
* close the device, kill the I/O request, and exit.
*/
void CloseDisk(int Unit) {
register struct IOStdReq **p = &IOStdReq[Unit];
if (*p) {
CloseDevice((void *)*p);
DeleteIOStdReq(*p);
*p = NULL;
}
}
/*
* Here we do our main track I/O with IOStdReq. The routine returns a parsed error field.
* Notice that the I/O is sync (much simpler), but the overall design of the program
* makes it automagically async-like.
*/
int DoTDIO(int Unit, int Track, void *Buffer, int Command, int Size) {
if (Unit>3) return(0);
IOStdReq[Unit]->io_Length = Size;
IOStdReq[Unit]->io_Data = Buffer;
IOStdReq[Unit]->io_Command = Command;
IOStdReq[Unit]->io_Offset = Track * (long)TRACKSIZE;
DoIO((void *)IOStdReq[Unit]);
if (IOStdReq[Unit]->io_Error == TDERR_DiskChanged) return(NO_DISK);
else if (IOStdReq[Unit]->io_Error == TDERR_WriteProt) return(WRITE_PROTECTED);
else if (IOStdReq[Unit]->io_Error) return(GENERIC_ERROR);
else return(0);
}
/*
* This code is executed by (max) *FIVE* tasks at the same time. It manages a disk
* (which is deduced from the UserData of the task structure) using a message passing
* interface. If the unit number is 4, it manages the internal 80 tracks buffer.
* This code is executed at priority 1.
*/
__saveds void DiskTask(void) {
void *VerifyBuffer;
int AllocFlag, Passes;
register struct IMsg *Message;
register int Unit = (int)FindTask(NULL)->tc_UserData;
register int n;
AllocFlag = ((TaskPort[Unit] = CreatePort(NULL, 0)) != NULL);
if (Unit<4) {
AllocFlag &= OpenDisk(Unit);
AllocFlag &= ((VerifyBuffer = AllocMem(TRACKSIZE, MEMF_CHIP))!=NULL);
AllocFlag &= ((TaskBuffer[Unit] = AllocMem(TRACKSIZE, MEMF_CHIP))!=NULL);
}
else AllocFlag &= ((Passes = IMsg[Unit].im_n = AllocBuffers()) != 0);
IMsg[Unit].im_RC = AllocFlag;
if (!AllocFlag) goto GameOver;
PutMsg(TPort, (struct Message *)&IMsg[Unit]);
SetTaskPri(FindTask(NULL), 1);
FOREVER {
WaitPort(TaskPort[Unit]);
while(Message = (void *)GetMsg(TaskPort[Unit])) {
Message->im_RC = 0;
n = Message->im_n;
if (Unit == 4) n = n % (80/Passes+(Passes==3));
switch(Message->im_Action) {
case INIT: if (n<0 && Unit<4) {
if (!DoTDIO(Unit, 0, VerifyBuffer, CMD_READ, 512) && (*((unsigned long *)VerifyBuffer) != (((ULONG)('D') << 24) | ((ULONG)('O') << 16) | ((ULONG)('S') << 8) | '\0') && *((unsigned long *)VerifyBuffer) != (((ULONG)('D') << 24) | ((ULONG)('O') << 16) | ((ULONG)('S') << 8) | '\1')))
Message->im_RC = NOT_DOS;
n = 79;
}
DoTDIO(Unit, n, 0, TD_SEEK, TRACKSIZE);
break;
case STOP_MOTOR: DoTDIO(Unit, 0, 0, TD_MOTOR, 0);
break;
case READ_TRACK : if (Unit<4) {
if ((Message->im_RC = DoTDIO(Unit, n, TaskBuffer[Unit], CMD_READ, TRACKSIZE)) == GENERIC_ERROR)
Message->im_RC = READ_ERROR;
Message->im_p = TaskBuffer[Unit];
}
else {
if (CheckSum[n] != Check((long *)Buffer[n])) Message->im_RC = READ_ERROR;
Message->im_p = Buffer[n];
}
break;
case WRITE_TRACK :
case WRITE_AND_VERIFY_TRACK:
if (Unit<4) {
if ((Message->im_RC = DoTDIO(Unit, n, TaskBuffer[Unit], TD_FORMAT, TRACKSIZE)) == GENERIC_ERROR)
Message->im_RC = WRITE_ERROR;
if (Message->im_Action == WRITE_TRACK || Message->im_RC) break;
DoTDIO(Unit, n, VerifyBuffer, CMD_READ, TRACKSIZE);
Message->im_RC = (fcmp(TaskBuffer[Unit], VerifyBuffer) ? VERIFY_ERROR : 0);
}
break;
case EXIT: goto GameOver;
}
ReplyMsg((void *)Message);
}
}
GameOver:
SetTaskPri(FindTask(NULL), 127);
if (TaskPort[Unit]) {
DeletePort(TaskPort[Unit]);
TaskPort[Unit] = NULL;
}
if (Unit<4) {
if (VerifyBuffer) FreeMem(VerifyBuffer, TRACKSIZE);
if (TaskBuffer[Unit]) FreeMem(TaskBuffer[Unit], TRACKSIZE);
TaskBuffer[Unit] = NULL;
CloseDisk(Unit);
}
else FreeBuffers(0);
PutMsg(TPort, (struct Message *)&IMsg[Unit]);
return;
}