/*
pcboot - bootable PC demo/game kernel
-Copyright (C) 2018 John Tsiombikas <nuclear@member.fsf.org>
+Copyright (C) 2018-2019 John Tsiombikas <nuclear@member.fsf.org>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
+#include <stdio.h>
+#include <string.h>
#include "keyb.h"
#include "intr.h"
#include "asmops.h"
+#include "kbregs.h"
+#include "kbscan.h"
+#include "power.h"
+#include "panic.h"
-#define KB_IRQ 1
-#define KB_PORT 0x60
-
-/* table with rough translations from set 1 scancodes to ASCII-ish */
-static int scantbl[] = {
- 0, KB_ESC, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', /* 0 - e */
- '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', /* f - 1c */
- KB_LCTRL, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', /* 1d - 29 */
- KB_LSHIFT, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', KB_RSHIFT, /* 2a - 36 */
- KB_NUM_MUL, KB_LALT, ' ', KB_CAPSLK, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10, /* 37 - 44 */
- KB_NUMLK, KB_SCRLK, KB_NUM_7, KB_NUM_8, KB_NUM_9, KB_NUM_MINUS, KB_NUM_4, KB_NUM_5, KB_NUM_6, KB_NUM_PLUS, /* 45 - 4e */
- KB_NUM_1, KB_NUM_2, KB_NUM_3, KB_NUM_0, KB_NUM_DOT, KB_SYSRQ, 0, 0, KB_F11, KB_F12, /* 4d - 58 */
- 0, 0, 0, 0, 0, 0, 0, /* 59 - 5f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 70 - 7f */
-};
+#define delay7us() \
+ do { \
+ iodelay(); iodelay(); iodelay(); iodelay(); \
+ iodelay(); iodelay(); iodelay(); \
+ } while(0)
+
+static void set_ccb(unsigned char ccb);
+static unsigned char get_ccb(void);
static void kbintr();
static unsigned int num_pressed;
static unsigned char keystate[256];
+
void kb_init(void)
{
+ buf_ridx = buf_widx = 0;
+ num_pressed = 0;
+ memset(keystate, 0, sizeof keystate);
+
+ /* make sure set1 translation is enabled */
+ kb_set_translate(1);
+
interrupt(IRQ_TO_INTR(KB_IRQ), kbintr);
+ kb_intr_enable();
+}
+
+void kb_intr_enable(void)
+{
+ unsigned char ccb = get_ccb();
+ ccb |= KB_CCB_KB_INTREN;
+ set_ccb(ccb);
+}
+
+void kb_intr_disable(void)
+{
+ unsigned char ccb = get_ccb();
+ ccb &= ~KB_CCB_KB_INTREN;
+ set_ccb(ccb);
+}
+
+int kb_setmode(int mode)
+{
+ kb_send_data(0xf0);
+ if(!kb_wait_read() || kb_read_data() != KB_ACK) {
+ return -1;
+ }
+ kb_send_data(mode);
+ if(!kb_wait_read() || kb_read_data() != KB_ACK) {
+ return -1;
+ }
+ return 0;
+}
+
+int kb_getmode(void)
+{
+ int mode;
+
+ kb_send_data(0xf0);
+ if(!kb_wait_read() || kb_read_data() != KB_ACK) {
+ return -1;
+ }
+ kb_send_data(0);
+ if(!kb_wait_read() || kb_read_data() != KB_ACK) {
+ return -1;
+ }
+ mode = kb_read_data();
+
+ switch(mode) {
+ case 0x43: return 1;
+ case 0x41: return 2;
+ case 0x3f: return 3;
+ default:
+ break;
+ }
+ return mode;
+}
+
+void kb_set_translate(int xlat)
+{
+ unsigned char ccb = get_ccb();
+ if(xlat) {
+ ccb |= KB_CCB_KB_XLAT;
+ } else {
+ ccb &= ~KB_CCB_KB_XLAT;
+ }
+ set_ccb(ccb);
+}
+
+int kb_get_translate(void)
+{
+ return get_ccb() & KB_CCB_KB_XLAT;
}
int kb_isdown(int key)
buffer[buf_ridx] = key;
}
+int kb_wait_write(void)
+{
+ int i;
+ for(i=0; i<32768; i++) {
+ if(!(inb(KB_STATUS_PORT) & KB_STAT_INBUF_FULL)) {
+ return 1;
+ }
+ iodelay();
+ }
+ /*printf("kb_wait_write timeout\n");*/
+ return 0;
+}
+
+int kb_wait_read(void)
+{
+ int i;
+ for(i=0; i<32768; i++) {
+ if((inb(KB_STATUS_PORT) & KB_STAT_OUTBUF_FULL)) {
+ return 1;
+ }
+ iodelay();
+ }
+ /*printf("kb_wait_read timeout\n");*/
+ return 0;
+}
+
+void kb_send_cmd(unsigned char cmd)
+{
+ kb_wait_write();
+ outb(cmd, KB_CMD_PORT);
+}
+
+void kb_send_data(unsigned char data)
+{
+ kb_wait_write();
+ outb(data, KB_DATA_PORT);
+}
+
+unsigned char kb_read_data(void)
+{
+ kb_wait_read();
+ delay7us();
+ return inb(KB_DATA_PORT);
+}
+
+static void set_ccb(unsigned char ccb)
+{
+ kb_send_cmd(KB_CMD_SET_CMDBYTE);
+ kb_send_data(ccb);
+
+ if(kb_wait_read()) {
+ kb_read_data();
+ }
+}
+
+static unsigned char get_ccb(void)
+{
+ kb_send_cmd(KB_CMD_GET_CMDBYTE);
+ return kb_read_data();
+}
+
static void kbintr()
{
unsigned char code;
int key, press;
+ static int ext = 0;
+
+ code = inb(KB_DATA_PORT);
- code = inb(KB_PORT);
+ if(code == 0xe0) {
+ ext = 1;
+ return;
+ }
- if(code >= 128) {
+ if(code & 0x80) {
press = 0;
- code -= 128;
+ code &= 0x7f;
if(num_pressed > 0) {
num_pressed--;
num_pressed++;
}
- key = scantbl[code];
+ key = ext ? scantbl_set1_ext[code] : scantbl_set1[code];
+ ext = 0;
if(press) {
+ if(key == KB_DEL && (keystate[KB_LALT] || keystate[KB_RALT]) && (keystate[KB_LCTRL] || keystate[KB_RCTRL])) {
+ reboot();
+ }
/* append to buffer */
buffer[buf_widx] = key;
ADVANCE(buf_widx);