Listing 11 (kserver.c) Interrupt Driven Task Keyboard Server

#include <synrtx.h>
#include <ascii.h>

#define BEEP    8
#define NCHARS  80
#define NOBODY  0
#define EOI     0x20

static word buffer[NCHARS], nCharsIn, charToSend, charToReceive;
static task_t  ksid, owner;
static msg_t  msg;

/* handler numbers */
#define ACQUIRE      0
#define RELEASE      1
#define HIT          2
#define EXCEPTION    3
#define GETCHAR      4

#define PORT_A 0x60  /* 8255 */
#define PORT_B 0x61

static char kbdTab[] = {
NUL,ESC,'1','2','3','4','5','6','7','8','9','0','-','=',   /* 00-13 */
BS,HT,'q','w','e','r','t','y','u','i','o','p','[',']',CR,  /* 14-28 */
0,'a','s','d','f','g','h','j','k','l',';','\"','`',        /* 29-41 */
0,'\\','z','x','c','v','b','n','m',',','.','/',0,'*',      /* 34-55 */
0,' ',0 };                                                 /* 56-58 */

static byte code, status;
static bool bufferFull;

/* Hardware handler Keyboard for interrupt vector 9 */
static handler Keyboard(void) {
   /* disable keyboard interrupt to not overwrite interrupt stack */
   dev_enable(DISABLE, 1, KEYBOARD);
   cpu_enable();       /* allow further interrupts */

   code = dev_byte(PORT_A);
   status = dev_byte(PORT_B);
   dev_setByte(status | 0x80, PORT_B); /* send ack _/^\_ to kbd */
   dev_setByte(status & 0x7F, PORT_B);

   if (code < 0x80 && kbdTab[code] && !bufferFull) {
      msg.value.w = (word)kbdTab[code];
      /* interrupt KeyboardServer.GetChar */
      task_interrupt(&msg);
   }
   /* keep all interrupts disable for the EOI and Exit */
   cpu_Disable();
   dev_setByte(EOI, 0x20);
   dev_enable(ENABLE, 1, KEYBOARD);
}

static handler Acquire(msg_t *msg_p) {
   register task_t caller = msg_p->srcTid;
   register task_t self   = msg_p->dstTid;

   owner      = caller;
   charToSend = charToReceive = nCharsIn = 0;
   bufferFull = FALSE;

   /* interrupt caller.Grant */
   msg_p->srcTid = self;
   msg_p->dstTid = caller;
   msg_p->dstHid = 0; /* GRANT = 0 */
   msg_p->type   = msg_type_SYNC;
   task_interrupt(msg_p);
}

static handler Release(msg_t *msg_p) {
   register task_t caller = msg_p->srcTid;
   register task_t self   = msg_p->dstTid;
   if (owner == caller) {
      owner = NOBODY;
      /* BufferFull is set to TRUE to avoid any software interrupts */
      bufferFull = TRUE;
   } else {
      /* interrupt self.Exception(caller) */
      msg_p->srcTid  = msg_p->dstTid = self;
      msg_p->dstHid  = EXCEPTION;
      msg_p->type    = msg_type_WORD;
      msg_p->value.w = (word)caller;
      task_interrupt(msg_p);
   }
}

static handler Hit(msg_t *msg_p) {
   register task_t caller = msg_p->srcTid;
   register task_t self   = msg_p->dstTid;
   register word c;
   if (owner == caller) {
      if (nCharsIn == 0)      /* buffer empty ? */
         c = 0;
      else {
         c = buffer[charToSend] | 0x0100;
         charToSend = (charToSend + 1) % NCHARS;
         nCharsIn--;
         bufferFull = FALSE;
      }

      /* interrupt caller.GetChar(character) */
      msg_p->srcTid  = msg_p->dstTid;
      msg_p->dstTid  = caller;
      msg_p->dstHid  = 1; /* GetChar = 1 */
      msg_p->type    = msg_type_WORD;
      msg_p->value.w = c;
      task_interrupt(msg_p);
   } else {
      /* interrupt self.Exception(caller) */
      msg_p->srcTid  = msg_p->dstTid = self;
      msg_p->dstHid  = EXCEPTION;
      msg_p->type    = msg_type_WORD;
      msg_p->value.w = (word)caller;
      task_interrupt(msg_p);
   }
}

static handler Exception(msg_t *msg_p) {
   io_putf("Illegal Access to KeyboardServer by Task #%w", msg_p->value.w);
}

static handler GetChar(msg_t *msg_p) {
   if (nCharsIn == NCHARS) /* buffer full ? */ {
      /* then, ignore the character (stops int from hard) */
      io_puts("\nKeyboardServer: buffer full !\n");
      bufferFull = TRUE;
   } else {
      buffer[charToReceive] = msg_p->value.w;
      charToReceive = (charToReceive + 1) % NCHARS;
      nCharsIn++;
   }
}

task KeyboardServer(void) {
   register word ps;

   ps = cpu_saveAndDisable();
   ksid = task_self();

   /* Install Keyboard hardware handler as the ISR for interrupt vector 9 */
   cpu_setHandler(INT9_KEYBOARD, Keyboard);

   /* Install software handlers */
   task_setHandler(5, Acquire, Release, Hit, Exception, GetChar);
   charToSend = charToReceive = nCharsIn = 0;
   /*
    *  The KeyboardServer cannot receive characters while it is not yet
    *  acquired, but should wait until a "client" gets it.
    *  BufferFull is set to TRUE to avoid any software interrupts.
    */
   bufferFull = TRUE;
   msg.srcTid = msg.dstTid = ksid;
   msg.dstHid = GETCHAR;
   msg.type   = msg_type_WORD;
   cpu_restore(ps);
   loop {
      /* enable wait Acquire */
      task_enableWait(NO_TIMEOUT, 1, ACQUIRE);

      do /* enable wait GetChar, Hit, Release, Exception */
         task_enableWait(NO_TIMEOUT,4,GETCHAR,HIT,RELEASE,EXCEPTION);
      while (owner != NOBODY);
   }
}