coreboot-v2/util/x86emu/yabel/vbe.c
<<
>>
Prefs
   1/******************************************************************************
   2 * Copyright (c) 2004, 2008 IBM Corporation
   3 * Copyright (c) 2009 Pattrick Hueper <phueper@hueper.net>
   4 * All rights reserved.
   5 * This program and the accompanying materials
   6 * are made available under the terms of the BSD License
   7 * which accompanies this distribution, and is available at
   8 * http://www.opensource.org/licenses/bsd-license.php
   9 *
  10 * Contributors:
  11 *     IBM Corporation - initial implementation
  12 *****************************************************************************/
  13
  14#include <string.h>
  15#include <types.h>
  16#ifndef CONFIG_COREBOOT_V2
  17#include <cpu.h>
  18#endif
  19
  20#include "debug.h"
  21
  22#include <x86emu/x86emu.h>
  23#include <x86emu/regs.h>
  24#ifdef CONFIG_COREBOOT_V2
  25#include "../x86emu/prim_ops.h"
  26#else
  27#include <x86emu/prim_ops.h>    // for push_word
  28#endif
  29
  30#include "biosemu.h"
  31#include "io.h"
  32#include "mem.h"
  33#include "interrupt.h"
  34#include "device.h"
  35
  36static X86EMU_memFuncs my_mem_funcs = {
  37        my_rdb, my_rdw, my_rdl,
  38        my_wrb, my_wrw, my_wrl
  39};
  40
  41static X86EMU_pioFuncs my_pio_funcs = {
  42        my_inb, my_inw, my_inl,
  43        my_outb, my_outw, my_outl
  44};
  45
  46// pointer to VBEInfoBuffer, set by vbe_prepare
  47u8 *vbe_info_buffer = 0;
  48// virtual BIOS Memory
  49u8 *biosmem;
  50u32 biosmem_size;
  51
  52// these structs are for input from and output to OF
  53typedef struct {
  54        u8 display_type;        // 0=NONE, 1= analog, 2=digital
  55        u16 screen_width;
  56        u16 screen_height;
  57        u16 screen_linebytes;   // bytes per line in framebuffer, may be more than screen_width
  58        u8 color_depth; // color depth in bpp
  59        u32 framebuffer_address;
  60        u8 edid_block_zero[128];
  61} __attribute__ ((__packed__)) screen_info_t;
  62
  63typedef struct {
  64        u8 signature[4];
  65        u16 size_reserved;
  66        u8 monitor_number;
  67        u16 max_screen_width;
  68        u8 color_depth;
  69} __attribute__ ((__packed__)) screen_info_input_t;
  70
  71// these structs only store a subset of the VBE defined fields
  72// only those needed.
  73typedef struct {
  74        char signature[4];
  75        u16 version;
  76        u8 *oem_string_ptr;
  77        u32 capabilities;
  78        u16 video_mode_list[256];       // lets hope we never have more than 256 video modes...
  79        u16 total_memory;
  80} vbe_info_t;
  81
  82typedef struct {
  83        u16 video_mode;
  84        u8 mode_info_block[256];
  85        u16 attributes;
  86        u16 linebytes;
  87        u16 x_resolution;
  88        u16 y_resolution;
  89        u8 x_charsize;
  90        u8 y_charsize;
  91        u8 bits_per_pixel;
  92        u8 memory_model;
  93        u32 framebuffer_address;
  94} vbe_mode_info_t;
  95
  96typedef struct {
  97        u8 port_number; // i.e. monitor number
  98        u8 edid_transfer_time;
  99        u8 ddc_level;
 100        u8 edid_block_zero[128];
 101} vbe_ddc_info_t;
 102
 103static inline u8
 104vbe_prepare()
 105{
 106        vbe_info_buffer = biosmem + (VBE_SEGMENT << 4); // segment:offset off VBE Data Area
 107        //clear buffer
 108        memset(vbe_info_buffer, 0, 512);
 109        //set VbeSignature to "VBE2" to indicate VBE 2.0+ request
 110        vbe_info_buffer[0] = 'V';
 111        vbe_info_buffer[0] = 'B';
 112        vbe_info_buffer[0] = 'E';
 113        vbe_info_buffer[0] = '2';
 114        // ES:DI store pointer to buffer in virtual mem see vbe_info_buffer above...
 115        M.x86.R_EDI = 0x0;
 116        M.x86.R_ES = VBE_SEGMENT;
 117
 118        return 0;               // successfull init
 119}
 120
 121// VBE Function 00h
 122u8
 123vbe_info(vbe_info_t * info)
 124{
 125        vbe_prepare();
 126        // call VBE function 00h (Info Function)
 127        M.x86.R_EAX = 0x4f00;
 128
 129        // enable trace
 130        CHECK_DBG(DEBUG_TRACE_X86EMU) {
 131                X86EMU_trace_on();
 132        }
 133        // run VESA Interrupt
 134        runInt10();
 135
 136        if (M.x86.R_AL != 0x4f) {
 137                DEBUG_PRINTF_VBE("%s: VBE Info Function NOT supported! AL=%x\n",
 138                                 __func__, M.x86.R_AL);
 139                return -1;
 140        }
 141
 142        if (M.x86.R_AH != 0x0) {
 143                DEBUG_PRINTF_VBE
 144                    ("%s: VBE Info Function Return Code NOT OK! AH=%x\n",
 145                     __func__, M.x86.R_AH);
 146                return M.x86.R_AH;
 147        }
 148        //printf("VBE Info Dump:");
 149        //dump(vbe_info_buffer, 64);
 150
 151        //offset 0: signature
 152        info->signature[0] = vbe_info_buffer[0];
 153        info->signature[1] = vbe_info_buffer[1];
 154        info->signature[2] = vbe_info_buffer[2];
 155        info->signature[3] = vbe_info_buffer[3];
 156
 157        // offset 4: 16bit le containing VbeVersion
 158        info->version = in16le(vbe_info_buffer + 4);
 159
 160        // offset 6: 32bit le containg segment:offset of OEM String in virtual Mem.
 161        info->oem_string_ptr =
 162            biosmem + ((in16le(vbe_info_buffer + 8) << 4) +
 163                       in16le(vbe_info_buffer + 6));
 164
 165        // offset 10: 32bit le capabilities
 166        info->capabilities = in32le(vbe_info_buffer + 10);
 167
 168        // offset 14: 32 bit le containing segment:offset of supported video mode table
 169        u16 *video_mode_ptr;
 170        video_mode_ptr =
 171            (u16 *) (biosmem +
 172                          ((in16le(vbe_info_buffer + 16) << 4) +
 173                           in16le(vbe_info_buffer + 14)));
 174        u32 i = 0;
 175        do {
 176                info->video_mode_list[i] = in16le(video_mode_ptr + i);
 177                i++;
 178        }
 179        while ((i <
 180                (sizeof(info->video_mode_list) /
 181                 sizeof(info->video_mode_list[0])))
 182               && (info->video_mode_list[i - 1] != 0xFFFF));
 183
 184        //offset 18: 16bit le total memory in 64KB blocks
 185        info->total_memory = in16le(vbe_info_buffer + 18);
 186
 187        return 0;
 188}
 189
 190// VBE Function 01h
 191u8
 192vbe_get_mode_info(vbe_mode_info_t * mode_info)
 193{
 194        vbe_prepare();
 195        // call VBE function 01h (Return VBE Mode Info Function)
 196        M.x86.R_EAX = 0x4f01;
 197        M.x86.R_CX = mode_info->video_mode;
 198
 199        // enable trace
 200        CHECK_DBG(DEBUG_TRACE_X86EMU) {
 201                X86EMU_trace_on();
 202        }
 203        // run VESA Interrupt
 204        runInt10();
 205
 206        if (M.x86.R_AL != 0x4f) {
 207                DEBUG_PRINTF_VBE
 208                    ("%s: VBE Return Mode Info Function NOT supported! AL=%x\n",
 209                     __func__, M.x86.R_AL);
 210                return -1;
 211        }
 212
 213        if (M.x86.R_AH != 0x0) {
 214                DEBUG_PRINTF_VBE
 215                    ("%s: VBE Return Mode Info (mode: %04x) Function Return Code NOT OK! AH=%02x\n",
 216                     __func__, mode_info->video_mode, M.x86.R_AH);
 217                return M.x86.R_AH;
 218        }
 219        //pointer to mode_info_block is in ES:DI
 220        memcpy(mode_info->mode_info_block,
 221               biosmem + ((M.x86.R_ES << 4) + M.x86.R_DI),
 222               sizeof(mode_info->mode_info_block));
 223
 224        //printf("Mode Info Dump:");
 225        //dump(mode_info_block, 64);
 226
 227        // offset 0: 16bit le mode attributes
 228        mode_info->attributes = in16le(mode_info->mode_info_block);
 229
 230        // offset 16: 16bit le bytes per scan line
 231        mode_info->linebytes = in16le(mode_info->mode_info_block + 16);
 232
 233        // offset 18: 16bit le x resolution
 234        mode_info->x_resolution = in16le(mode_info->mode_info_block + 18);
 235
 236        // offset 20: 16bit le y resolution
 237        mode_info->y_resolution = in16le(mode_info->mode_info_block + 20);
 238
 239        // offset 22: 8bit le x charsize
 240        mode_info->x_charsize = *(mode_info->mode_info_block + 22);
 241
 242        // offset 23: 8bit le y charsize
 243        mode_info->y_charsize = *(mode_info->mode_info_block + 23);
 244
 245        // offset 25: 8bit le bits per pixel
 246        mode_info->bits_per_pixel = *(mode_info->mode_info_block + 25);
 247
 248        // offset 27: 8bit le memory model
 249        mode_info->memory_model = *(mode_info->mode_info_block + 27);
 250
 251        // offset 40: 32bit le containg offset of frame buffer memory ptr
 252        mode_info->framebuffer_address =
 253            in32le(mode_info->mode_info_block + 40);
 254
 255        return 0;
 256}
 257
 258// VBE Function 02h
 259u8
 260vbe_set_mode(vbe_mode_info_t * mode_info)
 261{
 262        vbe_prepare();
 263        // call VBE function 02h (Set VBE Mode Function)
 264        M.x86.R_EAX = 0x4f02;
 265        M.x86.R_BX = mode_info->video_mode;
 266        M.x86.R_BX |= 0x4000;   // set bit 14 to request linear framebuffer mode
 267        M.x86.R_BX &= 0x7FFF;   // clear bit 15 to request clearing of framebuffer
 268
 269        DEBUG_PRINTF_VBE("%s: setting mode: 0x%04x\n", __func__,
 270                         M.x86.R_BX);
 271
 272        // enable trace
 273        CHECK_DBG(DEBUG_TRACE_X86EMU) {
 274                X86EMU_trace_on();
 275        }
 276        // run VESA Interrupt
 277        runInt10();
 278
 279        if (M.x86.R_AL != 0x4f) {
 280                DEBUG_PRINTF_VBE
 281                    ("%s: VBE Set Mode Function NOT supported! AL=%x\n",
 282                     __func__, M.x86.R_AL);
 283                return -1;
 284        }
 285
 286        if (M.x86.R_AH != 0x0) {
 287                DEBUG_PRINTF_VBE
 288                    ("%s: mode: %x VBE Set Mode Function Return Code NOT OK! AH=%x\n",
 289                     __func__, mode_info->video_mode, M.x86.R_AH);
 290                return M.x86.R_AH;
 291        }
 292        return 0;
 293}
 294
 295//VBE Function 08h
 296u8
 297vbe_set_palette_format(u8 format)
 298{
 299        vbe_prepare();
 300        // call VBE function 09h (Set/Get Palette Data Function)
 301        M.x86.R_EAX = 0x4f08;
 302        M.x86.R_BL = 0x00;      // set format
 303        M.x86.R_BH = format;
 304
 305        DEBUG_PRINTF_VBE("%s: setting palette format: %d\n", __func__,
 306                         format);
 307
 308        // enable trace
 309        CHECK_DBG(DEBUG_TRACE_X86EMU) {
 310                X86EMU_trace_on();
 311        }
 312        // run VESA Interrupt
 313        runInt10();
 314
 315        if (M.x86.R_AL != 0x4f) {
 316                DEBUG_PRINTF_VBE
 317                    ("%s: VBE Set Palette Format Function NOT supported! AL=%x\n",
 318                     __func__, M.x86.R_AL);
 319                return -1;
 320        }
 321
 322        if (M.x86.R_AH != 0x0) {
 323                DEBUG_PRINTF_VBE
 324                    ("%s: VBE Set Palette Format Function Return Code NOT OK! AH=%x\n",
 325                     __func__, M.x86.R_AH);
 326                return M.x86.R_AH;
 327        }
 328        return 0;
 329}
 330
 331// VBE Function 09h
 332u8
 333vbe_set_color(u16 color_number, u32 color_value)
 334{
 335        vbe_prepare();
 336        // call VBE function 09h (Set/Get Palette Data Function)
 337        M.x86.R_EAX = 0x4f09;
 338        M.x86.R_BL = 0x00;      // set color
 339        M.x86.R_CX = 0x01;      // set only one entry
 340        M.x86.R_DX = color_number;
 341        // ES:DI is address where color_value is stored, we store it at 2000:0000
 342        M.x86.R_ES = 0x2000;
 343        M.x86.R_DI = 0x0;
 344
 345        // store color value at ES:DI
 346        out32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI, color_value);
 347
 348        DEBUG_PRINTF_VBE("%s: setting color #%x: 0x%04x\n", __func__,
 349                         color_number, color_value);
 350
 351        // enable trace
 352        CHECK_DBG(DEBUG_TRACE_X86EMU) {
 353                X86EMU_trace_on();
 354        }
 355        // run VESA Interrupt
 356        runInt10();
 357
 358        if (M.x86.R_AL != 0x4f) {
 359                DEBUG_PRINTF_VBE
 360                    ("%s: VBE Set Palette Function NOT supported! AL=%x\n",
 361                     __func__, M.x86.R_AL);
 362                return -1;
 363        }
 364
 365        if (M.x86.R_AH != 0x0) {
 366                DEBUG_PRINTF_VBE
 367                    ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
 368                     __func__, M.x86.R_AH);
 369                return M.x86.R_AH;
 370        }
 371        return 0;
 372}
 373
 374u8
 375vbe_get_color(u16 color_number, u32 * color_value)
 376{
 377        vbe_prepare();
 378        // call VBE function 09h (Set/Get Palette Data Function)
 379        M.x86.R_EAX = 0x4f09;
 380        M.x86.R_BL = 0x00;      // get color
 381        M.x86.R_CX = 0x01;      // get only one entry
 382        M.x86.R_DX = color_number;
 383        // ES:DI is address where color_value is stored, we store it at 2000:0000
 384        M.x86.R_ES = 0x2000;
 385        M.x86.R_DI = 0x0;
 386
 387        // enable trace
 388        CHECK_DBG(DEBUG_TRACE_X86EMU) {
 389                X86EMU_trace_on();
 390        }
 391        // run VESA Interrupt
 392        runInt10();
 393
 394        if (M.x86.R_AL != 0x4f) {
 395                DEBUG_PRINTF_VBE
 396                    ("%s: VBE Set Palette Function NOT supported! AL=%x\n",
 397                     __func__, M.x86.R_AL);
 398                return -1;
 399        }
 400
 401        if (M.x86.R_AH != 0x0) {
 402                DEBUG_PRINTF_VBE
 403                    ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
 404                     __func__, M.x86.R_AH);
 405                return M.x86.R_AH;
 406        }
 407        // read color value from ES:DI
 408        *color_value = in32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI);
 409
 410        DEBUG_PRINTF_VBE("%s: getting color #%x --> 0x%04x\n", __func__,
 411                         color_number, *color_value);
 412
 413        return 0;
 414}
 415
 416// VBE Function 15h
 417u8
 418vbe_get_ddc_info(vbe_ddc_info_t * ddc_info)
 419{
 420        vbe_prepare();
 421        // call VBE function 15h (DDC Info Function)
 422        M.x86.R_EAX = 0x4f15;
 423        M.x86.R_BL = 0x00;      // get DDC Info
 424        M.x86.R_CX = ddc_info->port_number;
 425        M.x86.R_ES = 0x0;
 426        M.x86.R_DI = 0x0;
 427
 428        // enable trace
 429        CHECK_DBG(DEBUG_TRACE_X86EMU) {
 430                X86EMU_trace_on();
 431        }
 432        // run VESA Interrupt
 433        runInt10();
 434
 435        if (M.x86.R_AL != 0x4f) {
 436                DEBUG_PRINTF_VBE
 437                    ("%s: VBE Get DDC Info Function NOT supported! AL=%x\n",
 438                     __func__, M.x86.R_AL);
 439                return -1;
 440        }
 441
 442        if (M.x86.R_AH != 0x0) {
 443                DEBUG_PRINTF_VBE
 444                    ("%s: port: %x VBE Get DDC Info Function Return Code NOT OK! AH=%x\n",
 445                     __func__, ddc_info->port_number, M.x86.R_AH);
 446                return M.x86.R_AH;
 447        }
 448        // BH = approx. time in seconds to transfer one EDID block
 449        ddc_info->edid_transfer_time = M.x86.R_BH;
 450        // BL = DDC Level
 451        ddc_info->ddc_level = M.x86.R_BL;
 452
 453        vbe_prepare();
 454        // call VBE function 15h (DDC Info Function)
 455        M.x86.R_EAX = 0x4f15;
 456        M.x86.R_BL = 0x01;      // read EDID
 457        M.x86.R_CX = ddc_info->port_number;
 458        M.x86.R_DX = 0x0;       // block number
 459        // ES:DI is address where EDID is stored, we store it at 2000:0000
 460        M.x86.R_ES = 0x2000;
 461        M.x86.R_DI = 0x0;
 462
 463        // enable trace
 464        CHECK_DBG(DEBUG_TRACE_X86EMU) {
 465                X86EMU_trace_on();
 466        }
 467        // run VESA Interrupt
 468        runInt10();
 469
 470        if (M.x86.R_AL != 0x4f) {
 471                DEBUG_PRINTF_VBE
 472                    ("%s: VBE Read EDID Function NOT supported! AL=%x\n",
 473                     __func__, M.x86.R_AL);
 474                return -1;
 475        }
 476
 477        if (M.x86.R_AH != 0x0) {
 478                DEBUG_PRINTF_VBE
 479                    ("%s: port: %x VBE Read EDID Function Return Code NOT OK! AH=%x\n",
 480                     __func__, ddc_info->port_number, M.x86.R_AH);
 481                return M.x86.R_AH;
 482        }
 483
 484        memcpy(ddc_info->edid_block_zero,
 485               biosmem + (M.x86.R_ES << 4) + M.x86.R_DI,
 486               sizeof(ddc_info->edid_block_zero));
 487
 488        return 0;
 489}
 490
 491u32
 492vbe_get_info(u8 argc, char ** argv)
 493{
 494        u8 rval;
 495        u32 i;
 496        if (argc < 4) {
 497                printf
 498                    ("Usage %s <vmem_base> <device_path> <address of screen_info_t>\n",
 499                     argv[0]);
 500                int i = 0;
 501                for (i = 0; i < argc; i++) {
 502                        printf("argv[%d]: %s\n", i, argv[i]);
 503                }
 504                return -1;
 505        }
 506        // get a copy of input struct...
 507        screen_info_input_t input =
 508            *((screen_info_input_t *) strtoul((char *) argv[4], 0, 16));
 509        // output is pointer to the address passed as argv[4]
 510        screen_info_t *output =
 511            (screen_info_t *) strtoul((char *) argv[4], 0, 16);
 512        // zero output
 513        memset(output, 0, sizeof(screen_info_t));
 514
 515        // argv[1] is address of virtual BIOS mem...
 516        // argv[2] is the size
 517        biosmem = (u8 *) strtoul(argv[1], 0, 16);
 518        biosmem_size = strtoul(argv[2], 0, 16);;
 519        if (biosmem_size < MIN_REQUIRED_VMEM_SIZE) {
 520                printf("Error: Not enough virtual memory: %x, required: %x!\n",
 521                       biosmem_size, MIN_REQUIRED_VMEM_SIZE);
 522                return -1;
 523        }
 524        // argv[3] is the device to open and use...
 525        if (dev_init((char *) argv[3]) != 0) {
 526                printf("Error initializing device!\n");
 527                return -1;
 528        }
 529        //setup interrupt handler
 530        X86EMU_intrFuncs intrFuncs[256];
 531        for (i = 0; i < 256; i++)
 532                intrFuncs[i] = handleInterrupt;
 533        X86EMU_setupIntrFuncs(intrFuncs);
 534        X86EMU_setupPioFuncs(&my_pio_funcs);
 535        X86EMU_setupMemFuncs(&my_mem_funcs);
 536
 537        // set mem_base
 538        M.mem_base = (long) biosmem;
 539        M.mem_size = biosmem_size;
 540        DEBUG_PRINTF_VBE("membase set: %08x, size: %08x\n", (int) M.mem_base,
 541                         (int) M.mem_size);
 542
 543        vbe_info_t info;
 544        rval = vbe_info(&info);
 545        if (rval != 0)
 546                return rval;
 547
 548        DEBUG_PRINTF_VBE("VbeSignature: %s\n", info.signature);
 549        DEBUG_PRINTF_VBE("VbeVersion: 0x%04x\n", info.version);
 550        DEBUG_PRINTF_VBE("OemString: %s\n", info.oem_string_ptr);
 551        DEBUG_PRINTF_VBE("Capabilities:\n");
 552        DEBUG_PRINTF_VBE("\tDAC: %s\n",
 553                         (info.capabilities & 0x1) ==
 554                         0 ? "fixed 6bit" : "switchable 6/8bit");
 555        DEBUG_PRINTF_VBE("\tVGA: %s\n",
 556                         (info.capabilities & 0x2) ==
 557                         0 ? "compatible" : "not compatible");
 558        DEBUG_PRINTF_VBE("\tRAMDAC: %s\n",
 559                         (info.capabilities & 0x4) ==
 560                         0 ? "normal" : "use blank bit in Function 09h");
 561
 562        // argv[4] may be a pointer with enough space to return screen_info_t
 563        // as input, it must contain a screen_info_input_t with the following content:
 564        // byte[0:3] = "DDC\0" (zero-terminated signature header)
 565        // byte[4:5] = reserved space for the return struct... just in case we ever change
 566        //             the struct and dont have reserved enough memory (and let's hope the struct
 567        //             never gets larger than 64KB)
 568        // byte[6] = monitor port number for DDC requests ("only" one byte... so lets hope we never have more than 255 monitors...
 569        // byte[7:8] = max. screen width (OF may want to limit this)
 570        // byte[9] = required color depth in bpp
 571        if (strncmp((char *) input.signature, "DDC", 4) != 0) {
 572                printf
 573                    ("%s: Invalid input signature! expected: %s, is: %s\n",
 574                     __func__, "DDC", input.signature);
 575                return -1;
 576        }
 577        if (input.size_reserved != sizeof(screen_info_t)) {
 578                printf
 579                    ("%s: Size of return struct is wrong, required: %d, available: %d\n",
 580                     __func__, (int) sizeof(screen_info_t),
 581                     input.size_reserved);
 582                return -1;
 583        }
 584
 585        vbe_ddc_info_t ddc_info;
 586        ddc_info.port_number = input.monitor_number;
 587        vbe_get_ddc_info(&ddc_info);
 588
 589#if 0
 590        DEBUG_PRINTF_VBE("DDC: edid_tranfer_time: %d\n",
 591                         ddc_info.edid_transfer_time);
 592        DEBUG_PRINTF_VBE("DDC: ddc_level: %x\n", ddc_info.ddc_level);
 593        DEBUG_PRINTF_VBE("DDC: EDID: \n");
 594        CHECK_DBG(DEBUG_VBE) {
 595                dump(ddc_info.edid_block_zero,
 596                     sizeof(ddc_info.edid_block_zero));
 597        }
 598#endif
 599        if (*((u64 *) ddc_info.edid_block_zero) !=
 600            (u64) 0x00FFFFFFFFFFFF00) {
 601                // invalid EDID signature... probably no monitor
 602
 603                output->display_type = 0x0;
 604                return 0;
 605        } else if ((ddc_info.edid_block_zero[20] & 0x80) != 0) {
 606                // digital display
 607                output->display_type = 2;
 608        } else {
 609                // analog
 610                output->display_type = 1;
 611        }
 612        DEBUG_PRINTF_VBE("DDC: found display type %d\n", output->display_type);
 613        memcpy(output->edid_block_zero, ddc_info.edid_block_zero,
 614               sizeof(ddc_info.edid_block_zero));
 615        i = 0;
 616        vbe_mode_info_t mode_info;
 617        vbe_mode_info_t best_mode_info;
 618        // initialize best_mode to 0
 619        memset(&best_mode_info, 0, sizeof(best_mode_info));
 620        while ((mode_info.video_mode = info.video_mode_list[i]) != 0xFFFF) {
 621                //DEBUG_PRINTF_VBE("%x: Mode: %04x\n", i, mode_info.video_mode);
 622                vbe_get_mode_info(&mode_info);
 623#if 0
 624                DEBUG_PRINTF_VBE("Video Mode 0x%04x available, %s\n",
 625                                 mode_info.video_mode,
 626                                 (mode_info.attributes & 0x1) ==
 627                                 0 ? "not supported" : "supported");
 628                DEBUG_PRINTF_VBE("\tTTY: %s\n",
 629                                 (mode_info.attributes & 0x4) ==
 630                                 0 ? "no" : "yes");
 631                DEBUG_PRINTF_VBE("\tMode: %s %s\n",
 632                                 (mode_info.attributes & 0x8) ==
 633                                 0 ? "monochrome" : "color",
 634                                 (mode_info.attributes & 0x10) ==
 635                                 0 ? "text" : "graphics");
 636                DEBUG_PRINTF_VBE("\tVGA: %s\n",
 637                                 (mode_info.attributes & 0x20) ==
 638                                 0 ? "compatible" : "not compatible");
 639                DEBUG_PRINTF_VBE("\tWindowed Mode: %s\n",
 640                                 (mode_info.attributes & 0x40) ==
 641                                 0 ? "yes" : "no");
 642                DEBUG_PRINTF_VBE("\tFramebuffer: %s\n",
 643                                 (mode_info.attributes & 0x80) ==
 644                                 0 ? "no" : "yes");
 645                DEBUG_PRINTF_VBE("\tResolution: %dx%d\n",
 646                                 mode_info.x_resolution,
 647                                 mode_info.y_resolution);
 648                DEBUG_PRINTF_VBE("\tChar Size: %dx%d\n",
 649                                 mode_info.x_charsize, mode_info.y_charsize);
 650                DEBUG_PRINTF_VBE("\tColor Depth: %dbpp\n",
 651                                 mode_info.bits_per_pixel);
 652                DEBUG_PRINTF_VBE("\tMemory Model: 0x%x\n",
 653                                 mode_info.memory_model);
 654                DEBUG_PRINTF_VBE("\tFramebuffer Offset: %08x\n",
 655                                 mode_info.framebuffer_address);
 656#endif
 657                if ((mode_info.bits_per_pixel == input.color_depth)
 658                    && (mode_info.x_resolution <= input.max_screen_width)
 659                    && ((mode_info.attributes & 0x80) != 0)     // framebuffer mode
 660                    && ((mode_info.attributes & 0x10) != 0)     // graphics
 661                    && ((mode_info.attributes & 0x8) != 0)      // color
 662                    && (mode_info.x_resolution > best_mode_info.x_resolution))  // better than previous best_mode
 663                {
 664                        // yiiiihaah... we found a new best mode
 665                        memcpy(&best_mode_info, &mode_info, sizeof(mode_info));
 666                }
 667                i++;
 668        }
 669
 670        if (best_mode_info.video_mode != 0) {
 671                DEBUG_PRINTF_VBE
 672                    ("Best Video Mode found: 0x%x, %dx%d, %dbpp, framebuffer_address: 0x%x\n",
 673                     best_mode_info.video_mode,
 674                     best_mode_info.x_resolution,
 675                     best_mode_info.y_resolution,
 676                     best_mode_info.bits_per_pixel,
 677                     best_mode_info.framebuffer_address);
 678
 679                //printf("Mode Info Dump:");
 680                //dump(best_mode_info.mode_info_block, 64);
 681
 682                // set the video mode
 683                vbe_set_mode(&best_mode_info);
 684
 685                if ((info.capabilities & 0x1) != 0) {
 686                        // switch to 8 bit palette format
 687                        vbe_set_palette_format(8);
 688                }
 689                // setup a palette:
 690                // - first 216 colors are mixed colors for each component in 6 steps
 691                //   (6*6*6=216)
 692                // - then 10 shades of the three primary colors
 693                // - then 10 shades of grey
 694                // -------
 695                // = 256 colors
 696                //
 697                // - finally black is color 0 and white color FF (because SLOF expects it
 698                //   this way...)
 699                // this resembles the palette that the kernel/X Server seems to expect...
 700
 701                u8 mixed_color_values[6] =
 702                    { 0xFF, 0xDA, 0xB3, 0x87, 0x54, 0x00 };
 703                u8 primary_color_values[10] =
 704                    { 0xF3, 0xE7, 0xCD, 0xC0, 0xA5, 0x96, 0x77, 0x66, 0x3F,
 705                        0x27
 706                };
 707                u8 mc_size = sizeof(mixed_color_values);
 708                u8 prim_size = sizeof(primary_color_values);
 709
 710                u8 curr_color_index;
 711                u32 curr_color;
 712
 713                u8 r, g, b;
 714                // 216 mixed colors
 715                for (r = 0; r < mc_size; r++) {
 716                        for (g = 0; g < mc_size; g++) {
 717                                for (b = 0; b < mc_size; b++) {
 718                                        curr_color_index =
 719                                            (r * mc_size * mc_size) +
 720                                            (g * mc_size) + b;
 721                                        curr_color = 0;
 722                                        curr_color |= ((u32) mixed_color_values[r]) << 16;      //red value
 723                                        curr_color |= ((u32) mixed_color_values[g]) << 8;       //green value
 724                                        curr_color |= (u32) mixed_color_values[b];      //blue value
 725                                        vbe_set_color(curr_color_index,
 726                                                      curr_color);
 727                                }
 728                        }
 729                }
 730
 731                // 10 shades of each primary color
 732                // red
 733                for (r = 0; r < prim_size; r++) {
 734                        curr_color_index = mc_size * mc_size * mc_size + r;
 735                        curr_color = ((u32) primary_color_values[r]) << 16;
 736                        vbe_set_color(curr_color_index, curr_color);
 737                }
 738                //green
 739                for (g = 0; g < prim_size; g++) {
 740                        curr_color_index =
 741                            mc_size * mc_size * mc_size + prim_size + g;
 742                        curr_color = ((u32) primary_color_values[g]) << 8;
 743                        vbe_set_color(curr_color_index, curr_color);
 744                }
 745                //blue
 746                for (b = 0; b < prim_size; b++) {
 747                        curr_color_index =
 748                            mc_size * mc_size * mc_size + prim_size * 2 + b;
 749                        curr_color = (u32) primary_color_values[b];
 750                        vbe_set_color(curr_color_index, curr_color);
 751                }
 752                // 10 shades of grey
 753                for (i = 0; i < prim_size; i++) {
 754                        curr_color_index =
 755                            mc_size * mc_size * mc_size + prim_size * 3 + i;
 756                        curr_color = 0;
 757                        curr_color |= ((u32) primary_color_values[i]) << 16;    //red
 758                        curr_color |= ((u32) primary_color_values[i]) << 8;     //green
 759                        curr_color |= ((u32) primary_color_values[i]);  //blue
 760                        vbe_set_color(curr_color_index, curr_color);
 761                }
 762
 763                // SLOF is using color 0x0 (black) and 0xFF (white) to draw to the screen...
 764                vbe_set_color(0x00, 0x00000000);
 765                vbe_set_color(0xFF, 0x00FFFFFF);
 766
 767                output->screen_width = best_mode_info.x_resolution;
 768                output->screen_height = best_mode_info.y_resolution;
 769                output->screen_linebytes = best_mode_info.linebytes;
 770                output->color_depth = best_mode_info.bits_per_pixel;
 771                output->framebuffer_address =
 772                    best_mode_info.framebuffer_address;
 773        } else {
 774                printf("%s: No suitable video mode found!\n", __func__);
 775                //unset display_type...
 776                output->display_type = 0;
 777        }
 778        return 0;
 779}
 780
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.