Logo Search packages:      
Sourcecode: linux version File versions  Download package

kbd.c

#include <linux/keyboard.h>

#include "defkeymap.c"  /* yeah I know it's bad -- Cort */


unsigned char shfts, ctls, alts, caps;

#define     KBDATAP           0x60  /* kbd data port */
#define     KBSTATUSPORT      0x61  /* kbd status */
#define     KBSTATP           0x64  /* kbd status port */
#define     KBINRDY           0x01
#define     KBOUTRDY    0x02

extern unsigned char inb(int port);
extern void outb(int port, char val);
extern void puts(const char *);
extern void puthex(unsigned long val);
extern void udelay(long x);

static int kbd(int noblock)
{
      unsigned char dt, brk, val;
      unsigned code;
loop:
      if (noblock) {
          if ((inb(KBSTATP) & KBINRDY) == 0)
            return (-1);
      } else while((inb(KBSTATP) & KBINRDY) == 0) ;

      dt = inb(KBDATAP);

      brk = dt & 0x80;  /* brk == 1 on key release */
      dt = dt & 0x7f;         /* keycode */

      if (shfts)
          code = shift_map[dt];
      else if (ctls)
          code = ctrl_map[dt];
      else
          code = plain_map[dt];

      val = KVAL(code);
      switch (KTYP(code) & 0x0f) {
          case KT_LATIN:
            if (brk)
                break;
            if (alts)
                val |= 0x80;
            if (val == 0x7f)  /* map delete to backspace */
                val = '\b';
            return val;

          case KT_LETTER:
            if (brk)
                break;
            if (caps)
                val -= 'a'-'A';
            return val;

          case KT_SPEC:
            if (brk)
                break;
            if (val == KVAL(K_CAPS))
                caps = !caps;
            else if (val == KVAL(K_ENTER)) {
enter:                /* Wait for key up */
                while (1) {
                  while((inb(KBSTATP) & KBINRDY) == 0) ;
                  dt = inb(KBDATAP);
                  if (dt & 0x80) /* key up */ break;
                }
                return 10;
            }
            break;

          case KT_PAD:
            if (brk)
                break;
            if (val < 10)
                return val;
            if (val == KVAL(K_PENTER))
                goto enter;
            break;

          case KT_SHIFT:
            switch (val) {
                case KG_SHIFT:
                case KG_SHIFTL:
                case KG_SHIFTR:
                  shfts = brk ? 0 : 1;
                  break;
                case KG_ALT:
                case KG_ALTGR:
                  alts = brk ? 0 : 1;
                  break;
                case KG_CTRL:
                case KG_CTRLL:
                case KG_CTRLR:
                  ctls = brk ? 0 : 1;
                  break;
            }
            break;

          case KT_LOCK:
            switch (val) {
                case KG_SHIFT:
                case KG_SHIFTL:
                case KG_SHIFTR:
                  if (brk)
                      shfts = !shfts;
                  break;
                case KG_ALT:
                case KG_ALTGR:
                  if (brk)
                      alts = !alts;
                  break;
                case KG_CTRL:
                case KG_CTRLL:
                case KG_CTRLR:
                  if (brk)
                      ctls = !ctls;
                  break;
            }
            break;
      }
      if (brk) return (-1);  /* Ignore initial 'key up' codes */
      goto loop;
}

static int __kbdreset(void)
{
      unsigned char c;
      int i, t;

      /* flush input queue */
      t = 2000;
      while ((inb(KBSTATP) & KBINRDY))
      {
            (void)inb(KBDATAP);
            if (--t == 0)
                  return 1;
      }
      /* Send self-test */
      t = 20000;
      while (inb(KBSTATP) & KBOUTRDY)
            if (--t == 0)
                  return 2;
      outb(KBSTATP,0xAA);
      t = 200000;
      while ((inb(KBSTATP) & KBINRDY) == 0)     /* wait input ready */
            if (--t == 0)
                  return 3;
      if ((c = inb(KBDATAP)) != 0x55)
      {
            puts("Keyboard self test failed - result:");
            puthex(c);
            puts("\n");
      }
      /* Enable interrupts and keyboard controller */
      t = 20000;
      while (inb(KBSTATP) & KBOUTRDY)
            if (--t == 0) return 4;
      outb(KBSTATP,0x60);
      t = 20000;
      while (inb(KBSTATP) & KBOUTRDY)
            if (--t == 0) return 5;
      outb(KBDATAP,0x45);
      for (i = 0;  i < 10000;  i++) udelay(1);

      t = 20000;
      while (inb(KBSTATP) & KBOUTRDY)
            if (--t == 0) return 6;
      outb(KBSTATP,0x20);
      t = 200000;
      while ((inb(KBSTATP) & KBINRDY) == 0)     /* wait input ready */
            if (--t == 0) return 7;
      if (! (inb(KBDATAP) & 0x40)) {
            /*
             * Quote from PS/2 System Reference Manual:
             *
             * "Address hex 0060 and address hex 0064 should be
             * written only when the input-buffer-full bit and
             * output-buffer-full bit in the Controller Status
             * register are set 0." (KBINRDY and KBOUTRDY)
             */
            t = 200000;
            while (inb(KBSTATP) & (KBINRDY | KBOUTRDY))
                  if (--t == 0) return 8;
            outb(KBDATAP,0xF0);
            t = 200000;
            while (inb(KBSTATP) & (KBINRDY | KBOUTRDY))
                  if (--t == 0) return 9;
            outb(KBDATAP,0x01);
      }
      t = 20000;
      while (inb(KBSTATP) & KBOUTRDY)
            if (--t == 0) return 10;
      outb(KBSTATP,0xAE);
      return 0;
}

static void kbdreset(void)
{
      int ret = __kbdreset();

      if (ret) {
            puts("__kbdreset failed: ");
            puthex(ret);
            puts("\n");
      }
}

/* We have to actually read the keyboard when CRT_tstc is called,
 * since the pending data might be a key release code, and therefore
 * not valid data.  In this case, kbd() will return -1, even though there's
 * data to be read.  Of course, we might actually read a valid key press,
 * in which case it gets queued into key_pending for use by CRT_getc.
 */

static int kbd_reset = 0;

static int key_pending = -1;

int CRT_getc(void)
{
      int c;
      if (!kbd_reset) {kbdreset(); kbd_reset++; }

        if (key_pending != -1) {
                c = key_pending;
                key_pending = -1;
                return c;
        } else {
      while ((c = kbd(0)) == 0) ;
                return c;
        }
}

int CRT_tstc(void)
{
      if (!kbd_reset) {kbdreset(); kbd_reset++; }

        while (key_pending == -1 && ((inb(KBSTATP) & KBINRDY) != 0)) {
                key_pending = kbd(1);
        }

        return (key_pending != -1);
}

Generated by  Doxygen 1.6.0   Back to index