kdecore: KDeviceDatabase rewrite and test for it

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2022-04-29 13:42:03 +03:00
parent a70b97b0e2
commit eef792f6ff
17 changed files with 60868 additions and 43001 deletions

View file

@ -441,3 +441,9 @@ install(
DESTINATION ${KDE4_SERVICETYPES_INSTALL_DIR} DESTINATION ${KDE4_SERVICETYPES_INSTALL_DIR}
) )
install(
FILES
pci.ids
usb.ids
DESTINATION ${KDE4_DATA_INSTALL_DIR}/kdevicedatabase
)

View file

@ -1,82 +0,0 @@
#!/usr/bin/python3
# pci.ids can be obtained from:
# https://raw.githubusercontent.com/pciutils/pciids/master/pci.ids
import sys
def isvalidid(fromid):
if len(fromid) == 4:
return True
return False
def bytetostr(frombytes):
return frombytes.decode('utf-8')
def splitpciline(fromline):
doublespaceindex = fromline.index(b' ')
lineid = fromline[:doublespaceindex]
linename = fromline[doublespaceindex+2:]
# nested quotes
linename = linename.replace(b'"', b'\\"')
# what is the question?
linename = linename.replace(b'??', b'Unknown') # 036c
linename = linename.replace(b'???', b'Unknown') # 2a15
return (lineid, linename)
vendormap = {}
devicemap = {}
with open('./pci.ids', 'rb') as f:
ingroupsection = False
for line in f.readlines():
sline = line.strip()
if not sline or sline.startswith(b'#'):
continue;
elif line.startswith(b'\t\t'):
# subvendor
continue
elif line.startswith(b'C'):
ingroupsection = True
elif line.startswith(b'\t') and not ingroupsection:
deviceid, devicename = splitpciline(sline)
if b' ' in deviceid:
print('ranges are not supported: %s' % deviceid)
sys.exit(123)
if not isvalidid(deviceid):
continue
if not vendorid in devicemap.keys():
devicemap[vendorid] = []
devicemap[vendorid].append({'deviceid': deviceid, 'devicename': devicename })
else:
ingroupsection = False
vendorid, vendorname = splitpciline(sline)
if b' ' in vendorid:
print('ranges are not supported: %s' % vendorid)
sys.exit(123)
if not isvalidid(vendorid):
continue
vendormap[vendorid] = vendorname
print('''static const struct pciVendorTblData {
const char* const vendorid;
const char* const vendorname;
} pciVendorTbl[] = {''')
for vendorid in vendormap.keys():
print(' { "%s", "%s" },' % (bytetostr(vendorid), bytetostr(vendormap[vendorid])))
print('};')
print('static const size_t pciVendorTblSize = sizeof(pciVendorTbl) / sizeof(pciVendorTblData);')
print('')
print('''static const struct pciDeviceTblData {
const char* const vendorid;
const char* const deviceid;
const char* const devicename;
} pciDeviceTbl[] = {''')
for vendorid in devicemap.keys():
for devicedict in devicemap[vendorid]:
print(' { "%s", "%s", "%s" },' % (bytetostr(vendorid), bytetostr(devicedict['deviceid']), bytetostr(devicedict['devicename'])))
print('};')
print('static const size_t pciDeviceTblSize = sizeof(pciDeviceTbl) / sizeof(pciDeviceTblData);')

View file

