]> git.dujemihanovic.xyz Git - nameless-os.git/blob - kernel/drivers/input/ps2.c
365c0ceaf9179d2f6bd0bd60acc89e39786ec2da
[nameless-os.git] / kernel / drivers / input / ps2.c
1 #include <tty.h>
2 #include <io.h>
3 #include <input/ps2.h>
4 #include <bitflags.h>
5 #include <irq/interrupt.h>
6
7 static int was_released = 0, is_caps = 0;
8 static char buffer;
9
10 int ps2_keyb_handler()
11 {
12 uint8_t scancode = inb(PS2_DATA_PORT);
13 if (was_released) {
14 was_released = 0;
15 return 0;
16 }
17
18 if (scancode == 0xf0) {
19 was_released = 1;
20 uint8_t scancode = inb(PS2_DATA_PORT);
21 if (scancode == 0x12) {
22 is_caps = 0;
23 }
24 return 0;
25 } else {
26 if (scancode == 0x12) {
27 is_caps = 1;
28 return 0;
29 }
30 if (!is_caps) {
31 buffer = scancodes[scancode];
32 } else {
33 buffer = scancodes[scancode] - ('a'-'A');
34 }
35 }
36 return 0;
37 }
38
39 char ps2_get_keystroke()
40 {
41 buffer = 0;
42 while (!buffer);
43 return buffer;
44 }
45
46 int ps2_initialize()
47 {
48 uint8_t ccb, is_2channel, port_1_test, port_2_test;
49
50 kprint("ps2: Begin initializing PS/2 controller\n", 0);
51 outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_2_DISABLE);
52 ps2_input_wait();
53 outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_1_DISABLE);
54 ps2_input_wait();
55 inb(PS2_DATA_PORT);
56
57 outb(PS2_CMD_STS_PORT, PS2_CMD_READ_CCB);
58 ps2_output_wait();
59 ccb = inb(PS2_DATA_PORT);
60
61 CLEAR(ccb, 0);
62 CLEAR(ccb, 1);
63 CLEAR(ccb, 6);
64
65 ps2_input_wait();
66 outb(PS2_CMD_STS_PORT, PS2_CMD_WRITE_CCB);
67 ps2_input_wait();
68 outb(PS2_DATA_PORT, ccb);
69
70 ps2_input_wait();
71 outb(PS2_CMD_STS_PORT, PS2_CMD_CONTROLLER_TEST);
72 ps2_output_wait();
73 if (inb(PS2_DATA_PORT) != PS2_CONTROLLER_GOOD) {
74 kprint("ps2: Controller self test failed, exiting!\n", 0);
75 return -1;
76 };
77
78 ps2_input_wait();
79 outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_2_ENABLE);
80 ps2_input_wait();
81 outb(PS2_CMD_STS_PORT, PS2_CMD_READ_CCB);
82 ps2_output_wait();
83 ccb = inb(PS2_DATA_PORT);
84
85 if (ccb & PORT_2_CLK != PORT_2_CLK) {
86 is_2channel = 0;
87 kprint("ps2: Controller is single-channel\n", 0);
88 } else {
89 is_2channel = 1;
90 kprint("ps2: Controller is dual-channel\n", 0);
91 ps2_input_wait();
92 outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_2_DISABLE);
93 }
94
95 ps2_input_wait();
96 outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_1_TEST);
97 ps2_output_wait();
98
99 if (inb(PS2_DATA_PORT) != 0) {
100 port_1_test = 0;
101 kprint("ps2: Port 1 test failed!\n", 0);
102 if (!is_2channel) {
103 kprint("ps2: No functional port, exiting!\n", 0);
104 return -1;
105 }
106 } else port_1_test = 1;
107
108 ps2_input_wait();
109 if (is_2channel) {
110 outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_2_TEST);
111 ps2_output_wait();
112
113 if (inb(PS2_DATA_PORT) != 0) {
114 port_2_test = 0;
115 kprint("ps2: Port 2 test failed!", 0);
116 if (!port_1_test) {
117 kprint("ps2: No functional port, exiting!\n", 0);
118 return -1;
119 }
120 } else port_2_test = 1;
121 }
122
123 if (port_1_test) { ps2_input_wait(); outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_1_ENABLE); }
124 if (port_2_test) { ps2_input_wait(); outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_2_ENABLE); }
125
126 int dev_1_test, dev_2_test;
127
128 if (port_1_test) {
129 uint8_t resp;
130
131 do {
132 ps2_input_wait();
133 outb(PS2_DATA_PORT, PS2_DEV_RESET);
134 ps2_output_wait();
135 resp = inb(PS2_DATA_PORT);
136 } while (resp == RESEND);
137
138 if (resp == SELF_TEST_BAD || resp == SELF_TEST_BAD_2) {
139 dev_1_test = 0;
140 kprint("ps2: Port 1 device self test failed!\n", 0);
141 if (!port_2_test) {
142 kprint("ps2: No functioning devices, exiting!\n", 0);
143 return -1;
144 }
145 } else { dev_1_test = 1; kprint("ps2: Port 1 device test successful\n", 0); }
146 }
147
148 inb(PS2_DATA_PORT);
149 ps2_input_wait();
150
151 if (port_2_test) {
152 uint8_t resp;
153
154 do {
155 ps2_input_wait();
156 outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_2_WRITE);
157 ps2_input_wait();
158 outb(PS2_DATA_PORT, PS2_DEV_RESET);
159 ps2_output_wait();
160 resp = inb(PS2_DATA_PORT);
161 } while (resp == RESEND);
162
163 if (resp == SELF_TEST_BAD || resp == SELF_TEST_BAD_2) {
164 dev_2_test = 0;
165 kprint("ps2: Port 2 device self test failed!\n", 0);
166 if (!dev_1_test) {
167 kprint("ps2: No functioning devices, exiting!\n", 0);
168 return -1;
169 }
170 } else { dev_2_test = 1; kprint("ps2: Port 2 device test successful\n", 0); }
171 }
172
173 inb(PS2_DATA_PORT);
174 inb(PS2_DATA_PORT);
175 ps2_input_wait();
176 outb(PS2_CMD_STS_PORT, PS2_CMD_READ_CCB);
177 ps2_output_wait();
178 ccb = inb(PS2_DATA_PORT);
179
180 SET(ccb, PORT_1_IRQ);
181
182 ps2_input_wait();
183 outb(PS2_CMD_STS_PORT, PS2_CMD_WRITE_CCB);
184 ps2_input_wait();
185 outb(PS2_DATA_PORT, ccb);
186
187 if (dev_1_test) register_interrupt(33, &ps2_keyb_handler);
188
189 if (dev_2_test && dev_1_test) return 1;
190 else return 0;
191 }
192
193 void ps2_output_wait()
194 {
195 uint8_t status;
196 status = inb(PS2_CMD_STS_PORT);
197
198 while (!IS_SET(status, OUT_STATUS)) status = inb(PS2_CMD_STS_PORT);
199 return;
200 }
201
202 void ps2_input_wait()
203 {
204 uint8_t status;
205 status = inb(PS2_CMD_STS_PORT);
206
207 while (IS_SET(status, IN_STATUS)) status = inb(PS2_CMD_STS_PORT);
208 return;
209 }