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