/*
 * (C) 1984 UniSoft Corp. of Berkeley CA
 *
 * UniPlus Source Code. This program is proprietary
 * with Unisoft Corporation and is not to be reproduced
 * or used in any manner except as authorized in
 * writing by Unisoft.
 *
 * Interrupt handler for level 2 interrupts.
 *	keyboard, mouse, real time clock, on/off switch
 */

#include "sys/param.h"
#include "sys/types.h"
#include "sys/mmu.h"
#include "sys/reg.h"
#include "sys/local.h"
#include "sys/cops.h"
#include "sys/keyboard.h"
#include "sys/mouse.h"
#include "sys/ms.h"
#include "sys/l2.h"
#include "sys/kb.h"

extern struct rtime rtime;

char *kb_keytab = ToLA;
char kb_altkp;			/* are we in alternate keypad mode? (set in vt100.c) */

char pportplug;
char ms_plg, ms_btn;
short ms_row, ms_col;

kbintr()
{
	register char i;
	register struct device_e *p = COPSADDR;
	register char a, ud;
	register int tmp;
	extern time_t lbolt;
#ifdef SUNIX
	extern char kb_getchr;	/* flag for polling keyboard */
#endif SUNIX

	a = p->e_ifr;			/* Read and save reason for interrupt */
	if (a & FCA1) {			/* keyboard input */
		i = p->e_ira;			/* get keyboard/mouse input */
		if (a & FTIMER1)
			a = COPSADDR->e_t1cl;	/* prime timer */
	} else {			/* no character input */
		a = COPSADDR->e_t1cl;		/* prime timer */
		if (--kb_reptrap == 0)
			kbrepeat();		/* possible char repeat */
		return;		
	}

	switch (kb_state) {
	case NORMALWAIT:		/* IDLE LOOP */
		ud = i & 0x80;		/* whether up or down keycode */
		l2_dtrap = lbolt + l2_dtime;	/* reset dim delay */
		if (l2_dimmed)		/* restore screen intensity */
			l2undim();
		a = kb_keytab[i & 0x7F];/* convert to ascii */
		if (ud) {		/* "key went down" bit */
/* click(); /* key click */
			if (ARROW(i,a)) {	/* check arrow keys */
				kb_chrbuf = Esc;    /* send 3-char sequence */
				cointr(0);
				kb_chrbuf = '[';
				cointr(0);
				kb_chrbuf = a;
				cointr(0);
				goto out;
			}
			if (kb_altkp) {	/* send special sequence for keypad chars */
				if (a = altkpad[i & 0x7F]) {/* is it in the keypad? */
					kb_chrbuf = Esc;    /* send 3-char sequence */
					cointr(0);
					kb_chrbuf = 'O';
					cointr(0);
					kb_chrbuf = a;
					cointr(0);
					goto out;
				}
				a = kb_keytab[i & 0x7F];/* reset to ascii */
			}
			if (a >= 0) {	/* ascii ? */
				kb_keycount++;
				if (kb_ctrl) a &= 0x1F;
				else if (kb_keycount == 1) {
					kb_reptrap = kb_repwait;
					kb_lastc = a;
				} else kb_reptrap = 0;
				kb_chrbuf = a;
				cointr(0);
				goto out;
			}
		} else {		/* key went up */
			kb_reptrap = 0;
			if (a >= 0) {
				if (kb_keycount-- < 0) {
					kb_keycount = 0;
				}
				goto out;
			}
		}
		switch (a & 0xF) {
		case KB_CTRL:	kb_ctrl = ud; kb_reptrap = 0; msintr(M_CTL);
								goto out;
		case KB_SHFT:	kb_shft = ud; kbsetcvtab(); msintr(M_SFT);
								goto out;
		case KB_LOCK:	kb_lock = ud; kbsetcvtab();	goto out;
		case KB_OFF:	printf("[SOFT OFF %x]\n",i);	goto out;
		case KB_MSP:	ms_plg = ud; msintr(M_PLUG);	goto out;
		case KB_MSB:	ms_btn = ud; msintr(M_BUT);	goto out;
		case KB_PPORT:	pportplug = ud;			goto out;
		case KB_D2B:	printf("[disk1button %x]\n",i);	goto out;
		case KB_D2P:	printf("[disk1 %x]\n",i);	goto out;
		case KB_D1B:	printf("[disk2button %x]\n",i);	goto out;
		case KB_D1P:	printf("[disk2 %x]\n",i);	goto out;
		case KB_STATE:	if (ud == 0) {
					kb_state = MOUSERD;
				} else
					kb_state = RESETCODE;
				goto out;
		default:	printf("invalid key[0x%x]",i);
		}
		goto out;
	case MOUSERD:		/* PICKUP Y axis change in mouse pos */
		kb_state = YMOUSE;
		ms_col = (short)i;
		goto out;
	case YMOUSE:		/* PICKUP Y axis change in mouse pos */
		kb_state = NORMALWAIT;
		ms_row = (short)i;
		msintr(M_MOVE);
		goto out;
	case RESETCODE:		/* special condition */
		switch (i & 0xFF) {
		case KB_KBCOPS:	/* keyboard cops failure detected */
			printf("KEYBOARD COPS FAILURE\n");
			break;
		case KB_IOCOPS:	/* IO board cops failure detected */
			printf("IO BOARD COPS FAILURE\n");
			break;
		case KB_UNPLUG:	/* keyboard unplugged */
			kb_chrbuf = 's'&0x1F;	/* cntl S */
			cointr(0);
			break;
		case KB_CLOCKT:	/* clock timer interrupt */
			printf("Real Time Clock interrupt\n");
			break;
		case KB_SFTOFF:	/* soft power switch */
			kb_state = SHUTDOWN;
			printf("Shutting down...\n");
			update();
			for (tmp = 0; tmp < 500000; tmp++);
			l2_crate = 2;
			l2_desired = TOTALDIM;	/* completely blacken screen */
			l2ramp(0);
			l2ramp(0);
			SPL7();			/* extreme priority */
			l2copscmd(SHUTOFF);
			rom_mon();		/* return to the ROM monitor */
			/*NOTREACHED*/
		default: switch (i & 0xF0) {
			case KB_RESERV:
				printf("[Reserved keycode 0x%x]\n",i);
				break;
			case KB_RDCLK:
				rtime.rt_year = (i & 0xF) + 10;	
				kb_state = CLKREAD;
				goto out;
			default:
				kb_idcode = i;
				kb_chrbuf = 'q'&0x1F;	/* cntl Q */
				cointr(0);
				printf("Keyboard type 0x%x\n",i);
			}
		}
		kb_state = NORMALWAIT;
		goto out;
	case CLKREAD:
		rtime.rt_day = (((i&0xF0)>>4)*10 + (i&0xF))*10;
		kb_state++;
		goto out;
	case CLKREAD+1:
		rtime.rt_day += (i&0xF0) >> 4;
		rtime.rt_hour = (i & 0xF) * 10;
		kb_state++;
		goto out;
	case CLKREAD+2:
		rtime.rt_hour += (i & 0xF0) >> 4;
		rtime.rt_min = (i & 0x0F) * 10;
		kb_state++;
		goto out;
	case CLKREAD+3:
		rtime.rt_min += (i & 0xF0) >> 4;
		rtime.rt_sec = (i & 0x0F) * 10;
		kb_state++;
		goto out;
	case CLKREAD+4:
		rtime.rt_sec += (i & 0xF0) >> 4;
		rtime.rt_tenth = i & 0x0F;
		kb_state = NORMALWAIT;
		rtcsettod();
		goto out;
	case SHUTDOWN:
		goto out;
	}
out:	;
#ifdef SUNIX
	if (!ud)
		kb_getchr = 0;
#endif SUNIX
}

kbrepeat ()
{
	kb_reptrap = kb_repdlay;		/* reset repeat timeout */

	if (kb_keycount == 1) {
		kb_chrbuf = kb_lastc;
/* click(); /* key click */
		cointr(0);
	} else
		kb_reptrap = 0;		/* reset repeat timeout */
}

kbsetcvtab()
{
	kb_keytab = ccvtab[(kb_shft?2:0)+(kb_lock?1:0)];
	kb_reptrap = 0;
}
