linux/arch/e2k/boot/keyboard.c

250 lines
5.1 KiB
C

/*
* Adopted from Linux/PPC port.
*/
#include <linux/keyboard.h>
#include <linux/types.h>
#include "defkeymap.c"
#include "boot_io.h"
#include "bios/printk.h"
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
static void kbd_outb(u16 port, u8 byte)
{
NATIVE_WRITE_MAS_B(PHYS_X86_IO_BASE + port, byte, MAS_IOADDR);
}
static u8 kbd_inb(u16 port)
{
// u8 *addr = (u8 *) E2K_X86_IO_BASE;
// return *(addr + port);
return NATIVE_READ_MAS_B(PHYS_X86_IO_BASE + port, MAS_IOADDR);
}
static void kbd_udelay(int delay) /* Valid for LMS keyboard only */
{
int i;
for (i=0; i<delay; i++);
}
static int kbd(int noblock)
{
unsigned char dt, brk, val;
unsigned code;
loop:
if (noblock) {
if ((kbd_inb(KBSTATP) & KBINRDY) == 0)
return -1;
} else while((kbd_inb(KBSTATP) & KBINRDY) == 0) ;
dt = kbd_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((kbd_inb(KBSTATP) & KBINRDY) == 0) ;
dt = kbd_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 void kbdreset(void)
{
unsigned char c;
int i;
/* flush input queue */
while ((kbd_inb(KBSTATP) & KBINRDY))
{
(void)kbd_inb(KBDATAP);
}
/* Send self-test */
while (kbd_inb(KBSTATP) & KBOUTRDY) ;
kbd_outb(KBSTATP,0xAA);
while ((kbd_inb(KBSTATP) & KBINRDY) == 0) ; /* wait input ready */
if ((c = kbd_inb(KBDATAP)) != 0x55)
{
rom_puts("Keyboard self test failed - result:");
rom_printk("%x",c);
rom_puts("\n");
}
/* Enable interrupts and keyboard controller */
while (kbd_inb(KBSTATP) & KBOUTRDY) ;
kbd_outb(KBSTATP,0x60);
while (kbd_inb(KBSTATP) & KBOUTRDY) ;
kbd_outb(KBDATAP,0x45);
for (i = 0; i < 10000; i++) kbd_udelay(1);
while (kbd_inb(KBSTATP) & KBOUTRDY) ;
kbd_outb(KBSTATP,0x20);
while ((kbd_inb(KBSTATP) & KBINRDY) == 0) ; /* wait input ready */
if (! (kbd_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)
*/
while (kbd_inb(KBSTATP) & (KBINRDY | KBOUTRDY)) ;
kbd_outb(KBDATAP,0xF0);
while (kbd_inb(KBSTATP) & (KBINRDY | KBOUTRDY)) ;
kbd_outb(KBDATAP,0x01);
}
while (kbd_inb(KBSTATP) & KBOUTRDY) ;
kbd_outb(KBSTATP,0xAE);
}
/* 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 kbd_reset = 1; /* keayboard is already initiated by LMS */
static int key_pending = -1;
static 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;
}
}
static int CRT_tstc(void)
{
if (!kbd_reset) {kbdreset(); kbd_reset++; }
while (key_pending == -1 && ((kbd_inb(KBSTATP) & KBINRDY) != 0)) {
key_pending = kbd(1);
kbd_udelay(1000);
}
return key_pending != -1;
}
int keyb_tstc(void)
{
return CRT_tstc();
}
int keyb_getc(void)
{
while (1) {
if (CRT_tstc()) return CRT_getc();
}
}