mirror of
https://gitlab.freedesktop.org/emersion/libdisplay-info.git
synced 2024-12-26 21:59:15 +01:00
ac857e8985
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>
226 lines
4.3 KiB
C
226 lines
4.3 KiB
C
#include <inttypes.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
|
|
#include "edid.h"
|
|
#include "info.h"
|
|
#include "log.h"
|
|
|
|
/* Generated file pnp-id-table.c: */
|
|
const char *
|
|
pnp_id_table(const char *key);
|
|
|
|
struct di_info *
|
|
di_info_parse_edid(const void *data, size_t size)
|
|
{
|
|
struct di_edid *edid;
|
|
struct di_info *info;
|
|
char *failure_msg = NULL;
|
|
size_t failure_msg_size;
|
|
FILE *failure_msg_file;
|
|
|
|
failure_msg_file = open_memstream(&failure_msg,
|
|
&failure_msg_size);
|
|
if (!failure_msg_file)
|
|
return NULL;
|
|
|
|
edid = _di_edid_parse(data, size, failure_msg_file);
|
|
if (!edid)
|
|
goto err_failure_msg_file;
|
|
|
|
info = calloc(1, sizeof(*info));
|
|
if (!info)
|
|
goto err_edid;
|
|
|
|
info->edid = edid;
|
|
|
|
if (fflush(failure_msg_file) != 0)
|
|
goto err_info;
|
|
fclose(failure_msg_file);
|
|
if (failure_msg && failure_msg[0] != '\0')
|
|
info->failure_msg = failure_msg;
|
|
else
|
|
free(failure_msg);
|
|
|
|
return info;
|
|
|
|
err_info:
|
|
free(info);
|
|
err_edid:
|
|
_di_edid_destroy(edid);
|
|
err_failure_msg_file:
|
|
fclose(failure_msg_file);
|
|
free(failure_msg);
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
di_info_destroy(struct di_info *info)
|
|
{
|
|
_di_edid_destroy(info->edid);
|
|
free(info->failure_msg);
|
|
free(info);
|
|
}
|
|
|
|
const struct di_edid *
|
|
di_info_get_edid(const struct di_info *info)
|
|
{
|
|
return info->edid;
|
|
}
|
|
|
|
const char *
|
|
di_info_get_failure_msg(const struct di_info *info)
|
|
{
|
|
return info->failure_msg;
|
|
}
|
|
|
|
struct memory_stream {
|
|
FILE *fp;
|
|
char *str;
|
|
size_t str_len;
|
|
};
|
|
|
|
static bool
|
|
memory_stream_open(struct memory_stream *m)
|
|
{
|
|
*m = (struct memory_stream){ 0 };
|
|
m->fp = open_memstream(&m->str, &m->str_len);
|
|
|
|
return m->fp != NULL;
|
|
}
|
|
|
|
static char *
|
|
memory_stream_close(struct memory_stream *m)
|
|
{
|
|
char *str;
|
|
int ret;
|
|
|
|
ret = fclose(m->fp);
|
|
str = m->str;
|
|
*m = (struct memory_stream){ 0 };
|
|
|
|
if (ret != 0) {
|
|
free(str);
|
|
str = NULL;
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
static void
|
|
encode_ascii_byte(FILE *out, char ch)
|
|
{
|
|
uint8_t c = (uint8_t)ch;
|
|
|
|
/*
|
|
* Replace ASCII control codes and non-7-bit codes
|
|
* with an escape string. The result is guaranteed to be valid
|
|
* UTF-8.
|
|
*/
|
|
if (c < 0x20 || c >= 0x7f)
|
|
fprintf(out, "\\x%02x", c);
|
|
else
|
|
fputc(c, out);
|
|
}
|
|
|
|
static void
|
|
encode_ascii_string(FILE *out, const char *str)
|
|
{
|
|
size_t len = strlen(str);
|
|
size_t i;
|
|
|
|
for (i = 0; i < len; i++)
|
|
encode_ascii_byte(out, str[i]);
|
|
}
|
|
|
|
char *
|
|
di_info_get_make(const struct di_info *info)
|
|
{
|
|
const struct di_edid_vendor_product *evp;
|
|
char pnp_id[(sizeof(evp->manufacturer)) + 1] = { 0, };
|
|
const char *manuf;
|
|
struct memory_stream m;
|
|
|
|
if (!info->edid)
|
|
return NULL;
|
|
|
|
if (!memory_stream_open(&m))
|
|
return NULL;
|
|
|
|
evp = di_edid_get_vendor_product(info->edid);
|
|
memcpy(pnp_id, evp->manufacturer, sizeof(evp->manufacturer));
|
|
|
|
manuf = pnp_id_table(pnp_id);
|
|
if (manuf) {
|
|
encode_ascii_string(m.fp, manuf);
|
|
return memory_stream_close(&m);
|
|
}
|
|
|
|
fputs("PNP(", m.fp);
|
|
encode_ascii_string(m.fp, pnp_id);
|
|
fputs(")", m.fp);
|
|
|
|
return memory_stream_close(&m);
|
|
}
|
|
|
|
char *
|
|
di_info_get_model(const struct di_info *info)
|
|
{
|
|
const struct di_edid_vendor_product *evp;
|
|
const struct di_edid_display_descriptor *const *desc;
|
|
struct memory_stream m;
|
|
size_t i;
|
|
|
|
if (!info->edid)
|
|
return NULL;
|
|
|
|
if (!memory_stream_open(&m))
|
|
return NULL;
|
|
|
|
desc = di_edid_get_display_descriptors(info->edid);
|
|
for (i = 0; desc[i]; i++) {
|
|
if (di_edid_display_descriptor_get_tag(desc[i]) == DI_EDID_DISPLAY_DESCRIPTOR_PRODUCT_NAME) {
|
|
encode_ascii_string(m.fp, di_edid_display_descriptor_get_string(desc[i]));
|
|
return memory_stream_close(&m);
|
|
}
|
|
}
|
|
|
|
evp = di_edid_get_vendor_product(info->edid);
|
|
fprintf(m.fp, "0x%04" PRIX16, evp->product);
|
|
|
|
return memory_stream_close(&m);
|
|
}
|
|
|
|
char *
|
|
di_info_get_serial(const struct di_info *info)
|
|
{
|
|
const struct di_edid_display_descriptor *const *desc;
|
|
const struct di_edid_vendor_product *evp;
|
|
struct memory_stream m;
|
|
size_t i;
|
|
|
|
if (!info->edid)
|
|
return NULL;
|
|
|
|
if (!memory_stream_open(&m))
|
|
return NULL;
|
|
|
|
desc = di_edid_get_display_descriptors(info->edid);
|
|
for (i = 0; desc[i]; i++) {
|
|
if (di_edid_display_descriptor_get_tag(desc[i]) == DI_EDID_DISPLAY_DESCRIPTOR_PRODUCT_SERIAL) {
|
|
encode_ascii_string(m.fp, di_edid_display_descriptor_get_string(desc[i]));
|
|
return memory_stream_close(&m);
|
|
}
|
|
}
|
|
|
|
evp = di_edid_get_vendor_product(info->edid);
|
|
if (evp->serial != 0) {
|
|
fprintf(m.fp, "0x%08" PRIX32, evp->serial);
|
|
return memory_stream_close(&m);
|
|
}
|
|
|
|
free(memory_stream_close(&m));
|
|
return NULL;
|
|
}
|