/*
 *		unixclock - make the amiga hardware clock behave like a UNIX clock
 *
 *		© Copyright 1995 by Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be)
 *
 *		-----------------------------------------------------------------------------
 *
 *		This file is subject to the terms and conditions of the GNU General Public
 *		License.
 */

#include <stdio.h>
#include <dos/dos.h>
#include <devices/timer.h>
#include <libraries/locale.h>
#include <proto/exec.h>
#include <proto/locale.h>
#include <proto/battclock.h>


#define LVOReadBattClock	(-12)
#define LVOWriteBattClock	(-18)


struct Node *BattClockBase;
struct Device *TimerBase;
struct MsgPort *TimerPort;
struct timerequest *TimerRequest;
struct Locale *Locale;
ULONG GMTOffset;


APTR OldReadBattClock;
APTR OldWriteBattClock;


asm("
	.text
	.globl _NewReadBattClock
	.globl _NewWriteBattClock

_NewReadBattClock:
	move.l	(_OldReadBattClock),a0
	jsr		(a0)
	sub.l		(_GMTOffset),d0
	rts

_NewWriteBattClock:
	add.l		(_GMTOffset),d0
	move.l	(_OldWriteBattClock),a0
	jmp		(a0)
");


extern ULONG NewReadBattClock(void);
extern void NewWriteBattClock(ULONG);


void SetClock(void)
{
	TimerRequest->tr_node.io_Command = TR_SETSYSTIME;
	TimerRequest->tr_node.io_Flags = IOF_QUICK;
	TimerRequest->tr_time.tv_micro = 0;
	TimerRequest->tr_time.tv_secs = ReadBattClock();
	DoIO((struct IORequest *)TimerRequest);
}


int main(int argc, char *argv[])
{
	Locale = OpenLocale(NULL);
	GMTOffset = 60*Locale->loc_GMTOffset;
	BattClockBase = OpenResource("battclock.resource");
	if (TimerPort = CreateMsgPort()) {
		if (TimerRequest = CreateIORequest(TimerPort, sizeof(struct timerequest))) {
			if (!OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *)TimerRequest, NULL)) {
				TimerBase = TimerRequest->tr_node.io_Device;
				OldReadBattClock = SetFunction((struct Library *)BattClockBase, LVOReadBattClock,
														 NewReadBattClock);
				OldWriteBattClock = SetFunction((struct Library *)BattClockBase, LVOWriteBattClock,
														  (ULONG (*)())NewWriteBattClock);
				SetClock();
				SetSignal(NULL, SIGBREAKF_CTRL_C);
				Wait(SIGBREAKF_CTRL_C);
				SetFunction((struct Library *)BattClockBase, LVOReadBattClock, OldReadBattClock);
				SetFunction((struct Library *)BattClockBase, LVOWriteBattClock, OldWriteBattClock);
				SetClock();
				CloseDevice((struct IORequest *)TimerRequest);
			}
			DeleteIORequest(TimerRequest);
		}
		DeleteMsgPort(TimerPort);
	}
	exit(0);
}
