1 /*
2 * Copyright 2004-2009, Axel Dörfler, axeld@pinc-software.de.
3 * Copyright 2008, Stephan Aßmus <superstippi@gmx.de>
4 * Copyright 2008, Philippe Saint-Pierre <stpere@gmail.com>
5 * Copyright 2011, Rene Gollent, rene@gollent.com.
6 * Distributed under the terms of the MIT License.
7 */
8
9
10 #include "video.h"
11 #include "bios.h"
12 #include "vesa.h"
13 #include "vesa_info.h"
14 #include "vga.h"
15 #include "mmu.h"
16
17 #include <edid.h>
18
19 #include <arch/cpu.h>
20 #include <boot/stage2.h>
21 #include <boot/platform.h>
22 #include <boot/menu.h>
23 #include <boot/kernel_args.h>
24 #include <boot/platform/generic/video.h>
25 #include <util/list.h>
26 #include <drivers/driver_settings.h>
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32
33 #define TRACE_VIDEO
34 #ifdef TRACE_VIDEO
35 # define TRACE(x) dprintf x
36 #else
37 # define TRACE(x) ;
38 #endif
39
40
41 struct video_mode {
42 list_link link;
43 uint16 mode;
44 uint16 width, height, bits_per_pixel;
45 uint32 bytes_per_row;
46 crtc_info_block* timing;
47 };
48
49 static vbe_info_block sInfo;
50 static video_mode *sMode, *sDefaultMode;
51 static bool sVesaCompatible;
52 static struct list sModeList;
53 static uint32 sModeCount;
54 static addr_t sFrameBuffer;
55 static bool sModeChosen;
56 static bool sSettingsLoaded;
57
58
59 static int
compare_video_modes(video_mode * a,video_mode * b)60 compare_video_modes(video_mode *a, video_mode *b)
61 {
62 int compare = a->width - b->width;
63 if (compare != 0)
64 return compare;
65
66 compare = a->height - b->height;
67 if (compare != 0)
68 return compare;
69
70 // TODO: compare video_mode::mode?
71 return a->bits_per_pixel - b->bits_per_pixel;
72 }
73
74
75 /*! Insert the video mode into the list, sorted by resolution and bit depth.
76 Higher resolutions/depths come first.
77 */
78 static void
add_video_mode(video_mode * videoMode)79 add_video_mode(video_mode *videoMode)
80 {
81 video_mode *mode = NULL;
82 while ((mode = (video_mode *)list_get_next_item(&sModeList, mode))
83 != NULL) {
84 int compare = compare_video_modes(videoMode, mode);
85 if (compare == 0) {
86 // mode already exists
87 return;
88 }
89
90 if (compare > 0)
91 break;
92 }
93
94 list_insert_item_before(&sModeList, mode, videoMode);
95 sModeCount++;
96 }
97
98
99 /*! \brief Finds a video mode with the given resolution.
100 If \a allowPalette is true, 8-bit modes are considered, too.
101 If \a height is \c -1, the height is ignored, and only the width
102 matters.
103 */
104 static video_mode *
find_video_mode(int32 width,int32 height,bool allowPalette)105 find_video_mode(int32 width, int32 height, bool allowPalette)
106 {
107 video_mode *found = NULL;
108 video_mode *mode = NULL;
109 while ((mode = (video_mode *)list_get_next_item(&sModeList, mode))
110 != NULL) {
111 if (mode->width == width && (height == -1 || mode->height == height)
112 && (mode->bits_per_pixel > 8 || allowPalette)) {
113 if (found == NULL || found->bits_per_pixel < mode->bits_per_pixel)
114 found = mode;
115 }
116 }
117
118 return found;
119 }
120
121
122 /*! Returns the VESA mode closest to the one specified, with a width less or
123 equal as specified.
124 The height as well as the depth may vary in both directions, though.
125 */
126 static video_mode *
closest_video_mode(int32 width,int32 height,int32 depth)127 closest_video_mode(int32 width, int32 height, int32 depth)
128 {
129 video_mode *bestMode = NULL;
130 uint32 bestDiff = 0;
131
132 video_mode *mode = NULL;
133 while ((mode = (video_mode *)list_get_next_item(&sModeList, mode))
134 != NULL) {
135 if (mode->width > width) {
136 // Only choose modes with a width less or equal than the searched
137 // one; or else it might well be that the monitor cannot keep up.
138 continue;
139 }
140
141 uint32 diff = 2 * abs(mode->width - width) + abs(mode->height - height)
142 + abs(mode->bits_per_pixel - depth);
143
144 if (bestMode == NULL || bestDiff > diff) {
145 bestMode = mode;
146 bestDiff = diff;
147 }
148 }
149
150 return bestMode;
151 }
152
153
154 static crtc_info_block*
get_crtc_info_block(edid1_detailed_timing & timing)155 get_crtc_info_block(edid1_detailed_timing& timing)
156 {
157 // This feature is only available on chipsets supporting VBE3 and up
158 if (sInfo.version.major < 3)
159 return NULL;
160
161 // Copy timing structure to set the mode with
162 crtc_info_block* crtcInfo = (crtc_info_block*)malloc(
163 sizeof(crtc_info_block));
164 if (crtcInfo == NULL)
165 return NULL;
166
167 memset(crtcInfo, 0, sizeof(crtc_info_block));
168 crtcInfo->horizontal_sync_start = timing.h_active + timing.h_sync_off;
169 crtcInfo->horizontal_sync_end = crtcInfo->horizontal_sync_start
170 + timing.h_sync_width;
171 crtcInfo->horizontal_total = timing.h_active + timing.h_blank;
172 crtcInfo->vertical_sync_start = timing.v_active + timing.v_sync_off;
173 crtcInfo->vertical_sync_end = crtcInfo->vertical_sync_start
174 + timing.v_sync_width;
175 crtcInfo->vertical_total = timing.v_active + timing.v_blank;
176 crtcInfo->pixel_clock = timing.pixel_clock * 10000L;
177 crtcInfo->refresh_rate = crtcInfo->pixel_clock
178 / (crtcInfo->horizontal_total / 10)
179 / (crtcInfo->vertical_total / 10);
180
181 TRACE(("crtc: h %u/%u/%u, v %u/%u/%u, pixel clock %u, refresh %u\n",
182 crtcInfo->horizontal_sync_start, crtcInfo->horizontal_sync_end,
183 crtcInfo->horizontal_total, crtcInfo->vertical_sync_start,
184 crtcInfo->vertical_sync_end, crtcInfo->vertical_total,
185 crtcInfo->pixel_clock, crtcInfo->refresh_rate));
186
187 crtcInfo->flags = 0;
188 if (timing.sync == 3) {
189 // TODO: this switches the default sync when sync != 3 (compared to
190 // create_display_modes().
191 if ((timing.misc & 1) == 0)
192 crtcInfo->flags |= CRTC_NEGATIVE_HSYNC;
193 if ((timing.misc & 2) == 0)
194 crtcInfo->flags |= CRTC_NEGATIVE_VSYNC;
195 }
196 if (timing.interlaced)
197 crtcInfo->flags |= CRTC_INTERLACED;
198
199 return crtcInfo;
200 }
201
202
203 static crtc_info_block*
get_crtc_info_block(edid1_std_timing & timing)204 get_crtc_info_block(edid1_std_timing& timing)
205 {
206 // TODO: implement me!
207 return NULL;
208 }
209
210
211 static video_mode*
find_edid_mode(edid1_info & info,bool allowPalette)212 find_edid_mode(edid1_info& info, bool allowPalette)
213 {
214 video_mode *mode = NULL;
215
216 // try detailed timing first
217 for (int32 i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; i++) {
218 edid1_detailed_monitor& monitor = info.detailed_monitor[i];
219
220 if (monitor.monitor_desc_type == EDID1_IS_DETAILED_TIMING) {
221 mode = find_video_mode(monitor.data.detailed_timing.h_active,
222 monitor.data.detailed_timing.v_active, allowPalette);
223 if (mode != NULL) {
224 mode->timing
225 = get_crtc_info_block(monitor.data.detailed_timing);
226 return mode;
227 }
228 }
229 }
230
231 int32 best = -1;
232
233 // try standard timings next
234 for (int32 i = 0; i < EDID1_NUM_STD_TIMING; i++) {
235 if (info.std_timing[i].h_size <= 256)
236 continue;
237
238 video_mode* found = find_video_mode(info.std_timing[i].h_size,
239 info.std_timing[i].v_size, allowPalette);
240 if (found != NULL) {
241 if (mode != NULL) {
242 // prefer higher resolutions
243 if (found->width > mode->width) {
244 mode = found;
245 best = i;
246 }
247 } else {
248 mode = found;
249 best = i;
250 }
251 }
252 }
253
254 if (best >= 0)
255 mode->timing = get_crtc_info_block(info.std_timing[best]);
256
257 return mode;
258 }
259
260
261 static void
vesa_fixups(void * settings)262 vesa_fixups(void *settings)
263 {
264 const char *oem_string = (const char *)sInfo.oem_string;
265
266 if (!strcmp(oem_string, "NVIDIA")) {
267 const char *arg = NULL;
268 int32 scaling = -1;
269
270 if (settings != NULL)
271 arg = get_driver_parameter(settings, "nvidia_scaling", NULL, "1");
272 if (arg != NULL)
273 scaling = strtol(arg, NULL, 0);
274
275 if (scaling > -1) {
276 dprintf("Setting nvidia scaling mode to %" B_PRId32 "\n", scaling);
277 struct bios_regs regs;
278 regs.eax = 0x4f14;
279 regs.ebx = 0x0102;
280 regs.ecx = scaling;
281 call_bios(0x10, ®s);
282 }
283 }
284
285 }
286
287
288 static bool
get_mode_from_settings(void)289 get_mode_from_settings(void)
290 {
291 if (sSettingsLoaded)
292 return true;
293
294 void *handle = load_driver_settings("vesa");
295 if (handle == NULL)
296 return false;
297
298 vesa_fixups(handle);
299
300 bool found = false;
301
302 const driver_settings *settings = get_driver_settings(handle);
303 if (settings == NULL)
304 goto out;
305
306 sSettingsLoaded = true;
307
308 for (int32 i = 0; i < settings->parameter_count; i++) {
309 driver_parameter ¶meter = settings->parameters[i];
310
311 if (!strcmp(parameter.name, "mode") && parameter.value_count > 2) {
312 // parameter found, now get its values
313 int32 width = strtol(parameter.values[0], NULL, 0);
314 int32 height = strtol(parameter.values[1], NULL, 0);
315 int32 depth = strtol(parameter.values[2], NULL, 0);
316
317 // search mode that fits
318
319 video_mode *mode = closest_video_mode(width, height, depth);
320 if (mode != NULL) {
321 found = true;
322 sMode = mode;
323 }
324 }
325 }
326
327 out:
328 unload_driver_settings(handle);
329 return found;
330 }
331
332
333 // #pragma mark - vga
334
335
336 static void
vga_set_palette(const uint8 * palette,int32 firstIndex,int32 numEntries)337 vga_set_palette(const uint8 *palette, int32 firstIndex, int32 numEntries)
338 {
339 out8(firstIndex, VGA_COLOR_WRITE_MODE);
340 // write VGA palette
341 for (int32 i = firstIndex; i < numEntries; i++) {
342 // VGA (usually) has only 6 bits per gun
343 out8(palette[i * 3 + 0] >> 2, VGA_COLOR_DATA);
344 out8(palette[i * 3 + 1] >> 2, VGA_COLOR_DATA);
345 out8(palette[i * 3 + 2] >> 2, VGA_COLOR_DATA);
346 }
347 }
348
349
350 static void
vga_enable_bright_background_colors(void)351 vga_enable_bright_background_colors(void)
352 {
353 // reset attribute controller
354 in8(VGA_INPUT_STATUS_1);
355
356 // select mode control register
357 out8(0x30, VGA_ATTRIBUTE_WRITE);
358
359 // read mode control register, change it (we need to clear bit 3), and write it back
360 uint8 mode = in8(VGA_ATTRIBUTE_READ) & 0xf7;
361 out8(mode, VGA_ATTRIBUTE_WRITE);
362 }
363
364
365 // #pragma mark - vesa
366
367
368 static status_t
vesa_get_edid(edid1_info * info)369 vesa_get_edid(edid1_info *info)
370 {
371 struct bios_regs regs;
372 regs.eax = 0x4f15;
373 regs.ebx = 0;
374 // report DDC service
375 regs.ecx = 0;
376 regs.es = 0;
377 regs.edi = 0;
378 call_bios(0x10, ®s);
379
380 TRACE(("EDID1: %x\n", regs.eax));
381 // %ah contains the error code
382 // %al determines whether or not the function is supported
383 if (regs.eax != 0x4f)
384 return B_NOT_SUPPORTED;
385
386 TRACE(("EDID2: ebx %x\n", regs.ebx));
387 // test if DDC is supported by the monitor
388 if ((regs.ebx & 3) == 0)
389 return B_NOT_SUPPORTED;
390
391 edid1_raw edidRaw;
392
393 regs.eax = 0x4f15;
394 regs.ebx = 1;
395 // read EDID
396 regs.ecx = 0;
397 regs.edx = 0;
398 regs.es = ADDRESS_SEGMENT(&edidRaw);
399 regs.edi = ADDRESS_OFFSET(&edidRaw);
400 call_bios(0x10, ®s);
401 TRACE(("EDID3: %x\n", regs.eax));
402
403 if (regs.eax != 0x4f)
404 return B_NOT_SUPPORTED;
405
406 // retrieved EDID - now parse it
407 edid_decode(info, &edidRaw);
408
409 #ifdef TRACE_VIDEO
410 edid_dump(info);
411 #endif
412 return B_OK;
413 }
414
415
416 static status_t
vesa_get_mode_info(uint16 mode,struct vbe_mode_info * modeInfo)417 vesa_get_mode_info(uint16 mode, struct vbe_mode_info *modeInfo)
418 {
419 memset(modeInfo, 0, sizeof(vbe_mode_info));
420
421 struct bios_regs regs;
422 regs.eax = 0x4f01;
423 regs.ecx = mode;
424 regs.es = ADDRESS_SEGMENT(modeInfo);
425 regs.edi = ADDRESS_OFFSET(modeInfo);
426 call_bios(0x10, ®s);
427
428 // %ah contains the error code
429 if ((regs.eax & 0xff00) != 0)
430 return B_ENTRY_NOT_FOUND;
431
432 return B_OK;
433 }
434
435
436 static status_t
vesa_get_vbe_info_block(vbe_info_block * info)437 vesa_get_vbe_info_block(vbe_info_block *info)
438 {
439 memset(info, 0, sizeof(vbe_info_block));
440 info->signature = VBE2_SIGNATURE;
441
442 struct bios_regs regs;
443 regs.eax = 0x4f00;
444 regs.es = ADDRESS_SEGMENT(info);
445 regs.edi = ADDRESS_OFFSET(info);
446 call_bios(0x10, ®s);
447
448 // %ah contains the error code
449 if ((regs.eax & 0xff00) != 0)
450 return B_ERROR;
451
452 if (info->signature != VESA_SIGNATURE)
453 return B_ERROR;
454
455 dprintf("VESA version = %d.%d, capabilities %x\n", info->version.major,
456 info->version.minor, info->capabilities);
457
458 if (info->version.major < 2) {
459 dprintf("VESA support too old\n");
460 return B_ERROR;
461 }
462
463 info->oem_string = SEGMENTED_TO_LINEAR(info->oem_string);
464 info->mode_list = SEGMENTED_TO_LINEAR(info->mode_list);
465 dprintf("OEM string: %s\n", (const char *)info->oem_string);
466
467 return B_OK;
468 }
469
470
471 static status_t
vesa_init(vbe_info_block * info,video_mode ** _standardMode)472 vesa_init(vbe_info_block *info, video_mode **_standardMode)
473 {
474 if (vesa_get_vbe_info_block(info) != B_OK)
475 return B_ERROR;
476
477 // fill mode list and find standard video mode
478
479 video_mode *standardMode = NULL;
480
481 for (int32 i = 0; true; i++) {
482 uint16 mode = ((uint16 *)info->mode_list)[i];
483 if (mode == 0xffff)
484 break;
485
486 struct vbe_mode_info modeInfo;
487 if (vesa_get_mode_info(mode, &modeInfo) == B_OK) {
488 TRACE((" 0x%03x: %u x %u x %u (a = %d, mem = %d, phy = %x, p = %d, b = %d)\n", mode,
489 modeInfo.width, modeInfo.height, modeInfo.bits_per_pixel, modeInfo.attributes,
490 modeInfo.memory_model, modeInfo.physical_base, modeInfo.num_planes,
491 modeInfo.num_banks));
492 TRACE((" mask: r: %d %d g: %d %d b: %d %d dcmi: %d\n",
493 modeInfo.red_mask_size, modeInfo.red_field_position,
494 modeInfo.green_mask_size, modeInfo.green_field_position,
495 modeInfo.blue_mask_size, modeInfo.blue_field_position,
496 modeInfo.direct_color_mode_info));
497
498 const uint32 requiredAttributes = MODE_ATTR_AVAILABLE
499 | MODE_ATTR_GRAPHICS_MODE | MODE_ATTR_COLOR_MODE
500 | MODE_ATTR_LINEAR_BUFFER;
501
502 if (modeInfo.width >= 640
503 && modeInfo.physical_base != 0
504 && modeInfo.num_planes == 1
505 && (modeInfo.memory_model == MODE_MEMORY_PACKED_PIXEL
506 || modeInfo.memory_model == MODE_MEMORY_DIRECT_COLOR)
507 && (modeInfo.attributes & requiredAttributes)
508 == requiredAttributes) {
509 // this mode fits our needs
510 video_mode *videoMode = (video_mode *)malloc(
511 sizeof(struct video_mode));
512 if (videoMode == NULL)
513 continue;
514
515 videoMode->mode = mode;
516 videoMode->bytes_per_row = modeInfo.bytes_per_row;
517 videoMode->width = modeInfo.width;
518 videoMode->height = modeInfo.height;
519 videoMode->bits_per_pixel = modeInfo.bits_per_pixel;
520 videoMode->timing = NULL;
521
522 if (modeInfo.bits_per_pixel == 16
523 && modeInfo.red_mask_size + modeInfo.green_mask_size
524 + modeInfo.blue_mask_size == 15) {
525 // this is really a 15-bit mode
526 videoMode->bits_per_pixel = 15;
527 }
528
529 add_video_mode(videoMode);
530 }
531 } else
532 TRACE((" 0x%03x: (failed)\n", mode));
533 }
534
535 // Choose default resolution (when no EDID information is available)
536 const uint32 kPreferredWidth = 1024;
537 const uint32 kFallbackWidth = 800;
538
539 standardMode = find_video_mode(kPreferredWidth, -1, false);
540 if (standardMode == NULL) {
541 standardMode = find_video_mode(kFallbackWidth, -1, false);
542 if (standardMode == NULL) {
543 standardMode = find_video_mode(kPreferredWidth, -1, true);
544 if (standardMode == NULL)
545 standardMode = find_video_mode(kFallbackWidth, -1, true);
546 }
547 }
548 if (standardMode == NULL) {
549 // just take any mode
550 standardMode = (video_mode *)list_get_first_item(&sModeList);
551 }
552
553 if (standardMode == NULL) {
554 // no usable VESA mode found...
555 return B_ERROR;
556 }
557
558 TRACE(("Using mode 0x%03x\n", standardMode->mode));
559 *_standardMode = standardMode;
560 return B_OK;
561 }
562
563
564 #if 0
565 static status_t
566 vesa_get_mode(uint16 *_mode)
567 {
568 struct bios_regs regs;
569 regs.eax = 0x4f03;
570 call_bios(0x10, ®s);
571
572 if ((regs.eax & 0xffff) != 0x4f)
573 return B_ERROR;
574
575 *_mode = regs.ebx & 0xffff;
576 return B_OK;
577 }
578 #endif
579
580
581 static status_t
vesa_set_mode(video_mode * mode,bool useTiming)582 vesa_set_mode(video_mode* mode, bool useTiming)
583 {
584 struct bios_regs regs;
585 regs.eax = 0x4f02;
586 regs.ebx = (mode->mode & SET_MODE_MASK) | SET_MODE_LINEAR_BUFFER;
587
588 if (useTiming && mode->timing != NULL) {
589 regs.ebx |= SET_MODE_SPECIFY_CRTC;
590 regs.es = ADDRESS_SEGMENT(mode->timing);
591 regs.edi = ADDRESS_OFFSET(mode->timing);
592 }
593
594 call_bios(0x10, ®s);
595
596 if ((regs.eax & 0xffff) != 0x4f)
597 return B_ERROR;
598
599 #if 0
600 // make sure we have 8 bits per color channel
601 regs.eax = 0x4f08;
602 regs.ebx = 8 << 8;
603 call_bios(0x10, ®s);
604 #endif
605
606 return B_OK;
607 }
608
609
610 static status_t
vesa_set_palette(const uint8 * palette,int32 firstIndex,int32 numEntries)611 vesa_set_palette(const uint8 *palette, int32 firstIndex, int32 numEntries)
612 {
613 // is this an 8 bit indexed color mode?
614 if (gKernelArgs.frame_buffer.depth != 8)
615 return B_BAD_TYPE;
616
617 #if 0
618 struct bios_regs regs;
619 regs.eax = 0x4f09;
620 regs.ebx = 0;
621 regs.ecx = numEntries;
622 regs.edx = firstIndex;
623 regs.es = (addr_t)palette >> 4;
624 regs.edi = (addr_t)palette & 0xf;
625 call_bios(0x10, ®s);
626
627 if ((regs.eax & 0xffff) != 0x4f) {
628 #endif
629 // the VESA call does not work, just try good old VGA mechanism
630 vga_set_palette(palette, firstIndex, numEntries);
631 #if 0
632 return B_ERROR;
633 }
634 #endif
635 return B_OK;
636 }
637
638
639 // #pragma mark -
640
641
642 bool
video_mode_hook(Menu * menu,MenuItem * item)643 video_mode_hook(Menu *menu, MenuItem *item)
644 {
645 // find selected mode
646 video_mode *mode = NULL;
647
648 Menu* submenu = item->Submenu();
649 MenuItem* subitem = submenu->FindMarked();
650 if (subitem != NULL) {
651 switch (submenu->IndexOf(subitem)) {
652 case 0:
653 // "Default" mode special
654 sMode = sDefaultMode;
655 sModeChosen = false;
656 return true;
657 case 1:
658 // "Standard VGA" mode special
659 // sets sMode to NULL which triggers VGA mode
660 break;
661 default:
662 mode = (video_mode *)subitem->Data();
663 break;
664 }
665 }
666
667 if (mode != sMode) {
668 // update standard mode
669 // ToDo: update fb settings!
670 sMode = mode;
671 }
672
673 sModeChosen = true;
674 return true;
675 }
676
677
678 Menu *
video_mode_menu()679 video_mode_menu()
680 {
681 Menu *menu = new(nothrow) Menu(CHOICE_MENU, "Select Video Mode");
682 MenuItem *item;
683
684 menu->AddItem(item = new(nothrow) MenuItem("Default"));
685 item->SetMarked(true);
686 item->Select(true);
687 item->SetHelpText("The Default video mode is the one currently configured "
688 "in the system. If there is no mode configured yet, a viable mode will "
689 "be chosen automatically.");
690
691 menu->AddItem(new(nothrow) MenuItem("Standard VGA"));
692
693 video_mode *mode = NULL;
694 while ((mode = (video_mode *)list_get_next_item(&sModeList, mode)) != NULL) {
695 char label[64];
696 snprintf(label, sizeof(label), "%ux%u %u bit", mode->width,
697 mode->height, mode->bits_per_pixel);
698
699 menu->AddItem(item = new(nothrow) MenuItem(label));
700 item->SetData(mode);
701 }
702
703 menu->AddSeparatorItem();
704 menu->AddItem(item = new(nothrow) MenuItem("Return to main menu"));
705 item->SetType(MENU_ITEM_NO_CHOICE);
706
707 return menu;
708 }
709
710
711 static status_t
set_vga_mode(void)712 set_vga_mode(void)
713 {
714 // sets 640x480 16 colors graphics mode
715 bios_regs regs;
716 regs.eax = 0x0012;
717 call_bios(0x10, ®s);
718 return (regs.eax == 0x4f) ? B_OK : B_NOT_SUPPORTED;
719 }
720
721
722 static void
set_text_mode(void)723 set_text_mode(void)
724 {
725 // sets 80x25 text console
726 bios_regs regs;
727 regs.eax = 0x0003;
728 call_bios(0x10, ®s);
729
730 video_hide_text_cursor();
731 }
732
733
734 void
video_move_text_cursor(int x,int y)735 video_move_text_cursor(int x, int y)
736 {
737 bios_regs regs;
738 regs.eax = 0x0200;
739 regs.ebx = 0;
740 regs.edx = (y << 8) | x;
741 call_bios(0x10, ®s);
742 }
743
744
745 void
video_show_text_cursor(void)746 video_show_text_cursor(void)
747 {
748 bios_regs regs;
749 regs.eax = 0x0100;
750 regs.ecx = 0x0607;
751 call_bios(0x10, ®s);
752 }
753
754
755 void
video_hide_text_cursor(void)756 video_hide_text_cursor(void)
757 {
758 bios_regs regs;
759 regs.eax = 0x0100;
760 regs.ecx = 0x2000;
761 call_bios(0x10, ®s);
762 }
763
764
765 // #pragma mark - blit
766
767
768 void
platform_blit4(addr_t frameBuffer,const uint8 * data,uint16 width,uint16 height,uint16 imageWidth,uint16 left,uint16 top)769 platform_blit4(addr_t frameBuffer, const uint8 *data,
770 uint16 width, uint16 height, uint16 imageWidth, uint16 left, uint16 top)
771 {
772 if (!data)
773 return;
774 // ToDo: no boot logo yet in VGA mode
775 #if 1
776 // this draws 16 big rectangles in all the available colors
777 uint8 *bits = (uint8 *)frameBuffer;
778 uint32 bytesPerRow = 80;
779 for (int32 i = 0; i < 32; i++) {
780 bits[9 * bytesPerRow + i + 2] = 0x55;
781 bits[30 * bytesPerRow + i + 2] = 0xaa;
782 }
783
784 for (int32 y = 10; y < 30; y++) {
785 for (int32 i = 0; i < 16; i++) {
786 out16((15 << 8) | 0x02, VGA_SEQUENCER_INDEX);
787 bits[32 * bytesPerRow + i*2 + 2] = i;
788
789 if (i & 1) {
790 out16((1 << 8) | 0x02, VGA_SEQUENCER_INDEX);
791 bits[y * bytesPerRow + i*2 + 2] = 0xff;
792 bits[y * bytesPerRow + i*2 + 3] = 0xff;
793 }
794 if (i & 2) {
795 out16((2 << 8) | 0x02, VGA_SEQUENCER_INDEX);
796 bits[y * bytesPerRow + i*2 + 2] = 0xff;
797 bits[y * bytesPerRow + i*2 + 3] = 0xff;
798 }
799 if (i & 4) {
800 out16((4 << 8) | 0x02, VGA_SEQUENCER_INDEX);
801 bits[y * bytesPerRow + i*2 + 2] = 0xff;
802 bits[y * bytesPerRow + i*2 + 3] = 0xff;
803 }
804 if (i & 8) {
805 out16((8 << 8) | 0x02, VGA_SEQUENCER_INDEX);
806 bits[y * bytesPerRow + i*2 + 2] = 0xff;
807 bits[y * bytesPerRow + i*2 + 3] = 0xff;
808 }
809 }
810 }
811
812 // enable all planes again
813 out16((15 << 8) | 0x02, VGA_SEQUENCER_INDEX);
814 #endif
815 }
816
817
818 extern "C" void
platform_set_palette(const uint8 * palette)819 platform_set_palette(const uint8 *palette)
820 {
821 switch (gKernelArgs.frame_buffer.depth) {
822 case 4:
823 //vga_set_palette((const uint8 *)kPalette16, 0, 16);
824 break;
825 case 8:
826 if (vesa_set_palette((const uint8 *)palette, 0, 256) != B_OK)
827 dprintf("set palette failed!\n");
828
829 break;
830 default:
831 break;
832 }
833 }
834
835
836 // #pragma mark -
837
838 extern "C" void
platform_switch_to_logo(void)839 platform_switch_to_logo(void)
840 {
841 // in debug mode, we'll never show the logo
842 if ((platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) != 0)
843 return;
844
845 addr_t lastBase = gKernelArgs.frame_buffer.physical_buffer.start;
846 size_t lastSize = gKernelArgs.frame_buffer.physical_buffer.size;
847
848 if (sVesaCompatible && sMode != NULL) {
849 if (!sModeChosen)
850 get_mode_from_settings();
851
852 // On some BIOS / chipset / monitor combinations, there seems to be a
853 // timing issue between getting the EDID data and setting the video
854 // mode. As such we wait here briefly to give everything enough time
855 // to settle.
856 spin(1000);
857
858 if ((sMode->timing == NULL || vesa_set_mode(sMode, true) != B_OK)
859 && vesa_set_mode(sMode, false) != B_OK)
860 goto fallback;
861
862 struct vbe_mode_info modeInfo;
863 if (vesa_get_mode_info(sMode->mode, &modeInfo) != B_OK)
864 goto fallback;
865
866 gKernelArgs.frame_buffer.width = modeInfo.width;
867 gKernelArgs.frame_buffer.height = modeInfo.height;
868 gKernelArgs.frame_buffer.bytes_per_row = modeInfo.bytes_per_row;
869 gKernelArgs.frame_buffer.depth = modeInfo.bits_per_pixel;
870 gKernelArgs.frame_buffer.physical_buffer.size
871 = (phys_size_t)modeInfo.bytes_per_row
872 * (phys_size_t)gKernelArgs.frame_buffer.height;
873 gKernelArgs.frame_buffer.physical_buffer.start = modeInfo.physical_base;
874 } else {
875 fallback:
876 // try to use standard VGA mode 640x480x4
877 if (set_vga_mode() != B_OK) {
878 dprintf("no standard VGA output\n");
879 return;
880 }
881
882 gKernelArgs.frame_buffer.width = 640;
883 gKernelArgs.frame_buffer.height = 480;
884 gKernelArgs.frame_buffer.bytes_per_row = 80;
885 gKernelArgs.frame_buffer.depth = 4;
886 gKernelArgs.frame_buffer.physical_buffer.size
887 = (phys_size_t)gKernelArgs.frame_buffer.width
888 * (phys_size_t)gKernelArgs.frame_buffer.height / 2;
889 gKernelArgs.frame_buffer.physical_buffer.start = 0xa0000;
890 }
891
892 dprintf("video mode: %ux%ux%u\n", gKernelArgs.frame_buffer.width,
893 gKernelArgs.frame_buffer.height, gKernelArgs.frame_buffer.depth);
894
895 gKernelArgs.frame_buffer.enabled = true;
896
897 // If the new frame buffer is either larger than the old one or located at
898 // a different address, we need to remap it, so we first have to throw
899 // away its previous mapping
900 if (lastBase != 0
901 && (lastBase != gKernelArgs.frame_buffer.physical_buffer.start
902 || lastSize < gKernelArgs.frame_buffer.physical_buffer.size)) {
903 mmu_free((void *)sFrameBuffer, lastSize);
904 lastBase = 0;
905 }
906 if (lastBase == 0) {
907 // the graphics memory has not been mapped yet!
908 sFrameBuffer = mmu_map_physical_memory(
909 gKernelArgs.frame_buffer.physical_buffer.start,
910 gKernelArgs.frame_buffer.physical_buffer.size, kDefaultPageFlags);
911 }
912
913 video_display_splash(sFrameBuffer);
914 }
915
916
917 extern "C" void
platform_switch_to_text_mode(void)918 platform_switch_to_text_mode(void)
919 {
920 if (!gKernelArgs.frame_buffer.enabled) {
921 vga_enable_bright_background_colors();
922 return;
923 }
924
925 set_text_mode();
926 gKernelArgs.frame_buffer.enabled = 0;
927
928 vga_enable_bright_background_colors();
929 }
930
931
932 extern "C" status_t
platform_init_video(void)933 platform_init_video(void)
934 {
935 gKernelArgs.frame_buffer.enabled = 0;
936 list_init(&sModeList);
937
938 set_text_mode();
939 // You may wonder why we do this here:
940 // Obviously, some graphics card BIOS implementations don't
941 // report all available modes unless you've done this before
942 // getting the VESA information.
943 // One example of those is the SiS 630 chipset in my laptop.
944
945 sVesaCompatible = vesa_init(&sInfo, &sDefaultMode) == B_OK;
946 if (!sVesaCompatible) {
947 TRACE(("No VESA compatible graphics!\n"));
948 gKernelArgs.vesa_capabilities = 0;
949 return B_ERROR;
950 }
951
952 gKernelArgs.vesa_capabilities = sInfo.capabilities;
953
954 TRACE(("VESA compatible graphics!\n"));
955
956 // store VESA modes into kernel args
957 vesa_mode *modes = (vesa_mode *)kernel_args_malloc(
958 sModeCount * sizeof(vesa_mode));
959 if (modes != NULL) {
960 video_mode *mode = NULL;
961 uint32 i = 0;
962 while ((mode = (video_mode *)list_get_next_item(&sModeList, mode))
963 != NULL) {
964 modes[i].mode = mode->mode;
965 modes[i].width = mode->width;
966 modes[i].height = mode->height;
967 modes[i].bits_per_pixel = mode->bits_per_pixel;
968 i++;
969 }
970
971 gKernelArgs.vesa_modes = modes;
972 gKernelArgs.vesa_modes_size = sModeCount * sizeof(vesa_mode);
973 }
974
975 edid1_info info;
976 // Note, we currently ignore EDID information for VBE2 - while the EDID
977 // information itself seems to be reliable, older chips often seem to
978 // use very strange default timings with higher modes.
979 // TODO: Maybe add a setting to enable it anyway?
980 if (sInfo.version.major >= 3 && vesa_get_edid(&info) == B_OK) {
981 // we got EDID information from the monitor, try to find a new default
982 // mode
983 video_mode *defaultMode = find_edid_mode(info, false);
984 if (defaultMode == NULL)
985 defaultMode = find_edid_mode(info, true);
986
987 if (defaultMode != NULL) {
988 // We found a new default mode to use!
989 sDefaultMode = defaultMode;
990 }
991
992 gKernelArgs.edid_info = kernel_args_malloc(sizeof(edid1_info));
993 if (gKernelArgs.edid_info != NULL)
994 memcpy(gKernelArgs.edid_info, &info, sizeof(edid1_info));
995 }
996
997 sMode = sDefaultMode;
998 return B_OK;
999 }
1000
1001