summaryrefslogtreecommitdiff
path: root/kernel/src/drivers/ps2kb.c
blob: dec0b8773a2093eda0478e146b93d59e5dd4baa6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include <panic.h>
#include <sys.h>

#include "print.h"
#include "ps2kb.h"
#include "ps2ctrl.h"
#include "interrupt/pic.h"

#define BUFFER_LEN 16

#define KEYCODE_ARRAY_LEN 0x84

static uint8_t scancodes[] = {
//    	00/08          01/09          02/0A        03/0B         04/0C            05/0D          06/0E            07/0F
/*00*/	KEY_NONE,      KEY_F9,        KEY_NONE,    KEY_F5,       KEY_F3,          KEY_F1,        KEY_F2,          KEY_F12,
/*08*/	KEY_NONE,      KEY_F10,       KEY_F8,      KEY_F6,       KEY_F4,          KEY_TAB,       KEY_BACKTICK,    KEY_NONE,
/*10*/	KEY_NONE,      KEY_L_ALT,     KEY_L_SHIFT, KEY_NONE,     KEY_L_CTRL,      KEY_Q,         KEY_1,           KEY_NONE,
/*18*/	KEY_NONE,      KEY_NONE,      KEY_Z,       KEY_S,        KEY_A,           KEY_W,         KEY_2,           KEY_NONE,
/*20*/	KEY_NONE,      KEY_C,         KEY_X,       KEY_D,        KEY_E,           KEY_4,         KEY_3,           KEY_NONE,
/*28*/	KEY_NONE,      KEY_SPACE,     KEY_V,       KEY_F,        KEY_T,           KEY_R,         KEY_5,           KEY_NONE,
/*30*/	KEY_NONE,      KEY_N,         KEY_B,       KEY_H,        KEY_G,           KEY_Y,         KEY_6,           KEY_NONE,
/*38*/	KEY_NONE,      KEY_NONE,      KEY_M,       KEY_J,        KEY_U,           KEY_7,         KEY_8,           KEY_NONE,
/*40*/	KEY_NONE,      KEY_COMMA,     KEY_K,       KEY_I,        KEY_O,           KEY_0,         KEY_9,           KEY_NONE,
/*48*/	KEY_NONE,      KEY_PERIOD,    KEY_SLASH,   KEY_L,        KEY_SEMICOLON,   KEY_P,         KEY_MINUS,       KEY_NONE,
/*50*/	KEY_NONE,      KEY_NONE,      KEY_QUOTE,   KEY_NONE,     KEY_L_BRACE,     KEY_EQUAL,     KEY_NONE,        KEY_NONE,
/*58*/	KEY_CAPS_LOCK, KEY_R_SHIFT,   KEY_ENTER,   KEY_R_BRACE,  KEY_NONE,        KEY_BACKSLASH, KEY_NONE,        KEY_NONE,
/*60*/	KEY_NONE,      KEY_NONE,      KEY_NONE,    KEY_NONE,     KEY_NONE,        KEY_NONE,      KEY_BACKSPACE,   KEY_NONE,
/*68*/	KEY_NONE,      KEY_NP_1,      KEY_NONE,    KEY_NP_4,     KEY_NP_7,        KEY_NONE,      KEY_NONE,        KEY_NONE,
/*70*/	KEY_NP_0,      KEY_NP_PERIOD, KEY_NP_2,    KEY_NP_5,     KEY_NP_6,        KEY_NP_8,      KEY_ESCAPE,      KEY_NUM_LOCK,
/*78*/	KEY_F11,       KEY_NP_PLUS,   KEY_NP_3,    KEY_NP_MINUS, KEY_NP_ASTERISK, KEY_NP_9,      KEY_SCROLL_LOCK, KEY_NONE,
/*80*/	KEY_NONE,      KEY_NONE,      KEY_NONE,    KEY_F7,
};
static uint8_t scancodes_ext[] = {
//    	00/08        01/09        02/0A             03/0B        04/0C        05/0D        06/0E        07/0F
/*00*/	KEY_NONE,    KEY_NONE,    KEY_NONE,         KEY_NONE,    KEY_NONE,    KEY_NONE,    KEY_NONE,    KEY_NONE,
/*08*/	KEY_NONE,    KEY_NONE,    KEY_NONE,         KEY_NONE,    KEY_NONE,    KEY_NONE,    KEY_NONE,    KEY_NONE,
/*10*/	KEY_UNKNOWN, KEY_R_ALT,   KEY_PRINT_SCREEN, KEY_NONE,    KEY_R_CTRL,  KEY_UNKNOWN, KEY_NONE,    KEY_NONE,
/*18*/	KEY_UNKNOWN, KEY_NONE,    KEY_NONE,         KEY_NONE,    KEY_NONE,    KEY_NONE,    KEY_NONE,    KEY_L_META,
/*20*/	KEY_UNKNOWN, KEY_UNKNOWN, KEY_NONE,         KEY_UNKNOWN, KEY_NONE,    KEY_NONE,    KEY_NONE,    KEY_R_META,
/*28*/	KEY_UNKNOWN, KEY_NONE,    KEY_NONE,         KEY_UNKNOWN, KEY_NONE,    KEY_NONE,    KEY_NONE,    KEY_MENU,
/*30*/	KEY_UNKNOWN, KEY_NONE,    KEY_UNKNOWN,      KEY_NONE,    KEY_UNKNOWN, KEY_NONE,    KEY_NONE,    KEY_UNKNOWN,
/*38*/	KEY_UNKNOWN, KEY_NONE,    KEY_UNKNOWN,      KEY_UNKNOWN, KEY_NONE,    KEY_NONE,    KEY_NONE,    KEY_UNKNOWN,
/*40*/	KEY_UNKNOWN, KEY_NONE,    KEY_NONE,         KEY_NONE,    KEY_NONE,    KEY_NONE,    KEY_NONE,    KEY_NONE,
/*48*/	KEY_UNKNOWN, KEY_NONE,    KEY_NP_SLASH,     KEY_NONE,    KEY_NONE,    KEY_UNKNOWN, KEY_NONE,    KEY_NONE,
/*50*/	KEY_UNKNOWN, KEY_NONE,    KEY_NONE,         KEY_NONE,    KEY_NONE,    KEY_NONE,    KEY_NONE,    KEY_NONE,
/*58*/	KEY_NONE,    KEY_NONE,    KEY_NP_ENTER,     KEY_NONE,    KEY_NONE,    KEY_NONE,    KEY_UNKNOWN, KEY_NONE,
/*60*/	KEY_NONE,    KEY_NONE,    KEY_NONE,         KEY_NONE,    KEY_NONE,    KEY_NONE,    KEY_NONE,    KEY_NONE,
/*68*/	KEY_NONE,    KEY_END,     KEY_NONE,         KEY_LEFT,    KEY_HOME,    KEY_NONE,    KEY_NONE,    KEY_NONE,
/*70*/	KEY_INSERT,  KEY_DELETE,  KEY_DOWN,         KEY_NONE,    KEY_RIGHT,   KEY_UP,      KEY_NONE,    KEY_NONE,
/*78*/	KEY_NONE,    KEY_NONE,    KEY_PAGE_DOWN,    KEY_NONE,    KEY_NONE,    KEY_PAGE_UP, KEY_NONE,    KEY_NONE,
/*80*/	KEY_NONE,    KEY_NONE,    KEY_NONE,         KEY_NONE,    KEY_NONE,    KEY_NONE,    KEY_NONE,    KEY_NONE,
};

