1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <console/console.h>
24#include <pc80/keyboard.h>
25#include <device/device.h>
26#include <arch/io.h>
27#include <delay.h>
28
29#define KBD_DATA 0x60
30#define KBD_COMMAND 0x64
31#define KBD_STATUS 0x64
32#define KBD_IBF (1 << 1)
33#define KBD_OBF (1 << 0)
34
35
36#define KBC_CMD_READ_COMMAND 0x20
37#define KBC_CMD_WRITE_COMMAND 0x60
38#define KBC_CMD_SELF_TEST 0xAA
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54#define KBC_REPLY_SELFTEST_OK 0x55
55
56
57
58
59#define KBD_REPLY_POR 0xAA
60#define KBD_REPLY_ACK 0xFA
61#define KBD_REPLY_RESEND 0xFE
62
63
64#define KBC_TIMEOUT_IN_MS 200
65
66static int kbc_input_buffer_empty(void)
67{
68 u32 timeout;
69 for(timeout = KBC_TIMEOUT_IN_MS; timeout && (inb(KBD_STATUS) & KBD_IBF); timeout--) {
70 mdelay(1);
71 }
72
73 if (!timeout) {
74 printk_warning("Unexpected Keyboard controller input buffer full\n");
75 }
76 return !!timeout;
77}
78
79
80static int kbc_output_buffer_full(void)
81{
82 u32 timeout;
83 for(timeout = KBC_TIMEOUT_IN_MS; timeout && ((inb(KBD_STATUS) & KBD_OBF) == 0); timeout--) {
84 mdelay(1);
85 }
86
87 if (!timeout) {
88 printk_warning("Keyboard controller output buffer result timeout\n");
89 }
90 return !!timeout;
91}
92
93
94static int kbc_cleanup_buffers(void)
95{
96 u32 timeout;
97 for(timeout = KBC_TIMEOUT_IN_MS; timeout && (inb(KBD_STATUS) & (KBD_OBF | KBD_IBF)); timeout--) {
98 mdelay(1);
99 inb(KBD_DATA);
100 }
101
102 if (!timeout) {
103 printk_err("Couldn't cleanup the keyboard controller buffers\n");
104 printk_err("Status (0x%x): 0x%x, Buffer (0x%x): 0x%x\n",
105 KBD_STATUS, inb(KBD_STATUS), KBD_DATA, inb(KBD_DATA));
106 }
107
108 return !!timeout;
109}
110
111static int kbc_self_test(void)
112{
113 u8 self_test;
114
115
116
117
118 if (!kbc_cleanup_buffers())
119 return 0;
120
121
122 outb(KBC_CMD_SELF_TEST, KBD_COMMAND);
123
124 if (!kbc_output_buffer_full()) {
125
126 printk_err("Could not reset keyboard controller.\n");
127 return 0;
128 }
129
130
131 self_test = inb(KBD_DATA);
132
133 if (self_test != 0x55) {
134 printk_err("Keyboard Controller self-test failed: 0x%x\n",
135 self_test);
136 return 0;
137 }
138
139 return 1;
140}
141
142static u8 send_keyboard(u8 command)
143{
144 u8 regval = 0;
145 u8 resend = 10;
146
147 do {
148 if (!kbc_input_buffer_empty()) return 0;
149 outb(command, KBD_DATA);
150 if (!kbc_output_buffer_full()) {
151 printk_err("Could not send keyboard command %02x\n",
152 command);
153 return 0;
154 }
155 regval = inb(KBD_DATA);
156 --resend;
157 } while (regval == 0xFE && resend > 0);
158
159 return regval;
160}
161
162static void pc_keyboard_init(struct pc_keyboard *keyboard)
163{
164 u8 regval;
165 printk_debug("Keyboard init...\n");
166
167
168 if (!kbc_self_test())
169 return;
170
171
172 if (!kbc_input_buffer_empty()) return;
173 outb(0x60, KBD_COMMAND);
174 if (!kbc_input_buffer_empty()) return;
175 outb(0x20, KBD_DATA);
176 if (!kbc_input_buffer_empty()) {
177 printk_info("Timeout while enabling keyboard\n");
178 return;
179 }
180
181
182 if (!kbc_cleanup_buffers()) return;
183
184
185 regval = send_keyboard(0xFF);
186 if (regval != 0xFA) {
187 printk_err("Keyboard selftest failed ACK: 0x%x\n", regval);
188 return;
189 }
190
191 if (!kbc_output_buffer_full()) {
192 printk_err("Timeout waiting for keyboard after reset.\n");
193 return;
194 }
195
196 regval = inb(KBD_DATA);
197 if (regval != 0xAA) {
198 printk_err("Keyboard selftest failed: 0x%x\n", regval);
199 return;
200 }
201
202
203
204
205
206
207
208 regval = send_keyboard(0xF5);
209 if (regval != 0xFA) {
210 printk_err("Keyboard disable failed ACK: 0x%x\n", regval);
211 return;
212 }
213
214
215 regval = send_keyboard(0xF0);
216 if (regval != 0xFA) {
217 printk_err("Keyboard set scancode cmd failed ACK: 0x%x\n", regval);
218 return;
219 }
220
221 regval = send_keyboard(0x02);
222 if (regval != 0xFA) {
223 printk_err("Keyboard set scancode mode failed ACK: 0x%x\n", regval);
224 return;
225 }
226
227
228 regval = send_keyboard(0xF4);
229 if (regval != 0xFA) {
230 printk_err("Keyboard enable failed ACK: 0x%x\n", regval);
231 return;
232 }
233
234
235 if (!kbc_input_buffer_empty()) return;
236 outb(0x60, KBD_COMMAND);
237 if (!kbc_input_buffer_empty()) return;
238 outb(0x61, KBD_DATA);
239 if (kbc_output_buffer_full()) {
240 printk_err("Timeout during final keyboard enable\n");
241 return;
242 }
243}
244
245
246void init_pc_keyboard(unsigned port0, unsigned port1, struct pc_keyboard *kbd)
247{
248 if ((port0 == 0x60) && (port1 == 0x64)) {
249 pc_keyboard_init(kbd);
250 } else {
251 printk_warning("Unsupported keyboard controller.\n");
252 }
253}
254
255
256
257
258
259
260void set_kbc_ps2_mode(void)
261{
262
263 if (!kbc_self_test())
264 return;
265
266
267 if (!kbc_input_buffer_empty()) return;
268 outb(0xcb, KBD_COMMAND);
269
270 if (!kbc_input_buffer_empty()) return;
271 outb(0x01, KBD_DATA);
272
273 kbc_cleanup_buffers();
274}
275