Decode full monitor vendor name from EDID using hwdata

Test Plan:
KScreen now shows "Dell Inc." instead of DEL and
"Eizo Nano Corporation" instead of ENC in output names, which
matches closer to what's written on my monitors.

Reviewers: graesslin, davidedmundson, #plasma

Reviewed By: davidedmundson, #plasma

Subscribers: apol, feverfew, ngraham, davidedmundson, mart, kwin, sebas

Tags: #kwin

Differential Revision: https://phabricator.kde.org/D10041
This commit is contained in:
Daniel Vrátil 2020-02-26 12:37:01 +01:00
parent ce306a598a
commit 33a1777a5a
No known key found for this signature in database
GPG key ID: 4D69557AECB13683
6 changed files with 121 additions and 20 deletions

View file

@ -287,6 +287,14 @@ set_package_properties(Libcap PROPERTIES
)
set(HAVE_LIBCAP ${Libcap_FOUND})
find_package(hwdata)
set_package_properties(hwdata PROPERTIES
TYPE RUNTIME
PURPOSE "Runtime-only dependency needed for mapping monitor hardware vendor IDs to full names"
URL "https://github.com/vcrhonek/hwdata"
)
set(HAVE_HWDATA ${hwdata_FOUND})
include(ECMQMLModules)
ecm_find_qmlmodule(QtQuick 2.3)
ecm_find_qmlmodule(QtQuick.Controls 1.2)

View file

@ -0,0 +1,47 @@
# - Try to find hwdata
# Once done this will define
#
# hwdata_DIR - The hwdata directory
# hwdata_PNPIDS_FILE - File with mapping of hw vendor IDs to names
# hwdata_FOUND - The hwdata directory exists and contains pnp.ids file
# Copyright (c) 2020 Daniel Vrátil <dvratil@kde.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
if (UNIX AND NOT APPLE)
find_path(hwdata_DIR NAMES hwdata/pnp.ids HINTS /usr/share ENV XDG_DATA_DIRS)
find_file(hwdata_PNPIDS_FILE NAMES hwdata/pnp.ids HINTS /usr/share)
if (hwdata_DIR-NOTFOUND OR hwdata_PNPIDS_FILE-NOTFOUND)
set(hwdata_FOUND FALSE)
else()
set(hwdata_FOUND TRUE)
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(hwdata DEFAULT_MSG hwdata_FOUND hwdata_DIR hwdata_PNPIDS_FILE)
mark_as_advanced(hwdata_FOUND hwdata_DIR hwdata_PNPIDS_FILE)
endif()

View file

@ -25,6 +25,7 @@
#cmakedefine01 HAVE_BREEZE_DECO
#cmakedefine01 HAVE_LIBCAP
#cmakedefine01 HAVE_SCHED_RESET_ON_FORK
#cmakedefine01 HAVE_HWDATA
#if HAVE_BREEZE_DECO
#define BREEZE_KDECORATION_PLUGIN_ID "${BREEZE_KDECORATION_PLUGIN_ID}"
#endif
@ -41,3 +42,7 @@
#define XCB_ICCCM_WM_STATE_NORMAL 1
#define XCB_ICCCM_WM_STATE_ICONIC 3
#endif
#if HAVE_HWDATA
#cmakedefine HWDATA_PNPIDS_FILE "@hwdata_PNPIDS_FILE@"
#endif

View file

@ -301,7 +301,9 @@ void DrmOutput::initUuid()
void DrmOutput::initOutputDevice(drmModeConnector *connector)
{
QString manufacturer;
if (!m_edid.eisaId().isEmpty()) {
if (!m_edid.vendor().isEmpty()) {
manufacturer = QString::fromLatin1(m_edid.vendor());
} else if (!m_edid.eisaId().isEmpty()) {
manufacturer = QString::fromLatin1(m_edid.eisaId());
}
@ -379,7 +381,6 @@ bool DrmOutput::isCurrentMode(const drmModeModeInfo *mode) const
&& mode->type == m_mode.type
&& qstrcmp(mode->name, m_mode.name) == 0;
}
void DrmOutput::initEdid(drmModeConnector *connector)
{
DrmScopedPointer<drmModePropertyBlobRes> edid;

View file

@ -20,6 +20,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "edid.h"
#include "config-kwin.h"
#include <QFile>
namespace KWin
{
@ -40,25 +43,9 @@ static QSize parsePhysicalSize(const uint8_t *data)
return QSize(data[0x15], data[0x16]) * 10;
}
static QByteArray parseEisaId(const uint8_t *data)
static QByteArray parsePnpId(const uint8_t *data)
{
for (int i = 72; i <= 108; i += 18) {
// Skip the block if it isn't used as monitor descriptor.
if (data[i]) {
continue;
}
if (data[i + 1]) {
continue;
}
// We have found the EISA ID, it's stored as ASCII.
if (data[i + 3] == 0xfe) {
return QByteArray(reinterpret_cast<const char *>(&data[i + 5]), 12).trimmed();
}
}
// If there isn't an ASCII EISA ID descriptor, try to decode PNP ID from
// three 5 bit words packed into 2 bytes:
// Decode PNP ID from three 5 bit words packed into 2 bytes:
//
// | Byte | Bit |
// | | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
@ -80,6 +67,28 @@ static QByteArray parseEisaId(const uint8_t *data)
return QByteArray(pnpId);
}
static QByteArray parseEisaId(const uint8_t *data)
{
for (int i = 72; i <= 108; i += 18) {
// Skip the block if it isn't used as monitor descriptor.
if (data[i]) {
continue;
}
if (data[i + 1]) {
continue;
}
// We have found the EISA ID, it's stored as ASCII.
if (data[i + 3] == 0xfe) {
return QByteArray(reinterpret_cast<const char *>(&data[i + 5]), 12).trimmed();
}
}
// If there isn't an ASCII EISA ID descriptor, try to decode PNP ID
return parsePnpId(data);
}
static QByteArray parseMonitorName(const uint8_t *data)
{
for (int i = 72; i <= 108; i += 18) {
@ -131,6 +140,25 @@ static QByteArray parseSerialNumber(const uint8_t *data)
return QByteArray();
}
static QByteArray parseVendor(const uint8_t *data)
{
#if HAVE_HWDATA
const auto pnpId = parsePnpId(data);
// Map to vendor name
QFile pnpFile(QStringLiteral(HWDATA_PNPIDS_FILE));
if (pnpFile.exists() && pnpFile.open(QIODevice::ReadOnly)) {
while (!pnpFile.atEnd()) {
const auto line = pnpFile.readLine();
if (line.startsWith(pnpId)) {
return line.mid(4).trimmed();
}
}
}
#endif
return {};
}
Edid::Edid()
{
}
@ -151,6 +179,7 @@ Edid::Edid(const void *data, uint32_t size)
m_eisaId = parseEisaId(bytes);
m_monitorName = parseMonitorName(bytes);
m_serialNumber = parseSerialNumber(bytes);
m_vendor = parseVendor(bytes);
m_isValid = true;
}
@ -180,4 +209,9 @@ QByteArray Edid::serialNumber() const
return m_serialNumber;
}
QByteArray Edid::vendor() const
{
return m_vendor;
}
} // namespace KWin

View file

@ -62,8 +62,14 @@ public:
*/
QByteArray serialNumber() const;
/**
* Returns the name of the vendor.
*/
QByteArray vendor() const;
private:
QSize m_physicalSize;
QByteArray m_vendor;
QByteArray m_eisaId;
QByteArray m_monitorName;
QByteArray m_serialNumber;