[SeaBIOS] [PATCH 2/3] bochsvga: Implement vbe 15h function

Christian Gmeiner christian.gmeiner at gmail.com
Mon Sep 10 08:21:56 CEST 2012


2012/9/9 Hiroshi Miura <miurahr at linux.com>:
> This patch adds the ability for the Bochs VGA ROM to return information
> about a HD wide monitor.
>
> It is constructed from definitions at run time.
>
> Inspired by this patch I digged out from the vgabios mailing list:
> http://old.nabble.com/VBE-BIOS-support-for-monitor-information-(EDID)-td22952446.html
>
> Signed-off-by: Hiroshi Miura <miurahr at linux.com>
> ---
>  Makefile           |    3 +-
>  vgasrc/bochsedid.c |  147 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  vgasrc/bochsedid.h |  136 ++++++++++++++++++++++++++++++++++++++++++++++++
>  vgasrc/vgahw.h     |    5 ++
>  4 files changed, 290 insertions(+), 1 deletion(-)
>  create mode 100644 vgasrc/bochsedid.c
>  create mode 100644 vgasrc/bochsedid.h
>
> diff --git a/Makefile b/Makefile
> index 45ea48a..d3e22b9 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -189,7 +189,8 @@ $(OUT)bios.bin.elf $(OUT)bios.bin: $(OUT)rom.o tools/checkrom.py
>  SRCVGA=src/output.c src/util.c src/pci.c \
>      vgasrc/vgabios.c vgasrc/vgafb.c vgasrc/vgafonts.c vgasrc/vbe.c \
>      vgasrc/stdvga.c vgasrc/stdvgamodes.c vgasrc/stdvgaio.c \
> -    vgasrc/clext.c vgasrc/bochsvga.c vgasrc/geodevga.c
> +    vgasrc/clext.c vgasrc/bochsvga.c vgasrc/geodevga.c \
> +    vgasrc/bochsedid.c
>
>  CFLAGS16VGA = $(CFLAGS16INC) -Isrc
>
> diff --git a/vgasrc/bochsedid.c b/vgasrc/bochsedid.c
> new file mode 100644
> index 0000000..5a40593
> --- /dev/null
> +++ b/vgasrc/bochsedid.c
> @@ -0,0 +1,147 @@
> +// VESA VBE EDID capability for virtual display
> +//
> +// Copyright (C) 2012  Hiroshi Miura <miurahr at linux.com>
> +//
> +// This file may be distributed under the terms of the GNU LGPLv3 license.
> +
> +#include "vbe.h" // VBE_CAPABILITY_8BIT_DAC
> +#include "biosvar.h" // GET_GLOBAL
> +#include "util.h" // dprintf
> +#include "config.h" // CONFIG_*
> +#include "bochsedid.h"
> +
> +int bochs_get_ddc_capabilities(u16 unit)
> +{
> +    if (unit != 0)
> +        return -1;
> +
> +    return (1 << 8) | VBE_DDC1_PROTOCOL_SUPPORTED;
> +}
> +
> +u8 most_chromaticity[8] VAR16 = {0xA6,0x55,0x48,0x9B,0x26,0x12,0x50,0x54};
> +unsigned char vgabios_name[] VAR16 = "Sea VGABIOS";
> +struct edid_detailed_timing edid_dtd_1280x1024 VAR16 = {
> +     0x2a30, 0x00, 0x98, 0x51, 0x00, 0x2A,
> +     0x40, 0x30, 0x70, 0x13, 0x00, 0x2C, 0xE1, 0x10,
> +     0x00, 0x00, 0x1E};
> +struct edid_detailed_timing edid_dtd_1152x864 VAR16 = {
> +     0x2a30, 0x80, 0xC0, 0x41, 0x60, 0x24,
> +     0x30, 0x40, 0x80, 0x13, 0x00, 0x2C, 0xE1, 0x10,
> +     0x00, 0x00, 0x1E};
> +struct edid_detailed_timing edid_dtd_1600x1200 VAR16 = {
> +     0x3c8c, 0x40, 0x30, 0x62, 0xB0, 0x32,
> +     0x40, 0x40, 0xC0, 0x13, 0x00, 0x2C, 0xE1, 0x10,
> +     0x00, 0x00, 0x1E};
> +struct edid_detailed_timing edid_dtd_1920x1200 VAR16 = {
> +     0x4B7D,  0xB0, 0xA0, 0x72, 0xB0, 0x2D,
> +     0x40, 0x88, 0xC8, 0x55, 0x75, 0x21,
> +     0x00, 0x00, 0x1C};
> +struct edid_monitor_range_limit edid_range_limit VAR16 = {
> +    {0x00,0x00,0x00,0xfD,0x00},
> +    50,150,   /* Vertical 50Hz - 150Hz */
> +    31,135,   /* Horiz 31kHz - 135kHz */
> +    20,       /* clock 200MHz */
> +    0, /* no ext */
> +    0x0A,0x20,0x20,
> +    0x2020,
> +    0x20,0x20 /* padding */
> +    };
> +
> +int bochs_read_edid_block0(u16 unit, u16 block, u16 seg, void *data, u8 next)
> +{
> +    struct edid_info  *info = data;
> +    int i;
> +
> +    memset_far(seg, info, 0, sizeof(*info));
> +    /* header */
> +    SET_FARVAR(seg, info->header[0], 0);
> +    for (i = 1; i < 7; i++) {
> +        SET_FARVAR(seg, info->header[i], 0xFF);
> +    }
> +    SET_FARVAR(seg, info->header[7], 0);
> +    /* Vendor/Product/Serial/Date */
> +    SET_FARVAR(seg, info->vendor, 0x2104);
> +    SET_FARVAR(seg, info->product,0xCDAB);
> +    SET_FARVAR(seg, info->serial, 0x00000000);
> +    /* date/version  */
> +    SET_FARVAR(seg, info->week,36);
> +    SET_FARVAR(seg, info->year,22); /* 2012 */
> +    SET_FARVAR(seg, info->major_version,1);
> +    SET_FARVAR(seg, info->minor_version,3); /* 1.3 */
> +    /* video prameters */
> +    SET_FARVAR(seg, info->video_setup,0x0F);
> +    /* Video signal interface (analogue, 0.700 : 0.300 : 1.000 V p-p,
> +       Video Setup: Blank Level = Black Level, Separate Sync H & V Signals are
> +       supported, Composite Sync Signal on Horizontal is supported, Composite
> +       Sync Signal on Green Video is supported, Serration on the Vertical Sync
> +       is supported) */
> +    SET_FARVAR(seg, info->screen_width,0x21);
> +    SET_FARVAR(seg, info->screen_height,0x19); /* 330 mm * 250 mm */
> +    SET_FARVAR(seg, info->gamma,0x78); /* 2.2 */
> +    SET_FARVAR(seg, info->feature_flag,0x0F); /* no DMPS states, RGB, display is continuous frequency, prefered mode */
> +    SET_FARVAR(seg, info->least_chromaticity[0],0x78);
> +    SET_FARVAR(seg, info->least_chromaticity[1],0xF5);
> +    memcpy_far(seg, info->most_chromaticity, get_global_seg(), most_chromaticity,
> +               sizeof (most_chromaticity));
> +
> +    SET_FARVAR(seg, info->established_timing[0], 0xFF);
> +    SET_FARVAR(seg, info->established_timing[1], 0xEF);
> +    SET_FARVAR(seg, info->established_timing[2], 0x80);
> +    /* 720x400 at 70Hz, 720x400 at 88Hz, 640x480 at 60Hz, 640x480 at 67Hz, 640x480 at 72Hz, 640x480 at 75Hz,
> +       800x600 at 56Hz, 800x600 at 60Hz, 800x600 at 72Hz, 800x600 at 75Hz, 832x624 at 75Hz, 1152x870 at 75Hz,
> +       not 1024x768 at 87Hz(I), 1024x768 at 60Hz, 1024x768 at 70Hz, 1024x768 at 75Hz, 1280x1024 at 75Hz */
> +    /* standard timings */
> +    SET_FARVAR(seg, info->standard_timing[0], EDID_STD_640x480_85Hz);
> +    SET_FARVAR(seg, info->standard_timing[1], EDID_STD_800x600_85Hz);
> +    SET_FARVAR(seg, info->standard_timing[2], EDID_STD_1024x768_85Hz);
> +    SET_FARVAR(seg, info->standard_timing[3], EDID_STD_1280x720_70Hz);
> +    SET_FARVAR(seg, info->standard_timing[4], EDID_STD_1280x960_60Hz);
> +    SET_FARVAR(seg, info->standard_timing[5], EDID_STD_1440x900_60Hz);
> +    SET_FARVAR(seg, info->standard_timing[6], EDID_STD_1600x1200_60Hz);
> +    SET_FARVAR(seg, info->standard_timing[7], EDID_STD_NOP);
> +    /* detailed timing blocks */
> +    memcpy_far(seg, &(info->desc[0].dtd), get_global_seg(), &edid_dtd_1600x1200,
> +               sizeof (edid_dtd_1600x1200));
> +    /* monitor range */
> +    memcpy_far(seg, &(info->desc[1].mrld), get_global_seg(), &edid_range_limit,
> +               sizeof(edid_range_limit));
> +    /* serial */
> +    for (i = 0; i < 5; i++) {
> +        SET_FARVAR(seg, info->desc[2].mtxtd.header[i], 0);
> +    }
> +    SET_FARVAR(seg, info->desc[2].mtxtd.header[3], 0xFF);
> +    for (i = 0; i < 10; i++) {
> +        SET_FARVAR(seg, info->desc[2].mtxtd.text[i], i+0x30);
> +    }
> +    SET_FARVAR(seg, info->desc[2].mtxtd.text[10], 0x0A);
> +    SET_FARVAR(seg, info->desc[2].mtxtd.text[11], 0x20);
> +    SET_FARVAR(seg, info->desc[2].mtxtd.text[12], 0x20);
> +    /* monitor name */
> +    for (i = 0; i < 5; i++) {
> +         SET_FARVAR(seg, info->desc[3].mtxtd.header[i], 0);
> +    }
> +    SET_FARVAR(seg, info->desc[3].mtxtd.header[3], 0xFC);
> +    memcpy_far(seg, info->desc[3].mtxtd.text, get_global_seg(), vgabios_name, 12);
> +    SET_FARVAR(seg, info->desc[3].mtxtd.text[12], 0x0A);
> +    /* ext */
> +    SET_FARVAR(seg, info->extensions, next);
> +
> +    /* checksum */
> +    u8 sum = -checksum_far(get_global_seg(), info, sizeof(info));
> +    SET_FARVAR(seg, info->checksum, sum);
> +
> +    return 0;
> +}
> +
> +int bochs_read_edid(u16 unit, u16 block, u16 seg, void *data)
> +{
> +    if (unit != 0)
> +        return -1;
> +
> +    switch (block) {
> +    case 0:
> +        return bochs_read_edid_block0(unit, block, seg, data, 0);
> +    default:
> +        return -1;
> +    }
> +}
> diff --git a/vgasrc/bochsedid.h b/vgasrc/bochsedid.h
> new file mode 100644
> index 0000000..0f925df
> --- /dev/null
> +++ b/vgasrc/bochsedid.h
> @@ -0,0 +1,136 @@
> +#ifndef __BOCHEDID_H
> +#define __BOCHEDID_H
> +
> +/* EDID infomation definitions */
> +/* Detailed Timing Descriptor */
> +struct edid_detailed_timing {
> +    u16 pixel_clock;
> +    u8 horizontal_addressable_low;
> +    u8 horizontal_blanking_low;
> +    u8 horizontal_high;
> +    u8 vertical_addressable_low;
> +    u8 vertical_blanking_low;
> +    u8 vertical_high;
> +    u8 horizontal_front_porch_low;
> +    u8 horizontal_sync_pulse_low;
> +    u8 vertical_low4;
> +    u8 horizontal_vertical_sync_hi;
> +    u8 horizontal_video_image_low;
> +    u8 vertical_video_image_low;
> +    u8 video_image_high;
> +    u8 horizontal_border;
> +    u8 vertical_border;
> +    u8 features;
> +} PACKED;
> +
> +/* Other Monitor Descriptors */
> +/*
> +  0xFF: Monitor serial number (text)
> +  0xFE: Unspecified text (text)
> +  0xFC: Monitor name (text)
> + */
> +struct edid_monitor_text {
> +    u8 header[5];
> +    u8 text[13];
> +} PACKED;
> +
> +/* Monitor Range Limits Descriptor */
> +/*
> +  0xFD: Monitor range limits. 6- or 13-byte binary descriptor.
> + */
> +struct edid_monitor_range_limit {
> +    u8 header[5];
> +    u8 vertical_rate_min;
> +    u8 vertical_rate_max;
> +    u8 horizontal_rate_min;
> +    u8 horizontal_rate_max;
> +    u8 pixel_clock_max;
> +    u8 extended_timing_type;
> +    u8 reserved;
> +    u8 start_frequency;
> +    u8 gtf_c_val;
> +    u16 gtf_m_val;
> +    u8 gtf_k_val;
> +    u8 gtf_j_val;
> +} PACKED;
> +
> +/* White point Descriptor */
> +/*
> +  0xFB: Additional white point data. 2× 5-byte descriptors, padded with 0A 20 20.
> +  0xFA: Additional standard timing identifiers. 6× 2-byte descriptors, padded with 0A
> + */
> +struct edid_wp_desc {
> +    u8 index;
> +    u8 least;
> +    u8 x;
> +    u8 y;
> +    u8 gamma;
> +} PACKED;
> +
> +struct edid_white_point {
> +    u8 header[5];
> +    struct edid_wp_desc desc[2];
> +    u8 padding[3];
> +} PACKED;
> +
> +struct edid_additional_timing {
> +    u8 header[5];
> +    u16 standard_timing[6];
> +    u8 padding;
> +} PACKED;
> +
> +union edid_descriptors {
> +    struct edid_detailed_timing     dtd;
> +    struct edid_monitor_range_limit mrld;
> +    struct edid_monitor_text        mtxtd;
> +    struct edid_white_point         wpd;
> +    struct edid_additional_timing   astd;
> +} PACKED;
> +
> +struct edid_info {
> +    u8 header[8];
> +    u16 vendor;
> +    u16 product;
> +    u32 serial;
> +    u8 week;
> +    u8 year;
> +    u8 major_version;
> +    u8 minor_version;
> +    u8 video_setup;
> +    u8 screen_width;
> +    u8 screen_height;
> +    u8 gamma;
> +    u8 feature_flag;
> +    u8 least_chromaticity[2];
> +    u8 most_chromaticity[8];
> +    u8 established_timing[3];
> +    u16 standard_timing[8];
> +    union edid_descriptors desc[4];
> +    u8 extensions;
> +    u8 checksum;
> +} PACKED;
> +
> +/* EDID Standard Timing Description */
> +
> +/* First byte: X resolution, divided by 8, less 31 (256–2288 pixels) */
> +/* bit 7-6, X:Y pixel ratio: 00=16:10; 01=4:3; 10=5:4; 11=16:9 */
> +/* bit 5-0, Vertical frequency, less 60 (60–123 Hz), nop 01 01 in Big Endian*/
> +#define EDID_STD_640x480_85Hz                        0x5931
> +#define EDID_STD_800x600_85Hz                        0x5945
> +#define EDID_STD_1024x768_85Hz                       0x5961
> +#define EDID_STD_1152x864_70Hz                       0x4A71
> +#define EDID_STD_1280x720_70Hz                       0xCA81
> +#define EDID_STD_1280x800_70Hz                       0x0A81
> +#define EDID_STD_1280x960_60Hz                       0x4081
> +#define EDID_STD_1280x1024_60Hz                      0x8081
> +#define EDID_STD_1440x900_60Hz                       0x0095
> +#define EDID_STD_1600x1200_60Hz                      0x40A9
> +#define EDID_STD_1600x900_60Hz                       0xC0A9
> +#define EDID_STD_1680x1050_60Hz                      0x00B3
> +#define EDID_STD_1920x1080_60Hz                      0xC0D1
> +#define EDID_STD_1920x1200_60Hz                      0x00D1
> +#define EDID_STD_NOP                                 0x0101
> +

