/*
	FS1541

	main.c

	The handler entry point.

*/

#include <string.h>

#include <exec/types.h>
#include <exec/execbase.h>
#include <dos/dosextens.h>
#include <dos/dostags.h>
#include <dos/filehandler.h>
#include <utility/utility.h>
#include <devices/timer.h>

#include <proto/exec.h>
#include <proto/dos.h>

#include "main.h"
#include "packet.h"
#include "disk.h"
#include "volume.h"
#include "support.h"

char verstring[] = "$VER: 1541-handler 1.1 (19.2.97)";

struct ExecBase *SysBase;
struct DosLibrary *DOSBase;
struct UtilityBase *UtilityBase, *__UtilityBase;

struct Task *ourtask;
struct MsgPort *ourport;

struct FileSysStartupMsg *fssm;

static BOOL MakeFSSM(BSTR);

/*-------------------------------------------------------------------------*/

void entry(void)
{
	struct DosPacket *startuppacket;
	struct DosList *devnode;
	LONG error = ERROR_NO_FREE_STORE;

	SysBase = *(volatile APTR*)4;

	ourtask = FindTask(NULL);

	ourport = &((struct Process *)ourtask)->pr_MsgPort;
	WaitPort(ourport);
	startuppacket = GetPacket(ourport);

	devnode = (struct DosList*)BADDR(startuppacket->dp_Arg3);

	if((DOSBase = (struct DosLibrary*)OpenLibrary(DOSNAME, 37)))
	{
		if((UtilityBase = (struct UtilityBase*)OpenLibrary("utility.library",37)))
		{
			__UtilityBase = UtilityBase;

			/* I'm almost sure that using the MountList `Control' field
			   instead of `Startup' is better; well... next time ;-) */
			if(MakeFSSM(startuppacket->dp_Arg2))
			{
				devnode->dol_misc.dol_handler.dol_Startup = (BPTR)MKBADDR(fssm);

				if(!(error = InitDiskSS(&((STRPTR)BADDR(fssm->fssm_Device))[1],fssm->fssm_Unit,fssm->fssm_Flags)))
				{
					if(!(error = InitVolumeSS()))
					{
						ULONG pktsig = 1<<(ourport->mp_SigBit);
						ULONG diskchgsig = 1<<diskchgintbit;
						ULONG udssig = 1<<(UDStimer->tr_node.io_Message.mn_ReplyPort->mp_SigBit);
						ULONG mask = pktsig|diskchgsig|udssig;
		
						error = 0;
						devnode->dol_Task = ourport;
						ReturnPacket(startuppacket, DOSTRUE, 0);
		
						DoDiskInsert();
			
						for(;;)
						{
							ULONG sigs;
					
							while(!( SetSignal(0,0)&mask || LoadDisk() ));
		
							sigs = Wait(mask);
					
							if(sigs & pktsig)
								DoPackets();
							if(sigs & udssig)
								UpdateDiskStructure();
							if(sigs & diskchgsig)
							{
								if(!inhibited)
								{
									/* We do the remove for security reasons */
									DoDiskRemove();
									DoDiskInsert();
								}
							}
						}
			
						QuitVolumeSS();
					}
					QuitDiskSS();
				}
			} else error = ERROR_REQUIRED_ARG_MISSING;
			CloseLibrary((struct Library*)UtilityBase);
		}
		CloseLibrary((struct Library*)DOSBase);
	}

	if(error)
		ReturnPacket(startuppacket, DOSFALSE, error);
}

static BOOL MakeFSSM(BSTR startup)
{
	UBYTE str[258];
	STRPTR src = BADDR(startup);
	struct RDArgs *rdargs;

	if(src)
	{
		int i,len = src[0];

		/* Convert startup string */
		CopyMem(&src[1], str, len);
		str[len] = '\n';
		str[len+1] = '\0';

		for(i=0;i<len;i++)
			if(str[i] == '"') str[i] = ' ';

		if((rdargs = (struct RDArgs*)AllocDosObject(DOS_RDARGS, NULL)))
		{
			static char template[]=
				"D=DEVICE/A,"
				"U=UNIT/N/A,"
				"F=FLAGS/N,"
				"NS=NOAUTOSCAN/S"
				"I=INTERLEAVE/N";

			ULONG argarray[5];

			rdargs->RDA_Flags |= RDAF_NOPROMPT;
			rdargs->RDA_Source.CS_Buffer = str;
			rdargs->RDA_Source.CS_Length = strlen(str);
			rdargs->RDA_Source.CS_CurChr = 0;

			if(ReadArgs(template, &argarray[0], rdargs))
			{
				if((fssm = AllocVec(sizeof(struct FileSysStartupMsg), MEMF_PUBLIC)))
				{
					struct DosEnvec *env;
					STRPTR name;

					if((env = AllocVec(sizeof(struct DosEnvec), MEMF_PUBLIC|MEMF_CLEAR)))
					{
						if((name = AllocVec(strlen((STRPTR)argarray[0])+2, MEMF_PUBLIC)))
						{
							strcpy(name+1, (STRPTR)argarray[0]);
							name[0] = strlen(name+1);

							fssm->fssm_Unit = *(ULONG*)argarray[1];
							fssm->fssm_Device = (BPTR)MKBADDR(name);
							fssm->fssm_Flags = argarray[2] ? *(ULONG*)argarray[2] : 16;
							fssm->fssm_Environ = (BPTR)MKBADDR(env);

							/* These might be strange settings, but we must announce
							   the device as one single track with 683 sectors, other-
							   wise there would be some trouble with formatting etc. */
							env->de_TableSize = 19;
							env->de_SizeBlock = 256/4;
							env->de_Surfaces = 1;
							env->de_SectorPerBlock = 1;
							env->de_BlocksPerTrack = 683;
							env->de_LowCyl = 0;
							env->de_HighCyl = 0;
							env->de_DosType = ID_DOS_DISK;
							env->de_MaxTransfer = 256*683;
							env->de_Mask = 0x7ffffffe;
							env->de_NumBuffers = 683;
							env->de_Reserved = 1;

							if(argarray[3])
								autoscan = FALSE;

							if(argarray[4])
							{
								LONG i = *(ULONG*)argarray[4];
								if(i>0)
									interleave = i;
							}

							return(TRUE);
						}

						FreeVec(fssm);
					}
					FreeVec(fssm);
				}

				FreeArgs(rdargs);
			}

		    FreeDosObject(DOS_RDARGS, rdargs);
		}
	}

	return(FALSE);
}
