/*
   Lock keyboard when the device connecting pins 5 and 8 is removed,
   and unlock it when it is replaced.
     --RKeene [07/17/99:04:00]


   Flags:

    -DUSE_SVGA       	To use SVGAlib to clear the screen when locking
    -DKBD_BASE=0x60  	To change where the keyboard is.
    -DISABLE_ON_INT	To disable on the keyboard on SIGINT
    -DONT_LOG		To disable logging
    -DONT_DISABLE	Do not disable the keyboard.
    -DONT_DETACH	To not detach from the terminal.
    -DEXEC_DIS=program	Run program on disabilitation of keyboard
    -DEXEC_ENA=program  "             " rehabilitation "         "
    -DONT_FORK

*/

#ifdef GO32
#include <inlines/pc.h>
#undef LINUX
#endif /* GO32 */

#ifdef LINUX
#include <asm/io.h>
#include <syslog.h>
#endif /* Linux */
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#ifdef USE_SVGA
#include <vga.h>
#endif /* USE_SVGA */
#if (defined EXEC_DIS) || (defined EXEC_ENA)
#include <stdlib.h>
#endif

#ifndef KBDBASE
#define KBDBASE 0x60
#endif
int COMBASE=0x2f8;		/* /dev/ttyS1 */
int VGA_MODE;


#ifdef GO32
#define ONT_LOG

void outb(unsigned char value,int address) {
  outportb(value,address);
  return;
}
unsigned char inb(int address) {
  return(inportb(address));
}

unsigned char ioperm(unsigned long from, unsigned long num, int turn_on) {
  return(0);
}
#define LINUX
#endif /* GO32 */

#ifndef LINUX
#define ONT_LOG
/*
  These routines MIGHT work, but I dont know.
*/
void outb(unsigned char value, int address) {
  __asm__ __volatile__("
    movb %%al, %0
    outb %1, %%al"
    :
    : "g" (value), "g" (address)
  );
  return;
}

unsigned char inb(int address) {
  unsigned char value;
  __asm__ __volatile__("
    inb %0"
  : "=g" (value)
  : "g" (address)
  );
  return(value);
}

int ioperm(unsigned long from, unsigned long num, int turn_on) {
  return(0);
}
#endif /* !LINUX */


#ifndef ONT_LOG
void writelog(char message[128]) {
  openlog("kblockd", LOG_PID, LOG_DAEMON);
  syslog(LOG_INFO, message);
  closelog();
}
#endif


void disablekbd(int log) {
#ifndef ONT_LOG
  if (log==1) { writelog("Device removed, disabling keyboard"); }
#endif
#ifdef EXEC_DIS
  system(EXEC_DIS);
#endif
#ifndef ONT_DISABLE
  outb(0xa7,KBDBASE+4);
  outb(0xad,KBDBASE+4);
  outb(0xaf,KBDBASE+4);
#endif
#ifdef USE_SVGA
  VGA_MODE=vga_getcurrentmode();
  vga_setmode(1);
#endif
}


void enablekbd(int log) {
#ifndef ONT_LOG
  if (log==1) { writelog("Device detected, enabling keyboard"); }
#endif
#ifndef ONT_DISABLE
  outb(0xa8,KBDBASE+4);
  outb(0xae,KBDBASE+4);
  outb(0xb0,KBDBASE+4);
  outb(0xf4,KBDBASE);
#endif
#ifdef USE_SVGA
  vga_setmode(VGA_MODE);
#endif
#ifdef EXEC_ENA
  system(EXEC_ENA);
#endif
  return;
}

/*
  1=offline, 0=online
*/
int checkplug(void) {
  int i;
  outb(1,COMBASE+4);
  for (i=0;i<4;i++) { inb(COMBASE+6); }
  if (inb(COMBASE+6)!=128) { return 1; }
  return 0;
}
/*
  1=locked, 0=free
*/
int checkkbdlock(void) {
  int stats;
  outb(0xa9,0x64);
  stats=inb(0x60);
  if (stats==1) { return 1; }
  return 0;
}

void handleINT(void) {
#ifndef ONT_LOG
  writelog("SIGINT recieved, terminating.");
#endif
#ifndef ISABLE_ON_INT
  enablekbd(0);
#else
  disablekbd(0);
#endif
  exit(1);
}

void handleKill(void) {
#ifndef ONT_LOG
  writelog("Kill message recieved, ignored.");
#endif
  signal(SIGINT,(void *)handleINT);
  signal(SIGHUP,(void *)handleKill);
  signal(SIGTERM,(void *)handleKill);  
}

int main(int argc, char *argv[])
{
  int status=2,tmpstatus,log=0;
  if (getuid()!=0) { printf("You must be root to run this program.\n"); return 1; }
#ifndef ONT_FORK
  if (fork()!=0) { return(0); }
#endif
#ifndef USE_SVGA
#ifndef ONT_DETACH
  setsid();
  fclose(stdin);
  fclose(stdout);
  fclose(stderr);
#endif
#else
  if (vga_init()!=0) { printf("Unable to intialize SVGAlib, terminating.\n"); exit(1); }
  VGA_MODE=vga_getcurrentmode();
#endif
  chdir("/tmp");
  signal(SIGINT,(void *)handleINT);
  signal(SIGHUP,(void *)handleKill);
  signal(SIGTERM,(void *)handleKill);
  signal(SIGSEGV,(void *)handleINT);
  ioperm(KBDBASE,1,1);
#ifndef ONT_LOG
  writelog("Starting keyboard locking daemon.");
#endif
  ioperm(KBDBASE+4,1,1);
  if (argc!=1) { 
    if (strncmp(argv[1],"1",1)==0) { COMBASE=0x3f8; }
  }
  ioperm(COMBASE,16,1);
  while(1) {
    tmpstatus=checkplug();
    if ((status!=tmpstatus)) { 
      status=tmpstatus;
      if (tmpstatus==1) { disablekbd(log); }
      if (tmpstatus==0) { enablekbd(log); }
      log=1;
    }
    usleep(1000);
  }
  return(0);
}
