fwupd/plugins/optionrom/fu-optionrom-device.c
Richard Hughes 2e1245728f Call the superclass directly from subclassed devices
This allows a device subclass to call the parent method after doing an initial
action, or even deliberately not call the *generic* parent method at all.

It also simplifies the plugins; you no longer have to remember what the plugin
is deriving from and accidentally clobber the wrong superclass method.
2021-02-18 16:18:34 +00:00

144 lines
4.0 KiB
C

/*
* Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include "config.h"
#include "fu-optionrom-device.h"
struct _FuOptionromDevice {
FuUdevDevice parent_instance;
};
G_DEFINE_TYPE (FuOptionromDevice, fu_optionrom_device, FU_TYPE_UDEV_DEVICE)
static gboolean
fu_optionrom_device_probe (FuDevice *device, GError **error)
{
g_autofree gchar *fn = NULL;
/* FuUdevDevice->probe */
if (!FU_DEVICE_CLASS (fu_optionrom_device_parent_class)->probe (device, error))
return FALSE;
/* does the device even have ROM? */
fn = g_build_filename (fu_udev_device_get_sysfs_path (FU_UDEV_DEVICE (device)), "rom", NULL);
if (!g_file_test (fn, G_FILE_TEST_EXISTS)) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"Unable to read firmware from device");
return FALSE;
}
/* set the physical ID */
return fu_udev_device_set_physical_id (FU_UDEV_DEVICE (device), "pci", error);
}
static GBytes *
fu_optionrom_device_dump_firmware (FuDevice *device, GError **error)
{
FuUdevDevice *udev_device = FU_UDEV_DEVICE (device);
guint number_reads = 0;
g_autofree gchar *fn = NULL;
g_autofree gchar *rom_fn = NULL;
g_autoptr(GByteArray) buf = g_byte_array_new ();
g_autoptr(GError) error_local = NULL;
g_autoptr(GFile) file = NULL;
g_autoptr(GInputStream) stream = NULL;
/* open the file */
rom_fn = g_build_filename (fu_udev_device_get_sysfs_path (udev_device), "rom", NULL);
if (rom_fn == NULL) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"Unable to read firmware from device");
return NULL;
}
/* open file */
file = g_file_new_for_path (rom_fn);
stream = G_INPUT_STREAM (g_file_read (file, NULL, &error_local));
if (stream == NULL) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_AUTH_FAILED,
error_local->message);
return NULL;
}
/* we have to enable the read for devices */
fn = g_file_get_path (file);
if (g_str_has_prefix (fn, "/sys")) {
g_autoptr(GFileOutputStream) output_stream = NULL;
output_stream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE,
NULL, error);
if (output_stream == NULL)
return NULL;
if (g_output_stream_write (G_OUTPUT_STREAM (output_stream), "1", 1,
NULL, error) < 0)
return NULL;
}
/* ensure we got enough data to fill the buffer */
while (TRUE) {
gssize sz;
guint8 tmp[32 * 1024] = { 0x0 };
sz = g_input_stream_read (stream, tmp, sizeof(tmp), NULL, error);
if (sz == 0)
break;
g_debug ("ROM returned 0x%04x bytes", (guint) sz);
if (sz < 0)
return NULL;
g_byte_array_append (buf, tmp, sz);
/* check the firmware isn't serving us small chunks */
if (number_reads++ > 1024) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"firmware not fulfilling requests");
return NULL;
}
}
if (buf->len < 512) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"firmware too small: %u bytes", buf->len);
return NULL;
}
return g_byte_array_free_to_bytes (g_steal_pointer (&buf));
}
static void
fu_optionrom_device_init (FuOptionromDevice *self)
{
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL);
fu_device_add_icon (FU_DEVICE (self), "audio-card");
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE);
fu_device_set_logical_id (FU_DEVICE (self), "rom");
fu_udev_device_set_flags (FU_UDEV_DEVICE (self),
FU_UDEV_DEVICE_FLAG_OPEN_READ |
FU_UDEV_DEVICE_FLAG_VENDOR_FROM_PARENT);
}
static void
fu_optionrom_device_finalize (GObject *object)
{
G_OBJECT_CLASS (fu_optionrom_device_parent_class)->finalize (object);
}
static void
fu_optionrom_device_class_init (FuOptionromDeviceClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
object_class->finalize = fu_optionrom_device_finalize;
klass_device->dump_firmware = fu_optionrom_device_dump_firmware;
klass_device->probe = fu_optionrom_device_probe;
}