Compare commits
8 Commits
b185d7ef15
...
f3e431b35e
Author | SHA1 | Date |
---|---|---|
![]() |
f3e431b35e | |
![]() |
8afbcd491e | |
![]() |
2f6b0c244c | |
![]() |
e9d6996138 | |
![]() |
f4c98204d1 | |
![]() |
162e5a40c2 | |
![]() |
f5a6eb610c | |
![]() |
a2f7f4c70d |
|
@ -1091,7 +1091,7 @@ io.systemd.credential:vmm.notify_socket=vsock-stream:2:254570042
|
|||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
<title><command>systemd-analyze chid</command></title>
|
||||
<title><command>systemd-analyze chid <optional>/sys/class/drm/<card>/edid</optional></command></title>
|
||||
|
||||
<para>Shows a list of Computer Hardware IDs (CHIDs) of the local system. These IDs identify the
|
||||
system's computer hardware, based on SMBIOS data. See <ulink
|
||||
|
|
|
@ -3,27 +3,42 @@
|
|||
#include "analyze.h"
|
||||
#include "analyze-chid.h"
|
||||
#include "chid-fundamental.h"
|
||||
#include "device-util.h"
|
||||
#include "dirent-util.h"
|
||||
#include "edid-fundamental.h"
|
||||
#include "efi-api.h"
|
||||
#include "escape.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "format-table.h"
|
||||
#include "parse-util.h"
|
||||
#include "sd-device.h"
|
||||
#include "strv.h"
|
||||
#include "utf8.h"
|
||||
#include "virt.h"
|
||||
|
||||
static int parse_chid_type(const char *s, size_t *ret) {
|
||||
char *e;
|
||||
unsigned u;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
|
||||
r = safe_atou(s, &u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (u >= CHID_TYPES_MAX)
|
||||
return -ERANGE;
|
||||
if ((e = startswith(s, "ext"))) {
|
||||
r = safe_atou(e, &u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (u >= CHID_TYPES_MAX - EXTRA_CHID_BASE)
|
||||
return -ERANGE;
|
||||
u += EXTRA_CHID_BASE;
|
||||
} else {
|
||||
r = safe_atou(s, &u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (u >= EXTRA_CHID_BASE)
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
|
||||
if (ret)
|
||||
*ret = u;
|
||||
|
@ -43,6 +58,7 @@ static const char *const chid_smbios_friendly[_CHID_SMBIOS_FIELDS_MAX] = {
|
|||
[CHID_SMBIOS_BIOS_MAJOR] = "bios-major",
|
||||
[CHID_SMBIOS_BIOS_MINOR] = "bios-minor",
|
||||
[CHID_SMBIOS_ENCLOSURE_TYPE] = "enclosure-type",
|
||||
[CHID_EDID_PANEL] = "edid-panel",
|
||||
};
|
||||
|
||||
static const char chid_smbios_fields_char[_CHID_SMBIOS_FIELDS_MAX] = {
|
||||
|
@ -57,6 +73,7 @@ static const char chid_smbios_fields_char[_CHID_SMBIOS_FIELDS_MAX] = {
|
|||
[CHID_SMBIOS_BIOS_MAJOR] = 'R',
|
||||
[CHID_SMBIOS_BIOS_MINOR] = 'r',
|
||||
[CHID_SMBIOS_ENCLOSURE_TYPE] = 'e',
|
||||
[CHID_EDID_PANEL] = 'E',
|
||||
};
|
||||
|
||||
static char *chid_smbios_fields_string(uint32_t combination) {
|
||||
|
@ -90,10 +107,17 @@ static int add_chid(Table *table, const EFI_GUID guids[static CHID_TYPES_MAX], s
|
|||
if (!flags)
|
||||
return log_oom();
|
||||
|
||||
|
||||
if (t < EXTRA_CHID_BASE)
|
||||
r = table_add_many(table, TABLE_UINT, (unsigned) t);
|
||||
else
|
||||
r = table_add_cell_stringf(table, NULL, "ext%zu", t - EXTRA_CHID_BASE);
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
|
||||
r = table_add_many(table,
|
||||
TABLE_UINT, (unsigned) t,
|
||||
TABLE_STRING, flags,
|
||||
TABLE_UUID, id);
|
||||
TABLE_STRING, flags,
|
||||
TABLE_UUID, id);
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
|
||||
|
@ -223,6 +247,71 @@ static int smbios_fields_acquire(char16_t *fields[static _CHID_SMBIOS_FIELDS_MAX
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int edid_parse(sd_device *drm_card, char16_t **ret_panel) {
|
||||
assert(drm_card);
|
||||
assert(ret_panel);
|
||||
int r;
|
||||
const char *edid_content = NULL;
|
||||
size_t edid_size = 0;
|
||||
r = sd_device_get_sysattr_value_full(drm_card, "edid", &edid_content, &edid_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (edid_size == 0)
|
||||
return -ENODEV;
|
||||
|
||||
EdidHeader header;
|
||||
if (!edid_parse_blob(edid_content, edid_size, &header))
|
||||
return -EBADMSG;
|
||||
|
||||
_cleanup_free_ char16_t *panel_id = new0(char16_t, 8);
|
||||
if (!panel_id)
|
||||
return log_oom();
|
||||
|
||||
if (!edid_get_panel_id(&header, panel_id))
|
||||
return -EBADMSG;
|
||||
|
||||
*ret_panel = TAKE_PTR(panel_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int edid_search(char16_t **ret_panel) {
|
||||
assert(ret_panel);
|
||||
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
|
||||
int r, n = 0;
|
||||
|
||||
r = sd_device_enumerator_new(&e);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_device_enumerator_allow_uninitialized(e);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_device_enumerator_add_match_subsystem(e, "drm", true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
FOREACH_DEVICE(e, d) {
|
||||
const char *drm_path = NULL;
|
||||
r = edid_parse(d, ret_panel);
|
||||
if (r == -ENOENT)
|
||||
continue;
|
||||
if (r < 0) {
|
||||
r = sd_device_get_syspath(d, &drm_path);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to get DRM device path: %m");
|
||||
log_debug("Skipping DRM device with invalid EDID: %s", drm_path);
|
||||
continue;
|
||||
}
|
||||
n++;
|
||||
if (n > 1)
|
||||
return -ENOTUNIQ;
|
||||
|
||||
}
|
||||
|
||||
return n = 0 ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
int verb_chid(int argc, char *argv[], void *userdata) {
|
||||
|
||||
_cleanup_(table_unrefp) Table *table = NULL;
|
||||
|
@ -243,6 +332,30 @@ int verb_chid(int argc, char *argv[], void *userdata) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (arg_drm_card_path) {
|
||||
_cleanup_(sd_device_unrefp) sd_device *drm_card = NULL;
|
||||
r = sd_device_new_from_path(&drm_card, arg_drm_card_path);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to open device %s: %m", arg_drm_card_path);
|
||||
|
||||
const char *subsys = NULL;
|
||||
r = sd_device_get_subsystem(drm_card, &subsys);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get subsystem for device %s: %m", arg_drm_card_path);
|
||||
if (!streq(subsys, "drm"))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot read EDID from a \"%s\" device", subsys);
|
||||
|
||||
r = edid_parse(drm_card, &smbios_fields[CHID_EDID_PANEL]);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse EDID for device %s: %m", arg_drm_card_path);
|
||||
} else {
|
||||
r = edid_search(&smbios_fields[CHID_EDID_PANEL]);
|
||||
if (r == -ENOTUNIQ)
|
||||
return log_error_errno(r, "Detected multiple monitors, use --drm-card option");
|
||||
else if (r != -ENODEV && r < 0)
|
||||
return log_error_errno(r, "Failed to find a valid EDID: %m");
|
||||
}
|
||||
|
||||
EFI_GUID chids[CHID_TYPES_MAX] = {};
|
||||
chid_calculate((const char16_t* const*) smbios_fields, chids);
|
||||
|
||||
|
@ -257,7 +370,7 @@ int verb_chid(int argc, char *argv[], void *userdata) {
|
|||
size_t t;
|
||||
r = parse_chid_type(*as, &t);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to pare CHID type: %s", *as);
|
||||
return log_error_errno(r, "Failed to parse CHID type: %s", *as);
|
||||
|
||||
r = add_chid(table, chids, t);
|
||||
if (r < 0)
|
||||
|
|
|
@ -121,12 +121,14 @@ char *arg_profile = NULL;
|
|||
bool arg_legend = true;
|
||||
bool arg_table = false;
|
||||
ImagePolicy *arg_image_policy = NULL;
|
||||
char *arg_drm_card_path = NULL;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_dot_from_patterns, strv_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_dot_to_patterns, strv_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_security_policy, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_drm_card_path, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_unit, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_profile, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
|
||||
|
@ -287,6 +289,8 @@ static int help(int argc, char *argv[], void *userdata) {
|
|||
" --image=PATH Operate on disk image as filesystem root\n"
|
||||
" --image-policy=POLICY Specify disk image dissection policy\n"
|
||||
" -m --mask Parse parameter as numeric capability mask\n"
|
||||
" --drm-card=PATH Use this DRM card to get EDID\n"
|
||||
|
||||
"\nSee the %2$s for details.\n",
|
||||
program_invocation_short_name,
|
||||
link,
|
||||
|
@ -333,6 +337,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
ARG_TLDR,
|
||||
ARG_SCALE_FACTOR_SVG,
|
||||
ARG_DETAILED_SVG,
|
||||
ARG_DRM_CARD_PATH,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
|
@ -371,6 +376,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
{ "mask", no_argument, NULL, 'm' },
|
||||
{ "scale-svg", required_argument, NULL, ARG_SCALE_FACTOR_SVG },
|
||||
{ "detailed", no_argument, NULL, ARG_DETAILED_SVG },
|
||||
{ "drm-card", required_argument, NULL, ARG_DRM_CARD_PATH },
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -580,6 +586,12 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
arg_detailed_svg = true;
|
||||
break;
|
||||
|
||||
case ARG_DRM_CARD_PATH:
|
||||
r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_drm_card_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -638,6 +650,9 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
if (arg_capability != CAPABILITY_LITERAL && !streq_ptr(argv[optind], "capability"))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Option --mask is only supported for capability.");
|
||||
|
||||
if (arg_drm_card_path && !streq_ptr(argv[optind], "chid"))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Option --drm-card is only supported for chid right now.");
|
||||
|
||||
return 1; /* work to do */
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@ extern char *arg_profile;
|
|||
extern bool arg_legend;
|
||||
extern bool arg_table;
|
||||
extern ImagePolicy *arg_image_policy;
|
||||
extern char *arg_drm_card_path;
|
||||
|
||||
int acquire_bus(sd_bus **bus, bool *use_full_bus);
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "chid.h"
|
||||
#include "chid-fundamental.h"
|
||||
#include "edid.h"
|
||||
#include "efi.h"
|
||||
#include "sha1-fundamental.h"
|
||||
#include "smbios.h"
|
||||
|
@ -72,6 +73,8 @@ static void smbios_info_populate(SmbiosInfo *ret_info) {
|
|||
ret_info->smbios_fields[CHID_SMBIOS_FAMILY] = smbios_to_hashable_string(raw.family);
|
||||
ret_info->smbios_fields[CHID_SMBIOS_BASEBOARD_PRODUCT] = smbios_to_hashable_string(raw.baseboard_product);
|
||||
ret_info->smbios_fields[CHID_SMBIOS_BASEBOARD_MANUFACTURER] = smbios_to_hashable_string(raw.baseboard_manufacturer);
|
||||
|
||||
edid_get_discovered_panel_id(&ret_info->smbios_fields[CHID_EDID_PANEL]);
|
||||
}
|
||||
|
||||
static void smbios_info_done(SmbiosInfo *info) {
|
||||
|
@ -100,7 +103,7 @@ EFI_STATUS chid_match(const void *hwid_buffer, size_t hwid_length, uint32_t matc
|
|||
const Device *devices = ASSERT_PTR(hwid_buffer);
|
||||
|
||||
EFI_GUID chids[CHID_TYPES_MAX] = {};
|
||||
static const size_t priority[] = { 3, 6, 8, 10, 4, 5, 7, 9, 11 }; /* From most to least specific. */
|
||||
static const size_t priority[] = { 17, 16, 15, 3, 6, 8, 10, 4, 5, 7, 9, 11 }; /* From most to least specific. */
|
||||
|
||||
status = populate_board_chids(chids);
|
||||
if (EFI_STATUS_IS_ERROR(status))
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "edid.h"
|
||||
#include "edid-fundamental.h"
|
||||
#include "log.h"
|
||||
#include "proto/edid-discovered.h"
|
||||
#include "util.h"
|
||||
|
||||
EFI_STATUS edid_get_discovered_panel_id(char16_t **ret_panel) {
|
||||
assert(ret_panel);
|
||||
EFI_EDID_DISCOVERED_PROTOCOL *edid_discovered = NULL;
|
||||
EFI_STATUS status = BS->LocateProtocol(MAKE_GUID_PTR(EFI_EDID_DISCOVERED_PROTOCOL), NULL, (void **) &edid_discovered);
|
||||
if (EFI_STATUS_IS_ERROR(status))
|
||||
return status;
|
||||
|
||||
if (!edid_discovered)
|
||||
return EFI_UNSUPPORTED;
|
||||
if (!edid_discovered->Edid)
|
||||
return EFI_UNSUPPORTED;
|
||||
if (edid_discovered->SizeOfEdid == 0)
|
||||
return EFI_UNSUPPORTED;
|
||||
|
||||
/* EDID size is at least 128 as per the specification */
|
||||
if (edid_discovered->SizeOfEdid < 128)
|
||||
return EFI_BUFFER_TOO_SMALL;
|
||||
|
||||
EdidHeader header;
|
||||
if (!edid_parse_blob(edid_discovered->Edid, edid_discovered->SizeOfEdid, &header))
|
||||
return EFI_INCOMPATIBLE_VERSION;
|
||||
|
||||
*ret_panel = xnew0(char16_t, 8);
|
||||
if (!edid_get_panel_id(&header, *ret_panel))
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "efi.h"
|
||||
|
||||
EFI_STATUS edid_get_discovered_panel_id(char16_t **ret_panel);
|
|
@ -289,6 +289,7 @@ libefi_sources = files(
|
|||
'device-path-util.c',
|
||||
'devicetree.c',
|
||||
'drivers.c',
|
||||
'edid.c',
|
||||
'efi-firmware.c',
|
||||
'efi-string.c',
|
||||
'efivars.c',
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "efi.h"
|
||||
|
||||
#define EFI_EDID_DISCOVERED_PROTOCOL_GUID \
|
||||
GUID_DEF(0x1c0c34f6, 0xd380, 0x41fa, 0xa0, 0x49, 0x8a, 0xd0, 0x6c, 0x1a, 0x66, 0xaa)
|
||||
|
||||
typedef struct {
|
||||
uint32_t SizeOfEdid;
|
||||
uint8_t *Edid;
|
||||
} EFI_EDID_DISCOVERED_PROTOCOL;
|
|
@ -4,6 +4,7 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "chid.h"
|
||||
#include "edid.h"
|
||||
#include "smbios.h"
|
||||
#include "tests.h"
|
||||
|
||||
|
@ -79,6 +80,11 @@ void smbios_raw_info_get_cached(RawSmbiosInfo *ret_info) {
|
|||
*ret_info = current_info;
|
||||
}
|
||||
|
||||
EFI_STATUS edid_get_discovered_panel_id(char16_t **ret_panel) {
|
||||
assert(ret_panel);
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
TEST(chid_match) {
|
||||
for (size_t i = 0; i < ELEMENTSOF(info); i++) {
|
||||
current_info = info[i].smbios_info;
|
||||
|
|
|
@ -242,7 +242,10 @@ void *find_configuration_table(const EFI_GUID *guid);
|
|||
char16_t *get_extra_dir(const EFI_DEVICE_PATH *file_path);
|
||||
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
# define be16toh(x) __builtin_bswap16(x)
|
||||
# define be32toh(x) __builtin_bswap32(x)
|
||||
# define le16toh(x) (x)
|
||||
# define le32toh(x) (x)
|
||||
#else
|
||||
# error "Unexpected byte order in EFI mode?"
|
||||
#endif
|
||||
|
|
|
@ -147,6 +147,21 @@ const uint32_t chid_smbios_table[CHID_TYPES_MAX] = {
|
|||
(UINT32_C(1) << CHID_SMBIOS_BASEBOARD_PRODUCT),
|
||||
|
||||
[14] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER),
|
||||
|
||||
/* Extra non-standard CHIDs */
|
||||
|
||||
[EXTRA_CHID_BASE + 0] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
|
||||
(UINT32_C(1) << CHID_SMBIOS_FAMILY) |
|
||||
(UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME)|
|
||||
(UINT32_C(1) << CHID_EDID_PANEL),
|
||||
|
||||
[EXTRA_CHID_BASE + 1] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
|
||||
(UINT32_C(1) << CHID_SMBIOS_FAMILY) |
|
||||
(UINT32_C(1) << CHID_EDID_PANEL),
|
||||
|
||||
[EXTRA_CHID_BASE + 2] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
|
||||
(UINT32_C(1) << CHID_SMBIOS_PRODUCT_SKU) |
|
||||
(UINT32_C(1) << CHID_EDID_PANEL),
|
||||
};
|
||||
|
||||
void chid_calculate(const char16_t *const smbios_fields[static _CHID_SMBIOS_FIELDS_MAX], EFI_GUID ret_chids[static CHID_TYPES_MAX]) {
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
#include "efi-fundamental.h"
|
||||
#include "string-util-fundamental.h"
|
||||
|
||||
#define CHID_TYPES_MAX 15
|
||||
#define CHID_TYPES_MAX 18
|
||||
/* Any chids starting from EXTRA_CHID_BASE are non-standard and are subject to change and renumeration at any time */
|
||||
#define EXTRA_CHID_BASE 15
|
||||
|
||||
typedef enum ChidSmbiosFields {
|
||||
CHID_SMBIOS_MANUFACTURER,
|
||||
|
@ -25,6 +27,7 @@ typedef enum ChidSmbiosFields {
|
|||
CHID_SMBIOS_BIOS_MAJOR,
|
||||
CHID_SMBIOS_BIOS_MINOR,
|
||||
CHID_SMBIOS_ENCLOSURE_TYPE,
|
||||
CHID_EDID_PANEL,
|
||||
_CHID_SMBIOS_FIELDS_MAX,
|
||||
} ChidSmbiosFields;
|
||||
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "edid-fundamental.h"
|
||||
|
||||
#define EDID_FIXED_HEADER_PATTERN "\x00\xFF\xFF\xFF\xFF\xFF\xFF"
|
||||
assert_cc(sizeof_field(EdidHeader, pattern) == sizeof(EDID_FIXED_HEADER_PATTERN));
|
||||
|
||||
bool edid_parse_blob(const void *blob, size_t blob_size, EdidHeader *ret_header) {
|
||||
assert(ret_header);
|
||||
/* EDID size is at least 128 as per the specification */
|
||||
if (blob_size < 128)
|
||||
return false;
|
||||
|
||||
const EdidHeader *edid_header = ASSERT_PTR(blob);
|
||||
if (memcmp(edid_header->pattern, EDID_FIXED_HEADER_PATTERN, sizeof(EDID_FIXED_HEADER_PATTERN)) != 0)
|
||||
return false;
|
||||
|
||||
*ret_header = (EdidHeader) {
|
||||
.pattern = EDID_FIXED_HEADER_PATTERN,
|
||||
.manufacturer_id = be16toh(edid_header->manufacturer_id),
|
||||
.manufacturer_product_code = le16toh(edid_header->manufacturer_product_code),
|
||||
.serial_number = le32toh(edid_header->serial_number),
|
||||
.week_of_manufacture = edid_header->week_of_manufacture,
|
||||
.year_of_manufacture = edid_header->year_of_manufacture,
|
||||
.edid_version = edid_header->edid_version,
|
||||
.edid_revision = edid_header->edid_revision,
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
bool edid_get_panel_id(const EdidHeader *edid_header, char16_t ret_panel[static 8]) {
|
||||
assert(edid_header);
|
||||
assert(ret_panel);
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
uint8_t letter = (edid_header->manufacturer_id >> (5 * i)) & 0b11111;
|
||||
if (letter > 0b11010)
|
||||
return false;
|
||||
ret_panel[2 - i] = letter + 'A' - 1;
|
||||
}
|
||||
ret_panel[3] = hex[(edid_header->manufacturer_product_code >> 12) & 0x0F];
|
||||
ret_panel[4] = hex[(edid_header->manufacturer_product_code >> 8) & 0x0F];
|
||||
ret_panel[5] = hex[(edid_header->manufacturer_product_code >> 4) & 0x0F];
|
||||
ret_panel[6] = hex[(edid_header->manufacturer_product_code >> 0) & 0x0F];
|
||||
ret_panel[7] = L'\0';
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#if SD_BOOT
|
||||
# include "efi-string.h"
|
||||
# include "util.h"
|
||||
#else
|
||||
# include <endian.h>
|
||||
# include <stddef.h>
|
||||
# include <stdint.h>
|
||||
# include <uchar.h>
|
||||
#endif
|
||||
|
||||
#include "string-util-fundamental.h"
|
||||
|
||||
/* EDID structure, version 1.4 */
|
||||
typedef struct EdidHeader {
|
||||
uint8_t pattern[8]; /* fixed pattern */
|
||||
uint16_t manufacturer_id; /* big-endian 3-letter code */
|
||||
uint16_t manufacturer_product_code; /* little-endian */
|
||||
uint32_t serial_number; /* little-endian */
|
||||
uint8_t week_of_manufacture; /* week or model year flag (0xFF) */
|
||||
uint8_t year_of_manufacture; /* year or model if flag is set (0 is 1990) */
|
||||
uint8_t edid_version; /* 0x01 for 1.3 and 1.4 */
|
||||
uint8_t edid_revision; /* 0x03 for 1.3, 0x04 for 1.4 */
|
||||
} _packed_ EdidHeader;
|
||||
|
||||
bool edid_parse_blob(const void *blob, size_t blob_size, EdidHeader *ret_header);
|
||||
bool edid_get_panel_id(const EdidHeader *edid_header, char16_t ret_panel[static 8]);
|
|
@ -5,6 +5,7 @@ fundamental_include = include_directories('.')
|
|||
fundamental_sources = files(
|
||||
'bootspec-fundamental.c',
|
||||
'chid-fundamental.c',
|
||||
'edid-fundamental.c',
|
||||
'efivars-fundamental.c',
|
||||
'iovec-util-fundamental.h',
|
||||
'sha1-fundamental.c',
|
||||
|
|
|
@ -618,6 +618,7 @@ global:
|
|||
|
||||
sd_device_has_tag;
|
||||
sd_device_get_property_value;
|
||||
sd_device_get_sysattr_value_full;
|
||||
sd_device_get_sysattr_value;
|
||||
|
||||
sd_device_set_sysattr_value;
|
||||
|
|
|
@ -2333,6 +2333,7 @@ void device_clear_sysattr_cache(sd_device *device) {
|
|||
typedef struct SysAttrCacheEntry {
|
||||
char *key;
|
||||
char *value;
|
||||
size_t size;
|
||||
int error;
|
||||
} SysAttrCacheEntry;
|
||||
|
||||
|
@ -2350,7 +2351,7 @@ DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
|||
char, path_hash_func, path_compare,
|
||||
SysAttrCacheEntry, sysattr_cache_entry_free);
|
||||
|
||||
static int device_cache_sysattr_value_full(sd_device *device, char *key, char *value, int error, bool ignore_uevent) {
|
||||
static int device_cache_sysattr_value_full(sd_device *device, char *key, char *value, size_t size, int error, bool ignore_uevent) {
|
||||
int r;
|
||||
|
||||
assert(device);
|
||||
|
@ -2378,6 +2379,7 @@ static int device_cache_sysattr_value_full(sd_device *device, char *key, char *v
|
|||
*entry = (SysAttrCacheEntry) {
|
||||
.key = key,
|
||||
.value = value,
|
||||
.size = size,
|
||||
.error = error,
|
||||
};
|
||||
|
||||
|
@ -2390,10 +2392,10 @@ static int device_cache_sysattr_value_full(sd_device *device, char *key, char *v
|
|||
}
|
||||
|
||||
int device_cache_sysattr_value(sd_device *device, char *key, char *value, int error) {
|
||||
return device_cache_sysattr_value_full(device, key, value, error, /* ignore_uevent = */ true);
|
||||
return device_cache_sysattr_value_full(device, key, value, strlen(value), error, /* ignore_uevent = */ true);
|
||||
}
|
||||
|
||||
static int device_get_cached_sysattr_value(sd_device *device, const char *key, const char **ret_value) {
|
||||
static int device_get_cached_sysattr_value(sd_device *device, const char *key, const char **ret_value, size_t *ret_size) {
|
||||
SysAttrCacheEntry *entry;
|
||||
|
||||
assert(device);
|
||||
|
@ -2409,6 +2411,8 @@ static int device_get_cached_sysattr_value(sd_device *device, const char *key, c
|
|||
}
|
||||
if (ret_value)
|
||||
*ret_value = entry->value;
|
||||
if (ret_size)
|
||||
*ret_size = entry->size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2459,16 +2463,17 @@ int device_chase(sd_device *device, const char *path, ChaseFlags flags, char **r
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **ret_value) {
|
||||
_public_ int sd_device_get_sysattr_value_full(sd_device *device, const char *sysattr, const char **ret_value, size_t *ret_size) {
|
||||
_cleanup_free_ char *resolved = NULL, *value = NULL;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
size_t size = 0;
|
||||
int r;
|
||||
|
||||
assert_return(device, -EINVAL);
|
||||
assert_return(sysattr, -EINVAL);
|
||||
|
||||
/* Look for possibly already cached result. */
|
||||
r = device_get_cached_sysattr_value(device, sysattr, ret_value);
|
||||
r = device_get_cached_sysattr_value(device, sysattr, ret_value, ret_size);
|
||||
if (r != -ENOANO)
|
||||
return r;
|
||||
|
||||
|
@ -2496,13 +2501,12 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr,
|
|||
goto cache_result;
|
||||
|
||||
/* Look for cached result again with the resolved path. */
|
||||
r = device_get_cached_sysattr_value(device, resolved, ret_value);
|
||||
r = device_get_cached_sysattr_value(device, resolved, ret_value, ret_size);
|
||||
if (r != -ENOANO)
|
||||
return r;
|
||||
|
||||
/* Read attribute value, Some attributes contain embedded '\0'. So, it is necessary to also get the
|
||||
* size of the result. See issue #20025. */
|
||||
size_t size;
|
||||
r = read_virtual_file_fd(fd, SIZE_MAX, &value, &size);
|
||||
if (r < 0)
|
||||
goto cache_result;
|
||||
|
@ -2521,7 +2525,7 @@ cache_result:
|
|||
return RET_GATHER(r, -ENOMEM);
|
||||
}
|
||||
|
||||
int k = device_cache_sysattr_value_full(device, resolved, value, -r, /* ignore_uevent = */ false);
|
||||
int k = device_cache_sysattr_value_full(device, resolved, value, size, -r, /* ignore_uevent = */ false);
|
||||
if (k < 0) {
|
||||
if (r < 0)
|
||||
log_device_debug_errno(device, k,
|
||||
|
@ -2543,6 +2547,8 @@ cache_result:
|
|||
|
||||
if (ret_value && r >= 0)
|
||||
*ret_value = value;
|
||||
if (ret_size && r >= 0)
|
||||
*ret_size = size;
|
||||
|
||||
/* device_cache_sysattr_value_full() takes 'resolved' and 'value' on success. */
|
||||
TAKE_PTR(resolved);
|
||||
|
@ -2550,6 +2556,10 @@ cache_result:
|
|||
return r;
|
||||
}
|
||||
|
||||
_public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **ret_value) {
|
||||
return sd_device_get_sysattr_value_full(device, sysattr, ret_value, NULL);
|
||||
}
|
||||
|
||||
int device_get_sysattr_int(sd_device *device, const char *sysattr, int *ret_value) {
|
||||
const char *value;
|
||||
int r;
|
||||
|
|
|
@ -109,7 +109,8 @@ int sd_device_has_tag(sd_device *device, const char *tag);
|
|||
int sd_device_has_current_tag(sd_device *device, const char *tag);
|
||||
int sd_device_get_property_value(sd_device *device, const char *key, const char **value);
|
||||
int sd_device_get_trigger_uuid(sd_device *device, sd_id128_t *ret);
|
||||
int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value);
|
||||
int sd_device_get_sysattr_value_full(sd_device *device, const char *sysattr, const char **ret_value, size_t *ret_size);
|
||||
int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **ret_value);
|
||||
|
||||
int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, const char *value);
|
||||
int sd_device_set_sysattr_valuef(sd_device *device, const char *sysattr, const char *format, ...) _sd_printf_(3, 4);
|
||||
|
|
Loading…
Reference in New Issue