/*****************************************************************************
interrupt handler demo

CPU mode:	protected mode (32-bit)
using DOS?	yes
language:	DJGPP (GCC for DOS)

Note: there are other ways to handle interrupts under DJGPP.
For more information:
	http://www.delorie.com/djgpp/doc/ug/interrupts/hwirqs.html
	http://www.geocities.com/SiliconValley/Vista/6552/djints.txt
	http://mega.ist.utl.pt/~fjds/inthandlers1.html
	http://mega.ist.utl.pt/~fjds/inthandlers2.html
*****************************************************************************/
#include <sys/farptr.h> /* _farpokeb(), _farpokeb() */
#include <conio.h> /* getch(), cputs() */
#include <go32.h> /* _dos_ds, _my_cs() */
#include <dpmi.h> /* _go32_dpmi... */
#include <crt0.h> /* _CRT0_FLAG_LOCK_MEMORY */
#include <dos.h> /* outportb() */

#define	TIMER_VECT	8
#define	SYSCALL_VECT	50
#define	SYS_CPUTS	0

/* vector type and macros for portability  */
#define	INTERRUPT	/* nothing */

#define	SAVE_VECTOR(vec, num)						\
	_go32_dpmi_get_protected_mode_interrupt_vector(num, &vec.old_v)

#define	INSTALL_HANDLER(vec, num, fn)					\
	vec.new_v.pm_selector = _my_cs();				\
	vec.new_v.pm_offset = (unsigned long)fn;			\
	_go32_dpmi_allocate_iret_wrapper(&vec.new_v);			\
	_go32_dpmi_set_protected_mode_interrupt_vector(num, &vec.new_v);

#define	RESTORE_VECTOR(vec, num)					\
	_go32_dpmi_set_protected_mode_interrupt_vector(num, &vec.old_v);\
	_go32_dpmi_free_iret_wrapper(&vec.new_v);

typedef struct
{
	_go32_dpmi_seginfo old_v, new_v;
} vector_t;

/* lock all memory, to prevent it being swapped or paged out */
int _crt0_startup_flags = _CRT0_FLAG_LOCK_MEMORY;
/*****************************************************************************
increment char in upper left corner of screen on every timer tick
*****************************************************************************/
static void INTERRUPT timer_int(void)
{
	_farpokeb(_dos_ds, 0xB8000, _farpeekb(_dos_ds, 0xB8000) + 1);
	outportb(0x20, 0x20);
}
/*****************************************************************************
*****************************************************************************/
static void INTERRUPT syscall_int(__dpmi_regs *regs)
{
	switch(regs->d.eax)
	{
		case SYS_CPUTS:
			cputs((char *)regs->d.esi);
			break;
	}
}
/*****************************************************************************
*****************************************************************************/
int main(void)
{
	static const char *msg = "press a key to quit\n\r";
/**/
	vector_t old_timer_vector, old_syscall_vector;

/* save old vectors */
	SAVE_VECTOR(old_timer_vector, TIMER_VECT);
	SAVE_VECTOR(old_syscall_vector, SYSCALL_VECT);
/* install new handlers */
	INSTALL_HANDLER(old_timer_vector, TIMER_VECT, timer_int);
	INSTALL_HANDLER(old_syscall_vector, SYSCALL_VECT, syscall_int);
/* make a system call */
	__asm__ __volatile__(
		"int %0\n"
		:
		: "i"(SYSCALL_VECT), "a"(SYS_CPUTS), "S"(msg));
/* await key pressed */
	getch();
/* restore old vectors */
	RESTORE_VECTOR(old_timer_vector, TIMER_VECT);
	RESTORE_VECTOR(old_syscall_vector, SYSCALL_VECT);
	return 0;
}

