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
master
Daniel Vrátil 5 years ago
parent ce306a598a
commit 33a1777a5a
No known key found for this signature in database
GPG Key ID: 4D69557AECB13683

@ -287,6 +287,14 @@ set_package_properties(Libcap PROPERTIES
) )
set(HAVE_LIBCAP ${Libcap_FOUND}) 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) include(ECMQMLModules)
ecm_find_qmlmodule(QtQuick 2.3) ecm_find_qmlmodule(QtQuick 2.3)
ecm_find_qmlmodule(QtQuick.Controls 1.2) ecm_find_qmlmodule(QtQuick.Controls 1.2)

@ -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()

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

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

@ -20,6 +20,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/ *********************************************************************/
#include "edid.h" #include "edid.h"
#include "config-kwin.h"
#include <QFile>
namespace KWin namespace KWin
{ {
@ -40,25 +43,9 @@ static QSize parsePhysicalSize(const uint8_t *data)
return QSize(data[0x15], data[0x16]) * 10; 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) { // Decode PNP ID from three 5 bit words packed into 2 bytes:
// 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:
// //
// | Byte | Bit | // | Byte | Bit |
// | | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | // | | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
@ -80,6 +67,28 @@ static QByteArray parseEisaId(const uint8_t *data)
return QByteArray(pnpId); 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) static QByteArray parseMonitorName(const uint8_t *data)
{ {
for (int i = 72; i <= 108; i += 18) { for (int i = 72; i <= 108; i += 18) {
@ -131,6 +140,25 @@ static QByteArray parseSerialNumber(const uint8_t *data)
return QByteArray(); 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() Edid::Edid()
{ {
} }
@ -151,6 +179,7 @@ Edid::Edid(const void *data, uint32_t size)
m_eisaId = parseEisaId(bytes); m_eisaId = parseEisaId(bytes);
m_monitorName = parseMonitorName(bytes); m_monitorName = parseMonitorName(bytes);
m_serialNumber = parseSerialNumber(bytes); m_serialNumber = parseSerialNumber(bytes);
m_vendor = parseVendor(bytes);
m_isValid = true; m_isValid = true;
} }
@ -180,4 +209,9 @@ QByteArray Edid::serialNumber() const
return m_serialNumber; return m_serialNumber;
} }
QByteArray Edid::vendor() const
{
return m_vendor;
}
} // namespace KWin } // namespace KWin

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

Loading…
Cancel
Save