blob: 895c956ec9692ef6a53145a88fc7ee8311598e45 [file] [log] [blame]
Jordan Crousef6145c32008-03-19 23:56:58 +00001/*
2 * This file is part of the libpayload project.
3 *
4 * Copyright (C) 2008 Advanced Micro Devices, Inc.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
Jordan Crousef6145c32008-03-19 23:56:58 +000030#include <libpayload.h>
Patrick Georgie6408a32008-09-17 18:12:46 +000031#include <curses.h>
Jordan Crousef6145c32008-03-19 23:56:58 +000032
Jordan Crouse63f181f2008-04-25 23:09:39 +000033#define I8042_CMD_READ_MODE 0x20
34#define I8042_CMD_WRITE_MODE 0x60
35
36#define I8042_MODE_XLATE 0x40
37
Patrick Georgie6408a32008-09-17 18:12:46 +000038unsigned short map[4][0x57] = {
39 { /* No modifier */
Uwe Hermann6a441bf2008-03-20 19:54:59 +000040 0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
41 0x37, 0x38, 0x39, 0x30, 0x2D, 0x3D, 0x08, 0x09,
42 0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69,
43 0x6F, 0x70, 0x5B, 0x5D, 0x0A, 0x00, 0x61, 0x73,
44 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x3B,
45 0x27, 0x60, 0x00, 0x5C, 0x7A, 0x78, 0x63, 0x76,
46 0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2F, 0x00, 0x2A,
Patrick Georgie6408a32008-09-17 18:12:46 +000047 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, KEY_HOME,
49 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
50 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x00
Uwe Hermann6a441bf2008-03-20 19:54:59 +000051 },
Patrick Georgie6408a32008-09-17 18:12:46 +000052 { /* Shift */
Uwe Hermann6a441bf2008-03-20 19:54:59 +000053 0x00, 0x1B, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E,
54 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x08, 0x00,
55 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49,
56 0x4F, 0x50, 0x7B, 0x7D, 0x0A, 0x00, 0x41, 0x53,
57 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3A,
58 0x22, 0x7E, 0x00, 0x7C, 0x5A, 0x58, 0x43, 0x56,
59 0x42, 0x4E, 0x4D, 0x3C, 0x3E, 0x3F, 0x00, 0x2A,
Patrick Georgie6408a32008-09-17 18:12:46 +000060 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, KEY_HOME,
62 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
63 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x00
64 },
65 { /* ALT */
66 0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
67 0x37, 0x38, 0x39, 0x30, 0x2D, 0x3D, 0x08, 0x09,
68 0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69,
69 0x6F, 0x70, 0x5B, 0x5D, 0x0A, 0x00, 0x61, 0x73,
70 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x3B,
71 0x27, 0x60, 0x00, 0x5C, 0x7A, 0x78, 0x63, 0x76,
72 0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2F, 0x00, 0x2A,
73 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
74 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, KEY_HOME,
75 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
76 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x00
77 },
78 { /* Shift-ALT */
79 0x00, 0x1B, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E,
80 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x08, 0x00,
81 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49,
82 0x4F, 0x50, 0x7B, 0x7D, 0x0A, 0x00, 0x41, 0x53,
83 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3A,
84 0x22, 0x7E, 0x00, 0x7C, 0x5A, 0x58, 0x43, 0x56,
85 0x42, 0x4E, 0x4D, 0x3C, 0x3E, 0x3F, 0x00, 0x2A,
86 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
87 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, KEY_HOME,
88 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
89 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x00
Uwe Hermann6a441bf2008-03-20 19:54:59 +000090 }
Jordan Crousef6145c32008-03-19 23:56:58 +000091};
92
Patrick Georgie6408a32008-09-17 18:12:46 +000093#define MOD_SHIFT (1 << 0)
94#define MOD_CTRL (1 << 1)
95#define MOD_CAPSLOCK (1 << 2)
96#define MOD_ALT (1 << 3)
Jordan Crousef6145c32008-03-19 23:56:58 +000097
98int keyboard_havechar(void)
99{
100 unsigned char c = inb(0x64);
101 return c & 1;
102}
103
104unsigned char keyboard_get_scancode(void)
105{
106 unsigned char ch = 0;
107
108 if (keyboard_havechar())
109 ch = inb(0x60);
110
111 return ch;
112}
113
114int keyboard_getchar(void)
115{
Stefan Reinauer56471f12008-09-02 09:35:43 +0000116 static int modifier = 0;
Jordan Crousef6145c32008-03-19 23:56:58 +0000117 unsigned char ch;
118 int shift;
Jordan Crousef6145c32008-03-19 23:56:58 +0000119 int ret = 0;
120
Uwe Hermann6a441bf2008-03-20 19:54:59 +0000121 while (!keyboard_havechar()) ;
Jordan Crousef6145c32008-03-19 23:56:58 +0000122
123 ch = keyboard_get_scancode();
124
Uwe Hermann6a441bf2008-03-20 19:54:59 +0000125 switch (ch) {
Jordan Crousef6145c32008-03-19 23:56:58 +0000126 case 0x36:
127 case 0x2a:
Stefan Reinauer56471f12008-09-02 09:35:43 +0000128 modifier |= MOD_SHIFT;
Jordan Crousef6145c32008-03-19 23:56:58 +0000129 break;
Jordan Crousef6145c32008-03-19 23:56:58 +0000130 case 0x80 | 0x36:
131 case 0x80 | 0x2a:
Stefan Reinauer56471f12008-09-02 09:35:43 +0000132 modifier &= ~MOD_SHIFT;
Stefan Reinauer96b734c2008-08-12 14:19:40 +0000133 break;
Patrick Georgie6408a32008-09-17 18:12:46 +0000134 case 0x38:
135 modifier |= MOD_ALT;
136 break;
137 case 0x80 | 0x38:
138 modifier &= ~MOD_ALT;
139 break;
Jordan Crousef6145c32008-03-19 23:56:58 +0000140 case 0x1d:
Stefan Reinauer56471f12008-09-02 09:35:43 +0000141 modifier |= MOD_CTRL;
Jordan Crousef6145c32008-03-19 23:56:58 +0000142 break;
Jordan Crousef6145c32008-03-19 23:56:58 +0000143 case 0x80 | 0x1d:
Stefan Reinauer56471f12008-09-02 09:35:43 +0000144 modifier &= ~MOD_CTRL;
Jordan Crousef6145c32008-03-19 23:56:58 +0000145 break;
Jordan Crousef6145c32008-03-19 23:56:58 +0000146 case 0x3a:
147 if (modifier & MOD_CAPSLOCK)
148 modifier &= ~MOD_CAPSLOCK;
149 else
150 modifier |= MOD_CAPSLOCK;
151 break;
152 }
153
Uwe Hermann6a441bf2008-03-20 19:54:59 +0000154 if (!(ch & 0x80) && ch < 0x57) {
155 shift =
156 (modifier & MOD_SHIFT) ^ (modifier & MOD_CAPSLOCK) ? 1 : 0;
Patrick Georgie6408a32008-09-17 18:12:46 +0000157
158 if (modifier & MOD_ALT)
159 shift += 2;
160
Jordan Crousef6145c32008-03-19 23:56:58 +0000161 ret = map[shift][ch];
162
163 if (modifier & MOD_CTRL)
Patrick Georgie6408a32008-09-17 18:12:46 +0000164 ret = (ret >= 'a' && ret <= 'z') ? ret & 0x1f : 0;
Jordan Crousef6145c32008-03-19 23:56:58 +0000165
166 return ret;
167 }
168
169 return ret;
170}
Jordan Crouse63f181f2008-04-25 23:09:39 +0000171
172static int keyboard_wait_read(void)
173{
174 int timeout = 10000;
175
176 while(timeout-- && !(inb(0x64) & 0x01))
177 udelay(50);
178
179 return (timeout <= 0) ? -1 : 0;
180}
181
182static int keyboard_wait_write(void)
183{
184 int timeout = 10000;
185
186 while(timeout-- && (inb(0x64) & 0x02))
187 udelay(50);
188
189 return (timeout <= 0) ? -1 : 0;
190}
191
192static unsigned char keyboard_get_mode(void)
193{
194 outb(I8042_CMD_READ_MODE, 0x64);
195 keyboard_wait_read();
196 return inb(0x60);
197}
198
199static void keyboard_set_mode(unsigned char mode)
200{
201 outb(I8042_CMD_WRITE_MODE, 0x64);
202 keyboard_wait_write();
203 outb(mode, 0x60);
204}
205
206void keyboard_init(void)
207{
208 u8 mode;
209
Patrick Georgie6408a32008-09-17 18:12:46 +0000210 /* Empty keyboard buffer */
211 while (keyboard_havechar()) keyboard_getchar();
212
Jordan Crouse63f181f2008-04-25 23:09:39 +0000213 /* Read the current mode */
214 mode = keyboard_get_mode();
215
216 /* Turn on scancode translate mode so that we can
217 use the scancode set 1 tables */
218
219 mode |= I8042_MODE_XLATE;
220
221 /* Write the new mode */
222 keyboard_set_mode(mode);
223}
224