/*
	FS1541

	main.c

	The handler entry point.

*/

#include <string.h>

#include <exec/types.h>
#include <exec/execbase.h>
#include <dos/dos.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.2 (16.3.97)";

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

struct Task *ourtask;
struct MsgPort *ourport;

struct FileSysStartupMsg *fssm;

static UBYTE diskinfo_image[] = {
0xE3,0x10,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x3D,0x00,0x37,0x00,0x2A,
0x00,0x04,0x00,0x01,0x00,0x01,0x07,0x57,0x3F,0xD0,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x01,0x10,0x07,0x57,0x66,0xA0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,
0x00,0x3D,0x07,0x5B,0xCB,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x49,
0x00,0x30,0x01,0x64,0x00,0xB7,0xFF,0xFF,0x00,0x00,0x00,0x00,0x02,0x00,0x12,0x7F,
0x07,0x5B,0xCB,0x66,0x00,0x00,0x00,0x00,0x07,0x57,0x66,0xBC,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x5A,0x00,0x45,0xFF,0xFF,0xFF,0xFF,0x00,0x01,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x00,0x29,0x00,0x02,
0x00,0x03,0x3A,0xD0,0x03,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFE,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x00,0xFF,0xFF,0xC0,0x00,0x00,0x00,
0x1E,0x00,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x1E,0x00,0xFF,0xFF,0xC0,0xF8,0x0B,0xAA,
0x1E,0x00,0xFF,0xFF,0xC1,0xFB,0xCA,0x2A,0x1E,0x00,0xFF,0xFF,0xC1,0x83,0x8A,0x2A,
0x1E,0x00,0xFF,0xFF,0xC1,0x80,0x0B,0x1A,0x1E,0x00,0xFF,0xFF,0xC1,0x83,0x88,0x8A,
0x1E,0x00,0x3F,0xFF,0xC1,0xFB,0xCA,0x8A,0x18,0x00,0x3F,0xFF,0xC0,0xF8,0x0B,0x8A,
0x18,0x00,0x3F,0xFF,0xC0,0x00,0x00,0x00,0x18,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFE,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFE,0x00,0xFF,0xFF,0xFF,0x87,0xFF,0xFF,0xFE,0x00,0xFF,0xFF,0xFE,0x01,0xFF,0xFF,
0xFE,0x00,0xFF,0xFF,0xFC,0x00,0xFF,0xFF,0xFE,0x00,0xFF,0xFF,0xF8,0x00,0x7F,0xFF,
0xFE,0x00,0xFF,0xFF,0xF8,0x00,0x7F,0xFF,0xFE,0x00,0xFF,0xFF,0xF8,0x00,0x7F,0xFF,
0xFE,0x00,0xFF,0xFF,0xFC,0x00,0x7F,0xFF,0xFE,0x00,0xFF,0xFF,0xFE,0x01,0xFF,0xFF,
0xFE,0x00,0xFF,0xFF,0xFF,0x87,0xFF,0xFF,0xFE,0x00,0xFF,0xFF,0xFF,0xFF,0xEF,0xFF,
0xFE,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFE,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFE,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFE,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFE,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFE,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFE,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFE,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFE,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x80,0x00,0x3F,0xFF,0xFF,0xFF,0xE0,0x00,0x80,0x00,0x3F,0xFF,0xFF,0xFF,
0xE0,0x00,0x80,0x00,0x3F,0x07,0xF4,0x55,0xE0,0x00,0x80,0x00,0x3E,0x04,0x35,0xD5,
0xE0,0x00,0x80,0x00,0x3E,0x7C,0x75,0xD5,0xE0,0x00,0x80,0x00,0x3E,0x7F,0xF4,0xE5,
0xE0,0x00,0x80,0x00,0x3E,0x7C,0x77,0x75,0xE0,0x00,0x20,0x00,0x3E,0x04,0x35,0x75,
0xE0,0x00,0x20,0x00,0x3F,0x07,0xF4,0x75,0xE0,0x00,0x20,0x00,0x3F,0xFF,0xFF,0xFF,
0xE0,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x04,0x00,0x00,
0x00,0x00,0x80,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,
0x00,0x00,0x80,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x40,0x00,
0x00,0x00,0x80,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x80,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x04,0x20,0x00,
0x00,0x00,0x80,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x20,0x00,
0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x28,0x00,0x00,
0x00,0x00,0x80,0x00,0x00,0x54,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x28,0x00,0x00,
0x00,0x00,0x80,0x00,0x00,0x54,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x28,0x00,0x00,
0x00,0x00,0x80,0x00,0x00,0x54,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x28,0x00,0x00,
0x00,0x00,0x80,0x00,0x00,0x54,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x28,0x00,0x00,
0x00,0x00,0x80,0x00,0x00,0x54,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x28,0x00,0x00,
0x00,0x00,0x80,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x53,0x59,
0x53,0x3A,0x53,0x79,0x73,0x74,0x65,0x6D,0x2F,0x44,0x69,0x73,0x6B,0x43,0x6F,0x70,
0x79,0x00,0x00,0x00,0x00,0x02,0x00,0x02
};  

UBYTE *diskiconimg = diskinfo_image;
int diskiconlength = sizeof(diskinfo_image);

static ULONG argarray[6] = { 0, 0, 0, 0, 0, 0 };

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

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,"
				"ICON/K";

			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, 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);
}

static void LoadDiskIcon() {
	if(argarray[5]) {
		BPTR fh;

		if((fh = Open((STRPTR)argarray[5], MODE_OLDFILE))) {
			ULONG len;
			APTR data;

			Seek(fh, 0, OFFSET_END);
			len = Seek(fh, 0, OFFSET_BEGINNING);

			if((data = AllocVec(len, MEMF_ANY))) {
				if(Read(fh, data, len) != len) {
					FreeVec(data);
					data = NULL;
				}
			}

			Close(fh);

			if(data) {
				diskiconimg = data;
				diskiconlength = len;
			}
		}		
	}
}

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((ourport = CreateMsgPort())) {
		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;
							startuppacket->dp_Arg4 = (LONG)ourport;
							ReturnPacket(startuppacket, DOSTRUE, 0);
			
							LoadDiskIcon();

							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);
		}
		DeleteMsgPort(ourport);
	}

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

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