Bochs/bochs/iodev/display/ddc.cc

328 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018-2020 The Bochs Project
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// DDC support (returns the VESA EDID for the Bochs plug&play monitor)
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "bochs.h"
#include "ddc.h"
#include "param_names.h"
#define LOG_THIS
enum {
DDC_STAGE_START,
DDC_STAGE_ADDRESS,
DDC_STAGE_RW,
DDC_STAGE_DATA_IN,
DDC_STAGE_DATA_OUT,
DDC_STAGE_ACK_IN,
DDC_STAGE_ACK_OUT,
DDC_STAGE_STOP
};
const Bit8u vesa_EDID[128] = {
0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,
/* 0x0000 8-byte header */
0x04,0x21, /* 0x0008 Vendor ID ("AAA") */
0xAB,0xCD, /* 0x000A Product ID */
0x00,0x00,0x00,0x00, /* 0x000C Serial number (none) */
12, 11, /* 0x0010 Week of manufacture (12) and year of manufacture (2001) */
0x01, 0x03, /* 0x0012 EDID version number (1.3) */
0x0F, /* 0x0014 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) */
0x21,0x19, /* 0x0015 Scren size (330 mm * 250 mm) */
0x78, /* 0x0017 Display gamma (2.2) */
0x0D, /* 0x0018 Feature flags (no DMPS states, RGB, display is continuous frequency) */
0x78,0xF5, /* 0x0019 Least significant bits for chromaticity and default white point */
0xA6,0x55,0x48,0x9B,0x26,0x12,0x50,0x54,
/* 0x001B Most significant bits for chromaticity and default white point */
0xFF, /* 0x0023 Established timings 1 (720 x 400 @ 70Hz, 720 x 400 @ 88Hz,
640 x 480 @ 60Hz, 640 x 480 @ 67Hz, 640 x 480 @ 72Hz, 640 x 480 @ 75Hz,
800 x 600 @ 56Hz, 800 x 600 @ 60Hz) - historical resolutions */
0xEF, /* 0x0024 Established timings 2 (800 x 600 @ 72Hz, 800 x 600 @ 75Hz, 832 x 624 @ 75Hz
not 1024 x 768 @ 87Hz(I), 1024 x 768 @ 60Hz, 1024 x 768 @ 70Hz,
1024 x 768 @ 75Hz, 1280 x 1024 @ 75Hz) - historical resolutions */
0x80, /* 0x0025 Established timings 2 (1152 x 870 @ 75Hz and no manufacturer timings) */
/* Standard timing */
/* First byte: X resolution, divided by 8, less 31 (2562288 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 (60123 Hz), nop 01 01 */
0x31, 0x59, /* 0x0026 Standard timing #1 (640 x 480 @ 85 Hz) */
0x45, 0x59, /* 0x0028 Standard timing #2 (800 x 600 @ 85 Hz) */
0x61, 0x59, /* 0x002A Standard timing #3 (1024 x 768 @ 85 Hz) */
0x81, 0xCA, /* 0x002C Standard timing #4 (1280 x 720 @ 70 Hz) */
0x81, 0x0A, /* 0x002E Standard timing #5 (1280 x 800 @ 70 Hz) */
0xA9, 0xC0, /* 0x0030 Standard timing #6 (1600 x 900 @ 60 Hz) */
0xA9, 0x40, /* 0x0034 Standard timing #7 (1600 x 1200 @ 60 Hz) */
0xD1, 0x00, /* 0x0032 Standard timing #8 (1920 x 1080 @ 60 Hz) */
/* 0x0036 First 18-byte descriptor (1920 x 1200) */
0x3C, 0x28, /* Pixel clock = 154000000 Hz */
0x80, /* 0x0038 Horizontal addressable pixels low byte (0x0780 & 0xFF) */
0xA0, /* 0x0039 Horizontal blanking low byte (0x00A0 & 0xFF) */
0x70, /* 0x003A Horizontal addressable pixels high 4 bits ((0x0780 & 0x0F00) >> 4), and */
/* Horizontal blanking high 4 bits ((0x00A0 & 0x0F00 ) >> 8) as low bits */
0xB0, /* 0x003B Vertical addressable pixels low byte (0x04B0 & 0xFF) */
0x23, /* 0x003C Vertical blanking low byte (0x0023 & 0xFF) */
0x40, /* 0x003D Vertical addressable pixels high 4 bits ((0x04B0 & 0x0F00) >> 4), and */
/* Vertical blanking high 4 bits ((0x0024 & x0F00) >> 8) */
0x30, /* 0x003E Horizontal front porch in pixels low byte (0x0030 & 0xFF) */
0x20, /* 0x003F Horizontal sync pulse width in pixels low byte (0x0020 & 0xFF) */
0x36, /* 0x0040 Vertical front porch in lines low 4 bits ((0x0003 & 0x0F) << 4), and */
/* Vertical sync pulse width in lines low 4 bits (0x0006 & 0x0F) */
0x00, /* 0x0041 Horizontal front porch pixels high 2 bits (0x0030 >> 8), and */
/* Horizontal sync pulse width in pixels high 2 bits (0x0020 >> 8), and */
/* Vertical front porch in lines high 2 bits (0x0003 >> 4), and */
/* Vertical sync pulse width in lines high 2 bits (0x0006 >> 4) */
0x06, /* 0x0042 Horizontal addressable video image size in mm low 8 bits (0x0206 & 0xFF) */
0x44, /* 0x0043 Vertical addressable video image size in mm low 8 bits (0x0144 & 0xFF) */
0x21, /* 0x0044 Horizontal addressable video image size in mm high 8 bits (0x0206 >> 8), and */
/* Vertical addressable video image size in mm high 8 bits (0x0144 >> 8) */
0x00, /* 0x0045 Left and right border size in pixels (0x00) */
0x00, /* 0x0046 Top and bottom border size in lines (0x00) */
0x1E, /* 0x0047 Flags (non-interlaced, no stereo, analog composite sync, sync on */
/* all three (RGB) video signals) */
/* 0x0048 Second 18-byte descriptor (1280 x 1024) */
0x30, 0x2a, /* Pixel clock = 108000000 Hz */
0x00, /* 0x004A Horizontal addressable pixels low byte (0x0500 & 0xFF) */
0x98, /* 0x004B Horizontal blanking low byte (0x0198 & 0xFF) */
0x51, /* 0x004C Horizontal addressable pixels high 4 bits (0x0500 >> 8), and */
/* Horizontal blanking high 4 bits (0x0198 >> 8) */
0x00, /* 0x004D Vertical addressable pixels low byte (0x0400 & 0xFF) */
0x2A, /* 0x004E Vertical blanking low byte (0x002A & 0xFF) */
0x40, /* 0x004F Vertical addressable pixels high 4 bits (0x0400 >> 8), and */
/* Vertical blanking high 4 bits (0x002A >> 8) */
0x30, /* 0x0050 Horizontal front porch in pixels low byte (0x0030 & 0xFF) */
0x70, /* 0x0051 Horizontal sync pulse width in pixels low byte (0x0070 & 0xFF) */
0x13, /* 0x0052 Vertical front porch in lines low 4 bits (0x0001 & 0x0F), and */
/* Vertical sync pulse width in lines low 4 bits (0x0003 & 0x0F) */
0x00, /* 0x0053 Horizontal front porch pixels high 2 bits (0x0030 >> 8), and */
/* Horizontal sync pulse width in pixels high 2 bits (0x0070 >> 8), and */
/* Vertical front porch in lines high 2 bits (0x0001 >> 4), and */
/* Vertical sync pulse width in lines high 2 bits (0x0003 >> 4) */
0x2C, /* 0x0054 Horizontal addressable video image size in mm low 8 bits (0x012C & 0xFF) */
0xE1, /* 0x0055 Vertical addressable video image size in mm low 8 bits (0x00E1 & 0xFF) */
0x10, /* 0x0056 Horizontal addressable video image size in mm high 8 bits (0x012C >> 8), and */
/* Vertical addressable video image size in mm high 8 bits (0x00E1 >> 8) */
0x00, /* 0x0057 Left and right border size in pixels (0x00) */
0x00, /* 0x0058 Top and bottom border size in lines (0x00) */
0x1E, /* 0x0059 Flags (non-interlaced, no stereo, analog composite sync, sync on */
/* all three (RGB) video signals) */
0x00,0x00,0x00,0xFF,0x00, /* 0x005A Third 18-byte descriptor - display product serial number */
'0','1','2','3','4','5','6','7','8','9',
0x0A,0x20,0x20,
0x00,0x00,0x00,0xFC,0x00, /* 0x006C Fourth 18-byte descriptor - display product name */
'B','o','c','h','s',' ','S','c','r','e','e','n',
0x0A,
0x00, /* 0x007E Extension block count (none) */
0x94, /* 0x007F Checksum */
};
bx_ddc_c::bx_ddc_c(void)
{
int fd, ret;
struct stat stat_buf;
const char *path;
put("DDC");
s.DCKhost = 1;
s.DDAhost = 1;
s.DDAmon = 1;
s.ddc_stage = DDC_STAGE_STOP;
s.ddc_ack = 1;
s.ddc_rw = 1;
s.edid_index = 0;
s.ddc_mode = SIM->get_param_enum(BXPN_DDC_MODE)->get();
if (s.ddc_mode == BX_DDC_MODE_BUILTIN) {
memcpy(s.edid_data, vesa_EDID, 128);
s.edid_extblock = 0;
} else if (s.ddc_mode == BX_DDC_MODE_FILE) {
path = SIM->get_param_string(BXPN_DDC_FILE)->getptr();
fd = open(path, O_RDONLY
#ifdef O_BINARY
| O_BINARY
#endif
);
if (fd < 0) {
BX_PANIC(("failed to open monitor EDID file '%s'", path));
}
ret = fstat(fd, &stat_buf);
if (ret) {
BX_PANIC(("could not fstat() monitor EDID file."));
}
if ((stat_buf.st_size != 128) && (stat_buf.st_size != 256)) {
BX_PANIC(("monitor EDID file size must be 128 or 256 bytes"));
} else {
s.edid_extblock = (stat_buf.st_size == 256);
}
ret = ::read(fd, (bx_ptr_t) s.edid_data, (unsigned)stat_buf.st_size);
if (ret != stat_buf.st_size) {
BX_PANIC(("error reading monitor EDID file."));
}
close(fd);
BX_INFO(("Monitor EDID read from image file '%s'.", path));
}
}
bx_ddc_c::~bx_ddc_c(void)
{
}
Bit8u bx_ddc_c::read()
{
Bit8u retval = (((s.DDAmon & s.DDAhost) << 3) | (s.DCKhost << 2) |
(s.DDAhost << 1) | s.DCKhost);
return retval;
}
void bx_ddc_c::write(bx_bool dck, bx_bool dda)
{
bx_bool dck_change = 0;
bx_bool dda_change = 0;
if (s.ddc_mode == BX_DDC_MODE_DISABLED)
return;
if ((dck != s.DCKhost) || (dda != s.DDAhost)) {
dck_change = (dck != s.DCKhost);
dda_change = (dda != s.DDAhost);
if (dck_change && dda_change) {
BX_ERROR(("DDC unknown: DCK=%d DDA=%d", dck, dda));
} else if (dck_change) {
if (!dck) {
switch (s.ddc_stage) {
case DDC_STAGE_START:
s.ddc_stage = DDC_STAGE_ADDRESS;
s.ddc_bitshift = 6;
s.ddc_byte = 0;
break;
case DDC_STAGE_ADDRESS:
if (s.ddc_bitshift > 0) {
s.ddc_bitshift--;
} else {
s.ddc_ack = !(s.ddc_byte == 0x50);
BX_DEBUG(("Address = 0x%02x", s.ddc_byte));
s.ddc_stage = DDC_STAGE_RW;
}
break;
case DDC_STAGE_RW:
BX_DEBUG(("R/W mode = %d", s.ddc_rw));
s.ddc_stage = DDC_STAGE_ACK_OUT;
s.DDAmon = s.ddc_ack;
break;
case DDC_STAGE_DATA_IN:
if (s.ddc_bitshift > 0) {
s.ddc_bitshift--;
} else {
s.ddc_ack = 0;
BX_DEBUG(("Data = 0x%02x (setting offset address)", s.ddc_byte));
s.edid_index = s.ddc_byte;
s.DDAmon = s.ddc_ack;
s.ddc_stage = DDC_STAGE_ACK_OUT;
}
break;
case DDC_STAGE_DATA_OUT:
if (s.ddc_bitshift > 0) {
s.ddc_bitshift--;
s.DDAmon = ((s.ddc_byte >> s.ddc_bitshift) & 1);
} else {
s.ddc_stage = DDC_STAGE_ACK_IN;
s.DDAmon = 1;
}
break;
case DDC_STAGE_ACK_IN:
BX_DEBUG(("Received status %s", s.ddc_ack ? "NAK":"ACK"));
if (s.ddc_ack == 0) {
s.ddc_bitshift = 7;
s.ddc_stage = DDC_STAGE_DATA_OUT;
s.ddc_byte = get_edid_byte();
s.DDAmon = ((s.ddc_byte >> s.ddc_bitshift) & 1);
} else {
s.ddc_stage = DDC_STAGE_STOP;
}
break;
case DDC_STAGE_ACK_OUT:
BX_DEBUG(("Sent status %s", s.ddc_ack ? "NAK":"ACK"));
s.ddc_bitshift = 7;
if (s.ddc_rw) {
s.ddc_stage = DDC_STAGE_DATA_OUT;
s.ddc_byte = get_edid_byte();
s.DDAmon = ((s.ddc_byte >> s.ddc_bitshift) & 1);
} else {
s.ddc_stage = DDC_STAGE_DATA_IN;
s.DDAmon = 1;
s.ddc_byte = 0;
}
break;
}
} else {
switch (s.ddc_stage) {
case DDC_STAGE_ADDRESS:
case DDC_STAGE_DATA_IN:
s.ddc_byte |= (s.DDAhost << s.ddc_bitshift);
break;
case DDC_STAGE_RW:
s.ddc_rw = s.DDAhost;
break;
case DDC_STAGE_ACK_IN:
s.ddc_ack = s.DDAhost;
break;
}
}
} else {
if (s.DCKhost) {
if (!dda) {
s.ddc_stage = DDC_STAGE_START;
BX_DEBUG(("Start detected"));
} else {
s.ddc_stage = DDC_STAGE_STOP;
BX_DEBUG(("Stop detected"));
}
}
}
s.DCKhost = dck;
s.DDAhost = dda;
}
}
Bit8u bx_ddc_c::get_edid_byte()
{
Bit8u value = s.edid_data[s.edid_index++];
BX_DEBUG(("Sending EDID byte 0x%02x (value = 0x%02x)", s.edid_index - 1, value));
if (!s.edid_extblock) s.edid_index &= 0x7f;
return value;
}