@ -1,83 +0,0 @@
#!/usr/bin/python3
# usb.ids can be obtained from:
# http://www.linux-usb.org/usb.ids
import sys
def isvalidid(fromid):
if len(fromid) == 4:
return True
return False
def bytetostr(frombytes):
return frombytes.decode('utf-8')
def splitusbline(fromline):
doublespaceindex = fromline.index(b' ')
lineid = fromline[:doublespaceindex]
linename = fromline[doublespaceindex+2:]
# invalid escape sequence in C++
linename = linename.replace(b'\\', b'/') # 1400
# nested quotes
linename = linename.replace(b'"', b'\\"')
# what is the question?
linename = linename.replace(b'??', b'Unknown') # 1183
return (lineid, linename)
vendormap = {}
devicemap = {}
with open('./usb.ids', 'rb') as f:
ingroupsection = False
for line in f.readlines():
sline = line.strip()
if not sline or sline.startswith(b'#'):
continue;
elif line.startswith(b'\t\t'):
# subvendor
continue
elif line.startswith((b'C', b'AT', b'HID', b'R', b'BIAS', b'PHY', b'HUT', b'L', b'HCC', b'VT')):
ingroupsection = True
elif line.startswith(b'\t') and not ingroupsection:
deviceid, devicename = splitusbline(sline)
if b' ' in deviceid:
print('ranges are not supported: %s' % deviceid)
sys.exit(123)
if not isvalidid(deviceid):
continue
if not vendorid in devicemap.keys():
devicemap[vendorid] = []
devicemap[vendorid].append({'deviceid': deviceid, 'devicename': devicename })
else:
ingroupsection = False
vendorid, vendorname = splitusbline(sline)
if b' ' in vendorid:
print('ranges are not supported: %s' % vendorid)
sys.exit(123)
if not isvalidid(vendorid):
continue
vendormap[vendorid] = vendorname
print('''static const struct usbVendorTblData {
const char* const vendorid;
const char* const vendorname;
} usbVendorTbl[] = {''')
for vendorid in vendormap.keys():
print(' { "%s", "%s" },' % (bytetostr(vendorid), bytetostr(vendormap[vendorid])))
print('};')
print('static const size_t usbVendorTblSize = sizeof(usbVendorTbl) / sizeof(usbVendorTblData);')
print('')
print('''static const struct usbDeviceTblData {
const char* const vendorid;
const char* const deviceid;
const char* const devicename;
} usbDeviceTbl[] = {''')
for vendorid in devicemap.keys():
for devicedict in devicemap[vendorid]:
print(' { "%s", "%s", "%s" },' % (bytetostr(vendorid), bytetostr(devicedict['deviceid']), bytetostr(devicedict['devicename'])))
print('};')
print('static const size_t usbDeviceTblSize = sizeof(usbDeviceTbl) / sizeof(usbDeviceTblData);')

35086
kdecore/pci.ids Normal file

File diff suppressed because it is too large Load diff

10
kdecore/regen.sh Executable file
View file

@ -0,0 +1,10 @@
#!/bin/sh
set -e
# a little helper script to fetch PCI and USB IDs databases
rm -vf pci.ids usb.ids
wget https://raw.githubusercontent.com/pciutils/pciids/master/pci.ids
wget http://www.linux-usb.org/usb.ids

View file

@ -1,5 +1,7 @@
#!/bin/sh #!/bin/sh
set -e
# a little helper script to regenerate yacc.[c,h] and lex.c # a little helper script to regenerate yacc.[c,h] and lex.c
YACC="bison" YACC="bison"

View file

