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@linux.com --- vgasrc/bochsedid.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++--- vgasrc/bochsedid.h | 8 +++- vgasrc/bochsvga.c | 10 ++++- 3 files changed, 113 insertions(+), 9 deletions(-)
diff --git a/vgasrc/bochsedid.c b/vgasrc/bochsedid.c index ec43d41..cf90c04 100644 --- a/vgasrc/bochsedid.c +++ b/vgasrc/bochsedid.c @@ -10,10 +10,54 @@ #include "config.h" // CONFIG_* #include "bochsedid.h"
-struct edid_detailed_timing edid_dtd_1920x1200 VAR16 = { - 0x4B7D, 0xB0, 0xA0, 0x72, 0xB0, 0x2D, +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 bochs_edid_dtd { + struct edid_detailed_timing dtd; + u16 width; + u16 height; + u8 ratio; + int disabled; +} bochs_edid_dtds[] VAR16 = { + {{0x4B7D, 0xB0, 0xA0, 0x72, 0xB0, 0x2D, 0x40, 0x88, 0xC8, 0x55, 0x75, 0x21, - 0x00, 0x00, 0x1C}; + 0x00, 0x00, 0x1C}, + 1920,1200,EDID_STD_RATIO_16_10,0 + }, + {{0x3c8c, 0x40, 0x30, 0x62, 0xB0, 0x32, + 0x40, 0x40, 0xC0, 0x13, 0x00, 0x2C, 0xE1, 0x10, + 0x00, 0x00, 0x1E}, + 1600,1200,EDID_STD_RATIO_4_3,0 + }, + {{0x2a30, 0x00, 0x98, 0x51, 0x00, 0x2A, + 0x40, 0x30, 0x70, 0x13, 0x00, 0x2C, 0xE1, 0x10, + 0x00, 0x00, 0x1E}, + 1280,1024,EDID_STD_RATIO_5_4,0 + }, + {{0x2a30, 0x80, 0xC0, 0x41, 0x60, 0x24, + 0x30, 0x40, 0x80, 0x13, 0x00, 0x2C, 0xE1, 0x10, + 0x00, 0x00, 0x1E}, + 1152, 864,EDID_STD_RATIO_4_3,0 + }, +}; struct edid_monitor_range_limit edid_range_limit VAR16 = { {0x00,0x00,0x00,0xfD,0x00}, 50,150, /* Vertical 50Hz - 150Hz */ @@ -58,11 +102,58 @@ struct edid_info BochsEDID VAR16 = { EDID_STD_1600x1200_60Hz,EDID_STD_NOP}, };
-void bochs_pupulate_edid_block0(u8 next) +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); + } + } + struct bochs_edid_dtd *d = bochs_edid_dtds; + for (; d < &bochs_edid_dtds[ARRAY_SIZE(bochs_edid_dtds)]; d++){ + u16 width = GET_GLOBAL(d->width); + u16 height = GET_GLOBAL(d->height); + if (width > xres || height > yres) { + dprintf(1, "Removing edid dtd %d x %d\n", width, height); + SET_VGA(d->disabled, 1); + } + } +} + +int bochs_pupulate_edid_block0(u8 next) { + int i; + + 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_VGA(BochsEDID.standard_timing[i], GET_GLOBAL(m->mode)); + i++; + } + } + for (; i < 8; i++) { /* if rest, fill with NOP */ + SET_VGA(BochsEDID.standard_timing[i], EDID_STD_NOP); + } /* detailed timing block */ - memcpy_far(get_global_seg(), &(BochsEDID.desc[0]), get_global_seg(), - &edid_dtd_1920x1200, sizeof (struct edid_detailed_timing)); + /* select one that is largest and lower than max_xres */ + int done = 0; + struct bochs_edid_dtd *d = bochs_edid_dtds; + for (; d < &bochs_edid_dtds[ARRAY_SIZE(bochs_edid_dtds)]; d++){ + if (d->disabled) { + continue; + } + /* copy first entry within max_resolution */ + memcpy_far(get_global_seg(), &(BochsEDID.desc[0]), get_global_seg(), + &(d->dtd), sizeof (struct edid_detailed_timing)); + done = 1; + break; + } + if (done == 0) + return -1; + /* monitor range */ memcpy_far(get_global_seg(), &(BochsEDID.desc[1].mrld), get_global_seg(), &edid_range_limit, sizeof(edid_range_limit)); @@ -76,6 +167,7 @@ void bochs_pupulate_edid_block0(u8 next) SET_VGA(BochsEDID.extensions, next); u8 sum = -checksum_far(get_global_seg(), &BochsEDID, sizeof(BochsEDID)); SET_VGA(BochsEDID.checksum, sum); + return 0; }
int bochs_read_edid_block0(u16 unit, u16 block, u16 seg, void *data) diff --git a/vgasrc/bochsedid.h b/vgasrc/bochsedid.h index b6b2e3a..60ae3c9 100644 --- a/vgasrc/bochsedid.h +++ b/vgasrc/bochsedid.h @@ -131,7 +131,13 @@ struct edid_info { #define EDID_STD_1920x1200_60Hz 0x00D1 #define EDID_STD_NOP 0x0101
-void bochs_pupulate_edid_block0(u8 next); +#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) + +int bochs_pupulate_edid_block0(u8 next); +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 7b8f430..bcb41be 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,7 +390,11 @@ bochsvga_init(void) SET_VGA(m->mode, 0xffff); } } - bochs_pupulate_edid_block0(0); + /* edid resolutions */ + bochs_validate_edid_resolutions(max_xres, max_yres); + ret = bochs_pupulate_edid_block0(0); + if (ret) + return ret;
return 0; }