5fc54224a0f36ec53230e5ce1d9ae50e0f0d95a5
[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 #ifdef CONFIG_SERIAL_CONSOLE
48 /* We treat serial like a vt100 terminal.  For now we
49    do the cooking in here, but we should probably eventually
50    pass it to dedicated vt100 code */
51
52 static int getkeyseq(char *buffer, int len)
53 {
54         int i;
55
56         for(i = 0; i < 75; i++) {
57                 if (serial_havechar())
58                         break;
59                 mdelay(1);
60         }
61
62         if (i == 75)
63                 return len;
64
65         buffer[len++] = serial_getchar();
66         return getkeyseq(buffer, len);
67 }
68
69 static struct {
70         char *seq;
71         int key;
72 } escape_codes[] = {
73         { "[A", KEY_UP },
74         { "[B", KEY_DOWN },
75         { "[C", KEY_RIGHT },
76         { "[D", KEY_LEFT },
77         { "[F", KEY_END },
78         { "[H", KEY_HOME },
79         { "[2~", KEY_IC },
80         { "[3~", KEY_DC },
81         { "[5~", KEY_PPAGE },
82         { "[6~", KEY_NPAGE },
83         { "OP", KEY_F(1) },
84         { "OQ", KEY_F(2) },
85         { "OR", KEY_F(3) },
86         { "OS", KEY_F(4) },
87         { "[15~", KEY_F(5) },
88         { "[17~", KEY_F(6) },
89         { "[18~", KEY_F(7) },
90         { "[19~", KEY_F(8) },
91         { "[20~", KEY_F(9) },
92         { "[21~", KEY_F(10) },
93         { "[23~", KEY_F(11) },
94         { "[24~", KEY_F(12) },
95         { NULL },
96 };
97
98 static int handle_escape(void)
99 {
100         char buffer[5];
101         int len = getkeyseq(buffer, 0);
102         int i, t;
103
104         if (len == 0)
105                 return 27;
106
107         for(i = 0; escape_codes[i].seq != NULL; i++) {
108                 char *p = escape_codes[i].seq;
109
110                 for(t = 0; t < len; t++) {
111                         if (!*p || *p != buffer[t])
112                                 break;
113                         p++;
114                 }
115
116                 if (t == len)
117                         return escape_codes[i].key;
118         }
119
120         return 0;
121 }
122
123 static int cook_serial(unsigned char ch)
124 {
125         switch(ch) {
126         case 8:
127                 return KEY_BACKSPACE;
128
129         case 13:
130                 return KEY_ENTER;
131
132         case 27:
133                 return handle_escape();
134
135         default:
136                 return ch;
137         }
138 }
139 #endif
140
141 /* ================ Keyboard ================ */
142
143 static int curses_getchar(int delay)
144 {
145         unsigned short c;
146
147         do {
148 #ifdef CONFIG_PC_KEYBOARD
149                 if ((curses_flags & F_ENABLE_CONSOLE) &&
150                     keyboard_havechar()) {
151                         c = keyboard_getchar();
152                         if (c != 0) return c;
153                 }
154 #endif
155
156 #ifdef CONFIG_SERIAL_CONSOLE
157                 if ((curses_flags & F_ENABLE_SERIAL) &&
158                     serial_havechar()) {
159                         c = serial_getchar();
160                         return cook_serial(c);
161                 }
162 #endif
163
164                 if (delay == 0)
165                         break;
166
167                 if (delay > 0) {
168                         mdelay(100);
169                         delay--;
170                 }
171
172
173         } while (1);
174
175         return ERR;
176 }
177
178 /* === Public functions === */
179
180 int wgetch(WINDOW *win)
181 {
182         int delay = -1;
183
184         if (_halfdelay || win->_delay)
185                 delay = win->_delay ? 0 : _halfdelay;
186
187         return curses_getchar(delay);
188 }
189
190 int nodelay(WINDOW *win, NCURSES_BOOL flag)
191 {
192         win->_delay = flag ? 1 : 0;
193         return 0;
194 }
195
196 int halfdelay(int tenths)
197 {
198         if (tenths > 255)
199                 return ERR;
200
201         _halfdelay = tenths;
202         return 0;
203 }
204
205 int nocbreak(void)
206 {
207         /* Remove half delay timeout. */
208         _halfdelay = 0;
209         return 0;
210 }
211
212 #ifdef CONFIG_VGA_CONSOLE
213 void curses_enable_vga(int state)
214 {
215         if (state)
216                 curses_flags |= F_ENABLE_CONSOLE;
217         else
218                 curses_flags &= ~F_ENABLE_CONSOLE;
219 }
220
221 int curses_vga_enabled(void)
222 {
223         return (curses_flags & F_ENABLE_CONSOLE) != 0;
224 }
225 #else
226 void curses_enable_vga(int state) { }
227 int curses_vga_enabled(void) { return 0; }
228 #endif
229
230 #ifdef CONFIG_SERIAL_CONSOLE
231 void curses_enable_serial(int state)
232 {
233         if (state)
234                 curses_flags |= F_ENABLE_SERIAL;
235         else
236                 curses_flags &= ~F_ENABLE_SERIAL;
237 }
238
239 int curses_serial_enabled(void)
240 {
241         return (curses_flags & F_ENABLE_SERIAL) != 0;
242 }
243
244 #else
245 void curses_enable_serial(int state) { }
246 int curses_serial_enabled(void) { return 0; }
247 #endif
248