Add fu_mei_device_get_fw_status() for future usage

All MEI devices support these attributes, and this API addition will allow us
to support new Intel GPUs and also modernize other plugins.
This commit is contained in:
Richard Hughes 2022-11-01 13:14:12 +00:00
parent ae99b57b2a
commit 1f97275a33
3 changed files with 135 additions and 0 deletions

View File

@ -27,6 +27,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include "fu-bytes.h"
#include "fu-dump.h"
#include "fu-mei-device.h"
#include "fu-string.h"
@ -45,6 +46,7 @@ typedef struct {
guint32 max_msg_length;
guint8 protocol_version;
gchar *uuid;
gchar *parent_device_file;
} FuMeiDevicePrivate;
G_DEFINE_TYPE_WITH_PRIVATE(FuMeiDevice, fu_mei_device, FU_TYPE_UDEV_DEVICE)
@ -58,12 +60,53 @@ fu_mei_device_to_string(FuDevice *device, guint idt, GString *str)
FuMeiDevicePrivate *priv = GET_PRIVATE(self);
FU_DEVICE_CLASS(fu_mei_device_parent_class)->to_string(device, idt, str);
fu_string_append(str, idt, "Uuid", priv->uuid);
fu_string_append(str, idt, "ParentDeviceFile", priv->parent_device_file);
if (priv->max_msg_length > 0x0)
fu_string_append_kx(str, idt, "MaxMsgLength", priv->max_msg_length);
if (priv->protocol_version > 0x0)
fu_string_append_kx(str, idt, "ProtocolVer", priv->protocol_version);
}
static gchar *
fu_mei_device_get_parent_device_file(FuMeiDevice *self, GError **error)
{
const gchar *fn;
g_autofree gchar *parent_mei_path = NULL;
g_autoptr(FuUdevDevice) parent = NULL;
g_autoptr(GDir) dir = NULL;
/* get direct parent */
parent = fu_udev_device_get_parent_with_subsystem(FU_UDEV_DEVICE(self), NULL);
if (parent == NULL) {
g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "no MEI parent");
return NULL;
}
/* look for the only child with this subsystem */
parent_mei_path = g_build_filename(fu_udev_device_get_sysfs_path(parent), "mei", NULL);
dir = g_dir_open(parent_mei_path, 0, NULL);
if (dir == NULL) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"no MEI parent dir for %s",
fu_udev_device_get_sysfs_path(parent));
return NULL;
}
fn = g_dir_read_name(dir);
if (fn == NULL) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"no MEI parent in %s",
parent_mei_path);
return NULL;
}
/* success */
return g_build_filename(fu_udev_device_get_sysfs_path(parent), "mei", fn, NULL);
}
static gboolean
fu_mei_device_probe(FuDevice *device, GError **error)
{
@ -87,6 +130,11 @@ fu_mei_device_probe(FuDevice *device, GError **error)
priv->uuid = g_strdup(uuid);
fu_device_add_guid(device, uuid);
/* get the mei[0-9] device file the parent is using */
priv->parent_device_file = fu_mei_device_get_parent_device_file(self, error);
if (priv->parent_device_file == NULL)
return FALSE;
/* FuUdevDevice->probe */
if (!FU_DEVICE_CLASS(fu_mei_device_parent_class)->probe(device, error))
return FALSE;
@ -95,6 +143,86 @@ fu_mei_device_probe(FuDevice *device, GError **error)
return fu_udev_device_set_physical_id(FU_UDEV_DEVICE(device), "pci", error);
}
static gchar *
fu_mei_device_get_parent_attr(FuMeiDevice *self, const gchar *basename, guint idx, GError **error)
{
FuMeiDevicePrivate *priv = GET_PRIVATE(self);
g_autofree gchar *fn = NULL;
g_auto(GStrv) lines = NULL;
g_autoptr(GBytes) blob = NULL;
/* sanity check */
if (priv->parent_device_file == NULL) {
g_set_error_literal(error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"no parent device file");
return NULL;
}
/* load lines */
fn = g_build_filename(priv->parent_device_file, basename, NULL);
blob = fu_bytes_get_contents(fn, error);
if (blob == NULL)
return NULL;
lines = fu_strsplit((const gchar *)g_bytes_get_data(blob, NULL),
g_bytes_get_size(blob),
"\n",
-1);
if (g_strv_length(lines) <= idx) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"requested line %u of %u",
idx,
g_strv_length(lines));
return NULL;
}
/* success */
return g_strdup(lines[idx]);
}
/**
* fu_mei_device_get_fw_ver:
* @self: a #FuMeiDevice
* @idx: line index
* @error: (nullable): optional return location for an error
*
* Gets the firmware version for a specific index.
*
* Returns: string value
*
* Since: 1.8.7
**/
gchar *
fu_mei_device_get_fw_ver(FuMeiDevice *self, guint idx, GError **error)
{
g_return_val_if_fail(FU_IS_MEI_DEVICE(self), NULL);
g_return_val_if_fail(error == NULL || *error == NULL, NULL);
return fu_mei_device_get_parent_attr(self, "fw_ver", idx, error);
}
/**
* fu_mei_device_get_fw_status:
* @self: a #FuMeiDevice
* @idx: line index
* @error: (nullable): optional return location for an error
*
* Gets the firmware status for a specific index.
*
* Returns: string value
*
* Since: 1.8.7
**/
gchar *
fu_mei_device_get_fw_status(FuMeiDevice *self, guint idx, GError **error)
{
g_return_val_if_fail(FU_IS_MEI_DEVICE(self), NULL);
g_return_val_if_fail(error == NULL || *error == NULL, NULL);
return fu_mei_device_get_parent_attr(self, "fw_status", idx, error);
}
/**
* fu_mei_device_get_max_msg_length:
* @self: a #FuMeiDevice
@ -358,6 +486,7 @@ fu_mei_device_finalize(GObject *object)
FuMeiDevice *self = FU_MEI_DEVICE(object);
FuMeiDevicePrivate *priv = GET_PRIVATE(self);
g_free(priv->uuid);
g_free(priv->parent_device_file);
G_OBJECT_CLASS(fu_mei_device_parent_class)->finalize(object);
}

View File

@ -35,3 +35,7 @@ guint
fu_mei_device_get_max_msg_length(FuMeiDevice *self);
guint8
fu_mei_device_get_protocol_version(FuMeiDevice *self);
gchar *
fu_mei_device_get_fw_ver(FuMeiDevice *self, guint idx, GError **error);
gchar *
fu_mei_device_get_fw_status(FuMeiDevice *self, guint idx, GError **error);

View File

@ -1139,6 +1139,8 @@ LIBFWUPDPLUGIN_1.8.6 {
LIBFWUPDPLUGIN_1.8.7 {
global:
fu_mei_device_get_fw_status;
fu_mei_device_get_fw_ver;
fu_progress_to_string;
fu_udev_device_find_usb_device;
fu_udev_device_set_device_file;