diff --git a/deepin-devicemanager/3rdparty/ediddecode/ediddecode.cpp b/deepin-devicemanager/3rdparty/ediddecode/ediddecode.cpp new file mode 100755 index 000000000..79c1c895b --- /dev/null +++ b/deepin-devicemanager/3rdparty/ediddecode/ediddecode.cpp @@ -0,0 +1,1073 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright 2006-2012 Red Hat, Inc. + * Copyright 2018-2020 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * Author: Adam Jackson + * Maintainer: Hans Verkuil + */ +#include "ediddecode.h" + +#include +#include +#include +#include +#include +#include +#include +#include + + +static char *manufacturer_name(const unsigned char *x) +{ + static char name[4]; + + name[0] = ((x[0] & 0x7c) >> 2) + '@'; + name[1] = ((x[0] & 0x03) << 3) + ((x[1] & 0xe0) >> 5) + '@'; + name[2] = (x[1] & 0x1f) + '@'; + name[3] = 0; + + if (!isupper(name[0]) || !isupper(name[1]) || !isupper(name[2])) + fail("Manufacturer name field contains garbage.\n"); + + return name; +} + +/* extract a string from a detailed subblock, checking for termination */ +char *extract_string(const unsigned char *x, unsigned len) +{ + static char s[EDID_PAGE_SIZE]; + bool seen_newline = false; + unsigned i; + + memset(s, 0, sizeof(s)); + + for (i = 0; i < len; i++) { + if (seen_newline) { + if (x[i] != 0x20) { + fail("Non-space after newline.\n"); + return s; + } + } else if (isgraph(x[i]) || x[i] == 0x20) { + s[i] = x[i]; + } else if (x[i] == 0x0a) { + seen_newline = true; + if (!i) + fail("Empty string.\n"); + else if (s[i - 1] == 0x20) + fail("One or more trailing spaces.\n"); + } else { + fail("Non-printable character.\n"); + return s; + } + } + /* Does the string end with a space? */ + if (!seen_newline && s[len - 1] == 0x20) + fail("One or more trailing spaces.\n"); + + return s; +} + + +void edid_state::detailed_block(const unsigned char *x,QString &str) +{ + static const unsigned char zero_descr[18] = { 0 }; + unsigned cnt; + unsigned i; + + base.detailed_block_cnt++; + if (x[0] || x[1]) { + // detailed_timings(" ", x); + return; + } + + data_block = "Display Descriptor #" + std::to_string(base.detailed_block_cnt); + /* Monitor descriptor block, not detailed timing descriptor. */ + if (x[2] != 0) { + /* 1.3, 3.10.3 */ + fail("Monitor descriptor block has byte 2 nonzero (0x%02x).\n", x[2]); + } + if ((base.edid_minor < 4 || x[3] != 0xfd) && x[4] != 0x00) { + /* 1.3, 3.10.3 */ + fail("Monitor descriptor block has byte 4 nonzero (0x%02x).\n", x[4]); + } + + base.seen_non_detailed_descriptor = true; + if (base.edid_minor == 0) + fail("Has descriptor blocks other than detailed timings.\n"); + + if (!memcmp(x, zero_descr, sizeof(zero_descr))) { + // data_block = "Empty Descriptor"; + return; + } + + switch (x[3]) { + case 0x0e: + // detailed_epi(x); + return; + case 0x10: + + return; + case 0xf7: + + return; + case 0xf8: + // data_block = "CVT 3 Byte Timing Codes"; + return; + case 0xf9: + // data_block = "Display Color Management Data"; + return; + case 0xfa: + // data_block = "Standard Timing Identifications"; + return; + case 0xfb: { + + // data_block = "Color Point Data"; + return; + } + case 0xfc: + data_block = "Display Product Name"; + base.has_name_descriptor = 1; + printf(" %s: '%s'\n", data_block.c_str(), extract_string(x + 5, 13)); + return; + case 0xfd: + // detailed_display_range_limits(x); + return; + case 0xfe: + if (!base.has_spwg || base.detailed_block_cnt < 3) { + data_block = "Alphanumeric Data String"; + str = QString(extract_string(x + 5, 13)); + printf(" %s: '%s'\n", data_block.c_str(), extract_string(x + 5, 13)); + return; + } + // data_block = "SPWG Descriptor #3"; + + return; + case 0xff: { + // data_block = "Display Product Serial Number"; + return; + } + default: + printf(" %s Display Descriptor (0x%02hhx):", + x[3] <= 0x0f ? "Manufacturer-Specified" : "Unknown", x[3]); + // hex_block(" ", x + 2, 16); + if (x[3] > 0x0f) + fail("Unknown Type 0x%02hhx.\n", x[3]); + return; + } +} + +/* + * The sRGB chromaticities are (x, y): + * red: 0.640, 0.330 + * green: 0.300, 0.600 + * blue: 0.150, 0.060 + * white: 0.3127, 0.3290 + */ +static const unsigned char srgb_chromaticity[10] = { + 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54 +}; + + + +void edid_state::parse_base_block(const unsigned char *x,QString &str) +{ + time_t the_time; + struct tm *ptm; + int analog; + unsigned col_x, col_y; + bool has_preferred_timing = false; + + data_block = "EDID Structure Version & Revision"; + printf(" %s: %hhu.%hhu\n", data_block.c_str(), x[0x12], x[0x13]); + if (x[0x12] == 1) { + base.edid_minor = x[0x13]; + if (base.edid_minor > 4) + warn("Unknown EDID minor version %u, assuming 1.4 conformance.\n", base.edid_minor); + if (base.edid_minor < 3) + warn("EDID 1.%u is deprecated, do not use.\n", base.edid_minor); + } else { + fail("Unknown EDID major version.\n"); + } + + base.serial_number = x[0x0c] + (x[0x0d] << 8) + (x[0x0e] << 16) + (x[0x0f] << 24); + + + data_block = "Vendor & Product Identification"; + printf(" %s:\n", data_block.c_str()); + printf(" Manufacturer: %s\n Model: %x\n", manufacturer_name(x + 0x08), (x[0x0a] + (x[0x0b] << 8))); + if (base.serial_number) { + unsigned sn = base.serial_number; + printf(" Serial Number: %u (0x%08x)\n", sn, sn); + + // This is a list of known dummy values that are often used in EDIDs: + switch (sn) { + case 1: + case 0x01010101: + case 1010101: + case 0x5445: + case 0x80000000: + case 20000080: + case 8888: + case 6666: + warn("The serial number is one of the known dummy values, it should probably be set to 0.\n"); + break; + } + } + + time(&the_time); + ptm = localtime(&the_time); + + base.week = x[0x10]; + base.year = x[0x11]; + unsigned char week = base.week; + int year = 1990 + base.year; + + if (week) { + if (base.edid_minor <= 3 && week == 0xff) + fail("EDID 1.3 does not support week 0xff.\n"); + // The max week is 53 in EDID 1.3 and 54 in EDID 1.4. + // No idea why there is a difference. + if (base.edid_minor <= 3 && week == 54) + fail("EDID 1.3 does not support week 54.\n"); + if (week != 0xff && week > 54) + fail("Invalid week of manufacture (> 54).\n"); + } + if (year - 1 > ptm->tm_year + 1900) + fail("The year is more than one year in the future.\n"); + + if (week == 0xff) + printf(" Model year: %d\n", year); + else if (replace_unique_ids) + printf(" Made in: 2000\n"); + else if (week) + printf(" Made in: week %hhu of %d\n", week, year); + else + printf(" Made in: %d\n", year); + + /* display section */ + + // data_block = "Basic Display Parameters & Features"; + // printf(" %s:\n", data_block.c_str()); + // if (x[0x14] & 0x80) { + // analog = 0; + // printf(" Digital display\n"); + // if (base.edid_minor >= 4) { + // if ((x[0x14] & 0x70) == 0x00) + // printf(" Color depth is undefined\n"); + // else if ((x[0x14] & 0x70) == 0x70) + // fail("Color Bit Depth set to reserved value.\n"); + // else + // printf(" Bits per primary color channel: %u\n", + // ((x[0x14] & 0x70) >> 3) + 4); + + // printf(" "); + // switch (x[0x14] & 0x0f) { + // case 0x00: printf("Digital interface is not defined\n"); break; + // case 0x01: printf("DVI interface\n"); break; + // case 0x02: printf("HDMI-a interface\n"); break; + // case 0x03: printf("HDMI-b interface\n"); break; + // case 0x04: printf("MDDI interface\n"); break; + // case 0x05: printf("DisplayPort interface\n"); break; + // default: + // printf("Unknown interface: 0x%02x\n", x[0x14] & 0x0f); + // fail("Digital Video Interface Standard set to reserved value 0x%02x.\n", x[0x14] & 0x0f); + // break; + // } + // } else if (base.edid_minor >= 2) { + // if (x[0x14] & 0x01) { + // printf(" DFP 1.x compatible TMDS\n"); + // } + // if (x[0x14] & 0x7e) + // fail("Digital Video Interface Standard set to reserved value 0x%02x.\n", x[0x14] & 0x7e); + // } else if (x[0x14] & 0x7f) { + // fail("Digital Video Interface Standard set to reserved value 0x%02x.\n", x[0x14] & 0x7f); + // } + // } else { + // static const char * const voltages[] = { + // "0.700 : 0.300 : 1.000 V p-p", + // "0.714 : 0.286 : 1.000 V p-p", + // "1.000 : 0.400 : 1.400 V p-p", + // "0.700 : 0.000 : 0.700 V p-p" + // }; + // unsigned voltage = (x[0x14] & 0x60) >> 5; + // unsigned sync = (x[0x14] & 0x0f); + + // analog = 1; + // printf(" Analog display\n"); + // printf(" Signal Level Standard: %s\n", voltages[voltage]); + + // if (x[0x14] & 0x10) + // printf(" Blank-to-black setup/pedestal\n"); + // else + // printf(" Blank level equals black level\n"); + + // if (sync) + // printf(" Sync:%s%s%s%s\n", + // sync & 0x08 ? " Separate" : "", + // sync & 0x04 ? " Composite" : "", + // sync & 0x02 ? " SyncOnGreen" : "", + // sync & 0x01 ? " Serration" : ""); + // } + + if (x[0x15] && x[0x16]) { + printf(" Maximum image size: %u cm x %u cm\n", x[0x15], x[0x16]); + base.max_display_width_mm = x[0x15] * 10; + base.max_display_height_mm = x[0x16] * 10; + image_width = base.max_display_width_mm * 10; + image_height = base.max_display_height_mm * 10; + if (x[0x15] < 10 || x[0x16] < 10) + warn("Dubious maximum image size (%ux%u is smaller than 10x10 cm).\n", + x[0x15], x[0x16]); + } + // else if (base.edid_minor >= 4 && (x[0x15] || x[0x16])) { + // if (x[0x15]) + // printf(" Aspect ratio: %.2f (landscape)\n", (x[0x15] + 99) / 100.0); + // else + // printf(" Aspect ratio: %.2f (portrait)\n", 100.0 / (x[0x16] + 99)); + // } else { + // /* Either or both can be zero for 1.3 and before */ + // printf(" Image size is variable\n"); + // } + + // if (x[0x17] == 0xff) + // printf(" Gamma is defined in an extension block\n"); + // else + // printf(" Gamma: %.2f\n", (x[0x17] + 100.0) / 100.0); + + // if (x[0x18] & 0xe0) { + // printf(" DPMS levels:"); + // if (x[0x18] & 0x80) printf(" Standby"); + // if (x[0x18] & 0x40) printf(" Suspend"); + // if (x[0x18] & 0x20) printf(" Off"); + // printf("\n"); + // } + + // if (analog || base.edid_minor < 4) { + // printf(" "); + // switch (x[0x18] & 0x18) { + // case 0x00: printf("Monochrome or grayscale display\n"); break; + // case 0x08: printf("RGB color display\n"); break; + // case 0x10: printf("Non-RGB color display\n"); break; + // case 0x18: printf("Undefined display color type\n"); break; + // } + // } else { + // printf(" Supported color formats: RGB 4:4:4"); + // if (x[0x18] & 0x08) + // printf(", YCrCb 4:4:4"); + // if (x[0x18] & 0x10) + // printf(", YCrCb 4:2:2"); + // printf("\n"); + // } + + // if (x[0x18] & 0x04) { + // printf(" Default (sRGB) color space is primary color space\n"); + // if (memcmp(x + 0x19, srgb_chromaticity, sizeof(srgb_chromaticity))) + // fail("sRGB is signaled, but the chromaticities do not match.\n"); + // if (x[0x17] != 120) + // warn("sRGB is signaled, but the gamma != 2.2.\n"); + // base.uses_srgb = true; + // } else if (!memcmp(x + 0x19, srgb_chromaticity, sizeof(srgb_chromaticity))) { + // fail("The chromaticities match sRGB, but sRGB is not signaled.\n"); + // base.uses_srgb = true; + // } + + // if (base.edid_minor >= 4) { + // /* 1.4 always has a preferred timing and this bit means something else. */ + // has_preferred_timing = true; + // base.preferred_is_also_native = x[0x18] & 0x02; + // printf(" First detailed timing %s the native pixel format and preferred refresh rate\n", + // base.preferred_is_also_native ? "includes" : "does not include"); + // } else { + // if (x[0x18] & 0x02) { + // printf(" First detailed timing is the preferred timing\n"); + // has_preferred_timing = true; + // // 1.3 recommends that the preferred timing corresponds to the + // // native timing, but it is not a requirement. + // // That said, we continue with the assumption that it actually + // // is the native timing. + // base.preferred_is_also_native = true; + // } else if (base.edid_minor == 3) { + // fail("EDID 1.3 requires that the first detailed timing is the preferred timing.\n"); + // } + // } + + if (x[0x18] & 0x01) { + if (base.edid_minor >= 4) { + base.supports_continuous_freq = true; + printf(" Display supports continuous frequencies\n"); + } else { + printf(" Supports GTF timings within operating range\n"); + base.supports_gtf = true; + } + } + + // data_block = "Color Characteristics"; + // printf(" %s:\n", data_block.c_str()); + // col_x = (x[0x1b] << 2) | (x[0x19] >> 6); + // col_y = (x[0x1c] << 2) | ((x[0x19] >> 4) & 3); + // printf(" Red : 0.%04u, 0.%04u\n", + // (col_x * 10000) / 1024, (col_y * 10000) / 1024); + // col_x = (x[0x1d] << 2) | ((x[0x19] >> 2) & 3); + // col_y = (x[0x1e] << 2) | (x[0x19] & 3); + // printf(" Green: 0.%04u, 0.%04u\n", + // (col_x * 10000) / 1024, (col_y * 10000) / 1024); + // col_x = (x[0x1f] << 2) | (x[0x1a] >> 6); + // col_y = (x[0x20] << 2) | ((x[0x1a] >> 4) & 3); + // printf(" Blue : 0.%04u, 0.%04u\n", + // (col_x * 10000) / 1024, (col_y * 10000) / 1024); + // col_x = (x[0x21] << 2) | ((x[0x1a] >> 2) & 3); + // col_y = (x[0x22] << 2) | (x[0x1a] & 3); + // printf(" White: 0.%04u, 0.%04u\n", + // (col_x * 10000) / 1024, (col_y * 10000) / 1024); + + // data_block = "Established Timings I & II"; + // if (x[0x23] || x[0x24] || x[0x25]) { + // printf(" %s:\n", data_block.c_str()); + // for (unsigned i = 0; i < ARRAY_SIZE(established_timings12); i++) { + // if (x[0x23 + i / 8] & (1 << (7 - i % 8))) { + // unsigned char dmt_id = established_timings12[i].dmt_id; + // const struct timings *t; + // char type[16]; + + // if (dmt_id) { + // sprintf(type, "DMT 0x%02x", dmt_id); + // // t = find_dmt_id(dmt_id); + // } else { + // t = &established_timings12[i].t; + // sprintf(type, "%-8s", established_timings12[i].type); + // } + // } + // } + // } else { + // printf(" %s: none\n", data_block.c_str()); + // } + base.has_640x480p60_est_timing = x[0x23] & 0x20; + + // data_block = "Standard Timings"; + // bool found = false; + // for (unsigned i = 0; i < 8; i++) { + // if (x[0x26 + i * 2] != 0x01 || x[0x26 + i * 2 + 1] != 0x01) { + // found = true; + // break; + // } + // } + // if (found) { + // printf(" %s:\n", data_block.c_str()); + // for (unsigned i = 0; i < 8; i++) + // print_standard_timing(" ", x[0x26 + i * 2], x[0x26 + i * 2 + 1]); + // } else { + // printf(" %s: none\n", data_block.c_str()); + // } + + // /* 18 byte descriptors */ + // if (has_preferred_timing && !x[0x36] && !x[0x37]) + // fail("Missing preferred timing.\n"); + + // /* Look for SPWG Noteboook Panel EDID data blocks */ + // if ((x[0x36] || x[0x37]) && + // (x[0x48] || x[0x49]) && + // !x[0x5a] && !x[0x5b] && x[0x5d] == 0xfe && + // !x[0x6c] && !x[0x6d] && x[0x6f] == 0xfe && + // (x[0x79] == 1 || x[0x79] == 2) && x[0x7a] <= 1) + // base.has_spwg = true; + + // for (unsigned i = 0; i < (base.has_spwg ? 2 : 4); i++) + // if (x[0x36 + i * 18] || x[0x37 + i * 18]) + // cta.preparsed_total_dtds++; + + data_block = "Detailed Timing Descriptors"; + printf(" %s:\n", data_block.c_str()); + detailed_block(x + 0x36,str); + detailed_block(x + 0x48,str); + detailed_block(x + 0x5a,str); + detailed_block(x + 0x6c,str); + // base.has_spwg = false; + // if (!base.preferred_is_also_native) { + // cta.native_timings.clear(); + // base.preferred_timing = timings_ext(); + // } + + data_block = block; + // if (x[0x7e]) + // printf(" Extension blocks: %u\n", x[0x7e]); + + block = block_name(0x00); + data_block.clear(); + // do_checksum("", x, EDID_PAGE_SIZE); + // if (base.edid_minor >= 3) { + // if (!base.has_name_descriptor) + // msg(base.edid_minor >= 4, "Missing Display Product Name.\n"); + // if ((base.edid_minor == 3 || base.supports_continuous_freq) && + // !base.has_display_range_descriptor) + // fail("Missing Display Range Limits Descriptor.\n"); + // } +} + + +//------------------------- + +#define STR(x) #x +#define STRING(x) STR(x) + +static edid_state state; + +static unsigned char edid[EDID_PAGE_SIZE * EDID_MAX_BLOCKS]; +static bool odd_hex_digits; + +enum output_format { + OUT_FMT_DEFAULT, + OUT_FMT_HEX, + OUT_FMT_RAW, + OUT_FMT_CARRAY, + OUT_FMT_XML, +}; + + + + +static std::string s_msgs[EDID_MAX_BLOCKS + 1][2]; + +void msg(bool is_warn, const char *fmt, ...) +{ + char buf[1024] = ""; + va_list ap; + + va_start(ap, fmt); + vsprintf(buf, fmt, ap); + va_end(ap); + + if (is_warn) + state.warnings++; + else + state.failures++; + if (state.data_block.empty()) + s_msgs[state.block_nr][is_warn] += std::string(" ") + buf; + else + s_msgs[state.block_nr][is_warn] += " " + state.data_block + ": " + buf; + + // if (options[OptCheckInline]) + printf("%s: %s", is_warn ? "WARN" : "FAIL", buf); +} + +// static void show_msgs(bool is_warn) +// { +// printf("\n%s:\n\n", is_warn ? "Warnings" : "Failures"); +// for (unsigned i = 0; i < state.num_blocks; i++) { +// if (s_msgs[i][is_warn].empty()) +// continue; +// printf("Block %u, %s:\n%s", +// i, block_name(edid[i * EDID_PAGE_SIZE]).c_str(), +// s_msgs[i][is_warn].c_str()); +// } +// if (s_msgs[EDID_MAX_BLOCKS][is_warn].empty()) +// return; +// printf("EDID:\n%s", +// s_msgs[EDID_MAX_BLOCKS][is_warn].c_str()); +// } + + +// void replace_checksum(unsigned char *x, size_t len) +// { +// unsigned char sum = 0; +// unsigned i; + +// for (i = 0; i < len - 1; i++) +// sum += x[i]; +// x[len - 1] = -sum & 0xff; +// } + +void do_checksum(const char *prefix, const unsigned char *x, size_t len, unsigned unused_bytes) +{ + unsigned char check = x[len - 1]; + unsigned char sum = 0; + unsigned i; + + for (i = 0; i < len - 1; i++) + sum += x[i]; + + printf("%sChecksum: 0x%02hhx", prefix, check); + if ((unsigned char)(check + sum) != 0) { + printf(" (should be 0x%02x)", -sum & 0xff); + fail("Invalid checksum 0x%02x (should be 0x%02x).\n", + check, -sum & 0xff); + } + if (unused_bytes) + printf(" Unused space in Extension Block: %u byte%s", + unused_bytes, unused_bytes > 1 ? "s" : ""); + printf("\n"); +} + +unsigned gcd(unsigned a, unsigned b) +{ + while (b) { + unsigned t = b; + + b = a % b; + a = t; + } + return a; +} + +void calc_ratio(struct timings *t) +{ + unsigned d = gcd(t->hact, t->vact); + + if (d == 0) { + t->hratio = t->vratio = 0; + return; + } + t->hratio = t->hact / d; + t->vratio = t->vact / d; + + if (t->hratio == 8 && t->vratio == 5) { + t->hratio = 16; + t->vratio = 10; + } +} + +std::string edid_state::dtd_type(unsigned cnt) +{ + unsigned len = std::to_string(cta.preparsed_total_dtds).length(); + char buf[16]; + sprintf(buf, "DTD %*u", len, cnt); + return buf; +} + + +static void or_str(std::string &s, const std::string &flag, unsigned &num_flags) +{ + if (!num_flags) + s = flag; + else if (num_flags % 2 == 0) + s = s + " | \\\n\t\t" + flag; + else + s = s + " | " + flag; + num_flags++; +} + + + +std::string utohex(unsigned char x) +{ + char buf[10]; + + sprintf(buf, "0x%02hhx", x); + return buf; +} + +std::string ouitohex(unsigned oui) +{ + char buf[32]; + + sprintf(buf, "%02X-%02X-%02X", (oui >> 16) & 0xff, (oui >> 8) & 0xff, oui & 0xff); + return buf; +} + +bool memchk(const unsigned char *x, unsigned len, unsigned char v) +{ + for (unsigned i = 0; i < len; i++) + if (x[i] != v) + return false; + return true; +} + +static bool edid_add_byte(const char *s, bool two_digits = true) +{ + char buf[3]; + + if (state.edid_size == sizeof(edid)) + return false; + buf[0] = s[0]; + buf[1] = two_digits ? s[1] : 0; + buf[2] = 0; + edid[state.edid_size++] = strtoul(buf, NULL, 16); + return true; +} + +static bool extract_edid_quantumdata(const char *start) +{ + /* Parse QuantumData 980 EDID files */ + do { + start = strstr(start, ">"); + if (!start) + return false; + start++; + for (unsigned i = 0; start[i] && start[i + 1] && i < 256; i += 2) + if (!edid_add_byte(start + i)) + return false; + start = strstr(start, " strstr(start, half_indentation1)) + break; + + /* If we failed, retry assuming tabs for indentation */ + if (!s) { + s = strstr(start, indentation = indentation2); + /* Did we skip the start of another property? */ + if (s && s > strstr(start, half_indentation2)) + break; + } + + if (!s) + break; + + start = s + strlen(indentation); + + for (j = 0; j < 16; j++, start += 2) { + /* Read a %02x from the log */ + if (!isxdigit(start[0]) || !isxdigit(start[1])) { + if (j) + break; + return false; + } + if (!edid_add_byte(start)) + return false; + } + } + return state.edid_size; +} + +static bool extract_edid_xorg(const char *start) +{ + bool find_first_num = true; + + for (; *start; start++) { + if (find_first_num) { + const char *s; + + /* skip ahead to the : */ + s = strstr(start, ": \t"); + if (!s) + s = strstr(start, ": "); + if (!s) + break; + start = s; + /* and find the first number */ + while (!isxdigit(start[1])) + start++; + find_first_num = false; + continue; + } else { + /* Read a %02x from the log */ + if (!isxdigit(*start)) { + find_first_num = true; + continue; + } + if (!edid_add_byte(start)) + return false; + start++; + } + } + return state.edid_size; +} + +static bool extract_edid(int fd, FILE *errorr) +{ + std::vector edid_data; + char buf[EDID_PAGE_SIZE]; + + for (;;) { + ssize_t i = read(fd, buf, sizeof(buf)); + + if (i < 0) + return false; + if (i == 0) + break; + edid_data.insert(edid_data.end(), buf, buf + i); + } + + if (edid_data.empty()) { + state.edid_size = 0; + return false; + } + // Ensure it is safely terminated by a 0 char + edid_data.push_back('\0'); + + const char *data = &edid_data[0]; + const char *start; + + /* Look for edid-decode output */ + start = strstr(data, "EDID (hex):"); + if (!start) + start = strstr(data, "edid-decode (hex):"); + if (start) + return extract_edid_hex(strchr(start, ':')); + + /* Look for C-array */ + start = strstr(data, "unsigned char edid[] = {"); + if (start) + return extract_edid_hex(strchr(start, '{') + 1, false); + + /* Look for QuantumData EDID output */ + start = strstr(data, " sizeof(edid)) { +// fprintf(error, "Binary EDID length %zu is greater than %zu.\n", +// edid_data.size(), sizeof(edid)); + return false; + } + memcpy(edid, data, edid_data.size()); + state.edid_size = edid_data.size(); + return true; +} + +static int edid_from_file(const char *from_file, FILE *error) +{ + int flags = O_RDONLY; + + int fd; + + if (!strcmp(from_file, "-")) { + from_file = "stdin"; + fd = 0; + } else if ((fd = open(from_file, flags)) == -1) { + perror(from_file); + return -1; + } + + odd_hex_digits = false; + if (!extract_edid(fd, error)) { + if (!state.edid_size) { + fprintf(error, "EDID of '%s' was empty.\n", from_file); + return -1; + } + fprintf(error, "EDID extract of '%s' failed: ", from_file); + if (odd_hex_digits) + fprintf(error, "odd number of hexadecimal digits.\n"); + else + fprintf(error, "unknown format.\n"); + return -1; + } + if (state.edid_size % EDID_PAGE_SIZE) { + fprintf(error, "EDID length %u is not a multiple of %u.\n", + state.edid_size, EDID_PAGE_SIZE); + return -1; + } + state.num_blocks = state.edid_size / EDID_PAGE_SIZE; + if (fd != 0) + close(fd); + + if (memcmp(edid, "\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00", 8)) { + fprintf(error, "No EDID header found in '%s'.\n", from_file); + return -1; + } + return 0; +} + +int edid_decode_alphanumeric_data_string(const char *from_file, QString &str) +{ + int ret = edid_from_file(from_file, stdout); + if (ret) { + return ret; + } + return state.parse_edid(str); +} + +/* generic extension code */ + +std::string block_name(unsigned char block) +{ + char buf[10]; + + switch (block) { + case 0x00: return "Base EDID"; + case 0x02: return "CTA-861 Extension Block"; + case 0x10: return "Video Timing Extension Block"; + case 0x20: return "EDID 2.0 Extension Block"; + case 0x40: return "Display Information Extension Block"; + case 0x50: return "Localized String Extension Block"; + case 0x60: return "Microdisplay Interface Extension Block"; + case 0x70: return "DisplayID Extension Block"; + case 0xf0: return "Block Map Extension Block"; + case 0xff: return "Manufacturer-Specific Extension Block"; + default: + sprintf(buf, " 0x%02x", block); + return std::string("Unknown EDID Extension Block") + buf; + } +} + + + + +int edid_state::parse_edid(QString &str) +{ + + block = block_name(0x00); +// printf("Block %u, %s:\n", block_nr, block.c_str()); + parse_base_block(edid,str); + + // for (unsigned i = 1; i < num_blocks; i++) { + // block_nr++; + // printf("\n----------------\n"); + // parse_extension(edid + i * EDID_PAGE_SIZE); + // } + + // block = ""; + // block_nr = EDID_MAX_BLOCKS; + + // if (cta.has_svrs) + // cta_resolve_svrs(); + + // if (options[OptPreferredTimings]) + // print_preferred_timings(); + + // print_native_res(); + + + + // check_base_block(edid); + // if (has_cta) + // check_cta_blocks(); + // if (has_dispid) + // check_displayid_blocks(); + + printf("\n----------------\n"); + + +// printf("\nEDID conformity: %s\n", failures ? "FAIL" : "PASS"); + return failures ? -2 : 0; +} + +#ifndef __EMSCRIPTEN__ + +static unsigned char crc_calc(const unsigned char *b) +{ + unsigned char sum = 0; + unsigned i; + + for (i = 0; i < 127; i++) + sum += b[i]; + return 256 - sum; +} + +static int crc_ok(const unsigned char *b) +{ + return crc_calc(b) == b[127]; +} + +static void hexdumpedid(FILE *f, const unsigned char *edid, unsigned size) +{ + unsigned b, i, j; + + for (b = 0; b < size / 128; b++) { + const unsigned char *buf = edid + 128 * b; + + if (b) + fprintf(f, "\n"); + for (i = 0; i < 128; i += 0x10) { + fprintf(f, "%02x", buf[i]); + for (j = 1; j < 0x10; j++) { + fprintf(f, " %02x", buf[i + j]); + } + fprintf(f, "\n"); + } + if (!crc_ok(buf)) + fprintf(f, "Block %u has a checksum error (should be 0x%02x).\n", + b, crc_calc(buf)); + } +} + + + +static int edid_to_file(const char *to_file) +{ + FILE *out; + + // if (!strcmp(to_file, "-")) { + // to_file = "stdout"; + // out = stdout; + // } else + if ((out = fopen(to_file, "w")) == NULL) { + perror(to_file); + return -1; + } + hexdumpedid(out, edid, state.edid_size); + + fclose(out); + return 0; +} + +#else + + +#endif diff --git a/deepin-devicemanager/3rdparty/ediddecode/ediddecode.h b/deepin-devicemanager/3rdparty/ediddecode/ediddecode.h new file mode 100755 index 000000000..332153012 --- /dev/null +++ b/deepin-devicemanager/3rdparty/ediddecode/ediddecode.h @@ -0,0 +1,552 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright 2006-2012 Red Hat, Inc. + * Copyright 2018-2020 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * Author: Adam Jackson + * Maintainer: Hans Verkuil + */ + +#ifndef __EDID_DECODE_H_ +#define __EDID_DECODE_H_ + +#include +#include +#include +#include +#include + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define max(a, b) ((a) > (b) ? (a) : (b)) + +#define EDID_PAGE_SIZE 128U +#define EDID_MAX_BLOCKS 256U + +#define RB_ALT (1U << 7) + +#define RB_NONE (0U) +#define RB_CVT_V1 (1U) +#define RB_CVT_V2 (2U) +#define RB_CVT_V3 (3U) +#define RB_GTF (4U) + +// Video Timings +// If interlaced is true, then the vertical blanking +// for each field is (vfp + vsync + vbp + 0.5), except for +// the VIC 39 timings that doesn't have the 0.5 constant. +// +// The sequence of the various video parameters is as follows: +// +// border - front porch - sync - back porch - border - active video +// +// Note: this is slightly different from EDID 1.4 which calls +// 'active video' as 'addressable video' and the EDID 1.4 term +// 'active video' includes the borders. +// +// But since borders are rarely used, the term 'active video' will +// typically be the same as 'addressable video', and that's how I +// use it. +struct timings { + // Active horizontal and vertical frame height, excluding any + // borders, if present. + // Note: for interlaced formats the active field height is vact / 2 + unsigned hact, vact; + unsigned hratio, vratio; + unsigned pixclk_khz; + // 0: no reduced blanking + // 1: CVT reduced blanking version 1 + // 2: CVT reduced blanking version 2 + // 2 | RB_ALT: CVT reduced blanking version 2 video-optimized (1000/1001 fps) + // 3: CVT reduced blanking version 3 + // 3 | RB_ALT: v3 with a horizontal blank of 160 + // 4: GTF Secondary Curve + unsigned rb; + bool interlaced; + // The horizontal frontporch may be negative in GTF calculations, + // so use int instead of unsigned for hfp. Example: 292x176@76. + int hfp; + unsigned hsync; + // The backporch may be negative in buggy detailed timings. + // So use int instead of unsigned for hbp and vbp. + int hbp; + bool pos_pol_hsync; + // For interlaced formats the vertical front porch of the Even Field + // is actually a half-line longer. + unsigned vfp, vsync; + // For interlaced formats the vertical back porch of the Odd Field + // is actually a half-line longer. + int vbp; + bool pos_pol_vsync; + unsigned hborder, vborder; + bool even_vtotal; // special for VIC 39 + bool no_pol_vsync; // digital composite signals have no vsync polarity + unsigned hsize_mm, vsize_mm; + bool ycbcr420; // YCbCr 4:2:0 encoding +}; + +struct timings_ext { + timings_ext() + { + memset(&t, 0, sizeof(t)); + } + timings_ext(unsigned svr, const std::string &_type) + { + memset(&t, 0, sizeof(t)); + t.hact = svr; + type = _type; + } + timings_ext(const timings &_t, const std::string &_type, const std::string &_flags) + { + t = _t; + type = _type; + flags = _flags; + } + + bool is_valid() const { return t.hact; } + bool has_svr() const { return t.hact && !t.vact; } + unsigned svr() const { return t.hact; } + timings t; + std::string type; + std::string flags; +}; + +enum gtf_ip_parm { + gtf_ip_vert_freq = 1, + gtf_ip_hor_freq, + gtf_ip_clk_freq, +}; + +typedef std::vector vec_timings_ext; + +struct cta_rid { + unsigned hact, vact; + unsigned hratio, vratio; +}; + +struct cta_vfd { + unsigned char rid; + unsigned char fr_factor; + unsigned int bfr50:1; + unsigned int fr24:1; + unsigned int bfr60:1; + unsigned int fr144:1; + unsigned int fr48:1; +}; + +struct edid_state { + edid_state() + { + // Global state + edid_size = num_blocks = block_nr = 0; + max_hor_freq_hz = max_vert_freq_hz = max_pixclk_khz = 0; + min_hor_freq_hz = 0xffffff; + min_vert_freq_hz = 0xffffffff; + dtd_max_vsize_mm = dtd_max_hsize_mm = 0; + warnings = failures = 0; + has_cta = has_dispid = false; + hide_serial_numbers = false; + replace_unique_ids = false; + image_width = image_height = diagonal = 0; + serial_string_cnt = 0; + serial_strings.clear(); + + // Base block state + base.edid_minor = 0; + base.has_name_descriptor = base.has_display_range_descriptor = + base.supports_continuous_freq = base.supports_gtf = + base.supports_cvt = base.seen_non_detailed_descriptor = + base.has_640x480p60_est_timing = base.has_spwg = + base.preferred_is_also_native = false; + base.serial_number = 0; + base.week = base.year = 0; + base.supports_sec_gtf = false; + base.sec_gtf_start_freq = 0; + base.C = base.M = base.K = base.J = 0; + base.max_pos_neg_hor_freq_khz = 0; + base.uses_srgb = false; + base.detailed_block_cnt = base.dtd_cnt = 0; + + base.min_display_hor_freq_hz = base.max_display_hor_freq_hz = + base.min_display_vert_freq_hz = base.max_display_vert_freq_hz = + base.max_display_pixclk_khz = base.max_display_width_mm = + base.max_display_height_mm = 0; + + // CTA-861 block state + cta.has_vic_1 = cta.first_svd_might_be_preferred = cta.has_sldb = + cta.has_hdmi = cta.has_vcdb = cta.has_vfpdb = cta.has_cdb = + cta.has_nvrdb = false; + cta.previous_cta_tag = 0xfff; + cta.have_hf_vsdb = cta.have_hf_scdb = false; + cta.hdmi_max_rate = 0; + cta.hf_eeodb_blocks = 0; + cta.image_width = cta.image_height = 0; + cta.block_number = 0; + cta.has_svrs = false; + cta.first_svd = true; + cta.supported_hdmi_vic_codes = cta.supported_hdmi_vic_vsb_codes = 0; + memset(cta.vics, 0, sizeof(cta.vics)); + memset(cta.preparsed_has_vic, 0, sizeof(cta.preparsed_has_vic)); + memset(&cta.preparsed_first_vfd, 0, sizeof(cta.preparsed_first_vfd)); + cta.preparsed_phys_addr = 0xffff; + cta.preparsed_speaker_count = 0; + cta.preparsed_sld = false; + cta.preparsed_sld_has_coord = false; + cta.preparsed_total_dtds = 0; + cta.preparsed_total_vtdbs = 0; + cta.preparsed_has_t8vtdb = false; + cta.preparsed_t8vtdb_dmt = 0; + cta.preparsed_max_vic_pixclk_khz = 0; + cta.warn_about_hdmi_2x_dtd = false; + + // DisplayID block state + dispid.version = 0; + dispid.native_width = dispid.native_height = 0; + dispid.preparsed_color_ids = dispid.preparsed_xfer_ids = 0; + dispid.preparsed_displayid_blocks = 0; + dispid.is_base_block = true; + dispid.is_display = dispid.has_product_identification = + dispid.has_display_parameters = dispid.has_type_1_7 = + dispid.has_display_interface_features = false; + dispid.block_number = 0; + dispid.image_width = dispid.image_height = 0; + + // Block Map block state + block_map.saw_block_1 = false; + block_map.saw_block_128 = false; + } + + // Global state + unsigned edid_size; + unsigned num_blocks; + unsigned block_nr; + std::string block; + std::string data_block; + unsigned unused_bytes; + bool has_cta; + bool has_dispid; + bool hide_serial_numbers; + bool replace_unique_ids; + std::vector serial_strings; + unsigned serial_string_cnt; + + unsigned min_hor_freq_hz; + unsigned max_hor_freq_hz; + double min_vert_freq_hz; + double max_vert_freq_hz; + unsigned max_pixclk_khz; + unsigned dtd_max_hsize_mm; + unsigned dtd_max_vsize_mm; + + // in 0.1 mm units + unsigned image_width, image_height; + // in inches + double diagonal; + + unsigned warnings; + unsigned failures; + + // Base block state + struct { + unsigned edid_minor; + bool has_name_descriptor; + bool has_display_range_descriptor; + unsigned serial_number; + unsigned char week, year; + bool supports_continuous_freq; + bool supports_gtf; + bool supports_sec_gtf; + unsigned sec_gtf_start_freq; + double C, M, K, J; + bool supports_cvt; + bool has_spwg; + bool uses_srgb; + unsigned detailed_block_cnt; + unsigned dtd_cnt; + bool seen_non_detailed_descriptor; + bool has_640x480p60_est_timing; + bool preferred_is_also_native; + timings_ext preferred_timing; + + unsigned min_display_hor_freq_hz; + unsigned max_display_hor_freq_hz; + unsigned min_display_vert_freq_hz; + unsigned max_display_vert_freq_hz; + unsigned max_display_pixclk_khz; + unsigned max_display_width_mm; + unsigned max_display_height_mm; + unsigned max_pos_neg_hor_freq_khz; + } base; + + // CTA-861 block state + struct { + unsigned preparsed_total_dtds; + vec_timings_ext vec_dtds; + unsigned preparsed_total_vtdbs; + vec_timings_ext vec_vtdbs; + cta_vfd preparsed_first_vfd; + vec_timings_ext preferred_timings; + vec_timings_ext preferred_timings_vfpdb; + bool preparsed_has_t8vtdb; + unsigned preparsed_t8vtdb_dmt; + // Keep track of the found Tag/Extended Tag pairs. + // The unsigned value is equal to: (tag) | (OUI enum << 12) or (extended tag) | (tag << 8) | (OUI enum << 12) + std::vector found_tags; + timings_ext t8vtdb; + vec_timings_ext native_timings; + vec_timings_ext native_timing_nvrdb; + // in 0.1 mm units + unsigned image_width, image_height; + bool has_vic_1; + bool first_svd_might_be_preferred; + unsigned char byte3; + bool has_hdmi; + unsigned hdmi_max_rate; + bool has_vcdb; + bool has_vfpdb; + bool has_nvrdb; + bool has_cdb; + unsigned preparsed_speaker_count; + bool preparsed_sld_has_coord; + bool preparsed_sld; + bool has_sldb; + unsigned short preparsed_phys_addr; + unsigned previous_cta_tag; + bool have_hf_vsdb, have_hf_scdb; + unsigned hf_eeodb_blocks; + unsigned block_number; + bool has_svrs; + bool first_svd; + unsigned supported_hdmi_vic_codes; + unsigned supported_hdmi_vic_vsb_codes; + unsigned short vics[256][2]; + bool preparsed_has_vic[2][256]; + std::vector preparsed_svds[2]; + unsigned preparsed_max_vic_pixclk_khz; + bool warn_about_hdmi_2x_dtd; + } cta; +int edid_decode_alphanumeric_data_string(const char *from_file, std::string &str); + // DisplayID block state + struct { + unsigned char version; + unsigned short preparsed_color_ids; + unsigned short preparsed_xfer_ids; + unsigned preparsed_displayid_blocks; + bool is_base_block; + bool is_display; + bool has_product_identification; + bool has_display_parameters; + bool has_type_1_7; + bool has_display_interface_features; + vec_timings_ext preferred_timings; + unsigned native_width, native_height; + // in 0.1 mm units + unsigned image_width, image_height; + unsigned block_number; + // Keep track of the found CTA-861 Tag/Extended Tag pairs. + // The unsigned value is equal to: (tag) | (OUI enum << 12) or (extended tag) | (tag << 8) | (OUI enum << 12) + std::vector found_tags; + } dispid; + + // Block Map block state + struct { + bool saw_block_1; + bool saw_block_128; + } block_map; + + std::string dtd_type(unsigned dtd); + std::string dtd_type() { return dtd_type(base.dtd_cnt); } + + timings calc_gtf_mode(unsigned h_pixels, unsigned v_lines, + double ip_freq_rqd, bool int_rqd = false, + enum gtf_ip_parm ip_parm = gtf_ip_vert_freq, + bool margins_rqd = false, bool secondary = false, + double C = 40, double M = 600, double K = 128, double J = 20); + void edid_gtf_mode(unsigned refresh, struct timings &t); + timings calc_cvt_mode(unsigned h_pixels, unsigned v_lines, + double ip_freq_rqd, unsigned rb, bool int_rqd = false, + bool margins_rqd = false, bool alt = false, + unsigned rb_h_blank = 0, unsigned rb_v_blank = 460, + bool early_vsync_rqd = false); + void edid_cvt_mode(unsigned refresh, struct timings &t, unsigned rb_h_blank = 0, + unsigned rb_v_blank = 460, bool early_vsync_rqd = false); + void detailed_cvt_descriptor(const char *prefix, const unsigned char *x, bool first); + timings calc_ovt_mode(unsigned hact, unsigned vact, + unsigned hratio, unsigned vratio, + unsigned frame_rate); + void print_standard_timing(const char *prefix, unsigned char b1, unsigned char b2, + bool gtf_only = false, bool show_both = false); + void detailed_display_range_limits(const unsigned char *x); + void detailed_epi(const unsigned char *x); + void detailed_timings(const char *prefix, const unsigned char *x, + bool base_or_cta = true); + // bool preparse_detailed_block(unsigned char *x); + // void preparse_base_block(unsigned char *x); + void detailed_block(const unsigned char *x,QString &str); + void parse_base_block(const unsigned char *x,QString &str); + void check_base_block(const unsigned char *x); + void list_dmts(); + void list_established_timings(); + + void data_block_oui(std::string block_name, const unsigned char *x, unsigned length, unsigned *ouinum, + bool ignorezeros = false, bool do_ascii = false, bool big_endian = false); + + void print_vic_index(const char *prefix, unsigned idx, const char *suffix, bool ycbcr420 = false); + void hdmi_latency(unsigned char vid_lat, unsigned char aud_lat, bool is_ilaced); + void cta_vcdb(const unsigned char *x, unsigned length); + void cta_svd(const unsigned char *x, unsigned n, bool for_ycbcr420); + void cta_vfdb(const unsigned char *x, unsigned n); + void cta_y420cmdb(const unsigned char *x, unsigned length); + void cta_print_svr(unsigned char svr, vec_timings_ext &vec_tim); + void cta_vfpdb(const unsigned char *x, unsigned length); + void cta_nvrdb(const unsigned char *x, unsigned length); + cta_vfd cta_parse_vfd(const unsigned char *x, unsigned lvfd); + void cta_rcdb(const unsigned char *x, unsigned length); + void cta_sldb(const unsigned char *x, unsigned length); + void cta_preparse_sldb(const unsigned char *x, unsigned length); + void cta_colorimetry_block(const unsigned char *x, unsigned length); + void cta_hdmi_block(const unsigned char *x, unsigned length); + void cta_hf_scdb(const unsigned char *x, unsigned length); + void cta_displayid_type_7(const unsigned char *x, unsigned length); + void cta_displayid_type_8(const unsigned char *x, unsigned length); + void cta_displayid_type_10(const unsigned char *x, unsigned length); + void cta_block(const unsigned char *x, std::vector &found_tags); + // void preparse_cta_block(unsigned char *x); + // void parse_cta_block(const unsigned char *x); + void cta_resolve_svr(timings_ext &t_ext); + // void cta_resolve_svrs(); + // void check_cta_blocks(); + void cta_list_vics(); + void cta_list_hdmi_vics(); + void cta_list_rids(); + void cta_list_rid_timings(unsigned list_rid = 0); + + void set_displayid_native_res(unsigned w, unsigned h); + void parse_digital_interface(const unsigned char *x); + void parse_display_device(const unsigned char *x); + void parse_display_caps(const unsigned char *x); + void parse_display_xfer(const unsigned char *x); + // void parse_di_ext_block(const unsigned char *x); + + void check_displayid_datablock_revision(unsigned char hdr, + unsigned char valid_flags = 0, + unsigned char rev = 0); + void parse_displayid_product_id(const unsigned char *x); + std::string product_type(unsigned char x, bool heading); + void parse_displayid_interface_features(const unsigned char *x); + void parse_displayid_parameters(const unsigned char *x); + void parse_displayid_parameters_v2(const unsigned char *x, unsigned block_rev); + void parse_displayid_display_intf(const unsigned char *x); + void parse_displayid_color_characteristics(const unsigned char *x); + void parse_displayid_transfer_characteristics(const unsigned char *x); + void parse_displayid_stereo_display_intf(const unsigned char *x); + void parse_displayid_type_1_7_timing(const unsigned char *x, + bool type7, unsigned block_rev, bool is_cta = false); + void parse_displayid_type_2_timing(const unsigned char *x); + void parse_displayid_type_3_timing(const unsigned char *x); + void parse_displayid_type_4_8_timing(unsigned char type, unsigned short id, bool is_cta = false); + void parse_displayid_video_timing_range_limits(const unsigned char *x); + void parse_displayid_string(const unsigned char *x); + void parse_displayid_display_device(const unsigned char *x); + void parse_displayid_intf_power_sequencing(const unsigned char *x); + void parse_displayid_type_5_timing(const unsigned char *x); + void parse_displayid_tiled_display_topology(const unsigned char *x, bool is_v2); + void parse_displayid_type_6_timing(const unsigned char *x); + void parse_displayid_type_9_timing(const unsigned char *x); + void parse_displayid_dynamic_video_timings_range_limits(const unsigned char *x); + void parse_displayid_ContainerID(const unsigned char *x); + void parse_displayid_adaptive_sync(const unsigned char *x); + void parse_displayid_type_10_timing(const unsigned char *x, unsigned sz, + bool is_cta = false); + // void preparse_displayid_block(unsigned char *x); + unsigned displayid_block(const unsigned version, const unsigned char *x, unsigned length); + // void parse_displayid_block(const unsigned char *x); + void parse_displayid_vesa(const unsigned char *x); + void parse_displayid_apple(const unsigned char *x); + void parse_displayid_cta_data_block(const unsigned char *x); + void check_displayid_blocks(); + + // void parse_vtb_ext_block(const unsigned char *x); + + void parse_string_table(const unsigned char *x); + // void preparse_ls_ext_block(unsigned char *x); + // void parse_ls_ext_block(const unsigned char *x); + + void parse_block_map(const unsigned char *x); + + void preparse_extension(unsigned char *x); + void parse_extension(const unsigned char *x); + void print_preferred_timings(); + void print_native_res(); + int parse_edid(QString &str); +}; + +static inline void add_str(std::string &s, const std::string &add) +{ + if (s.empty()) + s = add; + else if (!add.empty()) + s = s + ", " + add; +} + +void msg(bool is_warn, const char *fmt, ...); + +#ifdef _WIN32 + +#define warn(fmt, ...) msg(true, fmt, __VA_ARGS__) +#define warn_once(fmt, ...) \ + do { \ + static bool shown_warn; \ + if (!shown_warn) { \ + shown_warn = true; \ + msg(true, fmt, __VA_ARGS__); \ + } \ + } while (0) +#define fail(fmt, ...) msg(false, fmt, __VA_ARGS__) + +#else + +#define warn(fmt, args...) msg(true, fmt, ##args) +#define warn_once(fmt, args...) \ + do { \ + static bool shown_warn; \ + if (!shown_warn) { \ + shown_warn = true; \ + msg(true, fmt, ##args); \ + } \ + } while (0) +#define fail(fmt, args...) msg(false, fmt, ##args) + +#endif + +std::string utohex(unsigned char x); +std::string ouitohex(unsigned oui); +// std::string containerid2s(const unsigned char *x); +bool memchk(const unsigned char *x, unsigned len, unsigned char v = 0); +void hex_block(const char *prefix, const unsigned char *x, unsigned length, + bool show_ascii = true, unsigned step = 16); +std::string block_name(unsigned char block); +void do_checksum(const char *prefix, const unsigned char *x, size_t len, unsigned unused_bytes = 0); +// void replace_checksum(unsigned char *x, size_t len); +void calc_ratio(struct timings *t); +const char *oui_name(unsigned oui, unsigned *ouinum = NULL); +unsigned gcd(unsigned a, unsigned b); + +// bool match_timings(const timings &t1, const timings &t2); +// bool timings_close_match(const timings &t1, const timings &t2); +const struct timings *find_dmt_id(unsigned char dmt_id); +const struct timings *close_match_to_dmt(const timings &t, unsigned &dmt); +const struct timings *find_vic_id(unsigned char vic); +const struct cta_rid *find_rid(unsigned char rid); +const struct timings *find_hdmi_vic_id(unsigned char hdmi_vic); +// const struct timings *cta_close_match_to_vic(const timings &t, unsigned &vic); +bool cta_matches_vic(const timings &t, unsigned &vic); +unsigned char hdmi_vic_to_vic(unsigned char hdmi_vic); +char *extract_string(const unsigned char *x, unsigned len); + +#define oneoui(c,k,n) const unsigned kOUI_##k = __LINE__<<12; +// #include "oui.h" + +int edid_decode_alphanumeric_data_string(const char *from_file, QString &str); + +#endif diff --git a/deepin-devicemanager/CMakeLists.txt b/deepin-devicemanager/CMakeLists.txt index 5650b6669..2c974e477 100644 --- a/deepin-devicemanager/CMakeLists.txt +++ b/deepin-devicemanager/CMakeLists.txt @@ -97,6 +97,7 @@ foreach(dir ${dirs}) endforeach() include_directories(${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/docx) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/QtXlsxWriter/include/QtXlsx) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/ediddecode) #add cups and zmq include_directories("/usr/include/cups/") diff --git a/deepin-devicemanager/assets/org.deepin.devicemanager.json b/deepin-devicemanager/assets/org.deepin.devicemanager.json index cbc0690f8..cc3d89efe 100644 --- a/deepin-devicemanager/assets/org.deepin.devicemanager.json +++ b/deepin-devicemanager/assets/org.deepin.devicemanager.json @@ -21,7 +21,7 @@ "flags": ["global"], "name": "Special Computer Type", "name[zh_CN]": "特殊机器类型", - "description": "special computer type:PGUW(value:1),KLVV/L540(value:2),KLVU(value:3),PGUV/W585(value:4),PGUX(value:5)", + "description": "special computer type:PGUW(value:1),KLVV/L540(value:2),KLVU(value:3),PGUV/W585(value:4),PGUX(value:5),M009(value:6)", "permissions": "readwrite", "visibility": "private" } diff --git a/deepin-devicemanager/src/DeviceManager/DeviceAudio.cpp b/deepin-devicemanager/src/DeviceManager/DeviceAudio.cpp index 067fa586c..ae77756e3 100644 --- a/deepin-devicemanager/src/DeviceManager/DeviceAudio.cpp +++ b/deepin-devicemanager/src/DeviceManager/DeviceAudio.cpp @@ -327,6 +327,7 @@ void DeviceAudio::loadBaseDeviceInfo() // 添加基本信息 addBaseDeviceInfo(tr("Name"), m_Name); addBaseDeviceInfo(tr("Vendor"), m_Vendor); + addBaseDeviceInfo(tr("Module Alias"), m_Modalias); addBaseDeviceInfo(tr("SysFS_Path"), m_SysPath); addBaseDeviceInfo(tr("Description"), m_Description); addBaseDeviceInfo(tr("Revision"), m_Version); diff --git a/deepin-devicemanager/src/DeviceManager/DeviceBluetooth.cpp b/deepin-devicemanager/src/DeviceManager/DeviceBluetooth.cpp index 66d1e6367..8ae146d30 100644 --- a/deepin-devicemanager/src/DeviceManager/DeviceBluetooth.cpp +++ b/deepin-devicemanager/src/DeviceManager/DeviceBluetooth.cpp @@ -33,6 +33,7 @@ void DeviceBluetooth::setInfoFromHciconfig(const QMap &mapInfo // 获取设备的基本信息 setAttribute(mapInfo, "Name", m_Name); setAttribute(mapInfo, "Manufacturer", m_Vendor); + setAttribute(mapInfo, "Modalias", m_Modalias); // 获取设备其他信息 getOtherMapInfo(mapInfo); diff --git a/deepin-devicemanager/src/DeviceManager/DeviceMonitor.cpp b/deepin-devicemanager/src/DeviceManager/DeviceMonitor.cpp index 370b964a6..44ea87773 100644 --- a/deepin-devicemanager/src/DeviceManager/DeviceMonitor.cpp +++ b/deepin-devicemanager/src/DeviceManager/DeviceMonitor.cpp @@ -164,6 +164,7 @@ void DeviceMonitor::setInfoFromEdid(const QMap &mapInfo) setAttribute(mapInfo, "Date", m_ProductionWeek); setAttribute(mapInfo, "Display Input", m_DisplayInput); setAttribute(mapInfo, "Model", m_Model); + if(m_Model.isEmpty()) m_Model = m_Name ; getOtherMapInfo(mapInfo); } diff --git a/deepin-devicemanager/src/DeviceManager/DeviceNetwork.cpp b/deepin-devicemanager/src/DeviceManager/DeviceNetwork.cpp index ddc322dc1..bd1b719a7 100644 --- a/deepin-devicemanager/src/DeviceManager/DeviceNetwork.cpp +++ b/deepin-devicemanager/src/DeviceManager/DeviceNetwork.cpp @@ -48,7 +48,8 @@ void DeviceNetwork::setInfoFromLshw(const QMap &mapInfo) { if (!matchToLshw(mapInfo) && Common::boardVendorType() != "KLVV" && Common::boardVendorType() != "KLVU" - && Common::boardVendorType() != "PGUW" && Common::boardVendorType() != "PGUV") { + && Common::boardVendorType() != "PGUW" && Common::boardVendorType() != "PGUV" + && Common::boardVendorType() != "M009") { return; } // 设置由lshw获取的信息 diff --git a/deepin-devicemanager/src/GenerateDevice/DeviceFactory.cpp b/deepin-devicemanager/src/GenerateDevice/DeviceFactory.cpp index 38d9f6aee..8ca51fa36 100644 --- a/deepin-devicemanager/src/GenerateDevice/DeviceFactory.cpp +++ b/deepin-devicemanager/src/GenerateDevice/DeviceFactory.cpp @@ -10,6 +10,7 @@ #include "KLUGenerator.h" #include "PanguGenerator.h" #include "PanguVGenerator.h" +#include "M009Generator.h" #include "HWGenerator.h" #include "KLVGenerator.h" #include "commonfunction.h" @@ -42,6 +43,8 @@ DeviceGenerator *DeviceFactory::getDeviceGenerator() generator = new KLVGenerator(); else if (type == "PGUV" || type == "PGUW") generator = new PanguVGenerator(); + else if (type == "M009") + generator = new M009Generator(); else if (type == "KLVU") generator = new KLUGenerator(); else if (type == "PGUX") diff --git a/deepin-devicemanager/src/GenerateDevice/DeviceGenerator.cpp b/deepin-devicemanager/src/GenerateDevice/DeviceGenerator.cpp index 2de58751b..504e62252 100644 --- a/deepin-devicemanager/src/GenerateDevice/DeviceGenerator.cpp +++ b/deepin-devicemanager/src/GenerateDevice/DeviceGenerator.cpp @@ -25,6 +25,7 @@ #include "DeviceManager/DevicePrint.h" #include "DeviceManager/DeviceInput.h" #include "MacroDefinition.h" +#include "commontools.h" // Dtk头文件 #include @@ -86,58 +87,6 @@ void DeviceGenerator::generatorComputerDevice() DeviceManager::instance()->addComputerDevice(device); } -void mergeSortCpuInfoByLogicalID(QList > &lsCpu, QList > &tmpLst, int begin, int end) -{ - // 合并列表 - int left_length = (end - begin + 1) / 2; - int left_index = begin; - int right_index = begin + left_length; - int result_index = begin; - - // 合并左右区间 左区间未合并结束且右区间未合并结束时 - while (left_index < begin + left_length && right_index < end + 1) { - // 左右区间,哪个小先排哪个,下标加1 - if (lsCpu[left_index]["processor"].toInt() <= lsCpu[right_index]["processor"].toInt()) - tmpLst[result_index++] = lsCpu[left_index++]; - else - tmpLst[result_index++] = lsCpu[right_index++]; - } - - // 合并左区间剩余数据 - while (left_index < begin + left_length) - tmpLst[result_index++] = lsCpu[left_index++]; - - // 合并右区间剩余数据 - while (right_index < end + 1) - tmpLst[result_index++] = lsCpu[right_index++]; -} - -void sortCpuInfoByLogicalID(QList > &lsCpu, QList > &tmpLst, int begin, int end) -{ - // 列表个数为1,直接返回 - if (0 == end - begin) - return; - - // bug 后台获取CPU信息是按照物理CPU,核心,逻辑CPU顺序获取的 - // 界面上展示顺序混乱实际是按照物理CPU,核心,逻辑CPU顺序展示 - // 与产品沟通后,按照用户的使用感修改,CPU信息按照逻辑CPU的id从小到大显示 - // 区间个数为2 - if (1 == end - begin) { - // 前 processor > 后 processor 时交换位置 - if (lsCpu[begin]["processor"].toInt() > lsCpu[end]["processor"].toInt()) { - QMap tmpMap = lsCpu[begin]; - lsCpu[begin] = lsCpu[end]; - lsCpu[end] = tmpMap; - } - } else { - // 区间个数 > 2 递归 - sortCpuInfoByLogicalID(lsCpu, tmpLst, begin, (end - begin) / 2 + begin); - sortCpuInfoByLogicalID(lsCpu, tmpLst, (end - begin + 1) / 2 + begin, end); - mergeSortCpuInfoByLogicalID(lsCpu, tmpLst, begin, end); - lsCpu = tmpLst; - } -} - void DeviceGenerator::generatorCpuDevice() { // 生成CPU @@ -150,7 +99,7 @@ void DeviceGenerator::generatorCpuDevice() // 按照processor id 从小到大排序 if (lsCpu.size() > 1) - sortCpuInfoByLogicalID(srcLst, tmpLst, 0, lsCpu.size() - 1); + CommonTools::sortCpuInfoByLogicalID(srcLst, tmpLst, 0, lsCpu.size() - 1); // get info from lshw const QList > &lshwCpu = DeviceManager::instance()->cmdInfo("lshw_cpu"); diff --git a/deepin-devicemanager/src/GenerateDevice/HWGenerator.cpp b/deepin-devicemanager/src/GenerateDevice/HWGenerator.cpp index eb4d5f01f..be1958914 100644 --- a/deepin-devicemanager/src/GenerateDevice/HWGenerator.cpp +++ b/deepin-devicemanager/src/GenerateDevice/HWGenerator.cpp @@ -26,6 +26,7 @@ #include "DeviceManager/DeviceBluetooth.h" #include "DeviceManager/DeviceNetwork.h" #include "DeviceManager/DeviceMemory.h" +#include "commonfunction.h" HWGenerator::HWGenerator() { @@ -115,7 +116,9 @@ void HWGenerator::generatorGpuDevice() QStringList items = deviceInfo.split("\n"); QMap mapInfo; - for (QString itemStr : items) { + if(Common::boardVendorType() == "M009") + mapInfo.insert("Name", "PANGU M900"); + else for (QString itemStr : items) { if (itemStr.contains(":")) continue; QString curItemStr = itemStr.trimmed(); @@ -266,6 +269,17 @@ void HWGenerator::getDiskInfoFromLshw() DeviceManager::instance()->addLshwinfoIntoStorageDevice(tempMap); } + // lshw -C storage + if(Common::boardVendorType() != "M009") + return; + const QList> &lstStorage = DeviceManager::instance()->cmdInfo("lshw_storage"); + QList >::const_iterator sIt = lstStorage.begin(); + for (; sIt != lstStorage.end(); ++sIt) { + if ((*sIt).size() < 2) + continue; + + DeviceManager::instance()->addLshwinfoIntoNVMEStorageDevice(*sIt); + } } void HWGenerator::getDiskInfoFromSmartCtl() diff --git a/deepin-devicemanager/src/GenerateDevice/M009Generator.cpp b/deepin-devicemanager/src/GenerateDevice/M009Generator.cpp new file mode 100644 index 000000000..393cfcd75 --- /dev/null +++ b/deepin-devicemanager/src/GenerateDevice/M009Generator.cpp @@ -0,0 +1,266 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +// 项目自身文件 +#include "M009Generator.h" + +#include +#include +#include + +// 其它头文件 +#include "../DeviceManager/DeviceManager.h" +#include "DeviceManager/DeviceNetwork.h" +#include "DeviceManager/DeviceAudio.h" +#include "DeviceManager/DeviceCpu.h" +#include "commontools.h" +#include "../DeviceManager/DeviceMonitor.h" +#include "EDIDParser.h" +#include "ediddecode.h" + +#include + +M009Generator::M009Generator() +{ + +} + +static void parseEDID(QStringList allEDIDS,QString input) +{ + for (auto edid:allEDIDS) { + QProcess process; + process.start(QString("hexdump %1").arg(edid)); + process.waitForFinished(-1); + + QString deviceInfo = process.readAllStandardOutput(); + if(deviceInfo.isEmpty()) + continue; + + QString edidStr; + QStringList lines = deviceInfo.split("\n"); + for (auto line:lines) { + QStringList words = line.trimmed().split(" "); + if(words.size() != 9) + continue; + + words.removeAt(0); + QString l = words.join(""); + l.append("\n"); + edidStr.append(l); + } + + lines = edidStr.split("\n"); + if(lines.size() > 3){ + EDIDParser edidParser; + QString errorMsg; + edidParser.setEdid(edidStr,errorMsg,"\n", false); + + QMap mapInfo; + mapInfo.insert("Vendor",edidParser.vendor()); + mapInfo.insert("Model",edidParser.model()); + mapInfo.insert("Date",edidParser.releaseDate()); + mapInfo.insert("Size",edidParser.screenSize()); + mapInfo.insert("Display Input",input); + QString alphanumericData; + edid_decode_alphanumeric_data_string(edid.toStdString().c_str(),alphanumericData); + if (!alphanumericData.isEmpty()) { + mapInfo["Model"] = alphanumericData; + } + + DeviceMonitor *device = new DeviceMonitor(); + device->setInfoFromEdid(mapInfo); + DeviceManager::instance()->addMonitor(device); + } + } +} + +void M009Generator::generatorMonitorDevice() +{ + QString toDir = "/sys/class/drm"; + QDir toDir_(toDir); + + if (!toDir_.exists()) + return; + + QFileInfoList fileInfoList = toDir_.entryInfoList(); + foreach(QFileInfo fileInfo, fileInfoList) { + if(fileInfo.fileName() == "." || fileInfo.fileName() == ".." || !fileInfo.fileName().startsWith("card")) + continue; + + if(QFile::exists(fileInfo.filePath() + "/" + "edid")) { + QStringList allEDIDS_all; + allEDIDS_all.append(fileInfo.filePath() + "/" + "edid"); + QString interface = fileInfo.fileName().remove("card0-").remove("card1-").remove("card2-"); + parseEDID(allEDIDS_all,interface); + } + } +} +/* +:/sys/class/net/wlan0$ ls +addr_assign_type carrier device duplex ifindex name_assign_type phys_port_id proto_down subsystem wireless +address carrier_changes dev_id flags iflink netdev_group phys_port_name queues tx_queue_len +addr_len carrier_down_count dev_port gro_flush_timeout link_mode operstate phys_switch_id speed type +broadcast carrier_up_count dormant ifalias mtu phy80211 power statistics uevent +:/sys/class/net/wlan0$ ls device +class device driver ieee80211 modalias net power subsystem uevent vendor +:/sys/class/net/wlan0$ cat device/vendor +0x024c +uos@uos-PC:/sys/class/net/wlan0$ cat device/device +0xa822 +*/ + +void M009Generator::generatorNetworkDevice() +{ + QStringList ifconfigCardName = getNetworkInfoFromifconfig(); + const QList> lstInfo = DeviceManager::instance()->cmdInfo("lshw_network"); + QList >::const_iterator it = lstInfo.begin(); + for (; it != lstInfo.end(); ++it) { + if ((*it).size() < 2) { + continue; + } + QMap tempMap = *it; + + QString logicalName = tempMap["logical name"].trimmed(); + if (! ifconfigCardName.contains(logicalName)) + continue; + + if (logicalName.contains("wlan0")) { + QFile file("/sys/class/net/wlan0/device/vendor"); + if (file.open(QIODevice::ReadOnly)) { + + QString vendorInfo = file.readAll(); + if (vendorInfo.contains("024c", Qt::CaseInsensitive)) { + tempMap["vendor"] = "Realtek"; + } else if (vendorInfo.contains("12d1", Qt::CaseInsensitive)) { + tempMap["vendor"] = "HiSilicon"; + } + } + } else + tempMap["vendor"] = "HiSilicon"; + + DeviceNetwork *device = new DeviceNetwork(); + device->setInfoFromLshw(tempMap); + device->setCanEnale(false); + device->setCanUninstall(false); + device->setForcedDisplay(true); + DeviceManager::instance()->addNetworkDevice(device); + } +} + +QStringList M009Generator::getNetworkInfoFromifconfig() +{ + //通过ifconfig 判断网络是否valiate + QStringList ret; + QProcess process; + QString cmd = "ifconfig -s"; + process.start(cmd); + QString ifconfigInfo; + bool re = process.waitForFinished(-1); + if (!re) + return ret; + ifconfigInfo = process.readAllStandardOutput(); + //截取查询到的各个网卡连接信息 + QStringList list = ifconfigInfo.split("\n"); + for (int i = 1; i < list.size(); i++) { //skip Iface + //filter "lo" 网卡 + if (list.at(i).contains("lo")) + continue; + + QStringList line = list.at(i).split(" ", QString::SkipEmptyParts); + { + if (line.size() < 2) + continue; + if (line.at(0).isEmpty()) + continue; + else + ret.append(line.at(0)); + } + } + return ret; +} + +void M009Generator::getAudioInfoFromCatAudio() /*this is for PAGU M009 special, conflict to master*/ +{ + QMap tempMap; + QFile file_vendor("/sys/firmware/devicetree/base/vendor_info/Vendor"); + if (file_vendor.open(QIODevice::ReadOnly)) { + QString vendorInfo = file_vendor.readAll(); + file_vendor.close(); + if (!vendorInfo.isEmpty()) { + tempMap["Vendor"] = vendorInfo; + } + } + + QFile file_name("/sys/firmware/devicetree/base/vendor_info/Name"); + if (file_name.open(QIODevice::ReadOnly)) { + QString nameInfo = file_name.readAll(); + file_name.close(); + if (!nameInfo.isEmpty()) { + tempMap["Name"] = nameInfo; + } + } + + if (tempMap.contains("Vendor") && tempMap.contains("Name")) { + DeviceAudio *device = new DeviceAudio(); + device->setCanEnale(false); + device->setCanUninstall(false); + device->setForcedDisplay(true); + device->setInfoFromCatAudio(tempMap); + DeviceManager::instance()->addAudioDevice(device); + } +} + +void M009Generator::generatorCpuDevice() /*this is for PAGU M009 special, conflict to master*/ +{ + // 生成CPU + // get info from lscpu + const QList > &lsCpu = DeviceManager::instance()->cmdInfo("lscpu"); + QList > tmpLst; + QList > srcLst; + tmpLst.append(lsCpu); + srcLst.append(lsCpu); + + // 按照processor id 从小到大排序 + if (lsCpu.size() > 1) + CommonTools::sortCpuInfoByLogicalID(srcLst, tmpLst, 0, lsCpu.size() - 1); + + // get info from lshw + const QList > &lshwCpu = DeviceManager::instance()->cmdInfo("lshw_cpu"); + QMap lshw = lshwCpu.size() > 0 ? lshwCpu[0] : QMap(); + lshw["vendor"] = "HiSilicon"; + + // get info from dmidecode -t 4 + const QList > &dmidecode4 = DeviceManager::instance()->cmdInfo("dmidecode4"); + QMap dmidecode = dmidecode4.size() > 0 ? dmidecode4[0] : QMap(); + dmidecode["Manufacturer"] = "HiSilicon"; + + // 获取逻辑数和core数 获取cpu个数 获取logical个数 + int coreNum = 0, logicalNum = 0; + const QList > &lsCpu_num = DeviceManager::instance()->cmdInfo("lscpu_num"); + if (lsCpu_num.size() <= 0) + return; + const QMap &map = lsCpu_num[0]; + if (map.find("core") != map.end()) + coreNum = map["core"].toInt(); + if (map.find("logical") != map.end()) + logicalNum = map["logical"].toInt(); + + // set cpu number + QSet allCPUS; + for (auto dd4 : dmidecode4) { + if (dd4.contains("Socket Designation")) + allCPUS.insert(dd4["Socket Designation"]); + } + DeviceManager::instance()->setCpuNum(allCPUS.isEmpty() ? dmidecode4.size() : allCPUS.size()); + + // set cpu info + QList >::const_iterator it = srcLst.begin(); + for (; it != srcLst.end(); ++it) { + DeviceCpu *device = new DeviceCpu; + device->setCpuInfo(*it, lshw, dmidecode, coreNum, logicalNum); + DeviceManager::instance()->addCpuDevice(device); + } + + DeviceManager::instance()->setCpuFrequencyIsCur(false); +} diff --git a/deepin-devicemanager/src/GenerateDevice/M009Generator.h b/deepin-devicemanager/src/GenerateDevice/M009Generator.h new file mode 100644 index 000000000..68e0ef7d4 --- /dev/null +++ b/deepin-devicemanager/src/GenerateDevice/M009Generator.h @@ -0,0 +1,34 @@ +// Copyright (C) 2019 ~ 2020 Uniontech Software Technology Co.,Ltd. +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef M009GENERATOR_H +#define M009GENERATOR_H + +#include +#include "HWGenerator.h" +#include "PanguVGenerator.h" + +/** + * @brief The PanguVGenerator class + * 将获取的设备信息生成设备对象,M009 下的生成器 + */ + +class M009Generator : public PanguVGenerator //HWGenerator +{ +public: + M009Generator(); + + /** + * @brief generatorMonitorDevice:生成显示设备信息 + */ + virtual void generatorMonitorDevice() override; +protected: + virtual void generatorNetworkDevice() override; + virtual QStringList getNetworkInfoFromifconfig() override; + virtual void getAudioInfoFromCatAudio() override; /*this is for PAGU M009 special, conflict to master*/ + virtual void generatorCpuDevice() override; /*this is for PAGU M009 special, conflict to master*/ +}; + +#endif // M009GENERATOR_H diff --git a/deepin-devicemanager/src/GenerateDevice/PanguVGenerator.cpp b/deepin-devicemanager/src/GenerateDevice/PanguVGenerator.cpp index c8c6bc34b..216816511 100644 --- a/deepin-devicemanager/src/GenerateDevice/PanguVGenerator.cpp +++ b/deepin-devicemanager/src/GenerateDevice/PanguVGenerator.cpp @@ -11,6 +11,8 @@ #include "EDIDParser.h" #include "DeviceManager/DeviceNetwork.h" #include +#include +#include PanguVGenerator::PanguVGenerator() { @@ -49,6 +51,7 @@ void parseEDID(QStringList allEDIDS,QString input) QMap mapInfo; mapInfo.insert("Vendor",edidParser.vendor()); + mapInfo.insert("Model",edidParser.model()); mapInfo.insert("Date",edidParser.releaseDate()); mapInfo.insert("Size",edidParser.screenSize()); mapInfo.insert("Display Input",input); @@ -62,15 +65,24 @@ void parseEDID(QStringList allEDIDS,QString input) void PanguVGenerator::generatorMonitorDevice() { - QStringList allEDIDS1; - allEDIDS1.append("/sys/devices/platform/hisi-drm/drm/card0/card0-HDMI-A-1/edid"); - allEDIDS1.append("/sys/devices/platform/hldrm/drm/card0/card0-HDMI-A-1/edid"); - parseEDID(allEDIDS1,"HDMI-A-1"); - - QStringList allEDIDS2; - allEDIDS2.append("/sys/devices/platform/hisi-drm/drm/card0/card0-VGA-1/edid"); - allEDIDS2.append("/sys/devices/platform/hldrm/drm/card0/card0-VGA-1/edid"); - parseEDID(allEDIDS2,"VGA-1"); + QString toDir = "/sys/class/drm"; + QDir toDir_(toDir); + + if (!toDir_.exists()) + return; + + QFileInfoList fileInfoList = toDir_.entryInfoList(); + foreach(QFileInfo fileInfo, fileInfoList) { + if(fileInfo.fileName() == "." || fileInfo.fileName() == ".." || !fileInfo.fileName().startsWith("card")) + continue; + + if(QFile::exists(fileInfo.filePath() + "/" + "edid")) { + QStringList allEDIDS_all; + allEDIDS_all.append(fileInfo.filePath() + "/" + "edid"); + QString interface = fileInfo.fileName().remove("card0-").remove("card1-").remove("card2-"); + parseEDID(allEDIDS_all,interface); + } + } } void PanguVGenerator::generatorNetworkDevice() diff --git a/deepin-devicemanager/src/Tool/commontools.cpp b/deepin-devicemanager/src/Tool/commontools.cpp index 8b29bea71..ebc332b8f 100644 --- a/deepin-devicemanager/src/Tool/commontools.cpp +++ b/deepin-devicemanager/src/Tool/commontools.cpp @@ -162,3 +162,55 @@ QString CommonTools::getBackupPath() { return "/usr/share/deepin-devicemanager/"; } + +void CommonTools::mergeSortCpuInfoByLogicalID(QList > &lsCpu, QList > &tmpLst, int begin, int end) +{ + // 合并列表 + int left_length = (end - begin + 1) / 2; + int left_index = begin; + int right_index = begin + left_length; + int result_index = begin; + + // 合并左右区间 左区间未合并结束且右区间未合并结束时 + while (left_index < begin + left_length && right_index < end + 1) { + // 左右区间,哪个小先排哪个,下标加1 + if (lsCpu[left_index]["processor"].toInt() <= lsCpu[right_index]["processor"].toInt()) + tmpLst[result_index++] = lsCpu[left_index++]; + else + tmpLst[result_index++] = lsCpu[right_index++]; + } + + // 合并左区间剩余数据 + while (left_index < begin + left_length) + tmpLst[result_index++] = lsCpu[left_index++]; + + // 合并右区间剩余数据 + while (right_index < end + 1) + tmpLst[result_index++] = lsCpu[right_index++]; +} + +void CommonTools::sortCpuInfoByLogicalID(QList > &lsCpu, QList > &tmpLst, int begin, int end) +{ + // 列表个数为1,直接返回 + if (0 == end - begin) + return; + + // bug 后台获取CPU信息是按照物理CPU,核心,逻辑CPU顺序获取的 + // 界面上展示顺序混乱实际是按照物理CPU,核心,逻辑CPU顺序展示 + // 与产品沟通后,按照用户的使用感修改,CPU信息按照逻辑CPU的id从小到大显示 + // 区间个数为2 + if (1 == end - begin) { + // 前 processor > 后 processor 时交换位置 + if (lsCpu[begin]["processor"].toInt() > lsCpu[end]["processor"].toInt()) { + QMap tmpMap = lsCpu[begin]; + lsCpu[begin] = lsCpu[end]; + lsCpu[end] = tmpMap; + } + } else { + // 区间个数 > 2 递归 + sortCpuInfoByLogicalID(lsCpu, tmpLst, begin, (end - begin) / 2 + begin); + sortCpuInfoByLogicalID(lsCpu, tmpLst, (end - begin + 1) / 2 + begin, end); + mergeSortCpuInfoByLogicalID(lsCpu, tmpLst, begin, end); + lsCpu = tmpLst; + } +} diff --git a/deepin-devicemanager/src/Tool/commontools.h b/deepin-devicemanager/src/Tool/commontools.h index 6948c8f68..b8b8c4e9c 100644 --- a/deepin-devicemanager/src/Tool/commontools.h +++ b/deepin-devicemanager/src/Tool/commontools.h @@ -78,6 +78,20 @@ class CommonTools : public QObject */ static QString getBackupPath(); + /** + * @brief mergeSortCpuInfoByLogicalID: 获取状态类型类型对应的图标 + * @param lsCpu CPU信息 + * @return + */ + static void mergeSortCpuInfoByLogicalID(QList > &lsCpu, QList > &tmpLst, int begin, int end); + /** + * @brief sortCpuInfoByLogicalID: 依CPU ID排序 + * @param lsCpu CPU信息 + * @return + */ + static void sortCpuInfoByLogicalID(QList > &lsCpu, QList > &tmpLst, int begin, int end); + + signals: public slots: diff --git a/deepin-devicemanager/src/commonfunction.cpp b/deepin-devicemanager/src/commonfunction.cpp index 47cab2fdd..58399d706 100644 --- a/deepin-devicemanager/src/commonfunction.cpp +++ b/deepin-devicemanager/src/commonfunction.cpp @@ -81,6 +81,7 @@ static bool isModeM900(void) } return false; } + /* dmidecode | grep -i “String 4”中的值来区分主板类型,PWC30表示PanguW(也就是W525)*/ static bool isModeW525(void) { @@ -128,6 +129,9 @@ QString Common::checkBoardVendorFlag() case PGUX: boardVendorKey = "PGUX"; break; + case M009: + boardVendorKey = "M009"; + break; default: boardVendorKey = "PGUW"; break; diff --git a/deepin-devicemanager/src/commonfunction.h b/deepin-devicemanager/src/commonfunction.h index 7c85fbfa3..91ffb0000 100644 --- a/deepin-devicemanager/src/commonfunction.h +++ b/deepin-devicemanager/src/commonfunction.h @@ -21,7 +21,8 @@ class Common KLVV, KLVU, PGUV, - PGUX + PGUX, + M009 }; static QString getArch(); @@ -33,7 +34,7 @@ class Common /** * @brief specialComType - * special computer type:PGUW(value:1),KLVV/L540(value:2),KLVU(value:3),PGUV/W585(value:4) + * special computer type:PGUW(value:1),KLVV/L540(value:2),KLVU(value:3),PGUV/W585(value:4),PGUX(value:5),M009(value:6) */ static int specialComType; };