/* cdromemu.c: * * Emulates trackdisk.device commands CMD_READ and TD_CHANGESTATE. * * Based on the example_device program by SAS. */ #define _USEOLDEXEC_ 1 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cdromemu.h" #ifdef DEBUG #define BUG(x) x #define EMIT(x) output?Write (output, x, strlen (x)):0 #else #define BUG(x) /* ignore */ #endif struct MsgPort *myPort; extern struct ExecBase *SysBase; struct IntuitionBase* IntuitionBase; struct START_MSG { struct Message msg; long devbase; }; static char* version = "$VER: " VERSION "\n"; void cmd_handler(void) { struct IORequest *ior; struct IOExtTD *iotd; long input; struct Process *proc; struct START_MSG *msg; char filename[80]; static struct EasyStruct easy = { sizeof (struct EasyStruct), 0, "cdromemu error", NULL, "Abort" }; short ok = 1; short inserted; long res; ULONG changenum = 0; BUG(long output;) BUG(static char buf[100];) LONG position; proc = (struct Process *)FindTask((char *)NULL); /* get the startup message */ while((msg = (struct START_MSG *)GetMsg(&proc->pr_MsgPort)) == NULL) WaitPort(&proc->pr_MsgPort); /* builtin compiler functions to set A4 to the global */ /* data area */ putreg(REG_A6, msg->devbase); geta4(); myPort = CreatePort("CDROMEMU",0); ReplyMsg((struct Message *)msg); if (myPort == NULL) return; IntuitionBase = (struct IntuitionBase *) OpenLibrary ("intuition.library", 0); if (GetVar ("CDROM_FILE", filename, 79, 0) < 0) { easy.es_TextFormat = "Environment variable CDROM_FILE not defined."; if (IntuitionBase) EasyRequest (NULL, &easy, NULL, NULL); ok = 0; } if (ok) { input = Open(filename, MODE_OLDFILE); inserted = (input != NULL); position = 0; } BUG(output = Open("CON:0/0/640/100/CDROMEMU", MODE_NEWFILE);) while (1) { WaitPort(myPort); while (ior = (struct IORequest *)GetMsg(myPort)) { short reply = 1; switch(ior->io_Command) { case CMD_TERM: BUG(EMIT("CMD_TERM\n");) BUG(if(output)Close(output);) if (ok && inserted) Close(input); Forbid(); ReplyMsg(&ior->io_Message); return; case CMD_XXX_REMOVE: BUG(EMIT("REMOVE\n");) reply = 0; if (ok && inserted) { Close(input); inserted = 0; changenum++; } break; case CMD_XXX_INSERT: BUG(EMIT("INSERT\n");) reply = 0; if (ok && !inserted) { input = Open(filename, MODE_OLDFILE); if (input) { inserted = 1; changenum++; position = 0; } } break; case TD_CHANGESTATE: { struct IOExtTD *iotd = (struct IOExtTD*) ior; iotd->iotd_Req.io_Actual = !inserted; #ifdef DEBUG EMIT ("TD_CHANGESTATE ==> "); if (inserted) EMIT ("inserted\n"); else EMIT ("removed\n"); #endif break; } case TD_CHANGENUM: { struct IOExtTD *iotd = (struct IOExtTD*) ior; iotd->iotd_Req.io_Actual = changenum; #ifdef DEBUG sprintf (buf, "TD_CHANGENUM ==> %lu\n", changenum); EMIT (buf); #endif break; } case CMD_READ: iotd = (struct IOExtTD *)ior; if (ok && inserted) { if (position != iotd->iotd_Req.io_Offset) { res = Seek (input, iotd->iotd_Req.io_Offset - position, OFFSET_CURRENT); if (res < 0) { iotd->iotd_Req.io_Error = 1; BUG(EMIT("CMD_READ: Seek error\n");) break; } position = iotd->iotd_Req.io_Offset; } iotd->iotd_Req.io_Actual = Read(input, iotd->iotd_Req.io_Data, iotd->iotd_Req.io_Length); position += iotd->iotd_Req.io_Actual; } else iotd->iotd_Req.io_Actual = 0; #ifdef DEBUG sprintf (buf, "CMD_READ offset=%lu length=%lu\n actual=%lu\n", iotd->iotd_Req.io_Offset, iotd->iotd_Req.io_Length, iotd->iotd_Req.io_Actual); EMIT(buf); #endif break; } if (reply) ReplyMsg(&ior->io_Message); } } } int __saveds __asm __UserDevInit(register __d0 long unit, register __a0 struct IORequest *ior, register __a6 struct MyLibrary *libbase) { struct Process *myProc; struct START_MSG msg; if (SysBase->LibNode.lib_Version < 36) return 1; /* can only run under 2.0 or greater */ myProc = CreateNewProcTags(NP_Entry, cmd_handler, NP_StackSize, 4096, NP_Name, "CMD_Handler", TAG_DONE); if (myProc == NULL) return 1; /* Send the startup message with the library base pointer */ msg.msg.mn_Length = sizeof(struct START_MSG) - sizeof (struct Message); msg.msg.mn_ReplyPort = CreatePort(0,0); msg.msg.mn_Node.ln_Type = NT_MESSAGE; msg.devbase = getreg(REG_A6); PutMsg(&myProc->pr_MsgPort, (struct Message *)&msg); WaitPort(msg.msg.mn_ReplyPort); if (myPort == NULL) /* CMD_Handler allocates this */ return NULL; DeletePort(msg.msg.mn_ReplyPort); return 0; } void __saveds __asm __UserDevCleanup(register __a0 struct IORequest *ior, register __a6 struct MyLibrary *libbase) { struct IORequest newior; /* send a message to the child process to shut down. */ newior.io_Message.mn_ReplyPort = CreateMsgPort(); newior.io_Command = CMD_TERM; newior.io_Unit = ior->io_Unit; PutMsg(myPort, &newior.io_Message); WaitPort(newior.io_Message.mn_ReplyPort); DeleteMsgPort(newior.io_Message.mn_ReplyPort); DeletePort(myPort); } void __saveds __asm DevBeginIO(register __a1 struct IORequest *ior) { ior->io_Error = 0; ior->io_Flags &= ~IOF_QUICK; switch(ior->io_Command) { case CMD_READ: case CMD_XXX_REMOVE: case CMD_XXX_INSERT: case TD_CHANGESTATE: case TD_CHANGENUM: PutMsg(myPort, &ior->io_Message); break; default: ior->io_Error = IOERR_NOCMD; ReplyMsg(&ior->io_Message); break; } } void __saveds __asm DevAbortIO(register __a1 struct IORequest *ior) { }