eficons.c revision 1.4 1 1.4 nonaka /* $NetBSD: eficons.c,v 1.4 2017/05/01 13:03:01 nonaka Exp $ */
2 1.1 nonaka
3 1.1 nonaka /*-
4 1.1 nonaka * Copyright (c) 2016 Kimihiro Nonaka <nonaka (at) netbsd.org>
5 1.1 nonaka * All rights reserved.
6 1.1 nonaka *
7 1.1 nonaka * Redistribution and use in source and binary forms, with or without
8 1.1 nonaka * modification, are permitted provided that the following conditions
9 1.1 nonaka * are met:
10 1.1 nonaka * 1. Redistributions of source code must retain the above copyright
11 1.1 nonaka * notice, this list of conditions and the following disclaimer.
12 1.1 nonaka * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 nonaka * notice, this list of conditions and the following disclaimer in the
14 1.1 nonaka * documentation and/or other materials provided with the distribution.
15 1.1 nonaka *
16 1.1 nonaka * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17 1.1 nonaka * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 1.1 nonaka * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 1.1 nonaka * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20 1.1 nonaka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 1.1 nonaka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 1.1 nonaka * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 1.1 nonaka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 1.1 nonaka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 1.1 nonaka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 1.1 nonaka * SUCH DAMAGE.
27 1.1 nonaka */
28 1.1 nonaka
29 1.1 nonaka #include <sys/bitops.h>
30 1.1 nonaka #include <sys/stdint.h>
31 1.1 nonaka
32 1.1 nonaka #include "efiboot.h"
33 1.1 nonaka
34 1.1 nonaka #include "bootinfo.h"
35 1.1 nonaka #include "vbe.h"
36 1.1 nonaka
37 1.4 nonaka extern struct x86_boot_params boot_params;
38 1.4 nonaka
39 1.1 nonaka struct btinfo_console btinfo_console;
40 1.1 nonaka
41 1.1 nonaka static EFI_GRAPHICS_OUTPUT_PROTOCOL *efi_gop;
42 1.1 nonaka static int efi_gop_mode = -1;
43 1.1 nonaka
44 1.1 nonaka static CHAR16 keybuf[16];
45 1.1 nonaka static int keybuf_read = 0;
46 1.1 nonaka static int keybuf_write = 0;
47 1.1 nonaka
48 1.1 nonaka static void eficons_init_video(void);
49 1.1 nonaka static void efi_switch_video_to_text_mode(void);
50 1.1 nonaka
51 1.4 nonaka static int
52 1.4 nonaka getcomaddr(int idx)
53 1.4 nonaka {
54 1.4 nonaka static const short comioport[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
55 1.4 nonaka
56 1.4 nonaka if (idx < __arraycount(comioport))
57 1.4 nonaka return comioport[idx];
58 1.4 nonaka return 0;
59 1.4 nonaka }
60 1.4 nonaka
61 1.4 nonaka /*
62 1.4 nonaka * XXX only pass console parameters to kernel.
63 1.4 nonaka */
64 1.4 nonaka void
65 1.4 nonaka consinit(int dev, int ioport, int speed)
66 1.4 nonaka {
67 1.4 nonaka int iodev;
68 1.4 nonaka
69 1.4 nonaka #if defined(CONSPEED)
70 1.4 nonaka btinfo_console.speed = CONSPEED;
71 1.4 nonaka #else
72 1.4 nonaka btinfo_console.speed = 9600;
73 1.4 nonaka #endif
74 1.4 nonaka
75 1.4 nonaka switch (dev) {
76 1.4 nonaka case CONSDEV_AUTO:
77 1.4 nonaka /* XXX comport */
78 1.4 nonaka goto nocom;
79 1.4 nonaka
80 1.4 nonaka case CONSDEV_COM0:
81 1.4 nonaka case CONSDEV_COM1:
82 1.4 nonaka case CONSDEV_COM2:
83 1.4 nonaka case CONSDEV_COM3:
84 1.4 nonaka iodev = dev;
85 1.4 nonaka comport:
86 1.4 nonaka btinfo_console.addr = ioport;
87 1.4 nonaka if (btinfo_console.addr == 0) {
88 1.4 nonaka btinfo_console.addr = getcomaddr(iodev - CONSDEV_COM0);
89 1.4 nonaka if (btinfo_console.addr == 0)
90 1.4 nonaka goto nocom;
91 1.4 nonaka }
92 1.4 nonaka if (speed != 0)
93 1.4 nonaka btinfo_console.speed = speed;
94 1.4 nonaka break;
95 1.4 nonaka
96 1.4 nonaka case CONSDEV_COM0KBD:
97 1.4 nonaka case CONSDEV_COM1KBD:
98 1.4 nonaka case CONSDEV_COM2KBD:
99 1.4 nonaka case CONSDEV_COM3KBD:
100 1.4 nonaka iodev = dev - CONSDEV_COM0KBD + CONSDEV_COM0;
101 1.4 nonaka goto comport; /* XXX kbd */
102 1.4 nonaka
103 1.4 nonaka case CONSDEV_PC:
104 1.4 nonaka default:
105 1.4 nonaka nocom:
106 1.4 nonaka iodev = CONSDEV_PC;
107 1.4 nonaka break;
108 1.4 nonaka }
109 1.4 nonaka
110 1.4 nonaka strlcpy(btinfo_console.devname, iodev == CONSDEV_PC ? "pc" : "com", 16);
111 1.4 nonaka }
112 1.4 nonaka
113 1.1 nonaka int
114 1.1 nonaka cninit(void)
115 1.1 nonaka {
116 1.1 nonaka
117 1.1 nonaka efi_switch_video_to_text_mode();
118 1.1 nonaka eficons_init_video();
119 1.1 nonaka
120 1.4 nonaka consinit(boot_params.bp_consdev, boot_params.bp_consaddr,
121 1.4 nonaka boot_params.bp_conspeed);
122 1.1 nonaka
123 1.1 nonaka return 0;
124 1.1 nonaka }
125 1.1 nonaka
126 1.1 nonaka int
127 1.1 nonaka getchar(void)
128 1.1 nonaka {
129 1.1 nonaka EFI_STATUS status;
130 1.1 nonaka EFI_INPUT_KEY key;
131 1.1 nonaka int c;
132 1.1 nonaka
133 1.1 nonaka if (keybuf_read != keybuf_write) {
134 1.1 nonaka c = keybuf[keybuf_read];
135 1.1 nonaka keybuf_read = (keybuf_read + 1) % __arraycount(keybuf);
136 1.1 nonaka return c;
137 1.1 nonaka }
138 1.1 nonaka
139 1.1 nonaka status = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn,
140 1.1 nonaka &key);
141 1.1 nonaka while (status == EFI_NOT_READY) {
142 1.1 nonaka WaitForSingleEvent(ST->ConIn->WaitForKey, 0);
143 1.1 nonaka status = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2,
144 1.1 nonaka ST->ConIn, &key);
145 1.1 nonaka }
146 1.1 nonaka return key.UnicodeChar;
147 1.1 nonaka }
148 1.1 nonaka
149 1.1 nonaka void
150 1.1 nonaka putchar(int c)
151 1.1 nonaka {
152 1.1 nonaka CHAR16 buf[2];
153 1.1 nonaka
154 1.1 nonaka buf[1] = 0;
155 1.1 nonaka if (c == '\n') {
156 1.1 nonaka buf[0] = '\r';
157 1.1 nonaka Output(buf);
158 1.1 nonaka }
159 1.1 nonaka buf[0] = c;
160 1.1 nonaka Output(buf);
161 1.1 nonaka }
162 1.1 nonaka
163 1.1 nonaka /*ARGSUSED*/
164 1.1 nonaka int
165 1.1 nonaka iskey(int intr)
166 1.1 nonaka {
167 1.1 nonaka EFI_STATUS status;
168 1.1 nonaka EFI_INPUT_KEY key;
169 1.1 nonaka
170 1.1 nonaka if (keybuf_read != keybuf_write)
171 1.1 nonaka return 1;
172 1.1 nonaka
173 1.1 nonaka status = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn,
174 1.1 nonaka &key);
175 1.1 nonaka if (EFI_ERROR(status))
176 1.1 nonaka return 0;
177 1.1 nonaka
178 1.1 nonaka keybuf[keybuf_write] = key.UnicodeChar;
179 1.1 nonaka keybuf_write = (keybuf_write + 1) % __arraycount(keybuf);
180 1.1 nonaka return 1;
181 1.1 nonaka }
182 1.1 nonaka
183 1.1 nonaka char
184 1.1 nonaka awaitkey(int timeout, int tell)
185 1.1 nonaka {
186 1.1 nonaka char c = 0;
187 1.1 nonaka
188 1.1 nonaka for (;;) {
189 1.1 nonaka if (tell) {
190 1.1 nonaka char numbuf[32];
191 1.1 nonaka int len;
192 1.1 nonaka
193 1.1 nonaka len = snprintf(numbuf, sizeof(numbuf), "%d seconds. ",
194 1.1 nonaka timeout);
195 1.1 nonaka if (len > 0 && len < sizeof(numbuf)) {
196 1.1 nonaka char *p = numbuf;
197 1.1 nonaka
198 1.1 nonaka printf("%s", numbuf);
199 1.1 nonaka while (*p)
200 1.1 nonaka *p++ = '\b';
201 1.1 nonaka printf("%s", numbuf);
202 1.1 nonaka }
203 1.1 nonaka }
204 1.1 nonaka if (iskey(1)) {
205 1.1 nonaka /* flush input buffer */
206 1.1 nonaka while (iskey(0))
207 1.1 nonaka c = getchar();
208 1.1 nonaka if (c == 0)
209 1.1 nonaka c = -1;
210 1.1 nonaka goto out;
211 1.1 nonaka }
212 1.1 nonaka if (timeout--)
213 1.1 nonaka WaitForSingleEvent(ST->ConIn->WaitForKey, 10000000);
214 1.1 nonaka else
215 1.1 nonaka break;
216 1.1 nonaka }
217 1.1 nonaka
218 1.1 nonaka out:
219 1.1 nonaka if (tell)
220 1.1 nonaka printf("0 seconds. \n");
221 1.1 nonaka
222 1.1 nonaka return c;
223 1.1 nonaka }
224 1.1 nonaka
225 1.1 nonaka void
226 1.1 nonaka clear_pc_screen(void)
227 1.1 nonaka {
228 1.1 nonaka
229 1.1 nonaka uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
230 1.1 nonaka }
231 1.1 nonaka
232 1.1 nonaka static uint8_t
233 1.1 nonaka getdepth(const EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info)
234 1.1 nonaka {
235 1.1 nonaka
236 1.1 nonaka switch (info->PixelFormat) {
237 1.1 nonaka case PixelBlueGreenRedReserved8BitPerColor:
238 1.1 nonaka case PixelRedGreenBlueReserved8BitPerColor:
239 1.1 nonaka return 32;
240 1.1 nonaka
241 1.1 nonaka case PixelBitMask:
242 1.1 nonaka return fls32(info->PixelInformation.RedMask
243 1.1 nonaka | info->PixelInformation.GreenMask
244 1.1 nonaka | info->PixelInformation.BlueMask
245 1.1 nonaka | info->PixelInformation.ReservedMask);
246 1.1 nonaka
247 1.1 nonaka case PixelBltOnly:
248 1.1 nonaka case PixelFormatMax:
249 1.1 nonaka return 0;
250 1.1 nonaka }
251 1.1 nonaka return 0;
252 1.1 nonaka }
253 1.1 nonaka
254 1.1 nonaka static void
255 1.1 nonaka setpixelformat(UINT32 mask, uint8_t *num, uint8_t *pos)
256 1.1 nonaka {
257 1.1 nonaka uint8_t n, p;
258 1.1 nonaka
259 1.1 nonaka n = popcount32(mask);
260 1.1 nonaka p = ffs32(mask);
261 1.1 nonaka if (p > 0)
262 1.1 nonaka p--;
263 1.1 nonaka
264 1.1 nonaka *num = n;
265 1.1 nonaka *pos = p;
266 1.1 nonaka }
267 1.1 nonaka
268 1.1 nonaka static void
269 1.1 nonaka bi_framebuffer(void)
270 1.1 nonaka {
271 1.1 nonaka EFI_STATUS status;
272 1.1 nonaka EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
273 1.1 nonaka struct btinfo_framebuffer fb;
274 1.1 nonaka INT32 bestmode = -1;
275 1.1 nonaka
276 1.1 nonaka if (efi_gop == NULL) {
277 1.1 nonaka framebuffer_configure(NULL);
278 1.1 nonaka return;
279 1.1 nonaka }
280 1.1 nonaka
281 1.1 nonaka if (efi_gop_mode >= 0) {
282 1.1 nonaka bestmode = efi_gop_mode;
283 1.1 nonaka } else {
284 1.2 nonaka #if 0
285 1.2 nonaka UINT64 res, bestres = 0;
286 1.2 nonaka UINTN sz;
287 1.2 nonaka UINT32 i;
288 1.2 nonaka
289 1.2 nonaka /* XXX EDID? EFI_EDID_DISCOVERED_PROTOCOL */
290 1.1 nonaka for (i = 0; i < efi_gop->Mode->MaxMode; i++) {
291 1.1 nonaka status = uefi_call_wrapper(efi_gop->QueryMode, 4,
292 1.1 nonaka efi_gop, i, &sz, &info);
293 1.1 nonaka if (EFI_ERROR(status))
294 1.1 nonaka continue;
295 1.1 nonaka
296 1.1 nonaka res = (UINT64)info->HorizontalResolution *
297 1.1 nonaka (UINT64)info->VerticalResolution *
298 1.1 nonaka (UINT64)getdepth(info);
299 1.1 nonaka if (res > bestres) {
300 1.1 nonaka bestmode = i;
301 1.1 nonaka bestres = res;
302 1.1 nonaka }
303 1.1 nonaka }
304 1.2 nonaka #endif
305 1.1 nonaka }
306 1.1 nonaka if (bestmode >= 0) {
307 1.1 nonaka status = uefi_call_wrapper(efi_gop->SetMode, 2, efi_gop,
308 1.1 nonaka bestmode);
309 1.1 nonaka if (EFI_ERROR(status) || efi_gop->Mode->Mode != bestmode)
310 1.1 nonaka Print(L"GOP setmode failed: %r\n", status);
311 1.1 nonaka }
312 1.1 nonaka
313 1.1 nonaka info = efi_gop->Mode->Info;
314 1.1 nonaka memset(&fb, 0, sizeof(fb));
315 1.1 nonaka fb.physaddr = efi_gop->Mode->FrameBufferBase;
316 1.1 nonaka fb.flags = 0;
317 1.1 nonaka fb.width = info->HorizontalResolution;
318 1.1 nonaka fb.height = info->VerticalResolution;
319 1.1 nonaka fb.depth = getdepth(info);
320 1.1 nonaka fb.stride = info->PixelsPerScanLine * ((fb.depth + 7) / 8);
321 1.1 nonaka fb.vbemode = 0; /* XXX */
322 1.1 nonaka
323 1.1 nonaka switch (info->PixelFormat) {
324 1.1 nonaka case PixelBlueGreenRedReserved8BitPerColor:
325 1.1 nonaka fb.rnum = 8;
326 1.1 nonaka fb.gnum = 8;
327 1.1 nonaka fb.bnum = 8;
328 1.1 nonaka fb.rpos = 16;
329 1.1 nonaka fb.gpos = 8;
330 1.1 nonaka fb.bpos = 0;
331 1.1 nonaka break;
332 1.1 nonaka
333 1.1 nonaka case PixelRedGreenBlueReserved8BitPerColor:
334 1.1 nonaka fb.rnum = 8;
335 1.1 nonaka fb.gnum = 8;
336 1.1 nonaka fb.bnum = 8;
337 1.1 nonaka fb.rpos = 0;
338 1.1 nonaka fb.gpos = 8;
339 1.1 nonaka fb.bpos = 16;
340 1.1 nonaka break;
341 1.1 nonaka
342 1.1 nonaka case PixelBitMask:
343 1.1 nonaka setpixelformat(info->PixelInformation.RedMask,
344 1.1 nonaka &fb.rnum, &fb.rpos);
345 1.1 nonaka setpixelformat(info->PixelInformation.GreenMask,
346 1.1 nonaka &fb.gnum, &fb.gpos);
347 1.1 nonaka setpixelformat(info->PixelInformation.BlueMask,
348 1.1 nonaka &fb.bnum, &fb.bpos);
349 1.1 nonaka break;
350 1.1 nonaka
351 1.1 nonaka case PixelBltOnly:
352 1.1 nonaka case PixelFormatMax:
353 1.1 nonaka Panic(L"Error: invalid pixel format (%d)", info->PixelFormat);
354 1.1 nonaka break;
355 1.1 nonaka }
356 1.1 nonaka
357 1.1 nonaka framebuffer_configure(&fb);
358 1.1 nonaka }
359 1.1 nonaka
360 1.1 nonaka int
361 1.1 nonaka vbe_commit(void)
362 1.1 nonaka {
363 1.1 nonaka
364 1.1 nonaka bi_framebuffer();
365 1.1 nonaka return 0;
366 1.1 nonaka }
367 1.1 nonaka
368 1.1 nonaka static void
369 1.1 nonaka print_text_modes(void)
370 1.1 nonaka {
371 1.1 nonaka EFI_STATUS status;
372 1.1 nonaka UINTN cols, rows;
373 1.1 nonaka INT32 i, curmode;
374 1.1 nonaka
375 1.1 nonaka curmode = ST->ConOut->Mode->Mode;
376 1.1 nonaka for (i = 0; i < ST->ConOut->Mode->MaxMode; i++) {
377 1.1 nonaka status = uefi_call_wrapper(ST->ConOut->QueryMode, 4,
378 1.1 nonaka ST->ConOut, i, &cols, &rows);
379 1.1 nonaka if (EFI_ERROR(status))
380 1.1 nonaka continue;
381 1.1 nonaka Print(L"%c%d: %dx%d\n", i == curmode ? '*' : ' ',
382 1.1 nonaka i, cols, rows);
383 1.1 nonaka }
384 1.1 nonaka }
385 1.1 nonaka
386 1.1 nonaka static int
387 1.1 nonaka efi_find_text_mode(char *arg)
388 1.1 nonaka {
389 1.1 nonaka EFI_STATUS status;
390 1.1 nonaka UINTN cols, rows;
391 1.1 nonaka INT32 i;
392 1.1 nonaka char mode[32];
393 1.1 nonaka
394 1.1 nonaka for (i = 0; i < ST->ConOut->Mode->MaxMode; i++) {
395 1.1 nonaka status = uefi_call_wrapper(ST->ConOut->QueryMode, 4,
396 1.1 nonaka ST->ConOut, i, &cols, &rows);
397 1.1 nonaka if (EFI_ERROR(status))
398 1.1 nonaka continue;
399 1.1 nonaka snprintf(mode, sizeof(mode), "%lux%lu", (long)cols, (long)rows);
400 1.1 nonaka if (strcmp(arg, mode) == 0)
401 1.1 nonaka return i;
402 1.1 nonaka }
403 1.1 nonaka return -1;
404 1.1 nonaka }
405 1.1 nonaka
406 1.1 nonaka void
407 1.1 nonaka command_text(char *arg)
408 1.1 nonaka {
409 1.1 nonaka EFI_STATUS status;
410 1.1 nonaka INT32 modenum;
411 1.1 nonaka
412 1.1 nonaka if (*arg == '\0' || strcmp(arg, "list") == 0) {
413 1.1 nonaka print_text_modes();
414 1.1 nonaka return;
415 1.1 nonaka }
416 1.1 nonaka
417 1.1 nonaka if (strchr(arg, 'x') != NULL) {
418 1.1 nonaka modenum = efi_find_text_mode(arg);
419 1.1 nonaka if (modenum == -1) {
420 1.1 nonaka printf("mode %s not supported by firmware\n", arg);
421 1.1 nonaka return;
422 1.1 nonaka }
423 1.1 nonaka } else {
424 1.1 nonaka modenum = strtoul(arg, NULL, 0);
425 1.1 nonaka }
426 1.1 nonaka
427 1.1 nonaka status = uefi_call_wrapper(ST->ConOut->SetMode, 2, ST->ConOut, modenum);
428 1.1 nonaka if (!EFI_ERROR(status))
429 1.1 nonaka return;
430 1.1 nonaka
431 1.1 nonaka printf("invalid flag, must be 'list', a display mode, "
432 1.1 nonaka "or a mode number\n");
433 1.1 nonaka }
434 1.1 nonaka
435 1.1 nonaka static int
436 1.1 nonaka print_gop_modes(void)
437 1.1 nonaka {
438 1.1 nonaka EFI_STATUS status;
439 1.1 nonaka EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
440 1.1 nonaka UINTN sz;
441 1.1 nonaka UINT32 i;
442 1.1 nonaka uint8_t depth;
443 1.1 nonaka
444 1.1 nonaka if (efi_gop == NULL)
445 1.1 nonaka return 1;
446 1.1 nonaka
447 1.1 nonaka for (i = 0; i < efi_gop->Mode->MaxMode; i++) {
448 1.1 nonaka status = uefi_call_wrapper(efi_gop->QueryMode, 4, efi_gop, i,
449 1.1 nonaka &sz, &info);
450 1.1 nonaka if (EFI_ERROR(status) && status == EFI_NOT_STARTED) {
451 1.1 nonaka status = uefi_call_wrapper(efi_gop->SetMode, 2,
452 1.1 nonaka efi_gop, efi_gop->Mode->Mode);
453 1.1 nonaka status = uefi_call_wrapper(efi_gop->QueryMode, 4,
454 1.1 nonaka efi_gop, i, &sz, &info);
455 1.1 nonaka }
456 1.1 nonaka if (EFI_ERROR(status))
457 1.1 nonaka continue;
458 1.1 nonaka
459 1.1 nonaka Print(L"%c%d: %dx%d ",
460 1.1 nonaka memcmp(info, efi_gop->Mode->Info, sizeof(*info)) == 0 ?
461 1.1 nonaka '*' : ' ',
462 1.1 nonaka i, info->HorizontalResolution, info->VerticalResolution);
463 1.1 nonaka switch (info->PixelFormat) {
464 1.1 nonaka case PixelRedGreenBlueReserved8BitPerColor:
465 1.1 nonaka Print(L"RGBR");
466 1.1 nonaka break;
467 1.1 nonaka case PixelBlueGreenRedReserved8BitPerColor:
468 1.1 nonaka Print(L"BGRR");
469 1.1 nonaka break;
470 1.1 nonaka case PixelBitMask:
471 1.1 nonaka Print(L"R:%08x G:%08x B:%08x X:%08x",
472 1.1 nonaka info->PixelInformation.RedMask,
473 1.1 nonaka info->PixelInformation.GreenMask,
474 1.1 nonaka info->PixelInformation.BlueMask,
475 1.1 nonaka info->PixelInformation.ReservedMask);
476 1.1 nonaka break;
477 1.1 nonaka case PixelBltOnly:
478 1.1 nonaka Print(L"(blt only)");
479 1.1 nonaka break;
480 1.1 nonaka default:
481 1.1 nonaka Print(L"(Invalid pixel format)");
482 1.1 nonaka break;
483 1.1 nonaka }
484 1.1 nonaka Print(L" pitch %d", info->PixelsPerScanLine);
485 1.1 nonaka depth = getdepth(info);
486 1.1 nonaka if (depth > 0)
487 1.1 nonaka Print(L" bpp %d", depth);
488 1.1 nonaka Print(L"\n");
489 1.1 nonaka }
490 1.1 nonaka
491 1.1 nonaka return 0;
492 1.1 nonaka }
493 1.1 nonaka
494 1.1 nonaka static int
495 1.1 nonaka efi_find_gop_mode(char *arg)
496 1.1 nonaka {
497 1.1 nonaka EFI_STATUS status;
498 1.1 nonaka EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
499 1.1 nonaka UINTN sz;
500 1.1 nonaka UINT32 i;
501 1.1 nonaka char mode[32];
502 1.1 nonaka uint8_t depth;
503 1.1 nonaka
504 1.1 nonaka for (i = 0; i < efi_gop->Mode->MaxMode; i++) {
505 1.1 nonaka status = uefi_call_wrapper(efi_gop->QueryMode, 4, efi_gop, i,
506 1.1 nonaka &sz, &info);
507 1.1 nonaka if (EFI_ERROR(status))
508 1.1 nonaka continue;
509 1.1 nonaka
510 1.1 nonaka depth = getdepth(info);
511 1.1 nonaka if (depth == 0)
512 1.1 nonaka continue;
513 1.1 nonaka
514 1.1 nonaka snprintf(mode, sizeof(mode), "%lux%lux%u",
515 1.1 nonaka (long)info->HorizontalResolution,
516 1.1 nonaka (long)info->HorizontalResolution,
517 1.1 nonaka depth);
518 1.1 nonaka if (strcmp(arg, mode) == 0)
519 1.1 nonaka return i;
520 1.1 nonaka }
521 1.1 nonaka return -1;
522 1.1 nonaka }
523 1.1 nonaka
524 1.1 nonaka void
525 1.1 nonaka command_gop(char *arg)
526 1.1 nonaka {
527 1.1 nonaka EFI_STATUS status;
528 1.1 nonaka INT32 modenum;
529 1.1 nonaka
530 1.1 nonaka if (efi_gop == NULL) {
531 1.1 nonaka printf("GOP not supported by firmware\n");
532 1.1 nonaka return;
533 1.1 nonaka }
534 1.1 nonaka
535 1.1 nonaka if (*arg == '\0' || strcmp(arg, "list") == 0) {
536 1.1 nonaka print_gop_modes();
537 1.1 nonaka return;
538 1.1 nonaka }
539 1.1 nonaka
540 1.1 nonaka if (strchr(arg, 'x') != NULL) {
541 1.1 nonaka modenum = efi_find_gop_mode(arg);
542 1.1 nonaka if (modenum == -1) {
543 1.1 nonaka printf("mode %s not supported by firmware\n", arg);
544 1.1 nonaka return;
545 1.1 nonaka }
546 1.1 nonaka } else {
547 1.1 nonaka modenum = strtoul(arg, NULL, 0);
548 1.1 nonaka }
549 1.1 nonaka
550 1.1 nonaka status = uefi_call_wrapper(efi_gop->SetMode, 2, efi_gop, modenum);
551 1.1 nonaka if (!EFI_ERROR(status) && efi_gop->Mode->Mode == modenum) {
552 1.1 nonaka efi_gop_mode = modenum;
553 1.1 nonaka return;
554 1.1 nonaka }
555 1.1 nonaka
556 1.1 nonaka printf("invalid flag, must be 'list', a display mode, "
557 1.1 nonaka "or a mode number\n");
558 1.1 nonaka }
559 1.1 nonaka
560 1.1 nonaka static void
561 1.1 nonaka eficons_init_video(void)
562 1.1 nonaka {
563 1.1 nonaka EFI_STATUS status;
564 1.3 nonaka UINTN cols, rows;
565 1.3 nonaka INT32 i, best, mode80x25, mode100x31;
566 1.1 nonaka
567 1.1 nonaka /*
568 1.1 nonaka * Setup text mode
569 1.1 nonaka */
570 1.1 nonaka uefi_call_wrapper(ST->ConOut->Reset, 2, ST->ConOut, TRUE);
571 1.1 nonaka
572 1.3 nonaka mode80x25 = mode100x31 = -1;
573 1.1 nonaka for (i = 0; i < ST->ConOut->Mode->MaxMode; i++) {
574 1.1 nonaka status = uefi_call_wrapper(ST->ConOut->QueryMode, 4,
575 1.1 nonaka ST->ConOut, i, &cols, &rows);
576 1.1 nonaka if (EFI_ERROR(status))
577 1.1 nonaka continue;
578 1.3 nonaka
579 1.3 nonaka if (mode80x25 < 0 && cols == 80 && rows == 25)
580 1.3 nonaka mode80x25 = i;
581 1.3 nonaka else if (mode100x31 < 0 && cols == 100 && rows == 31)
582 1.3 nonaka mode100x31 = i;
583 1.1 nonaka }
584 1.3 nonaka best = mode100x31 >= 0 ? mode100x31 : mode80x25 >= 0 ? mode80x25 : -1;
585 1.1 nonaka if (best >= 0)
586 1.1 nonaka uefi_call_wrapper(ST->ConOut->SetMode, 2, ST->ConOut, best);
587 1.1 nonaka uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, TRUE);
588 1.1 nonaka uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
589 1.1 nonaka
590 1.1 nonaka LibLocateProtocol(&GraphicsOutputProtocol, (void **)&efi_gop);
591 1.1 nonaka }
592 1.1 nonaka
593 1.1 nonaka /*
594 1.1 nonaka * for Apple EFI
595 1.1 nonaka */
596 1.1 nonaka #define CONSOLE_CONTROL_PROTOCOL \
597 1.1 nonaka {0xf42f7782, 0x12e, 0x4c12, {0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21}}
598 1.1 nonaka static EFI_GUID ConsoleControlProtocol = CONSOLE_CONTROL_PROTOCOL;
599 1.1 nonaka
600 1.1 nonaka struct _EFI_CONSOLE_CONTROL_INTERFACE;
601 1.1 nonaka typedef struct _EFI_CONSOLE_CONTROL_INTERFACE EFI_CONSOLE_CONTROL_INTERFACE;
602 1.1 nonaka typedef enum { EfiConsoleControlScreenText } EFI_CONSOLE_CONTROL_SCREEN_MODE;
603 1.1 nonaka typedef EFI_STATUS (EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE) (
604 1.1 nonaka IN EFI_CONSOLE_CONTROL_INTERFACE *This,
605 1.1 nonaka IN EFI_CONSOLE_CONTROL_SCREEN_MODE Mode
606 1.1 nonaka );
607 1.1 nonaka struct _EFI_CONSOLE_CONTROL_INTERFACE {
608 1.1 nonaka VOID *GetMode;
609 1.1 nonaka EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE SetMode;
610 1.1 nonaka VOID *LockStdIn;
611 1.1 nonaka };
612 1.1 nonaka
613 1.1 nonaka static void
614 1.1 nonaka efi_switch_video_to_text_mode(void)
615 1.1 nonaka {
616 1.1 nonaka EFI_STATUS status;
617 1.1 nonaka EFI_CONSOLE_CONTROL_INTERFACE *cci;
618 1.1 nonaka
619 1.1 nonaka /* Set up the console, so printf works. */
620 1.1 nonaka status = LibLocateProtocol(&ConsoleControlProtocol, (void **)&cci);
621 1.1 nonaka if (!EFI_ERROR(status)) {
622 1.1 nonaka uefi_call_wrapper(cci->SetMode, 2, cci,
623 1.1 nonaka EfiConsoleControlScreenText);
624 1.1 nonaka }
625 1.1 nonaka }
626