Fix incorrect mapping of ACS_PI for VGA console. A pi should look like pi and
[coreboot.git] / payloads / libpayload / curses / keyboard.c
1 /*
2  * This file is part of the libpayload project.
3  *
4  * Copyright (C) 2007 Uwe Hermann <uwe@hermann-uwe.de>
5  * Copyright (C) 2008 Advanced Micro Devices, Inc.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 /*
32  * This file handles reading keystrokes from serial and the console
33  * and "cooking" them so that they are correct for curses.
34  * Also, implement key related functions (mainly wgetch)
35  *
36  * TODO:
37  * Actually cook the serial (handle special keys)
38  */
39
40 #include <config.h>
41 #include "local.h"
42
43 static int _halfdelay = 0;
44
45 /* ============== Serial ==================== */
46
47 /* We treat serial like a vt100 terminal.  For now we
48    do the cooking in here, but we should probably eventually
49    pass it to dedicated vt100 code */
50
51 static int getkeyseq(char *buffer, int len)
52 {
53         int i;
54
55         for(i = 0; i < 75; i++) {
56                 if (serial_havechar())
57                         break;
58                 mdelay(1);
59         }
60
61         if (i == 75)
62                 return len;
63
64         buffer[len++] = serial_getchar();
65         return getkeyseq(buffer, len);
66 }
67
68 static struct {
69         char *seq;
70         int key;
71 } escape_codes[] = {
72         { "[A", KEY_UP },
73         { "[B", KEY_DOWN },
74         { "[C", KEY_RIGHT },
75         { "[D", KEY_LEFT },
76         { "OP", KEY_F(1) },
77         { "OQ", KEY_F(2) },
78         { "OR", KEY_F(3) },
79         { "OS", KEY_F(4) },
80         { "[15~", KEY_F(5) },
81         { "[17~", KEY_F(6) },
82         { "[18~", KEY_F(7) },
83         { "[19~", KEY_F(8) },
84         { "[20~", KEY_F(9) },
85         { "[21~", KEY_F(10) },
86         { "[24~", KEY_F(12) },
87         { NULL },
88 };
89
90 static int handle_escape(void)
91 {
92         char buffer[5];
93         int len = getkeyseq(buffer, 0);
94         int i, t;
95
96         if (len == 0)
97                 return 27;
98
99         for(i = 0; escape_codes[i].seq != NULL; i++) {
100                 char *p = escape_codes[i].seq;
101
102                 for(t = 0; t < len; t++) {
103                         if (!*p || *p != buffer[t])
104                                 break;
105                         p++;
106                 }
107
108                 if (t == len)
109                         return escape_codes[i].key;
110         }
111
112         return 0;
113 }
114
115 static int cook_serial(unsigned char ch)
116 {
117         switch(ch) {
118         case 8:
119                 return KEY_BACKSPACE;
120
121         case 13:
122                 return KEY_ENTER;
123
124         case 27:
125                 return handle_escape();
126
127         default:
128                 return ch;
129         }
130 }
131
132 /* ================ Keyboard ================ */
133
134 /* Scancode macros */
135
136 #define DOWN(_c) (0x80 | (_c))
137 #define UP(_c) (_c)
138
139 #define ISDOWN(_c) ((_c) & 0x80)
140 #define ISUP(_c) (!ISDOWN((_c)))
141
142 #define SCANCODE(_c) ((_c) & ~0x80)
143
144 /* Scancode definitions for the modifiers */
145
146 #define SCANCODE_RSHIFT   0x36
147 #define SCANCODE_LSHIFT   0x2a
148 #define SCANCODE_CAPSLOCK 0x3a
149 #define SCANCODE_LALT     0x38
150 #define SCANCODE_LCTRL    0x1d
151
152 /* Modifier flags */
153
154 #define SHIFT_MODIFIER    0x1
155 #define CAPSLOCK_MODIFIER 0x2
156 #define ALT_MODIFIER      0x4
157 #define CTRL_MODIFIER     0x8
158
159 #define CTRL(_c) (_c & 0x1f)
160
161 struct {
162         int normal;
163         int shift;
164 } scancode_map[] = {
165         { },
166         { CTRL('['), CTRL('[')}, 
167         { '1', '!' },
168         { '2', '@' },
169         { '3', '#' },
170         { '4', '$' },
171         { '5', '%' },
172         { '6', '^' },
173         { '7', '&' },
174         { '8', '*' },
175         { '9', '(' },
176         { '0', ')' },
177         { '-', '_' },
178         { '=', '+' },
179         { KEY_BACKSPACE, KEY_BACKSPACE},
180         { CTRL('I' ), KEY_BTAB },          /* 0x0F */
181         { 'q', 'Q' },
182         { 'w', 'W' },
183         { 'e', 'E' },
184         { 'r', 'R' },
185         { 't', 'T' },
186         { 'y', 'Y' },
187         { 'u', 'U' },
188         { 'i', 'I' },
189         { 'o', 'O' },
190         { 'p', 'P' },
191         { '[', '{' },
192         { ']', '{' },
193         { KEY_ENTER, KEY_ENTER },
194         { 0 , 0 },
195         { 'a', 'A' },
196         { 's', 'S' },                    /* 0x1F */
197         { 'd', 'D' },
198         { 'f', 'F' },
199         { 'g', 'G' },
200         { 'h', 'H' },
201         { 'j', 'J' },
202         { 'k', 'K' },
203         { 'l', 'L' },
204         { ';', ':' },
205         { '\'', '\"' },
206         { '`', '~', },
207         { 0, 0 },
208         { '\\', '|' },
209         { 'z', 'Z' },
210         { 'x', 'X' },
211         { 'c', 'C' },
212         { 'v', 'V' },                   /* 0x2F */
213         { 'b', 'B' },
214         { 'n', 'N' },
215         { 'm', 'M' },
216         { ',', '<'},
217         { '.', '>' },
218         { '/', '?' },
219         { 0, 0 },                       /* RSHIFT */
220         { '*', '*' },
221         { 0, 0 },                       /* LALT */
222         { ' ', ' ' },                   /* Space */
223         { 0, 0 },                       /* Capslock */
224         { KEY_F(1), KEY_F(1) },
225         { KEY_F(2), KEY_F(2) },
226         { KEY_F(3), KEY_F(3) },
227         { KEY_F(4), KEY_F(4) },
228         { KEY_F(5), KEY_F(5) },         /* 0x3F */
229         { KEY_F(6), KEY_F(6) },
230         { KEY_F(7), KEY_F(7) },
231         { KEY_F(8), KEY_F(8) },
232         { KEY_F(9), KEY_F(9) },
233         { KEY_F(10), KEY_F(10) },
234         { 0, 0 },                      /* Numlock */
235         { 0, 0 },                      /* Scroll lock */
236         { KEY_HOME, KEY_HOME },
237         { KEY_UP,   KEY_UP },
238         { KEY_PPAGE, KEY_PPAGE },
239         { '-',      '-' },
240         { KEY_LEFT, KEY_LEFT },
241         { 0,        0 },
242         { KEY_RIGHT, KEY_RIGHT },
243         { '-',       '-' },
244         { KEY_END,  KEY_END },         /* 0x4F */
245         { KEY_DOWN, KEY_DOWN },
246         { KEY_NPAGE, KEY_NPAGE },
247         { KEY_IC,    KEY_IC },
248         { KEY_DC,    KEY_DC },
249         { 0, 0 },                     /* sysreq */
250         { 0, 0 },
251         { KEY_F(11), KEY_F(11) },
252         { KEY_F(12), KEY_F(12) },
253 };
254
255 static int cook_scancodes(unsigned char code)
256 {
257         static int modifiers = 0;
258         int ch = 0, sc, shift;
259
260         switch (code) {
261         case DOWN(SCANCODE_RSHIFT):
262         case DOWN(SCANCODE_LSHIFT):
263                 modifiers |= SHIFT_MODIFIER;
264                 return 0;
265         case UP(SCANCODE_RSHIFT):
266         case UP(SCANCODE_LSHIFT):
267                 modifiers &= ~SHIFT_MODIFIER;
268                 return 0;
269         case UP(SCANCODE_CAPSLOCK):
270                 if (modifiers & CAPSLOCK_MODIFIER)
271                         modifiers &= ~CAPSLOCK_MODIFIER;
272                 else
273                         modifiers |= CAPSLOCK_MODIFIER;
274                 return 0;
275         case DOWN(SCANCODE_LALT):
276                 modifiers |= ALT_MODIFIER;
277                 return 0;
278         case UP(SCANCODE_LALT):
279                 modifiers &= ~ALT_MODIFIER;
280                 return 0;
281         case DOWN(SCANCODE_LCTRL):
282                 modifiers |= CTRL_MODIFIER;
283                 return 0;
284         case UP(SCANCODE_LCTRL):
285                 modifiers &= ~CTRL_MODIFIER;
286                 return 0;
287         }
288
289         /* Only process keys on an upstroke. */
290         if (!ISUP(code))
291                 return 0;
292
293         sc = SCANCODE(code);
294
295         if (sc == 0 || sc > 0x59)
296                 return ERR;
297
298         shift = (modifiers & SHIFT_MODIFIER) ^ (modifiers & CAPSLOCK_MODIFIER);
299
300         ch = shift ? scancode_map[sc].shift : scancode_map[sc].normal;
301
302         if (modifiers & CTRL_MODIFIER)
303                 ch = (ch >= 0x3F && ch <= 0x5F) ? CTRL(ch) : 0;
304
305         return ch;
306 }
307
308 static int curses_getchar(int delay)
309 {
310         unsigned char c = 0;
311         int ret;
312
313         do {
314                 if (curses_flags & F_ENABLE_CONSOLE)
315                         c = inb(0x64);
316
317                 if ((c & 1) == 0) {
318
319                         if ((curses_flags & F_ENABLE_SERIAL) &&
320                             serial_havechar()) {
321                                 c = serial_getchar();
322                                 return cook_serial(c);
323                         }
324
325                         if (delay == 0)
326                                 break;
327
328                         if (delay > 0) {
329                                 mdelay(100);
330                                 delay--;
331                         }
332
333                         continue;
334                 }
335
336                 c = inb(0x60);
337
338                 ret = cook_scancodes(c);
339
340                 if (ret != 0) {
341                         return ret;
342                 }
343
344         } while (1);
345
346         return ERR;
347 }
348
349 /* === Public functions === */
350
351 int wgetch(WINDOW *win)
352 {
353         int delay = -1;
354
355         if (_halfdelay || win->_delay)
356                 delay = win->_delay ? 0 : _halfdelay;
357
358         return curses_getchar(delay);
359 }
360
361 int nodelay(WINDOW *win, NCURSES_BOOL flag)
362 {
363         win->_delay = flag ? 1 : 0;
364         return 0;
365 }
366
367 int halfdelay(int tenths)
368 {
369         if (tenths > 255)
370                 return ERR;
371
372         _halfdelay = tenths;
373         return 0;
374 }
375
376 int nocbreak(void)
377 {
378         /* Remove half delay timeout. */
379         _halfdelay = 0;
380         return 0;
381 }
382
383 #ifdef CONFIG_VGA_CONSOLE
384 void curses_enable_vga(int state)
385 {
386         if (state)
387                 curses_flags |= F_ENABLE_CONSOLE;
388         else
389                 curses_flags &= ~F_ENABLE_CONSOLE;
390 }
391 #else
392 void curses_enable_vga(int state) { }
393 #endif
394
395 #ifdef CONFIG_SERIAL_CONSOLE
396 void curses_enable_serial(int state)
397 {
398         if (state)
399                 curses_flags |= F_ENABLE_SERIAL;
400         else
401                 curses_flags &= ~F_ENABLE_SERIAL;
402 }
403 #else
404 void curses_enable_serial(int state) { }
405 #endif
406