1 /*-
2 * Copyright (c) 2009 Jared D. McNeill <jmcneill@invisible.ca>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
15 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
16 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 /*
28 * VESA BIOS Extensions routines
29 */
30
31 #include <stand.h>
32 #include <bootstrap.h>
33 #include <machine/bootinfo.h>
34 #include <machine/metadata.h>
35 #include <sys/multiboot2.h>
36 #include <btxv86.h>
37 #include "libi386.h"
38 #include "gfx_fb.h" /* for EDID */
39 #include "vbe.h"
40 #include <sys/vgareg.h>
41 #include <sys/vgasubr.h>
42
43 multiboot_tag_vbe_t vbestate;
44 static struct vbeinfoblock *vbe =
45 (struct vbeinfoblock *) &vbestate.vbe_control_info;
46 static struct modeinfoblock *vbe_mode =
47 (struct modeinfoblock *) &vbestate.vbe_mode_info;
48 multiboot_color_t cmap[16];
49
50 /* Actually assuming mode 3. */
51 void
52 bios_set_text_mode(int mode)
53 {
54 int atr;
55
56 v86.ctl = V86_FLAGS;
57 v86.addr = 0x10;
58 v86.eax = mode; /* set VGA text mode */
59 v86int();
60 atr = vga_get_atr(VGA_REG_ADDR, VGA_ATR_MODE);
61 atr &= ~VGA_ATR_MODE_BLINK;
62 atr &= ~VGA_ATR_MODE_9WIDE;
63 vga_set_atr(VGA_REG_ADDR, VGA_ATR_MODE, atr);
64
65 vbestate.vbe_mode = 0; /* vbe is disabled */
66 gfx_fb.framebuffer_common.framebuffer_type =
67 MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT;
68 /* 16 bits per character */
69 gfx_fb.framebuffer_common.framebuffer_bpp = 16;
70 gfx_fb.framebuffer_common.framebuffer_addr =
71 VGA_MEM_ADDR + VGA_COLOR_BASE;
72 gfx_fb.framebuffer_common.framebuffer_width = TEXT_COLS;
73 gfx_fb.framebuffer_common.framebuffer_height = TEXT_ROWS;
74 gfx_fb.framebuffer_common.framebuffer_pitch = TEXT_COLS * 2;
75 }
76
77 /* Function 00h - Return VBE Controller Information */
78 static int
79 biosvbe_info(struct vbeinfoblock *vbe)
80 {
81 v86.ctl = V86_FLAGS;
82 v86.addr = 0x10;
83 v86.eax = 0x4f00;
84 v86.es = VTOPSEG(vbe);
85 v86.edi = VTOPOFF(vbe);
86 v86int();
87 return (v86.eax & 0xffff);
88 }
89
90 /* Function 01h - Return VBE Mode Information */
91 static int
92 biosvbe_get_mode_info(int mode, struct modeinfoblock *mi)
93 {
94 v86.ctl = V86_FLAGS;
95 v86.addr = 0x10;
96 v86.eax = 0x4f01;
97 v86.ecx = mode;
98 v86.es = VTOPSEG(mi);
99 v86.edi = VTOPOFF(mi);
100 v86int();
101 return (v86.eax & 0xffff);
102 }
103
104 /* Function 02h - Set VBE Mode */
105 static int
106 biosvbe_set_mode(int mode, struct crtciinfoblock *ci)
107 {
108 v86.ctl = V86_FLAGS;
109 v86.addr = 0x10;
110 v86.eax = 0x4f02;
111 v86.ebx = mode | 0x4000; /* set linear FB bit */
112 v86.es = VTOPSEG(ci);
113 v86.edi = VTOPOFF(ci);
114 v86int();
115 return (v86.eax & 0xffff);
116 }
117
118 /* Function 03h - Get VBE Mode */
119 static int
120 biosvbe_get_mode(int *mode)
121 {
122 v86.ctl = V86_FLAGS;
123 v86.addr = 0x10;
124 v86.eax = 0x4f03;
125 v86int();
126 *mode = v86.ebx & 0xffff;
127 return (v86.eax & 0xffff);
128 }
129
130 /* Function 08h - Set/Get DAC Palette Format */
131 int
132 biosvbe_palette_format(int *format)
133 {
134 v86.ctl = V86_FLAGS;
135 v86.addr = 0x10;
136 v86.eax = 0x4f08;
137 v86.ebx = *format;
138 v86int();
139 *format = v86.ebx & 0xffff;
140 return (v86.eax & 0xffff);
141 }
142
143 /* Function 09h - Set/Get Palette Data */
144 static int
145 biosvbe_palette_data(int mode, int reg, struct paletteentry *pe)
146 {
147 v86.ctl = V86_FLAGS;
148 v86.addr = 0x10;
149 v86.eax = 0x4f09;
150 v86.ebx = mode;
151 v86.edx = reg;
152 v86.ecx = 1;
153 v86.es = VTOPSEG(pe);
154 v86.edi = VTOPOFF(pe);
155 v86int();
156 return (v86.eax & 0xffff);
157 }
158
159 /*
160 * Function 15h BL=00h - Report VBE/DDC Capabilities
161 *
162 * int biosvbe_ddc_caps(void)
163 * return: VBE/DDC capabilities
164 */
165 static int
166 biosvbe_ddc_caps(void)
167 {
168 v86.ctl = V86_FLAGS;
169 v86.addr = 0x10;
170 v86.eax = 0x4f15; /* display identification extensions */
171 v86.ebx = 0; /* report DDC capabilities */
172 v86.ecx = 0; /* controller unit number (00h = primary) */
173 v86.es = 0;
174 v86.edi = 0;
175 v86int();
176 if (VBE_ERROR(v86.eax & 0xffff))
177 return (0);
178 return (v86.ebx & 0xffff);
179 }
180
181 /* Function 15h BL=01h - Read EDID */
182 static int
183 biosvbe_ddc_read_edid(int blockno, void *buf)
184 {
185 v86.ctl = V86_FLAGS;
186 v86.addr = 0x10;
187 v86.eax = 0x4f15; /* display identification extensions */
188 v86.ebx = 1; /* read EDID */
189 v86.ecx = 0; /* controller unit number (00h = primary) */
190 v86.edx = blockno;
191 v86.es = VTOPSEG(buf);
192 v86.edi = VTOPOFF(buf);
193 v86int();
194 return (v86.eax & 0xffff);
195 }
196
197 static int
198 vbe_mode_is_supported(struct modeinfoblock *mi)
199 {
200 if ((mi->ModeAttributes & 0x01) == 0)
201 return 0; /* mode not supported by hardware */
202 if ((mi->ModeAttributes & 0x08) == 0)
203 return 0; /* linear fb not available */
204 if ((mi->ModeAttributes & 0x10) == 0)
205 return 0; /* text mode */
206 if (mi->NumberOfPlanes != 1)
207 return 0; /* planar mode not supported */
208 if (mi->MemoryModel != 0x04 /* Packed pixel */ &&
209 mi->MemoryModel != 0x06 /* Direct Color */)
210 return 0; /* unsupported pixel format */
211 return 1;
212 }
213
214 static int
215 vbe_check(void)
216 {
217 if (vbestate.mb_type != MULTIBOOT_TAG_TYPE_VBE) {
218 printf("VBE not available\n");
219 return (0);
220 }
221 return (1);
222 }
223
224 void
225 vbe_init(void)
226 {
227 /* First set FB for text mode. */
228 gfx_fb.framebuffer_common.mb_type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER;
229 gfx_fb.framebuffer_common.framebuffer_type =
230 MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT;
231 /* 16 bits per character */
232 gfx_fb.framebuffer_common.framebuffer_bpp = 16;
233 gfx_fb.framebuffer_common.framebuffer_addr =
234 VGA_MEM_ADDR + VGA_COLOR_BASE;
235 gfx_fb.framebuffer_common.framebuffer_width = TEXT_COLS;
236 gfx_fb.framebuffer_common.framebuffer_height = TEXT_ROWS;
237 gfx_fb.framebuffer_common.framebuffer_pitch = TEXT_COLS * 2;
238
239 /* Now check if we have vesa. */
240 memset(vbe, 0, sizeof(*vbe));
241 memcpy(vbe->VbeSignature, "VBE2", 4);
242 if (biosvbe_info(vbe) != VBE_SUCCESS)
243 return;
244 if (memcmp(vbe->VbeSignature, "VESA", 4) != 0)
245 return;
246
247 vbestate.mb_type = MULTIBOOT_TAG_TYPE_VBE;
248 vbestate.mb_size = sizeof (vbestate);
249 vbestate.vbe_mode = 0;
250 /* vbe_set_mode() will set up the rest. */
251 }
252
253 int
254 vbe_available(void)
255 {
256 return vbestate.mb_type;
257 }
258
259 int
260 vbe_set_palette(const struct paletteentry *entry, int slot)
261 {
262 struct paletteentry pe;
263 int ret;
264
265 if (!vbe_check())
266 return (1);
267
268 if (gfx_fb.framebuffer_common.framebuffer_type !=
269 MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED) {
270 return (1);
271 }
272
273 pe.Blue = entry->Blue;
274 pe.Green = entry->Green;
275 pe.Red = entry->Red;
276 pe.Alignment = entry->Alignment;
277
278 ret = biosvbe_palette_data(0x00, slot, &pe);
279 if (ret == VBE_SUCCESS && slot < sizeof (cmap)) {
280 cmap[slot].mb_red = entry->Red;
281 cmap[slot].mb_green = entry->Green;
282 cmap[slot].mb_blue = entry->Blue;
283 }
284
285 return (ret == VBE_SUCCESS ? 0 : 1);
286 }
287
288 int
289 vbe_get_mode(void)
290 {
291 return vbestate.vbe_mode;
292 }
293
294 int
295 vbe_set_mode(int modenum)
296 {
297 struct modeinfoblock mi;
298 int ret, i, bpp;
299
300 if (!vbe_check())
301 return (1);
302
303 ret = biosvbe_get_mode_info(modenum, &mi);
304 if (VBE_ERROR(ret)) {
305 printf("mode 0x%x invalid\n", modenum);
306 return (1);
307 }
308
309 if (!vbe_mode_is_supported(&mi)) {
310 printf("mode 0x%x not supported\n", modenum);
311 return (1);
312 }
313
314 /* calculate bytes per pixel */
315 switch (mi.BitsPerPixel) {
316 case 32:
317 bpp = 4;
318 break;
319 case 24:
320 bpp = 3;
321 break;
322 case 16:
323 case 15:
324 bpp = 2;
325 break;
326 case 8:
327 bpp = 1;
328 break;
329 default:
330 printf("BitsPerPixel %d is not supported\n", mi.BitsPerPixel);
331 return (1);
332 }
333
334 ret = biosvbe_set_mode(modenum, NULL);
335 if (VBE_ERROR(ret)) {
336 printf("mode 0x%x could not be set\n", modenum);
337 return (1);
338 }
339
340 /* make sure we have current MI in vbestate */
341 memcpy(vbe_mode, &mi, sizeof (*vbe_mode));
342 vbestate.vbe_mode = modenum;
343
344 gfx_fb.framebuffer_common.framebuffer_addr =
345 (uint64_t)mi.PhysBasePtr & 0xffffffff;
346 gfx_fb.framebuffer_common.framebuffer_width = mi.XResolution;
347 gfx_fb.framebuffer_common.framebuffer_height = mi.YResolution;
348 gfx_fb.framebuffer_common.framebuffer_bpp = mi.BitsPerPixel;
349
350 /* vbe_mode_is_supported() excludes the rest */
351 switch (mi.MemoryModel) {
352 case 0x4:
353 gfx_fb.framebuffer_common.framebuffer_type =
354 MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED;
355 if (vbe->VbeVersion >= 0x300) {
356 gfx_fb.framebuffer_common.framebuffer_pitch =
357 mi.LinBytesPerScanLine;
358 } else {
359 gfx_fb.framebuffer_common.framebuffer_pitch =
360 mi.BytesPerScanLine;
361 }
362 gfx_fb.u.fb1.framebuffer_palette_num_colors = 16;
363 return (0); /* done */
364 case 0x6:
365 gfx_fb.framebuffer_common.framebuffer_type =
366 MULTIBOOT_FRAMEBUFFER_TYPE_RGB;
367 break;
368 }
369
370 if (vbe->VbeVersion >= 0x300) {
371 gfx_fb.framebuffer_common.framebuffer_pitch =
372 mi.LinBytesPerScanLine;
373 gfx_fb.u.fb2.framebuffer_red_field_position =
374 mi.LinRedFieldPosition;
375 gfx_fb.u.fb2.framebuffer_red_mask_size = mi.LinRedMaskSize;
376 gfx_fb.u.fb2.framebuffer_green_field_position =
377 mi.LinGreenFieldPosition;
378 gfx_fb.u.fb2.framebuffer_green_mask_size = mi.LinGreenMaskSize;
379 gfx_fb.u.fb2.framebuffer_blue_field_position =
380 mi.LinBlueFieldPosition;
381 gfx_fb.u.fb2.framebuffer_blue_mask_size = mi.LinBlueMaskSize;
382 } else {
383 gfx_fb.framebuffer_common.framebuffer_pitch =
384 mi.BytesPerScanLine;
385 gfx_fb.u.fb2.framebuffer_red_field_position =
386 mi.RedFieldPosition;
387 gfx_fb.u.fb2.framebuffer_red_mask_size = mi.RedMaskSize;
388 gfx_fb.u.fb2.framebuffer_green_field_position =
389 mi.GreenFieldPosition;
390 gfx_fb.u.fb2.framebuffer_green_mask_size = mi.GreenMaskSize;
391 gfx_fb.u.fb2.framebuffer_blue_field_position =
392 mi.BlueFieldPosition;
393 gfx_fb.u.fb2.framebuffer_blue_mask_size = mi.BlueMaskSize;
394 }
395
396 return (0);
397 }
398
399 static void *
400 vbe_farptr(uint32_t farptr)
401 {
402 return PTOV((((farptr & 0xffff0000) >> 12) + (farptr & 0xffff)));
403 }
404
405 static int
406 vbe_parse_mode_str(char *str, int *x, int *y, int *depth)
407 {
408 char *p;
409
410 p = str;
411 *x = strtoul(p, NULL, 0);
412 if (*x == 0)
413 return (0);
414 p = strchr(p, 'x');
415 if (!p)
416 return (0);
417 ++p;
418 *y = strtoul(p, NULL, 0);
419 if (*y == 0)
420 return (0);
421 p = strchr(p, 'x');
422 if (!p)
423 *depth = -1; /* auto select */
424 else {
425 ++p;
426 *depth = strtoul(p, NULL, 0);
427 if (*depth == 0)
428 return (0);
429 }
430
431 return (1);
432 }
433
434 /*
435 * Verify existance of mode number or find mode by
436 * dimensions. If depth is not given, walk values 32, 24, 16, 8.
437 */
438 static int
439 vbe_find_mode_xydm(int x, int y, int depth, int m)
440 {
441 struct modeinfoblock mi;
442 uint32_t farptr;
443 uint16_t mode;
444 int safety = 0, d, i;
445
446 memset(vbe, 0, sizeof(vbe));
447 memcpy(vbe->VbeSignature, "VBE2", 4);
448 if (biosvbe_info(vbe) != VBE_SUCCESS)
449 return (0);
450 if (memcmp(vbe->VbeSignature, "VESA", 4) != 0)
451 return (0);
452 farptr = vbe->VideoModePtr;
453 if (farptr == 0)
454 return (0);
455
456 if (m != -1)
457 i = 8;
458 else if (depth == -1)
459 i = 32;
460 else
461 i = depth;
462
463 while (i > 0) {
464 while ((mode = *(uint16_t *)vbe_farptr(farptr)) != 0xffff) {
465 safety++;
466 farptr += 2;
467 if (safety == 100)
468 return 0;
469 if (biosvbe_get_mode_info(mode, &mi) != VBE_SUCCESS) {
470 continue;
471 }
472 /* we only care about linear modes here */
473 if (vbe_mode_is_supported(&mi) == 0)
474 continue;
475 safety = 0;
476
477 if (m != -1) {
478 if (m == mode)
479 return (mode);
480 else
481 continue;
482 }
483
484 if (mi.XResolution == x &&
485 mi.YResolution == y &&
486 mi.BitsPerPixel == i)
487 return mode;
488 }
489 if (depth != -1)
490 break;
491
492 i -= 8;
493 }
494
495 return (0);
496 }
497
498 static int
499 vbe_find_mode(char *str)
500 {
501 int x, y, depth;
502
503 if (!vbe_parse_mode_str(str, &x, &y, &depth))
504 return (0);
505
506 return (vbe_find_mode_xydm(x, y, depth, -1));
507 }
508
509 static void
510 vbe_dump_mode(int modenum, struct modeinfoblock *mi)
511 {
512 printf("0x%x=%dx%dx%d", modenum,
513 mi->XResolution, mi->YResolution, mi->BitsPerPixel);
514 }
515
516 static int
517 vbe_get_edid(int *pwidth, int *pheight)
518 {
519 struct vesa_edid_info edid_info;
520 const uint8_t magic[] = EDID_MAGIC;
521 int ddc_caps, ret, i;
522
523 ddc_caps = biosvbe_ddc_caps();
524 if (ddc_caps == 0) {
525 return (1);
526 }
527
528 ret = biosvbe_ddc_read_edid(0, &edid_info);
529 if (VBE_ERROR(ret))
530 return (1);
531
532 if (memcmp(&edid_info, magic, sizeof(magic)) != 0)
533 return (1);
534
535 if (!(edid_info.header.version == 1 &&
536 (edid_info.display.supported_features
537 & EDID_FEATURE_PREFERRED_TIMING_MODE) &&
538 edid_info.detailed_timings[0].pixel_clock))
539 return (1);
540
541 *pwidth = edid_info.detailed_timings[0].horizontal_active_lo |
542 (((int)edid_info.detailed_timings[0].horizontal_hi & 0xf0) << 4);
543 *pheight = edid_info.detailed_timings[0].vertical_active_lo |
544 (((int)edid_info.detailed_timings[0].vertical_hi & 0xf0) << 4);
545
546 return (0);
547 }
548
549 static void
550 vbe_print_vbe_info(struct vbeinfoblock *vbep)
551 {
552 char *oemstring = "";
553 char *oemvendor = "", *oemproductname = "", *oemproductrev = "";
554
555 if (vbep->OemStringPtr != 0)
556 oemstring = vbe_farptr(vbep->OemStringPtr);
557
558 if (vbep->OemVendorNamePtr != 0)
559 oemvendor = vbe_farptr(vbep->OemVendorNamePtr);
560
561 if (vbep->OemProductNamePtr != 0)
562 oemproductname = vbe_farptr(vbep->OemProductNamePtr);
563
564 if (vbep->OemProductRevPtr != 0)
565 oemproductrev = vbe_farptr(vbep->OemProductRevPtr);
566
567 printf("VESA VBE Version %d.%d\n%s\n", vbep->VbeVersion >> 8,
568 vbep->VbeVersion & 0xF, oemstring);
569
570 if (vbep->OemSoftwareRev != 0) {
571 printf("OEM Version %d.%d, %s (%s, %s)\n",
572 vbep->OemSoftwareRev >> 8, vbep->OemSoftwareRev & 0xF,
573 oemvendor, oemproductname, oemproductrev);
574 }
575 }
576
577 /* List available modes, filter by depth. If depth is -1, list all. */
578 void
579 vbe_modelist(int depth)
580 {
581 struct modeinfoblock mi;
582 uint32_t farptr;
583 uint16_t mode;
584 int nmodes = 0, safety = 0;
585 int ddc_caps, edid_width, edid_height;
586
587 if (!vbe_check())
588 return;
589
590 ddc_caps = biosvbe_ddc_caps();
591 if (ddc_caps & 3) {
592 printf("DDC");
593 if (ddc_caps & 1)
594 printf(" [DDC1]");
595 if (ddc_caps & 2)
596 printf(" [DDC2]");
597
598 if (vbe_get_edid(&edid_width, &edid_height) != 0)
599 printf(": no EDID information\n");
600 else
601 printf(": EDID %dx%d\n", edid_width, edid_height);
602 }
603
604 memset(vbe, 0, sizeof(vbe));
605 memcpy(vbe->VbeSignature, "VBE2", 4);
606 if (biosvbe_info(vbe) != VBE_SUCCESS)
607 goto done;
608 if (memcmp(vbe->VbeSignature, "VESA", 4) != 0)
609 goto done;
610
611 vbe_print_vbe_info(vbe);
612 printf("Modes: ");
613
614 farptr = vbe->VideoModePtr;
615 if (farptr == 0)
616 goto done;
617
618 while ((mode = *(uint16_t *)vbe_farptr(farptr)) != 0xffff) {
619 safety++;
620 farptr += 2;
621 if (safety == 100) {
622 printf("[?] ");
623 break;
624 }
625 if (biosvbe_get_mode_info(mode, &mi) != VBE_SUCCESS)
626 continue;
627 /* we only care about linear modes here */
628 if (vbe_mode_is_supported(&mi) == 0)
629 continue;
630
631 /* we found some mode so reset safety counter */
632 safety = 0;
633
634 /* apply requested filter */
635 if (depth != -1 && mi.BitsPerPixel != depth)
636 continue;
637
638 if (nmodes % 4 == 0)
639 printf("\n");
640 else
641 printf(" ");
642
643 vbe_dump_mode(mode, &mi);
644 nmodes++;
645 }
646
647 done:
648 if (nmodes == 0)
649 printf("none found");
650 printf("\n");
651 }
652
653 static void
654 vbe_print_mode(void)
655 {
656 int mode, i, rc;
657 struct paletteentry pe;
658
659 memset(vbe, 0, sizeof(vbe));
660 memcpy(vbe->VbeSignature, "VBE2", 4);
661 if (biosvbe_info(vbe) != VBE_SUCCESS)
662 return;
663
664 if (memcmp(vbe->VbeSignature, "VESA", 4) != 0)
665 return;
666
667 vbe_print_vbe_info(vbe);
668
669 if (biosvbe_get_mode(&mode) != VBE_SUCCESS) {
670 printf("Error getting current VBE mode\n");
671 return;
672 }
673
674 if (biosvbe_get_mode_info(mode, vbe_mode) != VBE_SUCCESS ||
675 vbe_mode_is_supported(vbe_mode) == 0) {
676 printf("VBE mode (0x%x) is not framebuffer mode\n", mode);
677 return;
678 }
679
680 printf("\nCurrent VBE mode: ");
681 vbe_dump_mode(mode, vbe_mode);
682 printf("\n");
683
684 printf("%ux%ux%u, stride=%u",
685 gfx_fb.framebuffer_common.framebuffer_width,
686 gfx_fb.framebuffer_common.framebuffer_height,
687 gfx_fb.framebuffer_common.framebuffer_bpp,
688 (gfx_fb.framebuffer_common.framebuffer_pitch << 3) /
689 gfx_fb.framebuffer_common.framebuffer_bpp);
690 printf("\n frame buffer: address=%jx, size=%jx",
691 (uintmax_t) gfx_fb.framebuffer_common.framebuffer_addr,
692 (uintmax_t) gfx_fb.framebuffer_common.framebuffer_height *
693 gfx_fb.framebuffer_common.framebuffer_pitch);
694
695 if (vbe_mode->MemoryModel == 0x6) {
696 printf("\n color mask: R=%08x, G=%08x, B=%08x\n",
697 ((1 << gfx_fb.u.fb2.framebuffer_red_mask_size) - 1) <<
698 gfx_fb.u.fb2.framebuffer_red_field_position,
699 ((1 << gfx_fb.u.fb2.framebuffer_green_mask_size) - 1) <<
700 gfx_fb.u.fb2.framebuffer_green_field_position,
701 ((1 << gfx_fb.u.fb2.framebuffer_blue_mask_size) - 1) <<
702 gfx_fb.u.fb2.framebuffer_blue_field_position);
703 return;
704 }
705
706 mode = 1; /* get DAC palette width */
707 rc = biosvbe_palette_format(&mode);
708 if (rc != VBE_SUCCESS)
709 return;
710
711 printf(" palette format: %x bits per primary\n", mode >> 8);
712 for (i = 0; i < 16; i++) {
713 rc = biosvbe_palette_data(1, i, &pe);
714 if (rc != VBE_SUCCESS)
715 break;
716
717 printf("%d: R=%02x, G=%02x, B=%02x\n", i,
718 pe.Red, pe.Green, pe.Blue);
719 }
720 }
721
722 int
723 vbe_default_mode(void)
724 {
725 int modenum, edid_width, edid_height;
726
727 if (vbe_get_edid(&edid_width, &edid_height) != 0) {
728 modenum = vbe_find_mode(VBE_DEFAULT_MODE);
729 } else {
730 modenum = vbe_find_mode_xydm(edid_width, edid_height, -1, -1);
731 if (modenum == 0)
732 modenum = vbe_find_mode(VBE_DEFAULT_MODE);
733 }
734 return (modenum);
735 }
736
737 COMMAND_SET(framebuffer, "framebuffer", "framebuffer mode management",
738 command_vesa);
739
740 int
741 command_vesa(int argc, char *argv[])
742 {
743 char *arg, *cp;
744 int modenum = -1, n;
745
746 if (!vbe_check())
747 return (CMD_OK);
748
749 if (argc < 2)
750 goto usage;
751
752 if (strcmp(argv[1], "list") == 0) {
753 n = -1;
754 if (argc != 2 && argc != 3)
755 goto usage;
756
757 if (argc == 3) {
758 arg = argv[2];
759 errno = 0;
760 n = strtoul(arg, &cp, 0);
761 if (errno != 0 || *arg == '\0' || cp[0] != '\0') {
762 snprintf(command_errbuf,
763 sizeof (command_errbuf),
764 "depth should be an integer");
765 return (CMD_ERROR);
766 }
767 }
768 vbe_modelist(n);
769 return (CMD_OK);
770 }
771
772 if (strcmp(argv[1], "get") == 0) {
773 if (argc != 2)
774 goto usage;
775
776 vbe_print_mode();
777 return (CMD_OK);
778 }
779
780 if (strcmp(argv[1], "off") == 0) {
781 if (argc != 2)
782 goto usage;
783
784 if (vbestate.vbe_mode == 0)
785 return (CMD_OK);
786
787 bios_set_text_mode(3); /* set VGA text mode 3 */
788 plat_cons_update_mode(0);
789 return (CMD_OK);
790 }
791
792 if (strcmp(argv[1], "on") == 0) {
793 if (argc != 2)
794 goto usage;
795
796 modenum = vbe_default_mode();
797 if (modenum == 0) {
798 sprintf(command_errbuf,
799 "%s: no suitable VBE mode number found", argv[0]);
800 return (CMD_ERROR);
801 }
802 } else if (strcmp(argv[1], "set") == 0) {
803 if (argc != 3)
804 goto usage;
805
806 if (strncmp(argv[2], "0x", 2) == 0) {
807 arg = argv[2];
808 errno = 0;
809 n = strtoul(arg, &cp, 0);
810 if (errno != 0 || *arg == '\0' || cp[0] != '\0') {
811 snprintf(command_errbuf,
812 sizeof (command_errbuf),
813 "mode should be an integer");
814 return (CMD_ERROR);
815 }
816 modenum = vbe_find_mode_xydm(0, 0, 0, n);
817 } else if (strchr(argv[2], 'x') != NULL) {
818 modenum = vbe_find_mode(argv[2]);
819 }
820 }
821
822 if (modenum == 0) {
823 sprintf(command_errbuf, "%s: mode %s not supported by "
824 "firmware\n", argv[0], argv[2]);
825 return (CMD_ERROR);
826 }
827
828 if (modenum >= 0x100) {
829 if (vbestate.vbe_mode != modenum) {
830 vbe_set_mode(modenum);
831 plat_cons_update_mode(1);
832 }
833 return (CMD_OK);
834 } else {
835 sprintf(command_errbuf, "%s: mode %s is not framebuffer mode\n",
836 argv[0], argv[2]);
837 return (CMD_ERROR);
838 }
839
840 usage:
841 sprintf(command_errbuf, "usage: %s on | off | get | list [depth] | "
842 "set <display or VBE mode number>", argv[0]);
843 return (CMD_ERROR);
844 }