As same as bochsvga that init code disables modes
that is larger than max_{x|y}res, bochsedid
also disables STD_EDID that is larger than
max_{x|y}res.
The int15h returns largest and smaller edid mode
than MAX_XRES, MAX_YRES.
Signed-off-by: Hiroshi Miura <miurahr(a)linux.com>
---
vgasrc/bochsedid.c | 74 ++++++++++++++++++++++++++++++++++++++++++++--------
vgasrc/bochsedid.h | 6 +++++
vgasrc/bochsvga.c | 6 ++++-
3 files changed, 74 insertions(+), 12 deletions(-)
diff --git a/vgasrc/bochsedid.c b/vgasrc/bochsedid.c
index 5a40593..022a850 100644
--- a/vgasrc/bochsedid.c
+++ b/vgasrc/bochsedid.c
@@ -20,6 +20,26 @@ int bochs_get_ddc_capabilities(u16 unit)
u8 most_chromaticity[8] VAR16 = {0xA6,0x55,0x48,0x9B,0x26,0x12,0x50,0x54};
unsigned char vgabios_name[] VAR16 = "Sea VGABIOS";
+static struct bochs_edid_mode {
+ u16 mode;
+ u16 width;
+ u16 height;
+ u8 ratio;
+} bochs_edid_modes[] VAR16 = {
+{EDID_STD_1920x1200_60Hz,1920,1200, EDID_STD_RATIO_16_10},
+{EDID_STD_1920x1080_60Hz,1920,1080, EDID_STD_RATIO_16_9},
+{EDID_STD_1680x1050_60Hz,1680,1050, EDID_STD_RATIO_16_10},
+{EDID_STD_1600x1200_60Hz,1600,1200, EDID_STD_RATIO_4_3},
+{EDID_STD_1600x900_60Hz, 1600, 900, EDID_STD_RATIO_16_9},
+{EDID_STD_1440x900_60Hz, 1440, 900, EDID_STD_RATIO_16_10},
+{EDID_STD_1280x1024_60Hz,1280,1024, EDID_STD_RATIO_5_4},
+{EDID_STD_1280x960_60Hz, 1280, 960, EDID_STD_RATIO_4_3},
+{EDID_STD_1152x864_70Hz, 1152, 864, EDID_STD_RATIO_4_3},
+{EDID_STD_1024x768_85Hz, 1024, 768, EDID_STD_RATIO_4_3},
+{EDID_STD_800x600_85Hz, 800, 600, EDID_STD_RATIO_4_3},
+{EDID_STD_640x480_85Hz, 640, 480, EDID_STD_RATIO_4_3}
+};
+
struct edid_detailed_timing edid_dtd_1280x1024 VAR16 = {
0x2a30, 0x00, 0x98, 0x51, 0x00, 0x2A,
0x40, 0x30, 0x70, 0x13, 0x00, 0x2C, 0xE1, 0x10,
@@ -47,6 +67,22 @@ struct edid_monitor_range_limit edid_range_limit VAR16 = {
0x20,0x20 /* padding */
};
+u16 max_xres VAR16, max_yres VAR16;
+
+void bochs_validate_edid_resolutions(u16 xres, u16 yres) {
+ struct bochs_edid_mode *m = bochs_edid_modes;
+ for (; m < &bochs_edid_modes[ARRAY_SIZE(bochs_edid_modes)]; m++){
+ u16 width = GET_GLOBAL(m->width);
+ u16 height = GET_GLOBAL(m->height);
+ if (width > xres || height > yres) {
+ dprintf(1, "Removing edid mode %x\n", GET_GLOBAL(m->mode));
+ SET_VGA(m->mode, EDID_STD_NOP);
+ }
+ }
+ SET_VGA(max_xres, xres);
+ SET_VGA(max_yres, yres);
+}
+
int bochs_read_edid_block0(u16 unit, u16 block, u16 seg, void *data, u8 next)
{
struct edid_info *info = data;
@@ -90,18 +126,33 @@ int bochs_read_edid_block0(u16 unit, u16 block, u16 seg, void *data, u8 next)
/* 720x400@70Hz, 720x400@88Hz, 640x480@60Hz, 640x480@67Hz, 640x480@72Hz, 640x480@75Hz,
800x600@56Hz, 800x600@60Hz, 800x600@72Hz, 800x600@75Hz, 832x624@75Hz, 1152x870@75Hz,
not 1024x768@87Hz(I), 1024x768@60Hz, 1024x768@70Hz, 1024x768@75Hz, 1280x1024@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));
+ struct bochs_edid_mode *m = bochs_edid_modes;
+ for (i = 0; (i < 8) && (m < &bochs_edid_modes[ARRAY_SIZE(bochs_edid_modes)]); m++){
+ if (GET_GLOBAL(m->mode) != EDID_STD_NOP) {
+ SET_FARVAR(seg, info->standard_timing[i], GET_GLOBAL(m->mode));
+ i++;
+ }
+ }
+ for (; i < 8; i++) { /* if rest, fill with NOP */
+ SET_FARVAR(seg, info->standard_timing[i], EDID_STD_NOP);
+ }
+ /* detailed timing block */
+ /* select one that is largest and lower than max_xres */
+ if (GET_GLOBAL(max_xres) < 1280) {
+ memcpy_far(seg, &(info->desc[0].dtd), get_global_seg(), &edid_dtd_1152x864,
+ sizeof (struct edid_detailed_timing));
+ } else if (GET_GLOBAL(max_xres) < 1600) {
+ memcpy_far(seg, &(info->desc[0].dtd), get_global_seg(), &edid_dtd_1280x1024,
+ sizeof (struct edid_detailed_timing));
+ } else if (GET_GLOBAL(max_xres) >= 1600 && GET_GLOBAL(max_xres) < 1920) {
+ memcpy_far(seg, &(info->desc[0].dtd), get_global_seg(), &edid_dtd_1600x1200,
+ sizeof (struct edid_detailed_timing));
+ } else {
+ memcpy_far(seg, &(info->desc[0].dtd), get_global_seg(), &edid_dtd_1920x1200,
+ sizeof (struct edid_detailed_timing));
+ }
/* monitor range */
memcpy_far(seg, &(info->desc[1].mrld), get_global_seg(), &edid_range_limit,
sizeof(edid_range_limit));
@@ -145,3 +196,4 @@ int bochs_read_edid(u16 unit, u16 block, u16 seg, void *data)
return -1;
}
}
+
diff --git a/vgasrc/bochsedid.h b/vgasrc/bochsedid.h
index 0f925df..8f82316 100644
--- a/vgasrc/bochsedid.h
+++ b/vgasrc/bochsedid.h
@@ -131,6 +131,12 @@ struct edid_info {
#define EDID_STD_1920x1200_60Hz 0x00D1
#define EDID_STD_NOP 0x0101
+#define EDID_STD_RATIO_16_10 (1)
+#define EDID_STD_RATIO_4_3 (1 << 1)
+#define EDID_STD_RATIO_5_4 (1 << 2)
+#define EDID_STD_RATIO_16_9 (1 << 3)
+
+void bochs_validate_edid_resolutions(u16 xres, u16 yres);
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/bochsvga.c b/vgasrc/bochsvga.c
index 2a8aeb1..9fcbdae 100644
--- a/vgasrc/bochsvga.c
+++ b/vgasrc/bochsvga.c
@@ -369,12 +369,14 @@ bochsvga_init(void)
dprintf(1, "VBE DISPI: lfb_addr=%x, size %d MB\n",
lfb_addr, totalmem >> 20);
- // Validate modes
+ // Validate modes and edid resolutions
u16 en = dispi_read(VBE_DISPI_INDEX_ENABLE);
dispi_write(VBE_DISPI_INDEX_ENABLE, en | VBE_DISPI_GETCAPS);
u16 max_xres = dispi_read(VBE_DISPI_INDEX_XRES);
+ u16 max_yres = dispi_read(VBE_DISPI_INDEX_YRES);
u16 max_bpp = dispi_read(VBE_DISPI_INDEX_BPP);
dispi_write(VBE_DISPI_INDEX_ENABLE, en);
+ /* modes */
struct bochsvga_mode *m = bochsvga_modes;
for (; m < &bochsvga_modes[ARRAY_SIZE(bochsvga_modes)]; m++) {
u16 width = GET_GLOBAL(m->info.width);
@@ -388,6 +390,8 @@ bochsvga_init(void)
SET_VGA(m->mode, 0xffff);
}
}
+ /* edid resolutions */
+ bochs_validate_edid_resolutions(max_xres, max_yres);
return 0;
}
--
1.7.9.5