/* * FMS.C * * File Disk Device (fmsdisk.device) * * Simulates a trackdisk by using a large file to hold the 'blocks'. */ #include #include #include #include #include #include #include #include /*#define DEBUG*/ #define CMD_OPENUNIT (0x7FF0 & ~TDF_EXTCOM) #define CMD_CLOSEUNIT (0x7FF1 & ~TDF_EXTCOM) #define CMD_KILLPROC (0x7FF2 & ~TDF_EXTCOM) void SynchroMsg(); void ExtendSize(); typedef struct Library LIB; typedef struct Device DEV; typedef struct Process PROC; typedef struct MsgPort PORT; typedef struct Message MSG; typedef struct List LIST; typedef struct Node NODE; typedef long (*func_ptr)(); typedef struct { struct Unit U; UWORD OpenCnt; long Fh; /* file handle */ long Size; /* current size */ char NotSyn; char Reserved; } NDUnit; typedef struct { LIB Lib; NDUnit Unit[32]; } NDev; typedef struct { struct Message io_Message; struct Device *io_Device; /* device node pointer */ struct Unit *io_Unit; /* unit (driver private)*/ UWORD io_Command; /* device command */ UBYTE io_Flags; BYTE io_Error; /* error or warning num */ ULONG io_Actual; /* actual number of bytes transferred */ ULONG io_Length; /* requested number bytes transferred*/ APTR io_Data; /* points to data area */ ULONG io_Offset; /* offset for block structured devices */ long iotd_Count; /* (extension) */ long iotd_SecLabel; /* (extension) */ } IOB; extern char DeviceName[]; extern char IdString[]; extern void DUMmySeg(); typedef NDev *NDevP; typedef IOB *IOBP; long SysBase = NULL; NDev *DevBase = NULL; APTR DevSegment = NULL; PORT *FProc = NULL; PORT FPort; extern func_ptr DevVectors[]; __saveds NDevP __asm Init(register __a0 APTR seg) { NDev *db; SysBase = *(long *)4; DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 0); DevBase = db = (NDev *)MakeLibrary((long **)DevVectors,NULL,NULL,sizeof(NDev),NULL); db->Lib.lib_Node.ln_Type = NT_DEVICE; db->Lib.lib_Node.ln_Name = DeviceName; db->Lib.lib_Flags = LIBF_CHANGED|LIBF_SUMUSED; db->Lib.lib_Version = 1; db->Lib.lib_IdString= (APTR)IdString; DevSegment = seg; AddDevice((DEV *)db); return(db); } __saveds NDevP __asm DevOpen(register __d0 long unitnum, register __a1 IOBP iob, register __d1 long flags ) { NDev *nd = DevBase; NDUnit *unit = &nd->Unit[unitnum]; if (++nd->Lib.lib_OpenCnt == 1) { FProc = CreateProc("FMS-Dummy", 0, (long)DUMmySeg >> 2, 4096); FPort.mp_SigBit = SIGBREAKB_CTRL_D; /* port init */ FPort.mp_SigTask= FProc->mp_SigTask; FPort.mp_Flags = PA_SIGNAL; NewList(&FPort.mp_MsgList); } if (++unit->OpenCnt == 1) SynchroMsg(CMD_OPENUNIT, unit); nd->Lib.lib_Flags &= ~LIBF_DELEXP; iob->io_Unit = (struct Unit *)unit; iob->io_Error = 0; return(nd); } __saveds APTR DevExpunge() { NDev *nd = DevBase; if (DevSegment == NULL) Alert(24, (char *)24); if (nd->Lib.lib_OpenCnt) { nd->Lib.lib_Flags |= LIBF_DELEXP; return(NULL); } Remove((NODE *)nd); FreeMem((char *)nd - nd->Lib.lib_NegSize, nd->Lib.lib_NegSize + nd->Lib.lib_PosSize); DevSegment = NULL; return(DevSegment); } __saveds APTR __asm DevClose(register __a1 IOBP iob) { NDev *nd = DevBase; { NDUnit *unit = (NDUnit *)iob->io_Unit; if (unit->OpenCnt && --unit->OpenCnt == 0) SynchroMsg(CMD_CLOSEUNIT, unit); } if (nd->Lib.lib_OpenCnt && --nd->Lib.lib_OpenCnt) return(NULL); if (FProc) { SynchroMsg(CMD_KILLPROC, NULL); FProc = NULL; } if (nd->Lib.lib_Flags & LIBF_DELEXP) return(DevExpunge()); /* * close down resources */ return(NULL); } __saveds void __asm DevBeginIO(register __a1 IOBP iob) { /*NDev *nd = DevBase;*/ iob->io_Error = 0; iob->io_Actual = 0; switch(iob->io_Command & ~TDF_EXTCOM) { case CMD_INVALID: iob->io_Error = IOERR_NOCMD; break; case CMD_RESET: break; case CMD_READ: PutMsg(&FPort, &iob->io_Message); iob->io_Flags &= ~IOF_QUICK; /* not quick */ iob = NULL; break; case CMD_WRITE: PutMsg(&FPort, &iob->io_Message); iob->io_Flags &= ~IOF_QUICK; /* not quick */ iob = NULL; break; case CMD_UPDATE: break; case CMD_CLEAR: break; case CMD_STOP: break; case CMD_START: break; case CMD_FLUSH: break; case TD_MOTOR: /* motor, no action */ case TD_SEEK: /* seek, no action */ break; case TD_FORMAT: /* format */ PutMsg(&FPort, &iob->io_Message); iob->io_Flags &= ~IOF_QUICK; /* not quick */ iob = NULL; break; case TD_REMOVE: /* not supported */ iob->io_Error = IOERR_NOCMD; break; case TD_CHANGENUM: /* change count never changes */ iob->io_Actual = 1; break; case TD_CHANGESTATE: /* 0=disk in drive */ iob->io_Actual = 0; break; case TD_PROTSTATUS: /* io_Actual -> 0 (rw) */ iob->io_Actual = 0; break; case TD_RAWREAD: /* not supported */ case TD_RAWWRITE: iob->io_Error = IOERR_NOCMD; break; case TD_GETDRIVETYPE: /* drive type? */ iob->io_Actual = 0; break; case TD_GETNUMTRACKS: iob->io_Actual = 0; /* # of tracks? */ break; case TD_ADDCHANGEINT: /* action never taken */ case TD_REMCHANGEINT: break; default: iob->io_Error = IOERR_NOCMD; break; } if (iob) { if ((iob->io_Flags & IOF_QUICK) == 0) ReplyMsg((MSG *)iob); } } __saveds void __asm DevAbortIO(register __a1 IOBP iob) { /*NDev *nd = DevBase;*/ } func_ptr DevVectors[] = { (func_ptr)DevOpen, (func_ptr)DevClose, (func_ptr)DevExpunge, NULL, (func_ptr)DevBeginIO, (func_ptr)DevAbortIO, (func_ptr)-1 }; /* * Server communications */ void SynchroMsg(cmd, unit) UWORD cmd; struct Unit *unit; { IOB Iob; Iob.io_Message.mn_ReplyPort = CreatePort(NULL, 0); Iob.io_Command = cmd; Iob.io_Unit = unit; PutMsg(&FPort, &Iob.io_Message); WaitPort(Iob.io_Message.mn_ReplyPort); DeletePort(Iob.io_Message.mn_ReplyPort); } /* * SERVER SIDE (IS A PROCESS) * * File name is: */ __saveds void CoProc() { IOBP iob; NDUnit *unit; char buf[128]; char notdone = 1; #ifdef DEBUG long fh = Open("con:0/0/320/100/Debug", 1006); #endif Wait(SIGBREAKF_CTRL_D); /* wait for port init */ while (notdone) { WaitPort(&FPort); while (iob = (IOBP)GetMsg(&FPort)) { unit = (NDUnit *)iob->io_Unit; #ifdef DEBUG sprintf(buf, "Cmd %08lx/%04x @ %08lx Buf %08lx %04x\n", unit, iob->io_Command, iob->io_Offset, iob->io_Data, iob->io_Length ); Write(fh, buf, strlen(buf)); #endif switch(iob->io_Command & ~TDF_EXTCOM) { case CMD_OPENUNIT: sprintf(buf, "FMS:Unit%d", unit - &DevBase->Unit[0]); unit->Fh = Open(buf, 1005); if (unit->Fh == NULL) { unit->Fh = Open(buf, 1006); unit->NotSyn = 1; } if (unit->Fh) { Seek(unit->Fh, 0L, 1); unit->Size = Seek(unit->Fh, 0L, -1); } break; case CMD_CLOSEUNIT: if (unit->Fh) { Close(unit->Fh); unit->Fh = NULL; } break; case CMD_KILLPROC: notdone = 0; break; case CMD_READ: if (unit->Fh == NULL) break; if (iob->io_Offset + iob->io_Length > unit->Size) ExtendSize(unit, iob->io_Offset + iob->io_Length); Seek(unit->Fh, iob->io_Offset, -1); iob->io_Actual = Read(unit->Fh, (char *)iob->io_Data, iob->io_Length); break; case CMD_WRITE: /* * This causes file to be closed/reopened after * formatting. */ if (unit->NotSyn && unit->Fh) { Close(unit->Fh); sprintf(buf, "FMS:Unit%d", unit - &DevBase->Unit[0]); unit->Fh = Open(buf, 1005); unit->NotSyn = 0; } /* fall through */ case TD_FORMAT: if (unit->Fh == NULL) break; if (iob->io_Offset > unit->Size) ExtendSize(unit, iob->io_Offset); Seek(unit->Fh, iob->io_Offset, -1); iob->io_Actual = Write(unit->Fh, (char *)iob->io_Data, iob->io_Length); break; } if (notdone == 0) /* forbid before falling through */ Forbid(); /* and esp before replying */ ReplyMsg(&iob->io_Message); } } /* fall through to exit */ } void ExtendSize(unit, offset) NDUnit *unit; long offset; { long pos; char *buf = AllocMem(512, MEMF_CLEAR|MEMF_PUBLIC); if (unit->NotSyn == 0) unit->NotSyn = 1; Seek(unit->Fh, 0L, 1); pos = Seek(unit->Fh, 0L, 0); while (pos < offset) { if (Write(unit->Fh, buf, 512) != 512) break; pos += 512; } FreeMem(buf, 512); }