]>
Commit | Line | Data |
---|---|---|
976a4ea0 | 1 | /* |
2 | * GRUB -- GRand Unified Bootloader | |
f36cc108 | 3 | * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. |
976a4ea0 | 4 | * |
5a79f472 | 5 | * GRUB is free software: you can redistribute it and/or modify |
976a4ea0 | 6 | * it under the terms of the GNU General Public License as published by |
5a79f472 | 7 | * the Free Software Foundation, either version 3 of the License, or |
976a4ea0 | 8 | * (at your option) any later version. |
9 | * | |
5a79f472 | 10 | * GRUB is distributed in the hope that it will be useful, |
976a4ea0 | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
5a79f472 | 16 | * along with GRUB. If not, see <http://www.gnu.org/licenses/>. |
976a4ea0 | 17 | */ |
18 | ||
19 | #include <grub/term.h> | |
7f362539 | 20 | #include <grub/misc.h> |
976a4ea0 | 21 | #include <grub/types.h> |
22 | #include <grub/err.h> | |
23 | #include <grub/efi/efi.h> | |
24 | #include <grub/efi/api.h> | |
25 | #include <grub/efi/console.h> | |
26 | ||
20011694 | 27 | static grub_uint32_t |
28 | map_char (grub_uint32_t c) | |
29 | { | |
d7fd78dc VS |
30 | /* Map some unicode characters to the EFI character. */ |
31 | switch (c) | |
20011694 | 32 | { |
d7fd78dc VS |
33 | case GRUB_UNICODE_LEFTARROW: |
34 | c = GRUB_UNICODE_BLACK_LEFT_TRIANGLE; | |
35 | break; | |
36 | case GRUB_UNICODE_UPARROW: | |
37 | c = GRUB_UNICODE_BLACK_UP_TRIANGLE; | |
38 | break; | |
39 | case GRUB_UNICODE_RIGHTARROW: | |
40 | c = GRUB_UNICODE_BLACK_RIGHT_TRIANGLE; | |
41 | break; | |
42 | case GRUB_UNICODE_DOWNARROW: | |
43 | c = GRUB_UNICODE_BLACK_DOWN_TRIANGLE; | |
44 | break; | |
45 | case GRUB_UNICODE_HLINE: | |
46 | c = GRUB_UNICODE_LIGHT_HLINE; | |
47 | break; | |
48 | case GRUB_UNICODE_VLINE: | |
49 | c = GRUB_UNICODE_LIGHT_VLINE; | |
50 | break; | |
51 | case GRUB_UNICODE_CORNER_UL: | |
52 | c = GRUB_UNICODE_LIGHT_CORNER_UL; | |
53 | break; | |
54 | case GRUB_UNICODE_CORNER_UR: | |
55 | c = GRUB_UNICODE_LIGHT_CORNER_UR; | |
56 | break; | |
57 | case GRUB_UNICODE_CORNER_LL: | |
58 | c = GRUB_UNICODE_LIGHT_CORNER_LL; | |
59 | break; | |
60 | case GRUB_UNICODE_CORNER_LR: | |
61 | c = GRUB_UNICODE_LIGHT_CORNER_LR; | |
62 | break; | |
20011694 | 63 | } |
64 | ||
65 | return c; | |
66 | } | |
67 | ||
976a4ea0 | 68 | static void |
58664b94 VS |
69 | grub_console_putchar (struct grub_term_output *term __attribute__ ((unused)), |
70 | const struct grub_unicode_glyph *c) | |
976a4ea0 | 71 | { |
9a3355cf | 72 | grub_efi_char16_t str[2 + c->ncomb]; |
976a4ea0 | 73 | grub_efi_simple_text_output_interface_t *o; |
9a3355cf | 74 | unsigned i, j; |
b39f9d20 | 75 | |
91b58e6b VS |
76 | if (grub_efi_is_finished) |
77 | return; | |
78 | ||
976a4ea0 | 79 | o = grub_efi_system_table->con_out; |
b39f9d20 | 80 | |
976a4ea0 | 81 | /* For now, do not try to use a surrogate pair. */ |
9a3355cf VS |
82 | if (c->base > 0xffff) |
83 | str[0] = '?'; | |
84 | else | |
85 | str[0] = (grub_efi_char16_t) map_char (c->base & 0xffff); | |
86 | j = 1; | |
87 | for (i = 0; i < c->ncomb; i++) | |
88 | if (c->base < 0xffff) | |
89 | str[j++] = c->combining[i].code; | |
90 | str[j] = 0; | |
976a4ea0 | 91 | |
92 | /* Should this test be cached? */ | |
9a3355cf VS |
93 | if ((c->base > 0x7f || c->ncomb) |
94 | && efi_call_2 (o->test_string, o, str) != GRUB_EFI_SUCCESS) | |
976a4ea0 | 95 | return; |
b39f9d20 | 96 | |
20011694 | 97 | efi_call_2 (o->output_string, o, str); |
976a4ea0 | 98 | } |
99 | ||
7a6459e1 VS |
100 | const unsigned efi_codes[] = |
101 | { | |
39feb0e8 VS |
102 | 0, GRUB_TERM_KEY_UP, GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_RIGHT, |
103 | GRUB_TERM_KEY_LEFT, GRUB_TERM_KEY_HOME, GRUB_TERM_KEY_END, GRUB_TERM_KEY_INSERT, | |
104 | GRUB_TERM_KEY_DC, GRUB_TERM_KEY_PPAGE, GRUB_TERM_KEY_NPAGE, GRUB_TERM_KEY_F1, | |
7a6459e1 VS |
105 | GRUB_TERM_KEY_F2, GRUB_TERM_KEY_F3, GRUB_TERM_KEY_F4, GRUB_TERM_KEY_F5, |
106 | GRUB_TERM_KEY_F6, GRUB_TERM_KEY_F7, GRUB_TERM_KEY_F8, GRUB_TERM_KEY_F9, | |
107 | GRUB_TERM_KEY_F10, 0, 0, '\e' | |
108 | }; | |
109 | ||
110 | ||
976a4ea0 | 111 | static int |
df2174dd | 112 | grub_console_getkey (struct grub_term_input *term __attribute__ ((unused))) |
976a4ea0 | 113 | { |
114 | grub_efi_simple_input_interface_t *i; | |
115 | grub_efi_input_key_t key; | |
7f362539 | 116 | grub_efi_status_t status; |
b39f9d20 | 117 | |
91b58e6b VS |
118 | if (grub_efi_is_finished) |
119 | return 0; | |
120 | ||
976a4ea0 | 121 | i = grub_efi_system_table->con_in; |
20011694 | 122 | status = efi_call_2 (i->read_key_stroke, i, &key); |
7f362539 | 123 | |
7a6459e1 | 124 | if (status != GRUB_EFI_SUCCESS) |
9518e2a1 | 125 | return GRUB_TERM_NO_KEY; |
b39f9d20 | 126 | |
7a6459e1 | 127 | if (key.scan_code == 0) |
df2174dd | 128 | return key.unicode_char; |
7a6459e1 | 129 | else if (key.scan_code < ARRAY_SIZE (efi_codes)) |
df2174dd | 130 | return efi_codes[key.scan_code]; |
b39f9d20 | 131 | |
9518e2a1 | 132 | return GRUB_TERM_NO_KEY; |
976a4ea0 | 133 | } |
134 | ||
135 | static grub_uint16_t | |
58664b94 | 136 | grub_console_getwh (struct grub_term_output *term __attribute__ ((unused))) |
976a4ea0 | 137 | { |
138 | grub_efi_simple_text_output_interface_t *o; | |
139 | grub_efi_uintn_t columns, rows; | |
b39f9d20 | 140 | |
976a4ea0 | 141 | o = grub_efi_system_table->con_out; |
91b58e6b VS |
142 | if (grub_efi_is_finished || efi_call_4 (o->query_mode, o, o->mode->mode, |
143 | &columns, &rows) != GRUB_EFI_SUCCESS) | |
976a4ea0 | 144 | { |
145 | /* Why does this fail? */ | |
146 | columns = 80; | |
147 | rows = 25; | |
148 | } | |
149 | ||
150 | return ((columns << 8) | rows); | |
151 | } | |
152 | ||
153 | static grub_uint16_t | |
58664b94 | 154 | grub_console_getxy (struct grub_term_output *term __attribute__ ((unused))) |
976a4ea0 | 155 | { |
156 | grub_efi_simple_text_output_interface_t *o; | |
b39f9d20 | 157 | |
91b58e6b VS |
158 | if (grub_efi_is_finished) |
159 | return 0; | |
160 | ||
976a4ea0 | 161 | o = grub_efi_system_table->con_out; |
162 | return ((o->mode->cursor_column << 8) | o->mode->cursor_row); | |
163 | } | |
164 | ||
165 | static void | |
58664b94 VS |
166 | grub_console_gotoxy (struct grub_term_output *term __attribute__ ((unused)), |
167 | grub_uint8_t x, grub_uint8_t y) | |
976a4ea0 | 168 | { |
169 | grub_efi_simple_text_output_interface_t *o; | |
b39f9d20 | 170 | |
91b58e6b VS |
171 | if (grub_efi_is_finished) |
172 | return; | |
173 | ||
976a4ea0 | 174 | o = grub_efi_system_table->con_out; |
20011694 | 175 | efi_call_3 (o->set_cursor_position, o, x, y); |
976a4ea0 | 176 | } |
177 | ||
178 | static void | |
58664b94 | 179 | grub_console_cls (struct grub_term_output *term __attribute__ ((unused))) |
976a4ea0 | 180 | { |
181 | grub_efi_simple_text_output_interface_t *o; | |
89a7d726 | 182 | grub_efi_int32_t orig_attr; |
b39f9d20 | 183 | |
91b58e6b VS |
184 | if (grub_efi_is_finished) |
185 | return; | |
186 | ||
976a4ea0 | 187 | o = grub_efi_system_table->con_out; |
89a7d726 | 188 | orig_attr = o->mode->attribute; |
20011694 | 189 | efi_call_2 (o->set_attributes, o, GRUB_EFI_BACKGROUND_BLACK); |
190 | efi_call_1 (o->clear_screen, o); | |
191 | efi_call_2 (o->set_attributes, o, orig_attr); | |
976a4ea0 | 192 | } |
193 | ||
194 | static void | |
bc136973 VS |
195 | grub_console_setcolorstate (struct grub_term_output *term |
196 | __attribute__ ((unused)), | |
58664b94 | 197 | grub_term_color_state state) |
976a4ea0 | 198 | { |
199 | grub_efi_simple_text_output_interface_t *o; | |
200 | ||
91b58e6b VS |
201 | if (grub_efi_is_finished) |
202 | return; | |
203 | ||
976a4ea0 | 204 | o = grub_efi_system_table->con_out; |
205 | ||
206 | switch (state) { | |
207 | case GRUB_TERM_COLOR_STANDARD: | |
441cfe65 VS |
208 | efi_call_2 (o->set_attributes, o, GRUB_TERM_DEFAULT_STANDARD_COLOR |
209 | & 0x7f); | |
976a4ea0 | 210 | break; |
211 | case GRUB_TERM_COLOR_NORMAL: | |
bc136973 | 212 | efi_call_2 (o->set_attributes, o, grub_term_normal_color & 0x7f); |
976a4ea0 | 213 | break; |
214 | case GRUB_TERM_COLOR_HIGHLIGHT: | |
bc136973 | 215 | efi_call_2 (o->set_attributes, o, grub_term_highlight_color & 0x7f); |
976a4ea0 | 216 | break; |
217 | default: | |
218 | break; | |
219 | } | |
220 | } | |
221 | ||
976a4ea0 | 222 | static void |
58664b94 VS |
223 | grub_console_setcursor (struct grub_term_output *term __attribute__ ((unused)), |
224 | int on) | |
976a4ea0 | 225 | { |
226 | grub_efi_simple_text_output_interface_t *o; | |
227 | ||
91b58e6b VS |
228 | if (grub_efi_is_finished) |
229 | return; | |
230 | ||
976a4ea0 | 231 | o = grub_efi_system_table->con_out; |
20011694 | 232 | efi_call_2 (o->enable_cursor, o, on); |
976a4ea0 | 233 | } |
234 | ||
dd8ff5c9 CW |
235 | static grub_err_t |
236 | grub_efi_console_init (struct grub_term_output *term) | |
237 | { | |
4ce776d2 | 238 | grub_efi_set_text_mode (1); |
dd8ff5c9 CW |
239 | grub_console_setcursor (term, 1); |
240 | return 0; | |
241 | } | |
242 | ||
243 | static grub_err_t | |
244 | grub_efi_console_fini (struct grub_term_output *term) | |
245 | { | |
246 | grub_console_setcursor (term, 0); | |
4ce776d2 | 247 | grub_efi_set_text_mode (0); |
dd8ff5c9 CW |
248 | return 0; |
249 | } | |
250 | ||
651c29b7 | 251 | static struct grub_term_input grub_console_term_input = |
976a4ea0 | 252 | { |
253 | .name = "console", | |
976a4ea0 | 254 | .getkey = grub_console_getkey, |
651c29b7 | 255 | }; |
256 | ||
257 | static struct grub_term_output grub_console_term_output = | |
258 | { | |
259 | .name = "console", | |
dd8ff5c9 CW |
260 | .init = grub_efi_console_init, |
261 | .fini = grub_efi_console_fini, | |
651c29b7 | 262 | .putchar = grub_console_putchar, |
976a4ea0 | 263 | .getwh = grub_console_getwh, |
264 | .getxy = grub_console_getxy, | |
265 | .gotoxy = grub_console_gotoxy, | |
266 | .cls = grub_console_cls, | |
267 | .setcolorstate = grub_console_setcolorstate, | |
9a3355cf | 268 | .setcursor = grub_console_setcursor, |
1d383404 | 269 | .flags = GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS |
976a4ea0 | 270 | }; |
271 | ||
272 | void | |
273 | grub_console_init (void) | |
274 | { | |
275 | /* FIXME: it is necessary to consider the case where no console control | |
276 | is present but the default is already in text mode. */ | |
277 | if (! grub_efi_set_text_mode (1)) | |
278 | { | |
279 | grub_error (GRUB_ERR_BAD_DEVICE, "cannot set text mode"); | |
280 | return; | |
281 | } | |
282 | ||
822873a7 RM |
283 | grub_term_register_input ("console", &grub_console_term_input); |
284 | grub_term_register_output ("console", &grub_console_term_output); | |
976a4ea0 | 285 | } |
286 | ||
287 | void | |
288 | grub_console_fini (void) | |
289 | { | |
651c29b7 | 290 | grub_term_unregister_input (&grub_console_term_input); |
291 | grub_term_unregister_output (&grub_console_term_output); | |
976a4ea0 | 292 | } |