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