home *** CD-ROM | disk | FTP | other *** search
- #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;
- }
-