summaryrefslogtreecommitdiff
path: root/QemuVGADriver/src/QemuEdid.c
diff options
context:
space:
mode:
authorMark Cave-Ayland <mark.cave-ayland@ilande.co.uk>2018-12-28 10:03:43 +0000
committerMark Cave-Ayland <mark.cave-ayland@ilande.co.uk>2018-12-28 11:01:24 +0000
commitb21b73b8c6e779752557977d2ce7e664a19516d5 (patch)
tree1efabb81007deecf873cb4070d336d0f670683ea /QemuVGADriver/src/QemuEdid.c
parentd4e7d7ac663fcb55f1b93575445fcbca372f17a7 (diff)
downloadQemuMacDrivers-b21b73b8c6e779752557977d2ce7e664a19516d5.zip
QemuMacDrivers-b21b73b8c6e779752557977d2ce7e664a19516d5.tar.gz
QemuMacDrivers-b21b73b8c6e779752557977d2ce7e664a19516d5.tar.bz2
QemuVGADriver: add support for QEMU EDID data
Versions of QEMU >= 3.1 support passing of display information from host to guest via an EDID blob accessible from the stdvga PCI MMIO BAR. Whilst this feature is still in development, we can start by using the EDID data to generate the list of supported guest resolutions as suggested by the host. As EDID blob generation is currently disabled by default, it must be explicitly enabled on the QEMU command line using "-device VGA,edid=on". In the cases where the EDID data blob is not present, we fall back to using the previous hard-coded set of guest resolutions. Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Diffstat (limited to 'QemuVGADriver/src/QemuEdid.c')
-rw-r--r--QemuVGADriver/src/QemuEdid.c1
1 files changed, 1 insertions, 0 deletions
diff --git a/QemuVGADriver/src/QemuEdid.c b/QemuVGADriver/src/QemuEdid.c
new file mode 100644
index 0000000..57de244
--- /dev/null
+++ b/QemuVGADriver/src/QemuEdid.c
@@ -0,0 +1 @@
+#include <Video.h> #include "VideoDriverPrivate.h" #include "logger.h" #include "QemuVga.h" /* List of video modes */ struct vMode *vModes; /* Default modes if no EDID (must be 0 terminated) */ static struct _vMode defaultVModes[] = { { 640, 480 }, { 800, 600 }, { 1024, 768 }, { 1280, 1024 }, { 1600, 1200 }, { 1920, 1080 }, { 1920, 1200 }, }; /* EDID standard timings */ static struct _vMode edidStdVModes[] = { { 800, 600 }, /* 800x600 @ 60Hz */ { 800, 600 }, /* 800x600 @ 56Hz */ { 640, 480 }, /* 640x480 @ 75Hz */ { 640, 480 }, /* 640x480 @ 72Hz */ { 640, 480 }, /* 640x480 @ 67Hz */ { 640, 480 }, /* 640x480 @ 60Hz */ { 720, 400 }, /* 720x400 @ 88Hz */ { 720, 400 }, /* 720x400 @ 70Hz */ { 1280, 1024 }, /* 1280x1024 @ 75Hz */ { 1024, 768 }, /* 1024x768 @ 75Hz */ { 1024, 768 }, /* 1024x768 @ 72Hz */ { 1024, 768 }, /* 1024x768 @ 60Hz */ { 1024, 768 }, /* 1024x768 @ 87Hz */ { 832, 624 }, /* 832x624 @ 75Hz */ { 800, 600 }, /* 800x600 @ 75Hz */ { 800, 600 }, /* 800x600 @ 72Hz */ { 0, 0 }, /* Reserved */ { 0, 0 }, /* Reserved */ { 0, 0 }, /* Reserved */ { 0, 0 }, /* Reserved */ { 0, 0 }, /* Reserved */ { 0, 0 }, /* Reserved */ { 0, 0 }, /* Reserved */ { 1152, 870 }, /* 1152x870 @ 75Hz */ }; /* EDID extended standard timings */ static struct _vMode edidExtStdVModes[] = { { 1152, 864 }, /* 1152x864 @ 85Hz */ { 1024, 768 }, /* 1024x768 @ 75Hz */ { 800, 600 }, /* 800x600 @ 85Hz */ { 848, 480 }, /* 848x480 @ 60Hz */ { 640, 480 }, /* 640x480 @ 85Hz */ { 720, 400 }, /* 720x400 @ 85Hz */ { 640, 400 }, /* 640x400 @ 85Hz */ { 640, 350 }, /* 640x350 @ 85Hz */ { 1280, 1024 }, /* 1280x1024 @ 85Hz */ { 1280, 1024 }, /* 1280x1024 @ 60Hz */ { 1280, 960 }, /* 1280x960 @ 85Hz */ { 1280, 960 }, /* 1280x960 @ 60Hz */ { 1280, 768 }, /* 1280x768 @ 85Hz */ { 1280, 768 }, /* 1280x768 @ 75Hz */ { 1280, 768 }, /* 1280x768 @ 60Hz */ { 1280, 768 }, /* 1280x768 @ 60Hz (CVT-RB) */ { 1440, 1050 }, /* 1440x1050 @ 75Hz */ { 1440, 1050 }, /* 1440x1050 @ 60Hz */ { 1440, 1050 }, /* 1440x1050 @ 60Hz (CVT-RB) */ { 1440, 900 }, /* 1440x900 @ 85Hz */ { 1440, 900 }, /* 1440x900 @ 75Hz */ { 1440, 900 }, /* 1440x900 @ 60Hz (CVT-RB) */ { 1360, 768 }, /* 1360x768 @ 60Hz */ { 1360, 768 }, /* 1360x768 @ 60Hz (CVT-RB) */ { 1600, 1200 }, /* 1600x1200 @ 70Hz */ { 1600, 1200 }, /* 1600x1200 @ 65Hz */ { 1600, 1200 }, /* 1600x1200 @ 60Hz */ { 1680, 1050 }, /* 1680x1050 @ 85Hz */ { 1680, 1050 }, /* 1680x1050 @ 75Hz */ { 1680, 1050 }, /* 1680x1050 @ 60Hz */ { 1680, 1050 }, /* 1680x1050 @ 60Hz (CVT-RB) */ { 1440, 1050 }, /* 1440x1050 @ 85Hz */ { 1920, 1200 }, /* 1920x1200 @ 60Hz */ { 1920, 1200 }, /* 1920x1200 @ 60Hz (CVT-RB) */ { 1856, 1392 }, /* 1856x1392 @ 75Hz */ { 1856, 1392 }, /* 1856x1392 @ 60Hz */ { 1792, 1344 }, /* 1792x1344 @ 75Hz */ { 1792, 1344 }, /* 1792x1344 @ 60Hz */ { 1600, 1200 }, /* 1600x1200 @ 85Hz */ { 1600, 1200 }, /* 1600x1200 @ 75Hz */ { 0, 0 }, /* Reserved */ { 0, 0 }, /* Reserved */ { 0, 0 }, /* Reserved */ { 0, 0 }, /* Reserved */ { 1920, 1440 }, /* 1920x1440 @ 75Hz */ { 1920, 1440 }, /* 1920x1440 @ 60Hz */ { 1920, 1200 }, /* 1920x1200 @ 75Hz */ { 1920, 1200 }, /* 1920x1200 @ 60Hz */ }; /* EDID timing extension modes */ static struct _vMode edidTimingExtensionVModes[] = { { 640, 480 }, /* DMT0659 */ { 720, 480 }, /* 480p */ { 720, 480 }, /* 480pH */ { 1280, 720 }, /* 720p */ { 1920, 540 }, /* 1080i */ { 1440, 240 }, /* 480i */ { 1440, 240 }, /* 480iH */ { 1440, 240 }, /* 240p */ { 1440, 240 }, /* 240pH */ { 2880, 240 }, /* 480i4x */ { 2880, 240 }, /* 480i4xH */ { 2880, 240 }, /* 240p4x */ { 2880, 240 }, /* 240p4xH */ { 1440, 480 }, /* 480p2x */ { 1440, 480 }, /* 480p2xH */ { 1920, 1080 }, /* 1080p */ { 720, 576 }, /* 576p */ { 720, 576 }, /* 576pH */ { 1280, 720 }, /* 720p50 */ { 1920, 540 }, /* 1080i25 */ { 1440, 288 }, /* 576i */ { 1440, 288 }, /* 576iH */ { 1440, 288 }, /* 288p */ { 1440, 288 }, /* 288pH */ { 2880, 288 }, /* 576i4x */ { 2880, 288 }, /* 576i4xH */ { 2880, 288 }, /* 288p4x */ { 2880, 288 }, /* 288p4xH */ { 1440, 576 }, /* 576p2x */ { 1440, 576 }, /* 576p2xH */ { 1920, 1080 }, /* 1080p50 */ { 1920, 1080 }, /* 1080p24 */ { 1920, 1080 }, /* 1080p25 */ { 1920, 1080 }, /* 1080p30 */ { 2880, 240 }, /* 480p4x */ { 2880, 240 }, /* 480p4xH */ { 2880, 576 }, /* 576p4x */ { 2880, 576 }, /* 576p4xH */ { 1920, 540 }, /* 1080i25 */ { 1920, 540 }, /* 1080i50 */ { 1280, 720 }, /* 720p100 */ { 720, 576 }, /* 576p100 */ { 720, 576 }, /* 576p100H */ { 1440, 576 }, /* 576i50 */ { 1440, 576 }, /* 576i50H */ { 1920, 540 }, /* 1080i60 */ { 1280, 720 }, /* 720p120 */ { 720, 576 }, /* 480p119 */ { 720, 576 }, /* 480p119H */ { 1440, 576 }, /* 480i59 */ { 1440, 576 }, /* 480i59H */ { 720, 576 }, /* 576p200 */ { 720, 576 }, /* 576p200H */ { 1440, 288 }, /* 576i100 */ { 1440, 288 }, /* 576i100H */ { 720, 480 }, /* 480p239 */ { 720, 480 }, /* 480p239H */ { 1440, 240 }, /* 480i119 */ { 1440, 240 }, /* 480i119H */ { 1280, 720 }, /* 720p24 */ { 1280, 720 }, /* 720p25 */ { 1280, 720 }, /* 720p30 */ { 1920, 1080 }, /* 1080p120 */ { 1920, 1080 }, /* 1080p100 */ { 1280, 720 }, /* 720p24 */ { 1280, 720 }, /* 720p25 */ { 1280, 720 }, /* 720p30 */ { 1280, 720 }, /* 720p50 */ { 1650, 750 }, /* 720p */ { 1280, 720 }, /* 720p100 */ { 1280, 720 }, /* 720p120 */ { 1920, 1080 }, /* 1080p24 */ { 1920, 1280 }, /* 1080p25 */ { 1920, 1280 }, /* 1080p30 */ { 1920, 1280 }, /* 1080p50 */ { 1920, 1280 }, /* 1080p */ { 1920, 1280 }, /* 1080p100 */ { 1920, 1280 }, /* 1080p120 */ { 1680, 720 }, /* 720p2x24 */ { 1680, 720 }, /* 720p2x25 */ { 1680, 720 }, /* 720p2x30 */ { 1680, 720 }, /* 720p2x50 */ { 1680, 720 }, /* 720p2x */ { 1680, 720 }, /* 720p2x100 */ { 1680, 720 }, /* 720p2x120 */ { 2560, 1080 }, /* 1080p2x24 */ { 2560, 1080 }, /* 1080p2x25 */ { 2560, 1080 }, /* 1080p2x30 */ { 2560, 1080 }, /* 1080p2x50 */ { 2560, 1080 }, /* 1080p2x */ { 2560, 1080 }, /* 1080p2x100 */ { 2560, 1080 }, /* 1080p2x120 */ { 3840, 2160 }, /* 2160p24 */ { 3840, 2160 }, /* 2160p25 */ { 3840, 2160 }, /* 2160p30 */ { 3840, 2160 }, /* 2160p50 */ { 3840, 2160 }, /* 2160p */ { 4096, 2160 }, /* 2160p24 */ { 4096, 2160 }, /* 2160p25 */ { 4096, 2160 }, /* 2160p30 */ { 4096, 2160 }, /* 2160p50 */ { 4096, 2160 }, /* 2160p */ { 3840, 2160 }, /* 2160p24 */ { 3840, 2160 }, /* 2160p25 */ { 3840, 2160 }, /* 2160p30 */ { 3840, 2160 }, /* 2160p50 */ { 3840, 2160 }, /* 2160p */ { 1280, 720 }, /* 720p48 */ { 1280, 720 }, /* 720p48 */ { 1680, 720 }, /* 720p2x48 */ { 1920, 1280 }, /* 1080p48 */ { 1920, 1280 }, /* 1080p48 */ { 2560, 1080 }, /* 1080p2x48 */ { 3840, 2160 }, /* 2160p48 */ { 4096, 2160 }, /* 2160p48 */ { 3840, 2160 }, /* 2160p48 */ { 3840, 2160 }, /* 2160p100 */ { 3840, 2160 }, /* 2160p120 */ { 3840, 2160 }, /* 2160p100 */ { 3840, 2160 }, /* 2160p120 */ { 5120, 2160 }, /* 2160p2x24 */ { 5120, 2160 }, /* 2160p2x25 */ { 5120, 2160 }, /* 2160p2x30 */ { 5120, 2160 }, /* 2160p2x48 */ { 5120, 2160 }, /* 2160p2x50 */ { 5120, 2160 }, /* 2160p2x */ { 5120, 2160 }, /* 2160p2x100 */ { 0, 0 }, /* Reserved */ }; struct _vMode *getVMode(UInt16 idx) { struct vMode *v = vModes; UInt16 i = 0; while (v != NULL) { if (i == idx) { return v->mode; } v = v->next; i++; } return NULL; } static void dumpVModeList(void) { struct vMode *v = vModes; while (v != NULL) { lprintf(" %d, %d\n", v->mode->width, v->mode->height); v = v->next; } } static UInt16 getVModeListSize(void) { struct vMode *v = vModes; UInt16 i = 0; while (v != NULL) { v = v->next; i++; } return i; } static void addVModeToList(struct _vMode *vMode) { /* Add mode to list */ struct vMode **v = &vModes; struct vMode *n; while (*v != NULL) { /* Don't add mode if resulting framebuffer is too large for PCI MMIO space */ if (vMode->width * vMode->height * 4 > GLOBAL.boardFBMappedSize) { return; } /* Don't add duplicate mode if it already exists */ if ((*v)->mode->width == vMode->width && (*v)->mode->height == vMode->height) { return; } /* Add mode in order */ if (((*v)->mode->width == vMode->width && (*v)->mode->height > vMode->height) || ((*v)->mode->width > vMode->width)) { n = PoolAllocateResident(sizeof(struct vMode), true); n->next = *v; n->mode = vMode; *v = n; return; } v = &(*v)->next; } n = PoolAllocateResident(sizeof(struct vMode), true); n->next = NULL; n->mode = vMode; *v = n; } static UInt8 EdidReadB(UInt16 port) { UInt8 *ptr, val; ptr = (UInt8 *)((UInt32)GLOBAL.boardRegAddress + port); val = *ptr; SynchronizeIO(); return val; } static UInt16 GetEdidSize() { return 0x80 * ((UInt16)EdidReadB(0x7e) + 1); } static void ParseEdid(UInt8 *edid) { int i, j, d, idx; /* Standard modes */ lprintf("Standard modes: \n"); for (i = 35; i <= 37; i++) { for (j = 0; j <= 7; j++) { if (edid[i] & (1 << j)) { idx = ((i - 35) << 3) + j; lprintf(" %d, %d\n", edidStdVModes[idx].width, edidStdVModes[idx].height); addVModeToList(&edidStdVModes[idx]); } } } /* Extended standard modes */ lprintf("Extended standard modes: \n"); d = i = 54; while (d < 126) { /* Search for descriptor */ if (edid[d] == 0x0 && edid[d + 1] == 0x0 && edid[d + 2] == 0x0 && edid[d + 3] == 0xf7 && edid[d + 4] == 0x0) { for (i = d + 6; i <= d + 11; i++) { for (j = 0; j <= 7; j++) { if (edid[i] & (1 << j)) { idx = ((i - d - 6) << 3) + j; lprintf(" %d, %d\n", edidExtStdVModes[idx].width, edidExtStdVModes[idx].height); addVModeToList(&edidExtStdVModes[idx]); } } } break; } d += 18; } /* Extension block modes */ lprintf("Extension block modes: \n"); if (edid[126] > 0) { /* Search for descriptor */ i = 128; if (edid[i] == 0x2 && edid[i + 1] == 0x3) { /* Data present: check for video block */ d = edid[i + 2]; if (d > 0x4 && (edid[i + 4] & 0xf0) == (2 << 5)) { for (j = 0; j < (edid[i + 4] & 0x1f); j++) { idx = edid[(i + 5 + j)]; lprintf(" %d, %d\n", edidTimingExtensionVModes[idx].width, edidTimingExtensionVModes[idx].height); addVModeToList(&edidTimingExtensionVModes[idx]); } } } } } static void ParseDefaultVModes() { UInt8 defaultVModeCount; int i; defaultVModeCount = sizeof(defaultVModes) / sizeof(struct _vMode); lprintf("Default modes:\n"); for (i = 0; i < defaultVModeCount; i++) { lprintf(" %d, %d\n", defaultVModes[i].width, defaultVModes[i].height); addVModeToList(&defaultVModes[i]); } } UInt16 QemuVga_ReadEdidModes(void) { UInt16 edidSize = GetEdidSize(); UInt8 *edid; int i; if (EdidReadB(0x0) != 0x0 || EdidReadB(0x1) != 0xff) { lprintf("No valid EDID detected, using default modes\n"); ParseDefaultVModes(); return getVModeListSize(); } lprintf("EDID size: %d bytes, reading modes from EDID...\n", edidSize); edid = (UInt8 *)PoolAllocateResident(edidSize, true); if (!edid) return; for (i = 0; i < edidSize; i++) { edid[i] = EdidReadB(i); } ParseEdid(edid); PoolDeallocate(edid); lprintf("Final mode list:\n"); dumpVModeList(); return getVModeListSize(); } \ No newline at end of file