/* KICKDATE - Copyright 1990 Joe Porkka
		FREELY DISTRIBUTABLE

	Purpose: Keeps the current date on the Kickstart disk
		 for A1000 owners with autoboot harddrives.

Version 1.0

*/


#include <exec/types.h>
#include <exec/io.h>
#include <devices/trackdisk.h>
#include <exec/memory.h>

char *buffer;

struct IOStdReq *diskreq, *CreateStdIO();
struct	MsgPort *rport=0,*CreatePort();
int dev=0, ioreqs=0, ports=0;
int limit;
int outcount=0;

DeleteStdIO(req) struct IOStdReq *req;
{
    if(req==0) {
	/* printf("Delete a null message-ignored\n"); */
    } else {
	req->io_Message.mn_Node.ln_Type=0xff;
	req->io_Device=(struct Device *)-1;
	req->io_Unit=(struct Unit *)-1;
	/* printf("Freeing a stdio\n"); */
	FreeMem(req,sizeof(struct IOStdReq));
    }
}

void
main(av,ac)
    int av;
    char **ac;
{

    int status;
    int fetchtime=0;
    if(av!=2) {
	printf("Usage: kickdate set | get | getset\n");
	printf("       set -> write date to disk. get -> get date from disk\n");
	printf("       getset -> get, then periodically write date\n");
	return;
    }
    if( stricmp(ac[1],"set")==0 ) fetchtime=0;
    if( stricmp(ac[1],"get")==0 ) fetchtime = 1;
    if( stricmp(ac[1],"getset")==0 ) fetchtime = 2;
    buffer=0;
    rport=CreatePort("disk.port",0);
    if(rport==0) {
	printf("port open failed\n");
	goto portfail;
    }
    ports=1;
    /* printf("GEE!\n"); */
    diskreq=CreateStdIO(rport);
    if(diskreq==0) {
	printf("CreateStdIO failed\n");
	goto iofail;
    }
    ioreqs=1;
    /* printf("Attempt OpenDevice\n"); */
    status=OpenDevice("trackdisk.device",0,diskreq,0);
    if(status!=0) {
	printf("Opendevice failed\n");
	goto iofail;
    }
    dev=1;

    buffer = (char *)AllocMem(512, MEMF_CHIP);
    if(buffer==0) goto memfail;
    getsector(0,0,0);
    if(!(diskreq->io_Error || diskreq->io_Actual!=512)) {
	if( ((long *)buffer)[0]=='KICK') {
	    if(fetchtime) {
		SetNewTime( ((long *)buffer)[1]);
	    } else {
		((long*)buffer)[1]=GetSysTime();
		writesector(0,0,0);
		if(diskreq->io_Error || diskreq->io_Actual!=512) {
		    fetchtime=0;
		}
	    }
	}
	if(fetchtime==2) {  /* Stay resident */
	    while(1) {
		Delay(5*60*50); /* Sleep for 5 minutes */
		/* printf("Done sleep %ld\n", SetSignal(0,0)); */
		if(SetSignal(0,0)&(1<<12)) break;  /* CTRL_C */
		getsector(0,0,0);
		/* printf("Got it!\n"); */
		if(!(diskreq->io_Error || diskreq->io_Actual!=512)) {
		    if( ((long *)buffer)[0]=='KICK') {
			((long*)buffer)[1]=GetSysTime();
			writesector(0,0,0);
			/* printf("Wrote it!\n"); */
			if(diskreq->io_Error || diskreq->io_Actual!=512) {
			    /* break; */
			}
			MotorOff();
		    }
		    MotorOff();
		} else break;
	    }
	}
    }


    MotorOff();


memfail:
    if(buffer) FreeMem(buffer, 512);
    CloseDevice(diskreq);
iofail:
    DeleteStdIO(diskreq);
portfail:
    if(rport) {
	RemPort(rport);
	FreeMem(rport,sizeof(*rport));
    }
}

CXBRK() {
    MotorOff();

    if(dev) {CloseDevice(diskreq);}
    if(ioreqs) {
	DeleteStdIO(diskreq);
    }
    if(ports) {
	if(rport) {
	    RemPort(rport);
	    FreeMem(rport,sizeof(*rport));
	}
    }
    exit(0);
}

getsector(cyl,sec,head)
    int cyl,sec,head;
{
    diskreq->io_Offset = TD_SECTOR * (sec+NUMSECS*head+NUMSECS*2*cyl);
    diskreq->io_Length=TD_SECTOR;
    diskreq->io_Data=(APTR)buffer;
    diskreq->io_Command=CMD_READ;
    diskreq->io_Flags=0;
    DoIO(diskreq);
}

writesector(cyl,sec,head)
    int cyl,sec,head;
{
    diskreq->io_Offset = TD_SECTOR * (sec+NUMSECS*head+NUMSECS*2*cyl);
    diskreq->io_Length=TD_SECTOR;
    diskreq->io_Data=(APTR)buffer;
    diskreq->io_Command=CMD_WRITE;
    diskreq->io_Flags=0;
    DoIO(diskreq);
    diskreq->io_Command=CMD_UPDATE;
    diskreq->io_Flags=0;
    DoIO(diskreq);
}

MotorOff()
{
    diskreq->io_Command=TD_MOTOR;
    diskreq->io_Length=0;
    DoIO(diskreq);
}
