Rewrite custom EDID loading
This commit is contained in:
@@ -20,8 +20,9 @@
|
|||||||
#ifndef EMU_VID_DDC_H
|
#ifndef EMU_VID_DDC_H
|
||||||
#define EMU_VID_DDC_H
|
#define EMU_VID_DDC_H
|
||||||
|
|
||||||
extern void *ddc_init(void *i2c);
|
extern void *ddc_init(void *i2c);
|
||||||
extern void ddc_close(void *eeprom);
|
extern void ddc_close(void *eeprom);
|
||||||
extern void *ddc_create_default_edid(ssize_t* size_out);
|
extern size_t ddc_create_default_edid(uint8_t **size_out);
|
||||||
|
extern size_t ddc_load_edid(char *path, uint8_t *buf, size_t size);
|
||||||
|
|
||||||
#endif /*EMU_VID_DDC_H*/
|
#endif /*EMU_VID_DDC_H*/
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QStringBuilder>
|
#include <QStringBuilder>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <86box/86box.h>
|
#include <86box/86box.h>
|
||||||
#include <86box/device.h>
|
#include <86box/device.h>
|
||||||
@@ -343,11 +345,10 @@ void SettingsDisplay::on_pushButtonExportDefault_clicked()
|
|||||||
if (!str.isEmpty()) {
|
if (!str.isEmpty()) {
|
||||||
QFile file(str);
|
QFile file(str);
|
||||||
if (file.open(QFile::WriteOnly)) {
|
if (file.open(QFile::WriteOnly)) {
|
||||||
ssize_t size = 0;
|
uint8_t *bytes = nullptr;
|
||||||
auto bytes = ddc_create_default_edid(&size);
|
auto size = ddc_create_default_edid(&bytes);
|
||||||
file.write((char*)bytes, size);
|
file.write((char*)bytes, size);
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ add_library(utils OBJECT
|
|||||||
cJSON.c
|
cJSON.c
|
||||||
crc.c
|
crc.c
|
||||||
crc32.c
|
crc32.c
|
||||||
edid_parse.cpp
|
|
||||||
fifo.c
|
fifo.c
|
||||||
fifo8.c
|
fifo8.c
|
||||||
ini.c
|
ini.c
|
||||||
|
|||||||
@@ -1,119 +0,0 @@
|
|||||||
#include <cstdlib>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <vector>
|
|
||||||
#include <sstream>
|
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
#include <regex>
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#include <86box/86box.h>
|
|
||||||
#include <86box/plat.h>
|
|
||||||
|
|
||||||
extern int ini_detect_bom(const char *fn);
|
|
||||||
extern ssize_t local_getline(char **buf, size_t *bufsiz, FILE *fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://stackoverflow.com/a/64886763
|
|
||||||
static std::vector<std::string> split(const std::string str, const std::string regex_str)
|
|
||||||
{
|
|
||||||
std::regex regexz(regex_str);
|
|
||||||
std::vector<std::string> list(std::sregex_token_iterator(str.begin(), str.end(), regexz, -1),
|
|
||||||
std::sregex_token_iterator());
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
bool parse_edid_decode_file(const char* path, uint8_t* out, ssize_t* size_out)
|
|
||||||
{
|
|
||||||
std::regex regexLib("^([a-f0-9]{32}|[a-f0-9 ]{47})$", std::regex_constants::egrep);
|
|
||||||
FILE* file = NULL;
|
|
||||||
try {
|
|
||||||
bool bom = ini_detect_bom(path);
|
|
||||||
{
|
|
||||||
// First check for "edid-decode (hex)" string.
|
|
||||||
file = plat_fopen(path, "rb");
|
|
||||||
if (file) {
|
|
||||||
std::string str;
|
|
||||||
ssize_t size;
|
|
||||||
if (!fseek(file, 0, SEEK_END)) {
|
|
||||||
size = ftell(file);
|
|
||||||
if (size != -1) {
|
|
||||||
str.resize(size);
|
|
||||||
}
|
|
||||||
fseek(file, 0, SEEK_SET);
|
|
||||||
auto read = fread((void*)str.data(), 1, size, file);
|
|
||||||
str.resize(read);
|
|
||||||
fclose(file);
|
|
||||||
file = NULL;
|
|
||||||
|
|
||||||
if (str.size() == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (str.find("edid-decode (hex):") == std::string::npos) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file = plat_fopen(path, "rb");
|
|
||||||
if (file) {
|
|
||||||
size_t size = 0;
|
|
||||||
std::string edid_decode_text;
|
|
||||||
fseek(file, 0, SEEK_END);
|
|
||||||
size = ftell(file);
|
|
||||||
fseek(file, 0, SEEK_SET);
|
|
||||||
if (bom) {
|
|
||||||
fseek(file, 3, SEEK_SET);
|
|
||||||
size -= 3;
|
|
||||||
}
|
|
||||||
edid_decode_text.resize(size);
|
|
||||||
auto err = fread((void*)edid_decode_text.data(), size, 1, file);
|
|
||||||
fclose(file);
|
|
||||||
file = NULL;
|
|
||||||
if (err == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
std::istringstream isstream(edid_decode_text);
|
|
||||||
std::string line;
|
|
||||||
std::string edid;
|
|
||||||
while (std::getline(isstream, line)) {
|
|
||||||
if (line[line.size() - 1] == '\r') {
|
|
||||||
line.resize(line.size() - 1);
|
|
||||||
}
|
|
||||||
std::smatch matched;
|
|
||||||
if (std::regex_match(line, matched, regexLib)) {
|
|
||||||
edid.append(matched.str() + " ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (edid.size() >= 3) {
|
|
||||||
edid.resize(edid.size() - 1);
|
|
||||||
auto vals = split(edid, "\\s+");
|
|
||||||
if (vals.size()) {
|
|
||||||
*size_out = vals.size();
|
|
||||||
if (vals.size() > 256)
|
|
||||||
return false;
|
|
||||||
for (size_t i = 0; i < vals.size(); i++) {
|
|
||||||
out[i] = (uint8_t)std::strtoul(&vals[i][0], nullptr, 16);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
} catch (std::bad_alloc&) {
|
|
||||||
if (file) {
|
|
||||||
fclose(file);
|
|
||||||
file = NULL;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -44,6 +44,7 @@ add_library(vid OBJECT
|
|||||||
|
|
||||||
# DDC / monitor identification stuff
|
# DDC / monitor identification stuff
|
||||||
vid_ddc.c
|
vid_ddc.c
|
||||||
|
vid_ddc_custom.c
|
||||||
|
|
||||||
# CARDS start here
|
# CARDS start here
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
*
|
*
|
||||||
* Copyright 2020 RichardG.
|
* Copyright 2020 RichardG.
|
||||||
*/
|
*/
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -130,8 +129,8 @@ typedef struct {
|
|||||||
uint8_t padding[15], checksum2;
|
uint8_t padding[15], checksum2;
|
||||||
} edid_t;
|
} edid_t;
|
||||||
|
|
||||||
void*
|
size_t
|
||||||
ddc_create_default_edid(ssize_t* size_out)
|
ddc_create_default_edid(uint8_t **out)
|
||||||
{
|
{
|
||||||
edid_t *edid = malloc(sizeof(edid_t));
|
edid_t *edid = malloc(sizeof(edid_t));
|
||||||
memset(edid, 0, sizeof(edid_t));
|
memset(edid, 0, sizeof(edid_t));
|
||||||
@@ -226,120 +225,79 @@ ddc_create_default_edid(ssize_t* size_out)
|
|||||||
edid->checksum2 += edid_bytes[c];
|
edid->checksum2 += edid_bytes[c];
|
||||||
edid->checksum2 = 256 - edid->checksum2;
|
edid->checksum2 = 256 - edid->checksum2;
|
||||||
|
|
||||||
if (size_out)
|
if (out) {
|
||||||
*size_out = sizeof(edid_t);
|
*out = edid_bytes;
|
||||||
|
}
|
||||||
return edid;
|
|
||||||
|
return sizeof(edid_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern bool parse_edid_decode_file(const char* path, uint8_t* out, ssize_t* size);
|
void *
|
||||||
|
ddc_init_with_custom_edid(char *edid_path, void *i2c)
|
||||||
|
{
|
||||||
|
uint8_t buffer[384] = { 0 };
|
||||||
|
size_t size = ddc_load_edid(edid_path, buffer, sizeof(buffer));
|
||||||
|
|
||||||
|
if (size > 256) {
|
||||||
|
wchar_t errmsg[2048] = { 0 };
|
||||||
|
wchar_t path[2048] = { 0 };
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
mbstoc16s(path, monitor_edid_path, sizeof_w(path));
|
||||||
|
#else
|
||||||
|
mbstowcs(path, monitor_edid_path, sizeof_w(path));
|
||||||
|
#endif
|
||||||
|
swprintf(errmsg, sizeof_w(errmsg), plat_get_string(STRING_EDID_TOO_LARGE), path);
|
||||||
|
ui_msgbox_header(MBX_ERROR, L"EDID", errmsg);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
} else if (size == 0) {
|
||||||
|
return NULL;
|
||||||
|
} else if (size < 128) {
|
||||||
|
size = 128;
|
||||||
|
} else if (size < 256) {
|
||||||
|
size = 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
int checksum = 0;
|
||||||
|
for (int i = 0; i < 127; i++) {
|
||||||
|
checksum += buffer[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[127] = 256 - checksum;
|
||||||
|
|
||||||
|
if (size == 256) {
|
||||||
|
checksum = 0;
|
||||||
|
|
||||||
|
for (int i = 128; i < 255; i++) {
|
||||||
|
checksum += buffer[i];
|
||||||
|
}
|
||||||
|
buffer[255] = 256 - checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *edid_bytes = malloc(size);
|
||||||
|
memcpy(edid_bytes, buffer, size);
|
||||||
|
|
||||||
|
return i2c_eeprom_init(i2c, 0x50, edid_bytes, size);
|
||||||
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
ddc_init(void *i2c)
|
ddc_init(void *i2c)
|
||||||
{
|
{
|
||||||
ssize_t edid_size = 0;
|
if (monitor_edid && monitor_edid_path[0]) {
|
||||||
uint8_t* edid_bytes = NULL;
|
void *ret = ddc_init_with_custom_edid(monitor_edid_path, i2c);
|
||||||
if (monitor_edid == 1 && monitor_edid_path[0]) {
|
|
||||||
FILE* file;
|
|
||||||
{
|
|
||||||
edid_bytes = calloc(1, 256);
|
|
||||||
if (parse_edid_decode_file(monitor_edid_path, edid_bytes, &edid_size) == false) {
|
|
||||||
if (edid_size > 256) {
|
|
||||||
wchar_t errmsg[2048] = { 0 };
|
|
||||||
wchar_t path[2048] = { 0 };
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
if (ret) {
|
||||||
mbstoc16s(path, monitor_edid_path, sizeof_w(path));
|
return ret;
|
||||||
#else
|
|
||||||
mbstowcs(path, monitor_edid_path, sizeof_w(path));
|
|
||||||
#endif
|
|
||||||
swprintf(errmsg, sizeof_w(errmsg), plat_get_string(STRING_EDID_TOO_LARGE), path);
|
|
||||||
ui_msgbox_header(MBX_ERROR, L"EDID", errmsg);
|
|
||||||
}
|
|
||||||
free(edid_bytes);
|
|
||||||
} else {
|
|
||||||
goto calculate_cksum;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
file = plat_fopen(monitor_edid_path, "rb");
|
|
||||||
|
|
||||||
if (!file)
|
|
||||||
goto default_init;
|
|
||||||
|
|
||||||
if (fseek(file, 0, SEEK_END) == -1) {
|
|
||||||
fclose(file);
|
|
||||||
goto default_init;
|
|
||||||
}
|
|
||||||
|
|
||||||
edid_size = ftell(file);
|
|
||||||
fseek(file, 0, SEEK_SET);
|
|
||||||
|
|
||||||
if (edid_size <= 0) {
|
|
||||||
fclose(file);
|
|
||||||
goto default_init;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (edid_size > 256) {
|
|
||||||
wchar_t errmsg[2048] = { 0 };
|
|
||||||
wchar_t path[2048] = { 0 };
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
mbstoc16s(path, monitor_edid_path, sizeof_w(path));
|
|
||||||
#else
|
|
||||||
mbstowcs(path, monitor_edid_path, sizeof_w(path));
|
|
||||||
#endif
|
|
||||||
swprintf(errmsg, sizeof_w(errmsg), plat_get_string(STRING_EDID_TOO_LARGE), path);
|
|
||||||
ui_msgbox_header(MBX_ERROR, L"EDID", errmsg);
|
|
||||||
fclose(file);
|
|
||||||
goto default_init;
|
|
||||||
}
|
|
||||||
|
|
||||||
edid_bytes = calloc(1, edid_size);
|
|
||||||
if (!edid_bytes) {
|
|
||||||
fclose(file);
|
|
||||||
goto default_init;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fread(edid_bytes, edid_size, 1, file) <= 0) {
|
|
||||||
free(edid_bytes);
|
|
||||||
fclose(file);
|
|
||||||
goto default_init;
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(file);
|
|
||||||
calculate_cksum:
|
|
||||||
if (edid_size < 128) {
|
|
||||||
edid_bytes = realloc(edid_bytes, 128);
|
|
||||||
edid_size = 128;
|
|
||||||
} else if (edid_size < 256) {
|
|
||||||
edid_bytes = realloc(edid_bytes, 256);
|
|
||||||
edid_size = 256;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
int checksum = 0;
|
|
||||||
for (uint8_t c = 0; c < 127; c++)
|
|
||||||
checksum += edid_bytes[c];
|
|
||||||
edid_bytes[127] = 256 - checksum;
|
|
||||||
|
|
||||||
if (edid_size == 256) {
|
|
||||||
checksum = 0;
|
|
||||||
|
|
||||||
for (uint8_t c = 128; c < 255; c++) {
|
|
||||||
checksum += edid_bytes[c];
|
|
||||||
}
|
|
||||||
edid_bytes[255] = 256 - checksum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return i2c_eeprom_init(i2c, 0x50, edid_bytes, edid_size, 0);
|
|
||||||
}
|
}
|
||||||
default_init:
|
|
||||||
edid_size = sizeof(edid_t);
|
uint8_t *edid_bytes;
|
||||||
edid_bytes = ddc_create_default_edid(&edid_size);
|
size_t edid_size = ddc_generate_default_edid(&edid_bytes);
|
||||||
return i2c_eeprom_init(i2c, 0x50, edid_bytes, edid_size, 0);
|
return i2c_eeprom_init(i2c, 0x50, edid_bytes, edid_size, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ddc_close(void *eeprom)
|
ddc_close(void *eeprom)
|
||||||
{
|
{
|
||||||
|
|||||||
110
src/video/vid_ddc_custom.c
Normal file
110
src/video/vid_ddc_custom.c
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define EDID_BLOCK_SIZE 128
|
||||||
|
#define EDID_HEADER 0x00FFFFFFFFFFFF00
|
||||||
|
#define EDID_DECODE_HEADER "edid-decode (hex):"
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
read_block(FILE *fp, uint8_t *buf)
|
||||||
|
{
|
||||||
|
uint8_t temp[64];
|
||||||
|
size_t read = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
if (!fgets(temp, sizeof(temp), fp)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *tok = strtok(temp, " \t\r\n");
|
||||||
|
|
||||||
|
for (int j = 0; j < 16; j++) {
|
||||||
|
if (!tok) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[read++] = strtoul(tok, NULL, 16);
|
||||||
|
tok = strtok(NULL, " \t\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
ddc_load_edid(char *path, uint8_t *buf, size_t size)
|
||||||
|
{
|
||||||
|
FILE *fp = fopen(path, "rb");
|
||||||
|
size_t offset = 0;
|
||||||
|
uint8_t temp[64];
|
||||||
|
|
||||||
|
if (!fp) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the beginning of the file for the EDID header.
|
||||||
|
uint64_t header;
|
||||||
|
fread(&header, sizeof(header), 1, fp);
|
||||||
|
|
||||||
|
if (header == EDID_HEADER) {
|
||||||
|
// Binary format. Read as is
|
||||||
|
fseek(fp, 0, SEEK_SET);
|
||||||
|
offset = fread(buf, 1, size, fp);
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reopen in text mode.
|
||||||
|
fclose(fp);
|
||||||
|
fp = fopen(path, "rt");
|
||||||
|
|
||||||
|
if (!fp) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip the UTF-8 BOM, if any.
|
||||||
|
if (fread(temp, 1, 3, fp) != 3) {
|
||||||
|
fclose(fp);
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (temp[0] != 0xEF || temp[1] != 0xBB || temp[2] != 0xBF) {
|
||||||
|
fseek(fp, -3, SEEK_CUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the `edid-decode (hex):` header
|
||||||
|
do {
|
||||||
|
if (!fgets(temp, sizeof(temp), fp)) {
|
||||||
|
fclose(fp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} while (strncmp(temp, EDID_DECODE_HEADER, sizeof(EDID_DECODE_HEADER) - 1));
|
||||||
|
|
||||||
|
while (offset + EDID_BLOCK_SIZE <= size) {
|
||||||
|
// Skip any whitespace before the next block
|
||||||
|
do {
|
||||||
|
if (!fgets(temp, sizeof(temp), fp)) {
|
||||||
|
fclose(fp);
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
} while (strspn(temp, " \t\r\n") == strlen(temp));
|
||||||
|
|
||||||
|
fseek(fp, -strlen(temp), SEEK_CUR);
|
||||||
|
|
||||||
|
// Read the block
|
||||||
|
size_t block = read_block(fp, buf + offset);
|
||||||
|
|
||||||
|
if (block != EDID_BLOCK_SIZE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += block;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user