@ -63,6 +63,7 @@ KDECORE_UNIT_TESTS(
kdebug_qcoreapptest kdebug_qcoreapptest
kmimetype_nomimetypes kmimetype_nomimetypes
kunitconversiontest kunitconversiontest
kdevicedatabasetest
) )
KDECORE_EXECUTABLE_TESTS( KDECORE_EXECUTABLE_TESTS(

View file

@ -0,0 +1,57 @@
/* This file is part of the KDE libraries
Copyright (C) 2022 Ivailo Monev <xakepa10@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2, as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "kdevicedatabasetest.h"
#include "qtest_kde.h"
QTEST_KDEMAIN_CORE(KDeviceDatabaseTest)
void KDeviceDatabaseTest::initTestCase()
{
const QString pcivendor = m_devicedb.lookupPCIVendor("0001");
const QString usbvendor = m_devicedb.lookupUSBVendor("0001");
m_iskdelibsinstalled = (!pcivendor.isEmpty() && !usbvendor.isEmpty());
}
void KDeviceDatabaseTest::testPCI()
{
if (!m_iskdelibsinstalled) {
QSKIP("kdelibs not installed", SkipAll);
}
QCOMPARE(m_devicedb.lookupPCIVendor("0001"), QLatin1String("SafeNet (wrong ID)"));
QCOMPARE(m_devicedb.lookupPCIDevice("0010", "8139"), QLatin1String("AT-2500TX V3 Ethernet"));
QCOMPARE(m_devicedb.lookupPCIClass("00"), QLatin1String("Unclassified device"));
QCOMPARE(m_devicedb.lookupPCISubClass("00", "00"), QLatin1String("Non-VGA unclassified device"));
QCOMPARE(m_devicedb.lookupPCIProtocol("01", "01", "00"), QLatin1String("ISA Compatibility mode-only controller"));
}
void KDeviceDatabaseTest::testUSB()
{
if (!m_iskdelibsinstalled) {
QSKIP("kdelibs not installed", SkipAll);
}
QCOMPARE(m_devicedb.lookupUSBVendor("0001"), QLatin1String("Fry's Electronics"));
QCOMPARE(m_devicedb.lookupUSBDevice("0001", "7778"), QLatin1String("Counterfeit flash drive [Kingston]"));
QCOMPARE(m_devicedb.lookupUSBClass("00"), QLatin1String("(Defined at Interface level)"));
QCOMPARE(m_devicedb.lookupUSBSubClass("01", "01"), QLatin1String("Control Device"));
QCOMPARE(m_devicedb.lookupUSBProtocol("02", "02", "00"), QLatin1String("None"));
}
#include "moc_kdevicedatabasetest.cpp"

View file

@ -0,0 +1,40 @@
/* This file is part of the KDE libraries
Copyright (C) 2022 Ivailo Monev <xakepa10@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2, as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KDEVICEDATABASETEST_H
#define KDEVICEDATABASETEST_H
#include "kdevicedatabase.h"
#include <QtCore/QObject>
class KDeviceDatabaseTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
void testPCI();
void testUSB();
private:
bool m_iskdelibsinstalled;
KDeviceDatabase m_devicedb;
};
#endif // KDEVICEDATABASETEST_H

25236
kdecore/usb.ids Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -23,33 +23,67 @@
#include <QString> #include <QString>
class KDeviceDatabasePrivate;
/*! /*!
Class for obtaining device product and vendor strings from their IDs Class for obtaining device product and vendor strings from their IDs
IDs should be either 4 or 6 characters long, e.g. "1d14" or "0x1d14" Vendor and device IDs should be either 4 or 6 characters long, e.g. "1d14" or "0x1d14". Class,
sub-class and protocol IDs should be 2 characters long, e.g. "0b"
@since 4.21 @since 4.21
*/ */
class KDECORE_EXPORT KDeviceDatabase class KDECORE_EXPORT KDeviceDatabase
{ {
public: public:
/*! KDeviceDatabase();
@return The vendor for @p vendorid, empty string if unknown
*/
static QString lookupPCIVendor(const QByteArray &vendorid);
/*!
@return The device for @p vendorid and @p deviceid, empty string if unknown
*/
static QString lookupPCIDevice(const QByteArray &vendorid, const QByteArray &deviceid);
/*! /*!
@return The vendor for @p vendorid, empty string if unknown @return The vendor for @p vendorid, empty string if unknown
*/ */
static QString lookupUSBVendor(const QByteArray &vendorid); QString lookupPCIVendor(const QByteArray &vendorid);
/*! /*!
@return The device for @p vendorid and @p deviceid, empty string if unknown @return The device for @p vendorid and @p deviceid, empty string if unknown
*/ */
static QString lookupUSBDevice(const QByteArray &vendorid, const QByteArray &deviceid); QString lookupPCIDevice(const QByteArray &vendorid, const QByteArray &deviceid);
/*!
@return The class for @p classid, empty string if unknown
*/
QString lookupPCIClass(const QByteArray &classid);
/*!
@return The subclass for @p classid and @p subclassid, empty string if unknown
*/
QString lookupPCISubClass(const QByteArray &classid, const QByteArray &subclassid);
/*!
@return The protocol for @p classid, @p subclassid and @p protocolid, empty string if unknown
*/
QString lookupPCIProtocol(const QByteArray &classid, const QByteArray &subclassid, const QByteArray &protocolid);
/*!
@return The vendor for @p vendorid, empty string if unknown
*/
QString lookupUSBVendor(const QByteArray &vendorid);
/*!
@return The device for @p vendorid and @p deviceid, empty string if unknown
*/
QString lookupUSBDevice(const QByteArray &vendorid, const QByteArray &deviceid);
/*!
@return The class for @p classid, empty string if unknown
*/
QString lookupUSBClass(const QByteArray &classid);
/*!
@return The subclass for @p classid and @p subclassid, empty string if unknown
*/
QString lookupUSBSubClass(const QByteArray &classid, const QByteArray &subclassid);
/*!
@return The protocol for @p classid, @p subclassid and @p protocolid, empty string if unknown
*/
QString lookupUSBProtocol(const QByteArray &classid, const QByteArray &subclassid, const QByteArray &protocolid);
private:
Q_DISABLE_COPY(KDeviceDatabase);
KDeviceDatabasePrivate *d;
}; };
#endif // KDEVICEDATABASE_H #endif // KDEVICEDATABASE_H

View file

@ -25,7 +25,6 @@
#include "devinfographic.h" #include "devinfographic.h"
#include <QDebug> #include <QDebug>
#include "kdevicedatabase.h"
#include <sys/types.h> #include <sys/types.h>
#include <sys/sysctl.h> #include <sys/sysctl.h>
@ -133,9 +132,9 @@ QString DevinfoDevice::vendor() const
const QByteArray parent = deviceProperty(DevinfoDevice::DeviceParent); const QByteArray parent = deviceProperty(DevinfoDevice::DeviceParent);
QString result; QString result;
if (parent.contains("pci")) { if (parent.contains("pci")) {
result = KDeviceDatabase::lookupPCIVendor(pnpvendor); result = m_devicedb.lookupPCIVendor(pnpvendor);
} else { } else {
result = KDeviceDatabase::lookupUSBVendor(pnpvendor); result = m_devicedb.lookupUSBVendor(pnpvendor);
} }
return result; return result;
@ -164,9 +163,9 @@ QString DevinfoDevice::product() const
const QByteArray parent = deviceProperty(DevinfoDevice::DeviceParent); const QByteArray parent = deviceProperty(DevinfoDevice::DeviceParent);
QString result; QString result;
if (parent.contains("pci")) { if (parent.contains("pci")) {
result = KDeviceDatabase::lookupPCIDevice(pnpvendor, pnpdevice); result = m_devicedb.lookupPCIDevice(pnpvendor, pnpdevice);
} else { } else {
result = KDeviceDatabase::lookupUSBDevice(pnpvendor, pnpdevice); result = m_devicedb.lookupUSBDevice(pnpvendor, pnpdevice);
} }
return result; return result;

View file

@ -24,6 +24,8 @@
#include <solid/ifaces/device.h> #include <solid/ifaces/device.h>
#include <QtCore/QStringList> #include <QtCore/QStringList>
#include "kdevicedatabase.h"
namespace Solid namespace Solid
{ {
namespace Backends namespace Backends
@ -77,6 +79,7 @@ private:
QString m_device; QString m_device;
QMap<DeviceProperty, QByteArray> m_properties; QMap<DeviceProperty, QByteArray> m_properties;
QMap<PnPInfo, QByteArray> m_pnpinfo; QMap<PnPInfo, QByteArray> m_pnpinfo;
mutable KDeviceDatabase m_devicedb;
}; };
} }

