libpayload: Add a timeout function for getchar and getch
[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 "local.h"
41
42 static int _halfdelay = 0;
43
44 /* ============== Serial ==================== */
45
46 /* FIXME:  Cook the serial correctly */
47
48 static int cook_serial(unsigned char ch)
49 {
50         return (int) ch;
51 }
52
53 /* ================ Keyboard ================ */
54
55 /* Scancode macros */
56
57 #define DOWN(_c) (0x80 | (_c))
58 #define UP(_c) (_c)
59
60 #define ISDOWN(_c) ((_c) & 0x80)
61 #define ISUP(_c) (!ISDOWN((_c)))
62
63 #define SCANCODE(_c) ((_c) & ~0x80)
64
65 /* Scancode definitions for the modifiers */
66
67 #define SCANCODE_RSHIFT   0x36
68 #define SCANCODE_LSHIFT   0x2a
69 #define SCANCODE_CAPSLOCK 0x3a
70 #define SCANCODE_LALT     0x38
71 #define SCANCODE_LCTRL    0x1d
72
73 /* Modifier flags */
74
75 #define SHIFT_MODIFIER    0x1
76 #define CAPSLOCK_MODIFIER 0x2
77 #define ALT_MODIFIER      0x4
78 #define CTRL_MODIFIER     0x8
79
80 #define CTRL(_c) (_c & 0x1f)
81
82 struct {
83         int normal;
84         int shift;
85 } scancode_map[] = {
86         { },
87         { CTRL('['), CTRL('[')}, 
88         { '1', '!' },
89         { '2', '@' },
90         { '3', '#' },
91         { '4', '$' },
92         { '5', '%' },
93         { '6', '^' },
94         { '7', '&' },
95         { '8', '*' },
96         { '9', '(' },
97         { '0', ')' },
98         { '-', '_' },
99         { '=', '+' },
100         { KEY_BACKSPACE, KEY_BACKSPACE},
101         { CTRL('I' ), KEY_BTAB },          /* 0x0F */
102         { 'q', 'Q' },
103         { 'w', 'W' },
104         { 'e', 'E' },
105         { 'r', 'R' },
106         { 't', 'T' },
107         { 'y', 'Y' },
108         { 'u', 'U' },
109         { 'i', 'I' },
110         { 'o', 'O' },
111         { 'p', 'P' },
112         { '[', '{' },
113         { ']', '{' },
114         { KEY_ENTER, KEY_ENTER },
115         { 0 , 0 },
116         { 'a', 'A' },
117         { 's', 'S' },                    /* 0x1F */
118         { 'd', 'D' },
119         { 'f', 'F' },
120         { 'g', 'G' },
121         { 'h', 'H' },
122         { 'j', 'J' },
123         { 'k', 'K' },
124         { 'l', 'L' },
125         { ';', ':' },
126         { '\'', '\"' },
127         { '`', '~', },
128         { 0, 0 },
129         { '\\', '|' },
130         { 'z', 'Z' },
131         { 'x', 'X' },
132         { 'c', 'C' },
133         { 'v', 'V' },                   /* 0x2F */
134         { 'b', 'B' },
135         { 'n', 'N' },
136         { 'm', 'M' },
137         { ',', '<'},
138         { '.', '>' },
139         { '/', '?' },
140         { 0, 0 },                       /* RSHIFT */
141         { '*', '*' },
142         { 0, 0 },                       /* LALT */
143         { ' ', ' ' },                   /* Space */
144         { 0, 0 },                       /* Capslock */
145         { KEY_F(1), KEY_F(1) },
146         { KEY_F(2), KEY_F(2) },
147         { KEY_F(3), KEY_F(3) },
148         { KEY_F(4), KEY_F(4) },
149         { KEY_F(5), KEY_F(5) },         /* 0x3F */
150         { KEY_F(6), KEY_F(6) },
151         { KEY_F(7), KEY_F(7) },
152         { KEY_F(8), KEY_F(8) },
153         { KEY_F(9), KEY_F(9) },
154         { KEY_F(10), KEY_F(10) },
155         { 0, 0 },                      /* Numlock */
156         { 0, 0 },                      /* Scroll lock */
157         { KEY_HOME, KEY_HOME },
158         { KEY_UP,   KEY_UP },
159         { KEY_PPAGE, KEY_PPAGE },
160         { '-',      '-' },
161         { KEY_LEFT, KEY_LEFT },
162         { 0,        0 },
163         { KEY_RIGHT, KEY_RIGHT },
164         { '-',       '-' },
165         { KEY_END,  KEY_END },         /* 0x4F */
166         { KEY_DOWN, KEY_DOWN },
167         { KEY_NPAGE, KEY_NPAGE },
168         { KEY_IC,    KEY_IC },
169         { KEY_DC,    KEY_DC },
170         { 0, 0 },                     /* sysreq */
171         { 0, 0 },
172         { KEY_F(11), KEY_F(11) },
173         { KEY_F(12), KEY_F(12) },
174 };
175
176 static int cook_scancodes(unsigned char code)
177 {
178         static int modifiers = 0;
179         int ch = 0, sc, shift;
180
181         switch (code) {
182         case DOWN(SCANCODE_RSHIFT):
183         case DOWN(SCANCODE_LSHIFT):
184                 modifiers |= SHIFT_MODIFIER;
185                 return 0;
186         case UP(SCANCODE_RSHIFT):
187         case UP(SCANCODE_LSHIFT):
188                 modifiers &= ~SHIFT_MODIFIER;
189                 return 0;
190         case UP(SCANCODE_CAPSLOCK):
191                 if (modifiers & CAPSLOCK_MODIFIER)
192                         modifiers &= ~CAPSLOCK_MODIFIER;
193                 else
194                         modifiers |= CAPSLOCK_MODIFIER;
195                 return 0;
196         case DOWN(SCANCODE_LALT):
197                 modifiers |= ALT_MODIFIER;
198                 return 0;
199         case UP(SCANCODE_LALT):
200                 modifiers &= ~ALT_MODIFIER;
201                 return 0;
202         case DOWN(SCANCODE_LCTRL):
203                 modifiers |= CTRL_MODIFIER;
204                 return 0;
205         case UP(SCANCODE_LCTRL):
206                 modifiers &= ~CTRL_MODIFIER;
207                 return 0;
208         }
209
210         /* Only process keys on an upstroke. */
211         if (!ISUP(code))
212                 return 0;
213
214         sc = SCANCODE(code);
215
216         if (sc == 0 || sc > 0x59)
217                 return ERR;
218
219         shift = (modifiers & SHIFT_MODIFIER) ^ (modifiers & CAPSLOCK_MODIFIER);
220
221         ch = shift ? scancode_map[sc].shift : scancode_map[sc].normal;
222
223         if (modifiers & CTRL_MODIFIER)
224                 ch = (ch >= 0x3F && ch <= 0x5F) ? CTRL(ch) : 0;
225
226         return ch;
227 }
228
229 static int curses_getchar(int delay)
230 {
231         unsigned char c = 0;
232         int ret;
233
234         do {
235                 if (curses_flags & F_ENABLE_CONSOLE)
236                         c = inb(0x64);
237
238                 if ((c & 1) == 0) {
239
240                         if ((curses_flags & F_ENABLE_SERIAL) &&
241                             serial_havechar()) {
242                                 c = serial_getchar();
243                                 return cook_serial(c);
244                         }
245
246                         if (delay == 0)
247                                 break;
248
249                         if (delay > 0) {
250                                 mdelay(100);
251                                 delay--;
252                         }
253                 }
254
255                 c = inb(0x60);
256
257                 ret = cook_scancodes(c);
258
259                 if (ret != 0) {
260                         return ret;
261                 }
262
263         } while (1);
264
265         return ERR;
266 }
267
268 /* === Public functions === */
269
270 int wgetch(WINDOW *win)
271 {
272         int delay = -1;
273
274         if (_halfdelay || win->_delay)
275                 delay = win->_delay ? 0 : _halfdelay;
276
277         return curses_getchar(delay);
278 }
279
280 int nodelay(WINDOW *win, NCURSES_BOOL flag)
281 {
282         win->_delay = flag ? 1 : 0;
283         return 0;
284 }
285
286 int halfdelay(int tenths)
287 {
288         if (tenths > 255)
289                 return ERR;
290
291         _halfdelay = tenths;
292         return 0;
293 }
294
295 int nocbreak(void)
296 {
297         /* Remove half delay timeout. */
298         _halfdelay = 0;
299         return 0;
300 }
301
302 #ifdef CONFIG_VGA_CONSOLE
303 void curses_enable_vga(int state)
304 {
305         if (state)
306                 curses_flags |= F_ENABLE_CONSOLE;
307         else
308                 curses_flags &= ~F_ENABLE_CONSOLE;
309 }
310 #else
311 void curses_enable_vga(int state) { }
312 #endif
313
314 #ifdef CONFIG_SERIAL_CONSOLE
315 void curses_enable_serial(int state)
316 {
317         if (state)
318                 curses_flags |= F_ENABLE_SERIAL;
319         else
320                 curses_flags &= ~F_ENABLE_SERIAL;
321 }
322 #else
323 void curses_enable_serial(int state) { }
324 #endif
325