summaryrefslogtreecommitdiff
path: root/kernel/src/arch/i686/drivers/ps2kb.c
blob: 50bdfb6609e6ffffc9e7124a9689eb7a447f3c68 (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
#include <panic.h>
#include <arch/i686/drivers/ps2ctrl.h>
#include <arch/i686/pic.h>
#include <arch/i686/asm.h>
#include <drivers/ps2kb.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) {

	is_init = false;
	pic_mask(1);

	uint8_t result;

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

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

	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;
}