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