View file

@ -37,7 +37,6 @@
#include "udevmanager.h" #include "udevmanager.h"
#include "cpuinfo.h" #include "cpuinfo.h"
#include "kdevicedatabase.h"
#include "kglobal.h" #include "kglobal.h"
#include "klocale.h" #include "klocale.h"
@ -102,9 +101,9 @@ QString UDevDevice::vendor() const
if (!idvendorid.isEmpty()) { if (!idvendorid.isEmpty()) {
const QString idbus(m_device.deviceProperty("ID_BUS")); const QString idbus(m_device.deviceProperty("ID_BUS"));
if (idbus == QLatin1String("pci")) { if (idbus == QLatin1String("pci")) {
vendor = KDeviceDatabase::lookupPCIVendor(idvendorid); vendor = m_devicedb.lookupPCIVendor(idvendorid);
} else if (idbus == QLatin1String("usb")) { } else if (idbus == QLatin1String("usb")) {
vendor = KDeviceDatabase::lookupUSBVendor(idvendorid); vendor = m_devicedb.lookupUSBVendor(idvendorid);
} }
} }
} }
@ -146,9 +145,9 @@ QString UDevDevice::product() const
if (!idvendorid.isEmpty() && !idmodelid.isEmpty()) { if (!idvendorid.isEmpty() && !idmodelid.isEmpty()) {
const QString idbus(m_device.deviceProperty("ID_BUS")); const QString idbus(m_device.deviceProperty("ID_BUS"));
if (idbus == QLatin1String("pci")) { if (idbus == QLatin1String("pci")) {
product = KDeviceDatabase::lookupPCIDevice(idvendorid, idmodelid); product = m_devicedb.lookupPCIDevice(idvendorid, idmodelid);
} else if (idbus == QLatin1String("usb")) { } else if (idbus == QLatin1String("usb")) {
product = KDeviceDatabase::lookupUSBDevice(idvendorid, idmodelid); product = m_devicedb.lookupUSBDevice(idvendorid, idmodelid);
} }
} }
} }

View file

@ -22,6 +22,7 @@
#define SOLID_BACKENDS_UDEV_UDEVDEVICE_H #define SOLID_BACKENDS_UDEV_UDEVDEVICE_H
#include "udevqt.h" #include "udevqt.h"
#include "kdevicedatabase.h"
#include <solid/ifaces/device.h> #include <solid/ifaces/device.h>
#include <QtCore/QStringList> #include <QtCore/QStringList>
@ -63,6 +64,7 @@ private:
friend class AcAdapter; friend class AcAdapter;
friend class Battery; friend class Battery;
UdevQt::Device m_device; UdevQt::Device m_device;
mutable KDeviceDatabase m_devicedb;
}; };
} }

View file

@ -1,5 +1,7 @@
#!/bin/sh #!/bin/sh
set -e
# a little helper script to regenerate predicate_parser.[c,h] and predicate_lexer.c # a little helper script to regenerate predicate_parser.[c,h] and predicate_lexer.c
YACC="bison" YACC="bison"