Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / qemu-palcode / ps2port.c
1 // Support for handling the PS/2 mouse/keyboard ports.
2 //
3 // Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
4 // Several ideas taken from code Copyright (c) 1999-2004 Vojtech Pavlik
5 //
6 // This file may be distributed under the terms of the GNU LGPLv3 license.
7 //
8 // This file is copied (mostly) intact from SeaBIOS.
9
10 #include "protos.h"
11 #include "ioport.h"
12 #include "ps2port.h"
13
14 typedef uint64_t u64;
15
16 #define dprintf(lvl, fmt, ...)
17 #define warn_timeout()
18
19 static inline u64
20 calc_future_tsc(int timeout)
21 {
22   return get_wall_time() + timeout;
23 }
24
25 static inline bool
26 check_tsc(u64 end)
27 {
28   return get_wall_time() > end;
29 }
30
31 static inline void
32 yield(void)
33 {
34   udelay(1);
35 }
36
37 static struct {
38   u8 ps2ctr;
39 } ebda;
40
41 #define GET_EBDA(VAR)           ebda.VAR
42 #define SET_EBDA(VAR, VAL)      (ebda.VAR = (VAL))
43
44 #define ASSERT32FLAT()
45 #define CONFIG_PS2PORT 1
46
47 #define enable_hwirq(level, func)
48 #define run_thread(func, val)   func(val)
49
50 /****************************************************************
51  * Low level i8042 commands.
52  ****************************************************************/
53
54 // Timeout value.
55 #define I8042_CTL_TIMEOUT       10000
56
57 #define I8042_BUFFER_SIZE       16
58
59 static int
60 i8042_wait_read(void)
61 {
62     dprintf(7, "i8042_wait_read\n");
63     int i;
64     for (i=0; i<I8042_CTL_TIMEOUT; i++) {
65         u8 status = inb(PORT_PS2_STATUS);
66         if (status & I8042_STR_OBF)
67             return 0;
68         udelay(50);
69     }
70     warn_timeout();
71     return -1;
72 }
73
74 static int
75 i8042_wait_write(void)
76 {
77     dprintf(7, "i8042_wait_write\n");
78     int i;
79     for (i=0; i<I8042_CTL_TIMEOUT; i++) {
80         u8 status = inb(PORT_PS2_STATUS);
81         if (! (status & I8042_STR_IBF))
82             return 0;
83         udelay(50);
84     }
85     warn_timeout();
86     return -1;
87 }
88
89 static int
90 i8042_flush(void)
91 {
92     dprintf(7, "i8042_flush\n");
93     int i;
94     for (i=0; i<I8042_BUFFER_SIZE; i++) {
95         u8 status = inb(PORT_PS2_STATUS);
96         if (! (status & I8042_STR_OBF))
97             return 0;
98         udelay(50);
99         inb(PORT_PS2_DATA);
100     }
101
102     warn_timeout();
103     return -1;
104 }
105
106 static int
107 __i8042_command(int command, u8 *param)
108 {
109     int receive = (command >> 8) & 0xf;
110     int send = (command >> 12) & 0xf;
111
112     // Send the command.
113     int ret = i8042_wait_write();
114     if (ret)
115         return ret;
116     outb(command, PORT_PS2_STATUS);
117
118     // Send parameters (if any).
119     int i;
120     for (i = 0; i < send; i++) {
121         ret = i8042_wait_write();
122         if (ret)
123             return ret;
124         outb(param[i], PORT_PS2_DATA);
125     }
126
127     // Receive parameters (if any).
128     for (i = 0; i < receive; i++) {
129         ret = i8042_wait_read();
130         if (ret)
131             return ret;
132         param[i] = inb(PORT_PS2_DATA);
133         dprintf(7, "i8042 param=%x\n", param[i]);
134     }
135
136     return 0;
137 }
138
139 static int
140 i8042_command(int command, u8 *param)
141 {
142     dprintf(7, "i8042_command cmd=%x\n", command);
143     int ret = __i8042_command(command, param);
144     if (ret)
145         dprintf(2, "i8042 command %x failed\n", command);
146     return ret;
147 }
148
149 static int
150 i8042_kbd_write(u8 c)
151 {
152     dprintf(7, "i8042_kbd_write c=%d\n", c);
153     int ret = i8042_wait_write();
154     if (! ret)
155         outb(c, PORT_PS2_DATA);
156     return ret;
157 }
158
159 static int
160 i8042_aux_write(u8 c)
161 {
162     return i8042_command(I8042_CMD_AUX_SEND, &c);
163 }
164
165 void
166 i8042_reboot(void)
167 {
168     int i;
169     for (i=0; i<10; i++) {
170         i8042_wait_write();
171         udelay(50);
172         outb(0xfe, PORT_PS2_STATUS); /* pulse reset low */
173         udelay(50);
174     }
175 }
176
177
178 /****************************************************************
179  * Device commands.
180  ****************************************************************/
181
182 #define PS2_RET_ACK             0xfa
183 #define PS2_RET_NAK             0xfe
184
185 static int
186 ps2_recvbyte(int aux, int needack, int timeout)
187 {
188     u64 end = calc_future_tsc(timeout);
189     for (;;) {
190         u8 status = inb(PORT_PS2_STATUS);
191         if (status & I8042_STR_OBF) {
192             u8 data = inb(PORT_PS2_DATA);
193             dprintf(7, "ps2 read %x\n", data);
194
195             if (!!(status & I8042_STR_AUXDATA) == aux) {
196                 if (!needack)
197                     return data;
198                 if (data == PS2_RET_ACK)
199                     return data;
200                 if (data == PS2_RET_NAK) {
201                     dprintf(1, "Got ps2 nak (status=%x)\n", status);
202                     return data;
203                 }
204             }
205
206             // This data not part of command - just discard it.
207             dprintf(1, "Discarding ps2 data %02x (status=%02x)\n", data, status);
208         }
209
210         if (check_tsc(end)) {
211             // Don't warn on second byte of a reset
212             if (timeout > 100)
213                 warn_timeout();
214             return -1;
215         }
216         yield();
217     }
218 }
219
220 static int
221 ps2_sendbyte(int aux, u8 command, int timeout)
222 {
223     dprintf(7, "ps2_sendbyte aux=%d cmd=%x\n", aux, command);
224     int ret;
225     if (aux)
226         ret = i8042_aux_write(command);
227     else
228         ret = i8042_kbd_write(command);
229     if (ret)
230         return ret;
231
232     // Read ack.
233     ret = ps2_recvbyte(aux, 1, timeout);
234     if (ret < 0)
235         return ret;
236     if (ret != PS2_RET_ACK)
237         return -1;
238
239     return 0;
240 }
241
242 static int
243 __ps2_command(int aux, int command, u8 *param)
244 {
245     int ret2;
246     int receive = (command >> 8) & 0xf;
247     int send = (command >> 12) & 0xf;
248
249     // Disable interrupts and keyboard/mouse.
250     u8 ps2ctr = GET_EBDA(ps2ctr);
251     u8 newctr = ((ps2ctr | I8042_CTR_AUXDIS | I8042_CTR_KBDDIS)
252                  & ~(I8042_CTR_KBDINT|I8042_CTR_AUXINT));
253     dprintf(6, "i8042 ctr old=%x new=%x\n", ps2ctr, newctr);
254     int ret = i8042_command(I8042_CMD_CTL_WCTR, &newctr);
255     if (ret)
256         return ret;
257
258     // Flush any interrupts already pending.
259     yield();
260
261     // Enable port command is being sent to.
262     if (aux)
263         newctr &= ~I8042_CTR_AUXDIS;
264     else
265         newctr &= ~I8042_CTR_KBDDIS;
266     ret = i8042_command(I8042_CMD_CTL_WCTR, &newctr);
267     if (ret)
268         goto fail;
269
270     if (command == ATKBD_CMD_RESET_BAT) {
271         // Reset is special wrt timeouts and bytes received.
272
273         // Send command.
274         ret = ps2_sendbyte(aux, command, 1000);
275         if (ret)
276             goto fail;
277
278         // Receive parameters.
279         ret = ps2_recvbyte(aux, 0, 4000);
280         if (ret < 0)
281             goto fail;
282         param[0] = ret;
283         ret = ps2_recvbyte(aux, 0, 100);
284         if (ret < 0)
285             // Some devices only respond with one byte on reset.
286             ret = 0;
287         param[1] = ret;
288     } else if (command == ATKBD_CMD_GETID) {
289         // Getid is special wrt bytes received.
290
291         // Send command.
292         ret = ps2_sendbyte(aux, command, 200);
293         if (ret)
294             goto fail;
295
296         // Receive parameters.
297         ret = ps2_recvbyte(aux, 0, 500);
298         if (ret < 0)
299             goto fail;
300         param[0] = ret;
301         if (ret == 0xab || ret == 0xac || ret == 0x2b || ret == 0x5d
302             || ret == 0x60 || ret == 0x47) {
303             // These ids (keyboards) return two bytes.
304             ret = ps2_recvbyte(aux, 0, 500);
305             if (ret < 0)
306                 goto fail;
307             param[1] = ret;
308         } else {
309             param[1] = 0;
310         }
311     } else {
312         // Send command.
313         ret = ps2_sendbyte(aux, command, 200);
314         if (ret)
315             goto fail;
316
317         // Send parameters (if any).
318         int i;
319         for (i = 0; i < send; i++) {
320             ret = ps2_sendbyte(aux, param[i], 200);
321             if (ret)
322                 goto fail;
323         }
324
325         // Receive parameters (if any).
326         for (i = 0; i < receive; i++) {
327             ret = ps2_recvbyte(aux, 0, 500);
328             if (ret < 0)
329                 goto fail;
330             param[i] = ret;
331         }
332     }
333
334     ret = 0;
335
336 fail:
337     // Restore interrupts and keyboard/mouse.
338     ret2 = i8042_command(I8042_CMD_CTL_WCTR, &ps2ctr);
339     if (ret2)
340         return ret2;
341
342     return ret;
343 }
344
345 static int
346 ps2_command(int aux, int command, u8 *param)
347 {
348     dprintf(7, "ps2_command aux=%d cmd=%x\n", aux, command);
349     int ret = __ps2_command(aux, command, param);
350     if (ret)
351         dprintf(2, "ps2 command %x failed (aux=%d)\n", command, aux);
352     return ret;
353 }
354
355 int
356 ps2_kbd_command(int command, u8 *param)
357 {
358     return ps2_command(0, command, param);
359 }
360
361 int
362 ps2_mouse_command(int command, u8 *param)
363 {
364     return ps2_command(1, command, param);
365 }
366
367
368 /****************************************************************
369  * IRQ handlers
370  ****************************************************************/
371 #if 0
372
373 // INT74h : PS/2 mouse hardware interrupt
374 void VISIBLE16
375 handle_74(void)
376 {
377     if (! CONFIG_PS2PORT)
378         return;
379
380     debug_isr(DEBUG_ISR_74);
381
382     u8 v = inb(PORT_PS2_STATUS);
383     if ((v & (I8042_STR_OBF|I8042_STR_AUXDATA))
384         != (I8042_STR_OBF|I8042_STR_AUXDATA)) {
385         dprintf(1, "ps2 mouse irq but no mouse data.\n");
386         goto done;
387     }
388     v = inb(PORT_PS2_DATA);
389
390     if (!(GET_EBDA(ps2ctr) & I8042_CTR_AUXINT))
391         // Interrupts not enabled.
392         goto done;
393
394     process_mouse(v);
395
396 done:
397     eoi_pic2();
398 }
399
400 // INT09h : Keyboard Hardware Service Entry Point
401 void VISIBLE16
402 handle_09(void)
403 {
404     if (! CONFIG_PS2PORT)
405         return;
406
407     debug_isr(DEBUG_ISR_09);
408
409     // read key from keyboard controller
410     u8 v = inb(PORT_PS2_STATUS);
411     if (v & I8042_STR_AUXDATA) {
412         dprintf(1, "ps2 keyboard irq but found mouse data?!\n");
413         goto done;
414     }
415     v = inb(PORT_PS2_DATA);
416
417     if (!(GET_EBDA(ps2ctr) & I8042_CTR_KBDINT))
418         // Interrupts not enabled.
419         goto done;
420
421     process_key(v);
422
423 done:
424     eoi_pic1();
425 }
426
427 #endif
428 /****************************************************************
429  * Setup
430  ****************************************************************/
431
432 static void
433 keyboard_init(void *data)
434 {
435     /* flush incoming keys */
436     int ret = i8042_flush();
437     if (ret)
438         return;
439
440     // Controller self-test.
441     u8 param[2];
442     ret = i8042_command(I8042_CMD_CTL_TEST, param);
443     if (ret)
444         return;
445     if (param[0] != 0x55) {
446         dprintf(1, "i8042 self test failed (got %x not 0x55)\n", param[0]);
447         return;
448     }
449
450     // Controller keyboard test.
451     ret = i8042_command(I8042_CMD_KBD_TEST, param);
452     if (ret)
453         return;
454     if (param[0] != 0x00) {
455         dprintf(1, "i8042 keyboard test failed (got %x not 0x00)\n", param[0]);
456         return;
457     }
458
459     // Disable keyboard and mouse events.
460     SET_EBDA(ps2ctr, I8042_CTR_KBDDIS | I8042_CTR_AUXDIS);
461
462
463     /* ------------------- keyboard side ------------------------*/
464     /* reset keyboard and self test  (keyboard side) */
465     ret = ps2_kbd_command(ATKBD_CMD_RESET_BAT, param);
466     if (ret)
467         return;
468     if (param[0] != 0xaa) {
469         dprintf(1, "keyboard self test failed (got %x not 0xaa)\n", param[0]);
470         return;
471     }
472
473     /* Disable keyboard */
474     ret = ps2_kbd_command(ATKBD_CMD_RESET_DIS, NULL);
475     if (ret)
476         return;
477
478     // Set scancode command (mode 2)
479     param[0] = 0x02;
480     ret = ps2_kbd_command(ATKBD_CMD_SSCANSET, param);
481     if (ret)
482         return;
483
484     // Keyboard Mode: disable mouse, scan code convert, enable kbd IRQ
485     SET_EBDA(ps2ctr, I8042_CTR_AUXDIS | I8042_CTR_XLATE | I8042_CTR_KBDINT);
486
487     /* Enable keyboard */
488     ret = ps2_kbd_command(ATKBD_CMD_ENABLE, NULL);
489     if (ret)
490         return;
491
492     dprintf(1, "PS2 keyboard initialized\n");
493 }
494
495 void
496 ps2port_setup(void)
497 {
498     ASSERT32FLAT();
499     if (! CONFIG_PS2PORT)
500         return;
501     dprintf(3, "init ps2port\n");
502
503     enable_hwirq(1, FUNC16(entry_09));
504     enable_hwirq(12, FUNC16(entry_74));
505
506     run_thread(keyboard_init, NULL);
507 }