-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a support library to parse EDID that will be used by platform plugins. In order to tell the screen manufacturer from the identifier, the parsers reads /usr/share/hwdata/pnp.ids or, if it's missing, uses a lookup table previously generated from that file with a Python script. Change-Id: Ie021eb68be91f06dc0da54445f88e3533f78d23e Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
- Loading branch information
Showing
7 changed files
with
2,689 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
TARGET = QtEdidSupport | ||
MODULE = edid_support | ||
|
||
QT = core-private | ||
CONFIG += static internal_module | ||
|
||
DEFINES += QT_NO_CAST_FROM_ASCII | ||
PRECOMPILED_HEADER = ../../corelib/global/qt_pch.h | ||
|
||
HEADERS += qedidparser_p.h | ||
SOURCES += qedidparser.cpp | ||
|
||
load(qt_module) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
/**************************************************************************** | ||
** | ||
** Copyright (C) 2017 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> | ||
** Contact: https://www.qt.io/licensing/ | ||
** | ||
** This file is part of the plugins of the Qt Toolkit. | ||
** | ||
** $QT_BEGIN_LICENSE:LGPL$ | ||
** Commercial License Usage | ||
** Licensees holding valid commercial Qt licenses may use this file in | ||
** accordance with the commercial license agreement provided with the | ||
** Software or, alternatively, in accordance with the terms contained in | ||
** a written agreement between you and The Qt Company. For licensing terms | ||
** and conditions see https://www.qt.io/terms-conditions. For further | ||
** information use the contact form at https://www.qt.io/contact-us. | ||
** | ||
** GNU Lesser General Public License Usage | ||
** Alternatively, this file may be used under the terms of the GNU Lesser | ||
** General Public License version 3 as published by the Free Software | ||
** Foundation and appearing in the file LICENSE.LGPL3 included in the | ||
** packaging of this file. Please review the following information to | ||
** ensure the GNU Lesser General Public License version 3 requirements | ||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. | ||
** | ||
** GNU General Public License Usage | ||
** Alternatively, this file may be used under the terms of the GNU | ||
** General Public License version 2.0 or (at your option) the GNU General | ||
** Public license version 3 or any later version approved by the KDE Free | ||
** Qt Foundation. The licenses are as published by the Free Software | ||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 | ||
** included in the packaging of this file. Please review the following | ||
** information to ensure the GNU General Public License requirements will | ||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and | ||
** https://www.gnu.org/licenses/gpl-3.0.html. | ||
** | ||
** $QT_END_LICENSE$ | ||
** | ||
****************************************************************************/ | ||
|
||
#include <QtCore/QFile> | ||
|
||
#include "qedidparser_p.h" | ||
#include "qedidvendortable_p.h" | ||
|
||
#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) | ||
|
||
#define EDID_DESCRIPTOR_ALPHANUMERIC_STRING 0xfe | ||
#define EDID_DESCRIPTOR_PRODUCT_NAME 0xfc | ||
#define EDID_DESCRIPTOR_SERIAL_NUMBER 0xff | ||
|
||
#define EDID_OFFSET_DATA_BLOCKS 0x36 | ||
#define EDID_OFFSET_LAST_BLOCK 0x6c | ||
#define EDID_OFFSET_PNP_ID 0x08 | ||
#define EDID_OFFSET_SERIAL 0x0c | ||
#define EDID_PHYSICAL_WIDTH 0x15 | ||
#define EDID_OFFSET_PHYSICAL_HEIGHT 0x16 | ||
|
||
QT_BEGIN_NAMESPACE | ||
|
||
QEdidParser::QEdidParser() | ||
{ | ||
// Cache vendors list from pnp.ids | ||
const QString fileName = QLatin1String("/usr/share/hwdata/pnp.ids"); | ||
if (QFile::exists(fileName)) { | ||
QFile file(fileName); | ||
|
||
if (file.open(QFile::ReadOnly)) { | ||
while (!file.atEnd()) { | ||
QString line = QString::fromUtf8(file.readLine()).trimmed(); | ||
|
||
if (line.startsWith(QLatin1Char('#'))) | ||
continue; | ||
|
||
QStringList parts = line.split(QLatin1Char('\t')); | ||
if (parts.count() > 1) { | ||
QString pnpId = parts.at(0); | ||
parts.removeFirst(); | ||
m_vendorCache[pnpId] = parts.join(QLatin1Char(' ')); | ||
} | ||
} | ||
|
||
file.close(); | ||
} | ||
} | ||
} | ||
|
||
bool QEdidParser::parse(const QByteArray &blob) | ||
{ | ||
const quint8 *data = reinterpret_cast<const quint8 *>(blob.constData()); | ||
const size_t length = blob.length(); | ||
|
||
// Verify header | ||
if (length < 128) | ||
return false; | ||
if (data[0] != 0x00 || data[1] != 0xff) | ||
return false; | ||
|
||
/* Decode the PNP ID from three 5 bit words packed into 2 bytes | ||
* /--08--\/--09--\ | ||
* 7654321076543210 | ||
* |\---/\---/\---/ | ||
* R C1 C2 C3 */ | ||
char id[3]; | ||
id[0] = 'A' + ((data[EDID_OFFSET_PNP_ID] & 0x7c) / 4) - 1; | ||
id[1] = 'A' + ((data[EDID_OFFSET_PNP_ID] & 0x3) * 8) + ((data[EDID_OFFSET_PNP_ID + 1] & 0xe0) / 32) - 1; | ||
id[2] = 'A' + (data[EDID_OFFSET_PNP_ID + 1] & 0x1f) - 1; | ||
identifier = QString::fromLatin1(id, 3); | ||
|
||
// Clear manufacturer | ||
manufacturer = QString(); | ||
|
||
// Serial number, will be overwritten by an ASCII descriptor | ||
// when and if it will be found | ||
quint32 serial = data[EDID_OFFSET_SERIAL] | ||
+ (data[EDID_OFFSET_SERIAL + 1] << 8) | ||
+ (data[EDID_OFFSET_SERIAL + 2] << 16) | ||
+ (data[EDID_OFFSET_SERIAL + 3] << 24); | ||
if (serial > 0) | ||
serialNumber = QString::number(serial); | ||
else | ||
serialNumber = QString(); | ||
|
||
// Parse EDID data | ||
for (int i = 0; i < 5; ++i) { | ||
const uint offset = EDID_OFFSET_DATA_BLOCKS + i * 18; | ||
|
||
if (data[offset] != 0 || data[offset + 1] != 0 || data[offset + 2] != 0) | ||
continue; | ||
|
||
if (data[offset + 3] == EDID_DESCRIPTOR_PRODUCT_NAME) | ||
model = parseEdidString(&data[offset + 5]); | ||
else if (data[offset + 3] == EDID_DESCRIPTOR_ALPHANUMERIC_STRING) | ||
identifier = parseEdidString(&data[offset + 5]); | ||
else if (data[offset + 3] == EDID_DESCRIPTOR_SERIAL_NUMBER) | ||
serialNumber = parseEdidString(&data[offset + 5]); | ||
} | ||
|
||
// Try to use cache first because it is potentially more updated | ||
if (m_vendorCache.contains(identifier)) { | ||
manufacturer = m_vendorCache[identifier]; | ||
} else { | ||
// Find the manufacturer from the vendor lookup table | ||
for (size_t i = 0; i < ARRAY_LENGTH(q_edidVendorTable); i++) { | ||
if (strcmp(q_edidVendorTable[i].id, identifier.toLatin1().constData()) == 0) { | ||
manufacturer = QString::fromUtf8(q_edidVendorTable[i].name); | ||
break; | ||
} | ||
} | ||
} | ||
|
||
// If we don't know the manufacturer, fallback to PNP ID | ||
if (manufacturer.isEmpty()) | ||
manufacturer = identifier; | ||
|
||
// Physical size | ||
physicalSize = QSizeF(data[EDID_PHYSICAL_WIDTH], data[EDID_OFFSET_PHYSICAL_HEIGHT]) * 10; | ||
|
||
return true; | ||
} | ||
|
||
QString QEdidParser::parseEdidString(const quint8 *data) | ||
{ | ||
QByteArray buffer(reinterpret_cast<const char *>(data), 12); | ||
|
||
// Erase carriage return and line feed | ||
buffer = buffer.replace('\r', '\0').replace('\n', '\0'); | ||
|
||
// Replace non-printable characters with dash | ||
for (int i = 0; i < buffer.count(); ++i) { | ||
if (buffer[i] < '\040' && buffer[i] > '\176') | ||
buffer[i] = '-'; | ||
} | ||
|
||
return QString::fromLatin1(buffer.trimmed()); | ||
} | ||
|
||
QT_END_NAMESPACE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
/**************************************************************************** | ||
** | ||
** Copyright (C) 2017 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> | ||
** Contact: https://www.qt.io/licensing/ | ||
** | ||
** This file is part of the plugins of the Qt Toolkit. | ||
** | ||
** $QT_BEGIN_LICENSE:LGPL$ | ||
** Commercial License Usage | ||
** Licensees holding valid commercial Qt licenses may use this file in | ||
** accordance with the commercial license agreement provided with the | ||
** Software or, alternatively, in accordance with the terms contained in | ||
** a written agreement between you and The Qt Company. For licensing terms | ||
** and conditions see https://www.qt.io/terms-conditions. For further | ||
** information use the contact form at https://www.qt.io/contact-us. | ||
** | ||
** GNU Lesser General Public License Usage | ||
** Alternatively, this file may be used under the terms of the GNU Lesser | ||
** General Public License version 3 as published by the Free Software | ||
** Foundation and appearing in the file LICENSE.LGPL3 included in the | ||
** packaging of this file. Please review the following information to | ||
** ensure the GNU Lesser General Public License version 3 requirements | ||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. | ||
** | ||
** GNU General Public License Usage | ||
** Alternatively, this file may be used under the terms of the GNU | ||
** General Public License version 2.0 or (at your option) the GNU General | ||
** Public license version 3 or any later version approved by the KDE Free | ||
** Qt Foundation. The licenses are as published by the Free Software | ||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 | ||
** included in the packaging of this file. Please review the following | ||
** information to ensure the GNU General Public License requirements will | ||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and | ||
** https://www.gnu.org/licenses/gpl-3.0.html. | ||
** | ||
** $QT_END_LICENSE$ | ||
** | ||
****************************************************************************/ | ||
|
||
#ifndef QEDIDPARSER_P_H | ||
#define QEDIDPARSER_P_H | ||
|
||
#include <QtCore/QSize> | ||
#include <QtCore/QMap> | ||
|
||
// | ||
// W A R N I N G | ||
// ------------- | ||
// | ||
// This file is not part of the Qt API. It exists purely as an | ||
// implementation detail. This header file may change from version to | ||
// version without notice, or even be removed. | ||
// | ||
|
||
QT_BEGIN_NAMESPACE | ||
|
||
class QEdidParser | ||
{ | ||
public: | ||
QEdidParser(); | ||
|
||
bool parse(const QByteArray &blob); | ||
|
||
QString identifier; | ||
QString manufacturer; | ||
QString model; | ||
QString serialNumber; | ||
QSizeF physicalSize; | ||
|
||
private: | ||
QMap<QString, QString> m_vendorCache; | ||
|
||
QString parseEdidString(const quint8 *data); | ||
}; | ||
|
||
QT_END_NAMESPACE | ||
|
||
#endif // QEDIDPARSER_P_H |
Oops, something went wrong.