                                                                     
                                                                     
                                                                     
                                             
/* realinterrupt.c - HW interrupt example code.
					Edited and updated for amigaos 4 by Alfkil T. Wennermark 2010
					Edited and bug-tested by Steven Solie.

					Thanks to: Steven Solie, Jörg Strohmayer, Thomas Frieden and Colin Wenzel :-) */

/* REMARK: 	On a SAM/SAM-flex system, the returned counter will be a very large number.
			We have yet to figure out, why this is. On AmigaOne's it will be 1 as expected. */


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

#include <exec/memory.h>
#include <exec/interrupts.h>

#include <dos/dos.h>


#include <stdio.h>

uint32 *beef;


struct IData {
    uint32 counter;
	struct Interrupt *oldinterrupt;
};

struct IData *idata;

#if 0		//This will not work, because it doesn't call the old interrupt
asm (
"	.globl icode\n"
"    				\n"
"icode:				\n"
"	lwz %r3, 0(%r5)	\n"
"	addi %r3, %r3, 5\n"
"	stw %r3, 0(%r5)	\n"
"	li %r3, 1		\n"
"	blr				\n"
);
#endif


ULONG icode( struct ExceptionContext *context, struct ExecBase *sb, APTR trapData)
{
	struct IData *d = (struct IData *)trapData;
	struct Interrupt *oldi = d->oldinterrupt;

	d->counter++;

	//NB-NB-NB: You _need_ to call the old interrupt, otherwise you will go boom!
	typedef uint32 (*OLDVEC)();

	return ((OLDVEC)oldi->is_Code)(context, sb, oldi->is_Data);
}


int main()
{
	enum enTrapNumbers trapnumber = TRAPNUM_DATA_SEGMENT_VIOLATION;

	if (!(idata = IExec->AllocMem(sizeof(struct IData), MEMF_SHARED | MEMF_CLEAR)))
		return RETURN_FAIL;

    struct Interrupt *interrupt = IExec->AllocSysObjectTags(ASOT_INTERRUPT,
		ASOINTR_Code, icode,
		ASOINTR_Data, idata,
		TAG_END);

	if (interrupt == NULL)
	{
		IExec->FreeMem (idata, sizeof (struct IData));
		return(-20);
	}

    interrupt->is_Node.ln_Pri = -1;
	interrupt->is_Node.ln_Name = "my personal interrupt";

	//printf("icode = %#08x\n", icode (NULL, NULL, idata));
	//printf("counter = %d\n", idata->counter);

	printf("calling AddIntServer...\n");
	fflush(stdout);

//	IExec->Forbid();
	idata->oldinterrupt = IExec->SetIntVector(trapnumber, interrupt);
//	IExec->Permit();

	if(!idata->oldinterrupt)
	{
		printf("server not installed!\n");
	}
	else
	{
		printf("server installed\n");
		fflush(stdout);

		idata->counter = 0;

//#if 0
		/* cause a data storage violation: */
		beef = (uint32 *)0;
		*beef = 0L;
//#endif

		IDOS->Delay(10);

		printf("counter = %d\n", idata->counter);

		/* Remember to restore the old interrupt vector, or you will die ;-) */
		IExec->SetIntVector(trapnumber, idata->oldinterrupt);
	}

	IExec->FreeSysObject(ASOT_INTERRUPT, interrupt);
	IExec->FreeMem (idata, sizeof (struct IData));

	return 0;
}