static struct Keycode last_keycode;

static bool is_init = false;
static bool state_keyup = false;
static bool state_ext = false;

void ps2kb_init(void) {

    debugk("Loading PS/2 Keyboard");

	is_init = false;
	pic_mask(1);

	uint8_t result;

	ps2ctrl_out_data(0xFF);
	result = ps2ctrl_in();
	if(result != 0xFA) {
		errork("Failed to reset PS/2 keyboard: expected 0xFA, got 0x%X\n", result);
        return;
	}
	result = ps2ctrl_in();
	if(result != 0xAA) {
		errork("Failed to reset PS/2 keyboard: expected 0xAA, got 0x%X\n", result);
        return;
	}

	ps2ctrl_out_data(0xF4);
	result = ps2ctrl_in();
	if(result != 0xFA) {
	    errork("Failed to enable PS/2 keyboard: expected 0xFA, got 0x%X\n", result);
        return;
	}

    succek("PS/2 Keyboard has has been loaded");

	pic_unmask(1);
	is_init = true;
}

void ps2kb_recv(void) {
	if(!ps2ctrl_is_init() || !is_init) {
		inb(0x60);
		return;
	}
	uint8_t code = ps2ctrl_in();
	if (code == 0x00 || code == 0x0F) {
		last_keycode.key = KEY_NONE;
		last_keycode.flags = KC_FLAG_ERROR;
	} else if(code == 0xF0) {
		state_keyup = true;
	} else if(code == 0xE0) {
		state_ext = true;
	} else if(code <= KEYCODE_ARRAY_LEN) {
		uint8_t *scancode_table = state_ext ? scancodes_ext : scancodes;
		uint8_t keycode = scancode_table[code];
		if(keycode != KEY_NONE) {
			last_keycode.key = keycode;
			last_keycode.flags = state_keyup ? KC_FLAG_KEY_UP : KC_FLAG_KEY_DOWN;
		}
		state_keyup = false;
		state_ext = false;
	}
}

struct Keycode ps2kb_get(void) {
	struct Keycode code;
	if(is_init) {
		code = last_keycode;
	} else {
		code.key = KEY_NONE;
		code.flags = KC_FLAG_ERROR;
	}
	last_keycode.key = KEY_NONE;
	last_keycode.flags = 0;
	return code;
}