#include "DFC5.h"

extern char *df[];

void MemCleanup(void) {
} 								/* we don't need it */

/*
 * The MainPort is used for the handshaking with our DiskTask(). TPort is a temporary
 * port we use when we have sync stuff to do, like inhibit a drive, waiting for
 * the opening/closing message of a DiskTask, etc. TPort has *NEVER* pending
 * messages.
 */

static char SeveralPassesMsg[] = "You'll need x passes.";

struct MsgPort *TaskPort[6], *MainPort, *TPort;

struct IMsg IMsg[6] = {
	{	{	{	NULL, NULL, NT_MESSAGE, NULL, NULL	}, NULL, sizeof(struct IMsg)-sizeof(struct Message)	}, NULL, 0	},
	{	{	{	NULL, NULL, NT_MESSAGE, NULL, NULL	}, NULL, sizeof(struct IMsg)-sizeof(struct Message)	}, NULL, 1	},
	{	{	{	NULL, NULL, NT_MESSAGE, NULL, NULL	}, NULL, sizeof(struct IMsg)-sizeof(struct Message)	}, NULL, 2	},
	{	{	{	NULL, NULL, NT_MESSAGE, NULL, NULL	}, NULL, sizeof(struct IMsg)-sizeof(struct Message)	}, NULL, 3	},
	{	{	{	NULL, NULL, NT_MESSAGE, NULL, NULL	}, NULL, sizeof(struct IMsg)-sizeof(struct Message)	}, NULL, 4	},
	{	{	{	NULL, NULL, NT_MESSAGE, NULL, NULL	}, NULL, sizeof(struct IMsg)-sizeof(struct Message)	}, NULL, 5	}
};


char *Stack[5];

char NullName[1] = ""; /* stuff in public lists can't have NULL as a name */
struct Task Task[5];

/*
 * This routines sets up the main port and the replyport of the internal msgs.
 * Note that the sixth TaskPort is MainPort itself---a little trick for when
 * formatting.
 */

int SetUpPorts(void) {

	register int i;

	TaskPort[5] = MainPort = CreatePort(NULL,0);
	TPort = CreatePort(NULL,0);
	for(i=0; i<6; i++) IMsg[i].im_Message.mn_ReplyPort = MainPort;
	return(MainPort && TPort);
}

/*
 * Here we close our ports.
 */

void ClosePorts(void) {

	if (MainPort) DeletePort(MainPort);
	if (TPort) DeletePort(TPort);
}

/*
 * This routine sets up the internal message for a specified Unit and sends it.
 */

void SendMsg(int Unit, int Action, int n) {

	IMsg[Unit].im_Action = Action;
	IMsg[Unit].im_n = n;
	PutMsg(TaskPort[Unit], (struct Message *)&IMsg[Unit]);
}



/*
 *	  This routine gives us those pretty little DF0:BUSY things, which keep
 *	  AmigaDOS from futzing with the drives when we are playing with them.
 *	  Uses TPort.
 */

void Inhibit(int unit, int bool) {

	register struct MsgPort *handler ;
	static struct StandardPacket packet ;

	if (unit==4) return;
	handler = (struct MsgPort *)DeviceProc(df[unit]) ;
	if (handler == NULL) return ;

	packet.sp_Msg.mn_Node.ln_Name = (char *)&(packet.sp_Pkt) ;
	packet.sp_Pkt.dp_Link = &(packet.sp_Msg) ;
	packet.sp_Pkt.dp_Port = TPort ;
	packet.sp_Pkt.dp_Type = ACTION_INHIBIT ;
	packet.sp_Pkt.dp_Arg1 = bool ;
	PutMsg(handler, (void *)&packet) ;
	while (!GetMsg(TPort)) WaitPort(TPort) ;
}

/*
 * Here we open a DiskTask. 0 on failure, non 0 if all is OK. If the disk opened
 * was the unit 4, the RAM buffer, the number of passes needed is returned.
 * Note that we remind internally the number of passes, otherwise an OpenDiskTask(4)
 * with the unit 4 already opened could return a wrong answer. We use TPort.
 */

int OpenDiskTask(int Unit) {

	static char Passes;
	struct IMsg *Message;

	if (TaskPort[Unit]) return(Unit == 4 ? Passes : 1);

	if ((Stack[Unit] = AllocMem(STACKSIZE, MEMF_PUBLIC)) == NULL) return(0);

	Task[Unit].tc_Node.ln_Pri = 127;
	Task[Unit].tc_Node.ln_Type = NT_TASK;
	Task[Unit].tc_Node.ln_Name = NullName;
	Task[Unit].tc_UserData = (APTR)Unit;

	Task[Unit].tc_SPLower=(void *)(Stack[Unit]);
	Task[Unit].tc_SPReg=Task[Unit].tc_SPUpper=(void *)(Stack[Unit]+STACKSIZE);
	Task[Unit].tc_Node.ln_Pri = 127;

	AddTask(&Task[Unit], (void *)DiskTask, NULL);

	while (!(Message = (struct IMsg*)GetMsg(TPort))) WaitPort(TPort);

	if (Message->im_RC) {
		Inhibit(Unit, TRUE);
		if (Unit == 4) {
			Passes = Message->im_n;
			if (Passes>1) {
				SeveralPassesMsg[12] = Passes+48;
				Acknowledge(SeveralPassesMsg);
			}
			return((int)Passes);
		}
		return(1);
	}
	else {
		FreeMem(Stack[Unit], STACKSIZE);
		return(0);
	}
}

/*
 * Here we close a DiskTask. We use TPort.
 */

void CloseDiskTask(int Unit) {

	if (TaskPort[Unit]) {
		IMsg[Unit].im_Action = EXIT;
		PutMsg(TaskPort[Unit], (struct Message *)&IMsg[Unit]);
		while(!GetMsg(TPort)) WaitPort(TPort);
		Inhibit(Unit, FALSE);
		FreeMem(Stack[Unit], STACKSIZE);
	}
}