Maybe is a good idea to put all generic edid structs and defines into
its own header file - this would make it easier to reuse them.


> +int bochs_get_ddc_capabilities(u16 unit);
> +int bochs_read_edid(u16 unit, u16 block, u16 seg, void *data);
> +#endif /* bochedid.h */
> diff --git a/vgasrc/vgahw.h b/vgasrc/vgahw.h
> index 01d2609..130462c 100644
> --- a/vgasrc/vgahw.h
> +++ b/vgasrc/vgahw.h
> @@ -8,6 +8,7 @@
>  #include "bochsvga.h" // bochsvga_set_mode
>  #include "stdvga.h" // stdvga_set_mode
>  #include "geodevga.h" // geodevga_init
> +#include "bochsedid.h"
>
>  static inline struct vgamode_s *vgahw_find_mode(int mode) {
>      if (CONFIG_VGA_CIRRUS)
> @@ -130,10 +131,14 @@ static inline int vgahw_restore_state(u16 seg, void *data, int states) {
>  }
>
>  static inline int vgahw_get_ddc_capabilities(u16 unit) {
> +    if (CONFIG_VGA_BOCHS)
> +        return bochs_get_ddc_capabilities(unit);
>      return stdvga_get_ddc_capabilities(unit);
>  }
>
>  static inline int vgahw_read_edid(u16 unit, u16 block, u16 seg, void *data) {
> +    if (CONFIG_VGA_BOCHS)
> +        return bochs_read_edid(unit, block, seg, data);
>      return stdvga_read_edid(unit, block, seg, data);
>  }
>

---
Christian Gmeiner, MSc



More information about the SeaBIOS mailing list