mirror of
https://git.proxmox.com/git/fwupd
synced 2025-07-05 18:23:10 +00:00
Add a Raspberry Pi firmware provider
This queries the current firmware version and also allows online or offline updating.
This commit is contained in:
parent
804c075fee
commit
25cf6ab53e
@ -122,9 +122,15 @@ PKG_CHECK_MODULES(GCAB, libgcab-1.0)
|
|||||||
PKG_CHECK_MODULES(APPSTREAM_GLIB, appstream-glib >= 0.3.5)
|
PKG_CHECK_MODULES(APPSTREAM_GLIB, appstream-glib >= 0.3.5)
|
||||||
PKG_CHECK_MODULES(GUSB, gusb >= 0.2.2)
|
PKG_CHECK_MODULES(GUSB, gusb >= 0.2.2)
|
||||||
PKG_CHECK_MODULES(SQLITE, sqlite3)
|
PKG_CHECK_MODULES(SQLITE, sqlite3)
|
||||||
|
PKG_CHECK_MODULES(ARCHIVE, libarchive)
|
||||||
PKG_CHECK_MODULES(SOUP, libsoup-2.4 >= 2.42)
|
PKG_CHECK_MODULES(SOUP, libsoup-2.4 >= 2.42)
|
||||||
AC_PATH_PROG(DOCBOOK2MAN, docbook2man)
|
AC_PATH_PROG(DOCBOOK2MAN, docbook2man)
|
||||||
|
|
||||||
|
AC_PATH_PROG(GCAB, [gcab], [no])
|
||||||
|
if test x$GCAB = "xno" ; then
|
||||||
|
AC_MSG_ERROR([gcab program not found])
|
||||||
|
fi
|
||||||
|
|
||||||
# ColorHug support
|
# ColorHug support
|
||||||
AC_ARG_ENABLE(colorhug, AS_HELP_STRING([--enable-colorhug],[Enable ColorHug support]),
|
AC_ARG_ENABLE(colorhug, AS_HELP_STRING([--enable-colorhug],[Enable ColorHug support]),
|
||||||
enable_colorhug=$enableval, enable_colorhug=yes)
|
enable_colorhug=$enableval, enable_colorhug=yes)
|
||||||
@ -187,6 +193,7 @@ libfwupd/Makefile
|
|||||||
data/Makefile
|
data/Makefile
|
||||||
data/pki/Makefile
|
data/pki/Makefile
|
||||||
data/tests/Makefile
|
data/tests/Makefile
|
||||||
|
data/tests/rpiupdate/Makefile
|
||||||
docs/Makefile
|
docs/Makefile
|
||||||
docs/man/Makefile
|
docs/man/Makefile
|
||||||
policy/Makefile
|
policy/Makefile
|
||||||
|
@ -20,8 +20,10 @@ BuildRequires: sqlite-devel
|
|||||||
BuildRequires: gpgme-devel
|
BuildRequires: gpgme-devel
|
||||||
BuildRequires: systemd
|
BuildRequires: systemd
|
||||||
BuildRequires: libsoup-devel
|
BuildRequires: libsoup-devel
|
||||||
|
BuildRequires: libarchive-devel
|
||||||
BuildRequires: gobject-introspection-devel
|
BuildRequires: gobject-introspection-devel
|
||||||
BuildRequires: libappstream-glib-devel >= 0.3.6
|
BuildRequires: libappstream-glib-devel >= 0.3.6
|
||||||
|
BuildRequires: gcab
|
||||||
|
|
||||||
%ifarch x86_64 %{ix86} aarch64
|
%ifarch x86_64 %{ix86} aarch64
|
||||||
BuildRequires: fwupdate-devel >= 0.4
|
BuildRequires: fwupdate-devel >= 0.4
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
|
SUBDIRS = \
|
||||||
|
rpiupdate
|
||||||
|
|
||||||
test_files = \
|
test_files = \
|
||||||
colorhug-als-3.0.2.cab \
|
colorhug-als-3.0.2.cab \
|
||||||
firmware.bin \
|
firmware.bin \
|
||||||
|
rpiboot/start.elf \
|
||||||
pki/GPG-KEY-Linux-Vendor-Firmware-Service
|
pki/GPG-KEY-Linux-Vendor-Firmware-Service
|
||||||
|
|
||||||
EXTRA_DIST = $(test_files)
|
EXTRA_DIST = $(test_files)
|
||||||
|
BIN
data/tests/rpiboot/start.elf
Normal file
BIN
data/tests/rpiboot/start.elf
Normal file
Binary file not shown.
32
data/tests/rpiupdate/Makefile.am
Normal file
32
data/tests/rpiupdate/Makefile.am
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
test_files = \
|
||||||
|
firmware.bin \
|
||||||
|
rpi-firmware-20150805.cab
|
||||||
|
|
||||||
|
firmware.bin: $(srcdir)/*.elf $(srcdir)/overlays/* $(srcdir)/README
|
||||||
|
$(AM_V_GEN) tar -cf $@ \
|
||||||
|
$(srcdir)/README \
|
||||||
|
$(srcdir)/*.elf \
|
||||||
|
$(srcdir)/overlays/*.dtb
|
||||||
|
|
||||||
|
rpi-firmware-20150805.cab: firmware.bin firmware.inf firmware.metainfo.xml
|
||||||
|
$(AM_V_GEN) touch -c -m -d"2000-01-01T00:00:00" $?; \
|
||||||
|
$(GCAB) --create --nopath $@ \
|
||||||
|
$(builddir)/firmware.bin \
|
||||||
|
$(srcdir)/firmware.metainfo.xml \
|
||||||
|
$(srcdir)/firmware.inf
|
||||||
|
|
||||||
|
BUILT_SOURCES = \
|
||||||
|
firmware.bin \
|
||||||
|
rpi-firmware-20150805.cab
|
||||||
|
|
||||||
|
CLEANFILES = \
|
||||||
|
$(BUILT_SOURCES)
|
||||||
|
|
||||||
|
EXTRA_DIST = \
|
||||||
|
$(test_files) \
|
||||||
|
firmware.inf \
|
||||||
|
firmware.metainfo.xml \
|
||||||
|
overlays/test.dtb \
|
||||||
|
start.elf
|
||||||
|
|
||||||
|
-include $(top_srcdir)/git.mk
|
0
data/tests/rpiupdate/README
Normal file
0
data/tests/rpiupdate/README
Normal file
19
data/tests/rpiupdate/firmware.inf
Normal file
19
data/tests/rpiupdate/firmware.inf
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
; Copyright (C) 2015 Richard Hughes
|
||||||
|
|
||||||
|
[Version]
|
||||||
|
Class=Firmware
|
||||||
|
ClassGuid={f2e7dd72-6468-4e36-b6f1-6488f42c1b52}
|
||||||
|
|
||||||
|
[Firmware_CopyFiles]
|
||||||
|
firmware.bin
|
||||||
|
|
||||||
|
[Firmware_AddReg]
|
||||||
|
HKR,,FirmwareId,,{c77029fe-ffb2-3706-dc67-67af4a132afd}
|
||||||
|
HKR,,FirmwareVersion,%REG_DWORD%,0x0000000
|
||||||
|
HKR,,FirmwareFilename,,firmware.bin
|
||||||
|
|
||||||
|
[Strings]
|
||||||
|
Provider = "Raspberry Pi Foundation"
|
||||||
|
MfgName = "Raspberry Pi"
|
||||||
|
FirmwareDesc = "Raspberry Pi Firmware"
|
||||||
|
DiskName = "Firmware for the Raspberry Pi"
|
24
data/tests/rpiupdate/firmware.metainfo.xml
Normal file
24
data/tests/rpiupdate/firmware.metainfo.xml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Copyright 2015 Richard Hughes -->
|
||||||
|
<component type="firmware">
|
||||||
|
<id>c77029fe-ffb2-3706-dc67-67af4a132afd</id>
|
||||||
|
<name>Raspberry Pi Device Update</name>
|
||||||
|
<summary>Firmware for the Raspberry Pi</summary>
|
||||||
|
<description>
|
||||||
|
<p>
|
||||||
|
Updating the firmware on your Raspberry Pi device improves
|
||||||
|
performance and fixes reported bugs.
|
||||||
|
</p>
|
||||||
|
</description>
|
||||||
|
<url type="homepage">https://www.raspberrypi.org/</url>
|
||||||
|
<metadata_license>CC0-1.0</metadata_license>
|
||||||
|
<project_license>proprietary</project_license>
|
||||||
|
<developer_name>Raspberry Pi Foundation</developer_name>
|
||||||
|
<releases>
|
||||||
|
<release version="20150805">
|
||||||
|
<description>
|
||||||
|
<p>This release fixes device startup when running in FIXME mode.</p>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
|
</releases>
|
||||||
|
</component>
|
0
data/tests/rpiupdate/overlays/test.dtb
Normal file
0
data/tests/rpiupdate/overlays/test.dtb
Normal file
BIN
data/tests/rpiupdate/start.elf
Normal file
BIN
data/tests/rpiupdate/start.elf
Normal file
Binary file not shown.
@ -14,6 +14,7 @@ AM_CPPFLAGS = \
|
|||||||
$(UEFI_CFLAGS) \
|
$(UEFI_CFLAGS) \
|
||||||
$(GPGME_CFLAGS) \
|
$(GPGME_CFLAGS) \
|
||||||
$(SOUP_CFLAGS) \
|
$(SOUP_CFLAGS) \
|
||||||
|
$(ARCHIVE_CFLAGS) \
|
||||||
-I$(top_srcdir) \
|
-I$(top_srcdir) \
|
||||||
-I$(top_builddir) \
|
-I$(top_builddir) \
|
||||||
-I$(top_srcdir)/libfwupd \
|
-I$(top_srcdir)/libfwupd \
|
||||||
@ -98,6 +99,8 @@ fwupd_SOURCES = \
|
|||||||
fu-pending.h \
|
fu-pending.h \
|
||||||
fu-provider.c \
|
fu-provider.c \
|
||||||
fu-provider.h \
|
fu-provider.h \
|
||||||
|
fu-provider-rpi.c \
|
||||||
|
fu-provider-rpi.h \
|
||||||
fu-provider-udev.c \
|
fu-provider-udev.c \
|
||||||
fu-provider-udev.h \
|
fu-provider-udev.h \
|
||||||
fu-provider-usb.c \
|
fu-provider-usb.c \
|
||||||
@ -131,6 +134,7 @@ fwupd_LDADD = \
|
|||||||
$(POLKIT_LIBS) \
|
$(POLKIT_LIBS) \
|
||||||
$(SQLITE_LIBS) \
|
$(SQLITE_LIBS) \
|
||||||
$(GPGME_LIBS) \
|
$(GPGME_LIBS) \
|
||||||
|
$(ARCHIVE_LIBS) \
|
||||||
$(UEFI_LIBS)
|
$(UEFI_LIBS)
|
||||||
|
|
||||||
fwupd_LDFLAGS = \
|
fwupd_LDFLAGS = \
|
||||||
@ -193,6 +197,8 @@ fu_self_test_SOURCES = \
|
|||||||
fu-provider.h \
|
fu-provider.h \
|
||||||
fu-provider-fake.c \
|
fu-provider-fake.c \
|
||||||
fu-provider-fake.h \
|
fu-provider-fake.h \
|
||||||
|
fu-provider-rpi.c \
|
||||||
|
fu-provider-rpi.h \
|
||||||
fu-rom.c \
|
fu-rom.c \
|
||||||
fu-rom.h \
|
fu-rom.h \
|
||||||
fu-self-test.c
|
fu-self-test.c
|
||||||
@ -203,6 +209,7 @@ fu_self_test_LDADD = \
|
|||||||
$(SQLITE_LIBS) \
|
$(SQLITE_LIBS) \
|
||||||
$(GCAB_LIBS) \
|
$(GCAB_LIBS) \
|
||||||
$(GPGME_LIBS) \
|
$(GPGME_LIBS) \
|
||||||
|
$(ARCHIVE_LIBS) \
|
||||||
$(GLIB_LIBS)
|
$(GLIB_LIBS)
|
||||||
|
|
||||||
fu_self_test_CFLAGS = \
|
fu_self_test_CFLAGS = \
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
#include "fu-keyring.h"
|
#include "fu-keyring.h"
|
||||||
#include "fu-pending.h"
|
#include "fu-pending.h"
|
||||||
#include "fu-provider.h"
|
#include "fu-provider.h"
|
||||||
|
#include "fu-provider-rpi.h"
|
||||||
#include "fu-provider-udev.h"
|
#include "fu-provider-udev.h"
|
||||||
#include "fu-provider-usb.h"
|
#include "fu-provider-usb.h"
|
||||||
#include "fu-resources.h"
|
#include "fu-resources.h"
|
||||||
@ -1537,6 +1538,7 @@ main (int argc, char *argv[])
|
|||||||
if (g_key_file_get_boolean (config, "fwupd", "EnableOptionROM", NULL))
|
if (g_key_file_get_boolean (config, "fwupd", "EnableOptionROM", NULL))
|
||||||
fu_main_add_provider (priv, fu_provider_udev_new ());
|
fu_main_add_provider (priv, fu_provider_udev_new ());
|
||||||
fu_main_add_provider (priv, fu_provider_usb_new ());
|
fu_main_add_provider (priv, fu_provider_usb_new ());
|
||||||
|
fu_main_add_provider (priv, fu_provider_rpi_new ());
|
||||||
#ifdef HAVE_COLORHUG
|
#ifdef HAVE_COLORHUG
|
||||||
fu_main_add_provider (priv, fu_provider_chug_new ());
|
fu_main_add_provider (priv, fu_provider_chug_new ());
|
||||||
#endif
|
#endif
|
||||||
|
379
src/fu-provider-rpi.c
Normal file
379
src/fu-provider-rpi.c
Normal file
@ -0,0 +1,379 @@
|
|||||||
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
|
||||||
|
*
|
||||||
|
* Licensed under the GNU General Public License Version 2
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <archive_entry.h>
|
||||||
|
#include <archive.h>
|
||||||
|
#include <fwupd.h>
|
||||||
|
#include <gio/gio.h>
|
||||||
|
#include <glib-object.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "fu-cleanup.h"
|
||||||
|
#include "fu-guid.h"
|
||||||
|
#include "fu-device.h"
|
||||||
|
#include "fu-provider-rpi.h"
|
||||||
|
|
||||||
|
static void fu_provider_rpi_finalize (GObject *object);
|
||||||
|
|
||||||
|
#define FU_PROVIDER_RPI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), FU_TYPE_PROVIDER_RPI, FuProviderRpiPrivate))
|
||||||
|
|
||||||
|
#define FU_PROVIDER_RPI_FIRMWARE_FILENAME "start.elf"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FuProviderRpiPrivate:
|
||||||
|
**/
|
||||||
|
struct _FuProviderRpiPrivate
|
||||||
|
{
|
||||||
|
gchar *fw_dir;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (FuProviderRpi, fu_provider_rpi, FU_TYPE_PROVIDER)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fu_provider_rpi_get_name:
|
||||||
|
**/
|
||||||
|
static const gchar *
|
||||||
|
fu_provider_rpi_get_name (FuProvider *provider)
|
||||||
|
{
|
||||||
|
return "RaspberryPi";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fu_provider_rpi_strstr:
|
||||||
|
**/
|
||||||
|
static gchar *
|
||||||
|
fu_provider_rpi_strstr (const guint8 *haystack,
|
||||||
|
gsize haystack_len,
|
||||||
|
const gchar *needle,
|
||||||
|
guint *offset)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
guint needle_len;
|
||||||
|
|
||||||
|
if (needle == NULL || needle[0] == '\0')
|
||||||
|
return NULL;
|
||||||
|
if (haystack == NULL || haystack_len == 0)
|
||||||
|
return NULL;
|
||||||
|
needle_len = strlen (needle);
|
||||||
|
if (needle_len > haystack_len)
|
||||||
|
return NULL;
|
||||||
|
for (i = 0; i < haystack_len - needle_len; i++) {
|
||||||
|
if (memcmp (haystack + i, needle, needle_len) == 0) {
|
||||||
|
if (offset != NULL)
|
||||||
|
*offset = i + needle_len;
|
||||||
|
return g_strdup ((const gchar *) &haystack[i + needle_len]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fu_provider_rpi_parse_firmware:
|
||||||
|
**/
|
||||||
|
static gboolean
|
||||||
|
fu_provider_rpi_parse_firmware (FuDevice *device, const gchar *fn, GError **error)
|
||||||
|
{
|
||||||
|
GDate *date;
|
||||||
|
gsize len = 0;
|
||||||
|
guint offset;
|
||||||
|
_cleanup_free_ gchar *fwver = NULL;
|
||||||
|
_cleanup_free_ gchar *platform = NULL;
|
||||||
|
_cleanup_free_ gchar *vc_date = NULL;
|
||||||
|
_cleanup_free_ gchar *vc_time = NULL;
|
||||||
|
_cleanup_free_ guint8 *data = NULL;
|
||||||
|
|
||||||
|
/* read file -- things we can find are:
|
||||||
|
*
|
||||||
|
* VC_BUILD_ID_USER: dc4
|
||||||
|
* VC_BUILD_ID_TIME: 14:58:37
|
||||||
|
* VC_BUILD_ID_BRANCH: master
|
||||||
|
* VC_BUILD_ID_TIME: Aug 3 2015
|
||||||
|
* VC_BUILD_ID_HOSTNAME: dc4-XPS13-9333
|
||||||
|
* VC_BUILD_ID_PLATFORM: raspberrypi_linux
|
||||||
|
* VC_BUILD_ID_VERSION: 4b51d81eb0068a875b336f4cc2c468cbdd06d0c5 (clean)
|
||||||
|
*/
|
||||||
|
if (!g_file_get_contents (fn, (gchar **) &data, &len, error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* check the platform matches */
|
||||||
|
platform = fu_provider_rpi_strstr (data, len,
|
||||||
|
"VC_BUILD_ID_PLATFORM: ",
|
||||||
|
NULL);
|
||||||
|
if (g_strcmp0 (platform, "raspberrypi_linux") != 0) {
|
||||||
|
g_set_error (error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_INVALID_FILE,
|
||||||
|
"not a RasberryPi, platform is %s",
|
||||||
|
platform);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find the VC_BUILD info which paradoxically is split into two
|
||||||
|
* string segments */
|
||||||
|
vc_time = fu_provider_rpi_strstr (data, len,
|
||||||
|
"VC_BUILD_ID_TIME: ", &offset);
|
||||||
|
if (vc_time == NULL) {
|
||||||
|
g_set_error_literal (error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_INVALID_FILE,
|
||||||
|
"Failed to get 1st VC_BUILD_ID_TIME");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
vc_date = fu_provider_rpi_strstr (data + offset, len - offset,
|
||||||
|
"VC_BUILD_ID_TIME: ", NULL);
|
||||||
|
if (vc_date == NULL) {
|
||||||
|
g_set_error_literal (error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_INVALID_FILE,
|
||||||
|
"Failed to get 2nd VC_BUILD_ID_TIME");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse the date */
|
||||||
|
date = g_date_new ();
|
||||||
|
g_date_set_parse (date, vc_date);
|
||||||
|
if (!g_date_valid (date)) {
|
||||||
|
g_set_error (error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_INVALID_FILE,
|
||||||
|
"Failed to parse date '%s'",
|
||||||
|
vc_date);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create a version number from the date and time */
|
||||||
|
fwver = g_strdup_printf ("%04i%02i%02i",
|
||||||
|
g_date_get_year (date),
|
||||||
|
g_date_get_month (date),
|
||||||
|
g_date_get_day (date));
|
||||||
|
fu_device_set_metadata (device, FU_DEVICE_KEY_VERSION, fwver);
|
||||||
|
|
||||||
|
g_date_free (date);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fu_provider_rpi_explode_file:
|
||||||
|
**/
|
||||||
|
static gboolean
|
||||||
|
fu_provider_rpi_explode_file (struct archive_entry *entry, const gchar *dir)
|
||||||
|
{
|
||||||
|
const gchar *tmp;
|
||||||
|
_cleanup_free_ gchar *buf = NULL;
|
||||||
|
|
||||||
|
/* no output file */
|
||||||
|
if (archive_entry_pathname (entry) == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* update output path */
|
||||||
|
tmp = archive_entry_pathname (entry);
|
||||||
|
buf = g_build_filename (dir, tmp, NULL);
|
||||||
|
archive_entry_update_pathname_utf8 (entry, buf);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fu_provider_rpi_update:
|
||||||
|
**/
|
||||||
|
static gboolean
|
||||||
|
fu_provider_rpi_update (FuProvider *provider,
|
||||||
|
FuDevice *device,
|
||||||
|
gint fd,
|
||||||
|
FuProviderFlags flags,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
FuProviderRpi *provider_rpi = FU_PROVIDER_RPI (provider);
|
||||||
|
gboolean ret = TRUE;
|
||||||
|
gboolean valid;
|
||||||
|
int r;
|
||||||
|
struct archive *arch = NULL;
|
||||||
|
struct archive_entry *entry;
|
||||||
|
_cleanup_free_ gchar *fwfn = NULL;
|
||||||
|
|
||||||
|
/* decompress anything matching either glob */
|
||||||
|
fu_provider_set_status (provider, FWUPD_STATUS_DECOMPRESSING);
|
||||||
|
arch = archive_read_new ();
|
||||||
|
archive_read_support_format_all (arch);
|
||||||
|
archive_read_support_filter_all (arch);
|
||||||
|
r = archive_read_open_fd (arch, fd, 1024 * 32);
|
||||||
|
if (r) {
|
||||||
|
ret = FALSE;
|
||||||
|
g_set_error (error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_INTERNAL,
|
||||||
|
"Cannot open: %s",
|
||||||
|
archive_error_string (arch));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
fu_provider_set_status (provider, FWUPD_STATUS_DEVICE_WRITE);
|
||||||
|
for (;;) {
|
||||||
|
_cleanup_free_ gchar *path = NULL;
|
||||||
|
r = archive_read_next_header (arch, &entry);
|
||||||
|
if (r == ARCHIVE_EOF)
|
||||||
|
break;
|
||||||
|
if (r != ARCHIVE_OK) {
|
||||||
|
ret = FALSE;
|
||||||
|
g_set_error (error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_INTERNAL,
|
||||||
|
"Cannot read header: %s",
|
||||||
|
archive_error_string (arch));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* only extract if valid */
|
||||||
|
valid = fu_provider_rpi_explode_file (entry, provider_rpi->priv->fw_dir);
|
||||||
|
if (!valid)
|
||||||
|
continue;
|
||||||
|
r = archive_read_extract (arch, entry, 0);
|
||||||
|
if (r != ARCHIVE_OK) {
|
||||||
|
ret = FALSE;
|
||||||
|
g_set_error (error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_INTERNAL,
|
||||||
|
"Cannot extract: %s",
|
||||||
|
archive_error_string (arch));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the new VC build info */
|
||||||
|
fu_provider_set_status (provider, FWUPD_STATUS_DEVICE_VERIFY);
|
||||||
|
fwfn = g_build_filename (provider_rpi->priv->fw_dir,
|
||||||
|
FU_PROVIDER_RPI_FIRMWARE_FILENAME,
|
||||||
|
NULL);
|
||||||
|
if (!fu_provider_rpi_parse_firmware (device, fwfn, error))
|
||||||
|
return FALSE;
|
||||||
|
out:
|
||||||
|
if (arch != NULL) {
|
||||||
|
archive_read_close (arch);
|
||||||
|
archive_read_free (arch);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fu_provider_rpi_coldplug:
|
||||||
|
**/
|
||||||
|
static gboolean
|
||||||
|
fu_provider_rpi_coldplug (FuProvider *provider, GError **error)
|
||||||
|
{
|
||||||
|
FuProviderRpi *provider_rpi = FU_PROVIDER_RPI (provider);
|
||||||
|
_cleanup_free_ gchar *fwfn = NULL;
|
||||||
|
_cleanup_free_ gchar *fwver = NULL;
|
||||||
|
_cleanup_free_ gchar *guid = NULL;
|
||||||
|
_cleanup_object_unref_ FuDevice *device = NULL;
|
||||||
|
|
||||||
|
/* anything interesting */
|
||||||
|
fwfn = g_build_filename (provider_rpi->priv->fw_dir,
|
||||||
|
FU_PROVIDER_RPI_FIRMWARE_FILENAME,
|
||||||
|
NULL);
|
||||||
|
if (!g_file_test (fwfn, G_FILE_TEST_EXISTS))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/* create fake device */
|
||||||
|
device = fu_device_new ();
|
||||||
|
fu_device_set_id (device, "raspberry-pi");
|
||||||
|
guid = fu_guid_generate_from_string ("raspberrypi");
|
||||||
|
fu_device_set_guid (device, guid);
|
||||||
|
fu_device_set_display_name (device, "Raspberry Pi");
|
||||||
|
fu_device_add_flag (device, FU_DEVICE_FLAG_INTERNAL);
|
||||||
|
fu_device_add_flag (device, FU_DEVICE_FLAG_ALLOW_OFFLINE);
|
||||||
|
fu_device_add_flag (device, FU_DEVICE_FLAG_ALLOW_ONLINE);
|
||||||
|
|
||||||
|
/* get the VC build info */
|
||||||
|
if (!fu_provider_rpi_parse_firmware (device, fwfn, error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
fu_provider_device_add (provider, device);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fu_provider_rpi_class_init:
|
||||||
|
**/
|
||||||
|
static void
|
||||||
|
fu_provider_rpi_class_init (FuProviderRpiClass *klass)
|
||||||
|
{
|
||||||
|
FuProviderClass *provider_class = FU_PROVIDER_CLASS (klass);
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
|
provider_class->get_name = fu_provider_rpi_get_name;
|
||||||
|
provider_class->coldplug = fu_provider_rpi_coldplug;
|
||||||
|
provider_class->update_online = fu_provider_rpi_update;
|
||||||
|
object_class->finalize = fu_provider_rpi_finalize;
|
||||||
|
|
||||||
|
g_type_class_add_private (klass, sizeof (FuProviderRpiPrivate));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fu_provider_rpi_init:
|
||||||
|
**/
|
||||||
|
static void
|
||||||
|
fu_provider_rpi_init (FuProviderRpi *provider_rpi)
|
||||||
|
{
|
||||||
|
const gchar *tmp;
|
||||||
|
provider_rpi->priv = FU_PROVIDER_RPI_GET_PRIVATE (provider_rpi);
|
||||||
|
|
||||||
|
/* allow this to be overidden for testing */
|
||||||
|
provider_rpi->priv->fw_dir = g_strdup ("/boot");
|
||||||
|
tmp = g_getenv ("FWUPD_RPI_FW_DIR");
|
||||||
|
if (tmp != NULL)
|
||||||
|
fu_provider_rpi_set_fw_dir (provider_rpi, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fu_provider_rpi_set_fw_dir:
|
||||||
|
**/
|
||||||
|
void
|
||||||
|
fu_provider_rpi_set_fw_dir (FuProviderRpi *provider_rpi, const gchar *fw_dir)
|
||||||
|
{
|
||||||
|
g_free (provider_rpi->priv->fw_dir);
|
||||||
|
provider_rpi->priv->fw_dir = g_strdup (fw_dir);
|
||||||
|
g_mkdir_with_parents (fw_dir, 0700);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fu_provider_rpi_finalize:
|
||||||
|
**/
|
||||||
|
static void
|
||||||
|
fu_provider_rpi_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
FuProviderRpi *provider_rpi = FU_PROVIDER_RPI (object);
|
||||||
|
FuProviderRpiPrivate *priv = provider_rpi->priv;
|
||||||
|
|
||||||
|
g_free (priv->fw_dir);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (fu_provider_rpi_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fu_provider_rpi_new:
|
||||||
|
**/
|
||||||
|
FuProvider *
|
||||||
|
fu_provider_rpi_new (void)
|
||||||
|
{
|
||||||
|
FuProviderRpi *provider;
|
||||||
|
provider = g_object_new (FU_TYPE_PROVIDER_RPI, NULL);
|
||||||
|
return FU_PROVIDER (provider);
|
||||||
|
}
|
58
src/fu-provider-rpi.h
Normal file
58
src/fu-provider-rpi.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
|
||||||
|
*
|
||||||
|
* Licensed under the GNU General Public License Version 2
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FU_PROVIDER_RPI_H
|
||||||
|
#define __FU_PROVIDER_RPI_H
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
|
#include "fu-device.h"
|
||||||
|
#include "fu-provider.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define FU_TYPE_PROVIDER_RPI (fu_provider_rpi_get_type ())
|
||||||
|
#define FU_PROVIDER_RPI(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), FU_TYPE_PROVIDER_RPI, FuProviderRpi))
|
||||||
|
#define FU_IS_PROVIDER_RPI(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), FU_TYPE_PROVIDER_RPI))
|
||||||
|
|
||||||
|
typedef struct _FuProviderRpiPrivate FuProviderRpiPrivate;
|
||||||
|
typedef struct _FuProviderRpi FuProviderRpi;
|
||||||
|
typedef struct _FuProviderRpiClass FuProviderRpiClass;
|
||||||
|
|
||||||
|
struct _FuProviderRpi
|
||||||
|
{
|
||||||
|
FuProvider parent;
|
||||||
|
FuProviderRpiPrivate *priv;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _FuProviderRpiClass
|
||||||
|
{
|
||||||
|
FuProviderClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType fu_provider_rpi_get_type (void);
|
||||||
|
FuProvider *fu_provider_rpi_new (void);
|
||||||
|
void fu_provider_rpi_set_fw_dir (FuProviderRpi *provider_rpi,
|
||||||
|
const gchar *fw_dir);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __FU_PROVIDER_RPI_H */
|
@ -24,6 +24,7 @@
|
|||||||
#include <fwupd.h>
|
#include <fwupd.h>
|
||||||
#include <glib-object.h>
|
#include <glib-object.h>
|
||||||
#include <glib/gstdio.h>
|
#include <glib/gstdio.h>
|
||||||
|
#include <gio/gfiledescriptorbased.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "fu-cab.h"
|
#include "fu-cab.h"
|
||||||
@ -32,6 +33,7 @@
|
|||||||
#include "fu-keyring.h"
|
#include "fu-keyring.h"
|
||||||
#include "fu-pending.h"
|
#include "fu-pending.h"
|
||||||
#include "fu-provider-fake.h"
|
#include "fu-provider-fake.h"
|
||||||
|
#include "fu-provider-rpi.h"
|
||||||
#include "fu-rom.h"
|
#include "fu-rom.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -354,6 +356,76 @@ fu_provider_func (void)
|
|||||||
g_unlink (pending_cap);
|
g_unlink (pending_cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_provider_rpi_func (void)
|
||||||
|
{
|
||||||
|
gboolean ret;
|
||||||
|
guint cnt = 0;
|
||||||
|
int fd;
|
||||||
|
_cleanup_error_free_ GError *error = NULL;
|
||||||
|
_cleanup_free_ gchar *path = NULL;
|
||||||
|
_cleanup_free_ gchar *pending_db = NULL;
|
||||||
|
_cleanup_free_ gchar *fwfile = NULL;
|
||||||
|
_cleanup_object_unref_ FuDevice *device = NULL;
|
||||||
|
_cleanup_object_unref_ FuProvider *provider = NULL;
|
||||||
|
_cleanup_object_unref_ GFile *file = NULL;
|
||||||
|
_cleanup_object_unref_ GInputStream *stream = NULL;
|
||||||
|
|
||||||
|
/* test location */
|
||||||
|
path = fu_test_get_filename ("rpiboot");
|
||||||
|
g_assert (path != NULL);
|
||||||
|
|
||||||
|
/* create a fake device */
|
||||||
|
provider = fu_provider_rpi_new ();
|
||||||
|
fu_provider_rpi_set_fw_dir (FU_PROVIDER_RPI (provider), path);
|
||||||
|
g_signal_connect (provider, "device-added",
|
||||||
|
G_CALLBACK (_provider_device_added_cb),
|
||||||
|
&device);
|
||||||
|
g_signal_connect (provider, "status-changed",
|
||||||
|
G_CALLBACK (_provider_status_changed_cb),
|
||||||
|
&cnt);
|
||||||
|
ret = fu_provider_coldplug (provider, &error);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
g_assert (ret);
|
||||||
|
|
||||||
|
/* check we did the right thing */
|
||||||
|
g_assert_cmpint (cnt, ==, 0);
|
||||||
|
g_assert (device != NULL);
|
||||||
|
g_assert_cmpstr (fu_device_get_id (device), ==, "raspberry-pi");
|
||||||
|
g_assert_cmpstr (fu_device_get_guid (device), ==,
|
||||||
|
"c77029fe-ffb2-3706-dc67-67af4a132afd");
|
||||||
|
g_assert_cmpstr (fu_device_get_metadata (device, FU_DEVICE_KEY_VERSION), ==,
|
||||||
|
"20150803");
|
||||||
|
|
||||||
|
/* ensure clean */
|
||||||
|
g_unlink ("/tmp/rpiboot/start.elf");
|
||||||
|
|
||||||
|
/* do update */
|
||||||
|
fu_provider_rpi_set_fw_dir (FU_PROVIDER_RPI (provider), "/tmp/rpiboot");
|
||||||
|
fwfile = fu_test_get_filename ("rpiupdate/firmware.bin");
|
||||||
|
g_assert (fwfile != NULL);
|
||||||
|
file = g_file_new_for_path (fwfile);
|
||||||
|
stream = G_INPUT_STREAM (g_file_read (file, NULL, &error));
|
||||||
|
fd = g_file_descriptor_based_get_fd (G_FILE_DESCRIPTOR_BASED (stream));
|
||||||
|
g_assert_no_error (error);
|
||||||
|
g_assert (stream != NULL);
|
||||||
|
ret = fu_provider_update (provider, device, NULL, fd,
|
||||||
|
FU_PROVIDER_UPDATE_FLAG_NONE, &error);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
g_assert (ret);
|
||||||
|
g_assert_cmpint (cnt, ==, 3);
|
||||||
|
|
||||||
|
/* check the file was exploded to the right place */
|
||||||
|
g_assert (g_file_test ("/tmp/rpiboot/start.elf", G_FILE_TEST_EXISTS));
|
||||||
|
g_assert (g_file_test ("/tmp/rpiboot/overlays/test.dtb", G_FILE_TEST_EXISTS));
|
||||||
|
g_assert_cmpstr (fu_device_get_metadata (device, FU_DEVICE_KEY_VERSION), ==,
|
||||||
|
"20150805");
|
||||||
|
|
||||||
|
/* clean up */
|
||||||
|
pending_db = g_build_filename (LOCALSTATEDIR, "lib", "fwupd", "pending.db", NULL);
|
||||||
|
g_unlink (pending_db);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fu_pending_func (void)
|
fu_pending_func (void)
|
||||||
{
|
{
|
||||||
@ -491,6 +563,7 @@ main (int argc, char **argv)
|
|||||||
g_test_add_func ("/fwupd/cab", fu_cab_func);
|
g_test_add_func ("/fwupd/cab", fu_cab_func);
|
||||||
g_test_add_func ("/fwupd/pending", fu_pending_func);
|
g_test_add_func ("/fwupd/pending", fu_pending_func);
|
||||||
g_test_add_func ("/fwupd/provider", fu_provider_func);
|
g_test_add_func ("/fwupd/provider", fu_provider_func);
|
||||||
|
g_test_add_func ("/fwupd/provider{rpi}", fu_provider_rpi_func);
|
||||||
g_test_add_func ("/fwupd/keyring", fu_keyring_func);
|
g_test_add_func ("/fwupd/keyring", fu_keyring_func);
|
||||||
return g_test_run ();
|
return g_test_run ();
|
||||||
}
|
}
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
#!/usr/bin/sh
|
#!/usr/bin/sh
|
||||||
sudo LIBFWUP_ESRT_DIR="../../fwupdate/linux/sys/firmware/efi/esrt/" ./fwupd --verbose
|
sudo LIBFWUP_ESRT_DIR="../../fwupdate/linux/sys/firmware/efi/esrt/" FWUPD_RPI_FW_DIR="../data/tests/rpiboot" ./fwupd --verbose
|
||||||
|
Loading…
Reference in New Issue
Block a user