blob: 2062ac2ffed3682a41f379c49007943ee7be3857 [file] [log] [blame]
Jordan Crousef6145c32008-03-19 23:56:58 +00001/*
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
46static 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
80struct {
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
174static int cook_scancodes(unsigned char code)
175{
176 static int modifiers = 0;
Uwe Hermann6a441bf2008-03-20 19:54:59 +0000177 int ch = 0, sc, shift;
Jordan Crousef6145c32008-03-19 23:56:58 +0000178
Uwe Hermann6a441bf2008-03-20 19:54:59 +0000179 switch (code) {
Jordan Crousef6145c32008-03-19 23:56:58 +0000180 case DOWN(SCANCODE_RSHIFT):
181 case DOWN(SCANCODE_LSHIFT):
182 modifiers |= SHIFT_MODIFIER;
183 return 0;
Jordan Crousef6145c32008-03-19 23:56:58 +0000184 case UP(SCANCODE_RSHIFT):
185 case UP(SCANCODE_LSHIFT):
186 modifiers &= ~SHIFT_MODIFIER;
187 return 0;
Jordan Crousef6145c32008-03-19 23:56:58 +0000188 case UP(SCANCODE_CAPSLOCK):
189 if (modifiers & CAPSLOCK_MODIFIER)
190 modifiers &= ~CAPSLOCK_MODIFIER;
191 else
192 modifiers |= CAPSLOCK_MODIFIER;
193 return 0;
Jordan Crousef6145c32008-03-19 23:56:58 +0000194 case DOWN(SCANCODE_LALT):
195 modifiers |= ALT_MODIFIER;
196 return 0;
Jordan Crousef6145c32008-03-19 23:56:58 +0000197 case UP(SCANCODE_LALT):
198 modifiers &= ~ALT_MODIFIER;
199 return 0;
Jordan Crousef6145c32008-03-19 23:56:58 +0000200 case DOWN(SCANCODE_LCTRL):
201 modifiers |= CTRL_MODIFIER;
202 return 0;
Jordan Crousef6145c32008-03-19 23:56:58 +0000203 case UP(SCANCODE_LCTRL):
204 modifiers &= ~CTRL_MODIFIER;
205 return 0;
206 }
207
Uwe Hermann6a441bf2008-03-20 19:54:59 +0000208 /* Only process keys on an upstroke. */
Jordan Crousef6145c32008-03-19 23:56:58 +0000209 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
Uwe Hermann6a441bf2008-03-20 19:54:59 +0000227static int curses_getchar(int delay)
228{
Jordan Crousef6145c32008-03-19 23:56:58 +0000229 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) &&
Uwe Hermann6a441bf2008-03-20 19:54:59 +0000239 serial_havechar()) {
Jordan Crousef6145c32008-03-19 23:56:58 +0000240 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;
Uwe Hermann6a441bf2008-03-20 19:54:59 +0000254 }
Jordan Crousef6145c32008-03-19 23:56:58 +0000255
Uwe Hermann6a441bf2008-03-20 19:54:59 +0000256 } while (1);
Jordan Crousef6145c32008-03-19 23:56:58 +0000257
258 return ERR;
259}
260
261/* === Public functions === */
262
263int wgetch(WINDOW *win)
264{
265 return curses_getchar(win->_delay);
266}
267
268int nodelay(WINDOW *win, NCURSES_BOOL flag)
269{
270 win->_delay = flag ? 0 : -1;
Uwe Hermann14a3feb2008-03-20 20:46:44 +0000271 return 0;
Jordan Crousef6145c32008-03-19 23:56:58 +0000272}
273
274#ifdef CONFIG_VGA_CONSOLE
275void curses_enable_vga(int state)
276{
277 if (state)
278 curses_flags |= F_ENABLE_CONSOLE;
279 else
280 curses_flags &= ~F_ENABLE_CONSOLE;
281}
282#else
283void curses_enable_vga(int state) { }
284#endif
285
286#ifdef CONFIG_SERIAL_CONSOLE
287void curses_enable_serial(int state)
288{
289 if (state)
290 curses_flags |= F_ENABLE_SERIAL;
291 else
292 curses_flags &= ~F_ENABLE_SERIAL;
293}
294#else
295void curses_enable_serial(int state) { }
296#endif
297