blob: 8e9212ceda1d695963cc5e71ee19570d2d3ffcdf [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
Jordan Crouse672d0ae2008-04-08 23:21:33 +000042static int _halfdelay = 0;
43
Jordan Crousef6145c32008-03-19 23:56:58 +000044/* ============== Serial ==================== */
45
46/* FIXME: Cook the serial correctly */
47
48static 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
82struct {
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
176static int cook_scancodes(unsigned char code)
177{
178 static int modifiers = 0;
Uwe Hermann6a441bf2008-03-20 19:54:59 +0000179 int ch = 0, sc, shift;
Jordan Crousef6145c32008-03-19 23:56:58 +0000180
Uwe Hermann6a441bf2008-03-20 19:54:59 +0000181 switch (code) {
Jordan Crousef6145c32008-03-19 23:56:58 +0000182 case DOWN(SCANCODE_RSHIFT):
183 case DOWN(SCANCODE_LSHIFT):
184 modifiers |= SHIFT_MODIFIER;
185 return 0;
Jordan Crousef6145c32008-03-19 23:56:58 +0000186 case UP(SCANCODE_RSHIFT):
187 case UP(SCANCODE_LSHIFT):
188 modifiers &= ~SHIFT_MODIFIER;
189 return 0;
Jordan Crousef6145c32008-03-19 23:56:58 +0000190 case UP(SCANCODE_CAPSLOCK):
191 if (modifiers & CAPSLOCK_MODIFIER)
192 modifiers &= ~CAPSLOCK_MODIFIER;
193 else
194 modifiers |= CAPSLOCK_MODIFIER;
195 return 0;
Jordan Crousef6145c32008-03-19 23:56:58 +0000196 case DOWN(SCANCODE_LALT):
197 modifiers |= ALT_MODIFIER;
198 return 0;
Jordan Crousef6145c32008-03-19 23:56:58 +0000199 case UP(SCANCODE_LALT):
200 modifiers &= ~ALT_MODIFIER;
201 return 0;
Jordan Crousef6145c32008-03-19 23:56:58 +0000202 case DOWN(SCANCODE_LCTRL):
203 modifiers |= CTRL_MODIFIER;
204 return 0;
Jordan Crousef6145c32008-03-19 23:56:58 +0000205 case UP(SCANCODE_LCTRL):
206 modifiers &= ~CTRL_MODIFIER;
207 return 0;
208 }
209
Uwe Hermann6a441bf2008-03-20 19:54:59 +0000210 /* Only process keys on an upstroke. */
Jordan Crousef6145c32008-03-19 23:56:58 +0000211 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
Uwe Hermann6a441bf2008-03-20 19:54:59 +0000229static int curses_getchar(int delay)
230{
Jordan Crousef6145c32008-03-19 23:56:58 +0000231 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) &&
Uwe Hermann6a441bf2008-03-20 19:54:59 +0000241 serial_havechar()) {
Jordan Crousef6145c32008-03-19 23:56:58 +0000242 c = serial_getchar();
243 return cook_serial(c);
244 }
245
Jordan Crouse672d0ae2008-04-08 23:21:33 +0000246 if (delay == 0)
Jordan Crousef6145c32008-03-19 23:56:58 +0000247 break;
Jordan Crouse672d0ae2008-04-08 23:21:33 +0000248
249 if (delay > 0) {
250 mdelay(100);
251 delay--;
252 }
Jordan Crousef6145c32008-03-19 23:56:58 +0000253 }
254
255 c = inb(0x60);
256
257 ret = cook_scancodes(c);
258
259 if (ret != 0) {
260 return ret;
Uwe Hermann6a441bf2008-03-20 19:54:59 +0000261 }
Jordan Crousef6145c32008-03-19 23:56:58 +0000262
Uwe Hermann6a441bf2008-03-20 19:54:59 +0000263 } while (1);
Jordan Crousef6145c32008-03-19 23:56:58 +0000264
265 return ERR;
266}
267
268/* === Public functions === */
269
270int wgetch(WINDOW *win)
271{
Jordan Crouse672d0ae2008-04-08 23:21:33 +0000272 int delay = -1;
273
274 if (_halfdelay || win->_delay)
275 delay = win->_delay ? 0 : _halfdelay;
276
277 return curses_getchar(delay);
Jordan Crousef6145c32008-03-19 23:56:58 +0000278}
279
280int nodelay(WINDOW *win, NCURSES_BOOL flag)
281{
Jordan Crouse672d0ae2008-04-08 23:21:33 +0000282 win->_delay = flag ? 1 : 0;
283 return 0;
284}
285
286int halfdelay(int tenths)
287{
288 if (tenths > 255)
289 return ERR;
290
291 _halfdelay = tenths;
292 return 0;
293}
294
295int nocbreak(void)
296{
297 /* Remove half delay timeout. */
298 _halfdelay = 0;
Uwe Hermann14a3feb2008-03-20 20:46:44 +0000299 return 0;
Jordan Crousef6145c32008-03-19 23:56:58 +0000300}
301
302#ifdef CONFIG_VGA_CONSOLE
303void 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
311void curses_enable_vga(int state) { }
312#endif
313
314#ifdef CONFIG_SERIAL_CONSOLE
315void 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
323void curses_enable_serial(int state) { }
324#endif
325