info: use PNP ID database for manufacturer names

The three character PNP ID is a key to manufacturer name database. It
may be desirable to report the manufacturer's real name than just PNP ID
which can be misleading, e.g. MSI refers to Microstep and not MSI GmbH.

This builds the PNP ID database into libdisplay-info to avoid having to
find and parse files at runtime.

tool/gen-search-table.py started as a copy of Wayland 1.21.0's
src/embed.py and took influence from
10945c4ed8/conv.py
However, our script parses the text file shipped in hwdata package in
Debian (and presumably other distributions) rather than the original
CSV.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
This commit is contained in:
Pekka Paalanen 2022-10-18 13:49:39 +03:00
parent 3c675db02f
commit ac857e8985
15 changed files with 134 additions and 13 deletions

View file

@ -35,7 +35,12 @@ follows the [freedesktop.org Contributor Covenant].
## Building ## Building
libdisplay-info is built using [Meson]. It has no dependencies. libdisplay-info has the following dependencies:
- [hwdata](https://github.com/vcrhonek/hwdata) for the PNP ID database
used at build-time only.
libdisplay-info is built using [Meson]:
meson setup build/ meson setup build/
ninja -C build/ ninja -C build/

11
info.c
View file

@ -8,6 +8,10 @@
#include "info.h" #include "info.h"
#include "log.h" #include "log.h"
/* Generated file pnp-id-table.c: */
const char *
pnp_id_table(const char *key);
struct di_info * struct di_info *
di_info_parse_edid(const void *data, size_t size) di_info_parse_edid(const void *data, size_t size)
{ {
@ -136,6 +140,7 @@ di_info_get_make(const struct di_info *info)
{ {
const struct di_edid_vendor_product *evp; const struct di_edid_vendor_product *evp;
char pnp_id[(sizeof(evp->manufacturer)) + 1] = { 0, }; char pnp_id[(sizeof(evp->manufacturer)) + 1] = { 0, };
const char *manuf;
struct memory_stream m; struct memory_stream m;
if (!info->edid) if (!info->edid)
@ -147,7 +152,11 @@ di_info_get_make(const struct di_info *info)
evp = di_edid_get_vendor_product(info->edid); evp = di_edid_get_vendor_product(info->edid);
memcpy(pnp_id, evp->manufacturer, sizeof(evp->manufacturer)); memcpy(pnp_id, evp->manufacturer, sizeof(evp->manufacturer));
/* TODO: use pnp.ids to convert to a company name */ manuf = pnp_id_table(pnp_id);
if (manuf) {
encode_ascii_string(m.fp, manuf);
return memory_stream_close(&m);
}
fputs("PNP(", m.fp); fputs("PNP(", m.fp);
encode_ascii_string(m.fp, pnp_id); encode_ascii_string(m.fp, pnp_id);

View file

@ -10,6 +10,21 @@ project(
], ],
) )
dep_hwdata = dependency('hwdata', required: false, native: true)
if dep_hwdata.found()
hwdata_dir = dep_hwdata.get_variable(pkgconfig: 'pkgdatadir')
pnp_ids = files(hwdata_dir / 'pnp.ids')
else
pnp_ids = files('/usr/share/hwdata/pnp.ids')
endif
gen_search_table = find_program('tool/gen-search-table.py')
pnp_id_table = custom_target(
'pnp-id-table.c',
command: [ gen_search_table, pnp_ids, '@OUTPUT@', 'pnp_id_table' ],
output: 'pnp-id-table.c',
)
cc = meson.get_compiler('c') cc = meson.get_compiler('c')
math = cc.find_library('m', required: false) math = cc.find_library('m', required: false)
@ -42,6 +57,7 @@ di_lib = library(
'gtf.c', 'gtf.c',
'info.c', 'info.c',
'log.c', 'log.c',
pnp_id_table,
], ],
include_directories: include_directories('include'), include_directories: include_directories('include'),
dependencies: [math], dependencies: [math],

View file

@ -1,3 +1,3 @@
make: PNP(ACR) make: Acer Technologies
model: P1276 model: P1276
serial: JGG110015900 serial: JGG110015900

View file

@ -1,3 +1,3 @@
make: PNP(APP) make: Apple Computer Inc
model: ProDisplayXDR model: ProDisplayXDR
serial: 0x250D0E02 serial: 0x250D0E02

View file

@ -1,3 +1,3 @@
make: PNP(LNX) make: The Linux Foundation
model: hdmi-4k-600 model: hdmi-4k-600
serial: {null} serial: {null}

View file

@ -1,3 +1,3 @@
make: PNP(DEL) make: Dell Inc.
model: DELL 2408WFP model: DELL 2408WFP
serial: G283H8BI21MS serial: G283H8BI21MS

View file

@ -1,3 +1,3 @@
make: PNP(GSM) make: LG Electronics
model: ITE6604 model: ITE6604
serial: 0x01010101 serial: 0x01010101

View file

@ -1,3 +1,3 @@
make: PNP(HPN) make: HP Inc.
model: HP 27 QD model: HP 27 QD
serial: CN49120J6N serial: CN49120J6N

View file

@ -1,3 +1,3 @@
make: PNP(MSI) make: Microstep
model: MAG321CURV model: MAG321CURV
serial: DA2A019360041 serial: DA2A019360041

View file

@ -1,3 +1,3 @@
make: PNP(MEI) make: Panasonic Industry Company
model: 0x96A2 model: 0x96A2
serial: {null} serial: {null}

View file

@ -1,3 +1,3 @@
make: PNP(SAM) make: Samsung Electric Company
model: S27A950D model: S27A950D
serial: {null} serial: {null}

View file

@ -1,3 +1,3 @@
make: PNP(SUN) make: Sun Electronics Corporation
model: GH19PS model: GH19PS
serial: 0432MR0406 serial: 0432MR0406

View file

@ -1,3 +1,3 @@
make: PNP(VSC) make: ViewSonic Corporation
model: VP2768 Series model: VP2768 Series
serial: UY5171500307 serial: UY5171500307

91
tool/gen-search-table.py Executable file
View file

@ -0,0 +1,91 @@
#!/usr/bin/env python3
"""
string to string mapping table
License: MIT
Copyright (c) 2020 Simon Ser
Copyright 2022 Collabora, Ltd.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
import sys
def escape_for_c(s):
l = [c if c.isalnum() or c in ' .,' else '\\%03o' % ord(c) for c in s]
return ''.join(l)
if len(sys.argv) != 4:
print('usage: ' + sys.argv[0] + ' <infile> <outfile> <ident>', file=sys.stderr)
sys.exit(1)
infile = sys.argv[1]
outfile = sys.argv[2]
ident = sys.argv[3]
records = {}
with open(infile, 'r') as f:
for line in f:
[pnpid, name] = line.split(maxsplit=1)
if len(pnpid) != 3:
print("Warning: skipping invalid PNP ID %s" % (repr(pnpid)), file=sys.stderr)
continue
records[pnpid] = escape_for_c(name.strip())
with open(outfile, 'w') as f:
f.write(
f'''
#include <string.h>
#include <stdint.h>
const char *
{ident}(const char *key);
const char *
{ident}(const char *key)
{{
size_t len = strlen(key);
size_t i;
uint32_t u = 0;
if (len > 4)
return NULL;
for (i = 0; i < len; i++)
u = (u << 8) | (uint8_t)key[i];
switch (u) {{
''')
for id in sorted(records.keys()):
u = 0
for c in id:
u = (u << 8) | ord(c)
f.write(f' case {u}: return "{records[id]}";\n')
f.write(
f'''
default:
return NULL;
}}
}}
''')