329 lines
6.9 KiB
C
329 lines
6.9 KiB
C
|
/*
|
||
|
* Copyright (C) 2003, 2004 Stefan Reinauer
|
||
|
*
|
||
|
* See the file "COPYING" for further information about
|
||
|
* the copyright and warranty status of this work.
|
||
|
*/
|
||
|
|
||
|
#include "config.h"
|
||
|
#include "libopenbios/bindings.h"
|
||
|
#include "kernel/kernel.h"
|
||
|
#include "drivers/drivers.h"
|
||
|
#include "libc/vsprintf.h"
|
||
|
|
||
|
/* ******************************************************************
|
||
|
* simple polling video/keyboard console functions
|
||
|
* ****************************************************************** */
|
||
|
|
||
|
#define SER_SIZE 8
|
||
|
|
||
|
/*
|
||
|
* keyboard driver
|
||
|
*/
|
||
|
|
||
|
static const char normal[] = {
|
||
|
0x0, 0x1b, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-',
|
||
|
'=', '\b', '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o',
|
||
|
'p', '[', ']', 0xa, 0x0, 'a', 's', 'd', 'f', 'g', 'h', 'j',
|
||
|
'k', 'l', ';', 0x27, 0x60, 0x0, 0x5c, 'z', 'x', 'c', 'v', 'b',
|
||
|
'n', 'm', ',', '.', '/', 0x0, '*', 0x0, ' ', 0x0, 0x0, 0x0,
|
||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, '0', 0x7f
|
||
|
};
|
||
|
|
||
|
static const char shifted[] = {
|
||
|
0x0, 0x1b, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_',
|
||
|
'+', '\b', '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O',
|
||
|
'P', '{', '}', 0xa, 0x0, 'A', 'S', 'D', 'F', 'G', 'H', 'J',
|
||
|
'K', 'L', ':', 0x22, '~', 0x0, '|', 'Z', 'X', 'C', 'V', 'B',
|
||
|
'N', 'M', '<', '>', '?', 0x0, '*', 0x0, ' ', 0x0, 0x0, 0x0,
|
||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, '7', '8',
|
||
|
'9', 0x0, '4', '5', '6', 0x0, '1', '2', '3', '0', 0x7f
|
||
|
};
|
||
|
|
||
|
static int key_ext;
|
||
|
static int key_lshift = 0, key_rshift = 0, key_caps = 0;
|
||
|
|
||
|
static char last_key;
|
||
|
|
||
|
static void pc_kbd_cmd(unsigned char cmd, unsigned char val)
|
||
|
{
|
||
|
outb(cmd, 0x60);
|
||
|
/* wait until keyboard controller accepts cmds: */
|
||
|
while (inb(0x64) & 2);
|
||
|
outb(val, 0x60);
|
||
|
while (inb(0x64) & 2);
|
||
|
}
|
||
|
|
||
|
static void pc_kbd_controller_cmd(unsigned char cmd, unsigned char val)
|
||
|
{
|
||
|
outb(cmd, 0x64);
|
||
|
/* wait until keyboard controller accepts cmds: */
|
||
|
while (inb(0x64) & 2);
|
||
|
outb(val, 0x60);
|
||
|
while (inb(0x64) & 2);
|
||
|
}
|
||
|
|
||
|
static char pc_kbd_poll(void)
|
||
|
{
|
||
|
unsigned int c;
|
||
|
if (inb(0x64) & 1) {
|
||
|
c = inb(0x60);
|
||
|
switch (c) {
|
||
|
case 0xe0:
|
||
|
key_ext = 1;
|
||
|
return 0;
|
||
|
case 0x2a:
|
||
|
key_lshift = 1;
|
||
|
return 0;
|
||
|
case 0x36:
|
||
|
key_rshift = 1;
|
||
|
return 0;
|
||
|
case 0xaa:
|
||
|
key_lshift = 0;
|
||
|
return 0;
|
||
|
case 0xb6:
|
||
|
key_rshift = 0;
|
||
|
return 0;
|
||
|
case 0x3a:
|
||
|
if (key_caps) {
|
||
|
key_caps = 0;
|
||
|
pc_kbd_cmd(0xed, 0);
|
||
|
} else {
|
||
|
key_caps = 1;
|
||
|
pc_kbd_cmd(0xed, 4); /* set caps led */
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (key_ext) {
|
||
|
// void printk(const char *format, ...);
|
||
|
printk("extended keycode: %x\n", c);
|
||
|
|
||
|
key_ext = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (c & 0x80) /* unhandled key release */
|
||
|
return 0;
|
||
|
|
||
|
if (key_lshift || key_rshift)
|
||
|
return key_caps ? normal[c] : shifted[c];
|
||
|
else
|
||
|
return key_caps ? shifted[c] : normal[c];
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int pc_kbd_dataready(void)
|
||
|
{
|
||
|
if (last_key)
|
||
|
return 1;
|
||
|
|
||
|
last_key = pc_kbd_poll();
|
||
|
|
||
|
return (last_key != 0);
|
||
|
}
|
||
|
|
||
|
unsigned char pc_kbd_readdata(void)
|
||
|
{
|
||
|
char tmp;
|
||
|
while (!pc_kbd_dataready());
|
||
|
tmp = last_key;
|
||
|
last_key = 0;
|
||
|
return tmp;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pc_kbd_reset(void)
|
||
|
{
|
||
|
/* Reset first port */
|
||
|
outb(0xae, 0x64);
|
||
|
while (inb(0x64) & 2);
|
||
|
|
||
|
/* Write mode command, translated mode */
|
||
|
pc_kbd_controller_cmd(0x60, 0x40);
|
||
|
|
||
|
/* Reset keyboard device */
|
||
|
outb(0xff, 0x60);
|
||
|
while (inb(0x64) & 2);
|
||
|
inb(0x60); /* Should be 0xfa */
|
||
|
while (inb(0x64) & 2);
|
||
|
inb(0x60); /* Should be 0xaa */
|
||
|
}
|
||
|
|
||
|
/* ( addr len -- actual ) */
|
||
|
static void
|
||
|
pc_kbd_read(void)
|
||
|
{
|
||
|
unsigned char *addr;
|
||
|
int len;
|
||
|
|
||
|
len = POP();
|
||
|
addr = (unsigned char *)POP();
|
||
|
|
||
|
if (len != 1)
|
||
|
printk("pc_kbd_read: bad len, addr %lx len %x\n", (unsigned long)addr, len);
|
||
|
|
||
|
if (pc_kbd_dataready()) {
|
||
|
*addr = pc_kbd_readdata();
|
||
|
PUSH(1);
|
||
|
} else {
|
||
|
PUSH(0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pc_kbd_close(void)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pc_kbd_open(unsigned long *address)
|
||
|
{
|
||
|
PUSH(find_ih_method("address", my_self()));
|
||
|
fword("execute");
|
||
|
*address = POP();
|
||
|
|
||
|
RET ( -1 );
|
||
|
}
|
||
|
|
||
|
DECLARE_UNNAMED_NODE(pc_kbd, 0, sizeof(unsigned long));
|
||
|
|
||
|
NODE_METHODS(pc_kbd) = {
|
||
|
{ "open", pc_kbd_open },
|
||
|
{ "close", pc_kbd_close },
|
||
|
{ "read", pc_kbd_read },
|
||
|
};
|
||
|
|
||
|
void
|
||
|
ob_pc_kbd_init(const char *path, const char *kdev_name, const char *mdev_name,
|
||
|
uint64_t base, uint64_t offset, int kintr, int mintr)
|
||
|
{
|
||
|
phandle_t chosen, aliases;
|
||
|
char nodebuff[128];
|
||
|
|
||
|
fword("new-device");
|
||
|
|
||
|
push_str("8042");
|
||
|
fword("device-type");
|
||
|
|
||
|
push_str("8042");
|
||
|
fword("device-name");
|
||
|
|
||
|
/* Make openable */
|
||
|
fword("is-open");
|
||
|
|
||
|
PUSH((base + offset) >> 32);
|
||
|
fword("encode-int");
|
||
|
PUSH((base + offset) & 0xffffffff);
|
||
|
fword("encode-int");
|
||
|
fword("encode+");
|
||
|
PUSH(SER_SIZE);
|
||
|
fword("encode-int");
|
||
|
fword("encode+");
|
||
|
|
||
|
if (mdev_name != NULL) {
|
||
|
PUSH((base + offset) >> 32);
|
||
|
fword("encode-int");
|
||
|
fword("encode+");
|
||
|
PUSH((base + offset) & 0xffffffff);
|
||
|
fword("encode-int");
|
||
|
fword("encode+");
|
||
|
PUSH(SER_SIZE);
|
||
|
fword("encode-int");
|
||
|
fword("encode+");
|
||
|
}
|
||
|
|
||
|
push_str("reg");
|
||
|
fword("property");
|
||
|
|
||
|
chosen = get_cur_dev();
|
||
|
set_int_property(chosen, "#address-cells", 1);
|
||
|
set_int_property(chosen, "#size-cells", 0);
|
||
|
|
||
|
PUSH(kintr);
|
||
|
fword("encode-int");
|
||
|
|
||
|
if (mdev_name != NULL) {
|
||
|
PUSH(mintr);
|
||
|
fword("encode-int");
|
||
|
fword("encode+");
|
||
|
}
|
||
|
|
||
|
push_str("interrupts");
|
||
|
fword("property");
|
||
|
|
||
|
/* Keyboard */
|
||
|
fword("new-device");
|
||
|
|
||
|
push_str(kdev_name);
|
||
|
fword("device-name");
|
||
|
|
||
|
push_str("serial");
|
||
|
fword("device-type");
|
||
|
|
||
|
PUSH(0);
|
||
|
fword("encode-int");
|
||
|
push_str("reg");
|
||
|
fword("property");
|
||
|
|
||
|
PUSH(-1);
|
||
|
fword("encode-int");
|
||
|
push_str("keyboard");
|
||
|
fword("property");
|
||
|
|
||
|
PUSH(offset);
|
||
|
fword("encode-int");
|
||
|
push_str("address");
|
||
|
fword("property");
|
||
|
|
||
|
BIND_NODE_METHODS(get_cur_dev(), pc_kbd);
|
||
|
|
||
|
PUSH(offset);
|
||
|
feval("value address");
|
||
|
|
||
|
fword("finish-device");
|
||
|
|
||
|
snprintf(nodebuff, sizeof(nodebuff), "%s/8042/%s", path, kdev_name);
|
||
|
chosen = find_dev("/chosen");
|
||
|
push_str(nodebuff);
|
||
|
fword("open-dev");
|
||
|
set_int_property(chosen, "keyboard", POP());
|
||
|
|
||
|
aliases = find_dev("/aliases");
|
||
|
set_property(aliases, "keyboard", nodebuff, strlen(nodebuff) + 1);
|
||
|
|
||
|
pc_kbd_reset();
|
||
|
|
||
|
/* Mouse (optional) */
|
||
|
if (mdev_name != NULL) {
|
||
|
fword("new-device");
|
||
|
|
||
|
push_str(mdev_name);
|
||
|
fword("device-name");
|
||
|
|
||
|
push_str("mouse");
|
||
|
fword("device-type");
|
||
|
|
||
|
PUSH(1);
|
||
|
fword("encode-int");
|
||
|
push_str("reg");
|
||
|
fword("property");
|
||
|
|
||
|
PUSH(-1);
|
||
|
fword("encode-int");
|
||
|
push_str("mouse");
|
||
|
fword("property");
|
||
|
|
||
|
PUSH(offset);
|
||
|
fword("encode-int");
|
||
|
push_str("address");
|
||
|
fword("property");
|
||
|
|
||
|
fword("finish-device");
|
||
|
}
|
||
|
|
||
|
fword("finish-device");
|
||
|
}
|