#include #include #include #include #include "kbd.h" /***************************************************************************/ #define SS_DOLLAR_NORMAL 1 -1 #define INVALID_PTR -1L #define KBD_TYPE "US" /* Or "GY" */ #define RS232_VEC_ID 76 /* $130/4 */ #define KBD_OS_JUMP (0xfc3d5eL) /* Entry KBD-interrupthandler */ #define RS232_OS_JUMP (0xfc3426L) /* Entry RS232-output */ #define SYSHDR_PTR (0x4f2L) /* Ptr to Sysheaderstructure */ #define RWABS_VEC (0X476L) /* Rwabs-vector */ #define RCV_STAT_REG (0xfffffa2bL) /* Receiver-Status-register */ #define DATA_REG (0xfffffa2fL) /* USART-Data-register */ /***************************************************************************/ #define INSTALL_DIALOG \ \ "[0][ |KBD V1.4a by Bert Oberholz '91 |" \ \ " | suosws::oberholz |" \ " oberholz@suosws.enet.dec.com | ]"\ \ "[Install|Quit]" #define INSTALL_WARN_DIALOG \ \ "[1][ XBRA-chain interrupted | " \ " | KBD V1.4a by Bert Oberholz '91 " \ \ "| suosws::oberholz |" \ " oberholz@suosws.enet.dec.com ]"\ \ "[Install|Quit]" #define REMOVE_DIALOG \ \ "[0][ |KBD V1.4a by Bert Oberholz '91 |" \ \ " | suosws::oberholz |" \ " oberholz@suosws.enet.dec.com | ]"\ \ "[Remove|Keep]" #define REMOVE_BUTTON 1 #define INSTALL_BUTTON 1 #define QUIT_BUTTON 2 #define NO_AES 0 /***************************************************************************/ #define STR4EQU(a,b) (strncmp(a,b,4)==0) /* spec. comparision for XBRA */ #define BEGIN_ROM (0xfc0000L) #define END_ROM (0xfeffffL) #define IN_ROM(a) (((a) >= BEGIN_ROM && (a) <= END_ROM) ? 1 : 0) /***************************************************************************/ #define BOOT_KEY DEC_F_20 /***************************************************************************/ #define LEARN_KEY DEC_DO #define LEARN_BUF_SIZE 10 /* do not increase */ #define LEARN_IN_PROG 1 #define LEARNED 2 #define NO_LEARN 3 /***************************************************************************/ #define LED_ON 0x13 #define LED_OFF 0x11 #define WAIT_LED 0x81 #define ALT_LED 0x82 #define CAPS_LED 0x84 #define HOLD_LED 0x88 #define SOUND_BELL 0xA7 /***************************************************************************/ /* Global pointer declarations */ /***************************************************************************/ char *gl_ptr_rs; /* Ptr to Receiver-Status-reg. */ char *gl_ptr_ud; /* Ptr to USART-Data-reg. */ char *gl_kbshift; /* Ptr to Shiftregister */ IOREC *gl_iorec; /* Ptr to Keyboard-IOREC-struct. */ /***************************************************************************/ /* Declaration of XBRA structure */ /***************************************************************************/ typedef struct { char xb_magic[4]; char xb_id[4]; long xb_oldvec; } XBRA; /***************************************************************************/ /* Forward-declarations of subroutines (ANSI-C) */ /***************************************************************************/ void install_kbd (char *txt, int def_button, char* dialog); void remove_kbd (XBRA *old_xbra_ptr, XBRA *xbra_ptr, int def_button, char* dialog); long init_ptr (void); char convert_scan_code (char dec_scan); void my_c_hdl (void); void learn (char dec_scan); void send_rs232 (char code1, char code2); /***************************************************************************/ /* The OS-routine process_it expects *iorec in A0, st_scan in D0 */ /* The OS-routine put_rs232 expects code in D0 */ void (*process_it) (IOREC *iorec, char st_scan); void (*put_rs232) (char code); /* Keep this in mind! This is by chance the way my compiler passes Params */ /***************************************************************************/ /***************************************************************************/ /* external declarations of assembler routines */ /***************************************************************************/ extern void my_asm_hdl (void); extern void my_rwabs (void); /***************************************************************************/ /* */ /* main procedure */ /* - decide whether to install or remove kbd */ /* */ /***************************************************************************/ void main(void) { XBRA *xbra_ptr, *old_xbra_ptr; void (*chkvec)(); int found = 0; (long) chkvec = INVALID_PTR; (long) old_xbra_ptr = INVALID_PTR; /* get current vector */ xbra_ptr = (XBRA *) Setexc (RS232_VEC_ID, chkvec); /* follow the chain as long as it is XBRA and KBD not found */ while ( STR4EQU ((--xbra_ptr)->xb_magic,"XBRA") && (found = STR4EQU ( xbra_ptr ->xb_id, "KB14")) == 0) { old_xbra_ptr = xbra_ptr; (long) xbra_ptr = xbra_ptr->xb_oldvec; } if (found) /* KBD already installed */ remove_kbd (old_xbra_ptr, xbra_ptr, REMOVE_BUTTON, REMOVE_DIALOG); else if (IN_ROM ((long) xbra_ptr + sizeof(XBRA))) /* XBRA chain ok or no chain at all */ install_kbd(" \n ", INSTALL_BUTTON, INSTALL_DIALOG); else /* XBRA chain interrupted */ install_kbd(" \n XBRA-chain interrupted! ", QUIT_BUTTON, INSTALL_WARN_DIALOG); } /***************************************************************************/ /* */ /* remove_kbd */ /* - do dialog */ /* - unchain KBD or restore old vector */ /* */ /***************************************************************************/ void remove_kbd (XBRA *old_xbra_ptr, XBRA *xbra_ptr, int def_button, char* dialog) { void (*oldvec)(); int button; if ((button=form_alert(def_button,dialog)) != QUIT_BUTTON) { /* remove */ if ((long) old_xbra_ptr == INVALID_PTR) /* no more chain memb. ? */ { /* restore vector */ (long) oldvec = xbra_ptr->xb_oldvec; Setexc (RS232_VEC_ID, oldvec); } else /* unchain */ old_xbra_ptr->xb_oldvec = xbra_ptr->xb_oldvec; } /* run from autofolder ? */ if (button == NO_AES) puts("\n\x1bp DEC-LK201 Keyboard-driver V1.4a deactivated! \x1bq\n"); /* Process terminate with success */ Pterm (SS_DOLLAR_NORMAL); } /***************************************************************************/ /* */ /* install_kbd */ /* - do dialog */ /* - setup pointers */ /* - configure RS232-port */ /* - setup US-keytable (conditionally) */ /* - modify RS232-rcv-buf-full vector to point to my handler */ /* */ /***************************************************************************/ void install_kbd (char *txt, int def_button, char* dialog) { extern XBRA my_xbra1; int button; char unshift_tab [] = US_UNSHIFT_TAB; char shift_tab [] = US_SHIFT_TAB; char capslock_tab[] = US_CAPSLOCK_TAB; if ((button=form_alert(def_button,dialog)) != QUIT_BUTTON) { /* setup pointers and RWABS-vector in supervisor mode */ Supexec (init_ptr); /* setup RS232 port */ Rsconf (2, 0, -1, -1, -1, -1); /* install new interrupthandler, save the old one */ my_xbra1.xb_oldvec = (long) Setexc (RS232_VEC_ID, my_asm_hdl); /* Set keytable according to macro KBD_TYPE */ if (strcmp (KBD_TYPE, "US") == 0) Keytbl (unshift_tab, shift_tab, capslock_tab); } /* run from autofolder ? */ if (button == NO_AES) { if (txt[4] != ' ') puts (txt); puts("\x1bp DEC-LK201 Keyboard-driver V1.4a " KBD_TYPE " installed! \x1bq\n"); } /* process terminate and stay resident, _PgmSize is compilerspecific! */ Ptermres (_PgmSize, SS_DOLLAR_NORMAL); } /***************************************************************************/ /* */ /* init_ptr */ /* - setup some global pointers referred by the interrupthandler */ /* including function-pointers pointing to ROM */ /* - modify RWABS-vector */ /* */ /***************************************************************************/ long init_ptr(void) { extern XBRA my_xbra2; long *ptr; /* setup ptr to kbshift-register */ (long) ptr = SYSHDR_PTR; (long) ptr = *ptr; (long *) gl_kbshift = ((SYSHDR *) ptr)->kbshift; /* initialize kbshift-register */ *gl_kbshift &= 0xf0; /* setup ptr to kbd-iorec-register */ gl_iorec = Iorec(1); /* save and bend RWABS-vector */ (long) ptr = RWABS_VEC; my_xbra2.xb_oldvec = *ptr; *ptr = (long) my_rwabs; /* init ptr to MFP */ (long) gl_ptr_rs = RCV_STAT_REG; (long) gl_ptr_ud = DATA_REG; /* init function-ptr to ROM */ (long) process_it = KBD_OS_JUMP; (long) put_rs232 = RS232_OS_JUMP; return (SS_DOLLAR_NORMAL); } /***************************************************************************/ /* */ /* my_c_hdl - this is the 'real' interrupt-handler called by my_asm_hdl() */ /* */ /***************************************************************************/ void my_c_hdl(void) { char st_scan; char dec_scan; /* is it rcv-buf-full interrupt ? */ if (*gl_ptr_rs & 0x80) /* is converted content of USART-dataregister a processable key ? */ if ((st_scan = convert_scan_code (dec_scan=*gl_ptr_ud)) != 0) /* let the OS process it */ process_it (gl_iorec,st_scan); /* every key is send to learn function */ learn (dec_scan); } /***************************************************************************/ /* */ /* learn - handle learn-mechanism */ /* */ /* If you see the reason why I had to limit it to 9-keystrokes. */ /* Let me know. */ /* */ /***************************************************************************/ void learn (char dec_scan) { int do_it_ind; static int learn_stat = NO_LEARN; static char learn_buf [LEARN_BUF_SIZE]; static int cur_ind; char st_scan; /* this should by self-explaining */ if (dec_scan == LEARN_KEY) if (*gl_kbshift & 0x03) /* shift active? */ { learn_stat = LEARN_IN_PROG; cur_ind = 0; send_rs232 (LED_ON, HOLD_LED); } else if (learn_stat == LEARN_IN_PROG) { learn_stat = LEARNED; send_rs232 (LED_OFF, HOLD_LED); } else if (learn_stat == LEARNED) for (do_it_ind = 0; do_it_ind < cur_ind;) { st_scan = convert_scan_code(learn_buf[do_it_ind++]); if (st_scan) process_it (gl_iorec, st_scan); } else; else if (learn_stat == LEARN_IN_PROG) if (cur_ind < LEARN_BUF_SIZE) learn_buf [cur_ind++] = dec_scan; else put_rs232 (SOUND_BELL); } /***************************************************************************/ /* */ /* send_rs232 - useful because switching the lamps always requires 2 codes */ /* - expects codes in D0 and D1! (called from C and assembler) */ /* */ /***************************************************************************/ void send_rs232 (char code1, char code2) { put_rs232 (code1); put_rs232 (code2); } /***************************************************************************/ /* */ /* convert_scan_code */ /* - manipulates the keyboard-shift-register */ /* - converts scancodes (how did you know ?) */ /* */ /***************************************************************************/ char convert_scan_code (char dec_scan) { char st_scan; static long old_st_scan = 0; st_scan = 0; /* if last key was processable and alt is active */ if (old_st_scan && (*gl_kbshift & 0x08)) /* reset alt bit */ *gl_kbshift &= 0xf7; /* main dispatcher to convert scancodes, should be self-explaining */ switch (dec_scan) { case DEC_REPEAT : st_scan = old_st_scan; break; case DEC_ALT : *gl_kbshift |= 0x08; send_rs232 (LED_ON, ALT_LED); break; case DEC_CTRL : *gl_kbshift |= 0x04; break; case DEC_SHIFT : *gl_kbshift |= 0x03; break; case DEC_CAPS_LOCK : *gl_kbshift ^= 0x10; if (*gl_kbshift & 0x10) send_rs232 (LED_ON, CAPS_LED); else send_rs232 (LED_OFF, CAPS_LED); break; case DEC_ALL_UP : *gl_kbshift &= 0xf0; break; case BOOT_KEY : *gl_kbshift |= 0x0d; st_scan = ST_DELETE; break; case DEC_HASH : if (*gl_kbshift & 0x03) st_scan = ST_SCHLEIFE; else st_scan = ST_HASH; break; case DEC_SCHLEIFE : if (*gl_kbshift & 0x03) st_scan = ST_HASH; else st_scan = ST_SCHLEIFE; break; case DEC_RETURN : st_scan = ST_RETURN; break; case DEC_BACKSPACE : st_scan = ST_BACKSPACE; break; case DEC_TAB : st_scan = ST_TAB; break; case DEC_F_11 : st_scan = ST_ESC; break; case DEC_SPACE : st_scan = ST_SPACE; break; case DEC_A : st_scan = ST_A; break; case DEC_B : st_scan = ST_B; break; case DEC_C : st_scan = ST_C; break; case DEC_D : st_scan = ST_D; break; case DEC_E : st_scan = ST_E; break; case DEC_F : st_scan = ST_F; break; case DEC_G : st_scan = ST_G; break; case DEC_H : st_scan = ST_H; break; case DEC_I : st_scan = ST_I; break; case DEC_J : st_scan = ST_J; break; case DEC_K : st_scan = ST_K; break; case DEC_L : st_scan = ST_L; break; case DEC_M : st_scan = ST_M; break; case DEC_N : st_scan = ST_N; break; case DEC_O : st_scan = ST_O; break; case DEC_P : st_scan = ST_P; break; case DEC_Q : st_scan = ST_Q; break; case DEC_R : st_scan = ST_R; break; case DEC_S : st_scan = ST_S; break; case DEC_T : st_scan = ST_T; break; case DEC_U : st_scan = ST_U; break; case DEC_V : st_scan = ST_V; break; case DEC_W : st_scan = ST_W; break; case DEC_X : st_scan = ST_X; break; case DEC_Y : st_scan = ST_Y; break; case DEC_Z : st_scan = ST_Z; break; case DEC_1 : st_scan = ST_1; break; case DEC_2 : st_scan = ST_2; break; case DEC_3 : st_scan = ST_3; break; case DEC_4 : st_scan = ST_4; break; case DEC_5 : st_scan = ST_5; break; case DEC_6 : st_scan = ST_6; break; case DEC_7 : st_scan = ST_7; break; case DEC_8 : st_scan = ST_8; break; case DEC_9 : st_scan = ST_9; break; case DEC_0 : st_scan = ST_0; break; case DEC_SUCHEN : st_scan = ST_HELP; break; case DEC_EINFUEGEN : st_scan = ST_INSERT; break; case DEC_LOESCHEN : st_scan = ST_DELETE; break; case DEC_SELEKTIEREN : st_scan = ST_KP_PUNKT; break; case DEC_BILD_AUF : st_scan = ST_UNDO; break; case DEC_BILD_AB : st_scan = ST_CLR_HOME; break; case DEC_ARR_LINKS : st_scan = ST_ARR_LINKS; break; case DEC_ARR_RECHTS : st_scan = ST_ARR_RECHTS; break; case DEC_ARR_AUF : st_scan = ST_ARR_AUF; break; case DEC_ARR_AB : st_scan = ST_ARR_AB; break; case DEC_KP_PF1 : st_scan = ST_KP_OPAR; break; case DEC_KP_PF2 : st_scan = ST_KP_CPAR; break; case DEC_KP_PF3 : st_scan = ST_KP_SLASH; break; case DEC_KP_PF4 : st_scan = ST_KP_STERN; break; case DEC_KP_MINUS : st_scan = ST_KP_MINUS; break; case DEC_KP_KOMMA : st_scan = ST_KP_PLUS; break; case DEC_KP_EINGABE : st_scan = ST_KP_ENTER; break; case DEC_KP_PUNKT : st_scan = ST_KP_PUNKT; break; case DEC_KP_1 : st_scan = ST_KP_1; break; case DEC_KP_2 : st_scan = ST_KP_2; break; case DEC_KP_3 : st_scan = ST_KP_3; break; case DEC_KP_4 : st_scan = ST_KP_4; break; case DEC_KP_5 : st_scan = ST_KP_5; break; case DEC_KP_6 : st_scan = ST_KP_6; break; case DEC_KP_7 : st_scan = ST_KP_7; break; case DEC_KP_8 : st_scan = ST_KP_8; break; case DEC_KP_9 : st_scan = ST_KP_9; break; case DEC_KP_0 : st_scan = ST_KP_0; break; case DEC_F_1 : st_scan = ST_F_1; break; case DEC_F_2 : st_scan = ST_F_2; break; case DEC_F_3 : st_scan = ST_F_3; break; case DEC_F_4 : st_scan = ST_F_4; break; case DEC_F_5 : st_scan = ST_F_5; break; case DEC_F_6 : st_scan = ST_F_6; break; case DEC_F_7 : st_scan = ST_F_7; break; case DEC_F_8 : st_scan = ST_F_8; break; case DEC_F_9 : st_scan = ST_F_9; break; case DEC_F_10 : st_scan = ST_F_10; break; case DEC_HELP : st_scan = ST_HELP; break; case DEC_OE : st_scan = ST_OE; break; case DEC_AE : st_scan = ST_AE; break; case DEC_UE : st_scan = ST_UE; break; case DEC_SS : st_scan = ST_SS; break; case DEC_APO : st_scan = ST_APO; break; case DEC_KOMMA : st_scan = ST_KOMMA; break; case DEC_PUNKT : st_scan = ST_PUNKT; break; case DEC_MINUS : st_scan = ST_MINUS; break; case DEC_PLUS : st_scan = ST_PLUS; break; case DEC_KLEINER : st_scan = ST_KLEINER; break; /* useful for debugging purposes */ /* default : st_scan = 0; printf("\n%x",dec_scan); */ } /* if new key is processable and alt is active */ if (st_scan && (*gl_kbshift & 0x08)) /* turn off alt indicator */ send_rs232 (LED_OFF, ALT_LED); /* buffer new code */ old_st_scan = st_scan; /* function value is new code */ return st_scan; }