diff -Nru fwupd-1.1.4/.circleci/config.yml fwupd-1.2.5/.circleci/config.yml --- fwupd-1.1.4/.circleci/config.yml 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/.circleci/config.yml 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,64 @@ +version: 2 +jobs: + build: + docker: + - image: cibuilds/snapcraft:stable + steps: + - checkout + - run: + name: "Update apt" + command: apt update + - run: + name: "Build Snap" + command: snapcraft + - persist_to_workspace: + root: . + paths: + - "*.snap" + + publish-edge: + docker: + - image: cibuilds/snapcraft:stable + steps: + - attach_workspace: + at: . + - run: + name: "Publish to Store" + command: | + mkdir .snapcraft + echo $SNAPCRAFT_LOGIN_FILE | base64 --decode --ignore-garbage > .snapcraft/snapcraft.cfg + snapcraft push *.snap --release edge + + publish-stable: + docker: + - image: cibuilds/snapcraft:stable + steps: + - attach_workspace: + at: . + - run: + name: "Publish to Store" + command: | + mkdir .snapcraft + echo $SNAPCRAFT_LOGIN_FILE | base64 --decode --ignore-garbage > .snapcraft/snapcraft.cfg + snapcraft push *.snap --release stable + +workflows: + version: 2 + main: + jobs: + - build + - publish-edge: + requires: + - build + filters: + branches: + only: master + - publish-stable: + requires: + - build + filters: + branches: + ignore: /.*/ + tags: + only: /^\d+\.\d+\.\d+$/ + diff -Nru fwupd-1.1.4/contrib/ci/debian_s390x.sh fwupd-1.2.5/contrib/ci/debian_s390x.sh --- fwupd-1.1.4/contrib/ci/debian_s390x.sh 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/ci/debian_s390x.sh 2019-02-25 09:42:18.000000000 +0000 @@ -3,6 +3,12 @@ set -x export LC_ALL=C.UTF-8 + +#evaluate using Debian's build flags +eval "$(dpkg-buildflags --export=sh)" +#filter out -Bsymbolic-functions +export LDFLAGS=$(dpkg-buildflags --get LDFLAGS | sed "s/-Wl,-Bsymbolic-functions\s//") + rm -rf build mkdir -p build cp contrib/ci/s390x_cross.txt build/ @@ -12,10 +18,11 @@ --werror \ -Dplugin_uefi=false \ -Dplugin_dell=false \ - -Dplugin_nvme=false \ -Dplugin_redfish=false \ -Dintrospection=false \ -Dgtkdoc=false \ + -Dlibxmlb:introspection=false \ + -Dlibxmlb:gtkdoc=false \ -Dman=false ninja -v ninja test -v diff -Nru fwupd-1.1.4/contrib/ci/dependencies.xml fwupd-1.2.5/contrib/ci/dependencies.xml --- fwupd-1.1.4/contrib/ci/dependencies.xml 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/ci/dependencies.xml 2019-02-25 09:42:18.000000000 +0000 @@ -174,14 +174,14 @@ - (>= 10.3) + (>= 11) - (>= 10.3) + (>= 11) @@ -366,15 +366,6 @@ gnu-efi - - - - - - - - - @@ -551,30 +542,34 @@ - + - appstream-glib + libxmlb + - libappstream-glib-devel + libxmlb-devel - (>= 0.7.4) + (>= 0.1.5) - libappstream-glib-dev:s390x + libxmlb-dev:s390x + @@ -752,7 +747,10 @@ - + + i386 + amd64 + @@ -1052,6 +1050,27 @@ + + + + + + + + + + + + + + + + + + + + + @@ -1093,11 +1112,6 @@ - - - libuuid-devel - - vala diff -Nru fwupd-1.1.4/contrib/ci/Dockerfile-centos.in fwupd-1.2.5/contrib/ci/Dockerfile-centos.in --- fwupd-1.1.4/contrib/ci/Dockerfile-centos.in 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/ci/Dockerfile-centos.in 2019-02-25 09:42:18.000000000 +0000 @@ -7,7 +7,6 @@ RUN yum install epel-release -y RUN echo fubar > /etc/machine-id %%%INSTALL_DEPENDENCIES_COMMAND%%% -RUN yum install -y https://kojipkgs.fedoraproject.org//packages/libstemmer/0/10.585svn.fc29/x86_64/libstemmer-0-10.585svn.fc29.x86_64.rpm https://kojipkgs.fedoraproject.org//packages/libappstream-glib/0.7.7/3.fc29/x86_64/libappstream-glib-0.7.7-3.fc29.x86_64.rpm https://kojipkgs.fedoraproject.org//packages/libappstream-glib/0.7.7/3.fc29/x86_64/libappstream-glib-devel-0.7.7-3.fc29.x86_64.rpm RUN pip3 install pillow pygobject RUN wget https://copr.fedorainfracloud.org/coprs/jsynacek/systemd-backports-for-centos-7/repo/epel-7/jsynacek-systemd-backports-for-centos-7-epel-7.repo -O /etc/yum.repos.d/jsynacek-systemd-centos-7.repo RUN yum --enablerepo=epel-testing -y update diff -Nru fwupd-1.1.4/contrib/ci/Dockerfile-debian.in fwupd-1.2.5/contrib/ci/Dockerfile-debian.in --- fwupd-1.1.4/contrib/ci/Dockerfile-debian.in 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/ci/Dockerfile-debian.in 2019-02-25 09:42:18.000000000 +0000 @@ -1,4 +1,4 @@ -FROM %%%ARCH_PREFIX%%%debian:testing +FROM %%%ARCH_PREFIX%%%debian:unstable %%%OS%%% RUN echo fubar > /etc/machine-id %%%ARCH_SPECIFIC_COMMAND%%% diff -Nru fwupd-1.1.4/contrib/ci/Dockerfile-fedora.in fwupd-1.2.5/contrib/ci/Dockerfile-fedora.in --- fwupd-1.1.4/contrib/ci/Dockerfile-fedora.in 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/ci/Dockerfile-fedora.in 2019-02-25 09:42:18.000000000 +0000 @@ -1,10 +1,10 @@ -FROM fedora:28 +FROM fedora:29 %%%OS%%% ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 RUN echo fubar > /etc/machine-id -RUN dnf --enablerepo=updates-testing -y update +RUN dnf -y update RUN echo fubar > /etc/machine-id %%%INSTALL_DEPENDENCIES_COMMAND%%% RUN mkdir /build diff -Nru fwupd-1.1.4/contrib/ci/Dockerfile-flatpak.in fwupd-1.2.5/contrib/ci/Dockerfile-flatpak.in --- fwupd-1.1.4/contrib/ci/Dockerfile-flatpak.in 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/ci/Dockerfile-flatpak.in 2019-02-25 09:42:18.000000000 +0000 @@ -1,11 +1,12 @@ -FROM fedora:28 +FROM fedora:29 %%%OS%%% ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 RUN echo fubar > /etc/machine-id %%%INSTALL_DEPENDENCIES_COMMAND%%% +RUN dnf --enablerepo=updates-testing -y update RUN mkdir /build WORKDIR /build COPY . . -CMD ["./contrib/ci/flatpak.sh"] +CMD ["./contrib/ci/flatpak.py"] diff -Nru fwupd-1.1.4/contrib/ci/fedora.sh fwupd-1.2.5/contrib/ci/fedora.sh --- fwupd-1.1.4/contrib/ci/fedora.sh 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/ci/fedora.sh 2019-02-25 09:42:18.000000000 +0000 @@ -49,12 +49,22 @@ cp $HOME/rpmbuild/RPMS/*/*.rpm dist -# run the installed tests if [ "$CI" = "true" ]; then sed "s,^BlacklistPlugins=test,BlacklistPlugins=," -i /etc/fwupd/daemon.conf + + # set up enough PolicyKit and D-Bus to run the daemon mkdir -p /run/dbus mkdir -p /var ln -s /var/run /run dbus-daemon --system --fork + /usr/lib/polkit-1/polkitd & + sleep 5 + + # run the daemon startup to check it can start + /usr/libexec/fwupd/fwupd --immediate-exit --verbose + + # run the installed tests whilst the daemon debugging + /usr/libexec/fwupd/fwupd --verbose & + sleep 10 gnome-desktop-testing-runner fwupd fi diff -Nru fwupd-1.1.4/contrib/ci/flatpak.py fwupd-1.2.5/contrib/ci/flatpak.py --- fwupd-1.1.4/contrib/ci/flatpak.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/contrib/ci/flatpak.py 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,81 @@ +#!/usr/bin/python3 +import subprocess +import os +import json +import shutil + +def prepare (target): + #clone the flatpak json + cmd = ['git', 'submodule', 'update', '--remote', 'contrib/flatpak'] + subprocess.run (cmd, check=True) + + #clone the submodules for that + cmd = ['git', 'submodule', 'update', '--init', '--remote', 'shared-modules/'] + subprocess.run (cmd, cwd='contrib/flatpak', check=True) + + #parse json + if os.path.isdir ('build'): + shutil.rmtree ('build') + data = {} + with open ('contrib/flatpak/org.freedesktop.fwupd.json', 'r') as rfd: + data = json.load (rfd) + platform = 'runtime/%s/x86_64/%s' % (data['runtime'], data['runtime-version']) + sdk = 'runtime/%s/x86_64/%s' % (data['sdk'], data['runtime-version']) + num_modules = len (data['modules']) + + #update to build from master + data["branch"] = "master" + for index in range(0, num_modules): + module = data['modules'][index] + if type (module) != dict or not 'name' in module: + continue + name = module['name'] + if not 'fwupd' in name: + continue + data['modules'][index]['sources'][0].pop ('url') + data['modules'][index]['sources'][0].pop ('sha256') + data['modules'][index]['sources'][0]['type'] = 'dir' + data['modules'][index]['sources'][0]['skip'] = [".git"] + data['modules'][index]['sources'][0]['path'] = ".." + + #write json + os.mkdir('build') + with open (target, 'w') as wfd: + json.dump(data, wfd, indent=4) + os.symlink ('../contrib/flatpak/shared-modules','build/shared-modules') + + # install the runtimes (parsed from json!) + repo = 'flathub' + repo_url = 'https://dl.flathub.org/repo/flathub.flatpakrepo' + print ("Installing dependencies") + cmd = ['flatpak', 'remote-add', '--if-not-exists', repo, repo_url] + subprocess.run (cmd, check=True) + cmd = ['flatpak', 'install', '--assumeyes', repo, sdk] + subprocess.run (cmd, check=True) + cmd = ['flatpak', 'install', '--assumeyes', repo, platform] + subprocess.run (cmd, check=True) + + +def build (target): + cmd = ['flatpak-builder', '--repo=repo', '--force-clean', '--disable-rofiles-fuse', 'build-dir', target] + subprocess.run (cmd, check=True) + cmd = ['flatpak', 'build-bundle', 'repo', 'fwupd.flatpak', 'org.freedesktop.fwupd'] + subprocess.run (cmd, check=True) + +if __name__ == '__main__': + t = os.path.join ('build', 'org.freedesktop.fwupd.json') + prepare (t) + build (t) + +# to run from the builddir: +# sudo flatpak-builder --run build-dir org.freedesktop.fwupd.json /app/libexec/fwupd/fwupdtool get-devices + +# install the single file bundle +# flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo +# flatpak install fwupd.flatpak + +# to run a shell in the same environment that flatpak sees: +# flatpak run --command=sh --devel org.freedesktop.fwupd + +# to run fwupdtool as root: +# sudo flatpak run org.freedesktop.fwupd --verbose get-devices diff -Nru fwupd-1.1.4/contrib/ci/flatpak.sh fwupd-1.2.5/contrib/ci/flatpak.sh --- fwupd-1.1.4/contrib/ci/flatpak.sh 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/ci/flatpak.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -#!/bin/bash -set -e -set -x - -# install the runtimes -flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo -flatpak install --assumeyes flathub runtime/org.gnome.Sdk/x86_64/3.28 -flatpak install --assumeyes flathub runtime/org.gnome.Platform/x86_64/3.28 - -# build the repo -flatpak-builder --repo=repo --force-clean --disable-rofiles-fuse build-dir contrib/org.freedesktop.fwupd.json - -# show the files that were included -tree build-dir - -# build a single file bundle -flatpak build-bundle repo fwupd.flatpak org.freedesktop.fwupd - -# make available as a deliverable -cp fwupd.flatpak dist - -# to run from the builddir: -# sudo flatpak-builder --run build-dir org.freedesktop.fwupd.json /app/libexec/fwupd/fwupdtool get-devices - -# install the single file bundle -# flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo -# flatpak install fwupd.flatpak - -# to run a shell in the same environment that flatpak sees: -# flatpak run --command=sh --devel org.freedesktop.fwupd - -# to run fwupdtool as root: -# sudo flatpak run org.freedesktop.fwupd --verbose get-devices diff -Nru fwupd-1.1.4/contrib/ci/ubuntu.sh fwupd-1.2.5/contrib/ci/ubuntu.sh --- fwupd-1.1.4/contrib/ci/ubuntu.sh 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/ci/ubuntu.sh 2019-02-25 09:42:18.000000000 +0000 @@ -2,9 +2,14 @@ set -e set -x +#evaluate using Ubuntu's buildflags +eval "$(dpkg-buildflags --export=sh)" +#filter out -Bsymbolic-functions +export LDFLAGS=$(dpkg-buildflags --get LDFLAGS | sed "s/-Wl,-Bsymbolic-functions\s//") + rm -rf build meson build --werror #build with clang and -Werror -ninja -C build -v +ninja -C build test -v #run static analysis (these mostly won't be critical) ninja -C build scan-build -v diff -Nru fwupd-1.1.4/contrib/debian/compat fwupd-1.2.5/contrib/debian/compat --- fwupd-1.1.4/contrib/debian/compat 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/debian/compat 2019-02-25 09:42:18.000000000 +0000 @@ -1 +1 @@ -10 +11 diff -Nru fwupd-1.1.4/contrib/debian/control.in fwupd-1.2.5/contrib/debian/control.in --- fwupd-1.1.4/contrib/debian/control.in 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/debian/control.in 2019-02-25 09:42:18.000000000 +0000 @@ -6,7 +6,7 @@ Matthias Klumpp , Mario Limonciello Build-Depends: %%%DYNAMIC%%% -Standards-Version: 4.1.4 +Standards-Version: 4.3.0 Section: admin Homepage: https://github.com/hughsie/fwupd Vcs-Git: https://salsa.debian.org/efi-team/fwupd.git @@ -22,8 +22,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides the library used by the daemon. @@ -31,9 +30,12 @@ Package: fwupd Architecture: linux-any Depends: ${misc:Depends}, - ${shlibs:Depends} + ${shlibs:Depends}, + shared-mime-info Recommends: python3, bolt, + tpm2-tools, + tpm2-abrmd, fwupd-signed Breaks: gir1.2-dfu-1.0 (<< 0.9.7-1), libdfu1 (<< 0.9.7-1), @@ -46,8 +48,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details Package: fwupd-tests @@ -69,8 +70,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides a set of installed tests that can be run to validate @@ -85,8 +85,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides development documentation for creating a package that @@ -105,8 +104,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides the development files for libfwupd diff -Nru fwupd-1.1.4/contrib/debian/docs fwupd-1.2.5/contrib/debian/docs --- fwupd-1.1.4/contrib/debian/docs 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/debian/docs 2019-02-25 09:42:18.000000000 +0000 @@ -1 +1 @@ -NEWS + diff -Nru fwupd-1.1.4/contrib/debian/fwupd.install fwupd-1.2.5/contrib/debian/fwupd.install --- fwupd-1.1.4/contrib/debian/fwupd.install 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/debian/fwupd.install 2019-02-25 09:42:18.000000000 +0000 @@ -4,6 +4,7 @@ usr/share/bash-completion usr/share/fwupd/* usr/share/dbus-1/* +usr/share/icons/* usr/share/polkit-1/* usr/share/locale usr/share/metainfo/* diff -Nru fwupd-1.1.4/contrib/debian/fwupd-tests.install fwupd-1.2.5/contrib/debian/fwupd-tests.install --- fwupd-1.1.4/contrib/debian/fwupd-tests.install 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/debian/fwupd-tests.install 2019-02-25 09:42:18.000000000 +0000 @@ -5,3 +5,4 @@ usr/share/installed-tests/* usr/lib/*/fwupd-plugins-3/libfu_plugin_test.so debian/lintian/fwupd-tests usr/share/lintian/overrides +etc/fwupd/remotes.d/fwupd-tests.conf diff -Nru fwupd-1.1.4/contrib/debian/fwupd-tests.postinst fwupd-1.2.5/contrib/debian/fwupd-tests.postinst --- fwupd-1.1.4/contrib/debian/fwupd-tests.postinst 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/debian/fwupd-tests.postinst 2019-02-25 09:42:18.000000000 +0000 @@ -12,4 +12,12 @@ echo "To enable test suite, modify /etc/fwupd/daemon.conf" fi fi + if [ -f /etc/fwupd/remotes.d/fwupd-tests.conf ]; then + if [ "$CI" = "true" ]; then + sed "s,^Enabled=false,Enabled=true," -i /etc/fwupd/remotes.d/fwupd-tests.conf + else + echo "To enable test suite, enable fwupd-tests remote" + fi + + fi fi diff -Nru fwupd-1.1.4/contrib/debian/gir1.2-fwupd-2.0.install fwupd-1.2.5/contrib/debian/gir1.2-fwupd-2.0.install --- fwupd-1.1.4/contrib/debian/gir1.2-fwupd-2.0.install 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/debian/gir1.2-fwupd-2.0.install 2019-02-25 09:42:18.000000000 +0000 @@ -1 +1 @@ -usr/lib/*/girepository-1.0/Fwupd-2.0.typelib +usr/lib/*/girepository-1.0/*.typelib diff -Nru fwupd-1.1.4/contrib/debian/libfwupd2.install fwupd-1.2.5/contrib/debian/libfwupd2.install --- fwupd-1.1.4/contrib/debian/libfwupd2.install 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/debian/libfwupd2.install 2019-02-25 09:42:18.000000000 +0000 @@ -1 +1 @@ -usr/lib/*/libfwup*.so.* +usr/lib/*/*.so.* diff -Nru fwupd-1.1.4/contrib/debian/libfwupd-dev.install fwupd-1.2.5/contrib/debian/libfwupd-dev.install --- fwupd-1.1.4/contrib/debian/libfwupd-dev.install 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/debian/libfwupd-dev.install 2019-02-25 09:42:18.000000000 +0000 @@ -1,6 +1,5 @@ -usr/include/fwupd-1/fwupd.h -usr/include/fwupd-1/libfwupd -usr/lib/*/libfwupd*.so -usr/lib/*/pkgconfig/fwupd.pc -usr/share/gir-1.0/Fwupd*.gir +usr/include/* +usr/lib/*/*.so +usr/lib/*/pkgconfig/*.pc +usr/share/gir-1.0/*.gir usr/share/vala/vapi diff -Nru fwupd-1.1.4/contrib/debian/lintian/fwupd fwupd-1.2.5/contrib/debian/lintian/fwupd --- fwupd-1.1.4/contrib/debian/lintian/fwupd 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/debian/lintian/fwupd 2019-02-25 09:42:18.000000000 +0000 @@ -4,3 +4,5 @@ fwupd binary: systemd-service-file-missing-install-key lib/systemd/system/system-update.target.wants/fwupd-offline-update.service #see debian bug 896012 fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_upower.so +#EFI applications are PE executables +fwupd: executable-not-elf-or-script usr/lib/fwupd/efi/*.efi diff -Nru fwupd-1.1.4/contrib/debian/rules fwupd-1.2.5/contrib/debian/rules --- fwupd-1.1.4/contrib/debian/rules 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/debian/rules 2019-02-25 09:42:18.000000000 +0000 @@ -3,6 +3,7 @@ export LC_ALL := C.UTF-8 export DEB_BUILD_MAINT_OPTIONS = hardening=+all +export DEB_LDFLAGS_MAINT_STRIP=-Wl,-Bsymbolic-functions #GPGME needs this for proper building on 32 bit archs ifeq "$(DEB_HOST_ARCH_BITS)" "32" @@ -23,7 +24,7 @@ endif %: - dh $@ --with gir,systemd + dh $@ --with gir override_dh_auto_clean: rm -fr debian/build @@ -53,10 +54,15 @@ dh_install -pfwupd usr/lib/fwupd/efi ;\ dh_install -pfwupd usr/lib/fwupd/fwupdate; \ fi + #if build with meson subproject in CI need to install this too + if [ -n "$CI" ] && [ -f debian/tmp/usr/lib/xb-tool ]; then \ + dh_install -pfwupd usr/lib/xb-tool ;\ + fi dh_missing -a --fail-missing #this is placed in fwupd-tests rm -f debian/fwupd/usr/lib/*/fwupd-plugins-3/libfu_plugin_test.so + rm -f debian/fwupd/etc/fwupd/remotes.d/fwupd-tests.conf ifeq (debian,$(SB_STYLE)) # Generate the template source for the Debian signing service to use @@ -81,7 +87,7 @@ fi override_dh_builddeb: - dh_builddeb -- -Zxz + dh_builddeb ifeq (ubuntu,$(SB_STYLE)) if [ -d debian/tmp/usr/lib/fwupd/efi/ ]; then \ mkdir -p debian/fwupd-images/$(deb_version) ;\ @@ -91,3 +97,6 @@ dpkg-distaddfile $(tar_name) raw-uefi - ;\ fi endif + +override_dh_shlibdeps: + dh_shlibdeps $$DHSLIBS diff -Nru fwupd-1.1.4/contrib/debian/source/lintian-overrides fwupd-1.2.5/contrib/debian/source/lintian-overrides --- fwupd-1.1.4/contrib/debian/source/lintian-overrides 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/debian/source/lintian-overrides 2019-02-25 09:42:18.000000000 +0000 @@ -1,2 +1,4 @@ #github doesn't have these fwupd source: debian-watch-does-not-check-gpg-signature +#to make CI happy until libxmlb lands +fwupd source: source-is-missing diff -Nru fwupd-1.1.4/contrib/firmware-packager/firmware-packager fwupd-1.2.5/contrib/firmware-packager/firmware-packager --- fwupd-1.1.4/contrib/firmware-packager/firmware-packager 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/firmware-packager/firmware-packager 2019-02-25 09:42:18.000000000 +0000 @@ -24,14 +24,14 @@ firmware_metainfo_template = """ - {firmware_id} + org.{developer_name}.guid{firmware_id} {firmware_name} {firmware_summary} {firmware_description} - {device_unique_id} + {device_guid} {firmware_homepage} CC0-1.0 @@ -50,7 +50,9 @@ def make_firmware_metainfo(firmware_info, dst): - firmware_metainfo = firmware_metainfo_template.format(**vars(firmware_info), timestamp=time.time()) + local_info = vars(firmware_info) + local_info["firmware_id"] = local_info["device_guid"][0:8] + firmware_metainfo = firmware_metainfo_template.format(**local_info, timestamp=time.time()) with open(os.path.join(dst, 'firmware.metainfo.xml'), 'w') as f: f.write(firmware_metainfo) @@ -68,7 +70,15 @@ def create_firmware_cab(exe, folder): with cd(folder): - command = ['gcab', '--create', 'firmware.cab', 'firmware.bin', 'firmware.metainfo.xml'] + if os.name == "nt": + directive = os.path.join (folder, "directive") + with open (directive, 'w') as wfd: + wfd.write('"firmware.cab"\r\n') + wfd.write('"firmware.bin"\r\n') + wfd.write('"firmware.metainfo.xml"\r\n') + command = ['makecab.exe', '/f', directive] + else: + command = ['gcab', '--create', 'firmware.cab', 'firmware.bin', 'firmware.metainfo.xml'] subprocess.check_call(command) @@ -93,18 +103,17 @@ shutil.copy(os.path.join(dir, 'firmware.cab'), args.out) parser = argparse.ArgumentParser(description='Create fwupd packaged from windows executables') -parser.add_argument('--firmware-id', help='ID for the firmware package, can be a customized (e.g. net.queuecumber.DellTBT.firmware)', required=True) parser.add_argument('--firmware-name', help='Name of the firmware package can be customized (e.g. DellTBT)', required=True) parser.add_argument('--firmware-summary', help='One line description of the firmware package') parser.add_argument('--firmware-description', help='Longer description of the firmware package') -parser.add_argument('--device-unique-id', help='Unique ID of the device this firmware will run on, this *must* match the output from `fwupdmgr get-devices`', required=True) +parser.add_argument('--device-guid', help='GUID of the device this firmware will run on, this *must* match the output of one of the GUIDs in `fwupdmgr get-devices`', required=True) parser.add_argument('--firmware-homepage', help='Website for the firmware provider') parser.add_argument('--contact-info', help='Email address of the firmware developer') -parser.add_argument('--developer-name', help='Name of the firmware developer') +parser.add_argument('--developer-name', help='Name of the firmware developer', required=True) parser.add_argument('--release-version', help='Version number of the firmware package', required=True) parser.add_argument('--release-description', help='Description of the firmware release') -parser.add_argument('--exe', help='Executable file to extract firmware from') -parser.add_argument('--bin', help='Path to the .bin file inside the executable to use as the firmware image', required=True) +parser.add_argument('--exe', help='(optional) Executable file to extract firmware from') +parser.add_argument('--bin', help='Path to the .bin file (Relative if inside the executable; Absolute if outside) to use as the firmware image', required=True) parser.add_argument('--out', help='Output cab file path', required=True) args = parser.parse_args() diff -Nru fwupd-1.1.4/contrib/firmware-packager/meson.build fwupd-1.2.5/contrib/firmware-packager/meson.build --- fwupd-1.1.4/contrib/firmware-packager/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/firmware-packager/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -1,2 +1,4 @@ -install_data('firmware-packager', - install_dir : 'share/fwupd') +if get_option('firmware-packager') + install_data('firmware-packager', + install_dir : 'share/fwupd') +endif diff -Nru fwupd-1.1.4/contrib/firmware-packager/README.md fwupd-1.2.5/contrib/firmware-packager/README.md --- fwupd-1.1.4/contrib/firmware-packager/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/firmware-packager/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -26,21 +26,19 @@ ## Documentation -`--firmware-id` ID for the firmware package, can be a customized [fwupd.org](http://fwupd.org/vendors.html) recommends using "a reverse-DNS prefix similar to java" and to "always use a .firmware suffix" (e.g. net.queuecumber.DellTBT.firmware) **REQUIRED** - `--firmware-name` Short name of the firmware package can be customized (e.g. DellTBT) **REQUIRED** `--firmware-summary` One line description of the firmware package (e.g. Dell thunderbolt firmware) `--firmware-description` Longer description of the firmware package. Theoretically this can include HTML but I haven't tried it -`--device-unique-id` Unique ID of the device this firmware will run on, this *must* match the output from `fwupdmgr get-devices` (e.g. 72533768-6a6c-5c06-994a-367374336810) **REQUIRED** +`--device-guid` GUID ID of the device this firmware will run on, this *must* match the output from `fwupdmgr get-devices` (e.g. 72533768-6a6c-5c06-994a-367374336810) **REQUIRED** `--firmware-homepage` Website for the firmware provider (e.g. http://www.dell.com) `-contact-info` Email address of the firmware developer (e.g. someone@something.net) -`--developer-name` Name of the firmware developer (e.g. John Smith) +`--developer-name` Name of the firmware developer (e.g. Dell) **REQUIRED** `--release-version` Version number of the firmware package (e.g. 4.21.01.002) **REQUIRED** `--release-description` Description of the firmware release, again this can theoretically include HTML but I didnt try it. diff -Nru fwupd-1.1.4/contrib/fix_translations.py fwupd-1.2.5/contrib/fix_translations.py --- fwupd-1.1.4/contrib/fix_translations.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/contrib/fix_translations.py 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,50 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: LGPL-2.1+ + +import sys +import os +import subprocess + +def _do_msgattrib(fn): + argv = ['msgattrib', + '--no-location', + '--translated', + '--no-wrap', + '--sort-output', + fn, + '--output-file=' + fn] + ret = subprocess.run(argv) + if ret.returncode != 0: + return + +def _do_nukeheader(fn): + clean_lines = [] + with open(fn) as f: + lines = f.readlines() + for line in lines: + if line.startswith('"POT-Creation-Date:'): + continue + if line.startswith('"PO-Revision-Date:'): + continue + if line.startswith('"Last-Translator:'): + continue + clean_lines.append(line) + with open(fn, 'w') as f: + f.writelines(clean_lines) + +def _process_file(fn): + _do_msgattrib(fn) + _do_nukeheader(fn) + +if __name__ == '__main__': + if len(sys.argv) == 1: + print('path required') + sys.exit(1) + try: + dirname = sys.argv[1] + for fn in os.listdir(dirname): + if fn.endswith('.po'): + _process_file(os.path.join(dirname, fn)) + except NotADirectoryError as _: + print('path required') + sys.exit(2) diff -Nru fwupd-1.1.4/contrib/flatpak/pip-Makefile fwupd-1.2.5/contrib/flatpak/pip-Makefile --- fwupd-1.1.4/contrib/flatpak/pip-Makefile 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/flatpak/pip-Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -all: - python3 setup.py build - -install: - python3 setup.py install --prefix=/app ${ARGS} diff -Nru fwupd-1.1.4/contrib/fwupd.spec.in fwupd-1.2.5/contrib/fwupd.spec.in --- fwupd-1.1.4/contrib/fwupd.spec.in 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/fwupd.spec.in 2019-02-25 09:42:18.000000000 +0000 @@ -1,5 +1,5 @@ %global glib2_version 2.45.8 -%global libappstream_version 0.7.4 +%global libxmlb_version 0.1.3 %global libgusb_version 0.2.11 %global libsoup_version 2.51.92 %global systemd_version 231 @@ -36,7 +36,7 @@ BuildRequires: gettext BuildRequires: glib2-devel >= %{glib2_version} -BuildRequires: libappstream-glib-devel >= %{libappstream_version} +BuildRequires: libxmlb-devel >= %{libxmlb_version} BuildRequires: libgcab1-devel BuildRequires: libgudev1-devel BuildRequires: libgusb-devel >= %{libgusb_version} @@ -54,7 +54,6 @@ %endif BuildRequires: elfutils-libelf-devel BuildRequires: gtk-doc -BuildRequires: libuuid-devel BuildRequires: gnutls-devel BuildRequires: gnutls-utils BuildRequires: meson @@ -89,12 +88,14 @@ Requires(postun): systemd Requires: glib2%{?_isa} >= %{glib2_version} -Requires: libappstream-glib%{?_isa} >= %{libappstream_version} +Requires: libxmlb%{?_isa} >= %{libxmlb_version} Requires: libgusb%{?_isa} >= %{libgusb_version} Requires: libsoup%{?_isa} >= %{libsoup_version} Requires: bubblewrap +Requires: shared-mime-info Recommends: python3 +Recommends: tpm2-tools tpm2-abrmd Obsoletes: fwupd-sign < 0.1.6 Obsoletes: libebitdo < 0.7.5-3 @@ -201,7 +202,7 @@ %systemd_postun_with_restart pesign.service %files -f %{name}.lang -%doc README.md AUTHORS NEWS +%doc README.md AUTHORS %license COPYING %config(noreplace)%{_sysconfdir}/fwupd/daemon.conf %if 0%{?have_uefi} @@ -226,6 +227,7 @@ %config(noreplace)%{_sysconfdir}/fwupd/remotes.d/lvfs.conf %config(noreplace)%{_sysconfdir}/fwupd/remotes.d/lvfs-testing.conf %config(noreplace)%{_sysconfdir}/fwupd/remotes.d/vendor.conf +%config(noreplace)%{_sysconfdir}/fwupd/remotes.d/vendor-directory.conf %config(noreplace)%{_sysconfdir}/pki/fwupd %{_sysconfdir}/pki/fwupd-metadata %{_sysconfdir}/dbus-1/system.d/org.freedesktop.fwupd.conf @@ -241,6 +243,7 @@ %{_datadir}/man/man1/dfu-tool.1.gz %{_datadir}/man/man1/fwupdmgr.1.gz %{_datadir}/metainfo/org.freedesktop.fwupd.metainfo.xml +%{_datadir}/icons/hicolor/scalable/apps/org.freedesktop.fwupd.svg %{_datadir}/fwupd/firmware-packager %{_unitdir}/fwupd-offline-update.service %{_unitdir}/fwupd.service @@ -255,6 +258,7 @@ %dir %{_libdir}/fwupd-plugins-3 %{_libdir}/fwupd-plugins-3/libfu_plugin_altos.so %{_libdir}/fwupd-plugins-3/libfu_plugin_amt.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_ata.so %{_libdir}/fwupd-plugins-3/libfu_plugin_colorhug.so %{_libdir}/fwupd-plugins-3/libfu_plugin_csr.so %if 0%{?have_dell} @@ -264,6 +268,7 @@ %{_libdir}/fwupd-plugins-3/libfu_plugin_dell_dock.so %{_libdir}/fwupd-plugins-3/libfu_plugin_dfu.so %{_libdir}/fwupd-plugins-3/libfu_plugin_ebitdo.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_fastboot.so %{_libdir}/fwupd-plugins-3/libfu_plugin_flashrom.so %{_libdir}/fwupd-plugins-3/libfu_plugin_nitrokey.so %if 0%{?have_uefi} @@ -290,7 +295,8 @@ %endif %{_libdir}/fwupd-plugins-3/libfu_plugin_unifying.so %{_libdir}/fwupd-plugins-3/libfu_plugin_upower.so -%{_libdir}/fwupd-plugins-3/libfu_plugin_wacomhid.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_wacom_raw.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_wacom_usb.so %ghost %{_localstatedir}/lib/fwupd/gnupg %if 0%{?have_uefi} %{_datadir}/locale/*/LC_IMAGES/fwupd* @@ -306,12 +312,13 @@ %files tests %dir %{_datadir}/installed-tests/fwupd -%{_datadir}/installed-tests/fwupd/firmware-example.xml.gz -%{_datadir}/installed-tests/fwupd/firmware-example.xml.gz.asc +%{_datadir}/installed-tests/fwupd/fwupd-tests.xml %{_datadir}/installed-tests/fwupd/*.test %{_datadir}/installed-tests/fwupd/*.cab %{_datadir}/installed-tests/fwupd/*.sh %{_datadir}/installed-tests/fwupd/*.py* +%dir %{_sysconfdir}/fwupd/remotes.d +%config(noreplace)%{_sysconfdir}/fwupd/remotes.d/fwupd-tests.conf %changelog * #LONGDATE# Richard Hughes #VERSION#-0.#BUILD##ALPHATAG# diff -Nru fwupd-1.1.4/contrib/org.freedesktop.fwupd.json fwupd-1.2.5/contrib/org.freedesktop.fwupd.json --- fwupd-1.1.4/contrib/org.freedesktop.fwupd.json 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/org.freedesktop.fwupd.json 1970-01-01 00:00:00.000000000 +0000 @@ -1,255 +0,0 @@ -{ - "app-id": "org.freedesktop.fwupd", - "runtime": "org.gnome.Platform", - "runtime-version": "3.28", - "branch": "master", - "sdk": "org.gnome.Sdk", - "command": "/app/libexec/fwupd/fwupdtool", - "finish-args": [ - "--device=all", - "--filesystem=/boot", - "--filesystem=/sys", - "--filesystem=xdg-download", - "--share=network", - "--system-talk-name=org.freedesktop.fwupd", - "--system-talk-name=org.freedesktop.UPower" - ], - "build-options": { - "cflags": "-O2 -g", - "cxxflags": "-O2 -g" - }, - "cleanup": [ - "*.a", - "*.la", - "/include", - "/lib/girepository-1.0", - "/lib/pkgconfig", - "/share/bash-completion", - "/share/dbus-1/system-services", - "/share/gir-1.0", - "/share/gtk-doc", - "/share/info", - "/share/man", - "/share/pkgconfig" - ], - "modules": [ - { - /* not using shared-modules as we need gudev */ - "name": "udev", - "rm-configure": true, - "config-opts": [ - "--disable-hwdb", - "--disable-logging", - "--disable-introspection", - "--disable-keymap", - "--disable-mtd_probe" - ], - "cleanup": [ - "/etc/udev", - "/libexec/*", - "/share/gtk-doc/html/libudev/", - "/sbin/udevadm" - ], - "sources": [ - { - "type": "archive", - "url": "http://kernel.org/pub/linux/utils/kernel/hotplug/udev-175.tar.bz2", - "sha256": "4c7937fe5a1521316ea571188745b9a00a9fdf314228cffc53a7ba9e5968b7ab" - }, - { - "type": "script", - "dest-filename": "autogen.sh", - "commands": [ - "autoreconf -vfi" - ] - } - ] - }, - { - "name": "libusb", - "config-opts": [ - "--disable-static" - ], - "sources": [ - { - "type": "archive", - "url": "https://github.com/libusb/libusb/releases/download/v1.0.22/libusb-1.0.22.tar.bz2", - "sha256": "75aeb9d59a4fdb800d329a545c2e6799f732362193b465ea198f2aa275518157" - } - ] - }, - { - "name": "gusb", - "buildsystem": "meson", - "config-opts": [ - "-Ddocs=false", - "-Dvapi=false", - "-Dtests=false" - ], - "cleanup": [ - "/bin/gusbcmd" - ], - "sources": [ - { - "type": "archive", - "url": "https://people.freedesktop.org/~hughsient/releases/libgusb-0.3.0.tar.xz", - "sha256": "d8e7950f99b6ae4c3e9b8c65f3692b9635289e6cff8de40c4af41b2e9b348edc" - } - ] - }, - { - "name": "efivar", - "buildsystem": "simple", - "build-commands": [ - "make prefix=/app libdir=/app/lib", - "make install prefix=/app libdir=/app/lib" - ], - "cleanup": [ - "/bin/efivar" - ], - "sources": [ - { - "type": "archive", - "url": "https://github.com/rhboot/efivar/releases/download/35/efivar-35.tar.bz2", - "sha256": "1e033dc5d099a44fd473b0887dbcc4b105613efab0fb3c5df9f111ea5d147394" - } - ] - }, - { - "name": "libsmbios_c", - "only-arches": [ - "x86_64" - ], - "config-opts": [ - "--disable-doxygen", - "--disable-graphviz", - "--disable-python" - ], - "cleanup": [ - "/sbin/smbios*", - "/share/locale/*/LC_MESSAGES/libsmbios.mo" - ], - "sources": [ - { - "type": "archive", - "url": "https://github.com/dell/libsmbios/archive/v2.4.2.tar.gz", - "sha256": "ebfe18415e24bbec06d0a9ea1066c8dcd82982555373712713d7e194138650de" - } - ] - }, - { - "name": "gnu-efi", - "only-arches": [ - "aarch64", - "x86_64" - ], - "buildsystem": "simple", - "build-commands": [ - "make", - "make PREFIX=/app install" - ], - "no-autogen": true, - "cleanup": [ - "/bin/efivar" - ], - "sources": [ - { - "type": "archive", - "url": "http://superb-dca2.dl.sourceforge.net/project/gnu-efi/gnu-efi-3.0.5.tar.bz2", - "sha256": "bd8fcd5914f18fc0e4ba948ab03b00013e528504f529c60739b748f6ef130b22" - } - ] - }, - { - "name": "python3-olefile", - "only-arches": [ - "aarch64", - "x86_64" - ], - "buildsystem": "simple", - "build-commands": [ - "pip3 install --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} olefile" - ], - "sources": [ - { - "type": "file", - "url": "https://pypi.python.org/packages/35/17/c15d41d5a8f8b98cc3df25eb00c5cee76193114c78e5674df6ef4ac92647/olefile-0.44.zip", - "sha256": "61f2ca0cd0aa77279eb943c07f607438edf374096b66332fae1ee64a6f0f73ad" - } - ] - }, - { - "name": "python3-pillow", - "only-arches": [ - "aarch64", - "x86_64" - ], - "buildsystem": "simple", - "build-commands": [ - "pip3 install --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} Pillow" - ], - "cleanup": [ - "/bin/*.py" - ], - "sources": [ - { - "type": "file", - "url": "https://pypi.python.org/packages/93/73/66854f63b1941aad9af18a1de59f9cf95ad1a87c801540222e332f6688d7/Pillow-4.1.1.tar.gz", - "sha256": "00b6a5f28d00f720235a937ebc2f50f4292a5c7e2d6ab9a8b26153b625c4f431" - } - ] - }, - { - "name": "fwupd", - "buildsystem": "meson", - "config-opts": [ - "-Dconsolekit=false", - "-Ddaemon=false", - "-Dgpg=false", - "-Dgtkdoc=false", - "-Dintrospection=false", - "-Dman=false", - "-Dpkcs7=false", - "-Dsystemd=false", - "-Dtests=false", - "-Defi-includedir=/app/include/efi", - "-Defi-ldsdir=/app/lib", - "-Defi-libdir=/app/lib", - "--sysconfdir=/app/etc", - "--localstatedir=/var/data" - ], - "build-options" : { - "arch": { - "i386": { - "config-opts": [ - "-Dplugin_dell=false", - "-Dplugin_uefi=false" - ] - }, - "arm": { - "config-opts": [ - "-Dplugin_dell=false", - "-Dplugin_uefi=false" - ] - }, - "aarch64": { - "config-opts": [ - "-Dplugin_dell=false" - ] - } - } - }, - "cleanup": [ - "/etc/dbus-1/system.d/org.freedesktop.fwupd.conf", - "/share/fwupd/remotes.d/vendor" - ], - "sources": [ - { - "type": "dir", - "skip": [".git"], - "path": ".." - } - ] - } - ] -} diff -Nru fwupd-1.1.4/contrib/PKGBUILD fwupd-1.2.5/contrib/PKGBUILD --- fwupd-1.1.4/contrib/PKGBUILD 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/PKGBUILD 2019-02-25 09:42:18.000000000 +0000 @@ -8,7 +8,8 @@ arch=('i686' 'x86_64') url='https://github.com/hughsie/fwupd' license=('GPL2') -depends=('appstream-glib' 'libgusb') +depends=('libgusb') +optdepends=('tpm2-abrmd' 'tpm2-tools') makedepends=('meson' 'valgrind' 'gobject-introspection' 'gtk-doc' 'python-pillow' 'git' 'python-cairo' 'noto-fonts' 'noto-fonts-cjk' 'python-gobject' 'vala' 'libsoup' 'polkit' 'gcab') diff -Nru fwupd-1.1.4/contrib/simple_client.py fwupd-1.2.5/contrib/simple_client.py --- fwupd-1.1.4/contrib/simple_client.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/contrib/simple_client.py 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,126 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: LGPL-2.1+ +"""A simple fwupd frontend""" +import sys +import os +import gi +from gi.repository import GLib +gi.require_version('Fwupd', '2.0') +from gi.repository import Fwupd #pylint: disable=wrong-import-position + +class Progress(): + """Class to track the signal changes of progress events""" + def __init__(self): + self.device = None + self.status = None + self.percent = 0 + self.erase = 0 + + def device_changed(self, new_device): + """Indicate new device string to track""" + if self.device != new_device: + self.device = new_device + print("\nUpdating %s" % self.device) + + def status_changed(self, percent, status): + """Indicate new status string or % complete to track""" + if self.status != status or self.percent != percent: + for i in range(0, self.erase): + sys.stdout.write("\b \b") + self.status = status + self.percent = percent + status_str = "[" + for i in range(0, 50): + if i < percent/2: + status_str += '*' + else: + status_str += ' ' + status_str += "] %d%% %s" %(percent, status) + status_str.erase = len(status_str) + sys.stdout.write(status_str) + sys.stdout.flush() + if 'idle' in status: + sys.stdout.write("\n") + +def parse_args(): + """Parse arguments for this client""" + import argparse + parser = argparse.ArgumentParser(description="Interact with fwupd daemon") + parser.add_argument("--allow-older", action="store_true", + help="Install older payloads(default False)") + parser.add_argument("--allow-reinstall", action="store_true", + help="Reinstall payloads(default False)") + parser.add_argument("command", choices=["get-devices", + "get-details", + "install"], help="What to do") + parser.add_argument('cab', nargs='?', help='CAB file') + parser.add_argument('deviceid', nargs='?', + help='DeviceID to operate on(optional)') + args = parser.parse_args() + return args + +def get_devices(client): + """Use fwupd client to fetch devices""" + devices = client.get_devices() + for item in devices: + print(item.to_string()) + +def get_details(client, cab): + """Use fwupd client to fetch details for a CAB file""" + devices = client.get_details(cab, None) + for device in devices: + print(device.to_string()) + +def status_changed(client, spec, progress): #pylint: disable=unused-argument + """Signal emitted by fwupd daemon indicating status changed""" + progress.status_changed(client.get_percentage(), + Fwupd.status_to_string(client.get_status())) + +def device_changed(client, device, progress): #pylint: disable=unused-argument + """Signal emitted by fwupd daemon indicating active device changed""" + progress.device_changed(device.get_name()) + +def install(client, cab, target, older, reinstall): + """Use fwupd client to install CAB file to applicable devices""" + # FWUPD_DEVICE_ID_ANY + if not target: + target = '*' + flags = Fwupd.InstallFlags.NONE + if older: + flags |= Fwupd.InstallFlags.ALLOW_OLDER + if reinstall: + flags |= Fwupd.InstallFlags.ALLOW_REINSTALL + progress = Progress() + parent = super(client.__class__, client) + parent.connect('device-changed', device_changed, progress) + parent.connect('notify::percentage', status_changed, progress) + parent.connect('notify::status', status_changed, progress) + try: + client.install(target, cab, flags, None) + except GLib.Error as glib_err: #pylint: disable=catching-non-exception + progress.status_changed(0, 'idle') + print("%s" % glib_err) + sys.exit(1) + +def check_cab(cab): + """Check that CAB file exists""" + if not cab: + print("Need to specify payload") + sys.exit(1) + if not os.path.isfile(cab): + print("%s doesn't exist or isn't a file" % cab) + sys.exit(1) + +if __name__ == '__main__': + ARGS = parse_args() + CLIENT = Fwupd.Client() + CLIENT.connect() + + if ARGS.command == "get-devices": + get_devices(CLIENT) + elif ARGS.command == "get-details": + check_cab(ARGS.cab) + get_details(CLIENT, ARGS.cab) + elif ARGS.command == "install": + check_cab(ARGS.cab) + install(CLIENT, ARGS.cab, ARGS.deviceid, ARGS.allow_older, ARGS.allow_reinstall) diff -Nru fwupd-1.1.4/contrib/snap/snapcraft-master.yaml fwupd-1.2.5/contrib/snap/snapcraft-master.yaml --- fwupd-1.1.4/contrib/snap/snapcraft-master.yaml 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/snap/snapcraft-master.yaml 2019-02-25 09:42:18.000000000 +0000 @@ -71,7 +71,7 @@ meson: plugin: python source: https://github.com/mesonbuild/meson.git - source-tag: 0.46.1 + source-tag: 0.47.2 build-packages: - ninja-build prime: @@ -80,54 +80,6 @@ - -lib - -share - -usr - appstream-glib-dev: - plugin: meson - meson-parameters: [--prefix=/usr, -Dgtk-doc=false, -Dintrospection=false, -Dman=false, -Drpm=false] - source: https://github.com/hughsie/appstream-glib - source-type: git - build-packages: - - python3-pip - - gperf - - intltool - - libarchive-dev - - libgcab-dev - - libgdk-pixbuf2.0-dev - - libgirepository1.0-dev - - libglib2.0-dev - - libgtk-3-dev - - libjson-glib-dev - - libsoup2.4-dev - - libsqlite3-dev - - libyaml-dev - - libstemmer-dev - - uuid-dev - stage-packages: - - libarchive13 - - libgcab-1.0-0 - - libsoup2.4-1 - - libstemmer0d - - libgdk-pixbuf2.0-0 - prime: - - -usr/bin - - -usr/include - - -usr/share/doc - - -usr/lib/*/asb-plugins-5 - - -usr/share/bash-completion - - -usr/share/aclocal - - -usr/lib/*/pkgconfig - - -usr/share/installed-tests - - -usr/lib/systemd - - -usr/lib/glib-networking - - -usr/lib/dconf - - -usr/share/X11 - - -usr/share/GConf - - -usr/share/dbus-1 - - -usr/share/glib-2.0/schemas - - -usr/share/lintian - - -usr/share/man - - -usr/lib/*/gdk-pixbuf-2.0 - - -usr/share/gettext - after: [meson] gudev: plugin: autotools source: https://gitlab.gnome.org/GNOME/libgudev.git @@ -238,6 +190,8 @@ -Dintrospection=false, -Dman=false, -Dudevdir=$SNAPCRAFT_STAGE/lib/udev, + -Dlibxmlb:gtkdoc=false, + -Dlibxmlb:introspection=false, -Dpkcs7=false] source: . source-type: git @@ -310,7 +264,7 @@ - -usr/share/gir-1.0 - -usr/share/upstart - -usr/lib/*/pkgconfig - after: [appstream-glib-dev, gudev, gusb, gnu-efi, libefivar-fixpkgconfig, libsmbios, build-introspection, gettext] + after: [gudev, gusb, gnu-efi, libefivar-fixpkgconfig, libsmbios, build-introspection, gettext] fix-bash-completion: plugin: make source: contrib/snap/fix-bash-completion diff -Nru fwupd-1.1.4/contrib/snap/snapcraft-stable.yaml fwupd-1.2.5/contrib/snap/snapcraft-stable.yaml --- fwupd-1.1.4/contrib/snap/snapcraft-stable.yaml 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/snap/snapcraft-stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,337 +0,0 @@ -name: fwupd -version-script: cat $SNAPCRAFT_STAGE/version -version: 'daily' -summary: A standalone version of fwupd to install newer firmware updates -description: | - This is a tool that can be used to install firmware updates on devices - not yet supported by the version of fwupd distributed with the OS. - -grade: stable -confinement: classic - -architectures: - - amd64 - -apps: - dfu-tool: - command: dfu-tool.wrapper - fwupdtool: - command: fwupdtool.wrapper - completer: - share/bash-completion/completions/fwupdtool - fwupd: - command: fwupd.wrapper - daemon: simple - fwupdmgr: - command: fwupdmgr.wrapper - completer: - share/bash-completion/completions/fwupdmgr - -parts: - libefivar-dev: - plugin: make - make-parameters: - - prefix=/ - - libdir=/lib - source: https://github.com/rhboot/efivar/releases/download/35/efivar-35.tar.bz2 - build-packages: - - libpopt-dev - prime: - - -include - - -bin - - -share/man - - -lib/pkgconfig - #adjust the paths from libefivar - libefivar-fixpkgconfig: - plugin: make - source: contrib/snap/libefivar-fixpkgconfig - make-parameters: - - SNAPCRAFT_STAGE=$SNAPCRAFT_STAGE - after: [libefivar-dev] - libsmbios: - plugin: autotools - source: https://github.com/dell/libsmbios/archive/v2.4.2.tar.gz - build-packages: - - libxml2-dev - - pkg-config - - autoconf - - automake - - libtool - - autopoint - prime: - - -include/ - - -lib/pkgconfig - - -lib/python3.5 - - -sbin/ - - -share/ - - -etc/ - - -lib/*.a - meson: - plugin: python - source: https://github.com/mesonbuild/meson/releases/download/0.46.1/meson-0.46.1.tar.gz - build-packages: - - ninja-build - prime: - - -bin - - -etc - - -lib - - -share - - -usr - appstream-glib-dev: - plugin: meson - meson-parameters: [--prefix=/usr, -Dgtk-doc=false, -Dintrospection=false, -Dman=false, -Drpm=false] - source: https://github.com/hughsie/appstream-glib/archive/appstream_glib_0_7_9.tar.gz - build-packages: - - python3-pip - - gperf - - intltool - - libarchive-dev - - libgcab-dev - - libgdk-pixbuf2.0-dev - - libgirepository1.0-dev - - libglib2.0-dev - - libgtk-3-dev - - libjson-glib-dev - - libsoup2.4-dev - - libsqlite3-dev - - libyaml-dev - - libstemmer-dev - - uuid-dev - stage-packages: - - libarchive13 - - libgcab-1.0-0 - - libsoup2.4-1 - - libstemmer0d - - libgdk-pixbuf2.0-0 - prime: - - -usr/bin - - -usr/include - - -usr/share/doc - - -usr/lib/*/asb-plugins-5 - - -usr/share/bash-completion - - -usr/share/aclocal - - -usr/lib/*/pkgconfig - - -usr/share/installed-tests - - -usr/lib/systemd - - -usr/lib/glib-networking - - -usr/lib/dconf - - -usr/share/X11 - - -usr/share/GConf - - -usr/share/dbus-1 - - -usr/share/glib-2.0/schemas - - -usr/share/lintian - - -usr/share/man - - -usr/lib/*/gdk-pixbuf-2.0 - - -usr/share/gettext - after: [meson] - gudev: - plugin: autotools - source: https://github.com/GNOME/libgudev/archive/232.tar.gz - configflags: - - --disable-umockdev - build-packages: - - libglib2.0-dev - - pkg-config - - libudev-dev - - gtk-doc-tools - - gnome-common - prime: - - -include - - -lib/girepository-1.0 - - -lib/pkgconfig - - -share/ - libusb: - plugin: autotools - source: https://github.com/libusb/libusb/releases/download/v1.0.22/libusb-1.0.22.tar.bz2 - configflags: - - --disable-static - prime: - - -include/ - - -lib/pkgconfig - gusb: - plugin: meson - source: https://github.com/hughsie/libgusb/archive/0.3.0.tar.gz - meson-parameters: [--prefix=/, - -Dtests=false, - -Dvapi=false, - -Ddocs=false] - build-packages: - - libgirepository1.0-dev - prime: - - -bin/ - - -include - - -share - - -lib/*/pkgconfig - - -lib/*/girepository-1.0 - after: [meson, libusb] - gnu-efi: - plugin: make - source: http://superb-dca2.dl.sourceforge.net/project/gnu-efi/gnu-efi-3.0.5.tar.bz2 - make-parameters: - - PREFIX=/usr - make-install-var: INSTALLROOT - prime: - - -usr/include/ - - -usr/lib - #fetch the latest version of the signed bootloader - #this might not match our fwupdx64.efi, but it's better than nothing - fwup-efi-signed: - build-packages: - - python3-apt - plugin: make - source: contrib/snap/fwup-efi-signed - #needed for UEFI plugin to build UX labels - build-introspection: - plugin: nil - stage-packages: - - python3-gi - - python3-gi-cairo - - python3-pil - prime: - - -etc - - -usr - - -lib - - -var - #0.19.8.1 adds support for GETTEXTDATADIRS which is needed by meson's msgfmthelper - gettext: - source: https://ftp.gnu.org/pub/gnu/gettext/gettext-0.19.8.1.tar.xz - plugin: autotools - build-packages: - - bison - - libunistring-dev - - libxml2-dev - configflags: - - --prefix=/usr - - --disable-static - - --disable-curses - - --disable-java - - --enable-relocatable - - --without-emacs - - --without-included-glib - - --without-included-libunistring - - --without-included-libxml - stage-packages: - - libunistring0 - - libxml2 - - libgomp1 - prime: - - -**/*.a - - -**/*.la - - -usr/bin - - -usr/include - - -usr/lib/gettext - - -usr/share - fwupd: - plugin: meson - meson-parameters: [--prefix=/, - -Defi-includedir=$SNAPCRAFT_STAGE/usr/include/efi, - -Defi-ldsdir=$SNAPCRAFT_STAGE/usr/lib, - -Defi-libdir=$SNAPCRAFT_STAGE/usr/lib, - -Dtests=false, - -Ddaemon=true, - -Dgtkdoc=false, - -Dintrospection=false, - -Dman=false, - -Dudevdir=$SNAPCRAFT_STAGE/lib/udev, - -Dpkcs7=false] - source: . - source-type: git - override-build: | - snapcraftctl build - echo $(git describe HEAD --always) > $SNAPCRAFT_STAGE/version - build-packages: - - bash-completion - - gcab - - gnutls-dev - - libarchive-dev - - libcairo-dev - - libelf-dev - - libgcab-dev - - libglib2.0-dev - - libgpgme11-dev - - libjson-glib-dev - - libpango1.0-dev - - libpolkit-gobject-1-dev - - libsoup2.4-dev - - libsqlite3-dev - - locales - - pkg-config - - uuid-dev - stage-packages: - - libgcab-1.0-0 - - libarchive13 - - libassuan0 - - liblcms2-2 - - libelf1 - - libgpgme11 - - libjson-glib-1.0-0 - - libpolkit-gobject-1-0 - - libsoup2.4-1 - - glib-networking - - libglib2.0-bin - prime: - # we explicitly don't want /usr/bin/gpgconf - # this will cause gpgme to error finding it - # but that also avoids trying to use non-existent - # /usr/bin/gpg2 - - -usr/bin - - -usr/sbin - - -usr/share/man - - -usr/share/GConf - - -etc/X11 - - -etc/ldap - - -etc/logcheck - - -usr/lib/dconf - - -usr/lib/gcc - - -usr/lib/glib-networking - - -usr/lib/gnupg2 - - -usr/lib/sasl2 - - -usr/lib/systemd - - -usr/lib/*/audit - - -usr/share/glib-2.0/schemas - - -usr/share/X11 - - -include - - -lib/systemd - - -lib/udev - - -lib/*/pkgconfig - - -usr/share/lintian - - -usr/share/pkgconfig - - -usr/share/installed-tests - - -usr/share/polkit-1 - - -usr/share/vala - - -usr/share/doc - - -usr/share/gnupg2 - - -usr/share/info - - -usr/share/gir-1.0 - - -usr/share/upstart - - -usr/lib/*/pkgconfig - after: [appstream-glib-dev, gudev, gusb, gnu-efi, libefivar-fixpkgconfig, libsmbios, build-introspection, gettext] - fix-bash-completion: - plugin: make - source: contrib/snap/fix-bash-completion - after: [fwupd] - update-mime: - plugin: make - source: contrib/snap/update-mime - stage-packages: - - shared-mime-info - - gsettings-desktop-schemas - - libxml2 - prime: - - -usr/bin - - -usr/share/doc - - -usr/share/doc-base - - -usr/share/man - - -usr/share/lintian - - -usr/share/pkgconfig - - -usr/share/GConf - after: [fwupd] - fwupd-wrappers: - plugin: dump - source: contrib/snap - stage: - - dfu-tool.wrapper - - fwupd-command - - fwupdtool.wrapper - - fwupd.wrapper - - fwupdmgr.wrapper diff -Nru fwupd-1.1.4/contrib/standalone-installer/assets/header.py fwupd-1.2.5/contrib/standalone-installer/assets/header.py --- fwupd-1.1.4/contrib/standalone-installer/assets/header.py 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/standalone-installer/assets/header.py 2019-02-25 09:42:18.000000000 +0000 @@ -128,7 +128,7 @@ else: output = None #look for dependencies - dep = 'org.gnome.Platform/x86_64/3.28' + dep = 'org.gnome.Platform/x86_64/3.30' repo = 'flathub' repo_url = 'https://flathub.org/repo/flathub.flatpakrepo' cmd = ['flatpak', 'info', dep] @@ -209,7 +209,7 @@ try: install_snap (directory, verbose, uninstall) return True - except: + except Exception as _: if verbose: print ("Snap installation failed") if not try_flatpak: diff -Nru fwupd-1.1.4/contrib/standalone-installer/make.py fwupd-1.2.5/contrib/standalone-installer/make.py --- fwupd-1.1.4/contrib/standalone-installer/make.py 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/contrib/standalone-installer/make.py 2019-02-25 09:42:18.000000000 +0000 @@ -85,8 +85,23 @@ subprocess.run (cmd, cwd=directory, check=True) def download_flatpak (directory): - cmd = ['wget', 'https://people.freedesktop.org/~hughsient/temp/fwupd.flatpak', '-O', 'fwupd.flatpak'] - if 'DEBUG' in os.environ: + dep = 'org.freedesktop.fwupd' + flatpak_dir = os.path.join(os.getenv('HOME'),'.local', 'share', 'flatpak') + verbose = 'DEBUG' in os.environ + + #check if we have installed locally already or not + if not os.path.exists (os.path.join (flatpak_dir, 'app', dep)): + # install into local user's repo + cmd = ['flatpak', 'install', '--user', + 'https://www.flathub.org/repo/appstream/org.freedesktop.fwupd.flatpakref', '--no-deps', '-y'] + if verbose: + print(cmd) + subprocess.run (cmd, cwd=directory, check=True) + + # generate a bundle + repo = os.path.join(flatpak_dir, 'repo') + cmd = ['flatpak', 'build-bundle', repo, 'fwupd.flatpak', dep, 'stable'] + if verbose: print(cmd) subprocess.run (cmd, cwd=directory, check=True) diff -Nru fwupd-1.1.4/contrib/vscode/build.sh fwupd-1.2.5/contrib/vscode/build.sh --- fwupd-1.1.4/contrib/vscode/build.sh 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/contrib/vscode/build.sh 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,32 @@ +#!/bin/sh +# Copyright (C) 2018 Dell, Inc. + +SOURCE=$(dirname $0) +ROOT=$1 +if [ -z "$ROOT" ]; then + ROOT=`pwd` +fi + +# build in tree +rm -rf build ${ROOT}/dist +meson build --prefix=${ROOT}/dist -Dsystemd=false -Dudevdir=${ROOT}/dist +ninja -C build install + +#create helper scripts +TEMPLATE=${SOURCE}/launcher.sh +sed "s,#ROOT#,${ROOT},; s,#EXECUTABLE#,libexec/fwupd/fwupd," \ + ${TEMPLATE} > ${ROOT}/dist/fwupd.sh +sed "s,#ROOT#,${ROOT},; s,#EXECUTABLE#,libexec/fwupd/fwupdtool," \ + ${TEMPLATE} > ${ROOT}/dist/fwupdtool.sh +sed "s,#ROOT#,${ROOT},; s,#EXECUTABLE#,bin/fwupdmgr," \ + ${TEMPLATE} > ${ROOT}/dist/fwupdmgr.sh +chmod +x ${ROOT}/dist/*.sh + +#create debugging targets +TARGET=${ROOT}/.vscode +mkdir -p ${TARGET} +if [ -f ${TARGET}/launch.json ]; then + echo "${TARGET}/launch.json already exists, not overwriting" +else + cp ${SOURCE}/launch.json ${TARGET} +fi diff -Nru fwupd-1.1.4/contrib/vscode/launcher.sh fwupd-1.2.5/contrib/vscode/launcher.sh --- fwupd-1.1.4/contrib/vscode/launcher.sh 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/contrib/vscode/launcher.sh 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,8 @@ +#!/bin/sh +export ROOT=#ROOT# +export FWUPD_LOCALSTATEDIR=${ROOT}/dist +export FWUPD_SYSCONFDIR=${ROOT}/dist/etc +if [ -n "${DEBUG}" ]; then + DEBUG="gdbserver localhost:9091" +fi +${DEBUG} ${ROOT}/dist/#EXECUTABLE# "$@" diff -Nru fwupd-1.1.4/contrib/vscode/launch.json fwupd-1.2.5/contrib/vscode/launch.json --- fwupd-1.1.4/contrib/vscode/launch.json 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/contrib/vscode/launch.json 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,68 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "gdbserver (fwupdtool)", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/dist/libexec/fwupd/fwupdtool", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "miDebuggerServerAddress": "localhost:9091", + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + }, + { + "name": "gdbserver (fwupd)", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/dist/libexec/fwupd/fwupd", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "miDebuggerServerAddress": "localhost:9091", + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + }, + { + "name": "gdbserver (fwupdmgr)", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/dist/bin/fwupdmgr", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "miDebuggerServerAddress": "localhost:9091", + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + }, + ] +} diff -Nru fwupd-1.1.4/contrib/vscode/README.md fwupd-1.2.5/contrib/vscode/README.md --- fwupd-1.1.4/contrib/vscode/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/contrib/vscode/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,39 @@ +# Using Visual Studio Code to debug + +This directory contains a collection of scripts and assets to make debugging using Visual Studio Code easier. + +## Preparing +First install the following applications locally: +* GDB Server +* GDB +* Visual Studio Code + +In Visual Studio code, visit the extension store and install *C/C++* which is an extension provided by Microsoft. +Configure Visual Studio code to open the folder representing the root of the fwupd checkout. + +## Building +Run `./contrib/debugging/build.sh` to build fwupd with all default options and create helper scripts pre-configured for debugger use. +The application will be placed into `./dist` and helper scripts will be created for `fwupdtool`, `fwupdmgr`, and `fwupd`. + +## Running +To run any of the applications, execute the appropriate helper script in `./dist`. + +## Debugging +To debug any of the applications, launch the helper script with the environment variable `DEBUG` set. +For example to debug `fwupdtool get-devices` the command to launch would be: + +``` +sudo DEBUG=1 ./dist/fwupdtool.sh get-devices +``` + +This will configure `gdbserver` to listen on a local port waiting for a debugger to connect. + +## Using Visual Studio code +During build time a set of launch targets will have been created for use with Visual Studio Code. + +Press the debugging button on the left and 3 targets will be listed at the top. +* gdbserver (fwupdtool) +* gdbserver (fwupd) +* gdbserver (fwupdmgr) + +Select the appropriate target and press the green arrow to connect to `gdbserver` and start debugging. diff -Nru fwupd-1.1.4/data/bash-completion/fwupdmgr fwupd-1.2.5/data/bash-completion/fwupdmgr --- fwupd-1.1.4/data/bash-completion/fwupdmgr 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/data/bash-completion/fwupdmgr 2019-02-25 09:42:18.000000000 +0000 @@ -1,5 +1,4 @@ _fwupdmgr_cmd_list=( - 'build-firmware' 'clear-history' 'clear-offline' 'clear-results' @@ -17,7 +16,6 @@ 'install' 'install-prepared' 'modify-remote' - 'monitor' 'refresh' 'report-history' 'unlock' @@ -146,23 +144,6 @@ else _show_modifiers fi - ;; - build-firmware) - #file in - if [[ "$prev" = "$command" ]]; then - _filedir - #file out - elif [[ "$prev" = "${COMP_WORDS[2]}" ]]; then - _filedir - #script - elif [[ "$prev" = "${COMP_WORDS[3]}" ]]; then - _filedir - #output - elif [[ "$prev" = "${COMP_WORDS[4]}" ]]; then - _filedir - else - _show_modifiers - fi ;; *) #find first command diff -Nru fwupd-1.1.4/data/bash-completion/fwupdtool.in fwupd-1.2.5/data/bash-completion/fwupdtool.in --- fwupd-1.1.4/data/bash-completion/fwupdtool.in 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/data/bash-completion/fwupdtool.in 2019-02-25 09:42:18.000000000 +0000 @@ -1,11 +1,15 @@ _fwupdtool_cmd_list=( + 'build-firmware' + 'get-updates' 'get-details' 'get-devices' 'get-plugins' 'get-topology' 'hwids' + 'update' 'install' 'install-blob' + 'monitor' 'smbios-dump' 'attach' 'detach' @@ -19,6 +23,8 @@ '--force' '--show-all-devices' '--plugin-whitelist' + '--prepare' + '--cleanup' ) _show_plugins() @@ -65,6 +71,23 @@ else _show_modifiers fi + ;; + build-firmware) + #file in + if [[ "$prev" = "$command" ]]; then + _filedir + #file out + elif [[ "$prev" = "${COMP_WORDS[2]}" ]]; then + _filedir + #script + elif [[ "$prev" = "${COMP_WORDS[3]}" ]]; then + _filedir + #output + elif [[ "$prev" = "${COMP_WORDS[4]}" ]]; then + _filedir + else + _show_modifiers + fi ;; *) #find first command diff -Nru fwupd-1.1.4/data/daemon.conf fwupd-1.2.5/data/daemon.conf --- fwupd-1.1.4/data/daemon.conf 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/data/daemon.conf 2019-02-25 09:42:18.000000000 +0000 @@ -10,3 +10,9 @@ # Maximum archive size that can be loaded in Mb, with 0 for the default ArchiveSizeMax=0 + +# Idle time in seconds to shut down the daemon -- note some plugins might +# inhibit the auto-shutdown, for instance thunderbolt. +# +# A value of 0 specifies 'never' +IdleTimeout=7200 Binary files /tmp/tmpifvE7s/99aplePdGI/fwupd-1.1.4/data/installed-tests/firmware-example.xml.gz and /tmp/tmpifvE7s/TdryFJEQYW/fwupd-1.2.5/data/installed-tests/firmware-example.xml.gz differ diff -Nru fwupd-1.1.4/data/installed-tests/firmware-example.xml.gz.asc fwupd-1.2.5/data/installed-tests/firmware-example.xml.gz.asc --- fwupd-1.1.4/data/installed-tests/firmware-example.xml.gz.asc 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/data/installed-tests/firmware-example.xml.gz.asc 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ ------BEGIN PGP SIGNATURE----- -Version: GnuPG v2.0.14 (GNU/Linux) - -iQEcBAABAgAGBQJZQqy+AAoJEEim2A5FOLrCjuEH/1wIRvQ9FIUqQ2wV5pQRjF99 -wTd1+VtQCPHkBXvMnrF2cnhNhr13lN8BhuY3kgT9TGQCPNM+8akNvDLKWiR/39rP -z+v6KpgaYA5kghFskvW4t/1lQ+Jj+PKExb1bAusexdVvRD1iEDZ0q8u/DRGwrjYn -GFbHD3K91B4nIzYQVHa8+9gRRH2uKa2U9foH3++e/PAPQCoGHa6gxV3zM05AiEpA -Am5G5u8v5WnL9W9H53unj9M47iAlzdxStzK4poshlJoNITLw9SLl6rmrgMYLHVfD -QyZTM8jSjFc+V1swslLNMVCkCWfx3ClzkEff50HKua/BxMxxJscShX43On59cik= -=XhuO ------END PGP SIGNATURE----- diff -Nru fwupd-1.1.4/data/installed-tests/fwupdmgr.sh fwupd-1.2.5/data/installed-tests/fwupdmgr.sh --- fwupd-1.1.4/data/installed-tests/fwupdmgr.sh 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/data/installed-tests/fwupdmgr.sh 2019-02-25 09:42:18.000000000 +0000 @@ -9,8 +9,8 @@ rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi # --- -echo "Refreshing with dummy metadata..." -fwupdmgr refresh ${dirname}/firmware-example.xml.gz ${dirname}/firmware-example.xml.gz.asc lvfs +echo "Enabling fwupd-tests remote..." +fwupdmgr enable-remote fwupd-tests rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi # --- diff -Nru fwupd-1.1.4/data/installed-tests/fwupd-tests.xml fwupd-1.2.5/data/installed-tests/fwupd-tests.xml --- fwupd-1.1.4/data/installed-tests/fwupd-tests.xml 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/data/installed-tests/fwupd-tests.xml 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,77 @@ + + + + fakedevice.firmware + FakeDevice Firmware + Firmware for the ACME Corp Integrated Webcam + ACME Corp + GPL-2.0+ +

Updating the firmware on your webcam device improves performance and adds new features.

+ http://www.acme.com/ + + + 17 + 1163 + ./fakedevice124.cab + fc0aabcf98bf3546c91270f2941f0acd0395dd79 + 2b8546ba805ad10bf8a2e5ad539d53f303812ba5 +

Fixes another bug with the flux capacitor to prevent time going backwards.

+
+ + 17 + 1153 + ./fakedevice123.cab + bc3c32f42cf33fe5aade64f999417251fd8208d3 + 7998cd212721e068b2411135e1f90d0ad436d730 +

Fixes a bug with the flux capacitor to avoid year 2038 overflow.

+
+
+ + b585990a-003e-5270-89d5-3705a17f9a43 + +
+ + com.hughski.ColorHug2.firmware + ColorHug2 + Firmware for the Hughski ColorHug2 Colorimeter + Hughski Limited + GPL-2.0+ +

Updating the firmware on your ColorHug2 device improves performance and adds new features.

+ http://www.hughski.com/ + + + 16384 + 19592 + hughski-colorhug2-2.0.7.cab + 490be5c0b13ca4a3f169bf8bc682ba127b8f7b96 + 658851e6f27c4d87de19cd66b97b610d100efe09 +

This release fixes prevents the firmware returning an error when the remote SHA1 hash was never sent.

+
+
+ + 2082b5e0-7a64-478a-b1b2-e3404fab6dad + +
+ + com.hughski.ColorHug.firmware + ColorHug + Firmware for the Hughski ColorHug Colorimeter + Hughski Limited + GPL-2.0+ +

Updating the firmware on your ColorHug device improves performance and adds new features.

+ http://www.hughski.com/ + + + 16384 + 18054 + hughski-colorhug-1.2.6.cab + 570a4259af0c7670f3883e84d2f4e6ff7de572c2 + 111784ffadfd5dd43f05655b266b5142230195b6 +

This release fixes prevents the firmware returning an error when the remote SHA1 hash was never sent.

+
+
+ + 40338ceb-b966-4eae-adae-9c32edfcc484 + +
+
diff -Nru fwupd-1.1.4/data/installed-tests/meson.build fwupd-1.2.5/data/installed-tests/meson.build --- fwupd-1.1.4/data/installed-tests/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/data/installed-tests/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -13,8 +13,7 @@ install_data([ 'fwupdmgr.sh', - 'firmware-example.xml.gz', - 'firmware-example.xml.gz.asc', + 'fwupd-tests.xml', 'hardware.py', ], install_dir : 'share/installed-tests/fwupd', @@ -46,3 +45,12 @@ install: true, install_dir: join_paths('share', 'installed-tests', 'fwupd'), ) + +# replace @installedtestsdir@ +configure_file( + input : 'remote.conf.in', + output : 'fwupd-tests.conf', + configuration : con2, + install: true, + install_dir: join_paths(sysconfdir, 'fwupd', 'remotes.d'), +) diff -Nru fwupd-1.1.4/data/installed-tests/README.md fwupd-1.2.5/data/installed-tests/README.md --- fwupd-1.1.4/data/installed-tests/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/data/installed-tests/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,78 @@ +Installed tests +========= + +A test suite that can be used to interact with a fake device is installed when +configured with `-Ddaemon=true` and `-Dtests=true`. + +By default this test suite is disabled. + +Enabling +======= +To enable the test suite: +1. Modify `/etc/fwupd/daemon.conf` to remove the `test` plugin from `BlacklistPlugins` + ``` + # sed "s,^Enabled=false,Enabled=true," -i /etc/fwupd/remotes.d/fwupd-tests.conf + ``` +2. Enable the `fwupd-tests` remote for local CAB files. + ``` + # fwupdmgr enable-remote fwupd-tests + ``` + +Using test suite +===== +When the daemon is started with the test suite enabled a fake webcam device will be created with a pending update. + +``` +Integrated Webcam™ + DeviceId: 08d460be0f1f9f128413f816022a6439e0078018 + Guid: b585990a-003e-5270-89d5-3705a17f9a43 + Summary: A fake webcam + Plugin: test + Flags: updatable|supported|registered + Vendor: ACME Corp. + VendorId: USB:0x046D + Version: 1.2.2 + VersionLowest: 1.2.0 + VersionBootloader: 0.1.2 + Icon: preferences-desktop-keyboard + Created: 2018-11-29 +``` + +## Upgrading +This can be upgraded to a firmware version `1.2.4` by using `fwupdmgr update` or any fwupd frontend. + +``` +$ fwupdmgr get-updates +Integrated Webcam™ has firmware updates: +GUID: b585990a-003e-5270-89d5-3705a17f9a43 +ID: fakedevice.firmware +Update Version: 1.2.4 +Update Name: FakeDevice Firmware +Update Summary: Firmware for the ACME Corp Integrated Webcam +Update Remote ID: fwupd-tests +Update Checksum: SHA1(fc0aabcf98bf3546c91270f2941f0acd0395dd79) +Update Location: ./fakedevice124.cab +Update Description: Fixes another bug with the flux capacitor to prevent time going backwards. + +$ fwupdmgr update +Decompressing… [***************************************] +Authenticating… [***************************************] +Updating Integrated Webcam™… ] +Verifying… [***************************************] Less than one minute remaining… +``` + +## Downgrading +It can also be downgraded to firmware version `1.2.3`. +``` +$ fwupdmgr downgrade +Choose a device: +0. Cancel +1. 08d460be0f1f9f128413f816022a6439e0078018 (Integrated Webcam™) +2. 8a21cacfb0a8d2b30c5ee9290eb71db021619f8b (XPS 13 9370 System Firmware) +3. d10c5f0ed12c6dc773f596b8ac51f8ace4355380 (XPS 13 9370 Thunderbolt Controller) +1 +Decompressing… [***************************************] +Authenticating… [***************************************] +Downgrading Integrated Webcam™… \ ] +Verifying… [***************************************] Less than one minute remaining… +``` diff -Nru fwupd-1.1.4/data/installed-tests/remote.conf.in fwupd-1.2.5/data/installed-tests/remote.conf.in --- fwupd-1.1.4/data/installed-tests/remote.conf.in 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/data/installed-tests/remote.conf.in 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,9 @@ +[fwupd Remote] +# This is a local fwupd remote that is used only for installed tests +# either from continuous integration or for fake devices from fwupd +# frontends + +Enabled=false +Title=fwupd test suite +Keyring=none +MetadataURI=file://@installedtestsdir@/fwupd-tests.xml diff -Nru fwupd-1.1.4/data/meson.build fwupd-1.2.5/data/meson.build --- fwupd-1.1.4/data/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/data/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -3,8 +3,10 @@ subdir('remotes.d') subdir('bash-completion') -if get_option('tests') and get_option('daemon') +if get_option('tests') subdir('tests') +endif +if get_option('daemon') subdir('installed-tests') endif @@ -16,6 +18,10 @@ install_dir: join_paths(datadir, 'metainfo') ) +install_data(['org.freedesktop.fwupd.svg'], + install_dir : join_paths(datadir, 'icons', 'hicolor', 'scalable', 'apps') +) + install_data(['org.freedesktop.fwupd.conf'], install_dir : join_paths(sysconfdir, 'dbus-1', 'system.d') ) @@ -38,7 +44,7 @@ rw_directories = [] rw_directories += join_paths (localstatedir, 'lib', 'fwupd') - rw_directories += join_paths (default_sysconfdir, 'fwupd', 'remotes.d') + rw_directories += join_paths (sysconfdir, 'fwupd', 'remotes.d') if get_option('plugin_uefi') rw_directories += ['-/boot/efi', '-/efi/EFI', '-/boot/EFI'] endif diff -Nru fwupd-1.1.4/data/org.freedesktop.fwupd.metainfo.xml fwupd-1.2.5/data/org.freedesktop.fwupd.metainfo.xml --- fwupd-1.1.4/data/org.freedesktop.fwupd.metainfo.xml 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/data/org.freedesktop.fwupd.metainfo.xml 2019-02-25 09:42:18.000000000 +0000 @@ -1,6 +1,6 @@ - + org.freedesktop.fwupd CC0-1.0 LGPL-2.0+ @@ -30,4 +30,1137 @@ moderate + + + +

This release adds the following features:

+
    +
  • Allow a device to be updated using more than one plugin
  • +
  • Report the DeviceInstanceIDs from fwupdmgr when run as root
  • +
+

This release fixes the following bugs:

+
    +
  • Add an extra check for Dell NVMe drives to avoid false positives
  • +
  • Call composite prepare and cleanup using fwupdtool
  • +
  • Correct handling of CAB files with nested directories
  • +
  • Detect and special case Dell ATA hardware
  • +
  • Do not fail fwupdtool if dbus is unavailable
  • +
  • Do not unconditionally enable Werror for the EFI binary
  • +
  • Fill holes when reading SREC files
  • +
  • Filter the last supported payloads of certain Dell docks
  • +
  • Fix flashing failure with latest Intuos Pro tablet
  • +
  • Fix potential segfault when applying UEFI updates
  • +
  • Fix unifying regression when recovering from failed flash
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a directory remote that generates metadata
  • +
  • Add a new remote type "directory"
  • +
  • Add a plugin to update Wacom embedded EMR and AES panels
  • +
  • Add a plugin to upgrade firmware on ATA-ATAPI hardware
  • +
  • Add a quirk to use the legacy bootmgr description
  • +
  • Add flag to support manually aligning the NVMe firmware to the FWUG value
  • +
  • Add SuperIO IT89xx device support
  • +
  • Add support for Dell dock passive flow
  • +
  • Add 'update' and 'get-updates' commands to fwupdtool
  • +
  • Allow Dell dock flashing Thunderbolt over I2C
  • +
  • Check the battery percentage before flashing
  • +
  • Show a per-release source and details URL
  • +
  • Show a `UpdateMessage` and display it in tools
  • +
+

This release fixes the following bugs:

+
    +
  • Add the needs-shutdown quirk to Phison NVMe drives
  • +
  • Correct Nitrokey Storage invalid firmware version read
  • +
  • Do not check the BGRT status before uploading a UX capsule
  • +
  • Do the UEFI UX checksum calculation in fwupd
  • +
  • Fix flashing various Jabra devices
  • +
  • Fix the parser to support extended segment addresses
  • +
  • Flash the fastboot partition after downloading the file
  • +
  • Show a console warning if loading an out-of-tree plugin
  • +
  • Support FGUID to get the SKU GUID for NVMe hardware
  • +
+
+
+ + +

This release fixes the following bug:

+
    +
  • Correctly migrate the history database
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add support for devices that support fastboot
  • +
  • Add more standard USB identifier GUIDs
  • +
  • Add new API to get the release protocol from the metadata
  • +
  • Add the PCR0 value as the device checksum for system firmware
  • +
  • Include the device firmware checksum and update protocol in the report
  • +
+

This release fixes the following bugs:

+
    +
  • Add Dell TB18DC to the supported devices list
  • +
  • Allow replacing the last byte in the image when using 'dfu-tool replace-data'
  • +
  • Append the UEFI capsule header in userspace rather than in the loader
  • +
  • Check the device checksum as well as the content checksum during verify
  • +
  • Correctly parse format the version numbers correctly using old metadata
  • +
  • Fix a crash if AMT returns an empty response
  • +
  • Fix a regression when doing GetReleases on unsupported hardware
  • +
  • Fix the 8bitdo version number if the daemon locale is not C.UTF-8
  • +
  • Remove the Wacom DTH generation hardware from the whitelist
  • +
  • Sanitize the version if the version format has been specified
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add per-release install duration values
  • +
  • Shut down the daemon after 2h of inactivity when possible
  • +
+

This release fixes the following bugs:

+
    +
  • Fix a use-after-free when using --immediate-exit
  • +
  • Fix flashing the 8bitdo SF30
  • +
  • Fix showing the custom remote agreements
  • +
  • Include the os-release information in the release metadata
  • +
  • Speed up startup by loading less thunderbolt firmware
  • +
  • Speed up startup by using a silo index for GUID queries
  • +
  • Use less memory and fragment the heap less when starting
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a plugin for an upcoming Dell USB-C dock
  • +
  • Add a standalone installer creation script
  • +
  • Add support for devices to show an estimated flash time
  • +
  • Add support for some new Realtek USB devices
  • +
  • Allow firmware files to depend on versions from other devices
  • +
  • Allow setting the version format from a quirk entry
  • +
  • Port from libappstream-glib to libxmlb for a large reduction in RSS
  • +
  • Stop any running daemon over dbus when using fu-tool
  • +
  • Support the Intel ME version format
  • +
+

This release fixes the following bugs:

+
    +
  • Add version format quirks for several Lenovo machines
  • +
  • Adjust panamera ESM update routine for some reported issues
  • +
  • Adjust synapticsmst EVB board handling
  • +
  • Check the amount of free space on the ESP
  • +
  • Don't show devices pending a reboot in GetUpgrades
  • +
  • Ensure that parent ID is created before creating quirked children
  • +
  • Optionally wait for replug before updating a device
  • +
  • Set the full AMT device version including the BuildNum
  • +
  • Sort the firmware sack by component priority
  • +
  • Stop showing errors when no Dell dock plugged in
  • +
  • Stop showing the current release during updates in fwupdmgr
  • +
  • Update all sub-devices for a composite update
  • +
  • Use HTTPS_PROXY if set
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • + Add a new device flag 'ignore-validation' that will + override checks +
  • +
  • Add a new plugin to enumerate EC firmware
  • +
  • Add a new plugin to update NVMe hardware
  • +
  • Add a plugin for updating using the flashrom command line tool
  • +
  • Allow the device list to take care of waiting for the device replug
  • +
  • Allow updating just one specific device from the command line
  • +
  • Allow upgrades using a self-signed fwupd.efi binary
  • +
  • Download firmware if the user specifies a URI
  • +
  • Include serial number in daemon device output when trusted
  • +
  • Notify all plugins of device removals through a new vfunc
  • +
  • Use boltd force power API if available
  • +
+

This release fixes the following bugs:

+
    +
  • Add an install hook for classic snap
  • +
  • Allow forcing installation even if no AC power is applied
  • +
  • Allow using --force to ignore version_lowest
  • +
  • Always use the same HardwareIDs as Windows
  • +
  • Check the device state before assuming a fake DFU runtime
  • +
  • Copy over parent GUIDs from other plugin donors
  • +
  • Detect location of python3 interpreter
  • +
  • Do not add udev devices after a small delay
  • +
  • Don't fail to run if compiled without GPG/PKCS7
  • +
  • Fix a segfault in fwupdtool caused by cleanup of USB plugins
  • +
  • Implement the systemd recommendations for offline updates
  • +
  • Improve performance when reading keys from the quirk database
  • +
  • Remove children of devices when the parent is removed
  • +
  • Rewrite synapticsmst to use modern error handling
  • +
  • + Rewrite the unifying plugin to use the new daemon-provided + functionality +
  • +
  • Show a time estimate on the progressbar after an update has started
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add support for the Synaptics Panamera hardware
  • +
  • Add validation for Alpine and Titan Ridge
  • +
  • Improve the Redfish plugin to actually work with real hardware
  • +
+

This release fixes the following bugs:

+
    +
  • Allow different plugins to add the same device
  • +
  • Allow flashing unifying devices in recovery mode
  • +
  • Allow running synapticsmst on non-Dell hardware
  • +
  • Check the ESP for sanity at startup
  • +
  • Do not hold hidraw devices open forever
  • +
  • Don't override _FORTIFY_SOURCE when building the EFI binary
  • +
  • Don't show passwords in fwupdmgr
  • +
  • Fix a potential segfault in smbios data parsing
  • +
  • Fix encoding the GUID into the capsule EFI variable
  • +
  • Fix various bugs when reading the thunderbolt version number
  • +
  • Reboot synapticsmst devices at the end of flash cycle
  • +
  • Show status messages when the daemon is initializing
  • +
  • Show the correct title when updating devices
  • +
  • Show the reasons that plugins are not run on the CLI
  • +
  • Use localedir in po/make-images
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a initial Redfish support
  • +
  • Add a tool to mimic the original fwupdate CLI interface
  • +
  • Allow devices to assign a plugin from the quirk subsystem
  • +
  • Change the quirk file structure to be more efficient
  • +
  • Merge fwupdate functionality into fwupd
  • +
  • + Run a plugin vfunc before and after all the composite devices are + updated +
  • +
  • Support more Wacom tablets
  • +
+

This release fixes the following bugs:

+
    +
  • Add release information for locked devices
  • +
  • Allow building with older meson
  • +
  • Detect the EFI system partition location at runtime
  • +
  • Do not use 8bitdo bootloader commands after a successful flash
  • +
  • Enable accesing downloaded files in flatpak and snap
  • +
  • Fix a potential buffer overflow when applying a DFU patch
  • +
  • Fix downgrading older releases to devices
  • +
  • Fix flashing devices that require a manual replug
  • +
  • Fix several small memory leaks in various places
  • +
  • Fix the retrieval of Redfish version
  • +
  • Fix unifying failure to detach when using a slow host controller
  • +
  • Set the Wacom device status when erasing and writing firmware
  • +
  • Show errors in the CLI if unable to access directory
  • +
  • Use the parent device name for Wacom sub-modules
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a plugin to update some future Wacom tablets
  • +
  • Add 'fwupdmgr get-topology' to show logical device tree
  • +
  • Add support for creating a flatpak
  • +
  • Add support for creating a snap
  • +
  • Add support for Motorola S-record files
  • +
  • Add the Linux Foundation public GPG keys for firmware and metadata
  • +
  • Show a translated warning when the server is limiting downloads
  • +
+

This release fixes the following bugs:

+
    +
  • Add a firmware diagnostic tool called fwupdtool
  • +
  • Adjust all licensing to LGPL 2.1+
  • +
  • + Allow installing more than one firmware using 'fwupdmgr + install' +
  • +
  • Allow specifying hwids with OR relationships
  • +
  • Do not call fu_plugin_init() on blacklisted plugins
  • +
  • Do not require libcolorhug to build
  • +
  • Fix a crash in libfwupd where no device ID is set
  • +
  • Fix a potential DoS in libdfu by limiting holes to 1MiB
  • +
  • Fix a segfault that sometimes occurs during cleanup of USB plugins
  • +
  • Fix Hardware-ID{0,1,2,12} compatibility with Microsoft
  • +
  • Hide devices that aren't updatable by default in fwupdmgr
  • +
  • Search all UEFI GUIDs when matching hardware
  • +
  • Stop matching Nintendo Switch Pro in the 8bitdo plugin
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add enable-remote and disable-remote commands to fwupdmgr
  • +
  • Add fu_plugin_add_compile_version() for libraries to use
  • +
  • Allow requiring specific versions of libraries for firmware updates
  • +
  • If no remotes are enabled try to enable the LVFS
  • +
  • Show a warning with interactive prompt when enabling a remote
  • +
+

This release fixes the following bugs:

+
    +
  • Check that EFI system partition is mounted before update
  • +
  • Disable synapticsmst remote control on failure
  • +
  • Don't recoldplug thunderbolt to fix a flashing failure
  • +
  • Fix SQL error when running 'fwupdmgr clear-offline'
  • +
  • Improve the update report message
  • +
  • Only enumerate Dell Docks if the type is known
  • +
  • Only run certtool if a new enough gnutls is present
  • +
  • Prevent a client crash if the daemon somehow sends invalid data
  • +
  • Reboot after scheduling using logind not systemd
  • +
  • Use the right encoding for the label in make-images
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add bash completion for fwupdmgr
  • +
  • Add support for newest Thunderbolt chips
  • +
  • Allow all functions that take device arguments to be prompted
  • +
  • Allow devices to use the runtime version when in bootloader mode
  • +
  • Allow overriding ESP mount point via conf file
  • +
  • Delete any old fwupdate capsules and efivars when launching fwupd
  • +
  • Generate Vala bindings
  • +
+

This release fixes the following bugs:

+
    +
  • Allow ctrl-d out of the prompt for devices
  • +
  • Allow to create package out of provided binary
  • +
  • Correct handling of unknown Thunderbolt devices
  • +
  • Correctly detect new remotes that are manually copied
  • +
  • Fix a crash related to when passing device to downgrade in CLI
  • +
  • Fix running the self tests when no fwupd is installed
  • +
  • Fix Unifying signature writing and parsing for Texas bootloader
  • +
  • Only send success and failure reports to the server
  • +
  • Use a CNAME to redirect to the correct CDN for metadata
  • +
  • Use a longer timeout when powering back the Thunderbolt device
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Offer to reboot when processing an offline update
  • +
  • Report the efivar, libsmbios and fwupdate library versions
  • +
  • Report Thunderbolt safe mode and SecureBoot status
  • +
  • Show the user a URL when they report a known problem
  • +
  • Support split cabinet archives as produced by Windows Update
  • +
+

This release fixes the following bugs:

+
    +
  • Be more careful deleting and modifying device history
  • +
  • Clarify which devices don't have upgrades
  • +
  • Ensure the Thunderbolt version is xx.yy
  • +
  • Fix a daemon warning when using fwupdmgr get-results
  • +
  • Fix crasher with MST flashing
  • +
  • Fix DFU detach with newer releases of libusb
  • +
  • Include the device VID and PID when generating the device-id
  • +
  • Set the RemoteId when using GetDetails
  • +
  • Stop matching 8bitdo DS4 controller VID/PID
  • +
  • Use help2man for dfu-tool and drop docbook dependencies
  • +
  • Use ngettext for any strings with plurals
  • +
  • Use the default value if ArchiveSizeMax is unspecified
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add D-Bus methods to get and modify the history information
  • +
  • Allow the user to share firmware update success or failure
  • +
  • Ask the user to refresh metadata when it is very old
  • +
  • Store firmware update success and failure to a local database
  • +
+

This release fixes the following bugs:

+
    +
  • Add a device name for locked UEFI devices
  • +
  • Allow each plugin to opt-in to the recoldplug action
  • +
  • Fix firmware downloading using gnome-software
  • +
  • Fix UX capsule reference to the one specified in efivar
  • +
  • Never add two devices to the daemon with the same ID
  • +
  • Rescan supported flags when refreshing metadata
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a new plugin to add support for CSR 'Driverless DFU'
  • +
  • Add initial SF30/SN30 Pro support
  • +
  • Support AppStream metadata with relative <location> URLs
  • +
+

This release fixes the following bugs:

+
    +
  • Add more metadata to the user-agent string
  • +
  • Block owned Dell TPM updates
  • +
  • Choose the correct component from provides matches using requirements
  • +
  • Do not try to parse huge compressed archive files
  • +
  • Fix a double-free bug in the Udev code
  • +
  • Handle Thunderbolt 'native' mode
  • +
  • + Use the new functionality in libgcab >= 1.0 to avoid writing temp + files +
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a plugin for the Nitrokey Storage device
  • +
  • Add support for the original AVR DFU protocol
  • +
  • Allow different plugins to claim the same device
  • +
  • Allow quirks to set common USB properties
  • +
  • Move a common plugin functionality out to a new shared object
  • +
  • Optionally delay the device removal for better replugging
  • +
  • Set environment variables to allow easy per-plugin debugging
  • +
  • Use a SHA1 hash for the internal DeviceID
  • +
+

This release fixes the following bugs:

+
    +
  • Add quirk for AT32UC3B1256 as used in the RubberDucky
  • +
  • Disable the dell plugin if libsmbios fails
  • +
  • Don't register for USB UDev events to later ignore them
  • +
  • Fix a possible buffer overflow when debugging ebitdo devices
  • +
  • Fix critical warning when more than one remote fails to load
  • +
  • Fix DFU attaching AVR32 devices like the XMEGA
  • +
  • Ignore useless Thunderbolt device types
  • +
  • Refactor ColorHug into a much more modern plugin
  • +
  • Release the Steelseries interface if getting the version failed
  • +
  • Remove autoconf-isms from the meson configure options
  • +
  • Show a nicer error message if the requirement fails
  • +
  • Sort the output of GetUpgrades correctly
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add support for HWID requirements
  • +
  • Add support for programming various AVR32 and XMEGA parts using DFU
  • +
  • Add the various DFU quirks for the Jabra Speak devices
  • +
  • Allow specifying the output file type for 'dfu-tool read'
  • +
  • Move the database of supported devices out into runtime loaded files
  • +
  • Support the IHEX record type 0x05
  • +
  • Use help2man to generate the man page at build time
  • +
  • Use the new quirk infrastructure for version numbers
  • +
+

This release fixes the following bugs:

+
    +
  • Catch invalid Dell dock component requests
  • +
  • Correctly output Intel HEX files with > 16bit offset addresses
  • +
  • Do not try to verify the element write if upload is unsupported
  • +
  • Fix a double-unref when updating any 8Bitdo device
  • +
  • Fix crash when enumerating with Dell dock connected but with no UEFI
  • +
  • Fix uploading large firmware files over DFU
  • +
  • Format the BCD USB revision numbers correctly
  • +
  • Guess the DFU transfer size if it is not specified
  • +
  • Include the reset timeout as wValue to fix some DFU bootloaders
  • +
  • Make the error message clearer when sans fonts are missing
  • +
  • Support devices with truncated DFU interface data
  • +
  • + Use the correct remote-specified username and passord when using + fwupdmgr +
  • +
  • Use the correct wDetachTimeOut when writing DFU firmware
  • +
  • Verify devices with legacy VIDs are actually 8Bitdo controllers
  • +
+
+
+ + +

This release breaks API and ABI to remove deprecated symbols!

+

This release adds the following features:

+
    +
  • Add a human-readable title for each remote
  • +
  • Add a method to return a list of upgrades for a specific device
  • +
  • + Add an 'Summary' and 'Icons' properties to each + device +
  • +
  • Add FuDeviceLocker to simplify device open/close lifecycles
  • +
  • Add functionality to blacklist Dell HW with problems
  • +
  • Add fu_plugin_check_supported()
  • +
  • Add fwupd_remote_get_checksum() to use in client programs
  • +
  • Add ModifyRemote as an easy way to enable and disable remotes
  • +
  • Add the plugin documentation to the main gtk-doc
  • +
  • Allow plugins to depend on each other
  • +
  • Disable the fallback USB plugin
  • +
  • Parse the SMBIOS v2 and v3 DMI tables directly
  • +
  • Support uploading the UEFI firmware splash image
  • +
  • Use the intel-wmi-thunderbolt kernel module to force power
  • +
+

This release fixes the following bugs:

+
    +
  • Only run SMI to toggle host MST GPIO on Dell systems with host MST
  • +
  • Disable unifying support if no CONFIG_HIDRAW support
  • +
  • Do not auto-open all USB devices at startup
  • +
  • Do not fail to load the daemon if cached metadata is invalid
  • +
  • Do not use system-specific infomation for UEFI PCI devices
  • +
  • Fix a crash when using fu_plugin_device_add_delay()
  • +
  • Fix the libdfu self test failure on s390 and ppc64
  • +
  • Fix various printing issues with the progressbar
  • +
  • Generate the LD script from the GObject introspection data
  • +
  • Never fallback to an offline update from client code
  • +
  • Only set the Dell coldplug delay when we know we need it
  • +
  • Prefer to use HWIDs to get DMI keys and DE table
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a configure switch for the LVFS remotes
  • +
  • Add a FirmwareBaseURI parameter to the remote config
  • +
  • Add a firmware builder that uses bubblewrap
  • +
  • + Add a python script to create fwupd compatible cab files from + Microsoft .exe files +
  • +
  • Add a thunderbolt plugin for new kernel interface
  • +
  • Allow plugins to get DMI data from the hardware in a safe way
  • +
  • Allow plugins to set metadata on devices created by other plugins
  • +
  • Optionally install the LVFS PKCS7 root certificate
  • +
  • Optionally use GnuTLS to verify PKCS7 certificates
  • +
+

This release fixes the following bugs:

+
    +
  • Add back options for HAVE_SYNAPTICS and HAVE_THUNDERBOLT
  • +
  • Allow configuring systemd and udev directories
  • +
  • Enable C99 support in meson.build
  • +
  • Fix an incomplete cipher when using XTEA on data not in 4 byte chunks
  • +
  • Fix minor const-correctness issues
  • +
  • Implement thunderbolt image validation
  • +
  • Remove the confusing ALLOW_OFFLINE and ALLOW_ONLINE flags
  • +
  • Show a bouncing progress bar if the percentage remains at zero
  • +
  • Use a hwid to match supported systems for synapticsmst
  • +
  • Use the new bootloader PIDs for Unifying pico receivers
  • +
  • When thunderbolt is in safe mode on a Dell recover using SMBIOS
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add DfuPatch to support forward-only firmware patching
  • +
  • Add --version option to fwupdmgr
  • +
  • Display all errors recorded by efi_error tracing
  • +
  • Make building introspection optional
  • +
  • Support embedded devices with local firmware metadata
  • +
+

This release fixes the following bugs:

+
    +
  • Check all the device GUIDs against the blacklist when added
  • +
  • Correct a memory leak in Dell plugin
  • +
  • Default to 'en' for UEFI capsule graphics
  • +
  • Don't log a warning when an unknown unifying report is parsed
  • +
  • Enable test suite via /etc/fwupd.conf
  • +
  • Fix a hang on 32 bit computers
  • +
  • Fix compilation of the policy on a variety of configurations
  • +
  • Fix UEFI crash when the product name is NULL
  • +
  • Make flashing ebitdo devices work with fu-ebitdo-tool
  • +
  • Make messages from installing capsules useful
  • +
  • Make sure the unifying percentage completion goes from 0% to 100%
  • +
  • Run the plugin coldplug methods in a predictable order
  • +
  • Test UEFI for kernel support during coldplug
  • +
  • Use new GUsb functionality to fix flashing Unifying devices
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a get-remotes command to fwupdmgr
  • +
  • Add a plugin to get the version of the AMT ME interface
  • +
  • Add Arch Linux to CI
  • +
  • Add some installed tests flashing actual hardware
  • +
  • Allow flashing Unifying devices in bootloader modes
  • +
  • Allow ordering the metadata remotes
  • +
+

This release fixes the following bugs:

+
    +
  • Do not check the runtime if the DFU device is in bootloader mode
  • +
  • Do not unlock devices when doing VerifyUpdate
  • +
  • Filter by Unifying SwId when making HID++2.0 requests
  • +
  • Fix downgrades when version_lowest is set
  • +
  • Fix the self tests when running on PPC64 big endian
  • +
  • Move the remotes parsing from the client to the server
  • +
  • Split up the Unifying HID++2.0 and HID++1.0 functionality
  • +
  • Store the metadata files rather than merging to one store
  • +
  • Use a longer timeout for some Unifying operations
  • +
  • Use the UFY DeviceID prefix for Unifying devides
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add installed tests that use the daemon
  • +
  • Add the ability to restrict firmware to specific vendors
  • +
  • Enable Travis CI for Fedora and Debian
  • +
  • Export some more API for dealing with checksums
  • +
  • Generate a images for status messages during system firmware update
  • +
  • Show progress download when refreshing metadata
  • +
+

This release fixes the following bugs:

+
    +
  • Compile with newer versions of meson
  • +
  • Ensure that firmware provides are legal GUIDs
  • +
  • Fix a common crash when refreshing metadata
  • +
  • Use the correct type signature in the D-Bus introspection file
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a 'downgrade' command to fwupdmgr
  • +
  • Add a 'get-releases' command to fwupdmgr
  • +
  • Add support for ConsoleKit2
  • +
  • Add support for Microsoft HardwareIDs
  • +
  • Allow downloading metadata from more than just the LVFS
  • +
  • Allow multiple checksums on devices and releases
  • +
+

This release fixes the following bugs:

+
    +
  • Allow to specify bindir
  • +
  • Correctly open Unifying devices with original factory firmware
  • +
  • Deprecate some of the old FwupdResult API
  • +
  • Do not copy the origin from the new metadata file
  • +
  • Do not expect a Unifying reply when issuing a REBOOT command
  • +
  • Do not re-download firmware that exists in the cache
  • +
  • Fix a problem when testing for a Dell system
  • +
  • Fix flashing new firmware to 8bitdo controllers
  • +
  • Increase minimum required AppStream-Glib version to 0.6.13
  • +
  • Make documentation and man pages optional
  • +
  • Make systemd dependency at least version 231
  • +
  • Only decompress the firmware after the signature check
  • +
  • Remove 'lib' prefix when looking for libraries
  • +
  • Return the remote ID when getting updates about hardware
  • +
  • Send the daemon the remote ID when sending firmware metadata
  • +
+
+
+ + +

This release adds the following feature:

+
    +
  • Add support for Unifying DFU features
  • +
+

This release fixes the following bugs:

+
    +
  • Do not spew a critial warning when parsing an invalid URI
  • +
  • Ensure device is closed if did not complete setup
  • +
  • Ensure steelseries device is closed if it returns an invalid packet
  • +
  • Fix man page installation location
  • +
  • Ignore spaces in the Unifying version prefix
  • +
  • Set HAVE_POLKIT_0_114 when polkit is newer than 0.114
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a config option to allow runtime disabling plugins by name
  • +
  • Add the Meson build system and remove autotools
  • +
  • Support signed Intel HEX files
  • +
+

This release fixes the following bugs:

+
    +
  • Add DFU quirk for OpenPICC and SIMtrace
  • +
  • Create directories in /var/cache as required
  • +
  • Refactor the unifying plugin now we know more about the hardware
  • +
  • Set the source origin when saving metadata
  • +
  • Support proxy servers in fwupdmgr
  • +
  • Use a 60 second timeout on all client downloads
  • +
+
+
+ + +

This release fixes the following bugs:

+
    +
  • Adjust systemd confinement restrictions
  • +
  • Do not hardcode docbook2man path
  • +
  • Don't initialize libsmbios on unsupported systems
  • +
  • Fix a crash when enumerating devices on a Dell WLD15
  • +
  • Fix compiler warnings
  • +
  • Fix fwupdmgr timeout with missing pending database
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a set of vfuncs that are run before and after a device update
  • +
  • + Add Dell-specific functionality to allow other plugins turn on + TBT/GPIO +
  • +
  • Add support for Intel Thunderbolt devices
  • +
  • Add support for Logitech Unifying devices
  • +
  • Add support for Synaptics MST cascades hubs
  • +
  • Add support for the Altus-Metrum ChaosKey device
  • +
  • Add VerifyUpdate to update the device checksums server-side
  • +
  • + Allow the metadata to match a version of fwupd and the existing fw + version +
  • +
+

This release fixes the following bugs:

+
    +
  • Add a new method for forcing a controller to flash mode
  • +
  • Always make sure we're getting a C99 compiler
  • +
  • Close USB devices before error returns
  • +
  • Don't read data from some DfuSe targets
  • +
  • Include all debug messages when run with --verbose
  • +
  • Return the pending UEFI update when not on AC power
  • +
  • + Use a heuristic for the start address if the firmware has no DfuSe + footer +
  • +
  • Use more restrictive settings when running under systemd
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a 'replace-data' command to dfu-tool
  • +
  • Use an animated progress bar when performing DFU operations
  • +
+

This release fixes the following bugs:

+
    +
  • Add quirks for HydraBus as it does not have a DFU runtime
  • +
  • + Don't create the UEFI dummy device if the unlock will happen on + next boot +
  • +
  • Enable hardening flags on more binaries
  • +
  • Fix an assert when unlocking the dummy ESRT device
  • +
  • Fix writing firmware to devices using the ST reference bootloader
  • +
  • Match the Dell TB16 device
  • +
  • Re-get the quirks when the DfuDevice gets a new GUsbDevice
  • +
  • Show the nicely formatted target name for DfuSe devices
  • +
  • Verify devices support updating in mode they are called
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add dfu_firmware_add_symbol()
  • +
  • Allow the argument to 'dfu-tool set-release' be major.minor
  • +
  • Load the Altos USB descriptor from ELF files
  • +
  • Support writing the IHEX symbol table
  • +
+

This release fixes the following bugs:

+
    +
  • Add a fallback for older appstream-glib releases
  • +
  • Fix a possible crash when uploading firmware files using libdfu
  • +
  • Fix libfwupd self tests when a host-provided fwupd is not available
  • +
  • + Show the human-readable version in the 'dfu-tool dump' + output +
  • +
  • Write the ELF files with the correct section type
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a set-address and set-target-size commands to dfu-util
  • +
  • Add a small library for talking with 0bitdo hardware
  • +
  • Add Dell TPM and TB15/WD15 support via new Dell provider
  • +
  • Add FU_DEVICE_FLAG_NEEDS_BOOTLOADER
  • +
  • Add fwupd_client_get_status()
  • +
  • Add fwupd_result_get_unique_id()
  • +
  • Add initial ELF reading and writing support to libdfu
  • +
  • Add support for installing multiple devices from a CAB file
  • +
  • Allow providers to export percentage completion
  • +
  • Show a progress notification when installing firmware
  • +
  • Show the vendor flashing instructions when installing
  • +
+

This release fixes the following bugs:

+
    +
  • Add XPS 9250 to Dell TPM modeswitch blacklist
  • +
  • Allow blacklisting devices by their GUID
  • +
  • Conditionally enable all providers based upon installed
  • +
  • Display flashes left in results output when it gets low
  • +
  • Do not attempt to add DFU devices not in runtime mode
  • +
  • Do not use the deprecated GNOME_COMPILE_WARNINGS
  • +
  • Don't fail while checking versions or locked state
  • +
  • Embed fwupd version in generated documentation
  • +
  • Ensure the ID is set when getting local firmware details
  • +
  • Fix gtk-doc build when srcdir != builddir
  • +
  • Fix libdfu hang when parsing corrupt IHEX files
  • +
  • Ignore devices that do not add at least one GUID
  • +
  • In get-details output, display the blob filename
  • +
  • Save the unique ID in the pending database
  • +
  • Support the 'DEVO' cipher kind in libdfu
  • +
  • Switch to the Amazon S3 CDN for firmware metadata
  • +
  • Update fwupdmgr manpage for new commands and arguments
  • +
  • Use a private gnupg key store
  • +
  • Use the correct firmware when installing a composite device
  • +
  • Use the SHA1 hash of the local file data as the origin
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a GetDetailsLocal() method to eventually replace GetDetails()
  • +
  • Add fu_device_get_alternate()
  • +
  • Allow devices to have multiple assigned GUIDs
  • +
  • Allow metainfo files to match only specific revisions of devices
  • +
  • Show the DFU protocol version in 'dfu-tool list'
  • +
+

This release fixes the following bugs:

+
    +
  • Enforce allowing providers to take away flash abilities
  • +
  • Only claim the DFU interface when required
  • +
  • Only return updatable devices from GetDevices()
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a --force flag to override provider warnings
  • +
  • Add device-added, device-removed and device-changed signals
  • +
  • Add dfu_image_get_element_default()
  • +
  • Add for a new device field 'Flashes Left'
  • +
  • Add fwupd_client_connect()
  • +
  • Add the 'monitor' debugging command for fwupdmgr
  • +
  • Add the 'supported' flag to the FuDevice
  • +
+

This release fixes the following bugs:

+
    +
  • Add summary and name field for Rival SteelSeries
  • +
  • Fix a critical warning when restarting the daemon
  • +
  • Fix BE issues when reading and writing DFU files
  • +
  • Make the device display name nicer
  • +
  • Match the AppStream metadata after a device has been added
  • +
  • Remove non-interactive pinentry setting from fu-keyring
  • +
  • Return all update descriptions newer than the installed version
  • +
  • Set the device description when parsing local firmware files
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a version plugin for SteelSeries hardware
  • +
  • Add FwupdClient and FwupdResult to libfwupd
  • +
  • Generate gtk-doc documentation for libfwupd
  • +
  • Return the device flags when getting firmware details
  • +
  • Support other checksum kinds
  • +
+

This release fixes the following bugs:

+
    +
  • Add Alienware to the version quirk table
  • +
  • Allow the test suite to run in %check
  • +
  • Do not return updates that require AC when on battery
  • +
  • Do not use /tmp for downloaded files
  • +
  • Test that GPG key import actually was successful
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add an unlock method for devices
  • +
  • Add a simple plugin infrastructure
  • +
  • Add ESRT enable method into UEFI provider
  • +
  • Install the hardcoded firmware AppStream file
  • +
+

This release fixes the following bugs:

+
    +
  • Correct the BCD version number for DFU 1.1
  • +
  • Do not use deprecated API from libappstream-glib
  • +
  • Ignore the DFU runtime on the DW1820A
  • +
  • Only read PCI OptionROM firmware when devices are manually unlocked
  • +
  • Require AC power before scheduling some types of firmware update
  • +
  • Show ignored DFU devices in dfu-util, but not in fwupd
  • +
+
+
+ + +

This release adds the following feature:

+
    +
  • + Add 'Created' and 'Modified' properties on + managed devices +
  • +
+

This release fixes the following bugs:

+
    +
  • Fix get-results for UEFI provider
  • +
  • Support vendor-specific UEFI version encodings
  • +
+
+
+ + +

This release fixes the following bugs:

+
    +
  • Always persist ColorHug devices after replug
  • +
  • Do not misdetect different ColorHug devices
  • +
  • Only dump the profiling data when run with --verbose
  • +
+
+
+ + +

+ This release adds a new GObject library called libdfu and a command + line client called dfu-tool. This is a low-level tool used to upgrade + USB device firmware and can either be shipped in the same package as + fwupd or split off as separate subpackages. +

+

This release adds the following feature:

+
    +
  • Add support for automatically updating USB DFU-capable devices
  • +
+

This release fixes the following bugs:

+
    +
  • Emit the changed signal after doing an update
  • +
  • Export the AppStream ID when returning device results
  • +
  • Fix compile with --disable-shared
  • +
  • Use new API available in fwup 0.5
  • +
  • Use the same device identification string format as Microsoft
  • +
+
+
+ + +

This release fixes the following bugs:

+
    +
  • Avoid seeking when reading the file magic during refresh
  • +
  • Do not assume that the compressed XML data will be NUL terminated
  • +
  • Use the correct user agent string for fwupdmgr
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add profiling data to debug slow startup times
  • +
  • Support cabinet archives files with more than one firmware
  • +
+

This release fixes the following bugs:

+
    +
  • Add the update description to the GetDetails results
  • +
  • + Clear the in-memory firmware store only after parsing a valid XML + file +
  • +
  • Ensure D-Bus remote errors are registered at fwupdmgr startup
  • +
  • + Fix verify-update to produce components with the correct provide + values +
  • +
  • Require appstream-glib 0.5.1
  • +
  • Show the dotted-decimal representation of the UEFI version number
  • +
  • + When the version is from the 'FW' extension do not cache + the device +
  • +
+
+
+ + +

This release fixes the following bugs:

+
    +
  • Fix the error message when no devices can be updated
  • +
  • Fix reading symlink to prevent crash with some compilers
  • +
+
+
+ + +

This release adds the following feature:

+
    +
  • Raise the dep on GLib to support and use g_autoptr()
  • +
+

This release fixes the following bugs:

+
    +
  • Do not merge existing firmware metadata
  • +
  • Do not reboot if racing with the PackageKit offline update mechanism
  • +
+
+
+ + +

This release adds the following feature:

+
    +
  • Remove fwsignd, we have the LVFS now
  • +
+

This release fixes the following bugs:

+
    +
  • Add application metadata when getting the updates list
  • +
  • Depend on appstream-glib >= 0.5.0
  • +
  • Don't apply firmware if something else is processing the update
  • +
  • Install fwupd into /usr/lib/$(triplet)/fwupd instead
  • +
  • Simplify the version properties on devices to avoid complexity
  • +
  • Update the offline update service to invoke right command
  • +
  • Use the new secure metadata URI
  • +
+
+
+ + +

+ For the device verification code to work correctly you need at least + libappstream-glib 0.5.0 installed. +

+

This release adds the following features:

+
    +
  • Add a Raspberry Pi firmware provider
  • +
  • Add a simple config file to store the correct LVFS download URI
  • +
  • Make parsing the option ROM runtime optional
  • +
+

This release fixes the following bugs:

+
    +
  • Allow fwupd to be autostarted by systemd
  • +
  • + Allow no arguments to 'fwupdmgr verify-update' and use sane + defaults +
  • +
  • Devices with option ROM are always internal
  • +
  • Do not pre-convert the update description from AppStream XML
  • +
  • Fix validation of written firmware
  • +
  • Move the verification and metadata matching phase to the daemon
  • +
  • Sign the test binary with the correct key
  • +
  • Use the AppStream 0.9 firmware specification by default
  • +
+
+
+ + +

+ In this release we've moved the LVFS website to the fwupd project + and made them work really well together. To update all the firmware on + your system is now just a case of 'fwupdmgr refresh && + fwupdmgr update'. + We've also added verification of BIOS and PCI ROM firmware, which + may be useful for forensics or to verify that system updates have been + applied. +

+

This release adds the following features:

+
    +
  • Actually parse the complete PCI option ROM
  • +
  • + Add a 'fwupdmgr update' command to update all devices to + latest versions +
  • +
  • Add a simple signing server that operates on .cab files
  • +
  • + Add a 'verify' command that verifies the cryptographic hash + of device firmware +
  • +
  • Allow clients to add new firmware metadata to the system cache
  • +
  • Move GetUpdates to the daemon
  • +
  • Move the LVFS website to the fwupd project
  • +
+

This release fixes the following bugs:

+
    +
  • Accept multiple files at one time when using fwupdmgr dump-rom
  • +
  • Automatically download metadata using fwupdmgr if required
  • +
  • Do not return NULL as a gboolean
  • +
  • Don't call efibootmgr after fwupdate
  • +
  • Fallback to offline install when calling the update argument
  • +
  • Fix Intel VBIOS detection on Dell hardware
  • +
  • Reload appstream data after refreshing
  • +
  • Use the new LVFS GPG key
  • +
  • Fix build: libgusb is required even without colorhug support
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Get the firmware version from the device descriptors
  • +
  • Run the offline actions using systemd when required
  • +
  • Support OpenHardware devices using the fwupd vendor extensions
  • +
+

This release fixes the following bugs:

+
    +
  • Add an UNKNOWN status so we can return meaningful enum values
  • +
  • Coldplug the devices before acquiring the well known name
  • +
+
+
+ + + + + + +

This release adds the following features:

+
    +
  • Add a 'get-updates' command to fwupdmgr
  • +
  • Add and document the offline-update lifecycle
  • +
  • Create a libfwupd shared library
  • +
+

This release fixes the following bugs:

+
    +
  • Create runtime directories if they do not exist
  • +
  • Do not crash when there are no devices to return
  • +
+
+
+ + +

fwupd is a simple daemon to allow session software to update firmware.

+
+
+
diff -Nru fwupd-1.1.4/data/org.freedesktop.fwupd.svg fwupd-1.2.5/data/org.freedesktop.fwupd.svg --- fwupd-1.1.4/data/org.freedesktop.fwupd.svg 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/data/org.freedesktop.fwupd.svg 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,209 @@ + + + + Adwaita Icon Template + + + + + + + + + + + image/svg+xml + + + + GNOME Design Team + + + + + Adwaita Icon Template + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fwupd + firmwareupdater + diff -Nru fwupd-1.1.4/data/remotes.d/lvfs.metainfo.xml fwupd-1.2.5/data/remotes.d/lvfs.metainfo.xml --- fwupd-1.1.4/data/remotes.d/lvfs.metainfo.xml 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/data/remotes.d/lvfs.metainfo.xml 2019-02-25 09:42:18.000000000 +0000 @@ -4,7 +4,7 @@ org.freedesktop.fwupd.remotes.lvfs Linux Vendor Firmware Service (stable firmware) - CC0 + CC0-1.0 diff -Nru fwupd-1.1.4/data/remotes.d/lvfs-testing.metainfo.xml fwupd-1.2.5/data/remotes.d/lvfs-testing.metainfo.xml --- fwupd-1.1.4/data/remotes.d/lvfs-testing.metainfo.xml 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/data/remotes.d/lvfs-testing.metainfo.xml 2019-02-25 09:42:18.000000000 +0000 @@ -4,7 +4,7 @@ org.freedesktop.fwupd.remotes.lvfs-testing Linux Vendor Firmware Service (testing firmware) - CC0 + CC0-1.0 diff -Nru fwupd-1.1.4/data/remotes.d/meson.build fwupd-1.2.5/data/remotes.d/meson.build --- fwupd-1.1.4/data/remotes.d/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/data/remotes.d/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -46,3 +46,10 @@ install: true, install_dir: join_paths(sysconfdir, 'fwupd', 'remotes.d'), ) +configure_file( + input : 'vendor-directory.conf', + output : 'vendor-directory.conf', + configuration : con2, + install: true, + install_dir: join_paths(sysconfdir, 'fwupd', 'remotes.d'), +) diff -Nru fwupd-1.1.4/data/remotes.d/README.md fwupd-1.2.5/data/remotes.d/README.md --- fwupd-1.1.4/data/remotes.d/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/data/remotes.d/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -1,12 +1,12 @@ Vendor Firmware =============== -These are the steps to add vendor that is installed as part of an OSTree image: +These are the steps to add vendor firmware that is installed as part of an embedded image such as an OSTree or ChromeOS image: * Change `/etc/fwupd/remotes.d/vendor.conf` to have `Enabled=true` * Change `/etc/fwupd/remotes.d/vendor.conf` to have the correct `Title` * Deploy the firmware to `/usr/share/fwupd/remotes.d/vendor/firmware` -* Deploy the metadata to `/usr/share/fwupd/remotes.d/vendor/vendor.xml` +* Deploy the metadata to `/usr/share/fwupd/remotes.d/vendor/vendor.xml.gz` The metadata should be of the form: @@ -39,6 +39,20 @@ in `/etc/fwupd/remotes.d/vendor.conf` and ensure the correct public key or signing certificate is installed in the `/etc/pki/fwupd` location. +Automatic metadata generation +============================= +`fwupd` and `fwupdtool` support automatically generating metadata for a remote +by configuring it to be a *directory* type. This is very convenient if you want to dynamically add firmware from multiple packages while generating the image but there are a few deficiencies: +* There will be a performance impact of starting the daemon or tool measured by O(# CAB files) +* It's not possible to verify metadata signature and any file validation should be part of the image validation. + +To enable this: +* Change `/etc/fwupd/remotes.d/vendor-directory.conf` to have `Enabled=true` +* Change `/etc/fwupd/remotes.d/vendor.conf-directory` to have the correct `Title` +* Deploy the firmware to `/usr/share/fwupd/remotes.d/vendor/firmware` +* Change `MetadataURI` to that of the directory (Eg `/usr/share/fwupd/remotes.d/vendor/`) + + Mirroring a Repository ====================== diff -Nru fwupd-1.1.4/data/remotes.d/vendor.conf fwupd-1.2.5/data/remotes.d/vendor.conf --- fwupd-1.1.4/data/remotes.d/vendor.conf 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/data/remotes.d/vendor.conf 2019-02-25 09:42:18.000000000 +0000 @@ -1,7 +1,6 @@ [fwupd Remote] - # this remote provides metadata shipped by the OS vendor and can be found in -# /usr/share/fwupd/remotes.d/vendor and /usr/share/fwupd/remotes.d/vendor/firmware +# @datadir@/fwupd/remotes.d/vendor and firmware in @datadir@/fwupd/remotes.d/vendor/firmware Enabled=false Title=Vendor Keyring=none diff -Nru fwupd-1.1.4/data/remotes.d/vendor-directory.conf fwupd-1.2.5/data/remotes.d/vendor-directory.conf --- fwupd-1.1.4/data/remotes.d/vendor-directory.conf 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/data/remotes.d/vendor-directory.conf 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,7 @@ +[fwupd Remote] +# this remote provides dynamically generated metadata shipped by the OS vendor and can +# be found in @datadir@/fwupd/remotes.d/vendor/firmware +Enabled=false +Title=Vendor (Automatic) +Keyring=none +MetadataURI=file://@datadir@/fwupd/remotes.d/vendor/firmware diff -Nru fwupd-1.1.4/data/tests/remotes.d/directory.conf fwupd-1.2.5/data/tests/remotes.d/directory.conf --- fwupd-1.1.4/data/tests/remotes.d/directory.conf 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/data/tests/remotes.d/directory.conf 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,4 @@ +[fwupd Remote] +Enabled=true +Keyring=none +MetadataURI=file:///tmp/fwupd-self-test/var/cache/fwupd diff -Nru fwupd-1.1.4/debian/changelog fwupd-1.2.5/debian/changelog --- fwupd-1.1.4/debian/changelog 2018-11-07 17:30:14.000000000 +0000 +++ fwupd-1.2.5/debian/changelog 2019-02-26 22:30:52.000000000 +0000 @@ -1,3 +1,30 @@ +fwupd (1.2.5-1) unstable; urgency=medium + + * New upstream version (1.2.5) + * Drop all patches, upstream + + -- Mario Limonciello Tue, 26 Feb 2019 16:30:52 -0600 + +fwupd (1.2.4-3) unstable; urgency=medium + + * Backport a patch from master that fixes FTBFS with newer glib + + -- Mario Limonciello Fri, 15 Feb 2019 08:06:55 -0600 + +fwupd (1.2.4-2) unstable; urgency=medium + + * debian: explicitly depend on shared-mime-info + + -- Mario Limonciello Thu, 14 Feb 2019 21:21:46 -0600 + +fwupd (1.2.4-1) unstable; urgency=medium + + * New upstream version + * refresh build dependencies + * Recommends on tpm2 stack to read PCR values + + -- Mario Limonciello Wed, 06 Feb 2019 20:31:24 -0600 + fwupd (1.1.4-1) unstable; urgency=medium * New upstream version diff -Nru fwupd-1.1.4/debian/compat fwupd-1.2.5/debian/compat --- fwupd-1.1.4/debian/compat 2018-11-07 17:29:39.000000000 +0000 +++ fwupd-1.2.5/debian/compat 2019-02-26 22:30:52.000000000 +0000 @@ -1 +1 @@ -10 +11 diff -Nru fwupd-1.1.4/debian/control fwupd-1.2.5/debian/control --- fwupd-1.1.4/debian/control 2018-11-07 17:30:14.000000000 +0000 +++ fwupd-1.2.5/debian/control 2019-02-26 22:30:52.000000000 +0000 @@ -8,7 +8,7 @@ Build-Depends: bash-completion, bubblewrap, - debhelper (>= 10.3), + debhelper (>= 11), dh-strip-nondeterminism, fontconfig, fonts-noto, @@ -21,7 +21,6 @@ gobject-introspection, gtk-doc-tools, help2man, - libappstream-glib-dev (>= 0.7.4), libarchive-dev, libcairo-dev, libcairo-gobject2, @@ -41,6 +40,7 @@ libsoup2.4-dev, libsqlite3-dev, libtool-bin, + libxmlb-dev (>= 0.1.5), locales, meson, pkg-config, @@ -48,12 +48,13 @@ python3-gi-cairo, python3-pil, python3-requests, + shared-mime-info, systemd (>= 231), udev, umockdev, valac, valgrind [!ia64 !riscv64 !x32 !mips !sparc64 !sh4 !ppc64 !powerpcspe !hppa !alpha !mips64el !armhf !armel !mipsel !m68k], -Standards-Version: 4.1.4 +Standards-Version: 4.3.0 Section: admin Homepage: https://github.com/hughsie/fwupd Vcs-Git: https://salsa.debian.org/efi-team/fwupd.git @@ -69,8 +70,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides the library used by the daemon. @@ -78,9 +78,12 @@ Package: fwupd Architecture: linux-any Depends: ${misc:Depends}, - ${shlibs:Depends} + ${shlibs:Depends}, + shared-mime-info Recommends: python3, bolt, + tpm2-tools, + tpm2-abrmd, fwupd-signed Breaks: gir1.2-dfu-1.0 (<< 0.9.7-1), libdfu1 (<< 0.9.7-1), @@ -93,8 +96,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details Package: fwupd-tests @@ -116,8 +118,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides a set of installed tests that can be run to validate @@ -132,8 +133,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides development documentation for creating a package that @@ -152,8 +152,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides the development files for libfwupd diff -Nru fwupd-1.1.4/debian/control.in fwupd-1.2.5/debian/control.in --- fwupd-1.1.4/debian/control.in 2018-11-07 17:29:39.000000000 +0000 +++ fwupd-1.2.5/debian/control.in 2019-02-26 22:30:52.000000000 +0000 @@ -6,7 +6,7 @@ Matthias Klumpp , Mario Limonciello Build-Depends: %%%DYNAMIC%%% -Standards-Version: 4.1.4 +Standards-Version: 4.3.0 Section: admin Homepage: https://github.com/hughsie/fwupd Vcs-Git: https://salsa.debian.org/efi-team/fwupd.git @@ -22,8 +22,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides the library used by the daemon. @@ -31,9 +30,12 @@ Package: fwupd Architecture: linux-any Depends: ${misc:Depends}, - ${shlibs:Depends} + ${shlibs:Depends}, + shared-mime-info Recommends: python3, bolt, + tpm2-tools, + tpm2-abrmd, fwupd-signed Breaks: gir1.2-dfu-1.0 (<< 0.9.7-1), libdfu1 (<< 0.9.7-1), @@ -46,8 +48,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details Package: fwupd-tests @@ -69,8 +70,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides a set of installed tests that can be run to validate @@ -85,8 +85,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides development documentation for creating a package that @@ -105,8 +104,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides the development files for libfwupd diff -Nru fwupd-1.1.4/debian/docs fwupd-1.2.5/debian/docs --- fwupd-1.1.4/debian/docs 2018-11-07 17:29:39.000000000 +0000 +++ fwupd-1.2.5/debian/docs 2019-02-26 22:29:28.000000000 +0000 @@ -1 +1 @@ -NEWS + diff -Nru fwupd-1.1.4/debian/fwupd.install fwupd-1.2.5/debian/fwupd.install --- fwupd-1.1.4/debian/fwupd.install 2018-11-07 17:29:39.000000000 +0000 +++ fwupd-1.2.5/debian/fwupd.install 2019-02-26 22:30:52.000000000 +0000 @@ -4,6 +4,7 @@ usr/share/bash-completion usr/share/fwupd/* usr/share/dbus-1/* +usr/share/icons/* usr/share/polkit-1/* usr/share/locale usr/share/metainfo/* diff -Nru fwupd-1.1.4/debian/fwupd-tests.install fwupd-1.2.5/debian/fwupd-tests.install --- fwupd-1.1.4/debian/fwupd-tests.install 2018-11-07 17:29:39.000000000 +0000 +++ fwupd-1.2.5/debian/fwupd-tests.install 2019-02-26 22:29:28.000000000 +0000 @@ -5,3 +5,4 @@ usr/share/installed-tests/* usr/lib/*/fwupd-plugins-3/libfu_plugin_test.so debian/lintian/fwupd-tests usr/share/lintian/overrides +etc/fwupd/remotes.d/fwupd-tests.conf diff -Nru fwupd-1.1.4/debian/fwupd-tests.postinst fwupd-1.2.5/debian/fwupd-tests.postinst --- fwupd-1.1.4/debian/fwupd-tests.postinst 2018-11-07 17:29:39.000000000 +0000 +++ fwupd-1.2.5/debian/fwupd-tests.postinst 2019-02-26 22:29:28.000000000 +0000 @@ -12,4 +12,12 @@ echo "To enable test suite, modify /etc/fwupd/daemon.conf" fi fi + if [ -f /etc/fwupd/remotes.d/fwupd-tests.conf ]; then + if [ "$CI" = "true" ]; then + sed "s,^Enabled=false,Enabled=true," -i /etc/fwupd/remotes.d/fwupd-tests.conf + else + echo "To enable test suite, enable fwupd-tests remote" + fi + + fi fi diff -Nru fwupd-1.1.4/debian/gir1.2-fwupd-2.0.install fwupd-1.2.5/debian/gir1.2-fwupd-2.0.install --- fwupd-1.1.4/debian/gir1.2-fwupd-2.0.install 2018-11-07 17:29:39.000000000 +0000 +++ fwupd-1.2.5/debian/gir1.2-fwupd-2.0.install 2019-02-26 22:29:28.000000000 +0000 @@ -1 +1 @@ -usr/lib/*/girepository-1.0/Fwupd-2.0.typelib +usr/lib/*/girepository-1.0/*.typelib diff -Nru fwupd-1.1.4/debian/libfwupd2.install fwupd-1.2.5/debian/libfwupd2.install --- fwupd-1.1.4/debian/libfwupd2.install 2018-11-07 17:29:39.000000000 +0000 +++ fwupd-1.2.5/debian/libfwupd2.install 2019-02-26 22:29:28.000000000 +0000 @@ -1 +1 @@ -usr/lib/*/libfwup*.so.* +usr/lib/*/*.so.* diff -Nru fwupd-1.1.4/debian/libfwupd2.symbols fwupd-1.2.5/debian/libfwupd2.symbols --- fwupd-1.1.4/debian/libfwupd2.symbols 2018-11-07 17:29:39.000000000 +0000 +++ fwupd-1.2.5/debian/libfwupd2.symbols 2019-02-26 22:30:52.000000000 +0000 @@ -20,6 +20,10 @@ LIBFWUPD_1.1.1@LIBFWUPD_1.1.1 1.1.1 LIBFWUPD_1.1.2@LIBFWUPD_1.1.2 1.1.2 LIBFWUPD_1.1.3@LIBFWUPD_1.1.3 1.1.3 + LIBFWUPD_1.2.1@LIBFWUPD_1.2.1 1.2.1 + LIBFWUPD_1.2.2@LIBFWUPD_1.2.2 1.2.2 + LIBFWUPD_1.2.4@LIBFWUPD_1.2.4 1.2.4 + LIBFWUPD_1.2.5@LIBFWUPD_1.2.5 1.2.5 fwupd_build_history_report_json@LIBFWUPD_1.0.4 1.0.4 fwupd_build_machine_id@LIBFWUPD_1.0.4 1.0.4 fwupd_build_user_agent@LIBFWUPD_1.0.3 1.0.3 @@ -41,6 +45,7 @@ fwupd_client_get_remotes@LIBFWUPD_0.9.3 1.0.0 fwupd_client_get_results@LIBFWUPD_0.7.0 1.0.0 fwupd_client_get_status@LIBFWUPD_0.7.3 1.0.0 + fwupd_client_get_tainted@LIBFWUPD_1.2.4 1.2.4 fwupd_client_get_type@LIBFWUPD_0.7.0 1.0.0 fwupd_client_get_upgrades@LIBFWUPD_0.9.8 1.0.0 fwupd_client_install@LIBFWUPD_0.7.0 1.0.0 @@ -55,6 +60,7 @@ fwupd_device_add_flag@LIBFWUPD_0.9.3 1.0.0 fwupd_device_add_guid@LIBFWUPD_0.9.3 1.0.0 fwupd_device_add_icon@LIBFWUPD_0.9.8 1.0.0 + fwupd_device_add_instance_id@LIBFWUPD_1.2.5 1.2.5 fwupd_device_add_release@LIBFWUPD_0.9.8 1.0.0 fwupd_device_compare@LIBFWUPD_1.1.1 1.1.1 fwupd_device_flag_from_string@LIBFWUPD_0.7.0 1.0.0 @@ -70,6 +76,7 @@ fwupd_device_get_icons@LIBFWUPD_0.9.8 1.0.0 fwupd_device_get_id@LIBFWUPD_0.9.3 1.0.0 fwupd_device_get_install_duration@LIBFWUPD_1.1.3 1.1.3 + fwupd_device_get_instance_ids@LIBFWUPD_1.2.5 1.2.5 fwupd_device_get_modified@LIBFWUPD_0.9.3 1.0.0 fwupd_device_get_name@LIBFWUPD_0.9.3 1.0.0 fwupd_device_get_parent@LIBFWUPD_1.0.8 1.0.8 @@ -81,6 +88,7 @@ fwupd_device_get_summary@LIBFWUPD_0.9.3 1.0.0 fwupd_device_get_type@LIBFWUPD_0.9.3 1.0.0 fwupd_device_get_update_error@LIBFWUPD_0.9.8 1.0.0 + fwupd_device_get_update_message@LIBFWUPD_1.2.4 1.2.4 fwupd_device_get_update_state@LIBFWUPD_0.9.8 1.0.0 fwupd_device_get_vendor@LIBFWUPD_0.9.3 1.0.0 fwupd_device_get_vendor_id@LIBFWUPD_0.9.4 1.0.0 @@ -89,6 +97,7 @@ fwupd_device_get_version_lowest@LIBFWUPD_0.9.3 1.0.0 fwupd_device_has_flag@LIBFWUPD_0.9.3 1.0.0 fwupd_device_has_guid@LIBFWUPD_0.9.3 1.0.0 + fwupd_device_has_instance_id@LIBFWUPD_1.2.5 1.2.5 fwupd_device_incorporate@LIBFWUPD_1.1.0 1.1.0 fwupd_device_new@LIBFWUPD_0.9.3 1.0.0 fwupd_device_remove_flag@LIBFWUPD_0.9.3 1.0.0 @@ -106,6 +115,7 @@ fwupd_device_set_serial@LIBFWUPD_1.1.2 1.1.2 fwupd_device_set_summary@LIBFWUPD_0.9.3 1.0.0 fwupd_device_set_update_error@LIBFWUPD_0.9.8 1.0.0 + fwupd_device_set_update_message@LIBFWUPD_1.2.4 1.2.4 fwupd_device_set_update_state@LIBFWUPD_0.9.8 1.0.0 fwupd_device_set_vendor@LIBFWUPD_0.9.3 1.0.0 fwupd_device_set_vendor_id@LIBFWUPD_0.9.4 1.0.0 @@ -119,6 +129,11 @@ fwupd_error_quark@LIBFWUPD_0.1.1 1.0.0 fwupd_error_to_string@LIBFWUPD_0.7.0 1.0.0 fwupd_get_os_release@LIBFWUPD_1.0.7 1.0.7 + fwupd_guid_from_string@LIBFWUPD_1.2.5 1.2.5 + fwupd_guid_hash_data@LIBFWUPD_1.2.5 1.2.5 + fwupd_guid_hash_string@LIBFWUPD_1.2.5 1.2.5 + fwupd_guid_is_valid@LIBFWUPD_1.2.5 1.2.5 + fwupd_guid_to_string@LIBFWUPD_1.2.5 1.2.5 fwupd_keyring_kind_from_string@LIBFWUPD_0.9.7 1.0.0 fwupd_keyring_kind_to_string@LIBFWUPD_0.9.7 1.0.0 fwupd_release_add_checksum@LIBFWUPD_0.9.3 1.0.0 @@ -128,31 +143,41 @@ fwupd_release_get_appstream_id@LIBFWUPD_0.9.3 1.0.0 fwupd_release_get_checksums@LIBFWUPD_0.9.3 1.0.0 fwupd_release_get_description@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_get_details_url@LIBFWUPD_1.2.4 1.2.4 fwupd_release_get_filename@LIBFWUPD_0.9.3 1.0.0 fwupd_release_get_homepage@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_get_install_duration@LIBFWUPD_1.2.1 1.2.4 fwupd_release_get_license@LIBFWUPD_0.9.3 1.0.0 fwupd_release_get_metadata@LIBFWUPD_1.0.4 1.0.4 fwupd_release_get_metadata_item@LIBFWUPD_1.0.4 1.0.4 fwupd_release_get_name@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_get_protocol@LIBFWUPD_1.2.2 1.2.4 fwupd_release_get_remote_id@LIBFWUPD_0.9.3 1.0.0 fwupd_release_get_size@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_get_source_url@LIBFWUPD_1.2.4 1.2.4 fwupd_release_get_summary@LIBFWUPD_0.9.3 1.0.0 fwupd_release_get_trust_flags@LIBFWUPD_0.9.8 1.0.0 fwupd_release_get_type@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_get_update_message@LIBFWUPD_1.2.4 1.2.4 fwupd_release_get_uri@LIBFWUPD_0.9.3 1.0.0 fwupd_release_get_vendor@LIBFWUPD_0.9.3 1.0.0 fwupd_release_get_version@LIBFWUPD_0.9.3 1.0.0 fwupd_release_new@LIBFWUPD_0.9.3 1.0.0 fwupd_release_set_appstream_id@LIBFWUPD_0.9.3 1.0.0 fwupd_release_set_description@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_set_details_url@LIBFWUPD_1.2.4 1.2.4 fwupd_release_set_filename@LIBFWUPD_0.9.3 1.0.0 fwupd_release_set_homepage@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_set_install_duration@LIBFWUPD_1.2.1 1.2.4 fwupd_release_set_license@LIBFWUPD_0.9.3 1.0.0 fwupd_release_set_name@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_set_protocol@LIBFWUPD_1.2.2 1.2.4 fwupd_release_set_remote_id@LIBFWUPD_0.9.3 1.0.0 fwupd_release_set_size@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_set_source_url@LIBFWUPD_1.2.4 1.2.4 fwupd_release_set_summary@LIBFWUPD_0.9.3 1.0.0 fwupd_release_set_trust_flags@LIBFWUPD_0.9.8 1.0.0 + fwupd_release_set_update_message@LIBFWUPD_1.2.4 1.2.4 fwupd_release_set_uri@LIBFWUPD_0.9.3 1.0.0 fwupd_release_set_vendor@LIBFWUPD_0.9.3 1.0.0 fwupd_release_set_version@LIBFWUPD_0.9.3 1.0.0 diff -Nru fwupd-1.1.4/debian/libfwupd-dev.install fwupd-1.2.5/debian/libfwupd-dev.install --- fwupd-1.1.4/debian/libfwupd-dev.install 2018-11-07 17:29:39.000000000 +0000 +++ fwupd-1.2.5/debian/libfwupd-dev.install 2019-02-26 22:29:28.000000000 +0000 @@ -1,6 +1,5 @@ -usr/include/fwupd-1/fwupd.h -usr/include/fwupd-1/libfwupd -usr/lib/*/libfwupd*.so -usr/lib/*/pkgconfig/fwupd.pc -usr/share/gir-1.0/Fwupd*.gir +usr/include/* +usr/lib/*/*.so +usr/lib/*/pkgconfig/*.pc +usr/share/gir-1.0/*.gir usr/share/vala/vapi diff -Nru fwupd-1.1.4/debian/lintian/fwupd fwupd-1.2.5/debian/lintian/fwupd --- fwupd-1.1.4/debian/lintian/fwupd 2018-11-07 17:29:39.000000000 +0000 +++ fwupd-1.2.5/debian/lintian/fwupd 2019-02-26 22:30:52.000000000 +0000 @@ -4,3 +4,5 @@ fwupd binary: systemd-service-file-missing-install-key lib/systemd/system/system-update.target.wants/fwupd-offline-update.service #see debian bug 896012 fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_upower.so +#EFI applications are PE executables +fwupd: executable-not-elf-or-script usr/lib/fwupd/efi/*.efi diff -Nru fwupd-1.1.4/debian/rules fwupd-1.2.5/debian/rules --- fwupd-1.1.4/debian/rules 2018-11-07 17:29:39.000000000 +0000 +++ fwupd-1.2.5/debian/rules 2019-02-26 22:30:52.000000000 +0000 @@ -3,6 +3,7 @@ export LC_ALL := C.UTF-8 export DEB_BUILD_MAINT_OPTIONS = hardening=+all +export DEB_LDFLAGS_MAINT_STRIP=-Wl,-Bsymbolic-functions #GPGME needs this for proper building on 32 bit archs ifeq "$(DEB_HOST_ARCH_BITS)" "32" @@ -27,7 +28,7 @@ %: [ -f debian/control ] || debian/rules regenerate_control - dh $@ --with gir,systemd + dh $@ --with gir override_dh_auto_clean: regenerate_control rm -fr debian/build @@ -57,10 +58,15 @@ dh_install -pfwupd usr/lib/fwupd/efi ;\ dh_install -pfwupd usr/lib/fwupd/fwupdate; \ fi + #if build with meson subproject in CI need to install this too + if [ -n "$CI" ] && [ -f debian/tmp/usr/lib/xb-tool ]; then \ + dh_install -pfwupd usr/lib/xb-tool ;\ + fi dh_missing -a --fail-missing #this is placed in fwupd-tests rm -f debian/fwupd/usr/lib/*/fwupd-plugins-3/libfu_plugin_test.so + rm -f debian/fwupd/etc/fwupd/remotes.d/fwupd-tests.conf ifeq (debian,$(SB_STYLE)) # Generate the template source for the Debian signing service to use @@ -85,7 +91,7 @@ fi override_dh_builddeb: - dh_builddeb -- -Zxz + dh_builddeb ifeq (ubuntu,$(SB_STYLE)) if [ -d debian/tmp/usr/lib/fwupd/efi/ ]; then \ mkdir -p debian/fwupd-images/$(deb_version) ;\ @@ -95,3 +101,6 @@ dpkg-distaddfile $(tar_name) raw-uefi - ;\ fi endif + +override_dh_shlibdeps: + dh_shlibdeps $$DHSLIBS diff -Nru fwupd-1.1.4/debian/source/lintian-overrides fwupd-1.2.5/debian/source/lintian-overrides --- fwupd-1.1.4/debian/source/lintian-overrides 2018-11-07 17:29:39.000000000 +0000 +++ fwupd-1.2.5/debian/source/lintian-overrides 2019-02-26 22:29:28.000000000 +0000 @@ -1,2 +1,4 @@ #github doesn't have these fwupd source: debian-watch-does-not-check-gpg-signature +#to make CI happy until libxmlb lands +fwupd source: source-is-missing diff -Nru fwupd-1.1.4/docs/version-format.md fwupd-1.2.5/docs/version-format.md --- fwupd-1.1.4/docs/version-format.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/docs/version-format.md 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,58 @@ +Version Formats +=============== + +In some circumstances fwupd has to convert from a unsigned integer version +number into something that has either been used in documentation or has been +defined in some specification. +A good example here is the UEFI ESRT table, which specifies a `uint32_t` for +the version but does not specify how this should be formatted for the user. + +As is typical in underspecified specifications, vendors have converted the +integer in different ways. For instance, Dell uses version strings like 1.2.3 +and Microsoft use versions like 1.2.3.4. + +The fwudp daemon can match specific devices and apply the correct version style +using quirk files. The version format can also be specified in the firmware +`metainfo.xml` file so that the new version is correctly shown, and so that it +matches on the LVFS website. + +The current version formats supported by fwupd and the LVFS are: + + * `plain`: Use plain integer version numbers with no dots, e.g. `AABBCCDD` + * `quad`: Use Dell-style `AA.BB.CC.DD` version numbers + * `triplet`: Use Microsoft-style `AA.BB.CCDD` version numbers + * `pair`: Use two `AABB.CCDD` version numbers + * `bcd`: Use binary coded decimal notation + * `intel-me`: Use Intel ME-style notation (`aaa+11.bbbbb.CC.DDDD`) + * `intel-me2`: Use alternate Intel ME-style-style `A.B.CC.DDDD` notation + +These can be specified in quirk files like this: + + # Vendor Modelname + [Guid=5b92717b-2cad-4a96-a13b-9d65781df8bf] + VersionFormat = intel-me2 + +...or in metainfo.xml files like this: + + + intel-me2 + + +Runtime requirements +-------------------- + +Versions of fwupd `< 1.2.0` can only support firmware updates with key values +`LVFS::VersionFormat` of `quad` and `triplet`. Additionally, on older versions +no quirk `VersionFormat` device fixups are supported. + +If want to use one of the additional version formats you should depend on a +specific version of fwupd in the firmware file: + + + org.freedesktop.fwupd + + +This is not *strictly* required, as the integer value can be used for update +calculations if the version is specified in hex (e.g. `0x12345678`) in the +`` tag, although the user might get a bit confused if the update +version does not match the update description. diff -Nru fwupd-1.1.4/.github/pull_request_template.md fwupd-1.2.5/.github/pull_request_template.md --- fwupd-1.1.4/.github/pull_request_template.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/.github/pull_request_template.md 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,5 @@ +Type of pull request: +- [ ] New plugin (Please include [new plugin checklist](https://github.com/hughsie/fwupd/wiki/New-plugin-checklist)) +- [ ] Code fix +- [ ] Feature +- [ ] Documentation diff -Nru fwupd-1.1.4/.gitignore fwupd-1.2.5/.gitignore --- fwupd-1.1.4/.gitignore 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/.gitignore 2019-02-25 09:42:18.000000000 +0000 @@ -11,6 +11,7 @@ /prime /stage /snap/.snapcraft +/libxmlb /*.deb /*.ddeb /*.changes diff -Nru fwupd-1.1.4/.gitmodules fwupd-1.2.5/.gitmodules --- fwupd-1.1.4/.gitmodules 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/.gitmodules 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,3 @@ +[submodule "contrib/flatpak"] + path = contrib/flatpak + url = https://github.com/flathub/org.freedesktop.fwupd diff -Nru fwupd-1.1.4/.lgtm.yml fwupd-1.2.5/.lgtm.yml --- fwupd-1.1.4/.lgtm.yml 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/.lgtm.yml 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,21 @@ +extraction: + python: + python_setup: + version: "3" + cpp: + prepare: + packages: + - bsdtar + - python3-gi + - libcogl-pango-dev + - python3-pil + - python3-cairo + after_prepare: + - "wget -O libxmlb.zip https://github.com/hughsie/libxmlb/archive/0.1.5.zip" + - "mkdir -p subprojects/libxmlb" + - "bsdtar --strip-components=1 -xvf libxmlb.zip -C subprojects/libxmlb" + index: + build_command: + - "meson setup build" + - "ninja -C build" + diff -Nru fwupd-1.1.4/libfwupd/fwupd-client.c fwupd-1.2.5/libfwupd/fwupd-client.c --- fwupd-1.1.4/libfwupd/fwupd-client.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/libfwupd/fwupd-client.c 2019-02-25 09:42:18.000000000 +0000 @@ -37,6 +37,7 @@ typedef struct { FwupdStatus status; + gboolean tainted; guint percentage; gchar *daemon_version; GDBusConnection *conn; @@ -57,6 +58,7 @@ PROP_STATUS, PROP_PERCENTAGE, PROP_DAEMON_VERSION, + PROP_TAINTED, PROP_LAST }; @@ -131,6 +133,14 @@ g_object_notify (G_OBJECT (client), "status"); } } + if (g_variant_dict_contains (dict, "Tainted")) { + g_autoptr(GVariant) val = NULL; + val = g_dbus_proxy_get_cached_property (proxy, "Tainted"); + if (val != NULL) { + priv->tainted = g_variant_get_boolean (val); + g_object_notify (G_OBJECT (client), "tainted"); + } + } if (g_variant_dict_contains (dict, "Percentage")) { g_autoptr(GVariant) val = NULL; val = g_dbus_proxy_get_cached_property (proxy, "Percentage"); @@ -203,6 +213,7 @@ { FwupdClientPrivate *priv = GET_PRIVATE (client); g_autoptr(GVariant) val = NULL; + g_autoptr(GVariant) val2 = NULL; g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); @@ -235,6 +246,9 @@ val = g_dbus_proxy_get_cached_property (priv->proxy, "DaemonVersion"); if (val != NULL) fwupd_client_set_daemon_version (client, g_variant_get_string (val, NULL)); + val2 = g_dbus_proxy_get_cached_property (priv->proxy, "Tainted"); + if (val2 != NULL) + priv->tainted = g_variant_get_boolean (val2); return TRUE; } @@ -1139,6 +1153,24 @@ } /** + * fwupd_client_get_tainted: + * @client: A #FwupdClient + * + * Gets if the daemon has been tainted by 3rd party code. + * + * Returns: %TRUE if the daemon is unsupported + * + * Since: 1.2.4 + **/ +gboolean +fwupd_client_get_tainted (FwupdClient *client) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + return priv->tainted; +} + +/** * fwupd_client_update_metadata: * @client: A #FwupdClient * @remote_id: the remote ID, e.g. `lvfs-testing` @@ -1461,6 +1493,9 @@ case PROP_STATUS: g_value_set_uint (value, priv->status); break; + case PROP_TAINTED: + g_value_set_boolean (value, priv->tainted); + break; case PROP_PERCENTAGE: g_value_set_uint (value, priv->percentage); break; @@ -1595,10 +1630,21 @@ */ pspec = g_param_spec_uint ("status", NULL, NULL, 0, FWUPD_STATUS_LAST, FWUPD_STATUS_UNKNOWN, - G_PARAM_READWRITE); + G_PARAM_READWRITE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_STATUS, pspec); /** + * FwupdClient:tainted: + * + * If the daemon is tainted by 3rd party code. + * + * Since: 1.2.4 + */ + pspec = g_param_spec_boolean ("tainted", NULL, NULL, FALSE, + G_PARAM_READABLE | G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_TAINTED, pspec); + + /** * FwupdClient:percentage: * * The last-reported percentage of the daemon. @@ -1607,7 +1653,7 @@ */ pspec = g_param_spec_uint ("percentage", NULL, NULL, 0, 100, 0, - G_PARAM_READWRITE); + G_PARAM_READWRITE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_PERCENTAGE, pspec); /** @@ -1618,7 +1664,7 @@ * Since: 0.9.6 */ pspec = g_param_spec_string ("daemon-version", NULL, NULL, - NULL, G_PARAM_READABLE); + NULL, G_PARAM_READABLE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_DAEMON_VERSION, pspec); } diff -Nru fwupd-1.1.4/libfwupd/fwupd-client.h fwupd-1.2.5/libfwupd/fwupd-client.h --- fwupd-1.1.4/libfwupd/fwupd-client.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/libfwupd/fwupd-client.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_CLIENT_H -#define __FWUPD_CLIENT_H +#pragma once #include #include @@ -116,6 +115,7 @@ GCancellable *cancellable, GError **error); FwupdStatus fwupd_client_get_status (FwupdClient *client); +gboolean fwupd_client_get_tainted (FwupdClient *client); guint fwupd_client_get_percentage (FwupdClient *client); const gchar *fwupd_client_get_daemon_version (FwupdClient *client); @@ -128,6 +128,3 @@ GError **error); G_END_DECLS - -#endif /* __FWUPD_CLIENT_H */ - diff -Nru fwupd-1.1.4/libfwupd/fwupd-common.c fwupd-1.2.5/libfwupd/fwupd-common.c --- fwupd-1.1.4/libfwupd/fwupd-common.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/libfwupd/fwupd-common.c 2019-02-25 09:42:18.000000000 +0000 @@ -16,6 +16,10 @@ #include #include +#if !GLIB_CHECK_VERSION(2,54,0) +#include +#endif + /** * fwupd_checksum_guess_kind: * @checksum: A checksum @@ -45,7 +49,7 @@ } static const gchar * -_g_checksum_type_to_string (GChecksumType checksum_type) +fwupd_checksum_type_to_string_display (GChecksumType checksum_type) { if (checksum_type == G_CHECKSUM_MD5) return "MD5"; @@ -72,7 +76,9 @@ fwupd_checksum_format_for_display (const gchar *checksum) { GChecksumType kind = fwupd_checksum_guess_kind (checksum); - return g_strdup_printf ("%s(%s)", _g_checksum_type_to_string (kind), checksum); + return g_strdup_printf ("%s(%s)", + fwupd_checksum_type_to_string_display (kind), + checksum); } /** @@ -350,12 +356,27 @@ { FwupdRelease *rel = fwupd_device_get_release_default (dev); GPtrArray *checksums; + const gchar *tmp; /* identify the firmware used */ json_builder_set_member_name (builder, "Checksum"); checksums = fwupd_release_get_checksums (rel); json_builder_add_string_value (builder, fwupd_checksum_get_by_kind (checksums, G_CHECKSUM_SHA1)); + /* identify the firmware written */ + checksums = fwupd_device_get_checksums (dev); + tmp = fwupd_checksum_get_by_kind (checksums, G_CHECKSUM_SHA1); + if (tmp != NULL) { + json_builder_set_member_name (builder, "ChecksumDevice"); + json_builder_add_string_value (builder, tmp); + } + + /* include the protocol used */ + if (fwupd_release_get_protocol (rel) != NULL) { + json_builder_set_member_name (builder, "Protocol"); + json_builder_add_string_value (builder, fwupd_release_get_protocol (rel)); + } + /* set the error state of the report */ json_builder_set_member_name (builder, "UpdateState"); json_builder_add_int_value (builder, fwupd_device_get_update_state (dev)); @@ -363,6 +384,10 @@ json_builder_set_member_name (builder, "UpdateError"); json_builder_add_string_value (builder, fwupd_device_get_update_error (dev)); } + if (fwupd_release_get_update_message (rel) != NULL) { + json_builder_set_member_name (builder, "UpdateMessage"); + json_builder_add_string_value (builder, fwupd_release_get_update_message (rel)); + } /* map back to the dev type on the LVFS */ json_builder_set_member_name (builder, "Guid"); @@ -491,3 +516,305 @@ } return data; } + +#define FWUPD_GUID_NAMESPACE_DEFAULT "6ba7b810-9dad-11d1-80b4-00c04fd430c8" +#define FWUPD_GUID_NAMESPACE_MICROSOFT "70ffd812-4c7f-4c7d-0000-000000000000" + +typedef struct __attribute__((packed)) { + guint32 a; + guint16 b; + guint16 c; + guint16 d; + guint8 e[6]; +} fwupd_guid_native_t; + +/** + * fwupd_guid_to_string: + * @guid: a #fwupd_guid_t to read + * @flags: some %FwupdGuidFlags, e.g. %FWUPD_GUID_FLAG_MIXED_ENDIAN + * + * Returns a text GUID of mixed or BE endian for a packed buffer. + * + * Returns: A new GUID + * + * Since: 1.2.5 + **/ +gchar * +fwupd_guid_to_string (const fwupd_guid_t *guid, FwupdGuidFlags flags) +{ + fwupd_guid_native_t gnat; + + g_return_val_if_fail (guid != NULL, NULL); + + /* copy to avoid issues with aligning */ + memcpy (&gnat, guid, sizeof(gnat)); + + /* mixed is bizaar, but specified as the DCE encoding */ + if (flags & FWUPD_GUID_FLAG_MIXED_ENDIAN) { + return g_strdup_printf ("%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", + GUINT32_FROM_LE(gnat.a), + GUINT16_FROM_LE(gnat.b), + GUINT16_FROM_LE(gnat.c), + GUINT16_FROM_BE(gnat.d), + gnat.e[0], gnat.e[1], + gnat.e[2], gnat.e[3], + gnat.e[4], gnat.e[5]); + } + return g_strdup_printf ("%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", + GUINT32_FROM_BE(gnat.a), + GUINT16_FROM_BE(gnat.b), + GUINT16_FROM_BE(gnat.c), + GUINT16_FROM_BE(gnat.d), + gnat.e[0], gnat.e[1], + gnat.e[2], gnat.e[3], + gnat.e[4], gnat.e[5]); +} + +#if !GLIB_CHECK_VERSION(2,54,0) +static gboolean +str_has_sign (const gchar *str) +{ + return str[0] == '-' || str[0] == '+'; +} + +static gboolean +str_has_hex_prefix (const gchar *str) +{ + return str[0] == '0' && g_ascii_tolower (str[1]) == 'x'; +} + +static gboolean +g_ascii_string_to_unsigned (const gchar *str, + guint base, + guint64 min, + guint64 max, + guint64 *out_num, + GError **error) +{ + const gchar *end_ptr = NULL; + gint saved_errno = 0; + guint64 number; + + g_return_val_if_fail (str != NULL, FALSE); + g_return_val_if_fail (base >= 2 && base <= 36, FALSE); + g_return_val_if_fail (min <= max, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + if (str[0] == '\0') { + g_set_error_literal (error, + G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "Empty string is not a number"); + return FALSE; + } + + errno = 0; + number = g_ascii_strtoull (str, (gchar **)&end_ptr, base); + saved_errno = errno; + + if (g_ascii_isspace (str[0]) || str_has_sign (str) || + (base == 16 && str_has_hex_prefix (str)) || + (saved_errno != 0 && saved_errno != ERANGE) || + end_ptr == NULL || + *end_ptr != '\0') { + g_set_error (error, + G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "“%s” is not an unsigned number", str); + return FALSE; + } + if (saved_errno == ERANGE || number < min || number > max) { + g_autofree gchar *min_str = g_strdup_printf ("%" G_GUINT64_FORMAT, min); + g_autofree gchar *max_str = g_strdup_printf ("%" G_GUINT64_FORMAT, max); + g_set_error (error, + G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "Number “%s” is out of bounds [%s, %s]", + str, min_str, max_str); + return FALSE; + } + if (out_num != NULL) + *out_num = number; + return TRUE; +} +#endif /* GLIB_CHECK_VERSION(2,54,0) */ + +/** + * fwupd_guid_from_string: + * @guidstr: (nullable): a GUID, e.g. `00112233-4455-6677-8899-aabbccddeeff` + * @guid: a #fwupd_guid_t, or NULL to just check the GUID + * @flags: some %FwupdGuidFlags, e.g. %FWUPD_GUID_FLAG_MIXED_ENDIAN + * @error: A #GError or %NULL + * + * Converts a string GUID into its binary encoding. All string GUIDs are + * formatted as big endian but on-disk can be encoded in different ways. + * + * Returns: %TRUE for success + * + * Since: 1.2.5 + **/ +gboolean +fwupd_guid_from_string (const gchar *guidstr, + fwupd_guid_t *guid, + FwupdGuidFlags flags, + GError **error) +{ + fwupd_guid_native_t gu = { 0x0 }; + gboolean mixed_endian = flags & FWUPD_GUID_FLAG_MIXED_ENDIAN; + guint64 tmp; + g_auto(GStrv) split = NULL; + + g_return_val_if_fail (guidstr != NULL, FALSE); + + /* split into sections */ + if (strlen (guidstr) != 36) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "is not valid format"); + return FALSE; + } + split = g_strsplit (guidstr, "-", 5); + if (g_strv_length (split) != 5) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "is not valid format, no dashes"); + return FALSE; + } + if (strlen (split[0]) != 8 && strlen (split[1]) != 4 && + strlen (split[2]) != 4 && strlen (split[3]) != 4 && + strlen (split[4]) != 12) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "is not valid format, not GUID"); + return FALSE; + } + + /* parse */ + if (!g_ascii_string_to_unsigned (split[0], 16, 0, 0xffffffff, &tmp, error)) + return FALSE; + gu.a = mixed_endian ? GUINT32_TO_LE(tmp) : GUINT32_TO_BE(tmp); + if (!g_ascii_string_to_unsigned (split[1], 16, 0, 0xffff, &tmp, error)) + return FALSE; + gu.b = mixed_endian ? GUINT16_TO_LE(tmp) : GUINT16_TO_BE(tmp); + if (!g_ascii_string_to_unsigned (split[2], 16, 0, 0xffff, &tmp, error)) + return FALSE; + gu.c = mixed_endian ? GUINT16_TO_LE(tmp) : GUINT16_TO_BE(tmp); + if (!g_ascii_string_to_unsigned (split[3], 16, 0, 0xffff, &tmp, error)) + return FALSE; + gu.d = GUINT16_TO_BE(tmp); + for (guint i = 0; i < 6; i++) { + gchar buffer[3] = { 0x0 }; + memcpy (buffer, split[4] + (i * 2), 2); + if (!g_ascii_string_to_unsigned (buffer, 16, 0, 0xff, &tmp, error)) + return FALSE; + gu.e[i] = tmp; + } + if (guid != NULL) + memcpy (guid, &gu, sizeof(gu)); + + /* success */ + return TRUE; +} + +/** + * fwupd_guid_hash_data: + * @data: data to hash + * @datasz: length of @data + * @flags: some %FwupdGuidFlags, e.g. %FWUPD_GUID_FLAG_NAMESPACE_MICROSOFT + * + * Returns a GUID for some data. This uses a hash and so even small + * differences in the @data will produce radically different return values. + * + * The implementation is taken from RFC4122, Section 4.1.3; specifically + * using a type-5 SHA-1 hash. + * + * Returns: A new GUID, or %NULL for internal error + * + * Since: 1.2.5 + **/ +gchar * +fwupd_guid_hash_data (const guint8 *data, gsize datasz, FwupdGuidFlags flags) +{ + const gchar *namespace_id = FWUPD_GUID_NAMESPACE_DEFAULT; + gsize digestlen = 20; + guint8 hash[20]; + fwupd_guid_t uu_namespace; + fwupd_guid_t uu_new; + g_autoptr(GChecksum) csum = NULL; + + g_return_val_if_fail (namespace_id != NULL, NULL); + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (datasz != 0, NULL); + + /* old MS GUID */ + if (flags & FWUPD_GUID_FLAG_NAMESPACE_MICROSOFT) + namespace_id = FWUPD_GUID_NAMESPACE_MICROSOFT; + + /* convert the namespace to binary: hardcoded BE, not @flags */ + if (!fwupd_guid_from_string (namespace_id, &uu_namespace, FWUPD_GUID_FLAG_NONE, NULL)) + return NULL; + + /* hash the namespace and then the string */ + csum = g_checksum_new (G_CHECKSUM_SHA1); + g_checksum_update (csum, (guchar *) &uu_namespace, sizeof(uu_namespace)); + g_checksum_update (csum, (guchar *) data, (gssize) datasz); + g_checksum_get_digest (csum, hash, &digestlen); + + /* copy most parts of the hash 1:1 */ + memcpy (uu_new, hash, sizeof(uu_new)); + + /* set specific bits according to Section 4.1.3 */ + uu_new[6] = (guint8) ((uu_new[6] & 0x0f) | (5 << 4)); + uu_new[8] = (guint8) ((uu_new[8] & 0x3f) | 0x80); + return fwupd_guid_to_string ((const fwupd_guid_t *) &uu_new, flags); +} + +/** + * fwupd_guid_is_valid: + * @guid: string to check, e.g. `00112233-4455-6677-8899-aabbccddeeff` + * + * Checks the string is a valid GUID. + * + * Returns: %TRUE if @guid was a valid GUID, %FALSE otherwise + * + * Since: 1.2.5 + **/ +gboolean +fwupd_guid_is_valid (const gchar *guid) +{ + if (guid == NULL) + return FALSE; + if (!fwupd_guid_from_string (guid, NULL, FWUPD_GUID_FLAG_NONE, NULL)) + return FALSE; + if (g_strcmp0 (guid, "00000000-0000-0000-0000-000000000000") == 0) + return FALSE; + return TRUE; +} + +/** + * fwupd_guid_hash_string: + * @str: A source string to use as a key + * + * Returns a GUID for a given string. This uses a hash and so even small + * differences in the @str will produce radically different return values. + * + * The default implementation is taken from RFC4122, Section 4.1.3; specifically + * using a type-5 SHA-1 hash with a DNS namespace. + * The same result can be obtained with this simple python program: + * + * #!/usr/bin/python + * import uuid + * print uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org') + * + * Returns: A new GUID, or %NULL if the string was invalid + * + * Since: 1.2.5 + **/ +gchar * +fwupd_guid_hash_string (const gchar *str) +{ + if (str == NULL || str[0] == '\0') + return NULL; + return fwupd_guid_hash_data ((const guint8 *) str, strlen (str), + FWUPD_GUID_FLAG_NONE); +} diff -Nru fwupd-1.1.4/libfwupd/fwupd-common.h fwupd-1.2.5/libfwupd/fwupd-common.h --- fwupd-1.1.4/libfwupd/fwupd-common.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/libfwupd/fwupd-common.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,17 +4,39 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_COMMON_H -#define __FWUPD_COMMON_H +#pragma once #include +G_BEGIN_DECLS + #define FWUPD_DBUS_PATH "/" #define FWUPD_DBUS_SERVICE "org.freedesktop.fwupd" #define FWUPD_DBUS_INTERFACE "org.freedesktop.fwupd" #define FWUPD_DEVICE_ID_ANY "*" +/** + * FwupdGuidFlags: + * @FWUPD_GUID_FLAG_NONE: No trust + * @FWUPD_GUID_FLAG_NAMESPACE_MICROSOFT: Use the Microsoft-compatible namespace + * @FWUPD_GUID_FLAG_MIXED_ENDIAN: Use EFI mixed endian representation + * + * The flags to show how the data should be converted. + **/ +typedef enum { + FWUPD_GUID_FLAG_NONE = 0, /* Since: 1.2.5 */ + FWUPD_GUID_FLAG_NAMESPACE_MICROSOFT = 1 << 0, /* Since: 1.2.5 */ + FWUPD_GUID_FLAG_MIXED_ENDIAN = 1 << 1, /* Since: 1.2.5 */ + /*< private >*/ + FWUPD_GUID_FLAG_LAST +} FwupdGuidFlags; + +/* GObject Introspection does not understand typedefs with sizes */ +#ifndef __GI_SCANNER__ +typedef guint8 fwupd_guid_t[16]; +#endif + const gchar *fwupd_checksum_get_best (GPtrArray *checksums); const gchar *fwupd_checksum_get_by_kind (GPtrArray *checksums, GChecksumType kind); @@ -27,4 +49,25 @@ gchar *fwupd_build_history_report_json (GPtrArray *devices, GError **error); -#endif /* __FWUPD_COMMON_H */ +#ifndef __GI_SCANNER__ +gchar *fwupd_guid_to_string (const fwupd_guid_t *guid, + FwupdGuidFlags flags); +gboolean fwupd_guid_from_string (const gchar *guidstr, + fwupd_guid_t *guid, + FwupdGuidFlags flags, + GError **error); +#else +gchar *fwupd_guid_to_string (const guint8 guid[16], + FwupdGuidFlags flags); +gboolean fwupd_guid_from_string (const gchar *guidstr, + guint8 guid[16], + FwupdGuidFlags flags, + GError **error); +#endif +gboolean fwupd_guid_is_valid (const gchar *guid); +gchar *fwupd_guid_hash_string (const gchar *str); +gchar *fwupd_guid_hash_data (const guint8 *data, + gsize datasz, + FwupdGuidFlags flags); + +G_END_DECLS diff -Nru fwupd-1.1.4/libfwupd/fwupd-common-private.h fwupd-1.2.5/libfwupd/fwupd-common-private.h --- fwupd-1.1.4/libfwupd/fwupd-common-private.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/libfwupd/fwupd-common-private.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,13 +4,14 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_COMMON_PRIVATE_H -#define __FWUPD_COMMON_PRIVATE_H +#pragma once #include #include "fwupd-common.h" +G_BEGIN_DECLS + gchar *fwupd_checksum_format_for_display (const gchar *checksum); -#endif /* __FWUPD_COMMON_PRIVATE_H */ +G_END_DECLS diff -Nru fwupd-1.1.4/libfwupd/fwupd-deprecated.h fwupd-1.2.5/libfwupd/fwupd-deprecated.h --- fwupd-1.1.4/libfwupd/fwupd-deprecated.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/libfwupd/fwupd-deprecated.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,9 +4,10 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_DEPRECATED_H -#define __FWUPD_DEPRECATED_H +#pragma once + +G_BEGIN_DECLS /* indeed, nothing */ -#endif /* __FWUPD_DEPRECATED_H */ +G_END_DECLS diff -Nru fwupd-1.1.4/libfwupd/fwupd-device.c fwupd-1.2.5/libfwupd/fwupd-device.c --- fwupd-1.1.4/libfwupd/fwupd-device.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/libfwupd/fwupd-device.c 2019-02-25 09:42:18.000000000 +0000 @@ -34,6 +34,7 @@ guint64 modified; guint64 flags; GPtrArray *guids; + GPtrArray *instance_ids; GPtrArray *icons; gchar *name; gchar *serial; @@ -51,6 +52,7 @@ guint32 install_duration; FwupdUpdateState update_state; gchar *update_error; + gchar *update_message; GPtrArray *releases; FwupdDevice *parent; } FwupdDevicePrivate; @@ -362,6 +364,69 @@ } /** + * fwupd_device_get_instance_ids: + * @device: A #FwupdDevice + * + * Gets the InstanceIDs. + * + * Returns: (element-type utf8) (transfer none): the InstanceID + * + * Since: 1.2.5 + **/ +GPtrArray * +fwupd_device_get_instance_ids (FwupdDevice *device) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_val_if_fail (FWUPD_IS_DEVICE (device), NULL); + return priv->instance_ids; +} + +/** + * fwupd_device_has_instance_id: + * @device: A #FwupdDevice + * @instance_id: the InstanceID, e.g. `PCI\VEN_10EC&DEV_525A` + * + * Finds out if the device has this specific InstanceID. + * + * Returns: %TRUE if the InstanceID is found + * + * Since: 1.2.5 + **/ +gboolean +fwupd_device_has_instance_id (FwupdDevice *device, const gchar *instance_id) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + + g_return_val_if_fail (FWUPD_IS_DEVICE (device), FALSE); + + for (guint i = 0; i < priv->instance_ids->len; i++) { + const gchar *instance_id_tmp = g_ptr_array_index (priv->instance_ids, i); + if (g_strcmp0 (instance_id, instance_id_tmp) == 0) + return TRUE; + } + return FALSE; +} + +/** + * fwupd_device_add_instance_id: + * @device: A #FwupdDevice + * @instance_id: the GUID, e.g. `PCI\VEN_10EC&DEV_525A` + * + * Adds the InstanceID if it does not already exist. + * + * Since: 1.2.5 + **/ +void +fwupd_device_add_instance_id (FwupdDevice *device, const gchar *instance_id) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_if_fail (FWUPD_IS_DEVICE (device)); + if (fwupd_device_has_instance_id (device, instance_id)) + return; + g_ptr_array_add (priv->instance_ids, g_strdup (instance_id)); +} + +/** * fwupd_device_get_icons: * @device: A #FwupdDevice * @@ -977,6 +1042,8 @@ fwupd_device_set_plugin (self, priv_donor->plugin); if (priv->update_error == NULL) fwupd_device_set_update_error (self, priv_donor->update_error); + if (priv->update_message == NULL) + fwupd_device_set_update_message (self, priv_donor->update_message); if (priv->version == NULL) fwupd_device_set_version (self, priv_donor->version); if (priv->version_lowest == NULL) @@ -987,6 +1054,10 @@ const gchar *tmp = g_ptr_array_index (priv_donor->guids, i); fwupd_device_add_guid (self, tmp); } + for (guint i = 0; i < priv_donor->instance_ids->len; i++) { + const gchar *tmp = g_ptr_array_index (priv_donor->instance_ids, i); + fwupd_device_add_instance_id (self, tmp); + } for (guint i = 0; i < priv_donor->icons->len; i++) { const gchar *tmp = g_ptr_array_index (priv_donor->icons, i); fwupd_device_add_icon (self, tmp); @@ -1133,6 +1204,11 @@ FWUPD_RESULT_KEY_UPDATE_ERROR, g_variant_new_string (priv->update_error)); } + if (priv->update_message != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_UPDATE_MESSAGE, + g_variant_new_string (priv->update_message)); + } if (priv->update_state != FWUPD_UPDATE_STATE_UNKNOWN) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_STATE, @@ -1144,6 +1220,12 @@ FWUPD_RESULT_KEY_SERIAL, g_variant_new_string (priv->serial)); } + if (priv->instance_ids->len > 0) { + const gchar * const *tmp = (const gchar * const *) priv->instance_ids->pdata; + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_INSTANCE_IDS, + g_variant_new_strv (tmp, priv->instance_ids->len)); + } } /* create an array with all the metadata in */ @@ -1220,6 +1302,12 @@ fwupd_device_add_guid (device, guids[i]); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_INSTANCE_IDS) == 0) { + g_autofree const gchar **instance_ids = g_variant_get_strv (value, NULL); + for (guint i = 0; instance_ids != NULL && instance_ids[i] != NULL; i++) + fwupd_device_add_instance_id (device, instance_ids[i]); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_ICON) == 0) { g_autofree const gchar **icons = g_variant_get_strv (value, NULL); for (guint i = 0; icons != NULL && icons[i] != NULL; i++) @@ -1287,6 +1375,10 @@ fwupd_device_set_update_error (device, g_variant_get_string (value, NULL)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_MESSAGE) == 0) { + fwupd_device_set_update_message (device, g_variant_get_string (value, NULL)); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_STATE) == 0) { fwupd_device_set_update_state (device, g_variant_get_uint32 (value)); return; @@ -1386,6 +1478,42 @@ } /** + * fwupd_device_get_update_message: + * @device: A #FwupdDevice + * + * Gets the update message. + * + * Returns: the update message, or %NULL if unset + * + * Since: 1.2.4 + **/ +const gchar * +fwupd_device_get_update_message (FwupdDevice *device) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_val_if_fail (FWUPD_IS_DEVICE (device), NULL); + return priv->update_message; +} + +/** + * fwupd_device_set_update_message: + * @device: A #FwupdDevice + * @update_message: the update message string + * + * Sets the update message. + * + * Since: 1.2.4 + **/ +void +fwupd_device_set_update_message (FwupdDevice *device, const gchar *update_message) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_if_fail (FWUPD_IS_DEVICE (device)); + g_free (priv->update_message); + priv->update_message = g_strdup (update_message); +} + +/** * fwupd_device_get_update_error: * @device: A #FwupdDevice * @@ -1499,6 +1627,7 @@ { FwupdDevicePrivate *priv = GET_PRIVATE (device); GString *str; + g_autoptr(GHashTable) ids = NULL; g_return_val_if_fail (FWUPD_IS_DEVICE (device), NULL); @@ -1509,9 +1638,23 @@ str = g_string_append (str, "Unknown Device\n"); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DEVICE_ID, priv->id); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_PARENT_DEVICE_ID, priv->parent_id); + ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + for (guint i = 0; i < priv->instance_ids->len; i++) { + const gchar *instance_id = g_ptr_array_index (priv->instance_ids, i); + g_hash_table_insert (ids, + fwupd_guid_hash_string (instance_id), + g_strdup (instance_id)); + } for (guint i = 0; i < priv->guids->len; i++) { const gchar *guid = g_ptr_array_index (priv->guids, i); - fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_GUID, guid); + const gchar *instance_id = g_hash_table_lookup (ids, guid); + if (instance_id == NULL) { + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_GUID, guid); + } else { + g_autofree gchar *tmp = NULL; + tmp = g_strdup_printf ("%s <- %s", guid, instance_id); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_GUID, tmp); + } } fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_SERIAL, priv->serial); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_SUMMARY, priv->summary); @@ -1545,6 +1688,7 @@ fwupd_pad_kv_unx (str, FWUPD_RESULT_KEY_MODIFIED, priv->modified); fwupd_pad_kv_ups (str, FWUPD_RESULT_KEY_UPDATE_STATE, priv->update_state); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_ERROR, priv->update_error); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_MESSAGE, priv->update_message); for (guint i = 0; i < priv->releases->len; i++) { FwupdRelease *release = g_ptr_array_index (priv->releases, i); g_autofree gchar *tmp = fwupd_release_to_string (release); @@ -1567,6 +1711,7 @@ { FwupdDevicePrivate *priv = GET_PRIVATE (device); priv->guids = g_ptr_array_new_with_free_func (g_free); + priv->instance_ids = g_ptr_array_new_with_free_func (g_free); priv->icons = g_ptr_array_new_with_free_func (g_free); priv->checksums = g_ptr_array_new_with_free_func (g_free); priv->releases = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); @@ -1590,10 +1735,12 @@ g_free (priv->vendor_id); g_free (priv->plugin); g_free (priv->update_error); + g_free (priv->update_message); g_free (priv->version); g_free (priv->version_lowest); g_free (priv->version_bootloader); g_ptr_array_unref (priv->guids); + g_ptr_array_unref (priv->instance_ids); g_ptr_array_unref (priv->icons); g_ptr_array_unref (priv->checksums); g_ptr_array_unref (priv->releases); diff -Nru fwupd-1.1.4/libfwupd/fwupd-device.h fwupd-1.2.5/libfwupd/fwupd-device.h --- fwupd-1.1.4/libfwupd/fwupd-device.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/libfwupd/fwupd-device.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_DEVICE_H -#define __FWUPD_DEVICE_H +#pragma once #include @@ -102,6 +101,11 @@ const gchar *guid); GPtrArray *fwupd_device_get_guids (FwupdDevice *device); const gchar *fwupd_device_get_guid_default (FwupdDevice *device); +void fwupd_device_add_instance_id (FwupdDevice *device, + const gchar *instance_id); +gboolean fwupd_device_has_instance_id (FwupdDevice *device, + const gchar *instance_id); +GPtrArray *fwupd_device_get_instance_ids (FwupdDevice *device); void fwupd_device_add_icon (FwupdDevice *device, const gchar *icon); GPtrArray *fwupd_device_get_icons (FwupdDevice *device); @@ -112,6 +116,9 @@ const gchar *fwupd_device_get_update_error (FwupdDevice *device); void fwupd_device_set_update_error (FwupdDevice *device, const gchar *update_error); +const gchar *fwupd_device_get_update_message (FwupdDevice *device); +void fwupd_device_set_update_message (FwupdDevice *device, + const gchar *update_message); void fwupd_device_add_release (FwupdDevice *device, FwupdRelease *release); GPtrArray *fwupd_device_get_releases (FwupdDevice *device); @@ -120,6 +127,3 @@ FwupdDevice *device2); G_END_DECLS - -#endif /* __FWUPD_DEVICE_H */ - diff -Nru fwupd-1.1.4/libfwupd/fwupd-device-private.h fwupd-1.2.5/libfwupd/fwupd-device-private.h --- fwupd-1.1.4/libfwupd/fwupd-device-private.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/libfwupd/fwupd-device-private.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_DEVICE_PRIVATE_H -#define __FWUPD_DEVICE_PRIVATE_H +#pragma once #include @@ -22,5 +21,3 @@ G_END_DECLS -#endif /* __FWUPD_DEVICE_PRIVATE_H */ - diff -Nru fwupd-1.1.4/libfwupd/fwupd-enums.c fwupd-1.2.5/libfwupd/fwupd-enums.c --- fwupd-1.1.4/libfwupd/fwupd-enums.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/libfwupd/fwupd-enums.c 2019-02-25 09:42:18.000000000 +0000 @@ -57,6 +57,8 @@ return "downloading"; if (status == FWUPD_STATUS_WAITING_FOR_AUTH) return "waiting-for-auth"; + if (status == FWUPD_STATUS_SHUTDOWN) + return "shutdown"; return NULL; } @@ -99,6 +101,8 @@ return FWUPD_STATUS_DEVICE_BUSY; if (g_strcmp0 (status, "waiting-for-auth") == 0) return FWUPD_STATUS_WAITING_FOR_AUTH; + if (g_strcmp0 (status, "shutdown") == 0) + return FWUPD_STATUS_SHUTDOWN; return FWUPD_STATUS_LAST; } @@ -135,6 +139,8 @@ return "registered"; if (device_flag == FWUPD_DEVICE_FLAG_NEEDS_REBOOT) return "needs-reboot"; + if (device_flag == FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN) + return "needs-shutdown"; if (device_flag == FWUPD_DEVICE_FLAG_REPORTED) return "reported"; if (device_flag == FWUPD_DEVICE_FLAG_NOTIFIED) @@ -149,6 +155,10 @@ return "wait-for-replug"; if (device_flag == FWUPD_DEVICE_FLAG_IGNORE_VALIDATION) return "ignore-validation"; + if (device_flag == FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED) + return "another-write-required"; + if (device_flag == FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS) + return "no-auto-instance-ids"; if (device_flag == FWUPD_DEVICE_FLAG_UNKNOWN) return "unknown"; return NULL; @@ -189,6 +199,8 @@ return FWUPD_DEVICE_FLAG_REGISTERED; if (g_strcmp0 (device_flag, "needs-reboot") == 0) return FWUPD_DEVICE_FLAG_NEEDS_REBOOT; + if (g_strcmp0 (device_flag, "needs-shutdown") == 0) + return FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN; if (g_strcmp0 (device_flag, "reported") == 0) return FWUPD_DEVICE_FLAG_REPORTED; if (g_strcmp0 (device_flag, "notified") == 0) @@ -203,6 +215,10 @@ return FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG; if (g_strcmp0 (device_flag, "ignore-validation") == 0) return FWUPD_DEVICE_FLAG_IGNORE_VALIDATION; + if (g_strcmp0 (device_flag, "another-write-required") == 0) + return FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED; + if (g_strcmp0 (device_flag, "no-auto-instance-ids") == 0) + return FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS; return FWUPD_DEVICE_FLAG_UNKNOWN; } diff -Nru fwupd-1.1.4/libfwupd/fwupd-enums.h fwupd-1.2.5/libfwupd/fwupd-enums.h --- fwupd-1.1.4/libfwupd/fwupd-enums.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/libfwupd/fwupd-enums.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,11 +4,12 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_ENUMS_H -#define __FWUPD_ENUMS_H +#pragma once #include +G_BEGIN_DECLS + /** * FwupdStatus: * @FWUPD_STATUS_UNKNOWN: Unknown state @@ -24,6 +25,7 @@ * @FWUPD_STATUS_DEVICE_ERASE: Erasing a device * @FWUPD_STATUS_WAITING_FOR_AUTH: Waiting for authentication * @FWUPD_STATUS_DEVICE_BUSY: The device is busy + * @FWUPD_STATUS_SHUTDOWN: The daemon is shutting down * * The flags to show daemon status. **/ @@ -41,6 +43,7 @@ FWUPD_STATUS_DEVICE_ERASE, /* Since: 1.0.0 */ FWUPD_STATUS_WAITING_FOR_AUTH, /* Since: 1.0.0 */ FWUPD_STATUS_DEVICE_BUSY, /* Since: 1.0.1 */ + FWUPD_STATUS_SHUTDOWN, /* Since: 1.2.1 */ /*< private >*/ FWUPD_STATUS_LAST } FwupdStatus; @@ -81,6 +84,9 @@ * @FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG: The hardware is waiting to be replugged * @FWUPD_DEVICE_FLAG_IGNORE_VALIDATION: Ignore validation safety checks when flashing this device * @FWUPD_DEVICE_FLAG_TRUSTED: Extra metadata can be exposed about this device + * @FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN: Requires system shutdown to apply firmware + * @FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED: Requires the update to be retried with a new plugin + * @FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS: Do not add instance IDs from the device baseclass * * The device flags. **/ @@ -102,6 +108,9 @@ #define FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG (1u << 14) /* Since: 1.1.2 */ #define FWUPD_DEVICE_FLAG_IGNORE_VALIDATION (1u << 15) /* Since: 1.1.2 */ #define FWUPD_DEVICE_FLAG_TRUSTED (1u << 16) /* Since: 1.1.2 */ +#define FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN (1u << 17) /* Since: 1.2.4 */ +#define FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED (1u << 18) /* Since: 1.2.5 */ +#define FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS (1u << 19) /* Since: 1.2.5 */ #define FWUPD_DEVICE_FLAG_UNKNOWN G_MAXUINT64 /* Since: 0.7.3 */ typedef guint64 FwupdDeviceFlags; @@ -176,4 +185,4 @@ FwupdKeyringKind fwupd_keyring_kind_from_string (const gchar *keyring_kind); const gchar *fwupd_keyring_kind_to_string (FwupdKeyringKind keyring_kind); -#endif /* __FWUPD_ENUMS_H */ +G_END_DECLS diff -Nru fwupd-1.1.4/libfwupd/fwupd-enums-private.h fwupd-1.2.5/libfwupd/fwupd-enums-private.h --- fwupd-1.1.4/libfwupd/fwupd-enums-private.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/libfwupd/fwupd-enums-private.h 2019-02-25 09:42:18.000000000 +0000 @@ -1,11 +1,12 @@ /* - * Copyright (C) 2016-2017 Richard Hughes + * Copyright (C) 2016-2018 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_ENUMS_PRIVATE_H -#define __FWUPD_ENUMS_PRIVATE_H +#pragma once + +G_BEGIN_DECLS #define FWUPD_RESULT_KEY_APPSTREAM_ID "AppstreamId" /* s */ #define FWUPD_RESULT_KEY_CHECKSUM "Checksum" /* as */ @@ -14,11 +15,15 @@ #define FWUPD_RESULT_KEY_DEVICE_ID "DeviceId" /* s */ #define FWUPD_RESULT_KEY_PARENT_DEVICE_ID "ParentDeviceId"/* s */ #define FWUPD_RESULT_KEY_FILENAME "Filename" /* s */ +#define FWUPD_RESULT_KEY_PROTOCOL "Protocol" /* s */ #define FWUPD_RESULT_KEY_FLAGS "Flags" /* t */ #define FWUPD_RESULT_KEY_FLASHES_LEFT "FlashesLeft" /* u */ #define FWUPD_RESULT_KEY_INSTALL_DURATION "InstallDuration" /* u */ #define FWUPD_RESULT_KEY_GUID "Guid" /* as */ +#define FWUPD_RESULT_KEY_INSTANCE_IDS "InstanceIds" /* as */ #define FWUPD_RESULT_KEY_HOMEPAGE "Homepage" /* s */ +#define FWUPD_RESULT_KEY_DETAILS_URL "DetailsUrl" /* s */ +#define FWUPD_RESULT_KEY_SOURCE_URL "SourceUrl" /* s */ #define FWUPD_RESULT_KEY_ICON "Icon" /* as */ #define FWUPD_RESULT_KEY_LICENSE "License" /* s */ #define FWUPD_RESULT_KEY_MODIFIED "Modified" /* t */ @@ -31,6 +36,7 @@ #define FWUPD_RESULT_KEY_SIZE "Size" /* t */ #define FWUPD_RESULT_KEY_SUMMARY "Summary" /* s */ #define FWUPD_RESULT_KEY_TRUST_FLAGS "TrustFlags" /* t */ +#define FWUPD_RESULT_KEY_UPDATE_MESSAGE "UpdateMessage" /* s */ #define FWUPD_RESULT_KEY_UPDATE_ERROR "UpdateError" /* s */ #define FWUPD_RESULT_KEY_UPDATE_STATE "UpdateState" /* u */ #define FWUPD_RESULT_KEY_URI "Uri" /* s */ @@ -41,4 +47,4 @@ #define FWUPD_RESULT_KEY_VERSION_LOWEST "VersionLowest" /* s */ #define FWUPD_RESULT_KEY_VERSION "Version" /* s */ -#endif /* __FWUPD_ENUMS_PRIVATE_H */ +G_END_DECLS diff -Nru fwupd-1.1.4/libfwupd/fwupd-error.h fwupd-1.2.5/libfwupd/fwupd-error.h --- fwupd-1.1.4/libfwupd/fwupd-error.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/libfwupd/fwupd-error.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,11 +4,12 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_ERROR_H -#define __FWUPD_ERROR_H +#pragma once #include +G_BEGIN_DECLS + #define FWUPD_ERROR fwupd_error_quark() /** @@ -53,4 +54,4 @@ const gchar *fwupd_error_to_string (FwupdError error); FwupdError fwupd_error_from_string (const gchar *error); -#endif /* __FWUPD_ERROR_H */ +G_END_DECLS diff -Nru fwupd-1.1.4/libfwupd/fwupd.h fwupd-1.2.5/libfwupd/fwupd.h --- fwupd-1.1.4/libfwupd/fwupd.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/libfwupd/fwupd.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,14 +4,13 @@ * SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + /** * SECTION:fwupd * @short_description: Helper objects for accessing fwupd */ -#ifndef __FWUPD_H__ -#define __FWUPD_H__ - #define __FWUPD_H_INSIDE__ #include @@ -28,6 +27,3 @@ #endif #undef __FWUPD_H_INSIDE__ - -#endif /* __FWUPD_H__ */ - diff -Nru fwupd-1.1.4/libfwupd/fwupd.map fwupd-1.2.5/libfwupd/fwupd.map --- fwupd-1.1.4/libfwupd/fwupd.map 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/libfwupd/fwupd.map 2019-02-25 09:42:18.000000000 +0000 @@ -279,3 +279,44 @@ fwupd_device_set_install_duration; local: *; } LIBFWUPD_1.1.2; + +LIBFWUPD_1.2.1 { + global: + fwupd_release_get_install_duration; + fwupd_release_set_install_duration; + local: *; +} LIBFWUPD_1.1.3; + +LIBFWUPD_1.2.2 { + global: + fwupd_release_get_protocol; + fwupd_release_set_protocol; + local: *; +} LIBFWUPD_1.2.1; + +LIBFWUPD_1.2.4 { + global: + fwupd_client_get_tainted; + fwupd_device_get_update_message; + fwupd_device_set_update_message; + fwupd_release_get_details_url; + fwupd_release_get_source_url; + fwupd_release_get_update_message; + fwupd_release_set_details_url; + fwupd_release_set_source_url; + fwupd_release_set_update_message; + local: *; +} LIBFWUPD_1.2.2; + +LIBFWUPD_1.2.5 { + global: + fwupd_device_add_instance_id; + fwupd_device_get_instance_ids; + fwupd_device_has_instance_id; + fwupd_guid_from_string; + fwupd_guid_hash_data; + fwupd_guid_hash_string; + fwupd_guid_is_valid; + fwupd_guid_to_string; + local: *; +} LIBFWUPD_1.2.4; diff -Nru fwupd-1.1.4/libfwupd/fwupd-release.c fwupd-1.2.5/libfwupd/fwupd-release.c --- fwupd-1.1.4/libfwupd/fwupd-release.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/libfwupd/fwupd-release.c 2019-02-25 09:42:18.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2017 Richard Hughes + * Copyright (C) 2015-2018 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -33,7 +33,10 @@ GHashTable *metadata; gchar *description; gchar *filename; + gchar *protocol; gchar *homepage; + gchar *details_url; + gchar *source_url; gchar *appstream_id; gchar *license; gchar *name; @@ -43,7 +46,9 @@ gchar *version; gchar *remote_id; guint64 size; + guint32 install_duration; FwupdTrustFlags trust_flags; + gchar *update_message; } FwupdReleasePrivate; G_DEFINE_TYPE_WITH_PRIVATE (FwupdRelease, fwupd_release, G_TYPE_OBJECT) @@ -158,6 +163,78 @@ } /** + * fwupd_release_get_update_message: + * @release: A #FwupdRelease + * + * Gets the update message. + * + * Returns: the update message, or %NULL if unset + * + * Since: 1.2.4 + **/ +const gchar * +fwupd_release_get_update_message (FwupdRelease *release) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), NULL); + return priv->update_message; +} + +/** + * fwupd_release_set_update_message: + * @release: A #FwupdRelease + * @update_message: the update message string + * + * Sets the update message. + * + * Since: 1.2.4 + **/ +void +fwupd_release_set_update_message (FwupdRelease *release, const gchar *update_message) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + g_free (priv->update_message); + priv->update_message = g_strdup (update_message); +} + +/** + * fwupd_release_get_protocol: + * @release: A #FwupdRelease + * + * Gets the update protocol. + * + * Returns: the update protocol, or %NULL if unset + * + * Since: 1.2.2 + **/ +const gchar * +fwupd_release_get_protocol (FwupdRelease *release) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), NULL); + return priv->protocol; +} + +/** + * fwupd_release_set_protocol: + * @release: A #FwupdRelease + * @protocol: the update protocol, e.g. `org.usb.dfu` + * + * Sets the update protocol. + * + * Since: 1.2.2 + **/ +void +fwupd_release_set_protocol (FwupdRelease *release, const gchar *protocol) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + g_free (priv->protocol); + priv->protocol = g_strdup (protocol); +} + +/** * fwupd_release_get_checksums: * @release: A #FwupdRelease * @@ -356,6 +433,78 @@ } /** + * fwupd_release_get_details_url: + * @release: A #FwupdRelease + * + * Gets the URL for the online update notes. + * + * Returns: the update URL, or %NULL if unset + * + * Since: 1.2.4 + **/ +const gchar * +fwupd_release_get_details_url (FwupdRelease *release) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), NULL); + return priv->details_url; +} + +/** + * fwupd_release_set_details_url: + * @release: A #FwupdRelease + * @details_url: the URL + * + * Sets the URL for the online update notes. + * + * Since: 1.2.4 + **/ +void +fwupd_release_set_details_url (FwupdRelease *release, const gchar *details_url) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + g_free (priv->details_url); + priv->details_url = g_strdup (details_url); +} + +/** + * fwupd_release_get_source_url: + * @release: A #FwupdRelease + * + * Gets the URL of the source code used to build this release. + * + * Returns: the update source_url, or %NULL if unset + * + * Since: 1.2.4 + **/ +const gchar * +fwupd_release_get_source_url (FwupdRelease *release) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), NULL); + return priv->source_url; +} + +/** + * fwupd_release_set_source_url: + * @release: A #FwupdRelease + * @source_url: the URL + * + * Sets the URL of the source code used to build this release. + * + * Since: 1.2.4 + **/ +void +fwupd_release_set_source_url (FwupdRelease *release, const gchar *source_url) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + g_free (priv->source_url); + priv->source_url = g_strdup (source_url); +} + +/** * fwupd_release_get_description: * @release: A #FwupdRelease * @@ -641,6 +790,41 @@ priv->trust_flags = trust_flags; } +/** + * fwupd_release_get_install_duration: + * @release: A #FwupdRelease + * + * Gets the time estimate for firmware installation (in seconds) + * + * Returns: the estimated time to flash this release (or 0 if unset) + * + * Since: 1.2.1 + **/ +guint32 +fwupd_release_get_install_duration (FwupdRelease *release) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), 0); + return priv->install_duration; +} + +/** + * fwupd_release_set_install_duration: + * @release: A #FwupdRelease + * @duration: The amount of time + * + * Sets the time estimate for firmware installation (in seconds) + * + * Since: 1.2.1 + **/ +void +fwupd_release_set_install_duration (FwupdRelease *release, guint32 duration) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + priv->install_duration = duration; +} + static GVariant * _hash_kv_to_variant (GHashTable *hash) { @@ -703,6 +887,11 @@ FWUPD_RESULT_KEY_FILENAME, g_variant_new_string (priv->filename)); } + if (priv->protocol != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_PROTOCOL, + g_variant_new_string (priv->protocol)); + } if (priv->license != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_LICENSE, @@ -750,6 +939,16 @@ FWUPD_RESULT_KEY_HOMEPAGE, g_variant_new_string (priv->homepage)); } + if (priv->details_url != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_DETAILS_URL, + g_variant_new_string (priv->details_url)); + } + if (priv->source_url != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_SOURCE_URL, + g_variant_new_string (priv->source_url)); + } if (priv->version != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_VERSION, @@ -770,6 +969,11 @@ FWUPD_RESULT_KEY_METADATA, _hash_kv_to_variant (priv->metadata)); } + if (priv->install_duration > 0) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_INSTALL_DURATION, + g_variant_new_uint32 (priv->install_duration)); + } return g_variant_new ("a{sv}", &builder); } @@ -789,6 +993,10 @@ fwupd_release_set_filename (release, g_variant_get_string (value, NULL)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_PROTOCOL) == 0) { + fwupd_release_set_protocol (release, g_variant_get_string (value, NULL)); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_LICENSE) == 0) { fwupd_release_set_license (release, g_variant_get_string (value, NULL)); return; @@ -824,6 +1032,14 @@ fwupd_release_set_homepage (release, g_variant_get_string (value, NULL)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_DETAILS_URL) == 0) { + fwupd_release_set_details_url (release, g_variant_get_string (value, NULL)); + return; + } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_SOURCE_URL) == 0) { + fwupd_release_set_source_url (release, g_variant_get_string (value, NULL)); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_VERSION) == 0) { fwupd_release_set_version (release, g_variant_get_string (value, NULL)); return; @@ -836,6 +1052,14 @@ fwupd_release_set_trust_flags (release, g_variant_get_uint64 (value)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_INSTALL_DURATION) == 0) { + fwupd_release_set_install_duration (release, g_variant_get_uint32 (value)); + return; + } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_MESSAGE) == 0) { + fwupd_release_set_update_message (release, g_variant_get_string (value, NULL)); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_METADATA) == 0) { g_hash_table_unref (priv->metadata); priv->metadata = _variant_to_hash_kv (value); @@ -885,6 +1109,18 @@ fwupd_pad_kv_str (str, key, tmp->str); } +static void +fwupd_pad_kv_int (GString *str, const gchar *key, guint32 value) +{ + g_autofree gchar *tmp = NULL; + + /* ignore */ + if (value == 0) + return; + tmp = g_strdup_printf("%" G_GUINT32_FORMAT, value); + fwupd_pad_kv_str (str, key, tmp); +} + /** * fwupd_release_to_string: * @release: A #FwupdRelease @@ -911,6 +1147,7 @@ fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DESCRIPTION, priv->description); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_VERSION, priv->version); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_FILENAME, priv->filename); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_PROTOCOL, priv->protocol); for (guint i = 0; i < priv->checksums->len; i++) { const gchar *checksum = g_ptr_array_index (priv->checksums, i); g_autofree gchar *checksum_display = fwupd_checksum_format_for_display (checksum); @@ -920,9 +1157,13 @@ fwupd_pad_kv_siz (str, FWUPD_RESULT_KEY_SIZE, priv->size); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_URI, priv->uri); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_HOMEPAGE, priv->homepage); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DETAILS_URL, priv->details_url); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_SOURCE_URL, priv->source_url); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_VENDOR, priv->vendor); fwupd_pad_kv_tfl (str, FWUPD_RESULT_KEY_TRUST_FLAGS, priv->trust_flags); - + fwupd_pad_kv_int (str, FWUPD_RESULT_KEY_INSTALL_DURATION, priv->install_duration); + if (priv->update_message != NULL) + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_MESSAGE, priv->update_message); /* metadata */ keys = g_hash_table_get_keys (priv->metadata); for (GList *l = keys; l != NULL; l = l->next) { @@ -957,15 +1198,19 @@ g_free (priv->description); g_free (priv->filename); + g_free (priv->protocol); g_free (priv->appstream_id); g_free (priv->license); g_free (priv->name); g_free (priv->summary); g_free (priv->uri); g_free (priv->homepage); + g_free (priv->details_url); + g_free (priv->source_url); g_free (priv->vendor); g_free (priv->version); g_free (priv->remote_id); + g_free (priv->update_message); g_ptr_array_unref (priv->checksums); g_hash_table_unref (priv->metadata); diff -Nru fwupd-1.1.4/libfwupd/fwupd-release.h fwupd-1.2.5/libfwupd/fwupd-release.h --- fwupd-1.1.4/libfwupd/fwupd-release.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/libfwupd/fwupd-release.h 2019-02-25 09:42:18.000000000 +0000 @@ -1,11 +1,10 @@ /* - * Copyright (C) 2015-2017 Richard Hughes + * Copyright (C) 2015-2018 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_RELEASE_H -#define __FWUPD_RELEASE_H +#pragma once #include @@ -54,6 +53,9 @@ const gchar *fwupd_release_get_filename (FwupdRelease *release); void fwupd_release_set_filename (FwupdRelease *release, const gchar *filename); +const gchar *fwupd_release_get_protocol (FwupdRelease *release); +void fwupd_release_set_protocol (FwupdRelease *release, + const gchar *protocol); const gchar *fwupd_release_get_appstream_id (FwupdRelease *release); void fwupd_release_set_appstream_id (FwupdRelease *release, const gchar *appstream_id); @@ -75,6 +77,12 @@ const gchar *fwupd_release_get_homepage (FwupdRelease *release); void fwupd_release_set_homepage (FwupdRelease *release, const gchar *homepage); +const gchar *fwupd_release_get_details_url (FwupdRelease *release); +void fwupd_release_set_details_url (FwupdRelease *release, + const gchar *details_url); +const gchar *fwupd_release_get_source_url (FwupdRelease *release); +void fwupd_release_set_source_url (FwupdRelease *release, + const gchar *source_url); guint64 fwupd_release_get_size (FwupdRelease *release); void fwupd_release_set_size (FwupdRelease *release, guint64 size); @@ -84,8 +92,11 @@ FwupdTrustFlags fwupd_release_get_trust_flags (FwupdRelease *release); void fwupd_release_set_trust_flags (FwupdRelease *release, FwupdTrustFlags trust_flags); +guint32 fwupd_release_get_install_duration (FwupdRelease *release); +void fwupd_release_set_install_duration (FwupdRelease *release, + guint32 duration); +const gchar *fwupd_release_get_update_message (FwupdRelease *release); +void fwupd_release_set_update_message (FwupdRelease *release, + const gchar *update_message); G_END_DECLS - -#endif /* __FWUPD_RELEASE_H */ - diff -Nru fwupd-1.1.4/libfwupd/fwupd-release-private.h fwupd-1.2.5/libfwupd/fwupd-release-private.h --- fwupd-1.1.4/libfwupd/fwupd-release-private.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/libfwupd/fwupd-release-private.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_RELEASE_PRIVATE_H -#define __FWUPD_RELEASE_PRIVATE_H +#pragma once #include @@ -18,5 +17,3 @@ G_END_DECLS -#endif /* __FWUPD_RELEASE_PRIVATE_H */ - diff -Nru fwupd-1.1.4/libfwupd/fwupd-remote.c fwupd-1.2.5/libfwupd/fwupd-remote.c --- fwupd-1.1.4/libfwupd/fwupd-remote.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/libfwupd/fwupd-remote.c 2019-02-25 09:42:18.000000000 +0000 @@ -275,6 +275,8 @@ return FWUPD_REMOTE_KIND_DOWNLOAD; if (g_strcmp0 (kind, "local") == 0) return FWUPD_REMOTE_KIND_LOCAL; + if (g_strcmp0 (kind, "directory") == 0) + return FWUPD_REMOTE_KIND_DIRECTORY; return FWUPD_REMOTE_KIND_UNKNOWN; } @@ -295,6 +297,8 @@ return "download"; if (kind == FWUPD_REMOTE_KIND_LOCAL) return "local"; + if (kind == FWUPD_REMOTE_KIND_DIRECTORY) + return "directory"; return NULL; } @@ -384,7 +388,14 @@ if (metadata_uri == NULL) return FALSE; if (g_str_has_prefix (metadata_uri, "file://")) { - priv->kind = FWUPD_REMOTE_KIND_LOCAL; + const gchar *filename_cache = metadata_uri; + if (g_str_has_prefix (filename_cache, "file://")) + filename_cache += 7; + fwupd_remote_set_filename_cache (self, filename_cache); + if (g_file_test (filename_cache, G_FILE_TEST_IS_DIR)) + priv->kind = FWUPD_REMOTE_KIND_DIRECTORY; + else + priv->kind = FWUPD_REMOTE_KIND_LOCAL; } else if (g_str_has_prefix (metadata_uri, "http://") || g_str_has_prefix (metadata_uri, "https://")) { priv->kind = FWUPD_REMOTE_KIND_DOWNLOAD; @@ -444,14 +455,6 @@ fwupd_remote_set_filename_cache (self, filename_cache); } - /* all LOCAL remotes have to include a valid MetadataURI */ - if (priv->kind == FWUPD_REMOTE_KIND_LOCAL) { - const gchar *filename_cache = metadata_uri; - if (g_str_has_prefix (filename_cache, "file://")) - filename_cache += 7; - fwupd_remote_set_filename_cache (self, filename_cache); - } - /* load the checksum */ if (priv->filename_cache_sig != NULL && g_file_test (priv->filename_cache_sig, G_FILE_TEST_EXISTS)) { @@ -473,6 +476,25 @@ if (firmware_base_uri != NULL) fwupd_remote_set_firmware_base_uri (self, firmware_base_uri); + /* some validation around DIRECTORY types */ + if (priv->kind == FWUPD_REMOTE_KIND_DIRECTORY) { + if (priv->keyring_kind != FWUPD_KEYRING_KIND_NONE) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Keyring kind %s is not supported with directory remote", + fwupd_keyring_kind_to_string (priv->keyring_kind)); + return FALSE; + } + if (firmware_base_uri != NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Directory remotes don't support firmware base URI"); + return FALSE; + } + } + /* dep logic */ order_before = g_key_file_get_string (kf, group, "OrderBefore", NULL); if (order_before != NULL) @@ -1099,7 +1121,7 @@ * Since: 0.9.3 */ pspec = g_param_spec_string ("id", NULL, NULL, - NULL, G_PARAM_READWRITE); + NULL, G_PARAM_READWRITE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_ID, pspec); /** @@ -1110,7 +1132,7 @@ * Since: 0.9.3 */ pspec = g_param_spec_boolean ("enabled", NULL, NULL, - FALSE, G_PARAM_READWRITE); + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_ENABLED, pspec); } diff -Nru fwupd-1.1.4/libfwupd/fwupd-remote.h fwupd-1.2.5/libfwupd/fwupd-remote.h --- fwupd-1.1.4/libfwupd/fwupd-remote.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/libfwupd/fwupd-remote.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_REMOTE_H -#define __FWUPD_REMOTE_H +#pragma once #include "fwupd-enums.h" @@ -39,6 +38,7 @@ FWUPD_REMOTE_KIND_UNKNOWN, FWUPD_REMOTE_KIND_DOWNLOAD, FWUPD_REMOTE_KIND_LOCAL, + FWUPD_REMOTE_KIND_DIRECTORY, /* Since: 1.2.4 */ /*< private >*/ FWUPD_REMOTE_KIND_LAST } FwupdRemoteKind; @@ -70,6 +70,3 @@ GError **error); G_END_DECLS - -#endif /* __FWUPD_REMOTE_H */ - diff -Nru fwupd-1.1.4/libfwupd/fwupd-remote-private.h fwupd-1.2.5/libfwupd/fwupd-remote-private.h --- fwupd-1.1.4/libfwupd/fwupd-remote-private.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/libfwupd/fwupd-remote-private.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_REMOTE_PRIVATE_H -#define __FWUPD_REMOTE_PRIVATE_H +#pragma once #include "fwupd-remote.h" @@ -27,6 +26,3 @@ gchar **fwupd_remote_get_order_before (FwupdRemote *self); G_END_DECLS - -#endif /* __FWUPD_REMOTE_PRIVATE_H */ - diff -Nru fwupd-1.1.4/libfwupd/fwupd-self-test.c fwupd-1.2.5/libfwupd/fwupd-self-test.c --- fwupd-1.1.4/libfwupd/fwupd-self-test.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/libfwupd/fwupd-self-test.c 2019-02-25 09:42:18.000000000 +0000 @@ -43,6 +43,60 @@ return FALSE; } +/* https://gitlab.gnome.org/GNOME/glib/issues/225 */ +static guint +_g_string_replace (GString *string, const gchar *search, const gchar *replace) +{ + gchar *tmp; + guint count = 0; + gsize search_idx = 0; + gsize replace_len; + gsize search_len; + + g_return_val_if_fail (string != NULL, 0); + g_return_val_if_fail (search != NULL, 0); + g_return_val_if_fail (replace != NULL, 0); + + /* nothing to do */ + if (string->len == 0) + return 0; + + search_len = strlen (search); + replace_len = strlen (replace); + + do { + tmp = g_strstr_len (string->str + search_idx, -1, search); + if (tmp == NULL) + break; + + /* advance the counter in case @replace contains @search */ + search_idx = (gsize) (tmp - string->str); + + /* reallocate the string if required */ + if (search_len > replace_len) { + g_string_erase (string, + (gssize) search_idx, + (gssize) (search_len - replace_len)); + memcpy (tmp, replace, replace_len); + } else if (search_len < replace_len) { + g_string_insert_len (string, + (gssize) search_idx, + replace, + (gssize) (replace_len - search_len)); + /* we have to treat this specially as it could have + * been reallocated when the insertion happened */ + memcpy (string->str + search_idx, replace, replace_len); + } else { + /* just memcmp in the new string */ + memcpy (tmp, replace, replace_len); + } + search_idx += replace_len; + count++; + } while (TRUE); + + return count; +} + static void fwupd_enums_func (void) { @@ -211,6 +265,7 @@ g_autoptr(FwupdDevice) dev = NULL; g_autoptr(FwupdRelease) rel = NULL; g_autoptr(GError) error = NULL; + g_autoptr(GString) str_ascii = NULL; /* create dummy object */ dev = fwupd_device_new (); @@ -243,7 +298,11 @@ g_assert (fwupd_device_has_guid (dev, "00000000-0000-0000-0000-000000000000")); g_assert (!fwupd_device_has_guid (dev, "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")); - ret = fu_test_compare_lines (str, + /* convert the new non-breaking space back into a normal space: + * https://gitlab.gnome.org/GNOME/glib/commit/76af5dabb4a25956a6c41a75c0c7feeee74496da */ + str_ascii = g_string_new (str); + _g_string_replace (str_ascii, " ", " "); + ret = fu_test_compare_lines (str_ascii->str, "ColorHug2\n" " DeviceId: USB:foo\n" " Guid: 2082b5e0-7a64-478a-b1b2-e3404fab6dad\n" @@ -401,6 +460,58 @@ g_assert_cmpstr (mhash2, !=, mhash1); } +static void +fwupd_common_guid_func (void) +{ + g_autofree gchar *guid1 = NULL; + g_autofree gchar *guid2 = NULL; + g_autofree gchar *guid_be = NULL; + g_autofree gchar *guid_me = NULL; + fwupd_guid_t buf = { 0x0 }; + gboolean ret; + g_autoptr(GError) error = NULL; + + /* invalid */ + g_assert (!fwupd_guid_is_valid (NULL)); + g_assert (!fwupd_guid_is_valid ("")); + g_assert (!fwupd_guid_is_valid ("1ff60ab2-3905-06a1-b476")); + g_assert (!fwupd_guid_is_valid ("1ff60ab2-XXXX-XXXX-XXXX-0371f00c9e9b")); + g_assert (!fwupd_guid_is_valid (" 1ff60ab2-3905-06a1-b476-0371f00c9e9b")); + g_assert (!fwupd_guid_is_valid ("00000000-0000-0000-0000-000000000000")); + + /* valid */ + g_assert (fwupd_guid_is_valid ("1ff60ab2-3905-06a1-b476-0371f00c9e9b")); + + /* make valid */ + guid1 = fwupd_guid_hash_string ("python.org"); + g_assert_cmpstr (guid1, ==, "886313e1-3b8a-5372-9b90-0c9aee199e5d"); + + guid2 = fwupd_guid_hash_string ("8086:0406"); + g_assert_cmpstr (guid2, ==, "1fbd1f2c-80f4-5d7c-a6ad-35c7b9bd5486"); + + /* round-trip BE */ + ret = fwupd_guid_from_string ("00112233-4455-6677-8899-aabbccddeeff", &buf, + FWUPD_GUID_FLAG_NONE, &error); + g_assert_true (ret); + g_assert_no_error (error); + g_assert (memcmp (buf, "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff", sizeof(buf)) == 0); + guid_be = fwupd_guid_to_string ((const fwupd_guid_t *) &buf, FWUPD_GUID_FLAG_NONE); + g_assert_cmpstr (guid_be, ==, "00112233-4455-6677-8899-aabbccddeeff"); + + /* round-trip mixed encoding */ + ret = fwupd_guid_from_string ("00112233-4455-6677-8899-aabbccddeeff", &buf, + FWUPD_GUID_FLAG_MIXED_ENDIAN, &error); + g_assert_true (ret); + g_assert_no_error (error); + g_assert (memcmp (buf, "\x33\x22\x11\x00\x55\x44\x77\x66\x88\x99\xaa\xbb\xcc\xdd\xee\xff", sizeof(buf)) == 0); + guid_me = fwupd_guid_to_string ((const fwupd_guid_t *) &buf, FWUPD_GUID_FLAG_MIXED_ENDIAN); + g_assert_cmpstr (guid_me, ==, "00112233-4455-6677-8899-aabbccddeeff"); + + /* check failure */ + g_assert_false (fwupd_guid_from_string ("001122334455-6677-8899-aabbccddeeff", NULL, 0, NULL)); + g_assert_false (fwupd_guid_from_string ("0112233-4455-6677-8899-aabbccddeeff", NULL, 0, NULL)); +} + int main (int argc, char **argv) { @@ -413,6 +524,7 @@ /* tests go here */ g_test_add_func ("/fwupd/enums", fwupd_enums_func); g_test_add_func ("/fwupd/common{machine-hash}", fwupd_common_machine_hash_func); + g_test_add_func ("/fwupd/common{guid}", fwupd_common_guid_func); g_test_add_func ("/fwupd/release", fwupd_release_func); g_test_add_func ("/fwupd/device", fwupd_device_func); g_test_add_func ("/fwupd/remote{download}", fwupd_remote_download_func); diff -Nru fwupd-1.1.4/libfwupd/fwupd-version.h.in fwupd-1.2.5/libfwupd/fwupd-version.h.in --- fwupd-1.1.4/libfwupd/fwupd-version.h.in 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/libfwupd/fwupd-version.h.in 2019-02-25 09:42:18.000000000 +0000 @@ -3,6 +3,9 @@ * * SPDX-License-Identifier: LGPL-2.1+ */ + +#pragma once + /** * SECTION:fwupd-version * @short_description: Obtains the version for the installed fwupd @@ -15,9 +18,6 @@ #error "Only can be included directly." #endif -#ifndef __FWUPD_VERSION_H -#define __FWUPD_VERSION_H - /** * FWUPD_MAJOR_VERSION: * @@ -59,5 +59,3 @@ (FWUPD_MAJOR_VERSION == (major) && FWUPD_MINOR_VERSION > (minor)) || \ (FWUPD_MAJOR_VERSION == (major) && FWUPD_MINOR_VERSION == (minor) && \ FWUPD_MICRO_VERSION >= (micro))) - -#endif /* __FWUPD_VERSION_H */ diff -Nru fwupd-1.1.4/meson.build fwupd-1.2.5/meson.build --- fwupd-1.1.4/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -1,7 +1,7 @@ project('fwupd', 'c', - version : '1.1.4', + version : '1.2.5', license : 'LGPL-2.1+', - meson_version : '>=0.43.0', + meson_version : '>=0.47.0', default_options : ['warning_level=2', 'c_std=c99'], ) @@ -77,7 +77,7 @@ '-Wmissing-prototypes', '-Wnested-externs', '-Wno-cast-function-type', - '-Wno-error=cpp', + '-Wno-address-of-packed-member', # incompatable with g_autoptr() '-Wno-unknown-pragmas', '-Wno-discarded-qualifiers', '-Wno-missing-field-initializers', @@ -111,17 +111,12 @@ global_link_args = [] test_link_args = [ '-Wl,-z,relro', + '-Wl,-z,defs', '-Wl,-z,now', ] foreach arg: test_link_args - if meson.version().version_compare('>=0.46.0') - if cc.has_link_argument(arg) - global_link_args += arg - endif - else - if cc.has_argument(arg) - global_link_args += arg - endif + if cc.has_link_argument(arg) + global_link_args += arg endif endforeach add_global_link_arguments( @@ -160,7 +155,7 @@ if gudev.version().version_compare('>= 232') conf.set('HAVE_GUDEV_232', '1') endif -appstream_glib = dependency('appstream-glib', version : '>= 0.7.4') +libxmlb = dependency('xmlb', version : '>= 0.1.5', fallback : ['libxmlb', 'libxmlb_dep']) gusb = dependency('gusb', version : '>= 0.2.9') sqlite = dependency('sqlite3') libarchive = dependency('libarchive') @@ -188,7 +183,6 @@ conf.set('ENABLE_GPG', '1') endif libm = cc.find_library('m', required: false) -uuid = dependency('uuid') libgcab = dependency('libgcab-1.0') if libgcab.version().version_compare('>= 0.8') conf.set('HAVE_GCAB_0_8', '1') @@ -198,6 +192,7 @@ endif gcab = find_program('gcab', required : true) bashcomp = dependency('bash-completion', required: false) +python3 = find_program('python3') if valgrind.found() conf.set('HAVE_VALGRIND', '1') @@ -242,8 +237,6 @@ gnu_efi_arch = '' endif conf.set_quoted('EFI_MACHINE_TYPE_NAME', EFI_MACHINE_TYPE_NAME) - - python3 = find_program('python3') r = run_command([python3, 'po/test-deps']) if r.returncode() != 0 error(r.stdout()) @@ -260,7 +253,6 @@ endif if get_option('plugin_nvme') - efivar = dependency('efivar') if not cc.has_header('linux/nvme_ioctl.h') error('NVMe support requires kernel >= 4.4') endif @@ -310,14 +302,8 @@ configuration : conf ) -default_sysconfdir = get_option('sysconfdir') -if default_sysconfdir == 'etc' - message('sysconfdir of etc makes no sense, using /etc') - default_sysconfdir = '/etc' -endif - plugin_deps = [] -plugin_deps += appstream_glib +plugin_deps += libxmlb plugin_deps += gio plugin_deps += giounix plugin_deps += gmodule diff -Nru fwupd-1.1.4/meson_options.txt fwupd-1.2.5/meson_options.txt --- fwupd-1.1.4/meson_options.txt 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/meson_options.txt 2019-02-25 09:42:18.000000000 +0000 @@ -1,5 +1,6 @@ option('daemon', type : 'boolean', value : true, description : 'enable the fwupd daemon') option('consolekit', type : 'boolean', value : true, description : 'enable ConsoleKit support') +option('firmware-packager', type : 'boolean', value : true, description : 'enable firmware-packager installation') option('gpg', type : 'boolean', value : true, description : 'enable the GPG verification support') option('gtkdoc', type : 'boolean', value : true, description : 'enable developer documentation') option('introspection', type : 'boolean', value : true, description : 'generate GObject Introspection data') diff -Nru fwupd-1.1.4/NEWS fwupd-1.2.5/NEWS --- fwupd-1.1.4/NEWS 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/NEWS 1970-01-01 00:00:00.000000000 +0000 @@ -1,893 +0,0 @@ -Version 1.1.4 -~~~~~~~~~~~~~ -Released: 2018-11-07 - -New Features: - - Stop any running daemon over dbus before loading engine (Mario Limonciello) - -Bugfixes: - - Use HTTPS_PROXY if set (Richard Hughes) - - Make the dell-dock plugin more robust in several ways (Mario Limonciello) - - Adjust EVB board handling (Mario Limonciello, RyanChang) - -Version 1.1.3 -~~~~~~~~~~~~~ -Released: 2018-10-12 - -New Features: - - Add a plugin for an upcoming Dell USB-C dock (Mario Limonciello) - - Add support for devices to show an estimated flash time (Mario Limonciello) - - Add support for Realtek USB devices using vendor HID and HUB commands (Richard Hughes) - - Allow firmware files to depend on versions from other devices (Richard Hughes) - -Bugfixes: - - Adjust panamera ESM update routine for some reported issues (Mario Limonciello) - - Check the amount of free space on the ESP before upgrading (Richard Hughes) - - Don't show devices pending a reboot in GetUpgrades (Mario Limonciello) - - Fix possible crash in the thunderbolt-power plugin (Richard Hughes) - - Make various parts of the daemon thread-safe (Richard Hughes) - - Redirect all debugging output to stderr instead of stdout (Mario Limonciello) - - Run the Dell plugin initialization after the UEFI plugin (Mario Limonciello) - - Stop showing the current release during updates in fwupdmgr (Mario Limonciello) - - Update all sub-devices for a composite update (Mario Limonciello) - -Version 1.1.2 -~~~~~~~~~~~~~ -Released: 2018-09-10 - -New Features: - - Add a new device flag "ignore-validation" that will override checks (Mario Limonciello) - - Add a new plugin to enumerate EC firmware (Richard Hughes) - - Add a new plugin to update NVMe hardware (Richard Hughes, Mario Limonciello) - - Add a plugin for updating using the flashrom command line tool (Richard Hughes) - - Allow the device list to take care of waiting for the device replug (Richard Hughes) - - Allow updating just one specific device from the command line (Richard Hughes) - - Allow upgrades using a self-signed fwupd.efi binary (Richard Hughes) - - Download firmware if the user specifies a URI (Richard Hughes) - - Include serial number in daemon device output when trusted (Mario Limonciello) - - Notify all plugins of device removals through a new vfunc (Mario Limonciello) - - Use boltd force power API if available (Mario Limonciello) - -Bugfixes: - - Add an install hook for classic snap (Mario Limonciello) - - Allow forcing installation even if no AC power is applied (Mario Limonciello) - - Allow using --force to ignore version_lowest (Mario Limonciello) - - Always use the same HardwareIDs as Windows (Richard Hughes) - - Check the device state before assuming a fake DFU runtime (Richard Hughes) - - Copy over parent GUIDs from other plugin donors (Mario Limonciello) - - Detect location of python3 interpreter (Mario Limonciello) - - Do not add udev devices after a small delay (Richard Hughes) - - Don't fail to run if compiled without GPG/PKCS7 (Salud Lemus, Mario Limonciello) - - Fix a segfault in fwupdtool caused by cleanup of USB plugins (Mario Limonciello) - - Implement the systemd recommendations for offline updates (Richard Hughes) - - Improve performance when reading keys from the quirk database (Richard Hughes) - - Remove children of devices when the parent is removed (Mario Limonciello) - - Rewrite synapticsmst to use modern error handling (Mario Limonciello) - - Rewrite the unifying plugin to use the new daemon-provided functionality (Richard Hughes) - - Show a time estimate on the progressbar after an update has started (Mario Limonciello) - -Version 1.1.1 -~~~~~~~~~~~~~ -Released: 2018-08-13 - -New Features: - - Add support for the Synaptics Panamera hardware (Mario Limonciello) - - Add validation for Alpine and Titan Ridge (Andrei Emeltchenko, Mika Westerberg) - - Improve the Redfish plugin to actually work with real hardware (Gary Lin) - -Bugfixes: - - Allow different plugins to add the same device (Richard Hughes) - - Allow flashing unifying devices in recovery mode (Richard Hughes) - - Allow running synapticsmst on non-Dell hardware (Mario Limonciello) - - Check the ESP for sanity at at startup (Richard Hughes, Mario Limonciello) - - Do not hold hidraw devices open forever (Richard Hughes) - - Don't override _FORTIFY_SOURCE when building the EFI binary (Richard Hughes) - - Don't show passwords in fwupdmgr (Richard Hughes, Mario Limonciello) - - Fix a potential segfault in smbios data parsing (Mario Limonciello) - - Fix encoding the GUID into the capsule EFI variable (Mario Limonciello) - - Fix various bugs when reading the thunderbolt version number (Mika Westerberg) - - Reboot synapticsmst devices at the end of flash cycle (Mario Limonciello) - - Show status messages when the daemon is initializing (Mario Limonciello) - - Show the correct title when updating devices (Richard Hughes, Mario Limonciello) - - Show the reasons that plugins are not run on the CLI (Mario Limonciello) - - Use localedir in po/make-images (Jan Tojnar) - -Version 1.1.0 -~~~~~~~~~~~~~ -Released: 2018-07-11 - -New Features: - - Add a initial Redfish support (Richard Hughes) - - Add a tool to mimic the original fwupdate CLI interface (Richard Hughes) - - Allow devices to assign a plugin from the quirk subsystem (Richard Hughes) - - Change the quirk file structure to be more efficient (Richard Hughes) - - Merge fwupdate functionality into fwupd (Richard Hughes, Mario Limonciello) - - Run a plugin vfunc before and after all the composite devices are updated (Richard Hughes) - - Support more Wacom tablets (Richard Hughes) - -Bugfixes: - - Add release information for locked devices (Richard Hughes) - - Allow building with older meson (Mario Limonciello) - - Detect the EFI system partition location at runtime (Mario Limonciello) - - Do not use 8bitdo bootloader commands after a successful flash (Richard Hughes) - - Enable accesing downloaded files in flatpak and snap (Mario Limonciello) - - Fix a potential buffer overflow when applying a DFU patch (Richard Hughes) - - Fix downgrading older releases to devices (Richard Hughes) - - Fix flashing devices that require a manual replug (Richard Hughes) - - Fix several small memory leaks in various places (Richard Hughes) - - Fix the retrieval of Redfish version (Gary Lin) - - Fix unifying failure to detach when using a slow host controller (Richard Hughes) - - Set the Wacom device status when erasing and writing firmware (Richard Hughes) - - Show errors in the CLI if unable to access directory (Mario Limonciello) - - Use the parent device name for Wacom sub-modules (Richard Hughes) - -Version 1.0.8 -~~~~~~~~~~~~~ -Released: 2018-06-07 - -New Features: - - Add an plugin to update some future Wacom tablets (Richard Hughes) - - Add 'fwupdmgr get-topology' to show logical device tree (Richard Hughes, Mario Limonciello) - - Add support for creating a flatpak (Richard Hughes) - - Add support for creating a snap (Mario Limonciello, Richard Hughes) - - Add support for Motorola S-record files (Richard Hughes) - - Add the Linux Foundation public GPG keys for firmware and metadata (Richard Hughes) - - Show a translated warning when the server is limiting downloads (Richard Hughes) - -Bugfixes: - - Add a firmware diagnostic tool called fwupdtool (Richard Hughes, Mario Limonciello) - - Adjust all licensing to LGPL 2.1+ (Mario Limonciello) - - Allow installing more than one firmware using 'fwupdmgr install' (Richard Hughes) - - Allow specifying hwids with OR relationships (Richard Hughes) - - Do not call fu_plugin_init() on blacklisted plugins (Richard Hughes) - - Do not require libcolorhug to build (Richard Hughes) - - Fix a crash in libfwupd where no device ID is set (Richard Hughes) - - Fix a potential DoS in libdfu by limiting holes to 1MiB (Richard Hughes) - - Fix a segfault that sometimes occurs during cleanup of USB plugins (Mario Limonciello) - - Fix Hardware-ID{0,1,2,12} compatibility with Microsoft (Gergely Risko) - - Hide devices that aren't updatable by default in fwupdmgr (Mario Limonciello) - - Search all UEFI GUIDs when matching hardware (Richard Hughes, Mario Limonciello) - - Stop matching Nintendo Switch Pro in the 8bitdo plugin (Mario Limonciello) - -Version 1.0.7 -~~~~~~~~~~~~~ -Released: 2018-04-30 - -New Features: - - Add enable-remote and disable-remote commands to fwupdmgr (Richard Hughes) - - Add fu_plugin_add_compile_version() for libraries to use (Richard Hughes) - - Allow requiring specific versions of libraries for firmware updates (Richard Hughes) - - If no remotes are enabled try to enable the LVFS (Mario Limonciello) - - Show a warning with interactive prompt when enabling a remote (Richard Hughes) - -Bugfixes: - - Check that EFI system partition is mounted before update (Mario Limonciello) - - Disable synapticsmst remote control on failure (Sjoerd Simons) - - Don't recoldplug thunderbolt to fix a flashing failure (Mario Limonciello) - - Fix SQL error when running 'fwupdmgr clear-offline' (Richard Hughes) - - Improve the update report message (Mario Limonciello) - - Only enumerate Dell Docks if the type is known (Sjoerd Simons) - - Only run certtool if a new enough gnutls is present (Mario Limonciello) - - Prevent a client crash if the daemon somehow sends invalid data (Richard Hughes) - - Reboot after scheduling using logind not systemd (Richard Hughes) - - Use the right encoding for the label in make-images (Niels Ole Salscheider) - -Version 1.0.6 -~~~~~~~~~~~~~ -Released: 2018-03-12 - -New Features: - - Add bash completion for fwupdmgr (Mario Limonciello) - - Add support for newest Thunderbolt chips (Andrei Emeltchenko) - - Allow all functions that take device arguments to be prompted (Mario Limonciello) - - Allow devices to use the runtime version when in bootloader mode (Richard Hughes) - - Allow overriding ESP mount point via conf file (Mario Limonciello) - - Delete any old fwupdate capsules and efivars when launching fwupd (Richard Hughes) - - Generate Vala bindings (Robert Ancell) - -Bugfixes: - - Allow ctrl-d out of the prompt for devices (Mario Limonciello) - - Allow to create package out of provided binary (Andrei Emeltchenko) - - Correct handling of unknown Thunderbolt devices (Yehezkel Bernat) - - Correctly detect new remotes that are manually copied (Richard Hughes) - - Fix a crash related to when passing device to downgrade in CLI (Mario Limonciello) - - Fix running the self tests when no fwupd is installed (Richard Hughes) - - Fix Unifying signature writing and parsing for Texas bootloader (Ogier Bouvier) - - Only send success and failure reports to the server (Richard Hughes) - - Use a CNAME to redirect to the correct CDN for metadata (Richard Hughes) - - Use a longer timeout when powering back the Thunderbolt device (Richard Hughes) - -Version 1.0.5 -~~~~~~~~~~~~~ -Released: 2018-02-14 - -New Features: - - Offer to reboot when processing an offline update (Richard Hughes) - - Report the efivar, libsmbios and fwupdate library versions (Mario Limonciello) - - Report Thunderbolt safe mode and SecureBoot status (Mario Limonciello) - - Show the user a URL when they report a known problem (Richard Hughes) - - Support split cabinet archives as produced by Windows Update (Richard Hughes) - -Bugfixes: - - Be more careful deleting and modifying device history (Richard Hughes) - - Clarify which devices don't have upgrades (Mario Limonciello) - - Ensure the Thunderbolt version is xx.yy (Richard Hughes) - - Fix a daemon warning when using fwupdmgr get-results (Richard Hughes) - - Fix crasher with MST flashing (Mario Limonciello) - - Fix DFU detach with newer releases of libusb (Richard Hughes) - - Include the device VID and PID when generating the device-id (Richard Hughes) - - Set the RemoteId when using GetDetails (Richard Hughes) - - Stop matching 8bitdo DS4 controller VID/PID (Mario Limonciello) - - Use help2man for dfu-tool and drop docbook dependencies (Mario Limonciello) - - Use ngettext for any strings with plurals (Piotr Drąg) - - Use the default value if ArchiveSizeMax is unspecified (Richard Hughes) - -Version 1.0.4 -~~~~~~~~~~~~~ -Released: 2018-01-25 - -New Features: - - Add D-Bus methods to get and modify the history information (Richard Hughes) - - Allow the user to share firmware update success or failure (Richard Hughes) - - Ask the user to refresh metadata when it is very old (Richard Hughes) - - Store firmware update success and failure to a local database (Richard Hughes) - -Bugfixes: - - Add a device name for locked UEFI devices (Mario Limonciello) - - Allow each plugin to opt-in to the recoldplug action (Richard Hughes) - - Fix firmware downloading using gnome-software (Richard Hughes) - - Fix UX capsule reference to the one specified in efivar (Mario Limonciello) - - Never add two devices to the daemon with the same ID (Richard Hughes) - - Rescan supported flags when refreshing metadata (Richard Hughes) - -Version 1.0.3 -~~~~~~~~~~~~~ -Released: 2018-01-09 - -New Features: - - Add a new plugin to add support for CSR "Driverless DFU" (Richard Hughes) - - Add initial SF30/SN30 Pro support (Mario Limonciello) - - Support AppStream metadata with relative URLs (Richard Hughes) - -Bugfixes: - - Add more metadata to the user-agent string (Richard Hughes) - - Block owned Dell TPM updates (Mario Limonciello) - - Choose the correct component from provides matches using requirements (Richard Hughes) - - Do not try to parse huge compressed archive files (Richard Hughes) - - Fix a double-free bug in the Udev code (Philip Withnall) - - Handle Thunderbolt "native" mode (Yehezkel Bernat) - - Use the new functionality in libgcab >= 1.0 to avoid writing temp files (Richard Hughes) - -Version 1.0.2 -~~~~~~~~~~~~~ -Released: 2017-11-28 - -New Features: - - Add a plugin for the Nitrokey Storage device (Richard Hughes) - - Add support for the original AVR DFU protocol (Richard Hughes) - - Allow different plugins to claim the same device (Richard Hughes) - - Allow quirks to set common USB properties (Richard Hughes) - - Move a common plugin functionality out to a new shared object (Richard Hughes) - - Optionally delay the device removal for better replugging (Richard Hughes) - - Set environment variables to allow easy per-plugin debugging (Richard Hughes) - - Use a SHA1 hash for the internal DeviceID (Richard Hughes) - -Bugfixes: - - Add quirk for AT32UC3B1256 as used in the RubberDucky (Richard Hughes) - - Disable the dell plugin if libsmbios fails (Mario Limonciello) - - Don't register for USB UDev events to later ignore them (Richard Hughes) - - Fix a possible buffer overflow when debugging ebitdo devices (Richard Hughes) - - Fix critical warning when more than one remote fails to load (Richard Hughes) - - Fix DFU attaching AVR32 devices like the XMEGA (Richard Hughes) - - Ignore useless Thunderbolt device types (Mario Limonciello) - - Refactor ColorHug into a much more modern plugin (Richard Hughes) - - Release the Steelseries interface if getting the version failed (Richard Hughes) - - Remove autoconf-isms from the meson configure options (Richard Hughes) - - Show a nicer error message if the requirement fails (Richard Hughes) - - Sort the output of GetUpgrades correctly (Richard Hughes) - -Version 1.0.1 -~~~~~~~~~~~~~ -Released: 2017-11-09 - -New Features: - - Add support for HWID requirements (Richard Hughes) - - Add support for programming various AVR32 and XMEGA parts using DFU (Richard Hughes) - - Add the various DFU quirks for the Jabra Speak devices (Richard Hughes) - - Allow specifying the output file type for 'dfu-tool read' (Richard Hughes) - - Move the database of supported devices out into runtime loaded files (Richard Hughes) - - Support the IHEX record type 0x05 (Richard Hughes) - - Use help2man to generate the man page at build time (Richard Hughes) - - Use the new quirk infrastructure for version numbers (Richard Hughes) - -Bugfixes: - - Catch invalid Dell dock component requests (Mario Limonciello) - - Correctly output Intel HEX files with > 16bit offset addresses (Richard Hughes) - - Do not try to verify the element write if upload is unsupported (Richard Hughes) - - Fix a double-unref when updating any 8Bitdo device (Richard Hughes) - - Fix crash when enumerating with Dell dock connected but with no UEFI (Mario Limonciello) - - Fix uploading large firmware files over DFU (Richard Hughes) - - Format the BCD USB revision numbers correctly (Richard Hughes) - - Guess the DFU transfer size if it is not specified (Richard Hughes) - - Include the reset timeout as wValue to fix some DFU bootloaders (Richard Hughes) - - Make the error message clearer when sans fonts are missing (Mario Limonciello) - - Support devices with truncated DFU interface data (Richard Hughes) - - Use the correct remote-specified username and passord when using fwupdmgr (Richard Hughes) - - Use the correct wDetachTimeOut when writing DFU firmware (Richard Hughes) - - Verify devices with legacy VIDs are actually 8Bitdo controllers (Richard Hughes) - -Version 1.0.0 -~~~~~~~~~~~~~ -Released: 2017-10-09 - -Notes: - - This release breaks API and ABI to remove deprecated symbols - - libdfu is now not installed as a shared library - -New Features: - - Add a human-readable title for each remote (Richard Hughes) - - Add a method to return a list of upgrades for a specific device (Richard Hughes) - - Add an 'Summary' and 'Icons' properties to each device (Richard Hughes) - - Add FuDeviceLocker to simplify device open/close lifecycles (Richard Hughes) - - Add functionality to blacklist Dell HW with problems (Mario Limonciello) - - Add fu_plugin_check_supported() (Richard Hughes) - - Add fwupd_remote_get_checksum() to use in client programs (Richard Hughes) - - Add ModifyRemote as an easy way to enable and disable remotes (Richard Hughes) - - Add the plugin documentation to the main gtk-doc (Richard Hughes) - - Allow plugins to depend on each other (Richard Hughes) - - Disable the fallback USB plugin (Richard Hughes) - - Parse the SMBIOS v2 and v3 DMI tables directly (Richard Hughes) - - Support uploading the UEFI firmware splash image (Richard Hughes) - - Use the intel-wmi-thunderbolt kernel module to force power (Mario Limonciello) - -Bugfixes: - - Only run SMI to toggle host MST GPIO on Dell systems with host MST (Mario Limonciello) - - Disable unifying support if no CONFIG_HIDRAW support (Richard Hughes) - - Do not auto-open all USB devices at startup (Richard Hughes) - - Do not fail to load the daemon if cached metadata is invalid (Richard Hughes) - - Do not use system-specific infomation for UEFI PCI devices (Richard Hughes) - - Fix a crash when using fu_plugin_device_add_delay() (Richard Hughes) - - Fix the libdfu self test failure on s390 and ppc64 (Richard Hughes) - - Fix various printing issues with the progressbar (Richard Hughes) - - Generate the LD script from the GObject introspection data (Richard Hughes) - - Never fallback to an offline update from client code (Richard Hughes) - - Only set the Dell coldplug delay when we know we need it (Mario Limonciello) - - Prefer to use HWIDs to get DMI keys and DE table (Mario Limonciello) - -Version 0.9.7 -~~~~~~~~~~~~~ -Released: 2017-09-01 - -New Features: - - Add a configure switch for the LVFS remotes (Richard Hughes) - - Add a FirmwareBaseURI parameter to the remote config (Richard Hughes) - - Add a firmware builder that uses bubblewrap (Richard Hughes) - - Add a python script to create fwupd compatible cab files from Microsoft .exe files (Max Ehrlich) - - Add a thunderbolt plugin for new kernel interface (Christian Kellner, Yehezkel Bernat) - - Allow plugins to get DMI data from the hardware in a safe way (Richard Hughes) - - Allow plugins to set metadata on devices created by other plugins (Richard Hughes, Mario Limonciello) - - Optionally install the LVFS PKCS7 root certificate (Richard Hughes) - - Optionally use GnuTLS to verify PKCS7 certificates (Richard Hughes) - -Bugfixes: - - Add back options for HAVE_SYNAPTICS and HAVE_THUNDERBOLT (Mario Limonciello) - - Allow configuring systemd and udev directories (Mario Limonciello) - - Enable C99 support in meson.build (Philip Withnall) - - Fix an incomplete cipher when using XTEA on data not in 4 byte chunks (Richard Hughes) - - Fix minor const-correctness issues (Philip Withnall) - - Implement thunderbolt image validation (Yehezkel Bernat, Christian Kellner) - - Remove the confusing ALLOW_OFFLINE and ALLOW_ONLINE flags (Richard Hughes) - - Show a bouncing progress bar if the percentage remains at zero (Richard Hughes) - - Use a hwid to match supported systems for synapticsmst (Mario Limonciello) - - Use the new bootloader PIDs for Unifying pico receivers (Richard Hughes) - - When thunderbolt is in safe mode on a Dell recover using SMBIOS (Mario Limonciello) - -Version 0.9.6 -~~~~~~~~~~~~~ -Released: 2017-08-03 - -New Features: - - Add DfuPatch to support forward-only firmware patching (Richard Hughes) - - Add --version option to fwupdmgr (Richard Hughes, Mario Limonciello) - - Display all errors recorded by efi_error tracing (Mario Limonciello) - - Make building introspection optional (Patrick Ohly) - - Support embedded devices with local firmware metadata (Richard Hughes) - -Bugfixes: - - Check all the device GUIDs against the blacklist when added (Richard Hughes) - - Correct a memory leak in Dell plugin (Mario Limonciello, Richard Hughes) - - Default to "en" for UEFI capsule graphics (Mario Limonciello) - - Don't log a warning when an unknown unifying report is parsed (Richard Hughes) - - Enable test suite via /etc/fwupd.conf (Mario Limonciello) - - Fix a hang on 32 bit computers (Richard Hughes) - - Fix compilation of the policy on a variety of configurations (Mario Limonciello) - - Fix UEFI crash when the product name is NULL (Richard Hughes) - - Make flashing ebitdo devices work with fu-ebitdo-tool (Chris Lee) - - Make messages from installing capsules useful (Mario Limonciello) - - Make sure the unifying percentage completion goes from 0% to 100% (Richard Hughes) - - Run the plugin coldplug methods in a predictable order (Richard Hughes) - - Test UEFI for kernel support during coldplug (Mario Limonciello) - - Use new GUsb functionality to fix flashing Unifying devices (Richard Hughes) - -Version 0.9.5 -~~~~~~~~~~~~~ -Released: 2017-07-04 - -New Features: - - Add a get-remotes command to fwupdmgr (Richard Hughes) - - Add a plugin to get the version of the AMT ME interface (Richard Hughes) - - Add Arch Linux to CI (Bruno Pagani) - - Add some installed tests flashing actual hardware (Richard Hughes) - - Allow flashing Unifying devices in bootloader modes (Richard Hughes) - - Allow ordering the metadata remotes (Richard Hughes) - -Bugfixes: - - Do not check the runtime if the DFU device is in bootloader mode (Richard Hughes) - - Do not unlock devices when doing VerifyUpdate (Richard Hughes) - - Filter by Unifying SwId when making HID++2.0 requests (Richard Hughes) - - Fix downgrades when version_lowest is set (Richard Hughes) - - Fix the self tests when running on PPC64 big endian (Richard Hughes) - - Move the remotes parsing from the client to the server (Richard Hughes) - - Split up the Unifying HID++2.0 and HID++1.0 functionality (Richard Hughes) - - Store the metadata files rather than merging to one store (Richard Hughes) - - Use a longer timeout for some Unifying operations (Richard Hughes) - - Use the UFY DeviceID prefix for Unifying devides (Richard Hughes) - -Version 0.9.4 -~~~~~~~~~~~~~ -Released: 2017-06-15 - -New Features: - - Add installed tests that use the daemon (Richard Hughes) - - Add the ability to restrict firmware to specific vendors (Richard Hughes) - - Enable Travis CI for Fedora and Debian (Richard Hughes, Mario Limonciello) - - Export some more API for dealing with checksums (Richard Hughes) - - Generate a images for status messages during system firmware update (Peter Jones) - - Show progress download when refreshing metadata (Richard Hughes) - -Bugfixes: - - Compile with newer versions of meson (Richard Hughes, Mario Limonciello) - - Ensure that firmware provides are legal GUIDs (Richard Hughes) - - Fix a common crash when refreshing metadata (Richard Hughes) - - Use the correct type signature in the D-Bus introspection file (Richard Hughes) - -Version 0.9.3 -~~~~~~~~~~~~~ -Released: 2017-06-07 - -New Features: - - Add a 'downgrade' command to fwupdmgr (Richard Hughes) - - Add a 'get-releases' command to fwupdmgr (Richard Hughes) - - Add support for ConsoleKit2 (Eric Koegel) - - Add support for Microsoft HardwareIDs (Richard Hughes) - - Allow downloading metadata from more than just the LVFS (Richard Hughes) - - Allow multiple checksums on devices and releases (Richard Hughes) - -Bugfixes: - - Allow to specify bindir (Timo Gurr) - - Correctly open Unifying devices with original factory firmware (Richard Hughes) - - Deprecate some of the old FwupdResult API (Richard Hughes) - - Do not copy the origin from the new metadata file (Richard Hughes) - - Do not expect a Unifying reply when issuing a REBOOT command (Richard Hughes) - - Do not re-download firmware that exists in the cache (Richard Hughes) - - Fix a problem when testing for a Dell system (Mario Limonciello) - - Fix flashing new firmware to 8bitdo controllers (Richard Hughes) - - Increase minimum required AppStream-Glib version to 0.6.13 (Chris Mayo) - - Make documentation and man pages optional (Chris Mayo) - - Make systemd dependency at least version 231 (Mario Limonciello) - - Only decompress the firmware after the signature check (Richard Hughes) - - Remove 'lib' prefix when looking for libraries (Mirco Tischler) - - Return the remote ID when getting updates about hardware (Richard Hughes) - - Send the daemon the remote ID when sending firmware metadata (Richard Hughes) - -Version 0.9.2 -~~~~~~~~~~~~~ -Released: 2017-05-22 - -New Features: - - Add support for Unifying DFU features (Richard Hughes) - -Bugfixes: - - Do not spew a critial warning when parsing an invalid URI (Richard Hughes) - - Ensure device is closed if did not complete setup (Richard Hughes) - - Ensure steelseries device is closed if it returns an invalid packet (Richard Hughes) - - Fix man page installation location (Mario Limonciello) - - Ignore spaces in the Unifying version prefix (Richard Hughes) - - Set HAVE_POLKIT_0_114 when polkit is newer than 0.114 (Moritz Kiefer) - -Version 0.9.1 -~~~~~~~~~~~~~ -Released: 2017-04-28 - -New Features: - - Add a config option to allow runtime disabling plugins by name (Richard Hughes) - - Add the Meson build system and remove autotools (Richard Hughes) - - Support signed Intel HEX files (Richard Hughes) - -Bugfixes: - - Add DFU quirk for OpenPICC and SIMtrace (Richard Hughes) - - Create directories in /var/cache as required (Richard Hughes) - - Refactor the unifying plugin now we know more about the hardware (Richard Hughes) - - Set the source origin when saving metadata (Richard Hughes) - - Support proxy servers in fwupdmgr (Richard Hughes) - - Use a 60 second timeout on all client downloads (Richard Hughes) - -Version 0.8.1 -~~~~~~~~~~~~~ -Released: 2017-02-27 - -Bugfixes: - - Adjust systemd confinement restrictions (Mario Limonciello, Richard Hughes) - - Do not hardcode docbook2man path (Kai Krakow) - - Don't initialize libsmbios on unsupported systems (Mario Limonciello) - - Fix a crash when enumerating devices on a Dell WLD15 (Richard Hughes) - - Fix compiler warnings (Kai Krakow) - - Fix fwupdmgr timeout with missing pending database (Richard Hughes) - -Version 0.8.0 -~~~~~~~~~~~~~ -Released: 2017-02-08 - -New Features: - - Add a set of vfuncs that are run before and after a device update (Richard Hughes) - - Add Dell-specific functionality to allow other plugins turn on TBT/GPIO (Mario Limonciello) - - Add support for Intel Thunderbolt devices (Richard Hughes, Mario Limonciello) - - Add support for Logitech Unifying devices (Richard Hughes) - - Add support for Synaptics MST cascades hubs (Mario Limonciello) - - Add support for the Altus-Metrum ChaosKey device (Richard Hughes) - - Add VerifyUpdate to update the device checksums server-side (Richard Hughes) - - Allow the metadata to match a version of fwupd and the existing fw version (Richard Hughes) - -Bugfixes: - - Add a new method for forcing a controller to flash mode (Mario Limonciello) - - Always make sure we're getting a C99 compiler (Richard Hughes) - - Close USB devices before error returns (Tsunghan Liu) - - Don't read data from some DfuSe targets (Richard Hughes) - - Include all debug messages when run with --verbose (Richard Hughes) - - Return the pending UEFI update when not on AC power (Richard Hughes) - - Use a heuristic for the start address if the firmware has no DfuSe footer (Richard Hughes) - - Use more restrictive settings when running under systemd (Richard Hughes, Mario Limonciello) - -Version 0.7.5 -~~~~~~~~~~~~~ -Released: 2016-10-19 - -New Features: - - Add a 'replace-data' command to dfu-tool (Richard Hughes) - - Use an animated progress bar when performing DFU operations (Richard Hughes) - -Bugfixes: - - Add quirks for HydraBus as it does not have a DFU runtime (Richard Hughes) - - Don't create the UEFI dummy device if the unlock will happen on next boot (Richard Hughes) - - Enable hardening flags on more binaries (Mario Limonciello) - - Fix an assert when unlocking the dummy ESRT device (Richard Hughes) - - Fix writing firmware to devices using the ST reference bootloader (Richard Hughes) - - Match the Dell TB16 device (Mario Limonciello) - - Re-get the quirks when the DfuDevice gets a new GUsbDevice (Richard Hughes) - - Show the nicely formatted target name for DfuSe devices (Richard Hughes) - - Verify devices support updating in mode they are called (Mario Limonciello) - -Version 0.7.4 -~~~~~~~~~~~~~ -Released: 2016-09-19 - -New Features: - - Add dfu_firmware_add_symbol() (Richard Hughes) - - Allow the argument to 'dfu-tool set-release' be major.minor (Richard Hughes) - - Load the Altos USB descriptor from ELF files (Richard Hughes) - - Support writing the IHEX symbol table (Richard Hughes) - -Bugfixes: - - Add a fallback for older appstream-glib releases (Richard Hughes) - - Fix a possible crash when uploading firmware files using libdfu (Richard Hughes) - - Fix libfwupd self tests when a host-provided fwupd is not available (Richard Hughes) - - Show the human-readable version in the 'dfu-tool dump' output (Richard Hughes) - - Write the ELF files with the correct section type (Richard Hughes) - -Version 0.7.3 -~~~~~~~~~~~~~ -Released: 2016-08-29 - -New Features: - - Add a set-address and set-target-size commands to dfu-util (Richard Hughes) - - Add a small library for talking with 0bitdo hardware (Richard Hughes) - - Add Dell TPM and TB15/WD15 support via new Dell provider (Mario Limonciello) - - Add FU_DEVICE_FLAG_NEEDS_BOOTLOADER (Richard Hughes) - - Add fwupd_client_get_status() (Richard Hughes) - - Add fwupd_result_get_unique_id() (Richard Hughes) - - Add initial ELF reading and writing support to libdfu (Richard Hughes) - - Add support for installing multiple devices from a CAB file (Richard Hughes) - - Allow providers to export percentage completion (Richard Hughes) - - Show a progress notification when installing firmware (Richard Hughes) - - Show the vendor flashing instructions when installing (Richard Hughes) - -Bugfixes: - - Add XPS 9250 to Dell TPM modeswitch blacklist (Mario Limonciello) - - Allow blacklisting devices by their GUID (Richard Hughes) - - Conditionally enable all providers based upon installed (Mario Limonciello) - - Display flashes left in results output when it gets low (Mario Limonciello) - - Do not attempt to add DFU devices not in runtime mode (Richard Hughes) - - Do not use the deprecated GNOME_COMPILE_WARNINGS (Richard Hughes) - - Don't fail while checking versions or locked state (Richard Hughes) - - Embed fwupd version in generated documentation (Mario Limonciello) - - Ensure the ID is set when getting local firmware details (Richard Hughes) - - Fix gtk-doc build when srcdir != builddir (Ting-Wei Lan) - - Fix libdfu hang when parsing corrupt IHEX files (Richard Hughes) - - Ignore devices that do not add at least one GUID (Richard Hughes) - - In get-details output, display the blob filename (Mario Limonciello) - - Save the unique ID in the pending database (Richard Hughes) - - Support the 'DEVO' cipher kind in libdfu (Richard Hughes) - - Switch to the Amazon S3 CDN for firmware metadata (Richard Hughes) - - Update fwupdmgr manpage for new commands and arguments (Mario Limonciello) - - Use a private gnupg key store (Richard Hughes) - - Use the correct firmware when installing a composite device (Richard Hughes) - - Use the SHA1 hash of the local file data as the origin (Richard Hughes) - -Version 0.7.2 -~~~~~~~~~~~~~ -Released: 2016-06-13 - -New Features: - - Add a GetDetailsLocal() method to eventually replace GetDetails() (Richard Hughes) - - Add fu_device_get_alternate() (Richard Hughes) - - Allow devices to have multiple assigned GUIDs (Richard Hughes) - - Allow metainfo files to match only specific revisions of devices (Richard Hughes) - - Show the DFU protocol version in 'dfu-tool list' (Richard Hughes) - -Bugfixes: - - Enforce allowing providers to take away flash abilities (Mario Limonciello) - - Only claim the DFU interface when required (Richard Hughes) - - Only return updatable devices from GetDevices() (Richard Hughes) - -Version 0.7.1 -~~~~~~~~~~~~~ -Released: 2016-05-13 - -New Features: - - Add a --force flag to override provider warnings (Mario Limonciello) - - Add device-added, device-removed and device-changed signals (Richard Hughes) - - Add dfu_image_get_element_default() (Richard Hughes) - - Add for a new device field "Flashes Left" (Mario Limonciello) - - Add fwupd_client_connect() (Richard Hughes) - - Add the 'monitor' debugging command for fwupdmgr (Richard Hughes) - - Add the 'supported' flag to the FuDevice (Richard Hughes) - -Bugfixes: - - Add summary and name field for Rival SteelSeries (Mario Limonciello) - - Fix a critical warning when restarting the daemon (Richard Hughes) - - Fix BE issues when reading and writing DFU files (Mario Limonciello, Richard Hughes) - - Make the device display name nicer (Richard Hughes, Richard Hughes) - - Match the AppStream metadata after a device has been added (Richard Hughes) - - Remove non-interactive pinentry setting from fu-keyring (Mario Limonciello) - - Return all update descriptions newer than the installed version (Richard Hughes) - - Set the device description when parsing local firmware files (Richard Hughes) - -Version 0.7.0 -~~~~~~~~~~~~~ -Released: 2016-04-01 - -New Features: - - Add a version plugin for SteelSeries hardware (Richard Hughes) - - Add FwupdClient and FwupdResult to libfwupd (Richard Hughes) - - Generate gtk-doc documentation for libfwupd (Richard Hughes) - - Return the device flags when getting firmware details (Richard Hughes) - - Support other checksum kinds (Richard Hughes) - -Bugfixes: - - Add Alienware to the version quirk table (Mario Limonciello) - - Allow the test suite to run in %check (Richard Hughes) - - Do not return updates that require AC when on battery (Richard Hughes) - - Do not use /tmp for downloaded files (Richard Hughes) - - Test that GPG key import actually was successful (Mario Limonciello) - -Version 0.6.3 -~~~~~~~~~~~~~ -Released: 2016-03-14 - -New Features: - - Add an unlock method for devices (Richard Hughes) - - Add a simple plugin infrastructure (Richard Hughes) - - Add ESRT enable method into UEFI provider (Mario Limonciello) - - Install the hardcoded firmware AppStream file (Richard Hughes) - -Bugfixes: - - Correct the BCD version number for DFU 1.1 (Richard Hughes) - - Do not use deprecated API from libappstream-glib (Richard Hughes) - - Ignore the DFU runtime on the DW1820A (Richard Hughes) - - Only read PCI OptionROM firmware when devices are manually unlocked (Richard Hughes) - - Require AC power before scheduling some types of firmware update (Richard Hughes) - - Show ignored DFU devices in dfu-util, but not in fwupd (Richard Hughes) - -Version 0.6.2 -~~~~~~~~~~~~~ -Released: 2016-02-12 - -New Features: - - Add 'Created' and 'Modified' properties on managed devices (Richard Hughes) - -Bugfixes: - - Fix get-results for UEFI provider (Mario Limonciello) - - Support vendor-specific UEFI version encodings (Richard Hughes) - -Version 0.6.1 -~~~~~~~~~~~~~ -Released: 2016-01-19 - -Bugfixes: - - Always persist ColorHug devices after replug (Richard Hughes) - - Do not misdetect different ColorHug devices (Richard Hughes) - - Only dump the profiling data when run with --verbose (Richard Hughes) - -Version 0.6.0 -~~~~~~~~~~~~~ -Released: 2015-12-07 - -Notes: - - This release adds a new GObject library called libdfu and a command line - client called dfu-tool. This is a low-level tool used to upgrade USB device - firmware and can either be shipped in the same package as fwupd or split off - as separate subpackages. - -New Features: - - Add support for automatically updating USB DFU-capable devices (Richard Hughes) - -Bugfixes: - - Emit the changed signal after doing an update (Richard Hughes) - - Export the AppStream ID when returning device results (Richard Hughes) - - Fix compile with --disable-shared (Richard Hughes) - - Use new API available in fwup 0.5 (Richard Hughes, Mario Limonciello) - - Use the same device identification string format as Microsoft (Richard Hughes) - -Version 0.5.3 -~~~~~~~~~~~~~ -Released: 2015-11-05 - -Bugfixes: - - Avoid seeking when reading the file magic during refresh (Richard Hughes) - - Do not assume that the compressed XML data will be NUL terminated (Richard Hughes) - - Use the correct user agent string for fwupdmgr (Richard Hughes) - -Version 0.5.2 -~~~~~~~~~~~~~ -Released: 2015-10-28 - -New Features: - - Add profiling data to debug slow startup times (Richard Hughes) - - Support cabinet archives files with more than one firmware (Richard Hughes) - -Bugfixes: - - Add the update description to the GetDetails results (Richard Hughes) - - Clear the in-memory firmware store only after parsing a valid XML file (Richard Hughes) - - Ensure D-Bus remote errors are registered at fwupdmgr startup (Richard Hughes) - - Fix verify-update to produce components with the correct provide values (Richard Hughes) - - Require appstream-glib 0.5.1 (Mirco Tischler) - - Show the dotted-decimal representation of the UEFI version number (Richard Hughes) - - When the version is from the 'FW' extension do not cache the device (Richard Hughes) - -Version 0.5.1 -~~~~~~~~~~~~~ -Released: 2015-09-21 - -Bugfixes: - - Fix the error message when no devices can be updated (Richard Hughes) - - Fix reading symlink to prevent crash with some compilers (Kalev Lember) - -Version 0.5.0 -~~~~~~~~~~~~~ -Released: 2015-09-15 - -New Features: - - Raise the dep on GLib to support and use g_autoptr() (Richard Hughes) - -Bugfixes: - - Do not merge existing firmware metadata (Richard Hughes) - - Do not reboot if racing with the PackageKit offline update mechanism (Richard Hughes) - -Version 0.1.6 -~~~~~~~~~~~~~ -Released: 2015-09-10 - -New Features: - - Remove fwsignd, we have the LVFS now (Richard Hughes) - -Bugfixes: - - Add application metadata when getting the updates list (Richard Hughes) - - Depend on appstream-glib >= 0.5.0 (Richard Hughes) - - Don't apply firmware if something else is processing the update (Richard Hughes) - - Install fwupd into /usr/lib/$(triplet)/fwupd instead (Mario Limonciello) - - Simplify the version properties on devices to avoid complexity (Richard Hughes) - - Update the offline update service to invoke right command (Kalev Lember) - - Use the new secure metadata URI (Richard Hughes) - -Version 0.1.5 -~~~~~~~~~~~~~ -Released: 2015-08-12 - -Notes: - - For the device verification code to work correctly you need at least - libappstream-glib 0.5.0 installed. - -New Features: - - Add a Raspberry Pi firmware provider (Richard Hughes) - - Add a simple config file to store the correct LVFS download URI (Richard Hughes) - - Make parsing the option ROM runtime optional (Richard Hughes) - -Bugfixes: - - Allow fwupd to be autostarted by systemd (Richard Hughes) - - Allow no arguments to 'fwupdmgr verify-update' and use sane defaults (Richard Hughes) - - Devices with option ROM are always internal (Richard Hughes) - - Do not pre-convert the update description from AppStream XML (Richard Hughes) - - Fix validation of written firmware (Richard Hughes) - - Move the verification and metadata matching phase to the daemon (Richard Hughes) - - Sign the test binary with the correct key (Richard Hughes) - - Use the AppStream 0.9 firmware specification by default (Richard Hughes) - -Version 0.1.4 -~~~~~~~~~~~~~ -Released: 2015-07-25 - -Notes: - - In this release we've moved the LVFS website to the fwupd project and made - them work really well together. To update all the firmware on your system - is now just a case of "fwupdmgr refresh && fwupdmgr update" - - We've also added verification of BIOS and PCI ROM firmware, which may be - useful for forensics or to verify that system updates have been applied. - -New Features: - - Actually parse the complete PCI option ROM (Richard Hughes) - - Add a 'fwupdmgr update' command to update all devices to latest versions (Richard Hughes) - - Add a simple signing server that operates on .cab files (Richard Hughes) - - Add a 'verify' command that verifies the cryptographic hash of device firmware (Richard Hughes) - - Allow clients to add new firmware metadata to the system cache (Richard Hughes) - - Move GetUpdates to the daemon (Richard Hughes) - - Move the LVFS website to the fwupd project (Richard Hughes) - -Bugfixes: - - Accept multiple files at one time when using fwupdmgr dump-rom (Richard Hughes) - - Automatically download metadata using fwupdmgr if required (Richard Hughes) - - Do not return NULL as a gboolean (Thomas Hindoe Paaboel Andersen) - - Don't call efibootmgr after fwupdate (Mario Limonciello) - - Fallback to offline install when calling the update argument (Mario Limonciello) - - Fix Intel VBIOS detection on Dell hardware (Richard Hughes) - - Reload appstream data after refreshing (Mario Limonciello) - - Use the new LVFS GPG key (Richard Hughes) - - Fix build: libgusb is required even without colorhug support (Jussi Kukkonen) - -Version 0.1.3 -~~~~~~~~~~~~~ -Released: 2015-05-28 - -New Features: - - Get the firmware version from the device descriptors (Richard Hughes) - - Run the offline actions using systemd when required (Richard Hughes) - - Support OpenHardware devices using the fwupd vendor extensions (Richard Hughes) - -Bugfixes: - - Add an UNKNOWN status so we can return meaningful enum values (Richard Hughes) - - Coldplug the devices before acquiring the well known name (Richard Hughes) - -Version 0.1.2 -~~~~~~~~~~~~~ -Released: 2015-04-22 - - Add some guidelines for vendors to README (Richard Hughes) - - Only allow signed firmware to be upgraded without a password (Richard Hughes) - -Version 0.1.1 -~~~~~~~~~~~~~ -Released: 2015-03-23 - -New Features: - - Add a 'get-updates' command to fwupdmgr (Richard Hughes) - - Add and document the offline-update lifecycle (Richard Hughes) - - Create a libfwupd shared library (Richard Hughes) - -Bugfixes: - - Create runtime directories if they do not exist (Richard Hughes) - - Do not crash when there are no devices to return (Richard Hughes) - -Version 0.1.0 -~~~~~~~~~~~~~ -Released: 2015-03-16 - -Notes: - - fwupd is a simple daemon to allow session software to update firmware. diff -Nru fwupd-1.1.4/plugins/altos/fu-altos-device.c fwupd-1.2.5/plugins/altos/fu-altos-device.c --- fwupd-1.1.4/plugins/altos/fu-altos-device.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/altos/fu-altos-device.c 2019-02-25 09:42:18.000000000 +0000 @@ -12,6 +12,7 @@ #include #include +#include "fu-io-channel.h" #include "fu-altos-device.h" #include "fu-altos-firmware.h" @@ -25,7 +26,7 @@ guint64 addr_base; guint64 addr_bound; struct termios tty_termios; - gint tty_fd; + FuIOChannel *io_channel; }; G_DEFINE_TYPE (FuAltosDevice, fu_altos_device, FU_TYPE_USB_DEVICE) @@ -149,60 +150,15 @@ gssize data_len, GError **error) { - gint rc; - gssize idx = 0; - guint timeout_ms = 500; - struct pollfd fds; - /* lets assume this is text */ if (data_len < 0) data_len = strlen (data); - - fds.fd = self->tty_fd; - fds.events = POLLOUT; - - g_debug ("write, with timeout %ums", timeout_ms); - while (idx < data_len) { - - /* wait for data to be allowed to write without blocking */ - rc = poll (&fds, 1, (gint) timeout_ms); - if (rc == 0) - break; - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "failed to poll %i", - self->tty_fd); - return FALSE; - } - - /* we can write data */ - if (fds.revents & POLLOUT) { - gssize len; - g_debug ("writing %" G_GSSIZE_FORMAT " bytes: %s", data_len, data); - len = write (self->tty_fd, data + idx, data_len - idx); - if (len < 0) { - if (errno == EAGAIN) { - g_debug ("got EAGAIN, trying harder"); - continue; - } - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_WRITE, - "failed to write %" G_GSSIZE_FORMAT - " bytes to %i: %s" , - data_len, - self->tty_fd, - strerror (errno)); - return FALSE; - } - g_debug ("wrote %" G_GSSIZE_FORMAT " bytes", len); - idx += len; - } - } - - return TRUE; + return fu_io_channel_write_raw (self->io_channel, + (const guint8 *) data, + (gsize) data_len, + 500, /* ms */ + FU_IO_CHANNEL_FLAG_NONE, + error); } static GString * @@ -211,90 +167,12 @@ gssize max_size, GError **error) { - gint rc; - struct pollfd fds; - g_autoptr(GString) str = g_string_new (NULL); - - fds.fd = self->tty_fd; - fds.events = POLLIN; - - g_debug ("read, with timeout %ums", timeout_ms); - for (;;) { - /* wait for data to appear */ - rc = poll (&fds, 1, (gint) timeout_ms); - if (rc == 0) - break; - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "failed to poll %i", - self->tty_fd); - return NULL; - } - - /* we have data to read */ - if (fds.revents & POLLIN) { - guint8 buf[1024]; - gssize len = read (self->tty_fd, buf, sizeof (buf)); - if (len < 0) { - if (errno == EAGAIN) { - g_debug ("got EAGAIN, trying harder"); - continue; - } - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "failed to read %i: %s", - self->tty_fd, - strerror (errno)); - return NULL; - } - if (len > 0) { - g_debug ("read %" G_GSSIZE_FORMAT " bytes from device", len); - g_string_append_len (str, (gchar *) buf, len); - } - - /* check maximum size */ - if (max_size > 0 && str->len >= (guint) max_size) - break; - continue; - } - if (fds.revents & POLLERR) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "error condition"); - return NULL; - } - if (fds.revents & POLLHUP) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "connection hung up"); - return NULL; - } - if (fds.revents & POLLNVAL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "invalid request"); - return NULL; - } - } - - /* no data */ - if (str->len == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "no data received from device in %ums", - timeout_ms); + g_autoptr(GBytes) buf = NULL; + buf = fu_io_channel_read_bytes (self->io_channel, max_size, + timeout_ms, FU_IO_CHANNEL_FLAG_NONE, error); + if (buf == NULL) return NULL; - } - - /* return blob */ - return g_steal_pointer (&str); + return g_string_new_len (g_bytes_get_data (buf, NULL), g_bytes_get_size (buf)); } static gboolean @@ -304,18 +182,12 @@ g_autoptr(GString) str = NULL; /* open device */ - self->tty_fd = open (self->tty, O_RDWR | O_NONBLOCK); - if (self->tty_fd < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "failed to open %s", - self->tty); + self->io_channel = fu_io_channel_new_file (self->tty, error); + if (self->io_channel == NULL) return FALSE; - } /* get the old termios settings so we can restore later */ - if (tcgetattr (self->tty_fd, &termios) < 0) { + if (tcgetattr (fu_io_channel_unix_get_fd (self->io_channel), &termios) < 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -340,7 +212,8 @@ termios.c_cc[VTIME] = 0; /* set all new data */ - if (tcsetattr (self->tty_fd, TCSAFLUSH, &termios) < 0) { + if (tcsetattr (fu_io_channel_unix_get_fd (self->io_channel), + TCSAFLUSH, &termios) < 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -359,10 +232,11 @@ static gboolean fu_altos_device_tty_close (FuAltosDevice *self, GError **error) { - - tcsetattr (self->tty_fd, TCSAFLUSH, &self->tty_termios); - close (self->tty_fd); - + tcsetattr (fu_io_channel_unix_get_fd (self->io_channel), + TCSAFLUSH, &self->tty_termios); + if (!fu_io_channel_shutdown (self->io_channel, error)) + return FALSE; + g_clear_object (&self->io_channel); return TRUE; } diff -Nru fwupd-1.1.4/plugins/altos/fu-altos-device.h fwupd-1.2.5/plugins/altos/fu-altos-device.h --- fwupd-1.1.4/plugins/altos/fu-altos-device.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/altos/fu-altos-device.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_ALTOS_DEVICE_H -#define __FU_ALTOS_DEVICE_H +#pragma once #include "fu-plugin.h" @@ -35,5 +34,3 @@ FuAltosDeviceKind fu_altos_device_get_kind (FuAltosDevice *device); G_END_DECLS - -#endif /* __FU_ALTOS_DEVICE_H */ diff -Nru fwupd-1.1.4/plugins/altos/fu-altos-firmware.h fwupd-1.2.5/plugins/altos/fu-altos-firmware.h --- fwupd-1.1.4/plugins/altos/fu-altos-firmware.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/altos/fu-altos-firmware.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_ALTOS_FIRMWARE_H -#define __FU_ALTOS_FIRMWARE_H +#pragma once G_BEGIN_DECLS @@ -21,5 +20,3 @@ GError **error); G_END_DECLS - -#endif /* __FU_ALTOS_FIRMWARE_H */ diff -Nru fwupd-1.1.4/plugins/altos/fu-plugin-altos.c fwupd-1.2.5/plugins/altos/fu-plugin-altos.c --- fwupd-1.1.4/plugins/altos/fu-plugin-altos.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/altos/fu-plugin-altos.c 2019-02-25 09:42:18.000000000 +0000 @@ -13,7 +13,9 @@ void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.altusmetrum.altos"); } gboolean diff -Nru fwupd-1.1.4/plugins/altos/meson.build fwupd-1.2.5/plugins/altos/meson.build --- fwupd-1.1.4/plugins/altos/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/altos/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -5,6 +5,7 @@ ) shared_module('fu_plugin_altos', + fu_hash, sources : [ 'fu-altos-device.c', 'fu-altos-firmware.c', @@ -17,6 +18,9 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ libelf, diff -Nru fwupd-1.1.4/plugins/altos/README.md fwupd-1.2.5/plugins/altos/README.md --- fwupd-1.1.4/plugins/altos/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/altos/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -15,6 +15,25 @@ created so userspace can communicate with the hardware. Commands the bootloader accept are as follows: +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +ELF file format. The firmware image is inserted into the `.text` section. + +This plugin supports the following protocol ID: + + * org.altusmetrum.altos + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_1D50&PID_60C6&REV_0001` + * `USB\VID_1D50&PID_60C6` + * `USB\VID_1D50` + ### List Information Command: `l\n` diff -Nru fwupd-1.1.4/plugins/amt/fu-plugin-amt.c fwupd-1.2.5/plugins/amt/fu-plugin-amt.c --- fwupd-1.1.4/plugins/amt/fu-plugin-amt.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/amt/fu-plugin-amt.c 2019-02-25 09:42:18.000000000 +0000 @@ -13,7 +13,6 @@ #include #include #include -#include #include "fu-plugin-vfuncs.h" @@ -86,27 +85,26 @@ return TRUE; } -static gssize +static gboolean mei_recv_msg (mei_context *ctx, guchar *buffer, - gssize len, unsigned long timeout, GError **error) + gssize len, guint32 *readsz, unsigned long timeout, GError **error) { gssize rc; - - g_debug ("call read length = %zd", len); rc = read (ctx->fd, buffer, len); if (rc < 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_READ, "read failed with status %zd %s", - rc, strerror(errno)); - } else { - g_debug ("read succeeded with result %zd", rc); + rc, strerror(errno)); + return FALSE; } - return rc; + if (readsz != NULL) + *readsz = rc; + return TRUE; } -static gssize +static gboolean mei_send_msg (mei_context *ctx, const guchar *buffer, gssize len, unsigned long timeout, GError **error) { @@ -118,7 +116,6 @@ tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000000; - g_debug ("call write length = %zd", len); written = write (ctx->fd, buffer, len); if (written < 0) { g_set_error (error, @@ -126,16 +123,22 @@ FWUPD_ERROR_WRITE, "write failed with status %zd %s", written, strerror(errno)); - return -errno; + return FALSE; + } + if (written != len) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "only wrote %" G_GSSIZE_FORMAT " of %" G_GSSIZE_FORMAT, + written, len); + return FALSE; } FD_ZERO(&set); FD_SET(ctx->fd, &set); rc = select (ctx->fd + 1 , &set, NULL, NULL, &tv); - if (rc > 0 && FD_ISSET(ctx->fd, &set)) { - g_debug ("write success"); - return written; - } + if (rc > 0 && FD_ISSET(ctx->fd, &set)) + return TRUE; /* timed out */ if (rc == 0) { @@ -143,7 +146,7 @@ FWUPD_ERROR, FWUPD_ERROR_WRITE, "write failed on timeout with status"); - return 0; + return FALSE; } /* rc < 0 */ @@ -151,7 +154,7 @@ FWUPD_ERROR, FWUPD_ERROR_WRITE, "write failed on select with status %zd", rc); - return rc; + return FALSE; } /*************************************************************************** @@ -254,50 +257,91 @@ mei_context mei_cl; }; -static guint32 -amt_verify_code_versions (const struct amt_host_if_resp_header *resp) +static gboolean +amt_verify_code_versions (const struct amt_host_if_resp_header *resp, GError **error) { struct amt_code_versions *code_ver = (struct amt_code_versions *)resp->data; gsize code_ver_len = resp->header.length - sizeof(guint32); guint32 ver_type_cnt = code_ver_len - sizeof(code_ver->bios) - sizeof(code_ver->count); - if (code_ver->count != ver_type_cnt / sizeof(struct amt_version_type)) - return AMT_STATUS_INTERNAL_ERROR; + if (code_ver->count != ver_type_cnt / sizeof(struct amt_version_type)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid offset"); + return FALSE; + } for (guint32 i = 0; i < code_ver->count; i++) { guint32 len = code_ver->versions[i].description.length; - if (len > AMT_UNICODE_STRING_LEN) - return AMT_STATUS_INTERNAL_ERROR; + if (len > AMT_UNICODE_STRING_LEN) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "string too large"); + return FALSE; + } len = code_ver->versions[i].version.length; if (code_ver->versions[i].version.string[len] != '\0' || - len != strlen(code_ver->versions[i].version.string)) - return AMT_STATUS_INTERNAL_ERROR; + len != strlen(code_ver->versions[i].version.string)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "string was invalid size"); + return FALSE; + } } - return AMT_STATUS_SUCCESS; + return TRUE; } -static guint32 -amt_verify_response_header (guint32 command, - const struct amt_host_if_msg_header *resp_hdr, - guint32 response_size) +static gboolean +amt_status_set_error (guint32 status, GError **error) { - if (response_size < sizeof(struct amt_host_if_resp_header)) { - return AMT_STATUS_INTERNAL_ERROR; - } else if (response_size != (resp_hdr->length + - sizeof(struct amt_host_if_msg_header))) { - return AMT_STATUS_INTERNAL_ERROR; - } else if (resp_hdr->command != command) { - return AMT_STATUS_INTERNAL_ERROR; - } else if (resp_hdr->_reserved != 0) { - return AMT_STATUS_INTERNAL_ERROR; - } else if (resp_hdr->version.major != AMT_MAJOR_VERSION || - resp_hdr->version.minor < AMT_MINOR_VERSION) { - return AMT_STATUS_INTERNAL_ERROR; + if (status == AMT_STATUS_SUCCESS) + return TRUE; + if (status == AMT_STATUS_INTERNAL_ERROR) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "internal error"); + return FALSE; + } + if (status == AMT_STATUS_NOT_READY) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "not ready"); + return FALSE; } - return AMT_STATUS_SUCCESS; + if (status == AMT_STATUS_INVALID_AMT_MODE) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid AMT mode"); + return FALSE; + } + if (status == AMT_STATUS_INVALID_MESSAGE_LENGTH) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid message length"); + return FALSE; + } + if (status == AMT_STATUS_HOST_IF_EMPTY_RESPONSE) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Intel AMT is disabled"); + return FALSE; + } + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unknown error"); + return FALSE; } -static guint32 +static gboolean amt_host_if_call (mei_context *mei_cl, const guchar *command, gssize command_sz, @@ -309,53 +353,86 @@ { guint32 in_buf_sz; guint32 out_buf_sz; - gssize written; - guint32 status; struct amt_host_if_resp_header *msg_hdr; in_buf_sz = mei_cl->buf_size; *read_buf = (guint8 *) g_malloc0 (in_buf_sz); msg_hdr = (struct amt_host_if_resp_header *) *read_buf; - written = mei_send_msg (mei_cl, command, command_sz, send_timeout, error); - if (written != command_sz) - return AMT_STATUS_INTERNAL_ERROR; - - out_buf_sz = mei_recv_msg (mei_cl, *read_buf, in_buf_sz, 2000, error); - if (out_buf_sz <= 0) - return AMT_STATUS_HOST_IF_EMPTY_RESPONSE; - - status = msg_hdr->status; - if (status != AMT_STATUS_SUCCESS) - return status; - - status = amt_verify_response_header(rcmd, &msg_hdr->header, out_buf_sz); - if (status != AMT_STATUS_SUCCESS) - return status; - - if (expected_sz && expected_sz != out_buf_sz) - return AMT_STATUS_INTERNAL_ERROR; - - return AMT_STATUS_SUCCESS; + if (!mei_send_msg (mei_cl, command, command_sz, send_timeout, error)) + return FALSE; + if (!mei_recv_msg (mei_cl, *read_buf, in_buf_sz, &out_buf_sz, 2000, error)) + return FALSE; + if (out_buf_sz <= 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "empty response"); + return FALSE; + } + if (expected_sz && expected_sz != out_buf_sz) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "expected %u but got %" G_GUINT32_FORMAT, + expected_sz, out_buf_sz); + return FALSE; + } + if (!amt_status_set_error (msg_hdr->status, error)) + return FALSE; + if (out_buf_sz < sizeof(struct amt_host_if_resp_header)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "invalid response: too small"); + return FALSE; + } + if (out_buf_sz != (msg_hdr->header.length + + sizeof(struct amt_host_if_msg_header))) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "invalid response: headerlen"); + return FALSE; + } + if (msg_hdr->header.command != rcmd) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "invalid response: rcmd"); + return FALSE; + } + if (msg_hdr->header._reserved != 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "invalid response: reserved"); + return FALSE; + } + if (msg_hdr->header.version.major != AMT_MAJOR_VERSION || + msg_hdr->header.version.minor < AMT_MINOR_VERSION) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "invalid response: version"); + return FALSE; + } + return TRUE; } -static guint32 +static gboolean amt_get_provisioning_state (mei_context *mei_cl, guint8 *state, GError **error) { g_autofree struct amt_host_if_resp_header *response = NULL; - guint32 status; - - status = amt_host_if_call (mei_cl, - (const guchar *)&PROVISIONING_STATE_REQUEST, - sizeof(PROVISIONING_STATE_REQUEST), - (guint8 **)&response, - AMT_HOST_IF_PROVISIONING_STATE_RESPONSE, 0, - 5000, error); - if (status != AMT_STATUS_SUCCESS) { + if (!amt_host_if_call (mei_cl, + (const guchar *)&PROVISIONING_STATE_REQUEST, + sizeof(PROVISIONING_STATE_REQUEST), + (guint8 **)&response, + AMT_HOST_IF_PROVISIONING_STATE_RESPONSE, 0, + 5000, error)) { g_prefix_error (error, "unable to get provisioning state: "); return FALSE; } - *state = response->data[0]; return TRUE; } @@ -368,13 +445,14 @@ static FuDevice * fu_plugin_amt_create_device (GError **error) { - gchar guid_buf[37]; - guint32 status; guint8 state; struct amt_code_versions ver; - uuid_t uu; + fwupd_guid_t uu; + g_autofree gchar *guid_buf = NULL; g_autofree struct amt_host_if_resp_header *response = NULL; g_autoptr(FuDevice) dev = NULL; + g_autoptr(GString) version_bl = g_string_new (NULL); + g_autoptr(GString) version_fw = g_string_new (NULL); g_autoptr(mei_context) ctx = g_new0 (mei_context, 1); const uuid_le MEI_IAMTHIF = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, \ @@ -385,33 +463,18 @@ return NULL; /* check version */ - status = amt_host_if_call (ctx, - (const guchar *) &CODE_VERSION_REQ, - sizeof(CODE_VERSION_REQ), - (guint8 **) &response, - AMT_HOST_IF_CODE_VERSIONS_RESPONSE, 0, - 5000, - error); - if (status != AMT_STATUS_SUCCESS) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Failed to check version"); + if (!amt_host_if_call (ctx, + (const guchar *) &CODE_VERSION_REQ, + sizeof(CODE_VERSION_REQ), + (guint8 **) &response, + AMT_HOST_IF_CODE_VERSIONS_RESPONSE, 0, + 5000, + error)) { + g_prefix_error (error, "Failed to check version: "); return NULL; } - status = amt_verify_code_versions (response); - if (status == AMT_STATUS_HOST_IF_EMPTY_RESPONSE) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Intel AMT is disabled"); - return NULL; - } - if (status != AMT_STATUS_SUCCESS) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Failed to verify code versions"); + if (!amt_verify_code_versions (response, error)) { + g_prefix_error (error, "failed to verify code versions: "); return NULL; } memcpy (&ver, response->data, sizeof(struct amt_code_versions)); @@ -443,24 +506,44 @@ /* add guid */ memcpy (&uu, &ctx->guid, 16); - uuid_unparse (uu, guid_buf); + guid_buf = fwupd_guid_to_string ((const fwupd_guid_t *) &uu, FWUPD_GUID_FLAG_NONE); fu_device_add_guid (dev, guid_buf); /* get version numbers */ for (guint i = 0; i < ver.count; i++) { if (g_strcmp0 (ver.versions[i].description.string, "AMT") == 0) { - fu_device_set_version (dev, ver.versions[i].version.string); + g_string_append (version_fw, ver.versions[i].version.string); + continue; + } + if (g_strcmp0 (ver.versions[i].description.string, "Recovery Version") == 0) { + g_string_append (version_bl, ver.versions[i].version.string); + continue; + } + if (g_strcmp0 (ver.versions[i].description.string, "Build Number") == 0) { + g_string_append_printf (version_fw, ".%s", + ver.versions[i].version.string); continue; } - if (g_strcmp0 (ver.versions[i].description.string, - "Recovery Version") == 0) { - fu_device_set_version_bootloader (dev, ver.versions[i].version.string); + if (g_strcmp0 (ver.versions[i].description.string, "Recovery Build Num") == 0) { + g_string_append_printf (version_bl, ".%s", + ver.versions[i].version.string); continue; } } + if (version_fw->len > 0) + fu_device_set_version (dev, version_fw->str); + if (version_bl->len > 0) + fu_device_set_version_bootloader (dev, version_bl->str); + return g_steal_pointer (&dev); } +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + gboolean fu_plugin_coldplug (FuPlugin *plugin, GError **error) { diff -Nru fwupd-1.1.4/plugins/amt/meson.build fwupd-1.2.5/plugins/amt/meson.build --- fwupd-1.1.4/plugins/amt/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/amt/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -1,6 +1,7 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginAmt"'] shared_module('fu_plugin_amt', + fu_hash, sources : [ 'fu-plugin-amt.c', ], @@ -11,9 +12,11 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, - uuid, ], ) diff -Nru fwupd-1.1.4/plugins/amt/README.md fwupd-1.2.5/plugins/amt/README.md --- fwupd-1.1.4/plugins/amt/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/amt/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -15,3 +15,8 @@ That tool in turn is heavily based on mei-amt-version from samples/mei in the Linux source tree and copyright Intel Corporation. + +GUID Generation +--------------- + +These devices use the existing GUID provided by the AMT host interface. diff -Nru fwupd-1.1.4/plugins/ata/ata.quirk fwupd-1.2.5/plugins/ata/ata.quirk --- fwupd-1.1.4/plugins/ata/ata.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/ata/ata.quirk 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1 @@ + diff -Nru fwupd-1.1.4/plugins/ata/fu-ata-device.c fwupd-1.2.5/plugins/ata/fu-ata-device.c --- fwupd-1.1.4/plugins/ata/fu-ata-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/ata/fu-ata-device.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,677 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "fu-ata-device.h" +#include "fu-chunk.h" + +#define FU_ATA_IDENTIFY_SIZE 512 /* bytes */ +#define FU_ATA_BLOCK_SIZE 512 /* bytes */ + +struct ata_tf { + guint8 dev; + guint8 command; + guint8 error; + guint8 status; + guint8 feat; + guint8 nsect; + guint8 lbal; + guint8 lbam; + guint8 lbah; +}; + +#define ATA_USING_LBA (1 << 6) +#define ATA_STAT_DRQ (1 << 3) +#define ATA_STAT_ERR (1 << 0) + +#define ATA_OP_IDENTIFY 0xec +#define ATA_OP_DOWNLOAD_MICROCODE 0x92 + +#define ATA_SUBCMD_MICROCODE_OBSOLETE 0x01 +#define ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNKS_ACTIVATE 0x03 +#define ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNK 0x07 +#define ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNKS 0x0e +#define ATA_SUBCMD_MICROCODE_ACTIVATE 0x0f + +#define SG_CHECK_CONDITION 0x02 +#define SG_DRIVER_SENSE 0x08 + +#define SG_ATA_12 0xa1 +#define SG_ATA_12_LEN 12 + +#define SG_ATA_PROTO_NON_DATA (3 << 1) +#define SG_ATA_PROTO_PIO_IN (4 << 1) +#define SG_ATA_PROTO_PIO_OUT (5 << 1) + +enum { + SG_CDB2_TLEN_NODATA = 0 << 0, + SG_CDB2_TLEN_FEAT = 1 << 0, + SG_CDB2_TLEN_NSECT = 2 << 0, + + SG_CDB2_TLEN_BYTES = 0 << 2, + SG_CDB2_TLEN_SECTORS = 1 << 2, + + SG_CDB2_TDIR_TO_DEV = 0 << 3, + SG_CDB2_TDIR_FROM_DEV = 1 << 3, + + SG_CDB2_CHECK_COND = 1 << 5, +}; + +struct _FuAtaDevice { + FuUdevDevice parent_instance; + guint pci_depth; + guint usb_depth; + gint fd; + guint16 transfer_blocks; + guint8 transfer_mode; +}; + +G_DEFINE_TYPE (FuAtaDevice, fu_ata_device, FU_TYPE_UDEV_DEVICE) + +#ifndef HAVE_GUDEV_232 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref) +#pragma clang diagnostic pop +#endif + +guint8 +fu_ata_device_get_transfer_mode (FuAtaDevice *self) +{ + return self->transfer_mode; +} + +guint16 +fu_ata_device_get_transfer_blocks (FuAtaDevice *self) +{ + return self->transfer_blocks; +} + +static gchar * +fu_ata_device_get_string (const guint16 *buf, guint start, guint end) +{ + g_autoptr(GString) str = g_string_new (NULL); + for (guint i = start; i <= end; i++) { + g_string_append_c (str, (gchar) (buf[i] >> 8)); + g_string_append_c (str, (gchar) (buf[i] & 0xff)); + } + + /* remove whitespace before returning */ + if (str->len > 0) { + g_strstrip (str->str); + if (str->str[0] == '\0') + return NULL; + } + return g_string_free (g_steal_pointer (&str), FALSE); +} + +static void +fu_ata_device_to_string (FuDevice *device, GString *str) +{ + FuAtaDevice *self = FU_ATA_DEVICE (device); + g_string_append (str, " FuAtaDevice:\n"); + g_string_append_printf (str, " fd:\t\t\t%i\n", self->fd); + g_string_append_printf (str, " transfer-mode:\t0x%x\n", (guint) self->transfer_mode); + g_string_append_printf (str, " transfer-size:\t0x%x\n", (guint) self->transfer_blocks); + g_string_append_printf (str, " pci-depth:\t\t%u\n", self->pci_depth); + g_string_append_printf (str, " usb-depth:\t\t%u\n", self->usb_depth); +} + +/* https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-ide-devices */ +static gchar * +fu_ata_device_pad_string_for_id (const gchar *name) +{ + GString *str = g_string_new (name); + fu_common_string_replace (str, " ", "_"); + for (guint i = str->len; i < 40; i++) + g_string_append_c (str, '_'); + return g_string_free (str, FALSE); +} + +static gchar * +fu_ata_device_get_guid_safe (const guint16 *buf, guint16 addr_start) +{ + if (!fu_common_guid_is_plausible ((guint8 *) (buf + addr_start))) + return NULL; + return fwupd_guid_to_string ((const fwupd_guid_t *) (buf + addr_start), + FWUPD_GUID_FLAG_MIXED_ENDIAN); +} + +static void +fu_ata_device_parse_id_maybe_dell (FuAtaDevice *self, const guint16 *buf) +{ + g_autofree gchar *component_id = NULL; + g_autofree gchar *guid_efi = NULL; + g_autofree gchar *guid_id = NULL; + g_autofree gchar *guid = NULL; + + /* add extra component ID if set */ + component_id = fu_ata_device_get_string (buf, 137, 140); + if (component_id == NULL || + !g_str_is_ascii (component_id) || + strlen (component_id) < 6) { + g_debug ("invalid component ID, skipping"); + return; + } + + /* do not add the FuUdevDevice instance IDs as generic firmware + * should not be used on these OEM-specific devices */ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS); + + /* add instance ID *and* GUID as using no-auto-instance-ids */ + guid_id = g_strdup_printf ("STORAGE-DELL-%s", component_id); + fu_device_add_instance_id (FU_DEVICE (self), guid_id); + guid = fwupd_guid_hash_string (guid_id); + fu_device_add_guid (FU_DEVICE (self), guid); + + /* also add the EFI GUID */ + guid_efi = fu_ata_device_get_guid_safe (buf, 129); + if (guid_efi != NULL) + fu_device_add_guid (FU_DEVICE (self), guid_efi); +} + +static gboolean +fu_ata_device_parse_id (FuAtaDevice *self, const guint8 *buf, gsize sz, GError **error) +{ + FuDevice *device = FU_DEVICE (self); + guint16 xfer_min = 1; + guint16 xfer_max = 0xffff; + guint16 id[FU_ATA_IDENTIFY_SIZE/2]; + g_autofree gchar *name_pad = NULL; + g_autofree gchar *sku = NULL; + + /* check size */ + if (sz != FU_ATA_IDENTIFY_SIZE) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "ID incorrect size, got 0x%02x", + (guint) sz); + return FALSE; + } + + /* read LE buffer */ + for (guint i = 0; i < sz / 2; i++) + id[i] = fu_common_read_uint16 (buf + (i * 2), G_LITTLE_ENDIAN); + + /* verify drive correctly supports DOWNLOAD_MICROCODE */ + if (!(id[83] & 1 && id[86] & 1)) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "DOWNLOAD_MICROCODE not supported by device"); + return FALSE; + } + + fu_ata_device_parse_id_maybe_dell (self, id); + + /* firmware will be applied when the device restarts */ + if (self->transfer_mode == ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNKS) + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_REBOOT); + + /* the newer, segmented transfer mode */ + if (self->transfer_mode == ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNKS_ACTIVATE || + self->transfer_mode == ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNKS) { + xfer_min = id[234]; + if (xfer_min == 0x0 || xfer_min == 0xffff) + xfer_min = 1; + xfer_max = id[235]; + if (xfer_max == 0x0 || xfer_max == 0xffff) + xfer_max = xfer_min; + } + + /* fall back to a sane block size */ + if (self->transfer_blocks == 0x0) + self->transfer_blocks = xfer_min; + else if (self->transfer_blocks == 0xffff) + self->transfer_blocks = xfer_max; + + /* get values in case the kernel didn't */ + if (fu_device_get_serial (device) == NULL) { + g_autofree gchar *tmp = NULL; + tmp = fu_ata_device_get_string (id, 10, 19); + fu_device_set_serial (device, tmp); + } + if (fu_device_get_name (device) == NULL) { + g_autofree gchar *tmp = NULL; + tmp = fu_ata_device_get_string (id, 27, 46); + fu_device_set_name (device, tmp); + } + if (fu_device_get_version (device) == NULL) { + g_autofree gchar *tmp = NULL; + tmp = fu_ata_device_get_string (id, 23, 26); + fu_device_set_version (device, tmp); + } + + /* 8 byte additional product identifier == SKU? */ + sku = fu_ata_device_get_string (id, 170, 173); + if (sku != NULL) + g_debug ("SKU=%s", sku); + + /* if we have vendor defined identify blocks don't add generic GUID */ + if (fu_device_get_guids (device)->len != 0) + return TRUE; + + /* add extra GUIDs if none detected from identify block */ + name_pad = fu_ata_device_pad_string_for_id (fu_device_get_name (device)); + if (name_pad != NULL && + fu_device_get_version (device) != NULL) { + g_autofree gchar *tmp = NULL; + tmp = g_strdup_printf ("IDE\\%s%s", name_pad, + fu_device_get_version (device)); + fu_device_add_instance_id (device, tmp); + } + if (name_pad != NULL) { + g_autofree gchar *tmp = NULL; + tmp = g_strdup_printf ("IDE\\0%s", name_pad); + fu_device_add_instance_id (device, tmp); + } + + /* add the name fallback */ + fu_device_add_instance_id (device, fu_device_get_name (device)); + + return TRUE; +} + +static gboolean +fu_ata_device_open (FuDevice *device, GError **error) +{ + FuAtaDevice *self = FU_ATA_DEVICE (device); + GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (device)); + + /* open device */ + self->fd = g_open (g_udev_device_get_device_file (udev_device), O_RDONLY); + if (self->fd < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to open %s: %s", + g_udev_device_get_device_file (udev_device), + strerror (errno)); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_ata_device_probe (FuUdevDevice *device, GError **error) +{ + FuAtaDevice *self = FU_ATA_DEVICE (device); + + /* set the physical ID */ + if (!fu_udev_device_set_physical_id (device, "scsi", error)) + return FALSE; + + /* look at the PCI and USB depth to work out if in an external enclosure */ + self->pci_depth = fu_udev_device_get_slot_depth (device, "pci"); + self->usb_depth = fu_udev_device_get_slot_depth (device, "usb"); + if (self->pci_depth <= 2 && self->usb_depth <= 2) + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); + + return TRUE; +} + +static guint64 +fu_ata_device_tf_to_pack_id (struct ata_tf *tf) +{ + guint32 lba24 = (tf->lbah << 16) | (tf->lbam << 8) | (tf->lbal); + guint32 lbah = tf->dev & 0x0f; + return (((guint64) lbah) << 24) | (guint64) lba24; +} + +static gboolean +fu_ata_device_command (FuAtaDevice *self, struct ata_tf *tf, + gint dxfer_direction, guint timeout_ms, + guint8 *dxferp, gsize dxfer_len, GError **error) +{ + guint8 cdb[SG_ATA_12_LEN] = { 0x0 }; + guint8 sb[32] = { 0x0 }; + sg_io_hdr_t io_hdr = { 0x0 }; + + /* map _TO_DEV to PIO mode */ + if (dxfer_direction == SG_DXFER_TO_DEV) + cdb[1] = SG_ATA_PROTO_PIO_OUT; + else if (dxfer_direction == SG_DXFER_FROM_DEV) + cdb[1] = SG_ATA_PROTO_PIO_IN; + else + cdb[1] = SG_ATA_PROTO_NON_DATA; + + /* libata workaround: don't demand sense data for IDENTIFY */ + if (dxfer_len > 0) { + cdb[2] |= SG_CDB2_TLEN_NSECT | SG_CDB2_TLEN_SECTORS; + cdb[2] |= dxfer_direction == SG_DXFER_TO_DEV ? SG_CDB2_TDIR_TO_DEV : SG_CDB2_TDIR_FROM_DEV; + } else { + cdb[2] = SG_CDB2_CHECK_COND; + } + + /* populate non-LBA48 CDB */ + cdb[0] = SG_ATA_12; + cdb[3] = tf->feat; + cdb[4] = tf->nsect; + cdb[5] = tf->lbal; + cdb[6] = tf->lbam; + cdb[7] = tf->lbah; + cdb[8] = tf->dev; + cdb[9] = tf->command; + fu_common_dump_raw (G_LOG_DOMAIN, "CBD", cdb, sizeof(cdb)); + if (dxfer_direction == SG_DXFER_TO_DEV && dxferp != NULL) { + fu_common_dump_raw (G_LOG_DOMAIN, "outgoing_data", + dxferp, dxfer_len); + } + + /* hit hardware */ + io_hdr.interface_id = 'S'; + io_hdr.mx_sb_len = sizeof(sb); + io_hdr.dxfer_direction = dxfer_direction; + io_hdr.dxfer_len = dxfer_len; + io_hdr.dxferp = dxferp; + io_hdr.cmdp = cdb; + io_hdr.cmd_len = SG_ATA_12_LEN; + io_hdr.sbp = sb; + io_hdr.pack_id = fu_ata_device_tf_to_pack_id (tf); + io_hdr.timeout = timeout_ms; + if (ioctl (self->fd, SG_IO, &io_hdr) == -1) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "SG_IO not supported: %s", + strerror (errno)); + return FALSE; + } + g_debug ("ATA_%u status=0x%x, host_status=0x%x, driver_status=0x%x", + io_hdr.cmd_len, io_hdr.status, io_hdr.host_status, io_hdr.driver_status); + fu_common_dump_raw (G_LOG_DOMAIN, "SB", sb, sizeof(sb)); + + /* error check */ + if (io_hdr.status && io_hdr.status != SG_CHECK_CONDITION) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "bad status: 0x%x", io_hdr.status); + return FALSE; + } + if (io_hdr.host_status) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "bad host status: 0x%x", io_hdr.host_status); + return FALSE; + } + if (io_hdr.driver_status && (io_hdr.driver_status != SG_DRIVER_SENSE)) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "bad driver status: 0x%x", io_hdr.driver_status); + return FALSE; + } + + /* repopulate ata_tf */ + tf->error = sb[8 + 3]; + tf->nsect = sb[8 + 5]; + tf->lbal = sb[8 + 7]; + tf->lbam = sb[8 + 9]; + tf->lbah = sb[8 + 11]; + tf->dev = sb[8 + 12]; + tf->status = sb[8 + 13]; + g_debug ("ATA_%u stat=%02x err=%02x nsect=%02x lbal=%02x lbam=%02x lbah=%02x dev=%02x", + io_hdr.cmd_len, tf->status, tf->error, tf->nsect, tf->lbal, tf->lbam, tf->lbah, tf->dev); + + /* io error */ + if (tf->status & (ATA_STAT_ERR | ATA_STAT_DRQ)) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "I/O error, ata_op=0x%02x ata_status=0x%02x ata_error=0x%02x", + tf->command, tf->status, tf->error); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_ata_device_setup (FuDevice *device, GError **error) +{ + FuAtaDevice *self = FU_ATA_DEVICE (device); + struct ata_tf tf = { 0x0 }; + guint8 id[FU_ATA_IDENTIFY_SIZE]; + + /* get ID block */ + tf.dev = ATA_USING_LBA; + tf.command = ATA_OP_IDENTIFY; + tf.nsect = 1; /* 512 bytes */ + if (!fu_ata_device_command (self, &tf, SG_DXFER_FROM_DEV, 1000, + id, sizeof(id), error)) { + g_prefix_error (error, "failed to IDENTIFY"); + return FALSE; + } + if (!fu_ata_device_parse_id (self, id, sizeof(id), error)) + return FALSE; + + /* success */ + return TRUE; +} + +static gboolean +fu_ata_device_close (FuDevice *device, GError **error) +{ + FuAtaDevice *self = FU_ATA_DEVICE (device); + if (!g_close (self->fd, error)) + return FALSE; + self->fd = 0; + return TRUE; +} + +static gboolean +fu_ata_device_fw_download (FuAtaDevice *self, + guint32 idx, + guint32 addr, + const guint8 *data, + guint32 data_sz, + GError **error) +{ + struct ata_tf tf = { 0x0 }; + guint32 block_count = data_sz / FU_ATA_BLOCK_SIZE; + guint32 buffer_offset = addr / FU_ATA_BLOCK_SIZE; + + /* write block */ + tf.dev = 0xa0 | ATA_USING_LBA; + tf.command = ATA_OP_DOWNLOAD_MICROCODE; + tf.feat = self->transfer_mode; + tf.nsect = block_count & 0xff; + tf.lbal = block_count >> 8; + tf.lbam = buffer_offset & 0xff; + tf.lbah = buffer_offset >> 8; + if (!fu_ata_device_command (self, &tf, SG_DXFER_TO_DEV, + 120 * 1000, /* a long time! */ + (guint8 *) data, data_sz, error)) { + g_prefix_error (error, "failed to write firmware @0x%0x", + (guint) addr); + return FALSE; + } + + /* check drive status */ + if (tf.nsect == 0x0) + return TRUE; + + /* drive wants more data, or thinks it is all done */ + if (tf.nsect == 0x1 || tf.nsect == 0x2) + return TRUE; + + /* the offset was set up incorrectly */ + if (tf.nsect == 0x4) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "alignment error"); + return FALSE; + } + + /* other error */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "unknown return code 0x%02x", + tf.nsect); + return FALSE; +} + +static gboolean +fu_ata_device_write_firmware (FuDevice *device, GBytes *fw, GError **error) +{ + FuAtaDevice *self = FU_ATA_DEVICE (device); + guint32 chunksz = (guint32) self->transfer_blocks * FU_ATA_BLOCK_SIZE; + guint max_size = 0xffff * FU_ATA_BLOCK_SIZE; + g_autoptr(GPtrArray) chunks = NULL; + + /* only one block allowed */ + if (self->transfer_mode == ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNK) + max_size = 0xffff; + + /* check is valid */ + if (g_bytes_get_size (fw) > max_size) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "firmware is too large, maximum size is %u", + max_size); + return FALSE; + } + if (g_bytes_get_size (fw) % FU_ATA_BLOCK_SIZE != 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "firmware is not multiple of block size %i", + FU_ATA_BLOCK_SIZE); + return FALSE; + } + + /* write each block */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + chunks = fu_chunk_array_new_from_bytes (fw, 0x00, 0x00, chunksz); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + if (!fu_ata_device_fw_download (self, + chk->idx, + chk->address, + chk->data, + chk->data_sz, + error)) { + g_prefix_error (error, "failed to write chunk %u: ", i); + return FALSE; + } + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len + 1); + } + + /* success! */ + fu_device_set_progress (device, 100); + return TRUE; +} + +static gboolean +fu_ata_device_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuAtaDevice *self = FU_ATA_DEVICE (device); + if (g_strcmp0 (key, "AtaTransferMode") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp != ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNKS_ACTIVATE && + tmp != ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNKS && + tmp != ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNK) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "AtaTransferMode only supports " + "values 0x3, 0x7 or 0xe"); + return FALSE; + } + self->transfer_mode = (guint8) tmp; + return TRUE; + } + if (g_strcmp0 (key, "AtaTransferBlocks") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp > 0xffff) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "AtaTransferBlocks only supports " + "values <= 0xffff"); + return FALSE; + } + self->transfer_blocks = (guint16) tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + +static void +fu_ata_device_init (FuAtaDevice *self) +{ + /* we chose this default as _DOWNLOAD_CHUNKS_ACTIVATE applies the + * firmware straight away and the kernel might not like the unexpected + * ATA restart and panic */ + self->transfer_mode = ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNKS; + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_REQUIRE_AC); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_summary (FU_DEVICE (self), "ATA Drive"); + fu_device_add_icon (FU_DEVICE (self), "drive-harddisk"); +} + +static void +fu_ata_device_finalize (GObject *object) +{ + G_OBJECT_CLASS (fu_ata_device_parent_class)->finalize (object); +} + +static void +fu_ata_device_class_init (FuAtaDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass); + object_class->finalize = fu_ata_device_finalize; + klass_device->to_string = fu_ata_device_to_string; + klass_device->set_quirk_kv = fu_ata_device_set_quirk_kv; + klass_device->open = fu_ata_device_open; + klass_device->setup = fu_ata_device_setup; + klass_device->close = fu_ata_device_close; + klass_device->write_firmware = fu_ata_device_write_firmware; + klass_udev_device->probe = fu_ata_device_probe; +} + +FuAtaDevice * +fu_ata_device_new (FuUdevDevice *device) +{ + FuAtaDevice *self = g_object_new (FU_TYPE_ATA_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return self; +} + +FuAtaDevice * +fu_ata_device_new_from_blob (const guint8 *buf, gsize sz, GError **error) +{ + g_autoptr(FuAtaDevice) self = g_object_new (FU_TYPE_ATA_DEVICE, NULL); + if (!fu_ata_device_parse_id (self, buf, sz, error)) + return NULL; + return g_steal_pointer (&self); +} diff -Nru fwupd-1.1.4/plugins/ata/fu-ata-device.h fwupd-1.2.5/plugins/ata/fu-ata-device.h --- fwupd-1.1.4/plugins/ata/fu-ata-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/ata/fu-ata-device.h 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +G_BEGIN_DECLS + +#define FU_TYPE_ATA_DEVICE (fu_ata_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuAtaDevice, fu_ata_device, FU, ATA_DEVICE, FuUdevDevice) + +FuAtaDevice *fu_ata_device_new (FuUdevDevice *device); +FuAtaDevice *fu_ata_device_new_from_blob (const guint8 *buf, + gsize sz, + GError **error); + +/* for self tests */ +guint8 fu_ata_device_get_transfer_mode (FuAtaDevice *self); +guint16 fu_ata_device_get_transfer_blocks (FuAtaDevice *self); + +G_END_DECLS diff -Nru fwupd-1.1.4/plugins/ata/fu-plugin-ata.c fwupd-1.2.5/plugins/ata/fu-plugin-ata.c --- fwupd-1.1.4/plugins/ata/fu-plugin-ata.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/ata/fu-plugin-ata.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + +#include "fu-ata-device.h" + +gboolean +fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **error) +{ + GUdevDevice *udev_device = fu_udev_device_get_dev (device); + g_autoptr(FuAtaDevice) dev = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + + /* interesting device? */ + if (udev_device == NULL) + return TRUE; + if (g_strcmp0 (g_udev_device_get_subsystem (udev_device), "block") != 0) + return TRUE; + if (g_strcmp0 (g_udev_device_get_devtype (udev_device), "disk") != 0) + return TRUE; + if (!g_udev_device_get_property_as_boolean (udev_device, "ID_ATA_SATA")) + return TRUE; + if (!g_udev_device_get_property_as_boolean (udev_device, "ID_ATA_DOWNLOAD_MICROCODE")) + return TRUE; + + dev = fu_ata_device_new (device); + locker = fu_device_locker_new (dev, error); + if (locker == NULL) + return FALSE; + fu_plugin_device_add (plugin, FU_DEVICE (dev)); + return TRUE; +} + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_udev_subsystem (plugin, "block"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.t13.ata"); +} + +gboolean +fu_plugin_update (FuPlugin *plugin, + FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_write_firmware (device, blob_fw, error); +} diff -Nru fwupd-1.1.4/plugins/ata/fu-self-test.c fwupd-1.2.5/plugins/ata/fu-self-test.c --- fwupd-1.1.4/plugins/ata/fu-self-test.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/ata/fu-self-test.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-ata-device.h" +#include "fu-test.h" + +static void +fu_ata_id_func (void) +{ + gboolean ret; + gsize sz; + g_autofree gchar *data = NULL; + g_autofree gchar *path = NULL; + g_autoptr(FuAtaDevice) dev = NULL; + g_autoptr(GError) error = NULL; + + path = fu_test_get_filename (TESTDATADIR, "StarDrive-SBFM61.2.bin"); + g_assert_nonnull (path); + ret = g_file_get_contents (path, &data, &sz, &error); + g_assert_no_error (error); + g_assert (ret); + dev = fu_ata_device_new_from_blob ((guint8 *)data, sz, &error); + g_assert_no_error (error); + g_assert_nonnull (dev); + g_assert_cmpint (fu_ata_device_get_transfer_mode (dev), ==, 0xe); + g_assert_cmpint (fu_ata_device_get_transfer_blocks (dev), ==, 0x1); + g_assert_cmpstr (fu_device_get_serial (FU_DEVICE (dev)), ==, "A45A078A198600476509"); + g_assert_cmpstr (fu_device_get_name (FU_DEVICE (dev)), ==, "SATA SSD"); + g_assert_cmpstr (fu_device_get_version (FU_DEVICE (dev)), ==, "SBFM61.2"); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + + /* tests go here */ + g_test_add_func ("/fwupd/id", fu_ata_id_func); + return g_test_run (); +} diff -Nru fwupd-1.1.4/plugins/ata/meson.build fwupd-1.2.5/plugins/ata/meson.build --- fwupd-1.1.4/plugins/ata/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/ata/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,59 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginAta"'] + +install_data([ + 'ata.quirk', + ], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_ata', + fu_hash, + sources : [ + 'fu-plugin-ata.c', + 'fu-ata-device.c', + ], + include_directories : [ + include_directories('../..'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + install : true, + install_dir: plugin_dir, + c_args : [ + cargs, + '-DLOCALSTATEDIR="' + localstatedir + '"', + ], + link_with : [ + libfwupdprivate, + ], + dependencies : [ + plugin_deps, + ], +) + +if get_option('tests') + testdatadir = join_paths(meson.current_source_dir(), 'tests') + cargs += '-DTESTDATADIR="' + testdatadir + '"' + e = executable( + 'ata-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-ata-device.c', + ], + include_directories : [ + include_directories('..'), + include_directories('../..'), + include_directories('../../libfwupd'), + include_directories('../../src'), + ], + dependencies : [ + plugin_deps, + ], + link_with : [ + libfwupdprivate, + ], + c_args : cargs + ) + test('ata-self-test', e) +endif diff -Nru fwupd-1.1.4/plugins/ata/README.md fwupd-1.2.5/plugins/ata/README.md --- fwupd-1.1.4/plugins/ata/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/ata/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,44 @@ +ATA +=== + +Introduction +------------ + +This plugin allows updating ATA/ATAPI storage hardware. Devices are enumerated +from the block devices and if ID_ATA_DOWNLOAD_MICROCODE is supported they can +be updated with appropriate firmware file. + +Updating ATA devices is more dangerous than other hardware such as DFU or NVMe +and should be tested carefully with the help of the drive vendor. + +The device GUID is read from the trimmed model string. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. + +This plugin supports the following protocol ID: + + * org.t13.ata + +GUID Generation +--------------- + +These device use the Microsoft DeviceInstanceId values, e.g. + + * `IDE\VENDOR[40]REVISION[8]` + * `IDE\0VENDOR[40]` + +See https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-ide-devices +for more details. + +Quirk use +--------- +This plugin uses the following plugin-specific quirks: + +| Quirk | Description | Minimum fwupd version | +|------------------------|-------------------------------------------|-----------------------| +| `AtaTransferBlocks` | Blocks to transfer, or `0xffff` for max | 1.2.4 | +| `AtaTransferMode` | The transfer mode, `0x3`, `0x7` or `0xe` | 1.2.4 | Binary files /tmp/tmpifvE7s/99aplePdGI/fwupd-1.1.4/plugins/ata/tests/StarDrive-SBFM61.2.bin and /tmp/tmpifvE7s/TdryFJEQYW/fwupd-1.2.5/plugins/ata/tests/StarDrive-SBFM61.2.bin differ diff -Nru fwupd-1.1.4/plugins/colorhug/colorhug.quirk fwupd-1.2.5/plugins/colorhug/colorhug.quirk --- fwupd-1.1.4/plugins/colorhug/colorhug.quirk 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/colorhug/colorhug.quirk 2019-02-25 09:42:18.000000000 +0000 @@ -6,6 +6,7 @@ FirmwareSizeMin = 0x2000 FirmwareSizeMax = 0x8000 CounterpartGuid = USB\VID_273F&PID_1001 +InstallDuration = 8 [DeviceInstanceId=USB\VID_273F&PID_1001] Plugin = colorhug @@ -14,6 +15,7 @@ Icon = colorimeter-colorhug Guid = 40338ceb-b966-4eae-adae-9c32edfcc484 CounterpartGuid = USB\VID_273F&PID_1000 +InstallDuration = 8 # ColorHug2 [DeviceInstanceId=USB\VID_273F&PID_1004] @@ -25,12 +27,14 @@ FirmwareSizeMin = 0x2000 FirmwareSizeMax = 0x8000 CounterpartGuid = USB\VID_273F&PID_1005 +InstallDuration = 8 [DeviceInstanceId=USB\VID_273F&PID_1005] Plugin = colorhug Flags = is-bootloader Guid = 2082b5e0-7a64-478a-b1b2-e3404fab6dad CounterpartGuid = USB\VID_273F&PID_1004 +InstallDuration = 8 # ColorHugALS [DeviceInstanceId=USB\VID_273F&PID_1007] @@ -41,9 +45,11 @@ FirmwareSizeMin = 0x1000 FirmwareSizeMax = 0x4000 CounterpartGuid = USB\VID_273F&PID_1006 +InstallDuration = 5 [DeviceInstanceId=USB\VID_273F&PID_1006] Plugin = colorhug Flags = halfsize,is-bootloader Guid = 84f40464-9272-4ef7-9399-cd95f12da696 CounterpartGuid = USB\VID_273F&PID_1007 +InstallDuration = 5 diff -Nru fwupd-1.1.4/plugins/colorhug/fu-colorhug-common.c fwupd-1.2.5/plugins/colorhug/fu-colorhug-common.c --- fwupd-1.1.4/plugins/colorhug/fu-colorhug-common.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/colorhug/fu-colorhug-common.c 2019-02-25 09:42:18.000000000 +0000 @@ -85,17 +85,3 @@ return "Self test failed: EEPROM"; return NULL; } - -void -ch_buffer_dump (const gchar *title, const guint8 *buf, gsize sz) -{ - if (g_getenv ("FWUPD_COLORHUG_VERBOSE") == NULL) - return; - g_print ("%s (%" G_GSIZE_FORMAT "):\n", title, sz); - for (gsize i = 0; i < sz; i++) { - g_print ("%02x ", buf[i]); - if (i > 0 && (i + 1) % 256 == 0) - g_print ("\n"); - } - g_print ("\n"); -} diff -Nru fwupd-1.1.4/plugins/colorhug/fu-colorhug-common.h fwupd-1.2.5/plugins/colorhug/fu-colorhug-common.h --- fwupd-1.1.4/plugins/colorhug/fu-colorhug-common.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/colorhug/fu-colorhug-common.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_COLORHUG_COMMON_H -#define __FU_COLORHUG_COMMON_H +#pragma once #include @@ -52,10 +51,5 @@ } ChError; const gchar *ch_strerror (ChError error_enum); -void ch_buffer_dump (const gchar *title, - const guint8 *buf, - gsize sz); G_END_DECLS - -#endif /* __FU_COLORHUG_COMMON_H */ diff -Nru fwupd-1.1.4/plugins/colorhug/fu-colorhug-device.c fwupd-1.2.5/plugins/colorhug/fu-colorhug-device.c --- fwupd-1.1.4/plugins/colorhug/fu-colorhug-device.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/colorhug/fu-colorhug-device.c 2019-02-25 09:42:18.000000000 +0000 @@ -82,7 +82,8 @@ memcpy (buf + 1, ibuf, ibufsz); /* request */ - ch_buffer_dump ("REQ", buf, ibufsz + 1); + if (g_getenv ("FWUPD_COLORHUG_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "REQ", buf, ibufsz + 1); if (!g_usb_device_interrupt_transfer (usb_device, CH_USB_HID_EP_OUT, buf, @@ -115,7 +116,8 @@ g_prefix_error (error, "failed to get reply: "); return FALSE; } - ch_buffer_dump ("RES", buf, actual_length); + if (g_getenv ("FWUPD_COLORHUG_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "RES", buf, actual_length); /* old bootloaders do not return the full block */ if (actual_length != CH_USB_HID_EP_SIZE && diff -Nru fwupd-1.1.4/plugins/colorhug/fu-colorhug-device.h fwupd-1.2.5/plugins/colorhug/fu-colorhug-device.h --- fwupd-1.1.4/plugins/colorhug/fu-colorhug-device.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/colorhug/fu-colorhug-device.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_COLORHUG_DEVICE_H -#define __FU_COLORHUG_DEVICE_H +#pragma once #include "fu-plugin.h" @@ -22,5 +21,3 @@ GError **error); G_END_DECLS - -#endif /* __FU_COLORHUG_DEVICE_H */ diff -Nru fwupd-1.1.4/plugins/colorhug/fu-plugin-colorhug.c fwupd-1.2.5/plugins/colorhug/fu-plugin-colorhug.c --- fwupd-1.1.4/plugins/colorhug/fu-plugin-colorhug.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/colorhug/fu-plugin-colorhug.c 2019-02-25 09:42:18.000000000 +0000 @@ -13,7 +13,9 @@ void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.hughski.colorhug"); } gboolean diff -Nru fwupd-1.1.4/plugins/colorhug/meson.build fwupd-1.2.5/plugins/colorhug/meson.build --- fwupd-1.1.4/plugins/colorhug/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/colorhug/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -7,6 +7,7 @@ ) shared_module('fu_plugin_colorhug', + fu_hash, sources : [ 'fu-colorhug-common.c', 'fu-colorhug-device.c', @@ -19,6 +20,9 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff -Nru fwupd-1.1.4/plugins/colorhug/README.md fwupd-1.2.5/plugins/colorhug/README.md --- fwupd-1.1.4/plugins/colorhug/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/colorhug/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -10,3 +10,22 @@ ColorHug versions 1 and 2 support a custom HID-based flashing protocol, but version 3 (ColorHug+) has now switched to DFU. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +a packed binary file format. + +This plugin supports the following protocol ID: + + * com.hughski.colorhug + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_273F&PID_1001&REV_0001` + * `USB\VID_273F&PID_1001` + * `USB\VID_273F` diff -Nru fwupd-1.1.4/plugins/csr/fu-csr-device.c fwupd-1.2.5/plugins/csr/fu-csr-device.c --- fwupd-1.1.4/plugins/csr/fu-csr-device.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/csr/fu-csr-device.c 2019-02-25 09:42:18.000000000 +0000 @@ -67,17 +67,6 @@ g_string_append_printf (str, " timeout:\t\t%" G_GUINT32_FORMAT "\n", self->dnload_timeout); } -static void -fu_csr_device_dump (const gchar *title, const guint8 *buf, gsize sz) -{ - if (g_getenv ("FWUPD_CSR_VERBOSE") == NULL) - return; - g_print ("%s (%" G_GSIZE_FORMAT "):\n", title, sz); - for (gsize i = 0; i < sz; i++) - g_print ("%02x ", buf[i]); - g_print ("\n"); -} - static gboolean fu_csr_device_attach (FuDevice *device, GError **error) { @@ -86,7 +75,8 @@ gsize sz = 0; guint8 buf[] = { FU_CSR_REPORT_ID_CONTROL, FU_CSR_CONTROL_RESET }; - fu_csr_device_dump ("Reset", buf, sz); + if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "Reset", buf, sz); if (!g_usb_device_control_transfer (usb_device, G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, G_USB_DEVICE_REQUEST_TYPE_CLASS, @@ -135,7 +125,8 @@ g_prefix_error (error, "Failed to GetStatus: "); return FALSE; } - fu_csr_device_dump ("GetStatus", buf, sz); + if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "GetStatus", buf, sz); /* check packet */ if (sz != FU_CSR_STATUS_HEADER_SIZE) { @@ -179,7 +170,8 @@ return TRUE; /* hit hardware */ - fu_csr_device_dump ("ClearStatus", buf, sz); + if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "ClearStatus", buf, sz); if (!g_usb_device_control_transfer (usb_device, G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, G_USB_DEVICE_REQUEST_TYPE_CLASS, @@ -230,7 +222,8 @@ g_prefix_error (error, "Failed to ReadFirmware: "); return NULL; } - fu_csr_device_dump ("ReadFirmware", buf, sz); + if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "ReadFirmware", buf, sz); /* too small to parse */ if (sz < FU_CSR_COMMAND_HEADER_SIZE) { @@ -362,7 +355,8 @@ memcpy (buf + FU_CSR_COMMAND_HEADER_SIZE, chunk_data, chunk_sz); /* hit hardware */ - fu_csr_device_dump ("Upgrade", buf, sizeof(buf)); + if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "Upgrade", buf, sizeof(buf)); if (!g_usb_device_control_transfer (usb_device, G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, G_USB_DEVICE_REQUEST_TYPE_CLASS, diff -Nru fwupd-1.1.4/plugins/csr/fu-csr-device.h fwupd-1.2.5/plugins/csr/fu-csr-device.h --- fwupd-1.1.4/plugins/csr/fu-csr-device.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/csr/fu-csr-device.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_CSR_DEVICE_H -#define __FU_CSR_DEVICE_H +#pragma once #include "fu-plugin.h" @@ -17,5 +16,3 @@ FuCsrDevice *fu_csr_device_new (FuUsbDevice *device); G_END_DECLS - -#endif /* __FU_CSR_DEVICE_H */ diff -Nru fwupd-1.1.4/plugins/csr/fu-plugin-csr.c fwupd-1.2.5/plugins/csr/fu-plugin-csr.c --- fwupd-1.1.4/plugins/csr/fu-plugin-csr.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/csr/fu-plugin-csr.c 2019-02-25 09:42:18.000000000 +0000 @@ -13,7 +13,9 @@ void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.qualcomm.dfu"); } gboolean diff -Nru fwupd-1.1.4/plugins/csr/meson.build fwupd-1.2.5/plugins/csr/meson.build --- fwupd-1.1.4/plugins/csr/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/csr/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -5,6 +5,7 @@ ) shared_module('fu_plugin_csr', + fu_hash, sources : [ 'fu-csr-device.c', 'fu-plugin-csr.c', @@ -22,6 +23,7 @@ plugin_deps, ], link_with : [ + libfwupdprivate, dfu, ], ) diff -Nru fwupd-1.1.4/plugins/csr/README.md fwupd-1.2.5/plugins/csr/README.md --- fwupd-1.1.4/plugins/csr/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/csr/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,36 @@ +CSR Support +=========== + +Introduction +------------ + +CSR is often called “driverless DFU” and is used only by BlueCore chips from +Cambridge Silicon Radio (now owned by Qualcomm). The driverless just means that +it's DFU like, and is routed over HID. + +CSR is a ODM that makes most of the Bluetooth audio chips in vendor hardware. +The hardware vendor can enable or disable features on the CSR microcontroller +depending on licensing options (for instance echo cancellation), and there’s +even a little virtual machine to do simple vendor-specific things. + +All the CSR chips are updatable in-field, and most vendors issue updates to fix +sound quality issues or to add support for new protocols or devices. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +DFU file format. + +This plugin supports the following protocol ID: + + * com.qualcomm.dfu + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_0A12&PID_1337&REV_2520` + * `USB\VID_0A12&PID_1337` + * `USB\VID_0A12` diff -Nru fwupd-1.1.4/plugins/dell/dell.quirk fwupd-1.2.5/plugins/dell/dell.quirk --- fwupd-1.1.4/plugins/dell/dell.quirk 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell/dell.quirk 2019-02-25 09:42:18.000000000 +0000 @@ -38,10 +38,3 @@ [SmbiosManufacturer=Alienware] UefiVersionFormat = quad - -# DEPRECATED: put this in the AppStream metadata itself using -# -# quad -# -[DaemonVersionFormat=quad] -ComponentIDs = com.dell.uefi*.firmware diff -Nru fwupd-1.1.4/plugins/dell/fu-dell-smi.h fwupd-1.2.5/plugins/dell/fu-dell-smi.h --- fwupd-1.1.4/plugins/dell/fu-dell-smi.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell/fu-dell-smi.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_DELL_COMMON_H -#define __FU_DELL_COMMON_H +#pragma once #include "fu-device.h" #include @@ -126,5 +125,3 @@ /* VID/PID of ethernet controller on dock */ #define DOCK_NIC_VID 0x0bda #define DOCK_NIC_PID 0x8153 - -#endif /* __FU_DELL_COMMON_H */ diff -Nru fwupd-1.1.4/plugins/dell/fu-plugin-dell.c fwupd-1.2.5/plugins/dell/fu-plugin-dell.c --- fwupd-1.1.4/plugins/dell/fu-plugin-dell.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell/fu-plugin-dell.c 2019-02-25 09:42:18.000000000 +0000 @@ -13,6 +13,7 @@ #include #include +#include "fwupd-common.h" #include "fu-plugin-dell.h" #include "fu-plugin-vfuncs.h" #include "fu-device-metadata.h" @@ -44,6 +45,16 @@ const gchar * desc; } DOCK_DESCRIPTION; +struct da_structure { + guint8 type; + guint8 length; + guint16 handle; + guint16 cmd_address; + guint8 cmd_code; + guint32 supported_cmds; + guint8 *tokens; +} __attribute__((packed)); + /* These are for matching the components */ #define WD15_EC_STR "2 0 2 2 0" #define TB16_EC_STR "2 0 2 1 0" @@ -53,6 +64,8 @@ #define LEGACY_CBL_STR "2 2 2 1 0" #define UNIV_CBL_STR "2 2 2 2 0" #define TBT_CBL_STR "2 2 2 3 0" +#define FUTURE_EC_STR "3 0 2 4 0" +#define FUTURE_EC_STR2 "4 0 2 4 0" /* supported dock related GUIDs */ #define DOCK_FLASH_GUID "e7ca1f36-bf73-4574-afe6-a4ccacabf479" @@ -157,8 +170,10 @@ fu_dell_supported (FuPlugin *plugin) { GBytes *de_table = NULL; + GBytes *da_table = NULL; GBytes *enclosure = NULL; const guint8 *value; + const struct da_structure *da_values; gsize len; /* make sure that Dell SMBIOS methods are available */ @@ -170,6 +185,17 @@ return FALSE; if (*value != 0xDE) return FALSE; + da_table = fu_plugin_get_smbios_data (plugin, 0xDA); + if (da_table == NULL) + return FALSE; + da_values = (struct da_structure *) g_bytes_get_data (da_table, &len); + if (len == 0) + return FALSE; + if (!(da_values->supported_cmds & (1 << DACI_FLASH_INTERFACE_CLASS))) { + g_debug ("unable to access flash interface. supported commands: 0x%x", + da_values->supported_cmds); + return FALSE; + } /* only run on intended Dell hw types */ enclosure = fu_plugin_get_smbios_data (plugin, @@ -201,6 +227,8 @@ {TBT_CBL_GUID, TBT_CBL_STR, TBT_CBL_DESC}, {UNIV_CBL_GUID, UNIV_CBL_STR, UNIV_CBL_DESC}, {LEGACY_CBL_GUID, LEGACY_CBL_STR, LEGACY_CBL_DESC}, + {NULL, FUTURE_EC_STR, NULL}, + {NULL, FUTURE_EC_STR2, NULL}, }; for (guint i = 0; i < G_N_ELEMENTS (list); i++) { @@ -231,7 +259,7 @@ data->can_switch_modes = TRUE; } -static AsVersionParseFlag +static FuVersionFormat fu_plugin_dell_get_version_format (FuPlugin *plugin) { const gchar *content; @@ -240,17 +268,15 @@ content = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_MANUFACTURER); if (content == NULL) - return AS_VERSION_PARSE_FLAG_USE_TRIPLET; + return FU_VERSION_FORMAT_TRIPLET; /* any quirks match */ group = g_strdup_printf ("SmbiosManufacturer=%s", content); quirk = fu_plugin_lookup_quirk_by_id (plugin, group, FU_QUIRKS_UEFI_VERSION_FORMAT); - if (g_strcmp0 (quirk, "quad") == 0) - return AS_VERSION_PARSE_FLAG_NONE; - - /* fall back */ - return AS_VERSION_PARSE_FLAG_USE_TRIPLET; + if (quirk == NULL) + return FU_VERSION_FORMAT_TRIPLET; + return fu_common_version_format_from_string (quirk); } static gboolean @@ -318,7 +344,7 @@ GError **error) { FuPluginData *data = fu_plugin_get_data (plugin); - AsVersionParseFlag parse_flags; + FuVersionFormat version_format; guint16 pid; guint16 vid; const gchar *query_str; @@ -371,7 +397,7 @@ g_debug ("Dock cable type: %" G_GUINT32_FORMAT, dock_info->cable_type); g_debug ("Dock location: %d", dock_info->location); g_debug ("Dock component count: %d", dock_info->component_count); - parse_flags = fu_plugin_dell_get_version_format (plugin); + version_format = fu_plugin_dell_get_version_format (plugin); for (guint i = 0; i < dock_info->component_count; i++) { g_autofree gchar *fw_str = NULL; @@ -396,6 +422,10 @@ "invalid dock component request %s", query_str); return FALSE; } + if (component_guid == NULL || component_name == NULL) { + g_debug ("%s is supported by another plugin", query_str); + return TRUE; + } /* dock EC hasn't been updated for first time */ if (dock_info->flash_pkg_version == 0x00ffffff) { @@ -410,8 +440,8 @@ continue; } - fw_str = as_utils_version_from_uint32 (dock_info->components[i].fw_version, - parse_flags); + fw_str = fu_common_version_from_uint32 (dock_info->components[i].fw_version, + version_format); if (!fu_plugin_dock_node (plugin, platform, buf.record->dock_info_header.dock_type, @@ -426,8 +456,8 @@ /* if an old EC or invalid EC version found, create updatable parent */ if (old_ec) - flash_ver_str = as_utils_version_from_uint32 (dock_info->flash_pkg_version, - parse_flags); + flash_ver_str = fu_common_version_from_uint32 (dock_info->flash_pkg_version, + version_format); if (!fu_plugin_dock_node (plugin, platform, buf.record->dock_info_header.dock_type, @@ -597,17 +627,17 @@ } tpm_guid_raw = g_strdup_printf ("%04x-%s", system_id, tpm_mode); - tpm_guid = as_utils_guid_from_string (tpm_guid_raw); + tpm_guid = fwupd_guid_hash_string (tpm_guid_raw); tpm_id = g_strdup_printf ("DELL-%s" G_GUINT64_FORMAT, tpm_guid); tpm_guid_raw_alt = g_strdup_printf ("%04x-%s", system_id, tpm_mode_alt); - tpm_guid_alt = as_utils_guid_from_string (tpm_guid_raw_alt); + tpm_guid_alt = fwupd_guid_hash_string (tpm_guid_raw_alt); tpm_id_alt = g_strdup_printf ("DELL-%s" G_GUINT64_FORMAT, tpm_guid_alt); g_debug ("Creating primary TPM GUID %s and secondary TPM GUID %s", tpm_guid_raw, tpm_guid_raw_alt); - version_str = as_utils_version_from_uint32 (out->fw_version, - AS_VERSION_PARSE_FLAG_NONE); + version_str = fu_common_version_from_uint32 (out->fw_version, + FU_VERSION_FORMAT_QUAD); /* make it clear that the TPM is a discrete device of the product */ if (!data->smi_obj->fake_smbios) { @@ -699,7 +729,7 @@ device_id = g_strdup_printf ("TBT-%04x%04x", 0x00d4u, (unsigned) system_id); fu_device_set_vendor_id (device, vendor_id); - fu_device_add_guid (device, device_id); + fu_device_add_instance_id (device, device_id); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); } } @@ -787,6 +817,7 @@ FuPluginData *data = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); g_autofree gchar *tmp = NULL; + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); tmp = g_strdup_printf ("%d.%d", smbios_get_library_version_major(), smbios_get_library_version_minor()); diff -Nru fwupd-1.1.4/plugins/dell/fu-plugin-dell.h fwupd-1.2.5/plugins/dell/fu-plugin-dell.h --- fwupd-1.1.4/plugins/dell/fu-plugin-dell.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell/fu-plugin-dell.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_PLUGIN_DELL_H -#define __FU_PLUGIN_DELL_H +#pragma once #include "fu-plugin.h" #include "fu-dell-smi.h" @@ -40,5 +39,3 @@ #define TPM_TYPE_MASK 0x0F00 #define TPM_1_2_MODE 0x0001 #define TPM_2_0_MODE 0x0002 - -#endif /* __FU_PLUGIN_DELL_H */ diff -Nru fwupd-1.1.4/plugins/dell/fu-self-test.c fwupd-1.2.5/plugins/dell/fu-self-test.c --- fwupd-1.1.4/plugins/dell/fu-self-test.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell/fu-self-test.c 2019-02-25 09:42:18.000000000 +0000 @@ -69,7 +69,7 @@ struct tpm_status tpm_out; g_autoptr(FuPlugin) plugin_dell = NULL; g_autoptr(FuPlugin) plugin_uefi = NULL; - g_autoptr(GBytes) blob_fw = g_bytes_new_static ("fw", 2); + g_autoptr(GBytes) blob_fw = g_bytes_new_static ("fw", 30); g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = NULL; @@ -237,15 +237,18 @@ g_assert_false (fu_device_has_flag (device_v12, FWUPD_DEVICE_FLAG_UPDATABLE)); /* With one flash left we need an override */ - ret = fu_plugin_runner_update (plugin_uefi, device_v20, NULL, blob_fw, + ret = fu_plugin_runner_update (plugin_uefi, device_v20, blob_fw, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED); g_assert_false (ret); g_clear_error (&error); /* test override */ - ret = fu_plugin_runner_update (plugin_uefi, device_v20, NULL, blob_fw, + g_test_expect_message ("FuPluginUefi", G_LOG_LEVEL_WARNING, + "missing or invalid embedded capsule header"); + ret = fu_plugin_runner_update (plugin_uefi, device_v20, blob_fw, FWUPD_INSTALL_FLAG_FORCE, &error); + g_test_assert_expected_messages (); g_assert_no_error (error); g_assert (ret); } diff -Nru fwupd-1.1.4/plugins/dell/meson.build fwupd-1.2.5/plugins/dell/meson.build --- fwupd-1.1.4/plugins/dell/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -5,6 +5,7 @@ ) shared_module('fu_plugin_dell', + fu_hash, sources : [ 'fu-plugin-dell.c', 'fu-dell-smi.c', @@ -16,9 +17,12 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : [ - cargs, - ], + cargs, + ], dependencies : [ plugin_deps, efivar, @@ -33,6 +37,7 @@ cargs += '-DPLUGINBUILDDIR="' + meson.current_build_dir() + '"' e = executable( 'dell-self-test', + fu_hash, sources : [ 'fu-self-test.c', 'fu-dell-smi.c', @@ -51,7 +56,6 @@ valgrind, ], link_with : [ - fwupd, libfwupdprivate, ], c_args : [ diff -Nru fwupd-1.1.4/plugins/dell/README.md fwupd-1.2.5/plugins/dell/README.md --- fwupd-1.1.4/plugins/dell/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -6,6 +6,16 @@ This allows installing Dell capsules that are not part of the ESRT table. +GUID Generation +--------------- + +These devices uses custom GUIDs for Dell-specific hardware. + + * Thunderbolt devices: `TBT-0x00d4u$(system-id)` + * TPM devices `$(system-id)-$(mode)`, where `mode` is either `2.0` or `1.2` + +In both cases the `system-id` is derived from the SMBIOS Product SKU property. + Build Requirements ------------------ diff -Nru fwupd-1.1.4/plugins/dell/tests/efi/esrt/entries/entry2/capsule_flags fwupd-1.2.5/plugins/dell/tests/efi/esrt/entries/entry2/capsule_flags --- fwupd-1.1.4/plugins/dell/tests/efi/esrt/entries/entry2/capsule_flags 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/dell/tests/efi/esrt/entries/entry2/capsule_flags 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1 @@ +0x8010 diff -Nru fwupd-1.1.4/plugins/dell/tests/efi/esrt/entries/entry2/fw_class fwupd-1.2.5/plugins/dell/tests/efi/esrt/entries/entry2/fw_class --- fwupd-1.1.4/plugins/dell/tests/efi/esrt/entries/entry2/fw_class 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/dell/tests/efi/esrt/entries/entry2/fw_class 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1 @@ +00000000-0000-0000-0000-000000000000 diff -Nru fwupd-1.1.4/plugins/dell/tests/efi/esrt/entries/entry2/fw_type fwupd-1.2.5/plugins/dell/tests/efi/esrt/entries/entry2/fw_type --- fwupd-1.1.4/plugins/dell/tests/efi/esrt/entries/entry2/fw_type 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/dell/tests/efi/esrt/entries/entry2/fw_type 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1 @@ +2 diff -Nru fwupd-1.1.4/plugins/dell/tests/efi/esrt/entries/entry2/fw_version fwupd-1.2.5/plugins/dell/tests/efi/esrt/entries/entry2/fw_version --- fwupd-1.1.4/plugins/dell/tests/efi/esrt/entries/entry2/fw_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/dell/tests/efi/esrt/entries/entry2/fw_version 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1 @@ +3090287969 diff -Nru fwupd-1.1.4/plugins/dell/tests/efi/esrt/entries/entry2/last_attempt_status fwupd-1.2.5/plugins/dell/tests/efi/esrt/entries/entry2/last_attempt_status --- fwupd-1.1.4/plugins/dell/tests/efi/esrt/entries/entry2/last_attempt_status 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/dell/tests/efi/esrt/entries/entry2/last_attempt_status 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1 @@ +0 diff -Nru fwupd-1.1.4/plugins/dell/tests/efi/esrt/entries/entry2/last_attempt_version fwupd-1.2.5/plugins/dell/tests/efi/esrt/entries/entry2/last_attempt_version --- fwupd-1.1.4/plugins/dell/tests/efi/esrt/entries/entry2/last_attempt_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/dell/tests/efi/esrt/entries/entry2/last_attempt_version 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1 @@ +0 diff -Nru fwupd-1.1.4/plugins/dell/tests/efi/esrt/entries/entry2/lowest_supported_fw_version fwupd-1.2.5/plugins/dell/tests/efi/esrt/entries/entry2/lowest_supported_fw_version --- fwupd-1.1.4/plugins/dell/tests/efi/esrt/entries/entry2/lowest_supported_fw_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/dell/tests/efi/esrt/entries/entry2/lowest_supported_fw_version 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.1.4/plugins/dell/tests/tpm0/active fwupd-1.2.5/plugins/dell/tests/tpm0/active --- fwupd-1.1.4/plugins/dell/tests/tpm0/active 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/dell/tests/tpm0/active 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.1.4/plugins/dell/tests/tpm0/caps fwupd-1.2.5/plugins/dell/tests/tpm0/caps --- fwupd-1.1.4/plugins/dell/tests/tpm0/caps 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/dell/tests/tpm0/caps 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,3 @@ +Manufacturer: 0x49465800 +TCG version: 1.2 +Firmware version: 6.40 diff -Nru fwupd-1.1.4/plugins/dell/tests/tpm0/enabled fwupd-1.2.5/plugins/dell/tests/tpm0/enabled --- fwupd-1.1.4/plugins/dell/tests/tpm0/enabled 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/dell/tests/tpm0/enabled 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.1.4/plugins/dell/tests/tpm0/owned fwupd-1.2.5/plugins/dell/tests/tpm0/owned --- fwupd-1.1.4/plugins/dell/tests/tpm0/owned 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/dell/tests/tpm0/owned 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.1.4/plugins/dell/tests/tpm0/pcrs fwupd-1.2.5/plugins/dell/tests/tpm0/pcrs --- fwupd-1.1.4/plugins/dell/tests/tpm0/pcrs 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/dell/tests/tpm0/pcrs 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,24 @@ +PCR-00: 3C 97 99 20 C9 00 99 60 09 27 D5 DA B3 81 EB 95 1E 7F C8 68 +PCR-01: CE 9F A4 B2 01 09 D8 81 14 EA 1A 6D 13 94 CD 45 5F 52 69 23 +PCR-02: 47 09 7A 9A AD C3 26 A4 93 91 26 63 A1 6F DF 53 D7 88 96 8E +PCR-03: B2 A8 3B 0E BF 2F 83 74 29 9A 5B 2B DF C3 1E A9 55 AD 72 36 +PCR-04: A4 A5 87 4C 59 94 8D 9B 93 66 0A F4 19 D8 6F F8 94 36 20 CC +PCR-05: 00 0B 58 00 89 72 EF 6C 2A AC 79 33 C4 AE 67 6B A6 EF CF 6A +PCR-06: B2 A8 3B 0E BF 2F 83 74 29 9A 5B 2B DF C3 1E A9 55 AD 72 36 +PCR-07: 0A 2A 68 15 85 0D AC B2 D1 F4 E0 C1 F4 56 D5 E2 81 08 6D EA +PCR-08: DB A7 29 4E 49 BA D7 9E 53 99 0A 6E 3A CB 52 97 B9 08 3A 66 +PCR-09: 19 F9 6F 10 83 F5 5B 50 98 26 C3 14 73 43 35 21 1F E6 39 E9 +PCR-10: 37 3D 89 9E 10 0D DD 2D 21 B5 F4 96 8D 4F DC A7 6D 1A C7 BD +PCR-11: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-12: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-13: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-14: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-15: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-16: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-17: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-18: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-19: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-20: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-21: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-22: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-23: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 diff -Nru fwupd-1.1.4/plugins/dell-dock/dell-dock.quirk fwupd-1.2.5/plugins/dell-dock/dell-dock.quirk --- fwupd-1.1.4/plugins/dell-dock/dell-dock.quirk 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell-dock/dell-dock.quirk 2019-02-25 09:42:18.000000000 +0000 @@ -70,8 +70,8 @@ Flags = require-ac Children = FuDellDockStatus|USB\VID_413C&PID_B06E&hub&status,FuDellDockMst|MST-panamera-vmm5331-259 DellDockUnlockTarget = 1 -DellDockBoardMin = 2 -DellDockVersionLowest = 00.00.00.09 +DellDockBoardMin = 4 +DellDockVersionLowest = 00.00.00.17 DellDockBlobVersionOffset = 0x1AFC0 InstallDuration = 60 @@ -81,7 +81,6 @@ Summary = A representation of dock update status Plugin = dell_dock Vendor = Dell Inc -Flags = updatable FirmwareSizeMin = 24 FirmwareSizeMax = 24 InstallDuration = 5 @@ -114,14 +113,8 @@ FirmwareSizeMax=0x80000 Flags = require-ac InstallDuration = 22 - -# Thunderbolt controller (old ID) -# TODO: This should be dropped when DellDockBoardMin is 3+ -[Guid=TBT-00d40012] -Name = Thunderbolt controller in Dell dock -Summary = Thunderbolt controller -Vendor = Dell Inc -ParentGuid = USB\VID_413C&PID_B06E&hub&embedded -FirmwareSizeMin=0x40000 -FirmwareSizeMax=0x80000 -Flags = require-ac,ignore-validation +DellDockInstallDurationI2C = 181 +DellDockUnlockTarget = 10 +DellDockHubVersionLowest = 1.31 +DellDockBlobMajorOffset = 0x400a +DellDockBlobMinorOffset = 0x4009 diff -Nru fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-common.c fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-common.c --- fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-common.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-common.c 2019-02-25 09:42:18.000000000 +0000 @@ -47,10 +47,29 @@ void fu_dell_dock_will_replug (FuDevice *device) { + guint64 timeout = fu_device_get_install_duration (device); + g_return_if_fail (FU_IS_DEVICE (device)); - g_debug ("Activated %ds replug delay for %s", - REPLUG_TIMEOUT, fu_device_get_name (device)); - fu_device_set_remove_delay (device, REPLUG_TIMEOUT * 1000); + g_debug ("Activated %" G_GUINT64_FORMAT "s replug delay for %s", + timeout, fu_device_get_name (device)); + fu_device_set_remove_delay (device, timeout * 1000); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); } + +void +fu_dell_dock_clone_updatable (FuDevice *device) +{ + FuDevice *parent; + parent = fu_device_get_parent (device); + if (parent == NULL) + return; + if (fu_device_has_flag (parent, FWUPD_DEVICE_FLAG_UPDATABLE)) { + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + } else { + const gchar *message = fu_device_get_update_error (parent); + if (message != NULL) + fu_device_set_update_error (device, message); + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + } +} diff -Nru fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-common.h fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-common.h --- fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-common.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-common.h 2019-02-25 09:42:18.000000000 +0000 @@ -13,21 +13,20 @@ * SPDX-License-Identifier: LGPL-2.1+ OR MIT */ -#ifndef __FU_DELL_DOCK_COMMON_H -#define __FU_DELL_DOCK_COMMON_H +#pragma once #include "config.h" #include "fu-device.h" #include "fu-dell-dock-i2c-ec.h" #include "fu-dell-dock-i2c-mst.h" +#include "fu-dell-dock-i2c-tbt.h" #include "fu-dell-dock-hub.h" #include "fu-dell-dock-hid.h" #include "fu-dell-dock-status.h" -#define DELL_DOCK_EC_GUID "USB\\VID_413C&PID_B06E&hub&embedded" -#define DELL_DOCK_TBT_GUID "TBT-00d4b070" -#define REPLUG_TIMEOUT 60 /* s */ +#define DELL_DOCK_EC_INSTANCE_ID "USB\\VID_413C&PID_B06E&hub&embedded" +#define DELL_DOCK_TBT_INSTANCE_ID "TBT-00d4b070" gboolean fu_dell_dock_set_power (FuDevice *device, guint8 target, @@ -35,4 +34,4 @@ GError **error); void fu_dell_dock_will_replug (FuDevice *device); -#endif /* __FU_DELL_DOCK_COMMON_H */ +void fu_dell_dock_clone_updatable (FuDevice *device); diff -Nru fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-hid.c fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-hid.c --- fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-hid.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-hid.c 2019-02-25 09:42:18.000000000 +0000 @@ -17,6 +17,7 @@ #include "config.h" #include +#include #include "fu-usb-device.h" #include "fwupd-error.h" @@ -25,6 +26,7 @@ #define HIDI2C_MAX_REGISTER 4 #define HID_MAX_RETRIES 5 +#define TBT_MAX_RETRIES 2 #define HIDI2C_TRANSACTION_TIMEOUT 2000 #define HUB_CMD_READ_DATA 0xC0 @@ -36,6 +38,11 @@ #define HUB_EXT_I2C_READ 0xD6 #define HUB_EXT_VERIFYUPDATE 0xD9 #define HUB_EXT_ERASEBANK 0xE8 +#define HUB_EXT_WRITE_TBT_FLASH 0xFF + +#define TBT_COMMAND_WAKEUP 0x00000000 +#define TBT_COMMAND_AUTHENTICATE 0xFFFFFFFF +#define TBT_COMMAND_AUTHENTICATE_STATUS 0xFFFFFFFE typedef struct __attribute__ ((packed)) { guint8 cmd; @@ -55,6 +62,20 @@ guint8 data[192]; } FuHIDCmdBuffer; +typedef struct __attribute__ ((packed)) { + guint8 cmd; + guint8 ext; + guint8 i2cslaveaddr; + guint8 i2cspeed; + union { + guint32 startaddress; + guint32 tbt_command; + }; + guint8 bufferlen; + guint8 extended_cmdarea[55]; + guint8 data[192]; +} FuTbtCmdBuffer; + static gboolean fu_dell_dock_hid_set_report (FuDevice *self, guint8 *outbuffer, @@ -374,3 +395,142 @@ return TRUE; } + +gboolean +fu_dell_dock_hid_tbt_wake (FuDevice *self, + const FuHIDI2CParameters *parameters, + GError **error) +{ + FuTbtCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_READ_DATA, /* special write command that reads status result */ + .ext = HUB_EXT_WRITE_TBT_FLASH, + .i2cslaveaddr = parameters->i2cslaveaddr, + .i2cspeed = parameters->i2cspeed, /* unlike other commands doesn't need | 0x80 */ + .tbt_command = TBT_COMMAND_WAKEUP, + .bufferlen = 0, + .extended_cmdarea[0 ... 53] = 0, + .data[0 ... 191] = 0, + }; + + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, error)) { + g_prefix_error (error, "failed to set wake thunderbolt: "); + return FALSE; + } + if (!fu_dell_dock_hid_get_report (self, cmd_buffer.data, error)) { + g_prefix_error (error, "failed to get wake thunderbolt status: "); + return FALSE; + } + g_debug ("thunderbolt wake result: 0x%x", cmd_buffer.data[1]); + + return TRUE; +} + +static const gchar * +fu_dell_dock_hid_tbt_map_error (guint32 code) +{ + if (code == 1) + return g_strerror (EINVAL); + else if (code == 2) + return g_strerror (EPERM); + + return g_strerror (EIO); +} + +gboolean +fu_dell_dock_hid_tbt_write (FuDevice *self, + guint32 start_addr, + const guint8 *input, + gsize write_size, + const FuHIDI2CParameters *parameters, + GError **error) +{ + FuTbtCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_READ_DATA, /* It's a special write command that reads status result */ + .ext = HUB_EXT_WRITE_TBT_FLASH, + .i2cslaveaddr = parameters->i2cslaveaddr, + .i2cspeed = parameters->i2cspeed, /* unlike other commands doesn't need | 0x80 */ + .startaddress = GUINT32_TO_LE (start_addr), + .bufferlen = write_size, + .extended_cmdarea[0 ... 53] = 0, + }; + guint8 result; + + g_return_val_if_fail (input != NULL, FALSE); + g_return_val_if_fail (write_size <= HIDI2C_MAX_WRITE, FALSE); + + memcpy (cmd_buffer.data, input, write_size); + + for (gint i = 1; i <= TBT_MAX_RETRIES; i++) { + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, error)) { + g_prefix_error (error, "failed to run TBT update: "); + return FALSE; + } + if (!fu_dell_dock_hid_get_report (self, cmd_buffer.data, error)) { + g_prefix_error (error, "failed to get TBT flash status: "); + return FALSE; + } + result = cmd_buffer.data[1] & 0xf; + if (result == 0) + break; + g_debug ("attempt %d/%d: Thunderbolt write failed: %x", + i, TBT_MAX_RETRIES, result); + } + if (result != 0) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Writing address 0x%04x failed: %s", + start_addr, fu_dell_dock_hid_tbt_map_error (result)); + return FALSE; + } + + return TRUE; +} + +gboolean +fu_dell_dock_hid_tbt_authenticate (FuDevice *self, + const FuHIDI2CParameters *parameters, + GError **error) +{ + FuTbtCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_READ_DATA, /* It's a special write command that reads status result */ + .ext = HUB_EXT_WRITE_TBT_FLASH, + .i2cslaveaddr = parameters->i2cslaveaddr, + .i2cspeed = parameters->i2cspeed, /* unlike other commands doesn't need | 0x80 */ + .tbt_command = GUINT32_TO_LE (TBT_COMMAND_AUTHENTICATE), + .bufferlen = 0, + .extended_cmdarea[0 ... 53] = 0, + }; + guint8 result; + + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, error)) { + g_prefix_error (error, "failed to send authentication: "); + return FALSE; + } + + cmd_buffer.tbt_command = GUINT32_TO_LE (TBT_COMMAND_AUTHENTICATE_STATUS); + /* needs at least 2 seconds */ + g_usleep (2000000); + for (gint i = 1; i <= TBT_MAX_RETRIES; i++) { + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, error)) { + g_prefix_error (error, "failed to set check authentication: "); + return FALSE; + } + if (!fu_dell_dock_hid_get_report (self, cmd_buffer.data, error)) { + g_prefix_error (error, "failed to get check authentication: "); + return FALSE; + } + result = cmd_buffer.data[1] & 0xf; + if (result == 0) + break; + g_debug ("attempt %d/%d: Thunderbolt authenticate failed: %x", + i, TBT_MAX_RETRIES, result); + g_usleep (500000); + } + if (result != 0) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Thunderbolt authentication failed: %s", + fu_dell_dock_hid_tbt_map_error (result)); + return FALSE; + } + + return TRUE; +} diff -Nru fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-hid.h fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-hid.h --- fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-hid.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-hid.h 2019-02-25 09:42:18.000000000 +0000 @@ -14,8 +14,7 @@ * SPDX-License-Identifier: LGPL-2.1+ OR MIT */ -#ifndef __FU_DELL_DOCK_HID_H -#define __FU_DELL_DOCK_HID_H +#pragma once #include "config.h" @@ -78,4 +77,17 @@ gboolean *result, GError **error); -#endif /* __FU_DELL_DOCK_HID_H */ +gboolean fu_dell_dock_hid_tbt_wake (FuDevice *self, + const FuHIDI2CParameters *parameters, + GError **error); + +gboolean fu_dell_dock_hid_tbt_write (FuDevice *self, + guint32 start_addr, + const guint8 *input, + gsize write_size, + const FuHIDI2CParameters *parameters, + GError **error); + +gboolean fu_dell_dock_hid_tbt_authenticate (FuDevice *self, + const FuHIDI2CParameters *parameters, + GError **error); diff -Nru fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-hub.c fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-hub.c --- fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-hub.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-hub.c 2019-02-25 09:42:18.000000000 +0000 @@ -15,8 +15,6 @@ #include "config.h" -#include - #include "fu-usb-device.h" #include "fwupd-error.h" @@ -34,14 +32,14 @@ static gboolean fu_dell_dock_hub_probe (FuDevice *device, GError **error) { - g_autofree gchar *guid = NULL; + g_autofree gchar *devid = NULL; - guid = g_strdup_printf ("USB\\VID_%04X&PID_%04X&hub", + devid = g_strdup_printf ("USB\\VID_%04X&PID_%04X&hub", (guint) fu_usb_device_get_vid (FU_USB_DEVICE (device)), (guint) fu_usb_device_get_pid (FU_USB_DEVICE (device))); fu_device_set_logical_id (device, "hub"); - fu_device_add_guid (device, guid); + fu_device_add_instance_id (device, devid); return TRUE; } diff -Nru fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-hub.h fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-hub.h --- fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-hub.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-hub.h 2019-02-25 09:42:18.000000000 +0000 @@ -13,8 +13,7 @@ * SPDX-License-Identifier: LGPL-2.1+ OR MIT */ -#ifndef __FU_DELL_DOCK_HUB_H -#define __FU_DELL_DOCK_HUB_H +#pragma once #include "config.h" @@ -28,5 +27,3 @@ FuDellDockHub *fu_dell_dock_hub_new (FuUsbDevice *device); G_END_DECLS - -#endif /* __FU_DELL_DOCK_HUB_H */ diff -Nru fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-i2c-ec.c fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-i2c-ec.c --- fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-i2c-ec.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-i2c-ec.c 2019-02-25 09:42:18.000000000 +0000 @@ -15,9 +15,9 @@ #include "config.h" -#include #include +#include "fu-common-version.h" #include "fu-usb-device.h" #include "fwupd-error.h" @@ -32,14 +32,25 @@ #define EC_CMD_MODIFY_LOCK 0x0a #define EC_CMD_RESET 0x0b #define EC_CMD_REBOOT 0x0c +#define EC_CMD_PASSIVE 0x0d #define EC_GET_FW_UPDATE_STATUS 0x0f #define EXPECTED_DOCK_INFO_SIZE 0xb7 #define EXPECTED_DOCK_TYPE 0x04 +#define TBT_MODE_MASK 0x01 + +#define BIT_SET(x,y) (x |= (1<data->port0_dock_status & TBT_MODE_MASK; - return self->data->module_type == MODULE_TYPE_TBT; + /* check for TBT module type */ + if (self->data->module_type != MODULE_TYPE_TBT) + return FALSE; + g_debug ("found thunderbolt dock, port mode: %d", port0_tbt_mode); + + return !port0_tbt_mode; +} + +gboolean +fu_dell_dock_ec_tbt_passive (FuDevice *device) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + + if (self->passive_flow > 0) { + self->passive_flow |= PASSIVE_TBT_MASK; + return TRUE; + } + return FALSE; } static const gchar* @@ -187,6 +224,8 @@ else if (sub_type == SUBTYPE_GEN1) return "USB 3.1 Gen1"; return NULL; + case FU_DELL_DOCK_DEVICETYPE_PD: + return "PD"; default: return NULL; } @@ -273,6 +312,8 @@ const FuDellDockDockInfoHeader *header = NULL; const FuDellDockEcQueryEntry *device_entry = NULL; const FuDellDockEcAddrMap *map = NULL; + const gchar *hub_version; + guint32 oldest_base_pd = 0; g_autoptr(GBytes) data = NULL; g_return_val_if_fail (device != NULL, FALSE); @@ -332,7 +373,7 @@ device_entry[i].version.version_8[2], device_entry[i].version.version_8[3]); g_debug ("\tParsed version %s", self->ec_version); - fu_device_set_version (self, self->ec_version); + fu_device_set_version (FU_DEVICE (self), self->ec_version); } else if (map->device_type == FU_DELL_DOCK_DEVICETYPE_MST) { self->raw_versions->mst_version = device_entry[i].version.version_32; @@ -347,7 +388,8 @@ device_entry[i].version.version_8[2], device_entry[i].version.version_8[3]); g_debug ("\tParsed version %s", self->mst_version); - } else if (map->device_type == FU_DELL_DOCK_DEVICETYPE_TBT && fu_dell_dock_ec_has_tbt (device)) { + } else if (map->device_type == FU_DELL_DOCK_DEVICETYPE_TBT && + self->data->module_type == MODULE_TYPE_TBT) { /* guard against invalid Thunderbolt version read from EC */ if (!fu_dell_dock_test_valid_byte (device_entry[i].version.version_8, 2)) { g_warning ("[EC bug] EC read invalid Thunderbolt version %08x", @@ -365,17 +407,71 @@ self->raw_versions->hub2_version = device_entry[i].version.version_32; else if (map->sub_type == SUBTYPE_GEN1) self->raw_versions->hub1_version = device_entry[i].version.version_32; + } else if (map->device_type == FU_DELL_DOCK_DEVICETYPE_PD && + map->location == LOCATION_BASE && + map->sub_type == 0) { + if (oldest_base_pd == 0 || + device_entry[i].version.version_32 < oldest_base_pd) + oldest_base_pd = GUINT32_TO_BE (device_entry[i].version.version_32); + g_debug ("\tParsed version: %02x.%02x.%02x.%02x", + device_entry[i].version.version_8[0], + device_entry[i].version.version_8[1], + device_entry[i].version.version_8[2], + device_entry[i].version.version_8[3]); } } + /* Thunderbolt SKU takes a little longer */ + if (self->data->module_type == MODULE_TYPE_TBT) { + guint64 tmp = fu_device_get_install_duration (device); + fu_device_set_install_duration (device, tmp + 20); + } + /* minimum EC version this code will support */ - if (as_utils_vercmp (self->ec_version, self->ec_minimum_version) < 0) { + if (fu_common_vercmp (self->ec_version, self->ec_minimum_version) < 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "dock containing EC version %s is not supported", self->ec_version); return FALSE; } + /* TODO: Drop if setting minimum board to 5+ and minimum EC to 19+ + * If running on board 4 or later, already EC19+, then + * don't allow downgrades to anything < EC19 + */ + if (self->data->board_id >= 4 && + fu_common_vercmp (self->ec_version, "00.00.00.19") >= 0) { + g_debug ("Prohibiting downgrades below EC 00.00.00.19"); + g_free (self->ec_minimum_version); + self->ec_minimum_version = g_strdup ("00.00.00.19"); + } + fu_device_set_version_lowest (device, self->ec_minimum_version); + + + /* TODO: Drop part of clause if minimum EC is set to 26+ + * Determine if the passive flow should be used when flashing + */ + hub_version = fu_device_get_version (self->symbiote); + if (fu_common_vercmp (self->ec_version, "00.00.00.26") >= 0 && + fu_common_vercmp (hub_version, "1.42") >= 0) { + g_debug ("using passive flow"); + self->passive_flow = PASSIVE_REBOOT_MASK; + fu_device_set_custom_flags (device, "skip-restart"); + } else { + g_debug ("not using passive flow (EC: %s Hub2: %s)", + self->ec_version, hub_version); + } + /* TODO: drop if minimum board is to 5+ and minimum EC to 24+ */ + if (self->data->board_id == 4 && oldest_base_pd >= 0x18) { + if (fu_common_vercmp (self->ec_version, "00.00.00.24") < 0) + self->pd_blacklist = TRUE; + if (fu_common_vercmp (self->ec_version, "00.00.00.23") == 0) { + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_update_error (device, "No more updates will " + "be released for this " + "dock SKU"); + } + } return TRUE; } @@ -390,6 +486,7 @@ const guint8 *result; gsize length = sizeof(FuDellDockDockDataStructure); g_autofree gchar *bundled_serial = NULL; + FuDellDockECFWUpdateStatus status; g_return_val_if_fail (device != NULL, FALSE); @@ -433,11 +530,20 @@ /* copy this for being able to send in next commit transaction */ self->raw_versions->pkg_version = self->data->dock_firmware_pkg_ver; + /* read if passive update pending */ + if (!fu_dell_dock_get_ec_status (device, &status, error)) + return FALSE; + /* make sure this hardware spin matches our expecations */ if (self->data->board_id >= self->board_min) { - fu_dell_dock_ec_set_board (device); - fu_device_set_version (device, self->ec_version); - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + if (status != FW_UPDATE_IN_PROGRESS) { + fu_dell_dock_ec_set_board (device); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + } else { + fu_device_set_update_error (device, "An update is pending " + "next time the dock is " + "unplugged"); + } } else { g_warning ("This utility does not support this board, disabling updates for %s", fu_device_get_name (device)); @@ -478,6 +584,10 @@ self->data->module_type); g_string_append_printf (str, "\tminimum ec: %s\n", self->ec_minimum_version); + g_string_append_printf (str, "\tblacklist pd: %d\n", + self->pd_blacklist); + g_string_append_printf (str, "\tpassive flow: %d\n", + self->passive_flow); } gboolean @@ -486,6 +596,7 @@ gboolean unlocked, GError **error) { + FuDellDockEc *self = FU_DELL_DOCK_EC (device); guint32 cmd; g_return_val_if_fail (device != NULL, FALSE); @@ -506,6 +617,12 @@ fu_device_get_name (device), fu_device_get_id (device)); + if (unlocked) + BIT_SET (self->dock_unlock_status, target); + else + BIT_CLEAR (self->dock_unlock_status, target); + g_debug ("current overall unlock status: 0x%08x", self->dock_unlock_status); + return TRUE; } @@ -523,22 +640,24 @@ fu_dell_dock_ec_reboot_dock (FuDevice *device, GError **error) { FuDellDockEc *self = FU_DELL_DOCK_EC (device); - guint16 cmd = EC_CMD_REBOOT; g_return_val_if_fail (device != NULL, FALSE); - if (fu_device_has_custom_flag (device, "skip-restart")) { - g_debug ("Skipping reboot per quirk request"); - return TRUE; + if (self->passive_flow > 0) { + guint32 cmd = EC_CMD_PASSIVE | /* cmd */ + 1 << 8 | /* length of data arguments */ + self->passive_flow << 16; + g_debug ("activating passive flow (%x) for %s", + self->passive_flow, + fu_device_get_name (device)); + return fu_dell_dock_ec_write (device, 3, (guint8 *) &cmd, error); + } else { + guint16 cmd = EC_CMD_REBOOT; + g_debug ("rebooting %s", fu_device_get_name (device)); + return fu_dell_dock_ec_write (device, 2, (guint8 *) &cmd, error); } - /* TODO: Drop when bumping minimum EC version to 13+ */ - if (as_utils_vercmp (self->ec_version, "00.00.00.13") < 0) - g_print ("\nEC Reboot API may fail on EC %s. Please manually power cycle dock.\n", - self->ec_version); - g_debug ("Rebooting %s", fu_device_get_name (device)); - - return fu_dell_dock_ec_write (device, 2, (guint8 *) &cmd, error); + return TRUE; } static gboolean @@ -586,6 +705,16 @@ fu_dell_dock_ec_get_status_version (FuDevice *device) { FuDellDockEc *self = FU_DELL_DOCK_EC (device); + + /* TODO: drop if setting minimum board to 5+ + * this board was manufactured with 89.16.01.00 and won't upgrade + */ + if (self->data->board_id == 4 && + self->raw_versions->pkg_version == 71305) { + g_printerr ("Dock manufactured w/ invalid package %u\n", + self->raw_versions->pkg_version); + self->raw_versions->pkg_version = 0; + } return self->raw_versions->pkg_version; } @@ -617,13 +746,6 @@ g_debug ("\ttbt_version: %x", self->raw_versions->tbt_version); g_debug ("\tpkg_version: %x", self->raw_versions->pkg_version); - /* TODO: Drop when updating minimum EC to 11+ */ - if (as_utils_vercmp (self->ec_version, "00.00.00.11") < 0) { - g_debug ("EC %s doesn't support package version, ignoring", - self->ec_version); - return TRUE; - } - payload [0] = EC_CMD_SET_DOCK_PKG; payload [1] = length; memcpy (payload + 2, data, length); @@ -657,6 +779,18 @@ dynamic_version = g_strndup ((gchar *) data + self->blob_version_offset, 11); g_debug ("writing EC firmware version %s", dynamic_version); + /* TODO: drop if minimum board set to 5+ and minimum EC to 24+ */ + if (self->pd_blacklist && + fu_common_vercmp (dynamic_version, "00.00.00.24") >= 0) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, + "%s can not flash firmware %s. " + "only firmware %s -> 00.00.00.23 can be flashed.", + fu_device_get_name (device), + dynamic_version, + self->ec_minimum_version); + return FALSE; + } + if (!fu_dell_dock_ec_modify_lock (device, self->unlock_target, TRUE, error)) return FALSE; @@ -687,6 +821,13 @@ if (!fu_dell_dock_hid_raise_mcu_clock (self->symbiote, FALSE, error)) return FALSE; + /* dock will reboot to re-read; this is to appease the daemon */ + fu_device_set_version (device, dynamic_version); + + /* activate passive behavior */ + if (self->passive_flow) + self->passive_flow |= PASSIVE_RESET_MASK; + if (fu_device_has_custom_flag (device, "skip-restart")) { g_debug ("Skipping EC reset per quirk request"); return TRUE; @@ -723,11 +864,15 @@ error_local->message, status); return TRUE; } + if (status == FW_UPDATE_AUTHENTICATION_FAILED) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid EC firmware image"); + return FALSE; + } } - /* dock will reboot to re-read; this is to appease the daemon */ - fu_device_set_version (device, dynamic_version); - return TRUE; } @@ -788,7 +933,7 @@ fu_dell_dock_ec_probe (FuDevice *device, GError **error) { /* this will trigger setting up all the quirks */ - fu_device_add_guid (device, DELL_DOCK_EC_GUID); + fu_device_add_instance_id (device, DELL_DOCK_EC_INSTANCE_ID); return TRUE; } diff -Nru fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-i2c-ec.h fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-i2c-ec.h --- fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-i2c-ec.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-i2c-ec.h 2019-02-25 09:42:18.000000000 +0000 @@ -13,8 +13,7 @@ * SPDX-License-Identifier: LGPL-2.1+ OR MIT */ -#ifndef __FU_DELL_DOCK_EC_H -#define __FU_DELL_DOCK_EC_H +#pragma once #include "config.h" @@ -31,7 +30,8 @@ G_END_DECLS -gboolean fu_dell_dock_ec_has_tbt (FuDevice *device); +gboolean fu_dell_dock_ec_needs_tbt (FuDevice *device); +gboolean fu_dell_dock_ec_tbt_passive (FuDevice *device); gboolean fu_dell_dock_ec_modify_lock (FuDevice *self, guint8 target, gboolean unlocked, @@ -47,5 +47,3 @@ GBytes *blob_fw, GError **error); FuDevice *fu_dell_dock_ec_get_symbiote (FuDevice *device); - -#endif /* __FU_DELL_DOCK_EC_H */ diff -Nru fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-i2c-mst.c fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-i2c-mst.c --- fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-i2c-mst.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-i2c-mst.c 2019-02-25 09:42:18.000000000 +0000 @@ -16,7 +16,6 @@ #include "config.h" -#include #include #include "fu-common.h" @@ -386,7 +385,7 @@ static gboolean fu_dell_dock_mst_check_offset (guint8 byte, guint8 offset) { - if ((byte & offset) > 0) + if ((byte & offset) != 0) return TRUE; return FALSE; } @@ -426,35 +425,6 @@ } static gboolean -fu_dell_dock_mst_get_version_direct (FuDevice *symbiote, gchar **version_out, - GError **error) -{ - g_autoptr(GBytes) bytes = NULL; - const guint8 *data; - gsize length = 4; - - g_return_val_if_fail (version_out != NULL, FALSE); - - /* Try to read core MCU FW version */ - if (!fu_dell_dock_mst_read_register (symbiote, - MST_CORE_MCU_FW_VERSION, - length, &bytes, - error)) - return FALSE; - data = g_bytes_get_data (bytes, &length); - if (length < 4) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Invalid MST result %" G_GSIZE_FORMAT, length); - return FALSE; - } - *version_out = g_strdup_printf ("%02x.%02x.%02x", - data[1], /* major */ - data[0], /* minor */ - data[2]); /* build */ - return TRUE; -} - -static gboolean fu_dell_dock_mst_checksum_bank (FuDevice *symbiote, GBytes *blob_fw, MSTBank bank, @@ -646,7 +616,7 @@ if (!fu_dell_dock_mst_rc_command (symbiote, MST_CMD_WRITE_MEMORY, length, MST_REG_HDCP22_DISABLE, - data, + data_out, error)) return FALSE; @@ -772,7 +742,7 @@ MSTBank bank_in_use = 0; guint retries = 2; gboolean checksum = FALSE; - guint8 order[3] = {Bank0, ESM}; + guint8 order[2] = {ESM, Bank0}; guint16 chip_id; const guint8* data = g_bytes_get_data (blob_fw, NULL); g_autofree gchar *dynamic_version = NULL; @@ -792,7 +762,7 @@ return FALSE; if (bank_in_use == Bank0) - order[0] = Bank1; + order[1] = Bank1; /* enable remote control */ if (!fu_dell_dock_mst_enable_remote_control (self->symbiote, error)) @@ -924,7 +894,6 @@ FuDellDockMst *self = FU_DELL_DOCK_MST (device); FuDevice *parent; const gchar *version; - g_autofree gchar *dynamic_version = NULL; /* sanity check that we can talk to MST */ if (!fu_d19_mst_check_fw (self->symbiote, error)) @@ -934,24 +903,17 @@ parent = fu_device_get_parent (device); version = fu_dell_dock_ec_get_mst_version (parent); - /* TODO: Drop when we can guarantee EC 15+ */ - if (version == NULL) { - if (!fu_dell_dock_mst_get_version_direct (self->symbiote, - &dynamic_version, - error)) - return FALSE; - version = dynamic_version; - } if (version != NULL) fu_device_set_version (device, version); + fu_dell_dock_clone_updatable (device); + return TRUE; } static gboolean fu_dell_dock_mst_probe (FuDevice *device, GError **error) { - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_set_logical_id (FU_DEVICE (device), "mst"); return TRUE; diff -Nru fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-i2c-mst.h fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-i2c-mst.h --- fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-i2c-mst.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-i2c-mst.h 2019-02-25 09:42:18.000000000 +0000 @@ -13,8 +13,7 @@ * SPDX-License-Identifier: LGPL-2.1+ OR MIT */ -#ifndef __FU_DELL_DOCK_I2C_MST_H -#define __FU_DELL_DOCK_I2C_MST_H +#pragma once #include "config.h" @@ -28,5 +27,3 @@ FuDellDockMst *fu_dell_dock_mst_new (void); G_END_DECLS - -#endif /* __FU_DELL_DOCK_I2C_MST_H */ diff -Nru fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-i2c-tbt.c fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-i2c-tbt.c --- fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-i2c-tbt.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-i2c-tbt.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2019 Intel Corporation. + * Copyright (C) 2019 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#include "config.h" + +#include + +#include "fwupd-error.h" +#include "fu-device.h" +#include "fu-common.h" +#include "fu-common-version.h" + +#include "fu-dell-dock-common.h" + +#define I2C_TBT_ADDRESS 0xa2 + +const FuHIDI2CParameters tbt_base_settings = { + .i2cslaveaddr = I2C_TBT_ADDRESS, + .regaddrlen = 1, + .i2cspeed = I2C_SPEED_400K, +}; + +/* TR Device ID */ +#define PID_OFFSET 0x05 +#define INTEL_PID 0x15ef + +/* earlier versions have bugs */ +#define MIN_NVM "36.01" + +struct _FuDellDockTbt { + FuDevice parent_instance; + FuDevice *symbiote; + guint8 unlock_target; + guint64 blob_major_offset; + guint64 blob_minor_offset; + gchar *hub_minimum_version; +}; + +G_DEFINE_TYPE (FuDellDockTbt, fu_dell_dock_tbt, FU_TYPE_DEVICE) + +static gboolean +fu_dell_dock_tbt_write_fw (FuDevice *device, + GBytes *blob_fw, + GError **error) +{ + FuDellDockTbt *self = FU_DELL_DOCK_TBT (device); + guint32 start_offset = 0; + gsize image_size; + const guint8 *buffer = g_bytes_get_data (blob_fw, &image_size); + guint16 target_system = 0; + g_autoptr(GTimer) timer = g_timer_new (); + g_autofree gchar *dynamic_version = NULL; + + g_return_val_if_fail (device != NULL, FALSE); + g_return_val_if_fail (blob_fw != NULL, FALSE); + + dynamic_version = g_strdup_printf ("%02x.%02x", + buffer[self->blob_major_offset], + buffer[self->blob_minor_offset]); + g_debug ("writing Thunderbolt firmware version %s", dynamic_version); + g_debug ("Total Image size: %" G_GSIZE_FORMAT, image_size); + + memcpy (&start_offset, buffer, sizeof (guint32)); + g_debug ("Header size 0x%x", start_offset); + if (start_offset > image_size) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, + "Image header is too big (0x%x)", + start_offset); + return FALSE; + } + + memcpy (&target_system, buffer + start_offset + PID_OFFSET, sizeof (guint16)); + if (target_system != INTEL_PID) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, + "Image is not intended for this system (0x%x)", + target_system); + return FALSE; + } + + buffer += start_offset; + image_size -= start_offset; + + g_debug ("waking Thunderbolt controller"); + if (!fu_dell_dock_hid_tbt_wake (self->symbiote, &tbt_base_settings, error)) + return FALSE; + g_usleep (2000000); + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (guint i = 0; i < image_size; i+= HIDI2C_MAX_WRITE, buffer += HIDI2C_MAX_WRITE) { + guint8 write_size = (image_size - i) > HIDI2C_MAX_WRITE ? + HIDI2C_MAX_WRITE : (image_size - i); + + if (!fu_dell_dock_hid_tbt_write (self->symbiote, + i, + buffer, + write_size, + &tbt_base_settings, + error)) + return FALSE; + + fu_device_set_progress_full (device, i, image_size); + } + g_debug ("writing took %f seconds", + g_timer_elapsed (timer, NULL)); + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); + + if (fu_dell_dock_ec_tbt_passive (fu_device_get_parent (device))) { + g_debug ("using passive flow for Thunderbolt"); + } else if (!fu_dell_dock_hid_tbt_authenticate (self->symbiote, + &tbt_base_settings, + error)) { + g_prefix_error (error, "failed to authenticate: "); + return FALSE; + } + + /* dock will reboot to re-read; this is to appease the daemon */ + fu_device_set_version (device, dynamic_version); + + return TRUE; +} + +static gboolean +fu_dell_dock_tbt_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuDellDockTbt *self = FU_DELL_DOCK_TBT (device); + + if (g_strcmp0 (key, "DellDockUnlockTarget") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp < G_MAXUINT8) { + self->unlock_target = tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid DellDockUnlockTarget"); + return FALSE; + } else if (g_strcmp0 (key, "DellDockInstallDurationI2C") == 0) { + guint64 tmp = fu_common_strtoull (value); + fu_device_set_install_duration (device, tmp); + return TRUE; + } else if (g_strcmp0 (key, "DellDockHubVersionLowest") == 0) { + self->hub_minimum_version = g_strdup (value); + return TRUE; + } else if (g_strcmp0 (key, "DellDockBlobMajorOffset") == 0) { + self->blob_major_offset = fu_common_strtoull (value); + return TRUE; + } else if (g_strcmp0 (key, "DellDockBlobMinorOffset") == 0) { + self->blob_minor_offset = fu_common_strtoull (value); + return TRUE; + } + /* failed */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + + +static gboolean +fu_dell_dock_tbt_setup (FuDevice *device, GError **error) +{ + FuDellDockTbt *self = FU_DELL_DOCK_TBT (device); + FuDevice *parent; + const gchar *version; + const gchar *hub_version; + + /* set version from EC if we know it */ + parent = fu_device_get_parent (device); + version = fu_dell_dock_ec_get_tbt_version (parent); + + if (version != NULL) + fu_device_set_version (device, version); + + /* minimum version of NVM that supports this feature */ + if (version == NULL || fu_common_vercmp (version, MIN_NVM) < 0) { + fu_device_set_update_error (device, + "Updates over I2C are disabled due to insuffient NVM version"); + return TRUE; + } + /* minimum Hub2 version that supports this feature */ + hub_version = fu_device_get_version (self->symbiote); + if (fu_common_vercmp (hub_version, self->hub_minimum_version) < 0) { + fu_device_set_update_error (device, + "Updates over I2C are disabled due to insufficient USB 3.1 G2 hub version"); + return TRUE; + } + + fu_dell_dock_clone_updatable (device); + + return TRUE; +} + +static gboolean +fu_dell_dock_tbt_probe (FuDevice *device, GError **error) +{ + FuDevice *parent = fu_device_get_parent (device); + fu_device_set_physical_id (device, fu_device_get_physical_id (parent)); + fu_device_set_logical_id (FU_DEVICE (device), "tbt"); + fu_device_add_instance_id (device, DELL_DOCK_TBT_INSTANCE_ID); + + return TRUE; +} + +static gboolean +fu_dell_dock_tbt_open (FuDevice *device, GError **error) +{ + FuDellDockTbt *self = FU_DELL_DOCK_TBT (device); + FuDevice *parent; + + g_return_val_if_fail (self->unlock_target != 0, FALSE); + + parent = fu_device_get_parent (device); + if (parent == NULL) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "no parent"); + return FALSE; + } + + if (self->symbiote == NULL) + self->symbiote = g_object_ref (fu_dell_dock_ec_get_symbiote (parent)); + + if (!fu_device_open (self->symbiote, error)) + return FALSE; + + /* adjust to access controller */ + if (!fu_dell_dock_set_power (device, self->unlock_target, TRUE, error)) + return FALSE; + + return TRUE; +} + +static gboolean +fu_dell_dock_tbt_close (FuDevice *device, GError **error) +{ + FuDellDockTbt *self = FU_DELL_DOCK_TBT (device); + + /* adjust to access controller */ + if (!fu_dell_dock_set_power (device, self->unlock_target, FALSE, error)) + return FALSE; + + return fu_device_close (self->symbiote, error); +} + +static void +fu_dell_dock_tbt_finalize (GObject *object) +{ + FuDellDockTbt *self = FU_DELL_DOCK_TBT (object); + g_object_unref (self->symbiote); + g_free (self->hub_minimum_version); + + G_OBJECT_CLASS (fu_dell_dock_tbt_parent_class)->finalize (object); +} + +static void +fu_dell_dock_tbt_init (FuDellDockTbt *device) +{} + +static void +fu_dell_dock_tbt_class_init (FuDellDockTbtClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + object_class->finalize = fu_dell_dock_tbt_finalize; + klass_device->probe = fu_dell_dock_tbt_probe; + klass_device->setup = fu_dell_dock_tbt_setup; + klass_device->open = fu_dell_dock_tbt_open; + klass_device->close = fu_dell_dock_tbt_close; + klass_device->write_firmware = fu_dell_dock_tbt_write_fw; + klass_device->set_quirk_kv = fu_dell_dock_tbt_set_quirk_kv; +} + +FuDellDockTbt * +fu_dell_dock_tbt_new (void) +{ + FuDellDockTbt *device = NULL; + device = g_object_new (FU_TYPE_DELL_DOCK_TBT, NULL); + return device; +} diff -Nru fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-i2c-tbt.h fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-i2c-tbt.h --- fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-i2c-tbt.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-i2c-tbt.h 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2019 Intel Corporation. + * Copyright (C) 2019 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#pragma once + +#include "config.h" + +#include "fu-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_DELL_DOCK_TBT (fu_dell_dock_tbt_get_type ()) +G_DECLARE_FINAL_TYPE (FuDellDockTbt, fu_dell_dock_tbt, FU, DELL_DOCK_TBT, FuDevice) + +FuDellDockTbt *fu_dell_dock_tbt_new (void); + +G_END_DECLS diff -Nru fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-status.c fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-status.c --- fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-status.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-status.c 2019-02-25 09:42:18.000000000 +0000 @@ -16,7 +16,6 @@ #include "config.h" #include -#include #include "fu-dell-dock-common.h" @@ -52,6 +51,8 @@ fu_device_set_version (device, dynamic_version); fu_device_set_logical_id (FU_DEVICE (device), "status"); + fu_dell_dock_clone_updatable (device); + return TRUE; } diff -Nru fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-status.h fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-status.h --- fwupd-1.1.4/plugins/dell-dock/fu-dell-dock-status.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell-dock/fu-dell-dock-status.h 2019-02-25 09:42:18.000000000 +0000 @@ -13,8 +13,7 @@ * SPDX-License-Identifier: LGPL-2.1+ OR MIT */ -#ifndef __FU_DELL_DOCK_STATUS_H -#define __FU_DELL_DOCK_STATUS_H +#pragma once #include "config.h" @@ -28,5 +27,3 @@ FuDellDockStatus *fu_dell_dock_status_new (void); G_END_DECLS - -#endif /* __FU_DELL_DOCK_STATUS_H */ diff -Nru fwupd-1.1.4/plugins/dell-dock/fu-plugin-dell-dock.c fwupd-1.2.5/plugins/dell-dock/fu-plugin-dell-dock.c --- fwupd-1.1.4/plugins/dell-dock/fu-plugin-dell-dock.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell-dock/fu-plugin-dell-dock.c 2019-02-25 09:42:18.000000000 +0000 @@ -21,8 +21,11 @@ #include "fu-dell-dock-common.h" -void fu_plugin_init (FuPlugin *plugin) +void +fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + /* allow these to be built by quirks */ fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); g_type_ensure (FU_TYPE_DELL_DOCK_STATUS); @@ -30,6 +33,8 @@ /* currently slower performance, but more reliable in corner cases */ fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_BETTER_THAN, "synapticsmst"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.dell.dock"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.synaptics.mst"); } static gboolean @@ -63,6 +68,16 @@ error)) return FALSE; + /* create TBT endpoint if Thunderbolt SKU and Thunderbolt link inactive */ + if (fu_dell_dock_ec_needs_tbt (FU_DEVICE (ec_device))) { + g_autoptr(FuDellDockTbt) tbt_device = fu_dell_dock_tbt_new (); + fu_device_add_child (FU_DEVICE (ec_device), FU_DEVICE (tbt_device)); + if (!fu_plugin_dell_dock_create_node (plugin, + FU_DEVICE (tbt_device), + error)) + return FALSE; + } + return TRUE; } @@ -102,6 +117,9 @@ } } + /* clear updatable flag if parent doesn't have it */ + fu_dell_dock_clone_updatable (fu_device); + return TRUE; } diff -Nru fwupd-1.1.4/plugins/dell-dock/meson.build fwupd-1.2.5/plugins/dell-dock/meson.build --- fwupd-1.1.4/plugins/dell-dock/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell-dock/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -5,6 +5,7 @@ ) shared_module('fu_plugin_dell_dock', + fu_hash, sources : [ 'fu-plugin-dell-dock.c', 'fu-dell-dock-common.c', @@ -12,6 +13,7 @@ 'fu-dell-dock-status.c', 'fu-dell-dock-i2c-ec.c', 'fu-dell-dock-hub.c', + 'fu-dell-dock-i2c-tbt.c', 'fu-dell-dock-i2c-mst.c' ], include_directories : [ @@ -21,6 +23,9 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff -Nru fwupd-1.1.4/plugins/dell-dock/README.md fwupd-1.2.5/plugins/dell-dock/README.md --- fwupd-1.1.4/plugins/dell-dock/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell-dock/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -24,3 +24,48 @@ When this plugin is used, devices present in other plugins may be shown in the topology of this dock. This is intentional as this plugin works together with those plugins to manage the flashing of all components. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract several firmware +blobs with an unspecified binary file format. + +This plugin supports the following protocol ID: + + * com.dell.dock + * com.synaptics.mst + +GUID Generation +--------------- + +These devices use several different generation schemes, e.g. + + * USB Hub1: `USB\VID_413C&PID_B06F&hub` + * USB Hub2: `USB\VID_413C&PID_B06E&hub` + * Embedded Controller: `USB\VID_413C&PID_B06E&hub&embedded` + * Update Level: `USB\VID_413C&PID_B06E&hub&status` + * MST Hub: `MST-panamera-vmm5331-259` + * Thunderbolt Controller: `TBT-00d4b070` + +Custom flag use: +---------------- +This plugin uses the following plugin-specific custom flags: + +* `skip-restart`: Don't run the reset or reboot procedure of the component + +Quirk use +--------- +This plugin uses the following plugin-specific quirks: + +| Quirk | Description | Minimum fwupd version | +|------------------------------|-------------------------------------------------------------------------|-----------------------| +| `DellDockUnlockTarget` | The EC argument needed for unlocking certain device usage. | 1.1.3 | +| `DellDockBlobMajorOffset` | The offset of the major version number in a payload | 1.1.3 | +| `DellDockBlobMinorOffset` | The offset of the minor version number in a payload | 1.1.3 | +| `DellDockBlobBuildOffset` | The offset of the build version number in a payload | 1.1.3 | +| `DellDockBlobVersionOffset` | The offset of the ASCII representation of a version string in a payload | 1.1.3 | +| `DellDockBoardMin` | The minimum board revision required to safely operate the plugin | 1.1.3 | +| `DellDockVersionLowest` | The minimum component version required to safely operate the plugin | 1.1.3 | +| `DellDockBoard*` | The board description of a board revision | 1.1.3 | +| `DellDockInstallDurationI2C` | The duration of time required to install a payload via I2C. | 1.1.3 | diff -Nru fwupd-1.1.4/plugins/dell-esrt/fu-plugin-dell-esrt.c fwupd-1.2.5/plugins/dell-esrt/fu-plugin-dell-esrt.c --- fwupd-1.1.4/plugins/dell-esrt/fu-plugin-dell-esrt.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell-esrt/fu-plugin-dell-esrt.c 2019-02-25 09:42:18.000000000 +0000 @@ -83,6 +83,12 @@ return TRUE; } +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + gboolean fu_plugin_startup (FuPlugin *plugin, GError **error) { diff -Nru fwupd-1.1.4/plugins/dell-esrt/meson.build fwupd-1.2.5/plugins/dell-esrt/meson.build --- fwupd-1.1.4/plugins/dell-esrt/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell-esrt/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -1,6 +1,7 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginDellEsrt"'] shared_module('fu_plugin_dell_esrt', + fu_hash, sources : [ 'fu-plugin-dell-esrt.c', ], @@ -12,8 +13,11 @@ install : true, install_dir: plugin_dir, c_args : [ - cargs, - ], + cargs, + ], + link_with : [ + libfwupdprivate, + ], dependencies : [ plugin_deps, libsmbios_c, diff -Nru fwupd-1.1.4/plugins/dell-esrt/README.md fwupd-1.2.5/plugins/dell-esrt/README.md --- fwupd-1.1.4/plugins/dell-esrt/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dell-esrt/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -7,6 +7,11 @@ This allows enabling the BIOS setup option for UEFI capsule updates without manually going into BIOS setup. +GUID Generation +--------------- + +These device uses a hardcoded GUID of `2d47f29b-83a2-4f31-a2e8-63474f4d4c2e`. + Build Requirements ------------------ diff -Nru fwupd-1.1.4/plugins/dfu/dfu-cipher-xtea.h fwupd-1.2.5/plugins/dfu/dfu-cipher-xtea.h --- fwupd-1.1.4/plugins/dfu/dfu-cipher-xtea.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-cipher-xtea.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_FORMAT_XTEA_H -#define __DFU_FORMAT_XTEA_H +#pragma once #include #include @@ -22,5 +21,3 @@ GError **error); G_END_DECLS - -#endif /* __DFU_FORMAT_XTEA_H */ diff -Nru fwupd-1.1.4/plugins/dfu/dfu-common.c fwupd-1.2.5/plugins/dfu/dfu-common.c --- fwupd-1.1.4/plugins/dfu/dfu-common.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-common.c 2019-02-25 09:42:18.000000000 +0000 @@ -326,3 +326,27 @@ buffer[8] = '\0'; return (guint32) g_ascii_strtoull (buffer, NULL, 16); } + +/** + * dfu_utils_strnsplit: + * @str: a string to split + * @sz: size of @str + * @delimiter: a string which specifies the places at which to split the string + * @max_tokens: the maximum number of pieces to split @str into + * + * Splits a string into a maximum of @max_tokens pieces, using the given + * delimiter. If @max_tokens is reached, the remainder of string is appended + * to the last token. + * + * Return value: a newly-allocated NULL-terminated array of strings + **/ +gchar ** +dfu_utils_strnsplit (const gchar *str, gsize sz, + const gchar *delimiter, gint max_tokens) +{ + if (str[sz - 1] != '\0') { + g_autofree gchar *str2 = g_strndup (str, sz); + return g_strsplit (str2, delimiter, max_tokens); + } + return g_strsplit (str, delimiter, max_tokens); +} diff -Nru fwupd-1.1.4/plugins/dfu/dfu-common.h fwupd-1.2.5/plugins/dfu/dfu-common.h --- fwupd-1.1.4/plugins/dfu/dfu-common.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-common.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_COMMON_H -#define __DFU_COMMON_H +#pragma once #include #include @@ -165,7 +164,9 @@ guint16 dfu_utils_buffer_parse_uint16 (const gchar *data); guint32 dfu_utils_buffer_parse_uint24 (const gchar *data); guint32 dfu_utils_buffer_parse_uint32 (const gchar *data); +gchar **dfu_utils_strnsplit (const gchar *str, + gsize sz, + const gchar *delimiter, + gint max_tokens); G_END_DECLS - -#endif /* __DFU_COMMON_H */ diff -Nru fwupd-1.1.4/plugins/dfu/dfu-device.c fwupd-1.2.5/plugins/dfu/dfu-device.c --- fwupd-1.1.4/plugins/dfu/dfu-device.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-device.c 2019-02-25 09:42:18.000000000 +0000 @@ -578,6 +578,7 @@ { DfuDevicePrivate *priv = GET_PRIVATE (device); g_auto(GStrv) split = g_strsplit (str, ",", -1); + priv->quirks = DFU_DEVICE_QUIRK_NONE; for (guint i = 0; split[i] != NULL; i++) { if (g_strcmp0 (split[i], "ignore-polltimeout") == 0) { priv->quirks |= DFU_DEVICE_QUIRK_IGNORE_POLLTIMEOUT; @@ -1442,9 +1443,6 @@ DfuDevicePrivate *priv = GET_PRIVATE (self); GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - /* unset the quirks */ - priv->quirks = DFU_DEVICE_QUIRK_NONE; - /* release interface */ if (priv->claimed_interface) { g_usb_device_release_interface (usb_device, diff -Nru fwupd-1.1.4/plugins/dfu/dfu-device.h fwupd-1.2.5/plugins/dfu/dfu-device.h --- fwupd-1.1.4/plugins/dfu/dfu-device.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-device.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_DEVICE_H -#define __DFU_DEVICE_H +#pragma once #include #include @@ -162,5 +161,3 @@ GUsbContext *dfu_device_get_usb_context (DfuDevice *device); G_END_DECLS - -#endif /* __DFU_DEVICE_H */ diff -Nru fwupd-1.1.4/plugins/dfu/dfu-device-private.h fwupd-1.2.5/plugins/dfu/dfu-device-private.h --- fwupd-1.1.4/plugins/dfu/dfu-device-private.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-device-private.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_DEVICE_PRIVATE_H -#define __DFU_DEVICE_PRIVATE_H +#pragma once #include #include @@ -26,5 +25,3 @@ GError **error); G_END_DECLS - -#endif /* __DFU_DEVICE_PRIVATE_H */ diff -Nru fwupd-1.1.4/plugins/dfu/dfu-element.h fwupd-1.2.5/plugins/dfu/dfu-element.h --- fwupd-1.1.4/plugins/dfu/dfu-element.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-element.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_ELEMENT_H -#define __DFU_ELEMENT_H +#pragma once #include #include @@ -41,5 +40,3 @@ gchar *dfu_element_to_string (DfuElement *element); G_END_DECLS - -#endif /* __DFU_ELEMENT_H */ diff -Nru fwupd-1.1.4/plugins/dfu/dfu-firmware.c fwupd-1.2.5/plugins/dfu/dfu-firmware.c --- fwupd-1.1.4/plugins/dfu/dfu-firmware.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-firmware.c 2019-02-25 09:42:18.000000000 +0000 @@ -21,7 +21,8 @@ #include #include -#include + +#include "fu-common-version.h" #include "dfu-common.h" #include "dfu-firmware.h" @@ -642,8 +643,8 @@ g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), NULL); - release_str = as_utils_version_from_uint16 (priv->release, - AS_VERSION_PARSE_FLAG_USE_BCD); + release_str = fu_common_version_from_uint16 (priv->release, + FU_VERSION_FORMAT_BCD); str = g_string_new (""); g_string_append_printf (str, "vid: 0x%04x\n", priv->vid); g_string_append_printf (str, "pid: 0x%04x\n", priv->pid); diff -Nru fwupd-1.1.4/plugins/dfu/dfu-firmware.h fwupd-1.2.5/plugins/dfu/dfu-firmware.h --- fwupd-1.1.4/plugins/dfu/dfu-firmware.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-firmware.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_FIRMWARE_H -#define __DFU_FIRMWARE_H +#pragma once #include #include @@ -120,5 +119,3 @@ const gchar *key); G_END_DECLS - -#endif /* __DFU_FIRMWARE_H */ diff -Nru fwupd-1.1.4/plugins/dfu/dfu-format-dfu.h fwupd-1.2.5/plugins/dfu/dfu-format-dfu.h --- fwupd-1.1.4/plugins/dfu/dfu-format-dfu.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-format-dfu.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_FORMAT_DFU_H -#define __DFU_FORMAT_DFU_H +#pragma once #include #include @@ -23,5 +22,3 @@ GError **error); G_END_DECLS - -#endif /* __DFU_FORMAT_DFU_H */ diff -Nru fwupd-1.1.4/plugins/dfu/dfu-format-dfuse.h fwupd-1.2.5/plugins/dfu/dfu-format-dfuse.h --- fwupd-1.1.4/plugins/dfu/dfu-format-dfuse.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-format-dfuse.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_FORMAT_DFUSE_H -#define __DFU_FORMAT_DFUSE_H +#pragma once #include #include @@ -23,5 +22,3 @@ GError **error); G_END_DECLS - -#endif /* __DFU_FORMAT_DFUSE_H */ diff -Nru fwupd-1.1.4/plugins/dfu/dfu-format-ihex.c fwupd-1.2.5/plugins/dfu/dfu-format-ihex.c --- fwupd-1.1.4/plugins/dfu/dfu-format-ihex.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-format-ihex.c 2019-02-25 09:42:18.000000000 +0000 @@ -33,19 +33,47 @@ data = (guint8 *) g_bytes_get_data (bytes, &len); if (len < 12) return DFU_FIRMWARE_FORMAT_UNKNOWN; - if (data[0] != ':') - return DFU_FIRMWARE_FORMAT_UNKNOWN; - return DFU_FIRMWARE_FORMAT_INTEL_HEX; + + /* match the first char */ + if (data[0] == ':') + return DFU_FIRMWARE_FORMAT_INTEL_HEX; + + /* look for the EOF line */ + if (g_strstr_len ((const gchar *) data, (gssize) len, ":000000") != NULL) + return DFU_FIRMWARE_FORMAT_INTEL_HEX; + + /* failed */ + return DFU_FIRMWARE_FORMAT_UNKNOWN; } #define DFU_INHX32_RECORD_TYPE_DATA 0x00 #define DFU_INHX32_RECORD_TYPE_EOF 0x01 #define DFU_INHX32_RECORD_TYPE_EXTENDED_SEGMENT 0x02 #define DFU_INHX32_RECORD_TYPE_START_SEGMENT 0x03 -#define DFU_INHX32_RECORD_TYPE_EXTENDED 0x04 -#define DFU_INHX32_RECORD_TYPE_ADDR32 0x05 +#define DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR 0x04 +#define DFU_INHX32_RECORD_TYPE_START_LINEAR 0x05 #define DFU_INHX32_RECORD_TYPE_SIGNATURE 0xfd +static const gchar * +dfu_firmware_ihex_record_type_to_string (guint8 record_type) +{ + if (record_type == DFU_INHX32_RECORD_TYPE_DATA) + return "DATA"; + if (record_type == DFU_INHX32_RECORD_TYPE_EOF) + return "EOF"; + if (record_type == DFU_INHX32_RECORD_TYPE_EXTENDED_SEGMENT) + return "EXTENDED_SEGMENT"; + if (record_type == DFU_INHX32_RECORD_TYPE_START_SEGMENT) + return "START_SEGMENT"; + if (record_type == DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR) + return "EXTENDED_LINEAR"; + if (record_type == DFU_INHX32_RECORD_TYPE_START_LINEAR) + return "ADDR32"; + if (record_type == DFU_INHX32_RECORD_TYPE_SIGNATURE) + return "SIGNATURE"; + return NULL; +} + /** * dfu_firmware_from_ihex: (skip) * @firmware: a #DfuFirmware @@ -63,25 +91,19 @@ DfuFirmwareParseFlags flags, GError **error) { - const gchar *in_buffer; + const gchar *data; gboolean got_eof = FALSE; - gsize len_in; - guint16 addr_high = 0; - guint16 addr_low = 0; - guint32 addr32 = 0; - guint32 addr32_last = 0; - guint32 element_address = 0; - guint8 checksum; - guint8 data_tmp; - guint8 len_tmp; - guint8 type; - guint end; - guint offset = 0; + gsize sz = 0; + guint32 abs_addr = 0x0; + guint32 addr_last = 0x0; + guint32 base_addr = 0x0; + guint32 seg_addr = 0x0; + g_auto(GStrv) lines = NULL; g_autoptr(DfuElement) element = NULL; g_autoptr(DfuImage) image = NULL; g_autoptr(GBytes) contents = NULL; - g_autoptr(GString) string = NULL; - g_autoptr(GString) signature = g_string_new (NULL); + g_autoptr(GString) buf = g_string_new (NULL); + g_autoptr(GString) buf_signature = g_string_new (NULL); g_return_val_if_fail (bytes != NULL, FALSE); @@ -91,95 +113,110 @@ element = dfu_element_new (); /* parse records */ - in_buffer = g_bytes_get_data (bytes, &len_in); - string = g_string_new (""); - while (offset < len_in) { + data = g_bytes_get_data (bytes, &sz); + lines = dfu_utils_strnsplit (data, sz, "\n", -1); + for (guint ln = 0; lines[ln] != NULL; ln++) { + const gchar *line = lines[ln]; + gsize linesz; + guint32 addr; + guint8 byte_cnt; + guint8 record_type; + guint line_end; + + /* ignore comments */ + if (g_str_has_prefix (line, ";")) + continue; + + /* ignore blank lines */ + g_strdelimit (lines[ln], "\r\x1a", '\0'); + linesz = strlen (line); + if (linesz == 0) + continue; /* check starting token */ - if (in_buffer[offset] != ':') { + if (line[0] != ':') { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "invalid starting token, got %c at %x", - in_buffer[offset], offset); + "invalid starting token on line %u: %s", + ln + 1, line); return FALSE; } /* check there's enough data for the smallest possible record */ - if (offset + 12 > (guint) len_in) { + if (linesz < 11) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "record incomplete at %u, length %u", - offset, (guint) len_in); + "line %u is incomplete, length %u", + ln + 1, (guint) linesz); return FALSE; } /* length, 16-bit address, type */ - len_tmp = dfu_utils_buffer_parse_uint8 (in_buffer + offset + 1); - addr_low = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 3); - type = dfu_utils_buffer_parse_uint8 (in_buffer + offset + 7); + byte_cnt = dfu_utils_buffer_parse_uint8 (line + 1); + addr = dfu_utils_buffer_parse_uint16 (line + 3); + record_type = dfu_utils_buffer_parse_uint8 (line + 7); + g_debug ("%s:", dfu_firmware_ihex_record_type_to_string (record_type)); + g_debug (" addr_start:\t0x%04x", addr); + g_debug (" length:\t0x%02x", byte_cnt); + addr += seg_addr; + addr += abs_addr; + g_debug (" addr:\t0x%08x", addr); /* position of checksum */ - end = offset + 9 + len_tmp * 2; - if (end > (guint) len_in) { + line_end = 9 + byte_cnt * 2; + if (line_end > (guint) linesz) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "checksum > file length: %u", - end); + "line %u malformed, length: %u", + ln + 1, line_end); return FALSE; } /* verify checksum */ if ((flags & DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST) == 0) { - checksum = 0; - for (guint i = offset + 1; i < end + 2; i += 2) { - data_tmp = dfu_utils_buffer_parse_uint8 (in_buffer + i); + guint8 checksum = 0; + for (guint i = 1; i < line_end + 2; i += 2) { + guint8 data_tmp = dfu_utils_buffer_parse_uint8 (line + i); checksum += data_tmp; } if (checksum != 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "invalid record checksum at 0x%04x " - "to 0x%04x, got 0x%02x", - offset, end, checksum); + "line %u has invalid checksum (0x%02x)", + ln + 1, checksum); return FALSE; } } /* process different record types */ - switch (type) { + switch (record_type) { case DFU_INHX32_RECORD_TYPE_DATA: - /* if not contiguous with previous record */ - if ((addr_high + addr_low) != addr32) { - if (addr32 == 0x0) { - g_debug ("base address %08x", addr_low); - dfu_element_set_address (element, addr_low); - } - addr32 = ((guint32) addr_high << 16) + addr_low; - if (element_address == 0x0) - element_address = addr32; - } + /* base address for element */ + if (base_addr == 0x0) + base_addr = addr; /* does not make sense */ - if (addr32 < addr32_last) { + if (addr < addr_last) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "invalid address 0x%x, last was 0x%x", - (guint) addr32, - (guint) addr32_last); + (guint) addr, + (guint) addr_last); return FALSE; } /* parse bytes from line */ - g_debug ("writing data 0x%08x", (guint32) addr32); - for (guint i = offset + 9; i < end; i += 2) { + g_debug ("writing data 0x%08x", (guint32) addr); + for (guint i = 9; i < line_end; i += 2) { /* any holes in the hex record */ - guint32 len_hole = addr32 - addr32_last; - if (addr32_last > 0 && len_hole > 0x100000) { + guint32 len_hole = addr - addr_last; + guint8 data_tmp; + if (addr_last > 0 && len_hole > 0x100000) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, @@ -187,19 +224,19 @@ (guint) len_hole); return FALSE; } - if (addr32_last > 0x0 && len_hole > 1) { + if (addr_last > 0x0 && len_hole > 1) { + g_debug ("filling address 0x%08x to 0x%08x", + addr_last + 1, addr_last + len_hole - 1); for (guint j = 1; j < len_hole; j++) { - g_debug ("filling address 0x%08x", - addr32_last + j); /* although 0xff might be clearer, * we can't write 0xffff to pic14 */ - g_string_append_c (string, 0x00); + g_string_append_c (buf, 0x00); } } /* write into buf */ - data_tmp = dfu_utils_buffer_parse_uint8 (in_buffer + i); - g_string_append_c (string, (gchar) data_tmp); - addr32_last = addr32++; + data_tmp = dfu_utils_buffer_parse_uint8 (line + i); + g_string_append_c (buf, (gchar) data_tmp); + addr_last = addr++; } break; case DFU_INHX32_RECORD_TYPE_EOF: @@ -213,25 +250,28 @@ } got_eof = TRUE; break; - case DFU_INHX32_RECORD_TYPE_EXTENDED: - addr_high = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 9); - addr32 = ((guint32) addr_high << 16) + addr_low; + case DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR: + abs_addr = dfu_utils_buffer_parse_uint16 (line + 9) << 16; + g_debug (" abs_addr:\t0x%02x", abs_addr); break; - case DFU_INHX32_RECORD_TYPE_ADDR32: - addr32 = dfu_utils_buffer_parse_uint32 (in_buffer + offset + 9); + case DFU_INHX32_RECORD_TYPE_START_LINEAR: + abs_addr = dfu_utils_buffer_parse_uint32 (line + 9); + g_debug (" abs_addr:\t0x%08x", abs_addr); break; case DFU_INHX32_RECORD_TYPE_EXTENDED_SEGMENT: /* segment base address, so ~1Mb addressable */ - addr32 = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 9) * 16; + seg_addr = dfu_utils_buffer_parse_uint16 (line + 9) * 16; + g_debug (" seg_addr:\t0x%08x", seg_addr); break; case DFU_INHX32_RECORD_TYPE_START_SEGMENT: /* initial content of the CS:IP registers */ - addr32 = dfu_utils_buffer_parse_uint32 (in_buffer + offset + 9); + seg_addr = dfu_utils_buffer_parse_uint32 (line + 9); + g_debug (" seg_addr:\t0x%02x", seg_addr); break; case DFU_INHX32_RECORD_TYPE_SIGNATURE: - for (guint i = offset + 9; i < end; i += 2) { - guint8 tmp_c = dfu_utils_buffer_parse_uint8 (in_buffer + i); - g_string_append_c (signature, tmp_c); + for (guint i = 9; i < line_end; i += 2) { + guint8 tmp_c = dfu_utils_buffer_parse_uint8 (line + i); + g_string_append_c (buf_signature, tmp_c); } break; default: @@ -242,17 +282,9 @@ FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "invalid ihex record type %i", - type); + record_type); return FALSE; } - - /* ignore any line return */ - offset = end + 2; - for (; offset < len_in; offset++) { - if (in_buffer[offset] != '\n' && - in_buffer[offset] != '\r') - break; - } } /* no EOF */ @@ -265,19 +297,19 @@ } /* add single image */ - contents = g_bytes_new (string->str, string->len); + contents = g_bytes_new (buf->str, buf->len); dfu_element_set_contents (element, contents); - dfu_element_set_address (element, element_address); + dfu_element_set_address (element, base_addr); dfu_image_add_element (image, element); dfu_firmware_add_image (firmware, image); dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_INTEL_HEX); /* add optional signature */ - if (signature->len > 0) { + if (buf_signature->len > 0) { g_autoptr(DfuElement) element_sig = dfu_element_new (); g_autoptr(DfuImage) image_sig = dfu_image_new (); - g_autoptr(GBytes) data = g_bytes_new_static (signature->str, signature->len); - dfu_element_set_contents (element_sig, data); + g_autoptr(GBytes) data_sig = g_bytes_new_static (buf_signature->str, buf_signature->len); + dfu_element_set_contents (element_sig, data_sig); dfu_image_add_element (image_sig, element_sig); dfu_image_set_name (image_sig, "signature"); dfu_firmware_add_image (firmware, image_sig); @@ -329,7 +361,7 @@ guint8 buf[2]; fu_common_write_uint16 (buf, address_offset, G_BIG_ENDIAN); dfu_firmware_ihex_emit_chunk (str, 0x0, - DFU_INHX32_RECORD_TYPE_EXTENDED, + DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR, buf, 2); address_offset_last = address_offset; } diff -Nru fwupd-1.1.4/plugins/dfu/dfu-format-ihex.h fwupd-1.2.5/plugins/dfu/dfu-format-ihex.h --- fwupd-1.1.4/plugins/dfu/dfu-format-ihex.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-format-ihex.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_FORMAT_IHEX_H -#define __DFU_FORMAT_IHEX_H +#pragma once #include #include @@ -23,5 +22,3 @@ GError **error); G_END_DECLS - -#endif /* __DFU_FORMAT_IHEX_H */ diff -Nru fwupd-1.1.4/plugins/dfu/dfu-format-metadata.h fwupd-1.2.5/plugins/dfu/dfu-format-metadata.h --- fwupd-1.1.4/plugins/dfu/dfu-format-metadata.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-format-metadata.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_FORMAT_METADATA_H -#define __DFU_FORMAT_METADATA_H +#pragma once #include #include @@ -22,5 +21,3 @@ GError **error); G_END_DECLS - -#endif /* __DFU_FORMAT_METADATA_H */ diff -Nru fwupd-1.1.4/plugins/dfu/dfu-format-raw.h fwupd-1.2.5/plugins/dfu/dfu-format-raw.h --- fwupd-1.1.4/plugins/dfu/dfu-format-raw.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-format-raw.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_FORMAT_RAW_H -#define __DFU_FORMAT_RAW_H +#pragma once #include #include @@ -23,5 +22,3 @@ GError **error); G_END_DECLS - -#endif /* __DFU_FORMAT_RAW_H */ diff -Nru fwupd-1.1.4/plugins/dfu/dfu-format-srec.c fwupd-1.2.5/plugins/dfu/dfu-format-srec.c --- fwupd-1.1.4/plugins/dfu/dfu-format-srec.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-format-srec.c 2019-02-25 09:42:18.000000000 +0000 @@ -38,15 +38,6 @@ return DFU_FIRMWARE_FORMAT_SREC; } -typedef enum { - DFU_SREC_RECORD_CLASS_UNKNOWN, - DFU_SREC_RECORD_CLASS_HEADER, - DFU_SREC_RECORD_CLASS_DATA, - DFU_SREC_RECORD_CLASS_TERMINATION, - DFU_SREC_RECORD_CLASS_COUNT, - DFU_SREC_RECORD_CLASS_LAST -} DfuSrecClassType; - /** * dfu_firmware_from_srec: (skip) * @firmware: a #DfuFirmware @@ -65,65 +56,67 @@ DfuFirmwareParseFlags flags, GError **error) { - const gchar *in_buffer; + const gchar *data; gboolean got_eof = FALSE; gboolean got_hdr = FALSE; - gsize len_in; - guint16 class_data_cnt = 0; + gsize sz = 0; + guint16 data_cnt = 0; guint32 addr32_last = 0; guint32 element_address = 0; - guint offset = 0; - g_autoptr(DfuElement) element = NULL; + g_auto(GStrv) lines = NULL; + g_autoptr(DfuElement) element = dfu_element_new (); g_autoptr(GBytes) contents = NULL; - g_autoptr(GString) modname = g_string_new (NULL); - g_autoptr(GString) outbuf = NULL; + g_autoptr(GString) outbuf = g_string_new (NULL); g_return_val_if_fail (bytes != NULL, FALSE); - /* create element */ - element = dfu_element_new (); - /* parse records */ - in_buffer = g_bytes_get_data (bytes, &len_in); - outbuf = g_string_new (""); - while (offset < len_in) { - DfuSrecClassType rec_class = DFU_SREC_RECORD_CLASS_UNKNOWN; + data = g_bytes_get_data (bytes, &sz); + lines = dfu_utils_strnsplit (data, sz, "\n", -1); + for (guint ln = 0; lines[ln] != NULL; ln++) { + const gchar *line = lines[ln]; + gsize linesz; guint32 rec_addr32; - guint8 rec_count; /* bytes */ - guint8 rec_dataoffset; /* bytes */ + guint8 addrsz = 0; /* bytes */ + guint8 rec_count; /* words */ guint8 rec_kind; + /* ignore blank lines */ + g_strdelimit (lines[ln], "\r", '\0'); + linesz = strlen (line); + if (linesz == 0) + continue; + /* check starting token */ - if (in_buffer[offset] != 'S') { + if (line[0] != 'S') { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "invalid starting token, got 0x%02x at 0x%x", - (guint) in_buffer[offset], offset); + "invalid starting token, got '%c' at line %u", + line[0], ln); return FALSE; } /* check there's enough data for the smallest possible record */ - if (offset + 10 > (guint) len_in) { + if (linesz < 10) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "record incomplete at %u, length %u", - offset, (guint) len_in); + "record incomplete at line %u, length %u", + ln, (guint) linesz); return FALSE; } /* kind, count, address, (data), checksum, linefeed */ - rec_kind = in_buffer[offset + 1]; - rec_count = dfu_utils_buffer_parse_uint8 (in_buffer + offset + 2); - - /* check we can read out this much data */ - if (len_in < offset + (rec_count * 2) + 4) { + rec_kind = line[1] - '0'; + rec_count = dfu_utils_buffer_parse_uint8 (line + 2); + if (rec_count * 2 != linesz - 4) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "file incomplete at %u, length %u", - offset, (guint) len_in); + "count incomplete at line %u, " + "length %u, expected %u", + ln, (guint) linesz - 4, (guint) rec_count * 2); return FALSE; } @@ -132,28 +125,24 @@ guint8 rec_csum = 0; guint8 rec_csum_expected; for (guint8 i = 0; i < rec_count; i++) - rec_csum += dfu_utils_buffer_parse_uint8 (in_buffer + offset + (i * 2) + 2); + rec_csum += dfu_utils_buffer_parse_uint8 (line + (i * 2) + 2); rec_csum ^= 0xff; - rec_csum_expected = dfu_utils_buffer_parse_uint8 (in_buffer + offset + (rec_count * 2) + 2); + rec_csum_expected = dfu_utils_buffer_parse_uint8 (line + (rec_count * 2) + 2); if (rec_csum != rec_csum_expected) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "checksum incorrect @ 0x%04x, expected %02x, got %02x", - offset, rec_csum_expected, rec_csum); + "checksum incorrect line %u, " + "expected %02x, got %02x", + ln, rec_csum_expected, rec_csum); return FALSE; } } - /* record kind + record count (in bytes, not chars) */ - rec_dataoffset = 2; - - /* parse record */ + /* set each command settings */ switch (rec_kind) { - case '0': - rec_class = DFU_SREC_RECORD_CLASS_HEADER; - rec_dataoffset += 2; - rec_addr32 = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 4); + case 0: + addrsz = 2; if (got_hdr) { g_set_error_literal (error, FWUPD_ERROR, @@ -161,6 +150,63 @@ "duplicate header record"); return FALSE; } + got_hdr = TRUE; + break; + case 1: + addrsz = 2; + break; + case 2: + addrsz = 3; + break; + case 3: + addrsz = 4; + break; + case 5: + addrsz = 2; + got_eof = TRUE; + break; + case 6: + addrsz = 3; + break; + case 7: + addrsz = 4; + got_eof = TRUE; + break; + case 8: + addrsz = 3; + got_eof = TRUE; + break; + case 9: + addrsz = 2; + got_eof = TRUE; + break; + default: + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid srec record type S%c", + line[1]); + return FALSE; + } + + /* parse address */ + switch (addrsz) { + case 2: + rec_addr32 = dfu_utils_buffer_parse_uint16 (line + 4); + break; + case 3: + rec_addr32 = dfu_utils_buffer_parse_uint24 (line + 4); + break; + case 4: + rec_addr32 = dfu_utils_buffer_parse_uint32 (line + 4); + break; + default: + g_assert_not_reached (); + } + + /* header */ + if (rec_kind == 0) { + g_autoptr(GString) modname = g_string_new (NULL); if (rec_addr32 != 0x0) { g_set_error (error, FWUPD_ERROR, @@ -169,76 +215,34 @@ rec_addr32); return FALSE; } + /* could be anything, lets assume text */ - for (guint8 i = rec_dataoffset; i <= rec_count; i++) { - guint8 tmp = dfu_utils_buffer_parse_uint8 (in_buffer + offset + (i * 2)); + for (guint8 i = 4 + (addrsz * 2); i <= rec_count * 2; i += 2) { + guint8 tmp = dfu_utils_buffer_parse_uint8 (line + i); if (!g_ascii_isgraph (tmp)) break; g_string_append_c (modname, tmp); } if (modname->len != 0) dfu_image_set_name (image, modname->str); - got_hdr = TRUE; - break; - case '1': - rec_class = DFU_SREC_RECORD_CLASS_DATA; - rec_dataoffset += 2; - rec_addr32 = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 4); - break; - case '2': - rec_class = DFU_SREC_RECORD_CLASS_DATA; - rec_dataoffset += 3; - rec_addr32 = dfu_utils_buffer_parse_uint24 (in_buffer + offset + 4); - break; - case '3': - rec_class = DFU_SREC_RECORD_CLASS_DATA; - rec_dataoffset += 4; - rec_addr32 = dfu_utils_buffer_parse_uint32 (in_buffer + offset + 4); - break; - case '9': - rec_class = DFU_SREC_RECORD_CLASS_TERMINATION; - rec_addr32 = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 4); - got_eof = TRUE; - break; - case '8': - rec_class = DFU_SREC_RECORD_CLASS_TERMINATION; - rec_addr32 = dfu_utils_buffer_parse_uint24 (in_buffer + offset + 4); - got_eof = TRUE; - break; - case '7': - rec_class = DFU_SREC_RECORD_CLASS_TERMINATION; - rec_addr32 = dfu_utils_buffer_parse_uint32 (in_buffer + offset + 4); - got_eof = TRUE; - break; - case '5': - rec_class = DFU_SREC_RECORD_CLASS_COUNT; - rec_addr32 = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 4); - if (rec_addr32 != class_data_cnt) { + continue; + } + + /* verify we got all records */ + if (rec_kind == 5) { + if (rec_addr32 != data_cnt) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "count record was not valid, got 0x%02x expected 0x%02x", - (guint) rec_addr32, (guint) class_data_cnt); + (guint) rec_addr32, (guint) data_cnt); return FALSE; } - got_eof = TRUE; - break; - default: - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "invalid srec record type S%c", - rec_kind); - return FALSE; } - /* record EOF */ - if (rec_class == DFU_SREC_RECORD_CLASS_TERMINATION) - g_debug ("start execution location: 0x%04x", (guint) rec_addr32); - - /* read data */ - if (rec_class == DFU_SREC_RECORD_CLASS_DATA) { - /* probably invalid data */ + /* data */ + if (rec_kind == 1 || rec_kind == 2 || rec_kind == 3) { + /* invalid */ if (!got_hdr) { g_set_error_literal (error, FWUPD_ERROR, @@ -260,23 +264,36 @@ g_debug ("ignoring data at 0x%x as before start address 0x%x", (guint) rec_addr32, (guint) start_addr); } else { - for (guint8 i = rec_dataoffset; i <= rec_count; i++) { - guint8 tmp = dfu_utils_buffer_parse_uint8 (in_buffer + offset + (i * 2)); + guint bytecnt = 0; + guint32 len_hole = rec_addr32 - addr32_last; + + /* fill any holes, but only up to 1Mb to avoid a DoS */ + if (addr32_last > 0 && len_hole > 0x100000) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "hole of 0x%x bytes too large to fill", + (guint) len_hole); + return FALSE; + } + if (addr32_last > 0x0 && len_hole > 1) { + g_debug ("filling address 0x%08x to 0x%08x", + addr32_last + 1, addr32_last + len_hole - 1); + for (guint j = 0; j < len_hole; j++) + g_string_append_c (outbuf, 0xff); + } + + /* add data */ + for (guint8 i = 4 + (addrsz * 2); i <= rec_count * 2; i += 2) { + guint8 tmp = dfu_utils_buffer_parse_uint8 (line + i); g_string_append_c (outbuf, tmp); + bytecnt++; } if (element_address == 0x0) element_address = rec_addr32; + addr32_last = rec_addr32 + bytecnt; } - addr32_last = rec_addr32++; - class_data_cnt++; - } - - /* ignore any line return */ - offset += (rec_count * 2) + 4; - for (; offset < len_in; offset++) { - if (in_buffer[offset] != '\n' && - in_buffer[offset] != '\r') - break; + data_cnt++; } } diff -Nru fwupd-1.1.4/plugins/dfu/dfu-format-srec.h fwupd-1.2.5/plugins/dfu/dfu-format-srec.h --- fwupd-1.1.4/plugins/dfu/dfu-format-srec.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-format-srec.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_FORMAT_SREC_H -#define __DFU_FORMAT_SREC_H +#pragma once #include #include @@ -28,5 +27,3 @@ GError **error); G_END_DECLS - -#endif /* __DFU_FORMAT_SREC_H */ diff -Nru fwupd-1.1.4/plugins/dfu/dfu-image.h fwupd-1.2.5/plugins/dfu/dfu-image.h --- fwupd-1.1.4/plugins/dfu/dfu-image.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-image.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_IMAGE_H -#define __DFU_IMAGE_H +#pragma once #include #include @@ -43,5 +42,3 @@ gchar *dfu_image_to_string (DfuImage *image); G_END_DECLS - -#endif /* __DFU_IMAGE_H */ diff -Nru fwupd-1.1.4/plugins/dfu/dfu-patch.h fwupd-1.2.5/plugins/dfu/dfu-patch.h --- fwupd-1.1.4/plugins/dfu/dfu-patch.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-patch.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_PATCH_H -#define __DFU_PATCH_H +#pragma once #include #include @@ -54,5 +53,3 @@ GBytes *dfu_patch_get_checksum_new (DfuPatch *self); G_END_DECLS - -#endif /* __DFU_PATCH_H */ diff -Nru fwupd-1.1.4/plugins/dfu/dfu.quirk fwupd-1.2.5/plugins/dfu/dfu.quirk --- fwupd-1.1.4/plugins/dfu/dfu.quirk 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu.quirk 2019-02-25 09:42:18.000000000 +0000 @@ -1,3 +1,7 @@ +# All DFU devices +[DeviceInstanceId=USB\CLASS_FE&SUBCLASS_01] +Plugin = dfu + # on PC platforms the DW1820A firmware is loaded at runtime and can't # be stored on the device itself as the flash chip is unpopulated [DeviceInstanceId=USB\VID_0A5C&PID_6412] @@ -130,6 +134,7 @@ Plugin = dfu DfuFlags = use-any-interface,legacy-protocol,force-dfu-mode [DeviceInstanceId=USB\VID_03EB&PID_2FF4] +Plugin = dfu DfuFlags = use-any-interface,legacy-protocol,force-dfu-mode # Atmel XMEGA Bootloader diff -Nru fwupd-1.1.4/plugins/dfu/dfu-sector.h fwupd-1.2.5/plugins/dfu/dfu-sector.h --- fwupd-1.1.4/plugins/dfu/dfu-sector.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-sector.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_SECTOR_H -#define __DFU_SECTOR_H +#pragma once #include #include @@ -49,5 +48,3 @@ gchar *dfu_sector_to_string (DfuSector *sector); G_END_DECLS - -#endif /* __DFU_SECTOR_H */ diff -Nru fwupd-1.1.4/plugins/dfu/dfu-sector-private.h fwupd-1.2.5/plugins/dfu/dfu-sector-private.h --- fwupd-1.1.4/plugins/dfu/dfu-sector-private.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-sector-private.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_SECTOR_PRIVATE_H -#define __DFU_SECTOR_PRIVATE_H +#pragma once #include "dfu-sector.h" @@ -19,5 +18,3 @@ DfuSectorCap cap); G_END_DECLS - -#endif /* __DFU_SECTOR_PRIVATE_H */ diff -Nru fwupd-1.1.4/plugins/dfu/dfu-target-avr.h fwupd-1.2.5/plugins/dfu/dfu-target-avr.h --- fwupd-1.1.4/plugins/dfu/dfu-target-avr.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-target-avr.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_TARGET_AVR_H -#define __DFU_TARGET_AVR_H +#pragma once #include #include @@ -25,5 +24,3 @@ DfuTarget *dfu_target_avr_new (void); G_END_DECLS - -#endif /* __DFU_TARGET_AVR_H */ diff -Nru fwupd-1.1.4/plugins/dfu/dfu-target.h fwupd-1.2.5/plugins/dfu/dfu-target.h --- fwupd-1.1.4/plugins/dfu/dfu-target.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-target.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_TARGET_H -#define __DFU_TARGET_H +#pragma once #include #include @@ -91,5 +90,3 @@ DfuCipherKind dfu_target_get_cipher_kind (DfuTarget *target); G_END_DECLS - -#endif /* __DFU_TARGET_H */ diff -Nru fwupd-1.1.4/plugins/dfu/dfu-target-private.h fwupd-1.2.5/plugins/dfu/dfu-target-private.h --- fwupd-1.1.4/plugins/dfu/dfu-target-private.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-target-private.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_TARGET_PRIVATE_H -#define __DFU_TARGET_PRIVATE_H +#pragma once #include @@ -56,5 +55,3 @@ GError **error); G_END_DECLS - -#endif /* __DFU_TARGET_PRIVATE_H */ diff -Nru fwupd-1.1.4/plugins/dfu/dfu-target-stm.h fwupd-1.2.5/plugins/dfu/dfu-target-stm.h --- fwupd-1.1.4/plugins/dfu/dfu-target-stm.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-target-stm.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_TARGET_STM_H -#define __DFU_TARGET_STM_H +#pragma once #include #include @@ -25,5 +24,3 @@ DfuTarget *dfu_target_stm_new (void); G_END_DECLS - -#endif /* __DFU_TARGET_STM_H */ diff -Nru fwupd-1.1.4/plugins/dfu/dfu-tool.c fwupd-1.2.5/plugins/dfu/dfu-tool.c --- fwupd-1.1.4/plugins/dfu/dfu-tool.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/dfu-tool.c 2019-02-25 09:42:18.000000000 +0000 @@ -11,7 +11,6 @@ #include #include #include -#include #include "dfu-cipher-xtea.h" #include "dfu-device-private.h" @@ -50,6 +49,7 @@ if (priv == NULL) return; g_free (priv->device_vid_pid); + g_object_unref (priv->progressbar); g_object_unref (priv->cancellable); g_object_unref (priv->quirks); if (priv->cmd_array != NULL) @@ -480,7 +480,7 @@ g_return_val_if_fail (search_sz == replace_sz, FALSE); /* find and replace each one */ - for (gsize i = 0; i < data_sz - search_sz; i++) { + for (gsize i = 0; i < data_sz - search_sz + 1; i++) { if (memcmp (data_buf + i, search_buf, search_sz) == 0) { g_print ("Replacing %" G_GSIZE_FORMAT " bytes @0x%04x\n", replace_sz, (guint) i); @@ -675,7 +675,7 @@ if (cnt == 0) { g_set_error_literal (error, FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, + FWUPD_ERROR_NOT_FOUND, "search string was not found"); return FALSE; } @@ -2036,8 +2036,8 @@ dfu_device_set_usb_context (device, usb_context); if (!fu_device_probe (FU_DEVICE (device), NULL)) continue; - version = as_utils_version_from_uint16 (g_usb_device_get_release (usb_device), - AS_VERSION_PARSE_FLAG_USE_BCD); + version = fu_common_version_from_uint16 (g_usb_device_get_release (usb_device), + FU_VERSION_FORMAT_BCD); g_print ("%s %04x:%04x [v%s]:\n", /* TRANSLATORS: detected a DFU device */ _("Found"), @@ -2427,6 +2427,5 @@ } /* success/ */ - g_object_unref (priv->progressbar); return EXIT_SUCCESS; } diff -Nru fwupd-1.1.4/plugins/dfu/fu-plugin-dfu.c fwupd-1.2.5/plugins/dfu/fu-plugin-dfu.c --- fwupd-1.1.4/plugins/dfu/fu-plugin-dfu.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/fu-plugin-dfu.c 2019-02-25 09:42:18.000000000 +0000 @@ -6,12 +6,19 @@ #include "config.h" -#include - #include "fu-plugin-vfuncs.h" #include "dfu-device.h" +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.usb.dfu"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.st.dfuse"); +} + static void fu_plugin_dfu_state_changed_cb (DfuDevice *device, DfuState state, diff -Nru fwupd-1.1.4/plugins/dfu/meson.build fwupd-1.2.5/plugins/dfu/meson.build --- fwupd-1.1.4/plugins/dfu/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -6,6 +6,7 @@ dfu = static_library( 'dfu', + fu_hash, sources : [ 'dfu-cipher-xtea.c', 'dfu-common.c', @@ -26,12 +27,14 @@ 'dfu-target-avr.c', ], dependencies : [ - appstream_glib, giounix, libm, gusb, gudev, ], + link_with : [ + libfwupdprivate, + ], c_args : cargs, include_directories : [ include_directories('../..'), @@ -41,6 +44,7 @@ ) shared_module('fu_plugin_dfu', + fu_hash, sources : [ 'fu-plugin-dfu.c', ], @@ -56,12 +60,14 @@ plugin_deps, ], link_with : [ + libfwupdprivate, dfu, ], ) dfu_tool = executable( 'dfu-tool', + fu_hash, sources : [ 'dfu-tool.c', ], @@ -72,7 +78,7 @@ include_directories('../../libfwupd'), ], dependencies : [ - appstream_glib, + libxmlb, giounix, libm, gusb, @@ -80,7 +86,6 @@ ], link_with : [ dfu, - fwupd, libfwupdprivate, ], c_args : cargs, @@ -113,6 +118,7 @@ cargs += '-DTESTDATADIR="' + testdatadir + '"' e = executable( 'dfu-self-test', + fu_hash, sources : [ 'dfu-self-test.c' ], @@ -123,7 +129,7 @@ include_directories('../../src'), ], dependencies : [ - appstream_glib, + libxmlb, gio, gusb, gudev, @@ -131,7 +137,6 @@ ], link_with : [ dfu, - fwupd, libfwupdprivate, ], c_args : cargs diff -Nru fwupd-1.1.4/plugins/dfu/README.md fwupd-1.2.5/plugins/dfu/README.md --- fwupd-1.1.4/plugins/dfu/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/dfu/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -6,3 +6,33 @@ Device Firmware Update is a standard that allows USB devices to be easily and safely updated by any operating system. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +DFU or DfuSe file format. + +This plugin supports the following protocol IDs: + + * org.usb.dfu + * com.st.dfuse + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_273F&PID_1003&REV_0001` + * `USB\VID_273F&PID_1003` + * `USB\VID_273F` + +Quirk use +--------- +This plugin uses the following plugin-specific quirks: + +| Quirk | Description | Minimum fwupd version | +|------------------------|---------------------------------------------|-----------------------| +|`DfuFlags` | Optional quirks for a DFU device which doesn't follow the DFU 1.0 or 1.1 specification | 1.0.1| +|`DfuForceVersion` | Forces a specific DFU version for the hardware device. This is required if the device does not set, or sets incorrectly, items in the DFU functional descriptor. |1.0.1| +|`DfuJabraDetach` | Assigns the two magic bytes sent to the Jabra hardware when the device is in runtime mode to make it switch into DFU mode.|1.0.1| diff -Nru fwupd-1.1.4/plugins/ebitdo/ebitdo.quirk fwupd-1.2.5/plugins/ebitdo/ebitdo.quirk --- fwupd-1.1.4/plugins/ebitdo/ebitdo.quirk 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/ebitdo/ebitdo.quirk 2019-02-25 09:42:18.000000000 +0000 @@ -5,6 +5,7 @@ [DeviceInstanceId=USB\VID_2DC8&PID_5750] Plugin = ebitdo Flags = is-bootloader +InstallDuration = 120 # FC30 [DeviceInstanceId=USB\VID_1235&PID_AB11] @@ -13,6 +14,7 @@ [DeviceInstanceId=USB\VID_2DC8&PID_AB11] Plugin = ebitdo Flags = none +InstallDuration = 120 # NES30 [DeviceInstanceId=USB\VID_1235&PID_AB12] @@ -21,6 +23,7 @@ [DeviceInstanceId=USB\VID_2DC8&PID_AB12] Plugin = ebitdo Flags = none +InstallDuration = 120 # SFC30 [DeviceInstanceId=USB\VID_1235&PID_AB21] @@ -29,6 +32,7 @@ [DeviceInstanceId=USB\VID_2DC8&PID_AB21] Plugin = ebitdo Flags = none +InstallDuration = 120 # SNES30 [DeviceInstanceId=USB\VID_1235&PID_AB20] @@ -37,6 +41,7 @@ [DeviceInstanceId=USB\VID_2DC8&PID_AB20] Plugin = ebitdo Flags = none +InstallDuration = 120 # FC30PRO [DeviceInstanceId=USB\VID_1002&PID_9000] @@ -45,6 +50,7 @@ [DeviceInstanceId=USB\VID_2DC8&PID_9000] Plugin = ebitdo Flags = none +InstallDuration = 120 # NES30PRO [DeviceInstanceId=USB\VID_2002&PID_9000] @@ -53,6 +59,7 @@ [DeviceInstanceId=USB\VID_2DC8&PID_9001] Plugin = ebitdo Flags = none +InstallDuration = 120 # FC30_ARCADE [DeviceInstanceId=USB\VID_8000&PID_1002] @@ -61,6 +68,7 @@ [DeviceInstanceId=USB\VID_2DC8&PID_1002] Plugin = ebitdo Flags = none +InstallDuration = 120 # SF30 PRO/SN30 PRO ## Dinput mode (Start + B) @@ -70,7 +78,4 @@ [DeviceInstanceId=USB\VID_2DC8&PID_6001] Plugin = ebitdo Flags = none -## Xinput mode (Start + X) -[DeviceInstanceId=USB\VID_045E&PID_028E] -Plugin = ebitdo -Flags = none +InstallDuration = 120 diff -Nru fwupd-1.1.4/plugins/ebitdo/fu-ebitdo-common.c fwupd-1.2.5/plugins/ebitdo/fu-ebitdo-common.c --- fwupd-1.1.4/plugins/ebitdo/fu-ebitdo-common.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/ebitdo/fu-ebitdo-common.c 2019-02-25 09:42:18.000000000 +0000 @@ -65,20 +65,6 @@ } void -fu_ebitdo_dump_raw (const gchar *title, const guint8 *data, gsize len) -{ - g_print ("%s:", title); - for (gsize i = strlen (title); i < 16; i++) - g_print (" "); - for (gsize i = 0; i < len; i++) { - g_print ("%02x ", data[i]); - if (i > 0 && i % 32 == 0) - g_print ("\n"); - } - g_print ("\n"); -} - -void fu_ebitdo_dump_pkt (FuEbitdoPkt *hdr) { g_print ("PktLength: 0x%02x\n", hdr->pkt_len); diff -Nru fwupd-1.1.4/plugins/ebitdo/fu-ebitdo-common.h fwupd-1.2.5/plugins/ebitdo/fu-ebitdo-common.h --- fwupd-1.1.4/plugins/ebitdo/fu-ebitdo-common.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/ebitdo/fu-ebitdo-common.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_EBITDO_COMMON_H -#define __FU_EBITDO_COMMON_H +#pragma once #include @@ -70,8 +69,3 @@ const gchar *fu_ebitdo_pkt_type_to_string (FuEbitdoPktType type); void fu_ebitdo_dump_firmware_header (FuEbitdoFirmwareHeader *hdr); void fu_ebitdo_dump_pkt (FuEbitdoPkt *hdr); -void fu_ebitdo_dump_raw (const gchar *title, - const guint8 *data, - gsize len); - -#endif /* __FU_EBITDO_COMMON_H */ diff -Nru fwupd-1.1.4/plugins/ebitdo/fu-ebitdo-device.c fwupd-1.2.5/plugins/ebitdo/fu-ebitdo-device.c --- fwupd-1.1.4/plugins/ebitdo/fu-ebitdo-device.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/ebitdo/fu-ebitdo-device.c 2019-02-25 09:42:18.000000000 +0000 @@ -66,7 +66,7 @@ /* debug */ if (g_getenv ("FWUPD_EBITDO_VERBOSE") != NULL) { - fu_ebitdo_dump_raw ("->DEVICE", packet, (gsize) hdr->pkt_len + 1); + fu_common_dump_raw (G_LOG_DOMAIN, "->DEVICE", packet, (gsize) hdr->pkt_len + 1); fu_ebitdo_dump_pkt (hdr); } @@ -127,7 +127,7 @@ /* debug */ if (g_getenv ("FWUPD_EBITDO_VERBOSE") != NULL) { - fu_ebitdo_dump_raw ("<-DEVICE", packet, actual_length); + fu_common_dump_raw (G_LOG_DOMAIN, "<-DEVICE", packet, actual_length); fu_ebitdo_dump_pkt (hdr); } @@ -215,7 +215,7 @@ fu_ebitdo_device_set_version (FuEbitdoDevice *self, guint32 version) { g_autofree gchar *tmp = NULL; - tmp = g_strdup_printf ("%.2f", version / 100.f); + tmp = g_strdup_printf ("%u.%02u", version / 100, version % 100); fu_device_set_version (FU_DEVICE (self), tmp); } diff -Nru fwupd-1.1.4/plugins/ebitdo/fu-ebitdo-device.h fwupd-1.2.5/plugins/ebitdo/fu-ebitdo-device.h --- fwupd-1.1.4/plugins/ebitdo/fu-ebitdo-device.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/ebitdo/fu-ebitdo-device.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_EBITDO_DEVICE_H -#define __FU_EBITDO_DEVICE_H +#pragma once #include "fu-plugin.h" @@ -20,5 +19,3 @@ const guint32 *fu_ebitdo_device_get_serial (FuEbitdoDevice *device); G_END_DECLS - -#endif /* __FU_EBITDO_DEVICE_H */ diff -Nru fwupd-1.1.4/plugins/ebitdo/fu-plugin-ebitdo.c fwupd-1.2.5/plugins/ebitdo/fu-plugin-ebitdo.c --- fwupd-1.1.4/plugins/ebitdo/fu-plugin-ebitdo.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/ebitdo/fu-plugin-ebitdo.c 2019-02-25 09:42:18.000000000 +0000 @@ -13,7 +13,9 @@ void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.8bitdo"); } gboolean diff -Nru fwupd-1.1.4/plugins/ebitdo/meson.build fwupd-1.2.5/plugins/ebitdo/meson.build --- fwupd-1.1.4/plugins/ebitdo/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/ebitdo/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -5,6 +5,7 @@ ) shared_module('fu_plugin_ebitdo', + fu_hash, sources : [ 'fu-plugin-ebitdo.c', 'fu-ebitdo-common.c', @@ -17,6 +18,9 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff -Nru fwupd-1.1.4/plugins/ebitdo/README.md fwupd-1.2.5/plugins/ebitdo/README.md --- fwupd-1.1.4/plugins/ebitdo/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/ebitdo/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -11,3 +11,23 @@ The 8Bitdo devices share legacy USB VID/PIDs with other projects and so we have to be a bit careful to not claim other devices as our own. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. The binary file has a vendor-specific header +that is used when flashing the image. + +This plugin supports the following protocol ID: + + * com.8bitdo + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_2DC8&PID_AB11&REV_0001` + * `USB\VID_2DC8&PID_AB11` + * `USB\VID_2DC8` diff -Nru fwupd-1.1.4/plugins/fastboot/data/android/flashfile.xml fwupd-1.2.5/plugins/fastboot/data/android/flashfile.xml --- fwupd-1.1.4/plugins/fastboot/data/android/flashfile.xml 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/fastboot/data/android/flashfile.xml 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,6 @@ + + + + + + diff -Nru fwupd-1.1.4/plugins/fastboot/data/lsusb.txt fwupd-1.2.5/plugins/fastboot/data/lsusb.txt --- fwupd-1.1.4/plugins/fastboot/data/lsusb.txt 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/fastboot/data/lsusb.txt 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,58 @@ +Bus 001 Device 025: ID 18d1:4ee0 Google Inc. Nexus 4 (bootloader) +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x18d1 Google Inc. + idProduct 0x4ee0 Nexus 4 (bootloader) + bcdDevice 1.00 + iManufacturer 1 Google + iProduct 2 Android + iSerial 3 034412a082919b5c + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0020 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 500mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 66 + bInterfaceProtocol 3 + iInterface 4 fastboot + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 1 +Device Status: 0x0000 + (Bus Powered) diff -Nru fwupd-1.1.4/plugins/fastboot/data/qfil/partition_nand.xml fwupd-1.2.5/plugins/fastboot/data/qfil/partition_nand.xml --- fwupd-1.1.4/plugins/fastboot/data/qfil/partition_nand.xml 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/fastboot/data/qfil/partition_nand.xml 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,21 @@ + + + + 0xAA7D1B9A + 0x1F7D48BC + + 0x4 + + + 0:SBL + 0x8 + 0x2 + 0 + 0xFF + 0x01 + 0x00 + 0xFE + sbl1.mbn + + + diff -Nru fwupd-1.1.4/plugins/fastboot/fastboot.quirk fwupd-1.2.5/plugins/fastboot/fastboot.quirk --- fwupd-1.1.4/plugins/fastboot/fastboot.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/fastboot/fastboot.quirk 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,3 @@ +# All fastboot devices +[DeviceInstanceId=USB\CLASS_FF&SUBCLASS_42&PROT_03] +Plugin = fastboot diff -Nru fwupd-1.1.4/plugins/fastboot/fu-fastboot-device.c fwupd-1.2.5/plugins/fastboot/fu-fastboot-device.c --- fwupd-1.1.4/plugins/fastboot/fu-fastboot-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/fastboot/fu-fastboot-device.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,711 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-archive.h" +#include "fu-chunk.h" +#include "fu-fastboot-device.h" + +#define FASTBOOT_REMOVE_DELAY_RE_ENUMERATE 60000 /* ms */ +#define FASTBOOT_TRANSACTION_TIMEOUT 1000 /* ms */ +#define FASTBOOT_TRANSACTION_RETRY_MAX 600 +#define FASTBOOT_EP_IN 0x81 +#define FASTBOOT_EP_OUT 0x01 +#define FASTBOOT_CMD_BUFSZ 64 /* bytes */ + +struct _FuFastbootDevice { + FuUsbDevice parent_instance; + gboolean secure; + guint blocksz; + guint8 intf_nr; +}; + +G_DEFINE_TYPE (FuFastbootDevice, fu_fastboot_device, FU_TYPE_USB_DEVICE) + +static void +fu_fastboot_device_to_string (FuDevice *device, GString *str) +{ + FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); + g_string_append (str, " FuFastbootDevice:\n"); + g_string_append_printf (str, " intf:\t0x%02x\n", (guint) self->intf_nr); + g_string_append_printf (str, " secure:\t%i\n", self->secure); + g_string_append_printf (str, " blocksz:\t%u\n", self->blocksz); +} + +static gboolean +fu_fastboot_device_probe (FuDevice *device, GError **error) +{ + FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + g_autoptr(GUsbInterface) intf = NULL; + + /* find the correct fastboot interface */ + intf = g_usb_device_get_interface (usb_device, 0xff, 0x42, 0x03, error); + if (intf == NULL) + return FALSE; + self->intf_nr = g_usb_interface_get_number (intf); + return TRUE; +} + +static gboolean +fu_fastboot_device_open (FuUsbDevice *device, GError **error) +{ + FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (device); + + if (!g_usb_device_claim_interface (usb_device, self->intf_nr, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error)) { + g_prefix_error (error, "failed to claim interface: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +static void +fu_fastboot_buffer_dump (const gchar *title, const guint8 *buf, gsize sz) +{ + if (g_getenv ("FWUPD_FASTBOOT_VERBOSE") == NULL) + return; + g_print ("%s (%" G_GSIZE_FORMAT "):\n", title, sz); + for (gsize i = 0; i < sz; i++) { + g_print ("%02x[%c] ", buf[i], g_ascii_isprint (buf[i]) ? buf[i] : '?'); + if (i > 0 && (i + 1) % 256 == 0) + g_print ("\n"); + } + g_print ("\n"); +} + +static gboolean +fu_fastboot_device_write (FuDevice *device, const guint8 *buf, gsize buflen, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + gboolean ret; + gsize actual_len = 0; + g_autofree guint8 *buf2 = g_memdup (buf, (guint) buflen); + + fu_fastboot_buffer_dump ("writing", buf, buflen); + ret = g_usb_device_bulk_transfer (usb_device, + FASTBOOT_EP_OUT, + buf2, + buflen, + &actual_len, + FASTBOOT_TRANSACTION_TIMEOUT, + NULL, error); + if (!ret) { + g_prefix_error (error, "failed to do bulk transfer: "); + return FALSE; + } + if (actual_len != buflen) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "only wrote %" G_GSIZE_FORMAT "bytes", actual_len); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_fastboot_device_writestr (FuDevice *device, const gchar *str, GError **error) +{ + gsize buflen = strlen (str); + if (buflen > FASTBOOT_CMD_BUFSZ - 4) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "fastboot limits writes to %i bytes", + FASTBOOT_CMD_BUFSZ - 4); + return FALSE; + } + return fu_fastboot_device_write (device, (const guint8 *) str, buflen, error); +} + +typedef enum { + FU_FASTBOOT_DEVICE_READ_FLAG_NONE, + FU_FASTBOOT_DEVICE_READ_FLAG_STATUS_POLL, +} FuFastbootDeviceReadFlags; + +static gboolean +fu_fastboot_device_read (FuDevice *device, + gchar **str, + FuFastbootDeviceReadFlags flags, + GError **error) +{ + FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + guint retries = 1; + + /* these commands may return INFO or take some time to complete */ + if (flags & FU_FASTBOOT_DEVICE_READ_FLAG_STATUS_POLL) + retries = FASTBOOT_TRANSACTION_RETRY_MAX; + + for (guint i = 0; i < retries; i++) { + gboolean ret; + gsize actual_len = 0; + guint8 buf[FASTBOOT_CMD_BUFSZ] = { 0x00 }; + g_autofree gchar *tmp = NULL; + g_autoptr(GError) error_local = NULL; + + ret = g_usb_device_bulk_transfer (usb_device, + FASTBOOT_EP_IN, + buf, + sizeof(buf), + &actual_len, + FASTBOOT_TRANSACTION_TIMEOUT, + NULL, &error_local); + if (!ret) { + if (g_error_matches (error_local, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_TIMED_OUT)) { + g_debug ("ignoring %s", error_local->message); + continue; + } + g_propagate_prefixed_error (error, + g_steal_pointer (&error_local), + "failed to do bulk transfer: "); + return FALSE; + } + fu_fastboot_buffer_dump ("read", buf, actual_len); + if (actual_len < 4) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "only read %" G_GSIZE_FORMAT "bytes", actual_len); + return FALSE; + } + + /* info */ + tmp = g_strndup ((const gchar *) buf + 4, self->blocksz - 4); + if (memcmp (buf, "INFO", 4) == 0) { + if (g_strcmp0 (tmp, "erasing flash") == 0) + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + else if (g_strcmp0 (tmp, "writing flash") == 0) + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + else + g_debug ("INFO returned unknown: %s", tmp); + continue; + } + + /* success */ + if (memcmp (buf, "OKAY", 4) == 0 || memcmp (buf, "DATA", 4) == 0) { + if (str != NULL) + *str = g_steal_pointer (&tmp); + return TRUE; + } + + /* failure */ + if (memcmp (buf, "FAIL", 4) == 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to read response: %s", tmp); + return FALSE; + } + + /* unknown failure */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to read response"); + return FALSE; + } + + /* we timed out a *lot* */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "no response to read"); + return FALSE; +} + +static gboolean +fu_fastboot_device_getvar (FuDevice *device, const gchar *key, gchar **str, GError **error) +{ + g_autofree gchar *tmp = g_strdup_printf ("getvar:%s", key); + if (!fu_fastboot_device_writestr (device, tmp, error)) + return FALSE; + if (!fu_fastboot_device_read (device, str, + FU_FASTBOOT_DEVICE_READ_FLAG_NONE, error)) + return FALSE; + return TRUE; +} + +static gboolean +fu_fastboot_device_cmd (FuDevice *device, const gchar *cmd, + FuFastbootDeviceReadFlags flags, GError **error) +{ + if (!fu_fastboot_device_writestr (device, cmd, error)) + return FALSE; + if (!fu_fastboot_device_read (device, NULL, flags, error)) + return FALSE; + return TRUE; +} + +static gboolean +fu_fastboot_device_flash (FuDevice *device, const gchar *partition, GError **error) +{ + g_autofree gchar *tmp = g_strdup_printf ("flash:%s", partition); + return fu_fastboot_device_cmd (device, tmp, + FU_FASTBOOT_DEVICE_READ_FLAG_STATUS_POLL, + error); +} + +static gboolean +fu_fastboot_device_download (FuDevice *device, GBytes *fw, GError **error) +{ + FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); + gsize sz = g_bytes_get_size (fw); + g_autofree gchar *tmp = g_strdup_printf ("download:%08x", (guint) sz); + g_autoptr(GPtrArray) chunks = NULL; + + /* tell the client the size of data to expect */ + if (!fu_fastboot_device_cmd (device, tmp, + FU_FASTBOOT_DEVICE_READ_FLAG_STATUS_POLL, + error)) + return FALSE; + + /* send the data in chunks */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + chunks = fu_chunk_array_new_from_bytes (fw, + 0x00, /* start addr */ + 0x00, /* page_sz */ + self->blocksz); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + if (!fu_fastboot_device_write (device, chk->data, chk->data_sz, error)) + return FALSE; + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len * 2); + } + if (!fu_fastboot_device_read (device, NULL, + FU_FASTBOOT_DEVICE_READ_FLAG_STATUS_POLL, error)) + return FALSE; + return TRUE; +} + +static gboolean +fu_fastboot_device_setup (FuDevice *device, GError **error) +{ + FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); + g_autofree gchar *product = NULL; + g_autofree gchar *serialno = NULL; + g_autofree gchar *version = NULL; + g_autofree gchar *secure = NULL; + g_autofree gchar *version_bootloader = NULL; + + /* product */ + if (!fu_fastboot_device_getvar (device, "product", &product, error)) + return FALSE; + if (product != NULL && product[0] != '\0') { + g_autofree gchar *tmp = g_strdup_printf ("Fastboot %s", product); + fu_device_set_name (device, tmp); + } + + /* fastboot API version */ + if (!fu_fastboot_device_getvar (device, "version", &version, error)) + return FALSE; + if (version != NULL && version[0] != '\0') + g_debug ("fastboot version=%s", version); + + /* bootloader version */ + if (!fu_fastboot_device_getvar (device, "version-bootloader", &version_bootloader, error)) + return FALSE; + if (version_bootloader != NULL && version_bootloader[0] != '\0') + fu_device_set_version_bootloader (device, version_bootloader); + + /* serialno */ + if (!fu_fastboot_device_getvar (device, "serialno", &serialno, error)) + return FALSE; + if (serialno != NULL && serialno[0] != '\0') + fu_device_set_serial (device, serialno); + + /* secure */ + if (!fu_fastboot_device_getvar (device, "secure", &secure, error)) + return FALSE; + if (secure != NULL && secure[0] != '\0') + self->secure = TRUE; + + /* success */ + return TRUE; +} + +static gboolean +fu_fastboot_device_write_qfil_part (FuDevice *device, + FuArchive *archive, + XbNode *part, + GError **error) +{ + GBytes *data; + const gchar *fn; + const gchar *partition; + + /* not all partitions have images */ + fn = xb_node_query_text (part, "img_name", NULL); + if (fn == NULL) + return TRUE; + + /* find filename */ + data = fu_archive_lookup_by_fn (archive, fn, error); + if (data == NULL) + return FALSE; + + /* get the partition name */ + partition = xb_node_query_text (part, "name", error); + if (partition == NULL) + return FALSE; + if (g_str_has_prefix (partition, "0:")) + partition += 2; + + /* flash the partition */ + if (!fu_fastboot_device_download (device, data, error)) + return FALSE; + return fu_fastboot_device_flash (device, partition, error); +} + +static gboolean +fu_fastboot_device_write_motorola_part (FuDevice *device, + FuArchive *archive, + XbNode *part, + GError **error) +{ + const gchar *op = xb_node_get_attr (part, "operation"); + + /* oem */ + if (g_strcmp0 (op, "oem") == 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "OEM commands are not supported"); + return FALSE; + } + + /* getvar */ + if (g_strcmp0 (op, "getvar") == 0) { + const gchar *var = xb_node_get_attr (part, "var"); + g_autofree gchar *tmp = NULL; + + /* check required args */ + if (var == NULL) { + tmp = xb_node_export (part, XB_NODE_EXPORT_FLAG_NONE, NULL); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "required var for part: %s", tmp); + return FALSE; + } + + /* just has to be non-empty */ + if (!fu_fastboot_device_getvar (device, var, &tmp, error)) + return FALSE; + if (tmp == NULL || tmp[0] == '\0') { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "failed to getvar %s", var); + return FALSE; + } + return TRUE; + } + + /* erase */ + if (g_strcmp0 (op, "erase") == 0) { + const gchar *partition = xb_node_get_attr (part, "partition"); + g_autofree gchar *cmd = g_strdup_printf ("erase:%s", partition); + + /* check required args */ + if (partition == NULL) { + g_autofree gchar *tmp = NULL; + tmp = xb_node_export (part, XB_NODE_EXPORT_FLAG_NONE, NULL); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "required partition for part: %s", tmp); + return FALSE; + } + + /* erase the partition */ + return fu_fastboot_device_cmd (device, cmd, + FU_FASTBOOT_DEVICE_READ_FLAG_NONE, + error); + } + + /* flash */ + if (g_strcmp0 (op, "flash") == 0) { + GBytes *data; + const gchar *filename = xb_node_get_attr (part, "filename"); + const gchar *partition = xb_node_get_attr (part, "partition"); + struct { + GChecksumType kind; + const gchar *str; + } csum_kinds[] = { + { G_CHECKSUM_MD5, "MD5" }, + { G_CHECKSUM_SHA1, "SHA1" }, + { 0, NULL } + }; + + /* check required args */ + if (partition == NULL || filename == NULL) { + g_autofree gchar *tmp = NULL; + tmp = xb_node_export (part, XB_NODE_EXPORT_FLAG_NONE, NULL); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "required partition and filename: %s", tmp); + return FALSE; + } + + /* find filename */ + data = fu_archive_lookup_by_fn (archive, filename, error); + if (data == NULL) + return FALSE; + + /* checksum is optional */ + for (guint i = 0; csum_kinds[i].str != NULL; i++) { + const gchar *csum; + g_autofree gchar *csum_actual = NULL; + + /* not provided */ + csum = xb_node_get_attr (part, csum_kinds[i].str); + if (csum == NULL) + continue; + + /* check is valid */ + csum_actual = g_compute_checksum_for_bytes (csum_kinds[i].kind, data); + if (g_strcmp0 (csum, csum_actual) != 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "%s invalid, expected %s, got %s", + filename, csum, csum_actual); + return FALSE; + } + } + + /* flash the partition */ + if (!fu_fastboot_device_download (device, data, error)) + return FALSE; + return fu_fastboot_device_flash (device, partition, error); + } + + /* dumb operation that doesn't expect a response */ + if (g_strcmp0 (op, "boot") == 0 || + g_strcmp0 (op, "continue") == 0 || + g_strcmp0 (op, "reboot") == 0 || + g_strcmp0 (op, "reboot-bootloader") == 0 || + g_strcmp0 (op, "powerdown") == 0) { + return fu_fastboot_device_cmd (device, op, + FU_FASTBOOT_DEVICE_READ_FLAG_NONE, + error); + } + + /* unknown */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "unknown operation %s", op); + return FALSE; +} + +static gboolean +fu_fastboot_device_write_motorola (FuDevice *device, + FuArchive* archive, + GError **error) +{ + GBytes *data; + g_autoptr(GPtrArray) parts = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + g_autoptr(XbSilo) silo = NULL; + + /* load the manifest of operations */ + data = fu_archive_lookup_by_fn (archive, "flashfile.xml", error); + if (data == NULL) + return FALSE; + if (!xb_builder_source_load_bytes (source, data, + XB_BUILDER_SOURCE_FLAG_NONE, error)) + return FALSE; + xb_builder_import_source (builder, source); + silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_NONE, NULL, error); + if (silo == NULL) + return FALSE; + + /* get all the operation parts */ + parts = xb_silo_query (silo, "parts/part", 0, error); + if (parts == NULL) + return FALSE; + for (guint i = 0; i < parts->len; i++) { + XbNode *part = g_ptr_array_index (parts, i); + if (!fu_fastboot_device_write_motorola_part (device, + archive, + part, + error)) + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_fastboot_device_write_qfil (FuDevice *device, FuArchive* archive, GError **error) +{ + GBytes *data; + g_autoptr(GPtrArray) parts = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + g_autoptr(XbSilo) silo = NULL; + + /* load the manifest of operations */ + data = fu_archive_lookup_by_fn (archive, "partition_nand.xml", error); + if (data == NULL) + return FALSE; + if (!xb_builder_source_load_bytes (source, data, + XB_BUILDER_SOURCE_FLAG_NONE, error)) + return FALSE; + xb_builder_import_source (builder, source); + silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_NONE, NULL, error); + if (silo == NULL) + return FALSE; + + /* get all the operation parts */ + parts = xb_silo_query (silo, "nandboot/partitions/partition", 0, error); + if (parts == NULL) + return FALSE; + for (guint i = 0; i < parts->len; i++) { + XbNode *part = g_ptr_array_index (parts, i); + if (!fu_fastboot_device_write_qfil_part (device, + archive, + part, + error)) + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_fastboot_device_write_firmware (FuDevice *device, GBytes *fw, GError **error) +{ + g_autoptr(FuArchive) archive = NULL; + + /* decompress entire archive ahead of time */ + archive = fu_archive_new (fw, FU_ARCHIVE_FLAG_IGNORE_PATH, error); + if (archive == NULL) + return FALSE; + + /* load the manifest of operations */ + if (fu_archive_lookup_by_fn (archive, "partition_nand.xml", NULL) != NULL) + return fu_fastboot_device_write_qfil (device, archive, error); + if (fu_archive_lookup_by_fn (archive, "flashfile.xml", NULL) != NULL) { + return fu_fastboot_device_write_motorola (device, + archive, + error); + } + + /* not supported */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "manifest not supported"); + return FALSE; +} + +static gboolean +fu_fastboot_device_close (FuUsbDevice *device, GError **error) +{ + FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (device); + + /* we're done here */ + if (!g_usb_device_release_interface (usb_device, self->intf_nr, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error)) { + g_prefix_error (error, "failed to release interface: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_fastboot_device_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); + + /* load slave address from quirks */ + if (g_strcmp0 (key, "FastbootBlockSize") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp >= 0x40 && tmp < 0x100000) { + self->blocksz = tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid block size"); + return FALSE; + } + + /* failed */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; + +} + +static gboolean +fu_fastboot_device_attach (FuDevice *device, GError **error) +{ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + return fu_fastboot_device_cmd (device, "reboot", + FU_FASTBOOT_DEVICE_READ_FLAG_NONE, + error); +} + +static void +fu_fastboot_device_init (FuFastbootDevice *self) +{ + /* this is a safe default, even using USBv1 */ + self->blocksz = 512; + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_remove_delay (FU_DEVICE (self), FASTBOOT_REMOVE_DELAY_RE_ENUMERATE); +} + +static void +fu_fastboot_device_class_init (FuFastbootDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); + klass_device->probe = fu_fastboot_device_probe; + klass_device->setup = fu_fastboot_device_setup; + klass_device->write_firmware = fu_fastboot_device_write_firmware; + klass_device->attach = fu_fastboot_device_attach; + klass_device->to_string = fu_fastboot_device_to_string; + klass_device->set_quirk_kv = fu_fastboot_device_set_quirk_kv; + klass_usb_device->open = fu_fastboot_device_open; + klass_usb_device->close = fu_fastboot_device_close; +} + +FuFastbootDevice * +fu_fastboot_device_new (FuUsbDevice *device) +{ + FuFastbootDevice *self = g_object_new (FU_TYPE_FASTBOOT_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return self; +} diff -Nru fwupd-1.1.4/plugins/fastboot/fu-fastboot-device.h fwupd-1.2.5/plugins/fastboot/fu-fastboot-device.h --- fwupd-1.1.4/plugins/fastboot/fu-fastboot-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/fastboot/fu-fastboot-device.h 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +G_BEGIN_DECLS + +#define FU_TYPE_FASTBOOT_DEVICE (fu_fastboot_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuFastbootDevice, fu_fastboot_device, FU, FASTBOOT_DEVICE, FuUsbDevice) + +FuFastbootDevice *fu_fastboot_device_new (FuUsbDevice *device); + +G_END_DECLS diff -Nru fwupd-1.1.4/plugins/fastboot/fu-plugin-fastboot.c fwupd-1.2.5/plugins/fastboot/fu-plugin-fastboot.c --- fwupd-1.1.4/plugins/fastboot/fu-plugin-fastboot.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/fastboot/fu-plugin-fastboot.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + +#include "fu-fastboot-device.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.google.fastboot"); +} + +gboolean +fu_plugin_update (FuPlugin *plugin, + FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_write_firmware (device, blob_fw, error); +} + +gboolean +fu_plugin_update_attach (FuPlugin *plugin, FuDevice *device, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + + /* open device */ + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + + /* reset */ + if (!fu_device_attach (device, error)) + return FALSE; + + /* wait for replug */ + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + return TRUE; +} + +gboolean +fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *device, GError **error) +{ + g_autoptr(FuFastbootDevice) dev = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + dev = fu_fastboot_device_new (device); + locker = fu_device_locker_new (dev, error); + if (locker == NULL) + return FALSE; + fu_plugin_device_add (plugin, FU_DEVICE (dev)); + return TRUE; +} diff -Nru fwupd-1.1.4/plugins/fastboot/meson.build fwupd-1.2.5/plugins/fastboot/meson.build --- fwupd-1.1.4/plugins/fastboot/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/fastboot/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,27 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginFastboot"'] + +install_data(['fastboot.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_fastboot', + fu_hash, + sources : [ + 'fu-plugin-fastboot.c', + 'fu-fastboot-device.c', + ], + include_directories : [ + include_directories('../..'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + install : true, + install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) diff -Nru fwupd-1.1.4/plugins/fastboot/README.md fwupd-1.2.5/plugins/fastboot/README.md --- fwupd-1.1.4/plugins/fastboot/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/fastboot/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,40 @@ +Fastboot Support +================ + +Introduction +------------ + +This plugin is used to update hardware that uses the fastboot protocol. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmare blob in +ZIP file format. Inside the zip file must be all the firmware images for each +partition and a manifest file. The partition images can be in any format, but +the manifest must be either an Android `flashfile.xml` format file, or a QFIL +`partition_nand.xml` format file. + +For both types, all partitions with a defined image found in the zip file will +be updated. + +This plugin supports the following protocol ID: + + * com.google.fastboot + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_18D1&PID_4EE0&REV_0001` + * `USB\VID_18D1&PID_4EE0` + * `USB\VID_18D1` + +Quirk use +--------- +This plugin uses the following plugin-specific quirk: + +| Quirk | Description | Minimum fwupd version | +|------------------------|----------------------------------|-----------------------| +| `FastbootBlockSize` | Block size to use for transfers | 1.2.2 | diff -Nru fwupd-1.1.4/plugins/flashrom/fu-plugin-flashrom.c fwupd-1.2.5/plugins/flashrom/fu-plugin-flashrom.c --- fwupd-1.1.4/plugins/flashrom/fu-plugin-flashrom.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/flashrom/fu-plugin-flashrom.c 2019-02-25 09:42:18.000000000 +0000 @@ -32,7 +32,9 @@ void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.flashrom"); } void @@ -66,6 +68,7 @@ g_autofree gchar *device_id = g_strdup_printf ("flashrom-%s", quirk_str); g_autoptr(FuDevice) dev = fu_device_new (); fu_device_set_id (dev, device_id); + fu_device_set_quirks (dev, fu_plugin_get_quirks (plugin)); fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_INTERNAL); if (data->flashrom_fn != NULL) { fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); diff -Nru fwupd-1.1.4/plugins/flashrom/meson.build fwupd-1.2.5/plugins/flashrom/meson.build --- fwupd-1.1.4/plugins/flashrom/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/flashrom/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -5,6 +5,7 @@ ) shared_module('fu_plugin_flashrom', + fu_hash, sources : [ 'fu-plugin-flashrom.c', ], @@ -15,6 +16,9 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : [ cargs, '-DLOCALSTATEDIR="' + localstatedir + '"', diff -Nru fwupd-1.1.4/plugins/flashrom/README.md fwupd-1.2.5/plugins/flashrom/README.md --- fwupd-1.1.4/plugins/flashrom/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/flashrom/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -5,3 +5,21 @@ ------------ This plugin uses `flashrom` to update the system firmware. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format, which is typically the raw input for an +EEPROM programmer. + +This plugin supports the following protocol ID: + + * org.flashrom + +GUID Generation +--------------- + +These device uses hardware ID values which are derived from SMBIOS. They should +match the values provided by `fwupdtool hwids` or the `ComputerHardwareIds.exe` +Windows utility. diff -Nru fwupd-1.1.4/plugins/meson.build fwupd-1.2.5/plugins/meson.build --- fwupd-1.1.4/plugins/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -1,6 +1,8 @@ +subdir('ata') subdir('dfu') subdir('colorhug') subdir('ebitdo') +subdir('fastboot') subdir('flashrom') subdir('steelseries') subdir('dell-dock') @@ -11,7 +13,8 @@ subdir('udev') subdir('unifying') subdir('upower') -subdir('wacomhid') +subdir('wacom-raw') +subdir('wacom-usb') subdir('superio') # depends on dfu diff -Nru fwupd-1.1.4/plugins/nitrokey/fu-nitrokey-common.h fwupd-1.2.5/plugins/nitrokey/fu-nitrokey-common.h --- fwupd-1.1.4/plugins/nitrokey/fu-nitrokey-common.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/nitrokey/fu-nitrokey-common.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_NITROKEY_COMMON_H -#define __FU_NITROKEY_COMMON_H +#pragma once #include @@ -14,6 +13,54 @@ guint32 fu_nitrokey_perform_crc32 (const guint8 *data, gsize size); -G_END_DECLS +#define NITROKEY_TRANSACTION_TIMEOUT 100 /* ms */ +#define NITROKEY_NR_RETRIES 5 + +#define NITROKEY_REQUEST_DATA_LENGTH 59 +#define NITROKEY_REPLY_DATA_LENGTH 53 + +#define NITROKEY_CMD_GET_DEVICE_STATUS (0x20 + 14) -#endif /* __FU_NITROKEY_COMMON_H */ +typedef struct __attribute__((packed)) { + guint8 command; + guint8 payload[NITROKEY_REQUEST_DATA_LENGTH]; + guint32 crc; +} NitrokeyHidRequest; + +typedef struct __attribute__((packed)) { + guint8 device_status; + guint8 command_id; + guint32 last_command_crc; + guint8 last_command_status; + guint8 payload[NITROKEY_REPLY_DATA_LENGTH]; + guint32 crc; +} NitrokeyHidResponse; + +/* based from libnitrokey/stick20_commands.h from libnitrokey v3.4.1 */ +typedef struct __attribute__((packed)) { + guint8 _padding[18]; /* stick20_commands.h:132 // 26 - 8 = 18 */ + guint8 SendCounter; + guint8 SendDataType; + guint8 FollowBytesFlag; + guint8 SendSize; + guint16 MagicNumber_StickConfig; + guint8 ReadWriteFlagUncryptedVolume; + guint8 ReadWriteFlagCryptedVolume; + guint8 VersionMajor; + guint8 VersionMinor; + guint8 VersionReservedByte; + guint8 VersionBuildIteration; + guint8 ReadWriteFlagHiddenVolume; + guint8 FirmwareLocked; + guint8 NewSDCardFound; + guint8 SDFillWithRandomChars; + guint32 ActiveSD_CardID; + guint8 VolumeActiceFlag; + guint8 NewSmartCardFound; + guint8 UserPwRetryCount; + guint8 AdminPwRetryCount; + guint32 ActiveSmartCardID; + guint8 StickKeysNotInitiated; +} NitrokeyGetDeviceStatusPayload; + +G_END_DECLS diff -Nru fwupd-1.1.4/plugins/nitrokey/fu-nitrokey-device.c fwupd-1.2.5/plugins/nitrokey/fu-nitrokey-device.c --- fwupd-1.1.4/plugins/nitrokey/fu-nitrokey-device.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/nitrokey/fu-nitrokey-device.c 2019-02-25 09:42:18.000000000 +0000 @@ -13,56 +13,6 @@ G_DEFINE_TYPE (FuNitrokeyDevice, fu_nitrokey_device, FU_TYPE_USB_DEVICE) -#define NITROKEY_TRANSACTION_TIMEOUT 100 /* ms */ -#define NITROKEY_NR_RETRIES 5 - -#define NITROKEY_REQUEST_DATA_LENGTH 59 -#define NITROKEY_REPLY_DATA_LENGTH 53 - -#define NITROKEY_CMD_GET_DEVICE_STATUS (0x20 + 14) - -typedef struct __attribute__((packed)) { - guint8 command; - guint8 payload[NITROKEY_REQUEST_DATA_LENGTH]; - guint32 crc; -} NitrokeyHidRequest; - -typedef struct __attribute__((packed)) { - guint8 _padding; /* always zero */ - guint8 device_status; - guint32 last_command_crc; - guint8 last_command_status; - guint8 payload[NITROKEY_REPLY_DATA_LENGTH]; - guint32 crc; -} NitrokeyHidResponse; - -/* based from libnitrokey/stick20_commands.h */ -typedef struct __attribute__((packed)) { - guint8 _padding[24]; - guint8 SendCounter; - guint8 SendDataType; - guint8 FollowBytesFlag; - guint8 SendSize; - guint16 MagicNumber_StickConfig; - guint8 ReadWriteFlagUncryptedVolume; - guint8 ReadWriteFlagCryptedVolume; - guint8 VersionReserved1; - guint8 VersionMinor; - guint8 VersionReserved2; - guint8 VersionMajor; - guint8 ReadWriteFlagHiddenVolume; - guint8 FirmwareLocked; - guint8 NewSDCardFound; - guint8 SDFillWithRandomChars; - guint32 ActiveSD_CardID; - guint8 VolumeActiceFlag; - guint8 NewSmartCardFound; - guint8 UserPwRetryCount; - guint8 AdminPwRetryCount; - guint32 ActiveSmartCardID; - guint8 StickKeysNotInitiated; -} NitrokeyGetDeviceStatusPayload; - static void _dump_to_console (const gchar *title, const guint8 *buf, gsize buf_sz) { @@ -240,8 +190,8 @@ return FALSE; } _dump_to_console ("payload", buf_reply, sizeof(buf_reply)); - memcpy (&payload, buf_reply, sizeof(buf_reply)); - version = g_strdup_printf ("%u.%u", payload.VersionMinor, payload.VersionMajor); + memcpy (&payload, buf_reply, sizeof(payload)); + version = g_strdup_printf ("%u.%u", payload.VersionMajor, payload.VersionMinor); fu_device_set_version (FU_DEVICE (device), version); /* success */ diff -Nru fwupd-1.1.4/plugins/nitrokey/fu-nitrokey-device.h fwupd-1.2.5/plugins/nitrokey/fu-nitrokey-device.h --- fwupd-1.1.4/plugins/nitrokey/fu-nitrokey-device.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/nitrokey/fu-nitrokey-device.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_NITROKEY_DEVICE_H -#define __FU_NITROKEY_DEVICE_H +#pragma once #include "fu-plugin.h" @@ -22,5 +21,3 @@ FuNitrokeyDevice *fu_nitrokey_device_new (FuUsbDevice *device); G_END_DECLS - -#endif /* __FU_NITROKEY_DEVICE_H */ diff -Nru fwupd-1.1.4/plugins/nitrokey/fu-plugin-nitrokey.c fwupd-1.2.5/plugins/nitrokey/fu-plugin-nitrokey.c --- fwupd-1.1.4/plugins/nitrokey/fu-plugin-nitrokey.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/nitrokey/fu-plugin-nitrokey.c 2019-02-25 09:42:18.000000000 +0000 @@ -14,6 +14,7 @@ void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); } diff -Nru fwupd-1.1.4/plugins/nitrokey/fu-self-test.c fwupd-1.2.5/plugins/nitrokey/fu-self-test.c --- fwupd-1.1.4/plugins/nitrokey/fu-self-test.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/nitrokey/fu-self-test.c 2019-02-25 09:42:18.000000000 +0000 @@ -11,6 +11,59 @@ #include "fu-nitrokey-common.h" static void +fu_nitrokey_version_test (void) +{ + /* use the Nitrokey Storage v0.53 status response for test, CRC 0xa2762d14 */ + NitrokeyGetDeviceStatusPayload payload; + NitrokeyHidResponse res; + guint32 crc_tmp; + /* 65 bytes of response from HIDAPI; first byte is always 0 */ + const guint8 buf[] = { + /*0x00,*/ + 0x00, 0x2e, 0xef, 0xc4, 0x9b, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x2e, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x1c, 0x18, 0x33, + 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x45, 0x24, 0xf1, 0x4c, 0x01, 0x00, + 0x03, 0x03, 0xc7, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x2d, 0x76, + 0xa2 }; + + /* testing the whole path, as in fu_nitrokey_device_setup()*/ + memcpy (&res, buf, sizeof (buf)); + memcpy (&payload, &res.payload, sizeof (payload)); + + /* verify the version number */ + g_assert_cmpint (payload.VersionMajor, == , 0); + g_assert_cmpint (payload.VersionMinor, == , 53); + g_assert_cmpint (buf[34], == , payload.VersionMinor); + g_assert_cmpint (payload.VersionBuildIteration, == , 0); + + /* verify the response checksum */ + crc_tmp = fu_nitrokey_perform_crc32 (buf, sizeof (res) - 4); + g_assert_cmpint (GUINT32_FROM_LE (res.crc), == , crc_tmp); + +} + +static void +fu_nitrokey_version_test_static (void) +{ + /* use static response from numbered bytes, to make sure fields occupy + * expected bytes */ + NitrokeyGetDeviceStatusPayload payload; + NitrokeyHidResponse res; + + const guint8 buf[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + }; + memcpy (&res, buf, sizeof (buf)); + memcpy (&payload, &res.payload, sizeof (payload)); + g_assert_cmpint (payload.VersionMajor, == , 33); /* 0x1a */ + g_assert_cmpint (payload.VersionMinor, == , 34); /* 0x1b */ + g_assert_cmpint (buf[34], == , 34); +} + +static void fu_nitrokey_func (void) { const guint8 buf[] = { 0x00, 0x01, 0x02, 0x03, @@ -31,5 +84,7 @@ /* tests go here */ g_test_add_func ("/fwupd/nitrokey", fu_nitrokey_func); + g_test_add_func ("/fwupd/nitrokey-version-static", fu_nitrokey_version_test_static); + g_test_add_func ("/fwupd/nitrokey-version", fu_nitrokey_version_test); return g_test_run (); } diff -Nru fwupd-1.1.4/plugins/nitrokey/meson.build fwupd-1.2.5/plugins/nitrokey/meson.build --- fwupd-1.1.4/plugins/nitrokey/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/nitrokey/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -5,6 +5,7 @@ ) shared_module('fu_plugin_nitrokey', + fu_hash, sources : [ 'fu-nitrokey-device.c', 'fu-nitrokey-common.c', @@ -17,6 +18,9 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, @@ -26,6 +30,7 @@ if get_option('tests') e = executable( 'nitrokey-self-test', + fu_hash, sources : [ 'fu-nitrokey-common.c', 'fu-self-test.c', diff -Nru fwupd-1.1.4/plugins/nitrokey/README.md fwupd-1.2.5/plugins/nitrokey/README.md --- fwupd-1.1.4/plugins/nitrokey/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/nitrokey/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -10,3 +10,12 @@ The device is switched to a DFU bootloader only when the secret firmware pin is entered into the nitrokey-app tool. This cannot be automated. + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_20A0&PID_4109&REV_0001` + * `USB\VID_20A0&PID_4109` + * `USB\VID_20A0` diff -Nru fwupd-1.1.4/plugins/nvme/fu-nvme-common.c fwupd-1.2.5/plugins/nvme/fu-nvme-common.c --- fwupd-1.1.4/plugins/nvme/fu-nvme-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/nvme/fu-nvme-common.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-nvme-common.h" + +const gchar * +fu_nvme_status_to_string (guint32 status) +{ + switch (status) { + case NVME_SC_SUCCESS: + return "Command completed successfully"; + case NVME_SC_INVALID_OPCODE: + return "Associated command opcode field is not valid"; + case NVME_SC_INVALID_FIELD: + return "Unsupported value in a defined field"; + case NVME_SC_CMDID_CONFLICT: + return "Command identifier is already in use"; + case NVME_SC_DATA_XFER_ERROR: + return "Error while trying to transfer the data or metadata"; + case NVME_SC_POWER_LOSS: + return "Command aborted due to power loss notification"; + case NVME_SC_INTERNAL: + return "Internal error"; + case NVME_SC_ABORT_REQ: + return "Command Abort request"; + case NVME_SC_ABORT_QUEUE: + return "Delete I/O Submission Queue request"; + case NVME_SC_FUSED_FAIL: + return "Other command in a fused operation failing"; + case NVME_SC_FUSED_MISSING: + return "Missing Fused Command"; + case NVME_SC_INVALID_NS: + return "Namespace or the format of that namespace is invalid"; + case NVME_SC_CMD_SEQ_ERROR: + return "Protocol violation in a multicommand sequence"; + case NVME_SC_SANITIZE_FAILED: + return "No recovery actions has been successfully completed"; + case NVME_SC_SANITIZE_IN_PROGRESS: + return "A sanitize operation is in progress"; + case NVME_SC_LBA_RANGE: + return "LBA exceeds the size of the namespace"; + case NVME_SC_NS_WRITE_PROTECTED: + return "Namespace is write protected by the host"; + case NVME_SC_CAP_EXCEEDED: + return "Capacity of the namespace to be exceeded"; + case NVME_SC_NS_NOT_READY: + return "Namespace is not ready to be accessed"; + case NVME_SC_RESERVATION_CONFLICT: + return "Conflict with a reservation on the accessed namespace"; + case NVME_SC_CQ_INVALID: + return "Completion Queue does not exist"; + case NVME_SC_QID_INVALID: + return "Invalid queue identifier specified"; + case NVME_SC_QUEUE_SIZE: + return "Invalid queue size"; + case NVME_SC_ABORT_LIMIT: + return "Outstanding Abort commands has exceeded the limit"; + case NVME_SC_ABORT_MISSING: + return "Abort command is missing"; + case NVME_SC_ASYNC_LIMIT: + return "Outstanding Async commands has been exceeded"; + case NVME_SC_FIRMWARE_SLOT: + return "Slot is invalid or read only"; + case NVME_SC_FIRMWARE_IMAGE: + return "Image specified for activation is invalid"; + case NVME_SC_INVALID_VECTOR: + return "Creation failed due to an invalid interrupt vector"; + case NVME_SC_INVALID_LOG_PAGE: + return "Log page indicated is invalid"; + case NVME_SC_INVALID_FORMAT: + return "LBA Format specified is not supported"; + case NVME_SC_FW_NEEDS_CONV_RESET: + return "commit was successful, but activation requires reset"; + case NVME_SC_INVALID_QUEUE: + return "Failed to delete the I/O Completion Queue specified"; + case NVME_SC_FEATURE_NOT_SAVEABLE: + return "Feature Identifier does not support a saveable value"; + case NVME_SC_FEATURE_NOT_CHANGEABLE: + return "Feature Identifier is not able to be changed"; + case NVME_SC_FEATURE_NOT_PER_NS: + return "Feature Identifier specified is not namespace specific"; + case NVME_SC_FW_NEEDS_SUBSYS_RESET: + return "Commit was successful, activation requires NVM Subsystem"; + case NVME_SC_FW_NEEDS_RESET: + return "Commit was successful, activation requires a reset"; + case NVME_SC_FW_NEEDS_MAX_TIME: + return "Would exceed the Maximum Time for Firmware Activation"; + case NVME_SC_FW_ACIVATE_PROHIBITED: + return "Image specified is being prohibited from activation"; + case NVME_SC_OVERLAPPING_RANGE: + return "Image has overlapping ranges"; + case NVME_SC_NS_INSUFFICENT_CAP: + return "Requires more free space than is currently available"; + case NVME_SC_NS_ID_UNAVAILABLE: + return "Number of namespaces supported has been exceeded"; + case NVME_SC_NS_ALREADY_ATTACHED: + return "Controller is already attached to the namespace"; + case NVME_SC_NS_IS_PRIVATE: + return "Namespace is private"; + case NVME_SC_NS_NOT_ATTACHED: + return "Controller is not attached to the namespace"; + case NVME_SC_THIN_PROV_NOT_SUPP: + return "Thin provisioning is not supported by the controller"; + case NVME_SC_CTRL_LIST_INVALID: + return "Controller list provided is invalid"; + case NVME_SC_BP_WRITE_PROHIBITED: + return "Trying to modify a Boot Partition while it is locked"; + case NVME_SC_BAD_ATTRIBUTES: + return "Bad attributes"; + case NVME_SC_WRITE_FAULT: + return "Write data could not be committed to the media"; + case NVME_SC_READ_ERROR: + return "Read data could not be recovered from the media"; + case NVME_SC_GUARD_CHECK: + return "End-to-end guard check failure"; + case NVME_SC_APPTAG_CHECK: + return "End-to-end application tag check failure"; + case NVME_SC_REFTAG_CHECK: + return "End-to-end reference tag check failure"; + case NVME_SC_COMPARE_FAILED: + return "Miscompare during a Compare command"; + case NVME_SC_ACCESS_DENIED: + return "Access denied"; + case NVME_SC_UNWRITTEN_BLOCK: + return "Read from an LBA range containing a unwritten block"; + case NVME_SC_ANA_PERSISTENT_LOSS: + return "Namespace is in the ANA Persistent Loss state"; + case NVME_SC_ANA_INACCESSIBLE: + return "Namespace being in the ANA Inaccessible state"; + case NVME_SC_ANA_TRANSITION: + return "Namespace transitioning between Async Access states"; + default: + return "Unknown"; + } +} diff -Nru fwupd-1.1.4/plugins/nvme/fu-nvme-common.h fwupd-1.2.5/plugins/nvme/fu-nvme-common.h --- fwupd-1.1.4/plugins/nvme/fu-nvme-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/nvme/fu-nvme-common.h 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +enum { + /* + * Generic Command Status: + */ + NVME_SC_SUCCESS = 0x0, + NVME_SC_INVALID_OPCODE = 0x1, + NVME_SC_INVALID_FIELD = 0x2, + NVME_SC_CMDID_CONFLICT = 0x3, + NVME_SC_DATA_XFER_ERROR = 0x4, + NVME_SC_POWER_LOSS = 0x5, + NVME_SC_INTERNAL = 0x6, + NVME_SC_ABORT_REQ = 0x7, + NVME_SC_ABORT_QUEUE = 0x8, + NVME_SC_FUSED_FAIL = 0x9, + NVME_SC_FUSED_MISSING = 0xa, + NVME_SC_INVALID_NS = 0xb, + NVME_SC_CMD_SEQ_ERROR = 0xc, + NVME_SC_SGL_INVALID_LAST = 0xd, + NVME_SC_SGL_INVALID_COUNT = 0xe, + NVME_SC_SGL_INVALID_DATA = 0xf, + NVME_SC_SGL_INVALID_METADATA = 0x10, + NVME_SC_SGL_INVALID_TYPE = 0x11, + + NVME_SC_SGL_INVALID_OFFSET = 0x16, + NVME_SC_SGL_INVALID_SUBTYPE = 0x17, + + NVME_SC_SANITIZE_FAILED = 0x1C, + NVME_SC_SANITIZE_IN_PROGRESS = 0x1D, + + NVME_SC_NS_WRITE_PROTECTED = 0x20, + + NVME_SC_LBA_RANGE = 0x80, + NVME_SC_CAP_EXCEEDED = 0x81, + NVME_SC_NS_NOT_READY = 0x82, + NVME_SC_RESERVATION_CONFLICT = 0x83, + + /* + * Command Specific Status: + */ + NVME_SC_CQ_INVALID = 0x100, + NVME_SC_QID_INVALID = 0x101, + NVME_SC_QUEUE_SIZE = 0x102, + NVME_SC_ABORT_LIMIT = 0x103, + NVME_SC_ABORT_MISSING = 0x104, + NVME_SC_ASYNC_LIMIT = 0x105, + NVME_SC_FIRMWARE_SLOT = 0x106, + NVME_SC_FIRMWARE_IMAGE = 0x107, + NVME_SC_INVALID_VECTOR = 0x108, + NVME_SC_INVALID_LOG_PAGE = 0x109, + NVME_SC_INVALID_FORMAT = 0x10a, + NVME_SC_FW_NEEDS_CONV_RESET = 0x10b, + NVME_SC_INVALID_QUEUE = 0x10c, + NVME_SC_FEATURE_NOT_SAVEABLE = 0x10d, + NVME_SC_FEATURE_NOT_CHANGEABLE = 0x10e, + NVME_SC_FEATURE_NOT_PER_NS = 0x10f, + NVME_SC_FW_NEEDS_SUBSYS_RESET = 0x110, + NVME_SC_FW_NEEDS_RESET = 0x111, + NVME_SC_FW_NEEDS_MAX_TIME = 0x112, + NVME_SC_FW_ACIVATE_PROHIBITED = 0x113, + NVME_SC_OVERLAPPING_RANGE = 0x114, + NVME_SC_NS_INSUFFICENT_CAP = 0x115, + NVME_SC_NS_ID_UNAVAILABLE = 0x116, + NVME_SC_NS_ALREADY_ATTACHED = 0x118, + NVME_SC_NS_IS_PRIVATE = 0x119, + NVME_SC_NS_NOT_ATTACHED = 0x11a, + NVME_SC_THIN_PROV_NOT_SUPP = 0x11b, + NVME_SC_CTRL_LIST_INVALID = 0x11c, + NVME_SC_BP_WRITE_PROHIBITED = 0x11e, + + /* + * I/O Command Set Specific - NVM commands: + */ + NVME_SC_BAD_ATTRIBUTES = 0x180, + NVME_SC_INVALID_PI = 0x181, + NVME_SC_READ_ONLY = 0x182, + NVME_SC_ONCS_NOT_SUPPORTED = 0x183, + + /* + * I/O Command Set Specific - Fabrics commands: + */ + NVME_SC_CONNECT_FORMAT = 0x180, + NVME_SC_CONNECT_CTRL_BUSY = 0x181, + NVME_SC_CONNECT_INVALID_PARAM = 0x182, + NVME_SC_CONNECT_RESTART_DISC = 0x183, + NVME_SC_CONNECT_INVALID_HOST = 0x184, + + NVME_SC_DISCOVERY_RESTART = 0x190, + NVME_SC_AUTH_REQUIRED = 0x191, + + /* + * Media and Data Integrity Errors: + */ + NVME_SC_WRITE_FAULT = 0x280, + NVME_SC_READ_ERROR = 0x281, + NVME_SC_GUARD_CHECK = 0x282, + NVME_SC_APPTAG_CHECK = 0x283, + NVME_SC_REFTAG_CHECK = 0x284, + NVME_SC_COMPARE_FAILED = 0x285, + NVME_SC_ACCESS_DENIED = 0x286, + NVME_SC_UNWRITTEN_BLOCK = 0x287, + + /* + * Path-related Errors: + */ + NVME_SC_ANA_PERSISTENT_LOSS = 0x301, + NVME_SC_ANA_INACCESSIBLE = 0x302, + NVME_SC_ANA_TRANSITION = 0x303, + + NVME_SC_DNR = 0x4000, +}; + +const gchar *fu_nvme_status_to_string (guint32 status); + +G_END_DECLS diff -Nru fwupd-1.1.4/plugins/nvme/fu-nvme-device.c fwupd-1.2.5/plugins/nvme/fu-nvme-device.c --- fwupd-1.1.4/plugins/nvme/fu-nvme-device.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/nvme/fu-nvme-device.c 2019-02-25 09:42:18.000000000 +0000 @@ -15,17 +15,16 @@ #include -#include #include #include "fu-chunk.h" +#include "fu-nvme-common.h" #include "fu-nvme-device.h" #define FU_NVME_ID_CTRL_SIZE 0x1000 struct _FuNvmeDevice { FuUdevDevice parent_instance; - gchar *version_format; guint pci_depth; gint fd; guint64 write_block_size; @@ -79,29 +78,21 @@ static gchar * fu_nvme_device_get_guid_safe (const guint8 *buf, guint16 addr_start) { - efi_guid_t guid_tmp; - guint guint_sum = 0; - g_autofree char *guid = NULL; - - /* check the GUID is plausible */ - for (guint i = 0; i < 16; i++) - guint_sum += buf[addr_start + i]; - if (guint_sum == 0x00) + if (!fu_common_guid_is_plausible (buf + addr_start)) return NULL; - if (guint_sum < 0xff) { - g_warning ("implausible GUID with sum %02x", guint_sum); - return NULL; - } - memcpy (&guid_tmp, buf + addr_start, 16); - if (efi_guid_to_str (&guid_tmp, &guid) < 0) - return NULL; - return g_strdup (guid); + return fwupd_guid_to_string ((const fwupd_guid_t *) (buf + addr_start), + FWUPD_GUID_FLAG_MIXED_ENDIAN); } static gboolean fu_nvme_device_submit_admin_passthru (FuNvmeDevice *self, struct nvme_admin_cmd *cmd, GError **error) { - if (ioctl (self->fd, NVME_IOCTL_ADMIN_CMD, cmd) < 0) { + gint rc; + guint32 err; + + /* submit admin command */ + rc = ioctl (self->fd, NVME_IOCTL_ADMIN_CMD, cmd); + if (rc < 0) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, @@ -110,7 +101,26 @@ strerror (errno)); return FALSE; } - return TRUE; + + /* check the error code */ + err = rc & 0x3ff; + switch (err) { + case NVME_SC_SUCCESS: + /* devices are always added with _NEEDS_REBOOT, so ignore */ + case NVME_SC_FW_NEEDS_CONV_RESET: + case NVME_SC_FW_NEEDS_SUBSYS_RESET: + case NVME_SC_FW_NEEDS_RESET: + return TRUE; + default: + break; + } + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported: %s", + fu_nvme_status_to_string (err)); + return FALSE; + } static gboolean @@ -153,8 +163,8 @@ .opcode = 0x11, .addr = 0x0, /* memory address of data */ .data_len = data_sz, - .cdw10 = (data_sz >> 2) - 1, - .cdw11 = addr >> 2, + .cdw10 = (data_sz >> 2) - 1, /* convert to DWORDs */ + .cdw11 = addr >> 2, /* convert to DWORDs */ }; memcpy (&cmd.addr, &data, sizeof (gpointer)); return fu_nvme_device_submit_admin_passthru (self, &cmd, error); @@ -164,17 +174,28 @@ fu_nvme_device_parse_cns_maybe_dell (FuNvmeDevice *self, const guint8 *buf) { g_autofree gchar *component_id = NULL; + g_autofree gchar *devid = NULL; g_autofree gchar *guid_efi = NULL; - g_autofree gchar *guid_id = NULL; + g_autofree gchar *guid = NULL; /* add extra component ID if set */ component_id = fu_nvme_device_get_string_safe (buf, 0xc36, 0xc3d); - if (component_id == NULL || strlen (component_id) < 4) { + if (component_id == NULL || + !g_str_is_ascii (component_id) || + strlen (component_id) < 6) { g_debug ("invalid component ID, skipping"); return; } - guid_id = g_strdup_printf ("STORAGE-DELL-%s", component_id); - fu_device_add_guid (FU_DEVICE (self), guid_id); + + /* do not add the FuUdevDevice instance IDs as generic firmware + * should not be used on these OEM-specific devices */ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS); + + /* add instance ID *and* GUID as using no-auto-instance-ids */ + devid = g_strdup_printf ("STORAGE-DELL-%s", component_id); + fu_device_add_instance_id (FU_DEVICE (self), devid); + guid = fwupd_guid_hash_string (devid); + fu_device_add_guid (FU_DEVICE (self), guid); /* also add the EFI GUID */ guid_efi = fu_nvme_device_get_guid_safe (buf, 0x0c26); @@ -186,13 +207,13 @@ fu_nvme_device_set_version (FuNvmeDevice *self, const gchar *version, GError **error) { /* unset */ - if (self->version_format == NULL) { + if (fu_device_get_version_format (FU_DEVICE (self)) == FU_VERSION_FORMAT_UNKNOWN) { fu_device_set_version (FU_DEVICE (self), version); return TRUE; } /* AA.BB.CC.DD */ - if (g_strcmp0 (self->version_format, "quad") == 0) { + if (fu_device_get_version_format (FU_DEVICE (self)) == FU_VERSION_FORMAT_QUAD) { guint64 tmp = g_ascii_strtoull (version, NULL, 16); g_autofree gchar *version_new = NULL; if (tmp == 0 || tmp > G_MAXUINT32) { @@ -203,17 +224,16 @@ version); return FALSE; } - version_new = as_utils_version_from_uint32 (tmp, AS_VERSION_PARSE_FLAG_NONE); + version_new = fu_common_version_from_uint32 (tmp, FU_VERSION_FORMAT_QUAD); fu_device_set_version (FU_DEVICE (self), version_new); return TRUE; } /* invalid, or not supported */ - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "version format %s not recognised", - self->version_format); + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "version format not recognised"); return FALSE; } @@ -221,8 +241,10 @@ fu_nvme_device_parse_cns (FuNvmeDevice *self, const guint8 *buf, gsize sz, GError **error) { guint8 fawr; + guint8 fwug; guint8 nfws; guint8 s1ro; + g_autofree gchar *gu = NULL; g_autofree gchar *mn = NULL; g_autofree gchar *sn = NULL; g_autofree gchar *sr = NULL; @@ -251,12 +273,22 @@ return FALSE; } + /* firmware update granularity (FWUG) */ + fwug = buf[319]; + if (fwug != 0x00 && fwug != 0xff) + self->write_block_size = ((guint64) fwug) * 0x1000; + /* firmware slot information */ fawr = (buf[260] & 0x10) >> 4; nfws = (buf[260] & 0x0e) >> 1; s1ro = buf[260] & 0x01; g_debug ("fawr: %u, nr fw slots: %u, slot1 r/o: %u", fawr, nfws, s1ro); + /* FRU globally unique identifier (FGUID) */ + gu = fu_nvme_device_get_guid_safe (buf, 127); + if (gu != NULL) + fu_device_add_guid (FU_DEVICE (self), gu); + /* Dell helpfully provide an EFI GUID we can use in the vendor offset, * but don't have a header or any magic we can use -- so check if the * component ID looks plausible and the GUID is "sane" */ @@ -265,29 +297,11 @@ /* fall back to the device description */ if (fu_device_get_guids (FU_DEVICE (self))->len == 0) { g_debug ("no vendor GUID, falling back to mn"); - fu_device_add_guid (FU_DEVICE (self), mn); + fu_device_add_instance_id (FU_DEVICE (self), mn); } return TRUE; } -static guint -fu_nvme_device_pci_slot_depth (FuNvmeDevice *self) -{ - GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (self)); - g_autoptr(GUdevDevice) device_tmp = NULL; - - device_tmp = g_udev_device_get_parent_with_subsystem (udev_device, "pci", NULL); - if (device_tmp == NULL) - return 0; - for (guint i = 0; i < 0xff; i++) { - g_autoptr(GUdevDevice) parent = g_udev_device_get_parent (device_tmp); - if (parent == NULL) - return i; - g_set_object (&device_tmp, parent); - } - return 0; -} - static void fu_nvme_device_dump (const gchar *title, const guint8 *buf, gsize sz) { @@ -334,10 +348,15 @@ return FALSE; /* look at the PCI depth to work out if in an external enclosure */ - self->pci_depth = fu_nvme_device_pci_slot_depth (self); + self->pci_depth = fu_udev_device_get_slot_depth (device, "pci"); if (self->pci_depth <= 2) fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); + /* all devices need at least a warm reset, but some quirked drives + * need a full "cold" shutdown and startup */ + if (!fu_device_has_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_REBOOT); + return TRUE; } @@ -375,12 +394,21 @@ fu_nvme_device_write_firmware (FuDevice *device, GBytes *fw, GError **error) { FuNvmeDevice *self = FU_NVME_DEVICE (device); + g_autoptr(GBytes) fw2 = NULL; g_autoptr(GPtrArray) chunks = NULL; guint64 block_size = self->write_block_size > 0 ? self->write_block_size : 0x1000; + /* some vendors provide firmware files whose sizes are not multiples + * of blksz *and* the device won't accept blocks of different sizes */ + if (fu_device_has_custom_flag (device, "force-align")) { + fw2 = fu_common_bytes_align (fw, block_size, 0xff); + } else { + fw2 = g_bytes_ref (fw); + } + /* build packets */ - chunks = fu_chunk_array_new_from_bytes (fw, + chunks = fu_chunk_array_new_from_bytes (fw2, 0x00, /* start_addr */ 0x00, /* page_sz */ block_size); /* block size */ @@ -422,10 +450,6 @@ GError **error) { FuNvmeDevice *self = FU_NVME_DEVICE (device); - if (g_strcmp0 (key, "NvmeVersionFormat") == 0) { - self->version_format = g_strdup (value); - return TRUE; - } if (g_strcmp0 (key, "NvmeBlockSize") == 0) { self->write_block_size = fu_common_strtoull (value); return TRUE; @@ -443,7 +467,6 @@ { fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_REQUIRE_AC); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); - fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_REBOOT); fu_device_set_summary (FU_DEVICE (self), "NVM Express Solid State Drive"); fu_device_add_icon (FU_DEVICE (self), "drive-harddisk"); } @@ -451,8 +474,6 @@ static void fu_nvme_device_finalize (GObject *object) { - FuNvmeDevice *self = FU_NVME_DEVICE (object); - g_free (self->version_format); G_OBJECT_CLASS (fu_nvme_device_parent_class)->finalize (object); } diff -Nru fwupd-1.1.4/plugins/nvme/fu-nvme-device.h fwupd-1.2.5/plugins/nvme/fu-nvme-device.h --- fwupd-1.1.4/plugins/nvme/fu-nvme-device.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/nvme/fu-nvme-device.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_NVME_DEVICE_H -#define __FU_NVME_DEVICE_H +#pragma once #include "fu-plugin.h" @@ -20,5 +19,3 @@ GError **error); G_END_DECLS - -#endif /* __FU_NVME_DEVICE_H */ diff -Nru fwupd-1.1.4/plugins/nvme/fu-plugin-nvme.c fwupd-1.2.5/plugins/nvme/fu-plugin-nvme.c --- fwupd-1.1.4/plugins/nvme/fu-plugin-nvme.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/nvme/fu-plugin-nvme.c 2019-02-25 09:42:18.000000000 +0000 @@ -31,7 +31,9 @@ void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_udev_subsystem (plugin, "nvme"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.nvmexpress"); } gboolean diff -Nru fwupd-1.1.4/plugins/nvme/fu-self-test.c fwupd-1.2.5/plugins/nvme/fu-self-test.c --- fwupd-1.1.4/plugins/nvme/fu-self-test.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/nvme/fu-self-test.c 2019-02-25 09:42:18.000000000 +0000 @@ -8,6 +8,7 @@ #include +#include "fu-device-private.h" #include "fu-nvme-device.h" #include "fu-test.h" @@ -29,6 +30,7 @@ dev = fu_nvme_device_new_from_blob ((guint8 *)data, sz, &error); g_assert_no_error (error); g_assert_nonnull (dev); + fu_device_convert_instance_ids (FU_DEVICE (dev)); g_assert_cmpstr (fu_device_get_name (FU_DEVICE (dev)), ==, "THNSN5512GPU7 TOSHIBA"); g_assert_cmpstr (fu_device_get_version (FU_DEVICE (dev)), ==, "410557LA"); g_assert_cmpstr (fu_device_get_serial (FU_DEVICE (dev)), ==, "37RSDEADBEEF"); diff -Nru fwupd-1.1.4/plugins/nvme/meson.build fwupd-1.2.5/plugins/nvme/meson.build --- fwupd-1.1.4/plugins/nvme/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/nvme/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -1,8 +1,16 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginNvme"'] +install_data([ + 'nvme.quirk', + ], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + shared_module('fu_plugin_nvme', + fu_hash, sources : [ 'fu-plugin-nvme.c', + 'fu-nvme-common.c', 'fu-nvme-device.c', ], include_directories : [ @@ -16,9 +24,11 @@ cargs, '-DLOCALSTATEDIR="' + localstatedir + '"', ], + link_with : [ + libfwupdprivate, + ], dependencies : [ plugin_deps, - efivar, ], ) @@ -27,8 +37,10 @@ cargs += '-DTESTDATADIR="' + testdatadir + '"' e = executable( 'nvme-self-test', + fu_hash, sources : [ 'fu-self-test.c', + 'fu-nvme-common.c', 'fu-nvme-device.c', ], include_directories : [ @@ -39,10 +51,8 @@ ], dependencies : [ plugin_deps, - efivar, ], link_with : [ - fwupd, libfwupdprivate, ], c_args : cargs diff -Nru fwupd-1.1.4/plugins/nvme/nvme.quirk fwupd-1.2.5/plugins/nvme/nvme.quirk --- fwupd-1.1.4/plugins/nvme/nvme.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/nvme/nvme.quirk 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,3 @@ +# Phison +[DeviceInstanceId=NVME\VEN_1987] +Flags = force-align,needs-shutdown diff -Nru fwupd-1.1.4/plugins/nvme/README.md fwupd-1.2.5/plugins/nvme/README.md --- fwupd-1.1.4/plugins/nvme/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/nvme/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -10,3 +10,42 @@ The device GUID is read from the vendor specific area and if not found then generated from the trimmed model string. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. + +This plugin supports the following protocol ID: + + * org.nvmexpress + +GUID Generation +--------------- + +These device use the NVMe DeviceInstanceId values, e.g. + + * `NVME\VEN_1179&DEV_010F&REV_01` + * `NVME\VEN_1179&DEV_010F` + * `NVME\VEN_1179` + +The FRU globally unique identifier (FGUID) is also added from the CNS if set. +Please refer to this document for more details on how to add support for FGUID: +https://nvmexpress.org/wp-content/uploads/NVM_Express_Revision_1.3.pdf + +Additionally, for NVMe drives with Dell vendor firmware two extra GUIDs are +added: + + * `STORAGE-DELL-${component-id}` + +and any optional GUID saved in the vendor extension block. + +Quirk use +--------- +This plugin uses the following plugin-specific quirks: + +| Quirk | Description | Minimum fwupd version | +|------------------------|---------------------------------------------|-----------------------| +| `NvmeBlockSize` | The block size used for NVMe writes | 1.1.3 | +| `Flags` | `force-align` if image should be padded | 1.2.4 | diff -Nru fwupd-1.1.4/plugins/README.md fwupd-1.2.5/plugins/README.md --- fwupd-1.1.4/plugins/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -11,6 +11,9 @@ in this project, please file an issue and share the spec. Patches are also welcome. +We will not accept plugins that upgrade hardware using a proprietary Linux +executable, library, or DBus interface. + Plugin interaction ------------------ Some plugins may be able to influence the behavior of other plugins. diff -Nru fwupd-1.1.4/plugins/redfish/fu-plugin-redfish.c fwupd-1.2.5/plugins/redfish/fu-plugin-redfish.c --- fwupd-1.1.4/plugins/redfish/fu-plugin-redfish.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/redfish/fu-plugin-redfish.c 2019-02-25 09:42:18.000000000 +0000 @@ -117,6 +117,8 @@ { FuPluginData *data = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); data->client = fu_redfish_client_new (); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.dmtf.redfish"); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); } void diff -Nru fwupd-1.1.4/plugins/redfish/fu-redfish-client.h fwupd-1.2.5/plugins/redfish/fu-redfish-client.h --- fwupd-1.1.4/plugins/redfish/fu-redfish-client.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/redfish/fu-redfish-client.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_REDFISH_CLIENT_H -#define __FU_REDFISH_CLIENT_H +#pragma once #include @@ -40,7 +39,3 @@ GPtrArray *fu_redfish_client_get_devices (FuRedfishClient *self); G_END_DECLS - -#endif /* __FU_REDFISH_CLIENT_H */ - -/* vim: set noexpandtab: */ diff -Nru fwupd-1.1.4/plugins/redfish/fu-redfish-common.h fwupd-1.2.5/plugins/redfish/fu-redfish-common.h --- fwupd-1.1.4/plugins/redfish/fu-redfish-common.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/redfish/fu-redfish-common.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_REDFISH_COMMON_H -#define __FU_REDFISH_COMMON_H +#pragma once #include #include @@ -49,7 +48,3 @@ gchar *fu_redfish_common_buffer_to_ipv6 (const guint8 *buffer); G_END_DECLS - -#endif /* __FU_REDFISH_COMMON_H */ - -/* vim: set noexpandtab: */ diff -Nru fwupd-1.1.4/plugins/redfish/meson.build fwupd-1.2.5/plugins/redfish/meson.build --- fwupd-1.1.4/plugins/redfish/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/redfish/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -1,6 +1,7 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginRedfish"'] shared_module('fu_plugin_redfish', + fu_hash, sources : [ 'fu-plugin-redfish.c', 'fu-redfish-client.c', @@ -13,6 +14,9 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, @@ -28,6 +32,7 @@ if get_option('tests') e = executable( 'redfish-self-test', + fu_hash, sources : [ 'fu-self-test.c', 'fu-redfish-client.c', @@ -44,7 +49,6 @@ libjsonglib, ], link_with : [ - fwupd, libfwupdprivate, ], c_args : cargs diff -Nru fwupd-1.1.4/plugins/redfish/README.md fwupd-1.2.5/plugins/redfish/README.md --- fwupd-1.1.4/plugins/redfish/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/redfish/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -10,6 +10,22 @@ By specifying a RESTful interface and utilizing JSON and OData, Redfish helps customers integrate solutions within their existing tool chains. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. + +This plugin supports the following protocol ID: + + * org.dmtf.redfish + +GUID Generation +--------------- + +These devices use the provided GUID provided in the `SoftwareId` parameter +without modification. Devices without GUIDs are not supported. + Setting Service IP Manually --------------------------- diff -Nru fwupd-1.1.4/plugins/rts54hid/fu-plugin-rts54hid.c fwupd-1.2.5/plugins/rts54hid/fu-plugin-rts54hid.c --- fwupd-1.1.4/plugins/rts54hid/fu-plugin-rts54hid.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/rts54hid/fu-plugin-rts54hid.c 2019-02-25 09:42:18.000000000 +0000 @@ -14,7 +14,9 @@ void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.realtek.rts54"); /* register the custom types */ g_type_ensure (FU_TYPE_RTS54HID_MODULE); diff -Nru fwupd-1.1.4/plugins/rts54hid/fu-rts54hid-common.h fwupd-1.2.5/plugins/rts54hid/fu-rts54hid-common.h --- fwupd-1.1.4/plugins/rts54hid/fu-rts54hid-common.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/rts54hid/fu-rts54hid-common.h 2019-02-25 09:42:18.000000000 +0000 @@ -6,8 +6,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_RTS54HID_COMMON_H -#define __FU_RTS54HID_COMMON_H +#pragma once #define FU_RTS54HID_TRANSFER_BLOCK_SIZE 0x80 #define FU_RTS54HID_REPORT_LENGTH 0xc0 @@ -68,5 +67,3 @@ /* */ FU_RTS54HID_EXT_LAST, } FuRts54HidExt; - -#endif /* __FU_RTS54HID_COMMON_H */ diff -Nru fwupd-1.1.4/plugins/rts54hid/fu-rts54hid-device.h fwupd-1.2.5/plugins/rts54hid/fu-rts54hid-device.h --- fwupd-1.1.4/plugins/rts54hid/fu-rts54hid-device.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/rts54hid/fu-rts54hid-device.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_RTS54HID_DEVICE_H -#define __FU_RTS54HID_DEVICE_H +#pragma once #include "fu-plugin.h" @@ -25,5 +24,3 @@ GError **error); G_END_DECLS - -#endif /* __FU_RTS54HID_DEVICE_H */ diff -Nru fwupd-1.1.4/plugins/rts54hid/fu-rts54hid-module.h fwupd-1.2.5/plugins/rts54hid/fu-rts54hid-module.h --- fwupd-1.1.4/plugins/rts54hid/fu-rts54hid-module.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/rts54hid/fu-rts54hid-module.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_RTS54HID_MODULE_H -#define __FU_RTS54HID_MODULE_H +#pragma once #include "fu-plugin.h" @@ -17,5 +16,3 @@ FuRts54HidModule *fu_rts54hid_module_new (void); G_END_DECLS - -#endif /* __FU_RTS54HID_MODULE_H */ diff -Nru fwupd-1.1.4/plugins/rts54hid/meson.build fwupd-1.2.5/plugins/rts54hid/meson.build --- fwupd-1.1.4/plugins/rts54hid/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/rts54hid/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -7,6 +7,7 @@ ) shared_module('fu_plugin_rts54hid', + fu_hash, sources : [ 'fu-rts54hid-device.c', 'fu-rts54hid-module.c', @@ -19,6 +20,9 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff -Nru fwupd-1.1.4/plugins/rts54hid/README.md fwupd-1.2.5/plugins/rts54hid/README.md --- fwupd-1.1.4/plugins/rts54hid/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/rts54hid/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -10,3 +10,35 @@ Other devices connected to the RTS54HIDxx using I2C will be supported soon. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. + +This plugin supports the following protocol ID: + + * com.realtek.rts54 + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_0BDA&PID_1100&REV_0001` + * `USB\VID_0BDA&PID_1100` + * `USB\VID_0BDA` + +Child I²C devices are created using the device number as a suffix, for instance: + + * `USB\VID_0BDA&PID_1100&I2C_01` + +Quirk use +--------- +This plugin uses the following plugin-specific quirks: + +| Quirk | Description | Minimum fwupd version | +|------------------------|---------------------------------------------|-----------------------| +| `Rts54SlaveAddr` | The slave address of a child module. | 1.1.3 | +| `Rts54I2cSpeed` | The I2C speed to operate at (0, 1, 2). | 1.1.3 | +| `Rts54RegisterAddrLen` | The I2C register address length of commands | 1.1.3 | diff -Nru fwupd-1.1.4/plugins/rts54hub/fu-plugin-rts54hub.c fwupd-1.2.5/plugins/rts54hub/fu-plugin-rts54hub.c --- fwupd-1.1.4/plugins/rts54hub/fu-plugin-rts54hub.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/rts54hub/fu-plugin-rts54hub.c 2019-02-25 09:42:18.000000000 +0000 @@ -13,7 +13,9 @@ void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.realtek.rts54"); } gboolean diff -Nru fwupd-1.1.4/plugins/rts54hub/fu-rts54hub-device.h fwupd-1.2.5/plugins/rts54hub/fu-rts54hub-device.h --- fwupd-1.1.4/plugins/rts54hub/fu-rts54hub-device.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/rts54hub/fu-rts54hub-device.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_RTS54HUB_DEVICE_H -#define __FU_RTS54HUB_DEVICE_H +#pragma once #include "fu-plugin.h" @@ -17,5 +16,3 @@ FuRts54HubDevice *fu_rts54hub_device_new (FuUsbDevice *device); G_END_DECLS - -#endif /* __FU_RTS54HUB_DEVICE_H */ diff -Nru fwupd-1.1.4/plugins/rts54hub/meson.build fwupd-1.2.5/plugins/rts54hub/meson.build --- fwupd-1.1.4/plugins/rts54hub/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/rts54hub/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -7,6 +7,7 @@ ) shared_module('fu_plugin_rts54hub', + fu_hash, sources : [ 'fu-rts54hub-device.c', 'fu-plugin-rts54hub.c', @@ -18,6 +19,9 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff -Nru fwupd-1.1.4/plugins/rts54hub/README.md fwupd-1.2.5/plugins/rts54hub/README.md --- fwupd-1.1.4/plugins/rts54hub/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/rts54hub/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -10,3 +10,21 @@ Other devices connected to the RTS54xx using I2C will be supported soon. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. + +This plugin supports the following protocol ID: + + * com.realtek.rts54 + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_0BDA&PID_5423&REV_0001` + * `USB\VID_0BDA&PID_5423` + * `USB\VID_0BDA` diff -Nru fwupd-1.1.4/plugins/steelseries/fu-plugin-steelseries.c fwupd-1.2.5/plugins/steelseries/fu-plugin-steelseries.c --- fwupd-1.1.4/plugins/steelseries/fu-plugin-steelseries.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/steelseries/fu-plugin-steelseries.c 2019-02-25 09:42:18.000000000 +0000 @@ -13,6 +13,7 @@ void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); } diff -Nru fwupd-1.1.4/plugins/steelseries/fu-steelseries-device.h fwupd-1.2.5/plugins/steelseries/fu-steelseries-device.h --- fwupd-1.1.4/plugins/steelseries/fu-steelseries-device.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/steelseries/fu-steelseries-device.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_STEELSERIES_DEVICE_H -#define __FU_STEELSERIES_DEVICE_H +#pragma once #include "fu-plugin.h" @@ -22,5 +21,3 @@ FuSteelseriesDevice *fu_steelseries_device_new (FuUsbDevice *device); G_END_DECLS - -#endif /* __FU_STEELSERIES_DEVICE_H */ diff -Nru fwupd-1.1.4/plugins/steelseries/meson.build fwupd-1.2.5/plugins/steelseries/meson.build --- fwupd-1.1.4/plugins/steelseries/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/steelseries/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -5,6 +5,7 @@ ) shared_module('fu_plugin_steelseries', + fu_hash, sources : [ 'fu-plugin-steelseries.c', 'fu-steelseries-device.c', @@ -16,6 +17,9 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff -Nru fwupd-1.1.4/plugins/steelseries/README.md fwupd-1.2.5/plugins/steelseries/README.md --- fwupd-1.1.4/plugins/steelseries/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/steelseries/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -7,3 +7,12 @@ This plugin is used to get the correct version number on SteelSeries gaming mice. These mice have updatable firmware but so far no updates are available from the vendor. + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_1038&PID_1702&REV_0001` + * `USB\VID_1038&PID_1702` + * `USB\VID_1038` diff -Nru fwupd-1.1.4/plugins/superio/fu-plugin-superio.c fwupd-1.2.5/plugins/superio/fu-plugin-superio.c --- fwupd-1.1.4/plugins/superio/fu-plugin-superio.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/superio/fu-plugin-superio.c 2019-02-25 09:42:18.000000000 +0000 @@ -19,8 +19,7 @@ g_autoptr(FuDeviceLocker) locker = NULL; g_autofree gchar *key = g_strdup_printf ("SuperIO=%s", chipset); guint64 id; - guint64 data_port; - guint64 cmd_port; + guint64 port; /* get ID we need for the chipset */ id = fu_plugin_lookup_quirk_by_id_as_uint64 (plugin, key, "Id"); @@ -32,28 +31,18 @@ return FALSE; } - /* allow using a custom data port */ - data_port = fu_plugin_lookup_quirk_by_id_as_uint64 (plugin, key, "DataPort"); - if (data_port > 0xff) { + /* set address */ + port = fu_plugin_lookup_quirk_by_id_as_uint64 (plugin, key, "Port"); + if (port == 0x0 || port > 0xffff) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "SuperIO chip %s has invalid DataPort", chipset); - return FALSE; - } - - /* allow using a custom command port */ - cmd_port = fu_plugin_lookup_quirk_by_id_as_uint64 (plugin, key, "CmdPort"); - if (cmd_port > 0xff) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "SuperIO chip %s has invalid CmdPort", chipset); + "SuperIO chip %s has invalid Port", chipset); return FALSE; } /* create device and unlock */ - dev = fu_superio_device_new (chipset, id, data_port, cmd_port); + dev = fu_superio_device_new (chipset, id, port); locker = fu_device_locker_new (dev, error); if (locker == NULL) return FALSE; @@ -73,6 +62,12 @@ return TRUE; } +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + gboolean fu_plugin_coldplug (FuPlugin *plugin, GError **error) { diff -Nru fwupd-1.1.4/plugins/superio/fu-superio-common.c fwupd-1.2.5/plugins/superio/fu-superio-common.c --- fwupd-1.1.4/plugins/superio/fu-superio-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/superio/fu-superio-common.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-superio-common.h" + +gboolean +fu_superio_outb (gint fd, guint16 port, guint8 data, GError **error) +{ + if (pwrite (fd, &data, 1, (goffset) port) != 1) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to write to port %04x: %s", + (guint) port, + strerror (errno)); + return FALSE; + } + return TRUE; +} + +gboolean +fu_superio_inb (gint fd, guint16 port, guint8 *data, GError **error) +{ + if (pread (fd, data, 1, (goffset) port) != 1) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to read from port %04x: %s", + (guint) port, + strerror (errno)); + return FALSE; + } + return TRUE; +} + +gboolean +fu_superio_regval (gint fd, guint16 port, guint8 addr, + guint8 *data, GError **error) +{ + if (!fu_superio_outb (fd, port, addr, error)) + return FALSE; + if (!fu_superio_inb (fd, port + 1, data, error)) + return FALSE; + return TRUE; +} + +gboolean +fu_superio_regval16 (gint fd, guint16 port, guint8 addr, + guint16 *data, GError **error) +{ + guint8 msb; + guint8 lsb; + if (!fu_superio_regval (fd, port, addr, &msb, error)) + return FALSE; + if (!fu_superio_regval (fd, port, addr + 1, &lsb, error)) + return FALSE; + *data = ((guint16) msb << 8) | (guint16) lsb; + return TRUE; +} + +gboolean +fu_superio_regwrite (gint fd, guint16 port, guint8 addr, + guint8 data, GError **error) +{ + if (!fu_superio_outb (fd, port, addr, error)) + return FALSE; + if (!fu_superio_outb (fd, port + 1, data, error)) + return FALSE; + return TRUE; +} + +gboolean +fu_superio_set_ldn (gint fd, guint16 port, guint8 ldn, GError **error) +{ + return fu_superio_regwrite (fd, port, SIO_LDNxx_IDX_LDNSEL, ldn, error); +} + +const gchar * +fu_superio_ldn_to_text (guint8 ldn) +{ + if (ldn == SIO_LDN_FDC) + return "Floppy Disk Controller"; + if (ldn == SIO_LDN_GPIO) + return "General Purpose IO"; + if (ldn == SIO_LDN_PARALLEL_PORT) + return "Parallel Port"; + if (ldn == SIO_LDN_UART1) + return "Serial Port 1"; + if (ldn == SIO_LDN_UART2) + return "Serial Port 2"; + if (ldn == SIO_LDN_UART3) + return "Serial Port 3"; + if (ldn == SIO_LDN_UART4) + return "Serial Port 4"; + if (ldn == SIO_LDN_SWUC) + return "System Wake-Up Control"; + if (ldn == SIO_LDN_KBC_MOUSE) + return "KBC/Mouse"; + if (ldn == SIO_LDN_KBC_KEYBOARD) + return "KBC/Keyboard"; + if (ldn == SIO_LDN_CIR) + return "Consumer IR"; + if (ldn == SIO_LDN_SMFI) + return "Shared Memory/Flash"; + if (ldn == SIO_LDN_RTCT) + return "RTC-like Timer"; + if (ldn == SIO_LDN_SSSP1) + return "Serial Peripheral"; + if (ldn == SIO_LDN_PECI) + return "Platform Environmental Control"; + if (ldn == SIO_LDN_PM1) + return "Power Management 1"; + if (ldn == SIO_LDN_PM2) + return "Power Management 2"; + if (ldn == SIO_LDN_PM3) + return "Power Management 3"; + if (ldn == SIO_LDN_PM4) + return "Power Management 4"; + if (ldn == SIO_LDN_PM5) + return "Power Management 5"; + return NULL; +} + +gboolean +fu_superio_regdump (gint fd, guint16 port, guint8 ldn, GError **error) +{ + const gchar *ldnstr = fu_superio_ldn_to_text (ldn); + guint8 buf[0xff] = { 0x00 }; + guint16 iobad0 = 0x0; + guint16 iobad1 = 0x0; + g_autoptr(GString) str = g_string_new (NULL); + + /* set LDN */ + if (!fu_superio_set_ldn (fd, port, ldn, error)) + return FALSE; + for (guint i = 0x00; i < 0xff; i++) { + if (!fu_superio_regval (fd, port, i, &buf[i], error)) + return FALSE; + } + + /* get the i/o base addresses */ + if (!fu_superio_regval16 (fd, port, SIO_LDNxx_IDX_IOBAD0, &iobad0, error)) + return FALSE; + if (!fu_superio_regval16 (fd, port, SIO_LDNxx_IDX_IOBAD1, &iobad1, error)) + return FALSE; + + g_string_append_printf (str, "PORT:0x%04x ", port); + g_string_append_printf (str, "LDN:0x%02x ", ldn); + if (iobad0 != 0x0) + g_string_append_printf (str, "IOBAD0:0x%04x ", iobad0); + if (iobad1 != 0x0) + g_string_append_printf (str, "IOBAD1:0x%04x ", iobad1); + if (ldnstr != NULL) + g_string_append_printf (str, "(%s)", ldnstr); + fu_common_dump_raw (G_LOG_DOMAIN, str->str, buf, 0x100); + return TRUE; +} diff -Nru fwupd-1.1.4/plugins/superio/fu-superio-common.h fwupd-1.2.5/plugins/superio/fu-superio-common.h --- fwupd-1.1.4/plugins/superio/fu-superio-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/superio/fu-superio-common.h 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +G_BEGIN_DECLS + +/* for all LDNs */ +#define SIO_LDNxx_IDX_LDNSEL 0x07 +#define SIO_LDNxx_IDX_CHIPID1 0x20 +#define SIO_LDNxx_IDX_CHIPID2 0x21 +#define SIO_LDNxx_IDX_CHIPVER 0x22 +#define SIO_LDNxx_IDX_SIOCTRL 0x23 +#define SIO_LDNxx_IDX_SIOIRQ 0x25 +#define SIO_LDNxx_IDX_SIOGP 0x26 +#define SIO_LDNxx_IDX_SIOPWR 0x2d +#define SIO_LDNxx_IDX_D2ADR 0x2e +#define SIO_LDNxx_IDX_D2DAT 0x2f + +#define SIO_LDNxx_IDX_IOBAD0 0x60 /* 16 bit */ +#define SIO_LDNxx_IDX_IOBAD1 0x62 /* 16 bit */ + +typedef enum { + SIO_LDN_FDC = 0x00, /* IT87 */ + SIO_LDN_UART1 = 0x01, /* IT87+IT89 */ + SIO_LDN_UART2 = 0x02, /* IT87+IT89 */ + SIO_LDN_PARALLEL_PORT = 0x03, /* IT87 */ + SIO_LDN_SWUC = 0x04, /* IT87+IT89 */ + SIO_LDN_KBC_MOUSE = 0x05, /* IT87+IT89 */ + SIO_LDN_KBC_KEYBOARD = 0x06, /* IT87+IT89 */ + SIO_LDN_GPIO = 0x07, /* IT87 */ + SIO_LDN_UART3 = 0x08, /* IT87 */ + SIO_LDN_UART4 = 0x09, /* IT87 */ + SIO_LDN_CIR = 0x0a, /* IT89 */ + SIO_LDN_SMFI = 0x0f, /* IT89 */ + SIO_LDN_RTCT = 0x10, /* IT89 */ + SIO_LDN_PM1 = 0x11, /* IT89 */ + SIO_LDN_PM2 = 0x12, /* IT89 */ + SIO_LDN_SSSP1 = 0x13, /* IT89 */ + SIO_LDN_PECI = 0x14, /* IT89 */ + SIO_LDN_PM3 = 0x17, /* IT89 */ + SIO_LDN_PM4 = 0x18, /* IT89 */ + SIO_LDN_PM5 = 0x19, /* IT89 */ + SIO_LDN_LAST = 0x1a +} SioLdn; + +const gchar *fu_superio_ldn_to_text (guint8 ldn); +gboolean fu_superio_outb (gint fd, + guint16 port, + guint8 data, + GError **error); +gboolean fu_superio_inb (gint fd, + guint16 port, + guint8 *data, + GError **error); +gboolean fu_superio_regval (gint fd, + guint16 port, + guint8 addr, + guint8 *data, + GError **error); +gboolean fu_superio_regval16 (gint fd, + guint16 port, + guint8 addr, + guint16 *data, + GError **error); +gboolean fu_superio_regwrite (gint fd, + guint16 port, + guint8 addr, + guint8 data, + GError **error); +gboolean fu_superio_regdump (gint fd, + guint16 port, + guint8 ldn, + GError **error); +gboolean fu_superio_set_ldn (gint fd, + guint16 port, + guint8 ldn, + GError **error); + +G_END_DECLS diff -Nru fwupd-1.1.4/plugins/superio/fu-superio-device.c fwupd-1.2.5/plugins/superio/fu-superio-device.c --- fwupd-1.1.4/plugins/superio/fu-superio-device.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/superio/fu-superio-device.c 2019-02-25 09:42:18.000000000 +0000 @@ -12,19 +12,37 @@ #include +#include "fu-superio-common.h" #include "fu-superio-device.h" -#define FU_PLUGIN_SUPERIO_TIMEOUT 5 /* s */ +#define FU_PLUGIN_SUPERIO_TIMEOUT 0.25 /* s */ -#define KB_IBF (1 << 1) /* i/p buffer full */ -#define KB_OBF (1 << 0) /* o/p buffer full */ +/* EC Status Register (see ec/google/chromeec/ec_commands.h) */ +#define SIO_STATUS_EC_OBF (1 << 0) /* o/p buffer full */ +#define SIO_STATUS_EC_IBF (1 << 1) /* i/p buffer full */ +#define SIO_STATUS_EC_IS_BUSY (1 << 2) +#define SIO_STATUS_EC_IS_CMD (1 << 3) +#define SIO_STATUS_EC_BURST_ENABLE (1 << 4) +#define SIO_STATUS_EC_SCI (1 << 5) /* 1 if more events in queue */ + +/* EC Command Register (see KB3700-ds-01.pdf) */ +#define SIO_CMD_EC_READ 0x80 +#define SIO_CMD_EC_WRITE 0x81 +#define SIO_CMD_EC_BURST_ENABLE 0x82 +#define SIO_CMD_EC_BURST_DISABLE 0x83 +#define SIO_CMD_EC_QUERY_EVENT 0x84 + +/* unknown source, IT87 only */ +#define SIO_CMD_EC_GET_NAME_STR 0x92 +#define SIO_CMD_EC_GET_VERSION_STR 0x93 struct _FuSuperioDevice { FuDevice parent_instance; gint fd; gchar *chipset; - guint16 data_port; - guint16 cmd_port; + guint16 port; + guint16 pm1_iobad0; + guint16 pm1_iobad1; guint16 id; guint32 size; }; @@ -38,60 +56,22 @@ g_string_append (str, " FuSuperioDevice:\n"); g_string_append_printf (str, " fd:\t\t\t%i\n", self->fd); g_string_append_printf (str, " chipset:\t\t%s\n", self->chipset); - g_string_append_printf (str, " data-port:\t\t0x%04x\n", (guint) self->data_port); - g_string_append_printf (str, " cmd-port:\t\t0x%04x\n", (guint) self->cmd_port); g_string_append_printf (str, " id:\t\t\t0x%04x\n", (guint) self->id); + g_string_append_printf (str, " port:\t\t0x%04x\n", (guint) self->port); + g_string_append_printf (str, " pm1-iobad0:\t\t0x%04x\n", (guint) self->pm1_iobad0); + g_string_append_printf (str, " pm1-iobad1:\t\t0x%04x\n", (guint) self->pm1_iobad1); g_string_append_printf (str, " size:\t\t0x%04x\n", (guint) self->size); } -static gboolean -fu_superio_device_outb (FuSuperioDevice *self, guint16 port, guint8 data, GError **error) -{ - if (pwrite (self->fd, &data, 1, (goffset) port) != 1) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to write to port %04x: %s", - (guint) port, - strerror (errno)); - return FALSE; - } - return TRUE; -} - -static gboolean -fu_superio_device_inb (FuSuperioDevice *self, guint16 port, guint8 *data, GError **error) -{ - if (pread (self->fd, data, 1, (goffset) port) != 1) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to read from port %04x: %s", - (guint) port, - strerror (errno)); - return FALSE; - } - return TRUE; -} - static guint16 fu_superio_device_check_id (FuSuperioDevice *self, GError **error) { - guint8 msb; - guint8 lsb; guint16 id_tmp; - if (!fu_superio_device_outb (self, 0x2e, 0x20, error)) - return FALSE; - if (!fu_superio_device_inb (self, 0x2f, &msb, error)) + /* check ID, which can be done from any LDN */ + if (!fu_superio_regval16 (self->fd, self->port, + SIO_LDNxx_IDX_CHIPID1, &id_tmp, error)) return FALSE; - if (!fu_superio_device_outb (self, 0x2e, 0x21, error)) - return FALSE; - if (!fu_superio_device_inb (self, 0x2f, &lsb, error)) - return FALSE; - - /* check matches */ - id_tmp = ((guint16) msb << 8) | (guint16) lsb; if (self->id != id_tmp) { g_set_error (error, G_IO_ERROR, @@ -110,11 +90,11 @@ g_autoptr(GTimer) timer = g_timer_new (); do { guint8 status = 0x00; - if (!fu_superio_device_inb (self, self->cmd_port, &status, error)) + if (!fu_superio_inb (self->fd, self->pm1_iobad1, &status, error)) return FALSE; if (g_timer_elapsed (timer, NULL) > FU_PLUGIN_SUPERIO_TIMEOUT) break; - if (set && (status & mask) > 0) + if (set && (status & mask) != 0) return TRUE; if (!set && (status & mask) == 0) return TRUE; @@ -127,27 +107,25 @@ } static gboolean -fu_superio_device_ec_cmd (FuSuperioDevice *self, guint8 data, GError **error) +fu_superio_device_ec_read (FuSuperioDevice *self, + guint16 port, + guint8 *data, + GError **error) { - if (!fu_superio_device_wait_for (self, KB_IBF, FALSE, error)) + if (!fu_superio_device_wait_for (self, SIO_STATUS_EC_OBF, TRUE, error)) return FALSE; - return fu_superio_device_outb (self, self->cmd_port, data, error); + return fu_superio_inb (self->fd, port, data, error); } static gboolean -fu_superio_device_ec_read (FuSuperioDevice *self, guint8 *data, GError **error) +fu_superio_device_ec_write (FuSuperioDevice *self, + guint16 port, + guint8 data, + GError **error) { - if (!fu_superio_device_wait_for (self, KB_OBF, TRUE, error)) + if (!fu_superio_device_wait_for (self, SIO_STATUS_EC_IBF, FALSE, error)) return FALSE; - return fu_superio_device_inb (self, self->data_port, data, error); -} - -static gboolean -fu_superio_device_ec_write (FuSuperioDevice *self, guint8 data, GError **error) -{ - if (!fu_superio_device_wait_for (self, KB_IBF, FALSE, error)) - return FALSE; - return fu_superio_device_outb (self, self->data_port, data, error); + return fu_superio_outb (self->fd, port, data, error); } static gboolean @@ -157,11 +135,11 @@ g_autoptr(GTimer) timer = g_timer_new (); do { guint8 unused = 0; - if (!fu_superio_device_inb (self, self->cmd_port, &status, error)) + if (!fu_superio_inb (self->fd, self->pm1_iobad1, &status, error)) return FALSE; - if ((status & KB_OBF) == 0) + if ((status & SIO_STATUS_EC_OBF) == 0) break; - if (!fu_superio_device_inb (self, self->data_port, &unused, error)) + if (!fu_superio_inb (self->fd, self->pm1_iobad0, &unused, error)) return FALSE; if (g_timer_elapsed (timer, NULL) > FU_PLUGIN_SUPERIO_TIMEOUT) { g_set_error_literal (error, @@ -177,22 +155,24 @@ static gboolean fu_superio_device_ec_get_param (FuSuperioDevice *self, guint8 param, guint8 *data, GError **error) { - if (!fu_superio_device_ec_cmd (self, 0x80, error)) + if (!fu_superio_device_ec_write (self, self->pm1_iobad1, + SIO_CMD_EC_READ, error)) return FALSE; - if (!fu_superio_device_ec_write (self, param, error)) + if (!fu_superio_device_ec_write (self, self->pm1_iobad0, param, error)) return FALSE; - return fu_superio_device_ec_read (self, data, error); + return fu_superio_device_ec_read (self, self->pm1_iobad0, data, error); } #if 0 static gboolean fu_superio_device_ec_set_param (FuSuperioDevice *self, guint8 param, guint8 data, GError **error) { - if (!fu_superio_device_ec_cmd (self, 0x81, error)) + if (!fu_superio_device_ec_write (self, self->pm1_iobad1, + SIO_CMD_EC_WRITE, error)) return FALSE; - if (!fu_superio_device_ec_write (self, param, error)) + if (!fu_superio_device_ec_write (self, self->pm1_iobad0, param, error)) return FALSE; - return fu_superio_device_ec_write (self, data, error); + return fu_superio_device_ec_write (self, self->pm1_iobad0, data, error); } #endif @@ -200,11 +180,11 @@ fu_superio_device_ec_get_str (FuSuperioDevice *self, guint8 idx, GError **error) { GString *str = g_string_new (NULL); - if (!fu_superio_device_ec_cmd (self, idx, error)) + if (!fu_superio_device_ec_write (self, self->pm1_iobad1, idx, error)) return NULL; for (guint i = 0; i < 0xff; i++) { guint8 c = 0; - if (!fu_superio_device_ec_read (self, &c, error)) + if (!fu_superio_device_ec_read (self, self->pm1_iobad0, &c, error)) return NULL; if (c == '$') break; @@ -238,45 +218,172 @@ fu_superio_device_probe (FuDevice *device, GError **error) { FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); - g_autofree gchar *guid = NULL; + g_autofree gchar *devid = NULL; /* use the chipset name as the logical ID and for the GUID */ fu_device_set_logical_id (device, self->chipset); - guid = g_strdup_printf ("SuperIO-%s", self->chipset); - fu_device_add_guid (device, guid); + devid = g_strdup_printf ("SuperIO-%s", self->chipset); + fu_device_add_instance_id (device, devid); return TRUE; } static gboolean -fu_superio_device_setup (FuDevice *device, GError **error) +fu_superio_device_setup_it85xx (FuSuperioDevice *self, GError **error) { - FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); guint8 size_tmp = 0; g_autofree gchar *name = NULL; g_autofree gchar *version = NULL; + /* get EC size */ + if (!fu_superio_device_ec_flush (self, error)) { + g_prefix_error (error, "failed to flush: "); + return FALSE; + } + if (!fu_superio_device_ec_get_param (self, 0xe5, &size_tmp, error)) { + g_prefix_error (error, "failed to get EC size: "); + return FALSE; + } + self->size = ((guint32) size_tmp) << 10; + + /* get EC strings */ + name = fu_superio_device_ec_get_str (self, SIO_CMD_EC_GET_NAME_STR, error); + if (name == NULL) { + g_prefix_error (error, "failed to get EC name: "); + return FALSE; + } + fu_device_set_name (FU_DEVICE (self), name); + version = fu_superio_device_ec_get_str (self, SIO_CMD_EC_GET_VERSION_STR, error); + if (version == NULL) { + g_prefix_error (error, "failed to get EC version: "); + return FALSE; + } + fu_device_set_version (FU_DEVICE (self), version); + return TRUE; +} + +static gboolean +fu_superio_device_setup_it89xx (FuSuperioDevice *self, GError **error) +{ + guint8 version_tmp[2] = { 0x00 }; + g_autofree gchar *version = NULL; + + /* get version */ + if (!fu_superio_device_ec_flush (self, error)) { + g_prefix_error (error, "failed to flush: "); + return FALSE; + } + if (!fu_superio_device_ec_get_param (self, 0x00, &version_tmp[0], error)) { + g_prefix_error (error, "failed to get version major: "); + return FALSE; + } + if (!fu_superio_device_ec_get_param (self, 0x01, &version_tmp[1], error)) { + g_prefix_error (error, "failed to get version minor: "); + return FALSE; + } + version = g_strdup_printf ("%02u.%02u", version_tmp[0], version_tmp[1]); + fu_device_set_version (FU_DEVICE (self), version); + + /* FIXME: hardcoded */ + self->size = 0x20000; + return TRUE; +} + +static gboolean +fu_superio_device_setup (FuDevice *device, GError **error) +{ + FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); + /* check ID is correct */ if (!fu_superio_device_check_id (self, error)) { g_prefix_error (error, "failed to probe id: "); return FALSE; } - /* get EC size */ - if (!fu_superio_device_ec_flush (self, error)) + /* dump LDNs */ + if (g_getenv ("FWUPD_SUPERIO_VERBOSE") != NULL) { + for (guint j = 0; j < SIO_LDN_LAST; j++) { + if (!fu_superio_regdump (self->fd, self->port, j, error)) + return FALSE; + } + } + + /* set Power Management I/F Channel 1 LDN */ + if (!fu_superio_set_ldn (self->fd, self->port, SIO_LDN_PM1, error)) return FALSE; - if (!fu_superio_device_ec_get_param (self, 0xe5, &size_tmp, error)) + + /* get the PM1 IOBAD0 address */ + if (!fu_superio_regval16 (self->fd, self->port, + SIO_LDNxx_IDX_IOBAD0, + &self->pm1_iobad0, error)) + return FALSE; + + /* get the PM1 IOBAD1 address */ + if (!fu_superio_regval16 (self->fd, self->port, + SIO_LDNxx_IDX_IOBAD1, + &self->pm1_iobad1, error)) + return FALSE; + + /* dump PMC register map */ + if (g_getenv ("FWUPD_SUPERIO_VERBOSE") != NULL) { + guint8 buf[0xff] = { 0x00 }; + for (guint i = 0x00; i < 0xff; i++) { + g_autoptr(GError) error_local = NULL; + if (!fu_superio_device_ec_get_param (self, i, &buf[i], &error_local)) { + g_debug ("param: 0x%02x = %s", i, error_local->message); + continue; + } + } + fu_common_dump_raw (G_LOG_DOMAIN, "EC Registers", buf, 0x100); + } + + /* IT85xx */ + if (self->id >> 8 == 0x85) { + if (!fu_superio_device_setup_it85xx (self, error)) + return FALSE; + } + + /* IT89xx */ + if (self->id >> 8 == 0x89) { + if (!fu_superio_device_setup_it89xx (self, error)) + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_superio_device_attach (FuDevice *device, GError **error) +{ + FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); + + /* re-enable HOSTWA -- use 0xfd for LCFC */ + if (!fu_superio_device_ec_write (self, self->pm1_iobad1, 0xfc, error)) return FALSE; - self->size = ((guint32) size_tmp) << 10; - /* get EC strings */ - name = fu_superio_device_ec_get_str (self, 0x92, error); - if (name == NULL) + /* success */ + return TRUE; +} + +static gboolean +fu_superio_device_detach (FuDevice *device, GError **error) +{ + FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); + guint8 tmp = 0x00; + + /* turn off HOSTWA bit, keeping HSEMIE and HSEMW high */ + if (!fu_superio_device_ec_write (self, self->pm1_iobad1, 0xdc, error)) + return FALSE; + if (!fu_superio_device_ec_read (self, self->pm1_iobad0, &tmp, error)) return FALSE; - fu_device_set_name (device, name); - version = fu_superio_device_ec_get_str (self, 0x93, error); - if (version == NULL) + if (tmp != 0x33) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "failed to clear HOSTWA, got 0x%02x, expected 0x33", + tmp); return FALSE; - fu_device_set_version (device, version); + } /* success */ return TRUE; @@ -315,19 +422,20 @@ object_class->finalize = fu_superio_device_finalize; klass_device->to_string = fu_superio_device_to_string; klass_device->open = fu_superio_device_open; + klass_device->attach = fu_superio_device_attach; + klass_device->detach = fu_superio_device_detach; klass_device->probe = fu_superio_device_probe; klass_device->setup = fu_superio_device_setup; klass_device->close = fu_superio_device_close; } FuSuperioDevice * -fu_superio_device_new (const gchar *chipset, guint16 id, guint8 data_port, guint8 cmd_port) +fu_superio_device_new (const gchar *chipset, guint16 id, guint16 port) { FuSuperioDevice *self; self = g_object_new (FU_TYPE_SUPERIO_DEVICE, NULL); self->chipset = g_strdup (chipset); self->id = id; - self->data_port = data_port > 0 ? data_port : 0x62; - self->cmd_port = cmd_port > 0 ? cmd_port : 0x66; + self->port = port; return self; } diff -Nru fwupd-1.1.4/plugins/superio/fu-superio-device.h fwupd-1.2.5/plugins/superio/fu-superio-device.h --- fwupd-1.1.4/plugins/superio/fu-superio-device.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/superio/fu-superio-device.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_SUPERIO_DEVICE_H -#define __FU_SUPERIO_DEVICE_H +#pragma once #include "fu-plugin.h" @@ -16,9 +15,6 @@ FuSuperioDevice *fu_superio_device_new (const gchar *chipset, guint16 id, - guint8 data_port, - guint8 cmd_port); + guint16 port); G_END_DECLS - -#endif /* __FU_SUPERIO_DEVICE_H */ diff -Nru fwupd-1.1.4/plugins/superio/meson.build fwupd-1.2.5/plugins/superio/meson.build --- fwupd-1.1.4/plugins/superio/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/superio/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -5,9 +5,11 @@ ) shared_module('fu_plugin_superio', + fu_hash, sources : [ 'fu-plugin-superio.c', 'fu-superio-device.c', + 'fu-superio-common.c', ], include_directories : [ include_directories('../..'), @@ -16,6 +18,9 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff -Nru fwupd-1.1.4/plugins/superio/README.md fwupd-1.2.5/plugins/superio/README.md --- fwupd-1.1.4/plugins/superio/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/superio/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -20,3 +20,10 @@ * https://github.com/coreboot/coreboot/blob/master/util/superiotool/superiotool.h * https://github.com/flashrom/flashrom/blob/master/it85spi.c * http://wiki.laptop.org/go/Ec_specification + +GUID Generation +--------------- + +These devices use a custom GUID generated using the SuperIO chipset name: + + * `SuperIO-$(chipset)`, for example `SuperIO-IT8512` diff -Nru fwupd-1.1.4/plugins/superio/superio.quirk fwupd-1.2.5/plugins/superio/superio.quirk --- fwupd-1.1.4/plugins/superio/superio.quirk 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/superio/superio.quirk 2019-02-25 09:42:18.000000000 +0000 @@ -6,23 +6,42 @@ [HwId=f00d8c4e-dce2-51c3-89d6-6cbc5fc5cdbb] SuperioChipsets=IT8587 +# Star LabTop Mk3 +[HwId=3dc52d2c-9e9b-5ba5-b10d-9ba1eb11dacc] +SuperioChipsets=IT8987 + +# Star Lite Mk2 +[HwId=d1a64840-4307-58fb-a62c-de28a07c0151] +SuperioChipsets=IT8987 + [SuperIO=IT8510] Id=0x8510 +Port=0x2e [SuperIO=IT8511] Id=0x8511 +Port=0x2e [SuperIO=IT8512] Id=0x8512 +Port=0x2e [SuperIO=IT8513] Id=0x8513 +Port=0x2e [SuperIO=IT8516] Id=0x8516 +Port=0x2e [SuperIO=IT8518] Id=0x8518 +Port=0x2e [SuperIO=IT8587] Id=0x8587 +Port=0x2e + +[SuperIO=IT8987] +Id=0x8987 +Port=0x4e diff -Nru fwupd-1.1.4/plugins/synapticsmst/fu-plugin-synapticsmst.c fwupd-1.2.5/plugins/synapticsmst/fu-plugin-synapticsmst.c --- fwupd-1.1.4/plugins/synapticsmst/fu-plugin-synapticsmst.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/synapticsmst/fu-plugin-synapticsmst.c 2019-02-25 09:42:18.000000000 +0000 @@ -41,9 +41,8 @@ const gchar *str) { guint16 board_id = synapticsmst_device_get_board_id (device); - g_autofree gchar *guid = g_strdup_printf ("MST-%s-%u", str, board_id); - - fu_device_add_guid (fu_device, guid); + g_autofree gchar *devid = g_strdup_printf ("MST-%s-%u", str, board_id); + fu_device_add_instance_id (fu_device, devid); } /* creates MST-$str-$chipid-$BOARDID */ @@ -171,6 +170,10 @@ fu_plugin_device_add (plugin, dev); fu_plugin_cache_add (plugin, dev_id_str, dev); + + /* inhibit the idle sleep of the daemon */ + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_INHIBITS_IDLE, + "SynapticsMST can cause the screen to flash when probing"); return TRUE; } @@ -467,4 +470,6 @@ { /* make sure dell is already coldplugged */ fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "dell"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.synaptics.mst"); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); } diff -Nru fwupd-1.1.4/plugins/synapticsmst/meson.build fwupd-1.2.5/plugins/synapticsmst/meson.build --- fwupd-1.1.4/plugins/synapticsmst/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/synapticsmst/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -5,6 +5,7 @@ ) shared_module('fu_plugin_synapticsmst', + fu_hash, sources : [ 'fu-plugin-synapticsmst.c', 'synapticsmst-common.c', @@ -18,8 +19,11 @@ install : true, install_dir: plugin_dir, c_args : [ - cargs, - ], + cargs, + ], + link_with : [ + libfwupdprivate, + ], dependencies : [ plugin_deps, ], @@ -31,6 +35,7 @@ cargs += '-DSOURCEDIR="' + meson.current_source_dir() + '"' e = executable( 'synapticsmst-self-test', + fu_hash, sources : [ 'fu-self-test.c', 'synapticsmst-common.c', @@ -47,7 +52,6 @@ valgrind, ], link_with : [ - fwupd, libfwupdprivate, ], c_args : [ diff -Nru fwupd-1.1.4/plugins/synapticsmst/README.md fwupd-1.2.5/plugins/synapticsmst/README.md --- fwupd-1.1.4/plugins/synapticsmst/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/synapticsmst/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -3,6 +3,26 @@ This plugin supports querying and flashing Synaptics MST hubs used in Dell systems and docks. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. + +This plugin supports the following protocol ID: + + * com.synaptics.mst + +GUID Generation +--------------- + +These devices use custom GUID values, e.g. + + * `MST-$(device_kind)-$(chip-ID)-$(board-ID)` + +Please refer to the plugin source for more details about how the GUID is +constructed for specific hardware. + ## Requirements ### (Kernel) DP Aux Interface Kernel 4.6 introduced an DRM DP Aux interface for manipulation of the registers @@ -41,18 +61,19 @@ ## Supported devices Not all Dell systems or accessories contain MST hubs. Here is a sample list of systems known to support them however: -1. Dell WD15 dock -2. Dell TB16 dock -3. Latitude E5570 -4. Latitude E5470 -5. Latitude E5270 -6. Latitude E7470 -7. Latitude E7270 -8. Latitude E7450 -9. Latitude E7250 -10. Latitude E5550 -11. Latitude E5450 -12. Latitude E5250 -13. Latitude Rugged 5414 -14. Latitude Rugged 7214 -15. Latitude Rugged 7414 + * Dell WD15 dock + * Dell TB16 dock + * Dell TB18DC + * Latitude E5570 + * Latitude E5470 + * Latitude E5270 + * Latitude E7470 + * Latitude E7270 + * Latitude E7450 + * Latitude E7250 + * Latitude E5550 + * Latitude E5450 + * Latitude E5250 + * Latitude Rugged 5414 + * Latitude Rugged 7214 + * Latitude Rugged 7414 diff -Nru fwupd-1.1.4/plugins/synapticsmst/synapticsmst-common.h fwupd-1.2.5/plugins/synapticsmst/synapticsmst-common.h --- fwupd-1.1.4/plugins/synapticsmst/synapticsmst-common.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/synapticsmst/synapticsmst-common.h 2019-02-25 09:42:18.000000000 +0000 @@ -5,8 +5,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __SYNAPTICSMST_COMMON_H -#define __SYNAPTICSMST_COMMON_H +#pragma once #include #include @@ -108,5 +107,3 @@ #pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC(SynapticsMSTConnection, synapticsmst_common_free) #pragma clang diagnostic pop - -#endif /* __SYNAPTICSMST_COMMON_H */ diff -Nru fwupd-1.1.4/plugins/synapticsmst/synapticsmst-device.h fwupd-1.2.5/plugins/synapticsmst/synapticsmst-device.h --- fwupd-1.1.4/plugins/synapticsmst/synapticsmst-device.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/synapticsmst/synapticsmst-device.h 2019-02-25 09:42:18.000000000 +0000 @@ -6,8 +6,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __SYNAPTICSMST_DEVICE_H -#define __SYNAPTICSMST_DEVICE_H +#pragma once #include @@ -86,5 +85,3 @@ GError **error); G_END_DECLS - -#endif /* __SYNAPTICSMST_DEVICE_H */ diff -Nru fwupd-1.1.4/plugins/test/fu-plugin-test.c fwupd-1.2.5/plugins/test/fu-plugin-test.c --- fwupd-1.1.4/plugins/test/fu-plugin-test.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/test/fu-plugin-test.c 2019-02-25 09:42:18.000000000 +0000 @@ -15,6 +15,11 @@ void fu_plugin_init (FuPlugin *plugin) { + if (g_strcmp0 (g_getenv ("FWUPD_PLUGIN_TEST"), "build-hash") == 0) + fu_plugin_set_build_hash (plugin, "invalid"); + else + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.acme.test"); fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); g_debug ("init"); } @@ -159,6 +164,17 @@ } else { fu_device_set_version (device, "1.2.3"); } + + /* do this all over again */ + if (g_strcmp0 (g_getenv ("FWUPD_PLUGIN_TEST"), "another-write-required") == 0) { + g_unsetenv ("FWUPD_PLUGIN_TEST"); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED); + } + + /* for the self tests only */ + fu_device_set_metadata_integer (device, "nr-update", + fu_device_get_metadata_integer (device, "nr-update") + 1); + return TRUE; } diff -Nru fwupd-1.1.4/plugins/test/meson.build fwupd-1.2.5/plugins/test/meson.build --- fwupd-1.1.4/plugins/test/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/test/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -6,6 +6,7 @@ endif shared_module('fu_plugin_test', + fu_hash, sources : [ 'fu-plugin-test.c', ], @@ -16,6 +17,9 @@ ], install : install_dummy, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff -Nru fwupd-1.1.4/plugins/test/README.md fwupd-1.2.5/plugins/test/README.md --- fwupd-1.1.4/plugins/test/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/test/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -5,3 +5,9 @@ ------------ This plugin is used when running the self tests in the fwupd project. + +GUID Generation +--------------- + +The devices created by this plugin use hardcoded GUIDs that do not correspond +to any kind of DeviceInstanceId values. diff -Nru fwupd-1.1.4/plugins/thunderbolt/fu-plugin-thunderbolt.c fwupd-1.2.5/plugins/thunderbolt/fu-plugin-thunderbolt.c --- fwupd-1.1.4/plugins/thunderbolt/fu-plugin-thunderbolt.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/thunderbolt/fu-plugin-thunderbolt.c 2019-02-25 09:42:18.000000000 +0000 @@ -193,23 +193,45 @@ static gboolean fu_plugin_thunderbolt_is_native (GUdevDevice *udevice, gboolean *is_native, GError **error) { + gsize nr_chunks; g_autoptr(GFile) nvmem = NULL; g_autoptr(GBytes) controller_fw = NULL; - gchar *content; - gsize length; + g_autoptr(GInputStream) istr = NULL; nvmem = fu_plugin_thunderbolt_find_nvmem (udevice, TRUE, error); if (nvmem == NULL) return FALSE; - if (!g_file_load_contents (nvmem, NULL, &content, &length, NULL, error)) + /* read just enough bytes to read the status byte */ + nr_chunks = (FU_TBT_OFFSET_NATIVE + FU_TBT_CHUNK_SZ - 1) / FU_TBT_CHUNK_SZ; + istr = G_INPUT_STREAM (g_file_read (nvmem, NULL, error)); + if (istr == NULL) + return FALSE; + controller_fw = g_input_stream_read_bytes (istr, + nr_chunks * FU_TBT_CHUNK_SZ, + NULL, error); + if (controller_fw == NULL) return FALSE; - controller_fw = g_bytes_new_take (content, length); + return fu_thunderbolt_image_controller_is_native (controller_fw, + is_native, + error); +} - return fu_plugin_thunderbolt_controller_is_native (controller_fw, - is_native, - error); +static gboolean +fu_plugin_thunderbolt_can_update (GUdevDevice *udevice) +{ + g_autoptr(GError) nvmem_error = NULL; + g_autoptr(GFile) non_active_nvmem = NULL; + + non_active_nvmem = fu_plugin_thunderbolt_find_nvmem (udevice, FALSE, + &nvmem_error); + if (non_active_nvmem == NULL) { + g_debug ("%s", nvmem_error->message); + return FALSE; + } + + return TRUE; } static void @@ -293,22 +315,29 @@ is_safemode ? "True" : "False"); } if (!is_safemode) { - if (is_host) { - g_autoptr(GError) error_local = NULL; - if (!fu_plugin_thunderbolt_is_native (device, &is_native, &error_local)) { - g_warning ("failed to get native mode status: %s", error_local->message); - return; + if (fu_plugin_thunderbolt_can_update (device)) { + if (is_host) { + g_autoptr(GError) native_error = NULL; + if (!fu_plugin_thunderbolt_is_native (device, + &is_native, + &native_error)) { + g_warning ("failed to get native mode status: %s", + native_error->message); + return; + } + fu_plugin_add_report_metadata (plugin, + "ThunderboltNative", + is_native ? "True" : "False"); } - fu_plugin_add_report_metadata (plugin, - "ThunderboltNative", - is_native ? "True" : "False"); + vendor_id = g_strdup_printf ("TBT:0x%04X", (guint) vid); + device_id = g_strdup_printf ("TBT-%04x%04x%s", + (guint) vid, + (guint) did, + is_native ? "-native" : ""); + fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); + } else { + fu_device_set_update_error (dev, "Missing non-active nvmem"); } - vendor_id = g_strdup_printf ("TBT:0x%04X", (guint) vid); - device_id = g_strdup_printf ("TBT-%04x%04x%s", - (guint) vid, - (guint) did, - is_native ? "-native" : ""); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); } else { fu_device_set_update_error (dev, "Device is in safe mode"); } @@ -340,14 +369,20 @@ if (vendor_id != NULL) fu_device_set_vendor_id (dev, vendor_id); if (device_id != NULL) - fu_device_add_guid (dev, device_id); + fu_device_add_instance_id (dev, device_id); if (version != NULL) fu_device_set_version (dev, version); if (is_host) fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_INTERNAL); + /* we never open the device, so convert the instance IDs */ + fu_device_setup (dev, NULL); fu_plugin_cache_add (plugin, id, dev); fu_plugin_device_add (plugin, dev); + + /* inhibit the idle sleep of the daemon */ + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_INHIBITS_IDLE, + "thunderbolt requires device wakeup"); } static void @@ -436,10 +471,7 @@ return VALIDATION_FAILED; controller_fw = g_bytes_new_take (content, length); - - return fu_plugin_thunderbolt_validate_image (controller_fw, - blob_fw, - error); + return fu_thunderbolt_image_validate (controller_fw, blob_fw, error); } static gboolean @@ -555,9 +587,14 @@ FuPluginData *data = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); const gchar *subsystems[] = { "thunderbolt", NULL }; + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.intel.thunderbolt"); data->udev = g_udev_client_new (subsystems); g_signal_connect (data->udev, "uevent", G_CALLBACK (udev_uevent_cb), plugin); + + /* dell-dock plugin uses a slower bus for flashing */ + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_BETTER_THAN, "dell_dock"); } void @@ -706,8 +743,7 @@ return FALSE; } status = g_ascii_strtoull (attribute, NULL, 16); - if ((status == 0x00 && errno == EINVAL) || - (status == G_MAXUINT64 && errno == ERANGE)) { + if (status == G_MAXUINT64 && errno == ERANGE) { g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "failed to read 'nvm_authenticate: %s", diff -Nru fwupd-1.1.4/plugins/thunderbolt/fu-self-test.c fwupd-1.2.5/plugins/thunderbolt/fu-self-test.c --- fwupd-1.1.4/plugins/thunderbolt/fu-self-test.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/thunderbolt/fu-self-test.c 2019-02-25 09:42:18.000000000 +0000 @@ -1045,40 +1045,40 @@ g_assert_nonnull (bad_data); /* now for some testing ... this should work */ - val = fu_plugin_thunderbolt_validate_image (ctl_data, fwi_data, &error); + val = fu_thunderbolt_image_validate (ctl_data, fwi_data, &error); g_assert_no_error (error); g_assert_cmpint (val, ==, VALIDATION_PASSED); /* these all should fail */ /* valid controller, bad update data */ - val = fu_plugin_thunderbolt_validate_image (ctl_data, ctl_data, &error); + val = fu_thunderbolt_image_validate (ctl_data, ctl_data, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_READ); g_assert_cmpint (val, ==, VALIDATION_FAILED); g_debug ("expected image validation error [ctl, ctl]: %s", error->message); g_clear_error (&error); - val = fu_plugin_thunderbolt_validate_image (ctl_data, bad_data, &error); + val = fu_thunderbolt_image_validate (ctl_data, bad_data, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_READ); g_assert_cmpint (val, ==, VALIDATION_FAILED); g_debug ("expected image validation error [ctl, bad]: %s", error->message); g_clear_error (&error); /* bad controller data, valid update data */ - val = fu_plugin_thunderbolt_validate_image (fwi_data, fwi_data, &error); + val = fu_thunderbolt_image_validate (fwi_data, fwi_data, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); g_assert_cmpint (val, ==, VALIDATION_FAILED); g_debug ("expected image validation error [fwi, fwi]: %s", error->message); g_clear_error (&error); - val = fu_plugin_thunderbolt_validate_image (bad_data, fwi_data, &error); + val = fu_thunderbolt_image_validate (bad_data, fwi_data, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); g_assert_cmpint (val, ==, VALIDATION_FAILED); g_debug ("expected image validation error [bad, fwi]: %s", error->message); g_clear_error (&error); /* both bad */ - val = fu_plugin_thunderbolt_validate_image (bad_data, bad_data, &error); + val = fu_thunderbolt_image_validate (bad_data, bad_data, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_READ); g_assert_cmpint (val, ==, VALIDATION_FAILED); g_debug ("expected image validation error [bad, bad]: %s", error->message); @@ -1131,7 +1131,7 @@ /* simulate an update, where the device goes away and comes back * after the time in the last parameter (given in ms) */ up_ctx = mock_tree_prepare_for_update (tree, plugin, "42.23", fw_data, 1000); - ret = fu_plugin_runner_update (plugin, tree->fu_device, NULL, fw_data, 0, &error); + ret = fu_plugin_runner_update (plugin, tree->fu_device, fw_data, 0, &error); g_assert_no_error (error); g_assert_true (ret); @@ -1180,7 +1180,7 @@ up_ctx = mock_tree_prepare_for_update (tree, plugin, "42.23", fw_data, 1000); up_ctx->result = UPDATE_FAIL_DEVICE_INTERNAL; - ret = fu_plugin_runner_update (plugin, tree->fu_device, NULL, fw_data, 0, &error); + ret = fu_plugin_runner_update (plugin, tree->fu_device, fw_data, 0, &error); g_assert_no_error (error); g_assert_true (ret); @@ -1228,7 +1228,7 @@ up_ctx = mock_tree_prepare_for_update (tree, plugin, "42.23", fw_data, 1000); up_ctx->result = UPDATE_FAIL_DEVICE_NOSHOW; - ret = fu_plugin_runner_update (plugin, tree->fu_device, NULL, fw_data, 0, &error); + ret = fu_plugin_runner_update (plugin, tree->fu_device, fw_data, 0, &error); g_assert_no_error (error); g_assert_true (ret); diff -Nru fwupd-1.1.4/plugins/thunderbolt/fu-thunderbolt-image.c fwupd-1.2.5/plugins/thunderbolt/fu-thunderbolt-image.c --- fwupd-1.1.4/plugins/thunderbolt/fu-thunderbolt-image.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/thunderbolt/fu-thunderbolt-image.c 2019-02-25 09:42:18.000000000 +0000 @@ -642,9 +642,9 @@ } FuPluginValidation -fu_plugin_thunderbolt_validate_image (GBytes *controller_fw, - GBytes *blob_fw, - GError **error) +fu_thunderbolt_image_validate (GBytes *controller_fw, + GBytes *blob_fw, + GError **error) { gboolean is_host; guint16 device_id; @@ -779,16 +779,18 @@ } gboolean -fu_plugin_thunderbolt_controller_is_native (GBytes *controller_fw, - gboolean *is_native, - GError **error) +fu_thunderbolt_image_controller_is_native (GBytes *controller_fw, + gboolean *is_native, + GError **error) { guint32 controller_sections[SECTION_COUNT] = { [DIGITAL_SECTION] = 0 }; gsize fw_size; const guint8 *fw_data = g_bytes_get_data (controller_fw, &fw_size); const FuThunderboltFwObject controller = { fw_data, fw_size, controller_sections }; - - const FuThunderboltFwLocation location = { .offset = 0x7B, .len = 1, .description = "Native", .mask = 0x20 }; - + const FuThunderboltFwLocation location = { + .offset = FU_TBT_OFFSET_NATIVE, + .len = 1, + .description = "Native", + .mask = 0x20 }; return read_bool (&location, &controller, is_native, error); } diff -Nru fwupd-1.1.4/plugins/thunderbolt/fu-thunderbolt-image.h fwupd-1.2.5/plugins/thunderbolt/fu-thunderbolt-image.h --- fwupd-1.1.4/plugins/thunderbolt/fu-thunderbolt-image.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/thunderbolt/fu-thunderbolt-image.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_THUNDERBOLT_IMAGE_H__ -#define __FU_THUNDERBOLT_IMAGE_H__ +#pragma once #include @@ -15,12 +14,14 @@ UNKNOWN_DEVICE, } FuPluginValidation; -FuPluginValidation fu_plugin_thunderbolt_validate_image (GBytes *controller_fw, +/* byte offsets in firmware image */ +#define FU_TBT_OFFSET_NATIVE 0x7B +#define FU_TBT_CHUNK_SZ 0x40 + +FuPluginValidation fu_thunderbolt_image_validate (GBytes *controller_fw, GBytes *blob_fw, GError **error); -gboolean fu_plugin_thunderbolt_controller_is_native (GBytes *controller_fw, +gboolean fu_thunderbolt_image_controller_is_native (GBytes *controller_fw, gboolean *is_native, GError **error); - -#endif /* __FU_THUNDERBOLT_IMAGE_H__ */ diff -Nru fwupd-1.1.4/plugins/thunderbolt/fu-thunderbolt-tool.c fwupd-1.2.5/plugins/thunderbolt/fu-thunderbolt-tool.c --- fwupd-1.1.4/plugins/thunderbolt/fu-thunderbolt-tool.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/thunderbolt/fu-thunderbolt-tool.c 2019-02-25 09:42:18.000000000 +0000 @@ -82,7 +82,7 @@ controller = g_bytes_new_take (controller_data, controller_len); } - validation = fu_plugin_thunderbolt_validate_image (controller, image, &error); + validation = fu_thunderbolt_image_validate (controller, image, &error); g_assert_no_error (error); g_assert_cmpint (validation, ==, VALIDATION_PASSED); diff -Nru fwupd-1.1.4/plugins/thunderbolt/meson.build fwupd-1.2.5/plugins/thunderbolt/meson.build --- fwupd-1.1.4/plugins/thunderbolt/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/thunderbolt/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -1,6 +1,7 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginThunderbolt"'] fu_plugin_thunderbolt = shared_module('fu_plugin_thunderbolt', + fu_hash, sources : [ 'fu-plugin-thunderbolt.c', 'fu-thunderbolt-image.c', @@ -12,6 +13,9 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, @@ -22,6 +26,7 @@ testdatadir_dst = join_paths(meson.build_root(), 'data', 'tests') cargs += '-DTESTDATADIR="' + testdatadir_src + ':' + testdatadir_dst + '"' executable('tbtfwucli', + fu_hash, sources : [ 'fu-thunderbolt-tool.c', ], @@ -33,7 +38,6 @@ c_args : cargs, link_with : [ fu_plugin_thunderbolt, - fwupd, libfwupdprivate, ], dependencies : [ @@ -47,6 +51,7 @@ cargs += '-DPLUGINBUILDDIR="' + meson.current_build_dir() + '"' e = executable( 'thunderbolt-self-test', + fu_hash, sources : [ 'fu-self-test.c', 'fu-plugin-thunderbolt.c', @@ -62,7 +67,6 @@ umockdev, ], link_with : [ - fwupd, libfwupdprivate, ], c_args : cargs diff -Nru fwupd-1.1.4/plugins/thunderbolt/README.md fwupd-1.2.5/plugins/thunderbolt/README.md --- fwupd-1.1.4/plugins/thunderbolt/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/thunderbolt/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -9,6 +9,28 @@ Versions 1 and 2 use the same connector as Mini DisplayPort (MDP), whereas version 3 uses USB Type-C. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format, with vendor specific header. + +This plugin supports the following protocol ID: + + * com.intel.thunderbolt + +GUID Generation +--------------- + +These devices use a custom GUID generation scheme. +When the device is in "safe mode" the GUID is hardcoded using: + + * `TBT-safemode` + +... and when in runtime mode the GUID is: + + * `TBT-$(vid)$(pid)-native` when native, and `TBT-$(vid)$(pid)` otherwise. + Runtime Power Management ------------------------ diff -Nru fwupd-1.1.4/plugins/thunderbolt-power/fu-plugin-thunderbolt-power.c fwupd-1.2.5/plugins/thunderbolt-power/fu-plugin-thunderbolt-power.c --- fwupd-1.1.4/plugins/thunderbolt-power/fu-plugin-thunderbolt-power.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/thunderbolt-power/fu-plugin-thunderbolt-power.c 2019-02-25 09:42:18.000000000 +0000 @@ -320,6 +320,7 @@ /* make sure it's tried to coldplug */ fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "thunderbolt"); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); } void diff -Nru fwupd-1.1.4/plugins/thunderbolt-power/meson.build fwupd-1.2.5/plugins/thunderbolt-power/meson.build --- fwupd-1.1.4/plugins/thunderbolt-power/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/thunderbolt-power/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -1,6 +1,7 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginThunderbolt"'] fu_plugin_thunderbolt_power = shared_module('fu_plugin_thunderbolt_power', + fu_hash, sources : [ 'fu-plugin-thunderbolt-power.c', ], @@ -11,6 +12,9 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff -Nru fwupd-1.1.4/plugins/udev/fu-plugin-udev.c fwupd-1.2.5/plugins/udev/fu-plugin-udev.c --- fwupd-1.1.4/plugins/udev/fu-plugin-udev.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/udev/fu-plugin-udev.c 2019-02-25 09:42:18.000000000 +0000 @@ -13,6 +13,7 @@ void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_udev_subsystem (plugin, "pci"); } @@ -84,14 +85,18 @@ return FALSE; /* did we get enough data */ - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_INTERNAL); - fu_device_add_icon (device, "audio-card"); + fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_icon (FU_DEVICE (device), "audio-card"); /* get the FW version from the rom when unlocked */ rom_fn = g_build_filename (fu_udev_device_get_sysfs_path (device), "rom", NULL); if (g_file_test (rom_fn, G_FILE_TEST_EXISTS)) fu_device_set_metadata (FU_DEVICE (device), "RomFilename", rom_fn); + /* we never open the device, so convert the instance IDs */ + if (!fu_device_setup (FU_DEVICE (device), error)) + return FALSE; + /* insert to hash */ fu_plugin_device_add (plugin, FU_DEVICE (device)); return TRUE; diff -Nru fwupd-1.1.4/plugins/udev/fu-rom.c fwupd-1.2.5/plugins/udev/fu-rom.c --- fwupd-1.1.4/plugins/udev/fu-rom.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/udev/fu-rom.c 2019-02-25 09:42:18.000000000 +0000 @@ -7,7 +7,6 @@ #include "config.h" #include -#include #include #include @@ -549,7 +548,6 @@ guint32 sz = buffer_sz; guint32 jump = 0; guint32 hdr_sz = 0; - g_autofree gchar *id = NULL; g_autoptr(GChecksum) checksum_sha1 = g_checksum_new (G_CHECKSUM_SHA1); g_autoptr(GChecksum) checksum_sha256 = g_checksum_new (G_CHECKSUM_SHA256); @@ -687,10 +685,8 @@ g_ptr_array_add (self->checksums, g_strdup (g_checksum_get_string (checksum_sha256))); /* update guid */ - id = g_strdup_printf ("PCI\\VEN_%04X&DEV_%04X", - self->vendor_id, self->device_id); - self->guid = as_utils_guid_from_string (id); - g_debug ("using %s for %s", self->guid, id); + self->guid = g_strdup_printf ("PCI\\VEN_%04X&DEV_%04X", + self->vendor_id, self->device_id); /* not known */ if (self->version == NULL) { diff -Nru fwupd-1.1.4/plugins/udev/fu-rom.h fwupd-1.2.5/plugins/udev/fu-rom.h --- fwupd-1.1.4/plugins/udev/fu-rom.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/udev/fu-rom.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_ROM_H -#define __FU_ROM_H +#pragma once #include @@ -54,6 +53,3 @@ const gchar *fu_rom_kind_to_string (FuRomKind kind); G_END_DECLS - -#endif /* __FU_ROM_H */ - diff -Nru fwupd-1.1.4/plugins/udev/meson.build fwupd-1.2.5/plugins/udev/meson.build --- fwupd-1.1.4/plugins/udev/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/udev/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -1,6 +1,7 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginUdev"'] shared_module('fu_plugin_udev', + fu_hash, sources : [ 'fu-plugin-udev.c', 'fu-rom.c', @@ -12,6 +13,9 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, @@ -20,6 +24,7 @@ executable( 'fu-rom-tool', + fu_hash, sources : [ 'fu-rom-tool.c', 'fu-rom.c', @@ -33,7 +38,6 @@ plugin_deps, ], link_with : [ - fwupd, libfwupdprivate, ], c_args : cargs, @@ -46,6 +50,7 @@ cargs += '-DTESTDATADIR="' + testdatadir + '"' e = executable( 'udev-self-test', + fu_hash, sources : [ 'fu-self-test.c', 'fu-rom.c', @@ -59,7 +64,6 @@ plugin_deps, ], link_with : [ - fwupd, libfwupdprivate, ], c_args : cargs diff -Nru fwupd-1.1.4/plugins/udev/README.md fwupd-1.2.5/plugins/udev/README.md --- fwupd-1.1.4/plugins/udev/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/udev/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -10,3 +10,12 @@ This plugin is also able to read and parse the firmware of some PCI devices which allows some host state verification to be done. + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `PCI\VEN_%04X&DEV_%04X` + +Additionally, GUIDs found in OptionROMs may also be added. diff -Nru fwupd-1.1.4/plugins/uefi/efi/fwup-cleanups.h fwupd-1.2.5/plugins/uefi/efi/fwup-cleanups.h --- fwupd-1.1.4/plugins/uefi/efi/fwup-cleanups.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/efi/fwup-cleanups.h 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#define _DEFINE_CLEANUP_FUNCTION0(Type, name, func) \ + static inline VOID name(VOID *v) \ + { \ + if (*(Type*)v) \ + func (*(Type*)v); \ + } +_DEFINE_CLEANUP_FUNCTION0(VOID *, _FreePool_p, FreePool) +#define _cleanup_free __attribute__ ((cleanup(_FreePool_p))) + +static inline VOID * +_steal_pointer(VOID *pp) +{ + VOID **ptr = (VOID **) pp; + VOID *ref = *ptr; + *ptr = NULL; + return ref; +} diff -Nru fwupd-1.1.4/plugins/uefi/efi/fwup-common.c fwupd-1.2.5/plugins/uefi/efi/fwup-common.c --- fwupd-1.1.4/plugins/uefi/efi/fwup-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/efi/fwup-common.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include +#include + +#include "fwup-debug.h" +#include "fwup-common.h" + +VOID +fwup_msleep(unsigned long msecs) +{ + BS->Stall(msecs); +} + +/* + * Allocate some raw pages that aren't part of the pool allocator. + */ +VOID * +fwup_malloc_raw(UINTN size) +{ + UINTN pages = size / 4096 + ((size % 4096) ? 1 : 0); /* page size is always 4096 */ + EFI_STATUS rc; + EFI_PHYSICAL_ADDRESS pageaddr = 0; + EFI_ALLOCATE_TYPE type = AllocateAnyPages; + + if (sizeof(VOID *) == 4) { + pageaddr = 0xffffffffULL - 8192; + type = AllocateMaxAddress; + } + + rc = uefi_call_wrapper(BS->AllocatePages, 4, type, + EfiLoaderData, pages, + &pageaddr); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not allocate %d", size); + return NULL; + } + if (sizeof(VOID *) == 4 && pageaddr > 0xffffffffULL) { + uefi_call_wrapper(BS->FreePages, 2, pageaddr, pages); + fwup_warning(L"Got bad allocation at 0x%016x", (UINT64)pageaddr); + return NULL; + } + return (VOID *)(UINTN)pageaddr; +} + +/* + * Free our raw page allocations. + */ +static EFI_STATUS +fwup_free_raw(VOID *addr, UINTN size) +{ + UINTN pages = size / 4096 + ((size % 4096) ? 1 : 0); + return uefi_call_wrapper(BS->FreePages, 2, + (EFI_PHYSICAL_ADDRESS)(UINTN)addr, pages); +} + +VOID * +fwup_malloc (UINTN size) +{ + VOID *addr = AllocatePool(size); + if (addr == NULL) + fwup_warning(L"Could not allocate %d", size); + return addr; +} + +VOID * +fwup_malloc0 (UINTN size) +{ + VOID *addr = AllocateZeroPool(size); + if (addr == NULL) + fwup_warning(L"Could not allocate %d", size); + return addr; +} + +EFI_STATUS +fwup_time(EFI_TIME *ts) +{ + EFI_TIME_CAPABILITIES timecaps = { 0, }; + return uefi_call_wrapper(RT->GetTime, 2, ts, &timecaps); +} + +EFI_STATUS +fwup_read_file(EFI_FILE_HANDLE fh, UINT8 **buf_out, UINTN *buf_size_out) +{ + const UINTN bs = 512; + UINTN i = 0; + UINTN n_blocks = 4096; + UINT8 *buf = NULL; + + while (1) { + VOID *newb = NULL; + UINTN news = n_blocks * bs * 2; + + newb = fwup_malloc_raw(news); + if (newb == NULL) + return EFI_OUT_OF_RESOURCES; + if (buf != NULL) { + CopyMem(newb, buf, bs * n_blocks); + fwup_free_raw(buf, bs * n_blocks); + } + buf = newb; + n_blocks *= 2; + + for (; i < n_blocks; i++) { + EFI_STATUS rc; + UINTN sz = bs; + + rc = uefi_call_wrapper(fh->Read, 3, fh, &sz, &buf[i * bs]); + if (EFI_ERROR(rc)) { + fwup_free_raw(buf, bs * n_blocks); + fwup_warning(L"Could not read file: %r", rc); + return rc; + } + + if (sz != bs) { + *buf_size_out = bs * i + sz; + *buf_out = buf; + return EFI_SUCCESS; + } + } + } + return EFI_SUCCESS; +} diff -Nru fwupd-1.1.4/plugins/uefi/efi/fwup-common.h fwupd-1.2.5/plugins/uefi/efi/fwup-common.h --- fwupd-1.1.4/plugins/uefi/efi/fwup-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/efi/fwup-common.h 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2015-2016 Peter Jones + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fwup-efi.h" + +VOID fwup_msleep (unsigned long msecs); +EFI_STATUS fwup_time (EFI_TIME *ts); +EFI_STATUS fwup_read_file (EFI_FILE_HANDLE fh, + UINT8 **buf_out, + UINTN *buf_size_out); +VOID *fwup_malloc_raw (UINTN size); + +VOID *fwup_malloc (UINTN size); +VOID *fwup_malloc0 (UINTN size); + +#define fwup_new(struct_type, n) ((struct_type*)fwup_malloc((n)*sizeof(struct_type))) +#define fwup_new0(struct_type, n) ((struct_type*)fwup_malloc0((n)*sizeof(struct_type))) diff -Nru fwupd-1.1.4/plugins/uefi/efi/fwupdate.c fwupd-1.2.5/plugins/uefi/efi/fwupdate.c --- fwupd-1.1.4/plugins/uefi/efi/fwupdate.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/efi/fwupdate.c 2019-02-25 09:42:18.000000000 +0000 @@ -7,285 +7,37 @@ #include #include -#include - +#include "fwup-cleanups.h" +#include "fwup-common.h" #include "fwup-efi.h" -#include "hexdump.h" +#include "fwup-debug.h" #define UNUSED __attribute__((__unused__)) +#define GNVN_BUF_SIZE 1024 +#define FWUP_NUM_CAPSULE_UPDATES_MAX 128 -EFI_GUID empty_guid = {0x0,0x0,0x0,{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}}; -EFI_GUID fwupdate_guid = - {0x0abba7dc,0xe516,0x4167,{0xbb,0xf5,0x4d,0x9d,0x1c,0x73,0x94,0x16}}; -EFI_GUID ux_capsule_guid = - {0x3b8c8162,0x188c,0x46a4,{0xae,0xc9,0xbe,0x43,0xf1,0xd6,0x56,0x97}}; -EFI_GUID fmp_capsule_guid = - {0x6dcbd5ed,0xe82d,0x4c44,{0xbd,0xa1,0x71,0x94,0x19,0x9a,0xd9,0x2a}}; -EFI_GUID global_variable_guid = EFI_GLOBAL_VARIABLE; - - -typedef struct update_table_s { - CHAR16 *name; - UINT32 attributes; - UINTN size; - update_info *info; -} update_table; - -static EFI_STATUS -delete_variable(CHAR16 *name, EFI_GUID guid, UINT32 attributes); -static EFI_STATUS -set_variable(CHAR16 *name, EFI_GUID guid, VOID *data, UINTN size, - UINT32 attrs); - -static int debugging; - -#define SECONDS 1000000 +typedef struct { + CHAR16 *name; + UINT32 attrs; + UINTN size; + FWUP_UPDATE_INFO *info; +} FWUP_UPDATE_TABLE; static VOID -msleep(unsigned long msecs) -{ - BS->Stall(msecs); -} - - -/* - * I'm not actually sure when these appear, but they're present in the - * version in front of me. - */ -#if defined(__GNUC__) && defined(__GNUC_MINOR__) -#if __GNUC__ >= 5 && __GNUC_MINOR__ >= 1 -#define uintn_mult(a, b, c) __builtin_mul_overflow(a, b, c) -#endif -#endif -#ifndef uintn_mult -#define uintn_mult(a, b, c) ({ \ - const UINTN _limit = ~0UL; \ - int _ret = 1; \ - if ((a) != 0 && (b) != 0) { \ - _ret = _limit / (a) < (b); \ - } \ - if (!_ret) \ - *(c) = ((a) * (b)); \ - _ret; \ - }) -#endif - -int -debug_print(const char *func, const char *file, const int line, - CHAR16 *fmt, ...) +fwup_update_table_free(FWUP_UPDATE_TABLE *update) { - va_list args0, args1; - CHAR16 *out0, *out1; - UINT32 attrs = EFI_VARIABLE_NON_VOLATILE | - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS; - CHAR16 *name = L"FWUPDATE_DEBUG_LOG"; - static bool once = true; - - va_start(args0, fmt); - out0 = VPoolPrint(fmt, args0); - va_end(args0); - if (!out0) { - if (debugging) { - va_start(args1, fmt); - VPrint(fmt, args1); - va_end(args1); - msleep(200000); - } - Print(L"fwupdate: Allocation for debug log failed!\n"); - return debugging; - } - if (debugging) - Print(L"%s", out0); - out1 = PoolPrint(L"%a:%d:%a(): %s", file, line, func, out0); - FreePool(out0); - if (!out1) { - Print(L"fwupdate: Allocation for debug log failed!\n"); - return debugging; - } - - if (once) { - once = false; - delete_variable(name, fwupdate_guid, attrs); - } else { - attrs |= EFI_VARIABLE_APPEND_WRITE; - } - set_variable(name, fwupdate_guid, out1, StrSize(out1) - sizeof (CHAR16), attrs); - - FreePool(out1); - - return debugging; + FreePool(update->info); + FreePool(update->name); + FreePool(update); } -#define dprint(fmt, args...) debug_print(__func__, __FILE__, __LINE__, fmt, ## args ) -#define print(fmt, args...) ({ if (!dprint(fmt, ## args)) Print(fmt, ## args); }) - -/* - * Allocate some raw pages that aren't part of the pool allocator. - */ -static EFI_STATUS -allocate(void **addr, UINTN size) -{ - /* - * We're actually guaranteed that page size is 4096 by UEFI. - */ - UINTN pages = size / 4096 + ((size % 4096) ? 1 : 0); - EFI_STATUS rc; - EFI_PHYSICAL_ADDRESS pageaddr = 0; - EFI_ALLOCATE_TYPE type = AllocateAnyPages; - - if (sizeof (VOID *) == 4) { - pageaddr = 0xffffffffULL - 8192; - type = AllocateMaxAddress; - } - - rc = uefi_call_wrapper(BS->AllocatePages, 4, type, - EfiLoaderData, pages, - &pageaddr); - if (EFI_ERROR(rc)) - return rc; - if (sizeof (VOID *) == 4 && pageaddr > 0xffffffffULL) { - uefi_call_wrapper(BS->FreePages, 2, pageaddr, pages); - print(L"Got bad allocation at 0x%016x\n", (UINT64)pageaddr); - return EFI_OUT_OF_RESOURCES; - } - *addr = (void *)(UINTN)pageaddr; - return rc; -} - -/* - * Free our raw page allocations. - */ -static EFI_STATUS -free(void *addr, UINTN size) -{ - UINTN pages = size / 4096 + ((size % 4096) ? 1 : 0); - EFI_STATUS rc; - - rc = uefi_call_wrapper(BS->FreePages, 2, - (EFI_PHYSICAL_ADDRESS)(UINTN)addr, - pages); - return rc; -} - -static inline int -guid_cmp(efi_guid_t *a, efi_guid_t *b) -{ - return CompareMem(a, b, sizeof (*a)); -} - -EFI_STATUS -read_file(EFI_FILE_HANDLE fh, UINT8 **buf_out, UINTN *buf_size_out) -{ - UINT8 *b = NULL; - const UINTN bs = 512; - UINTN n_blocks = 4096; - UINTN i = 0; - EFI_STATUS rc; - - while (1) { - void *newb = NULL; - UINTN news = 0; - if (uintn_mult(bs * 2, n_blocks, &news)) { - if (b) - free(b, bs * n_blocks); - print(L"allocation %d * %d would overflow size\n", - bs * 2, n_blocks); - return EFI_OUT_OF_RESOURCES; - } - rc = allocate(&newb, news); - if (EFI_ERROR(rc)) { - print(L"Tried to allocate %d\n", - bs * n_blocks * 2); - print(L"Could not allocate memory.\n"); - return EFI_OUT_OF_RESOURCES; - } - if (b) { - CopyMem(newb, b, bs * n_blocks); - free(b, bs * n_blocks); - } - b = newb; - n_blocks *= 2; - - for (; i < n_blocks; i++) { - EFI_STATUS rc; - UINTN sz = bs; - - rc = uefi_call_wrapper(fh->Read, 3, fh, &sz, - &b[i * bs]); - if (EFI_ERROR(rc)) { - free(b, bs * n_blocks); - print(L"Could not read file: %r\n", rc); - return rc; - } +_DEFINE_CLEANUP_FUNCTION0(FWUP_UPDATE_TABLE *, _fwup_update_table_free_p, fwup_update_table_free) +#define _cleanup_update_table __attribute__ ((cleanup(_fwup_update_table_free_p))) - if (sz != bs) { - *buf_size_out = bs * i + sz; - *buf_out = b; - return EFI_SUCCESS; - } - } - } - return EFI_SUCCESS; -} - -static EFI_STATUS -delete_variable(CHAR16 *name, EFI_GUID guid, UINT32 attributes) -{ - return uefi_call_wrapper(RT->SetVariable, 5, name, &guid, attributes, - 0, NULL); -} - -static EFI_STATUS -set_variable(CHAR16 *name, EFI_GUID guid, VOID *data, UINTN size, - UINT32 attrs) -{ - return uefi_call_wrapper(RT->SetVariable, 5, name, &guid, attrs, - size, data); -} - -static EFI_STATUS -read_variable(CHAR16 *name, EFI_GUID guid, void **buf_out, UINTN *buf_size_out, - UINT32 *attributes_out) -{ - EFI_STATUS rc; - UINT32 attributes; - UINTN size = 0; - void *buf = NULL; - - rc = uefi_call_wrapper(RT->GetVariable, 5, name, - &guid, &attributes, &size, NULL); - if (EFI_ERROR(rc)) { - if (rc == EFI_BUFFER_TOO_SMALL) { - buf = AllocatePool(size); - if (!buf) { - print(L"Tried to allocate %d\n", size); - print(L"Could not allocate memory.\n"); - return EFI_OUT_OF_RESOURCES; - } - } else if (rc != EFI_NOT_FOUND) { - print(L"Could not get variable \"%s\": %r\n", name, rc); - return rc; - } - } else { - print(L"GetVariable(%s) succeeded with size=0.\n", name); - return EFI_INVALID_PARAMETER; - } - rc = uefi_call_wrapper(RT->GetVariable, 5, name, &guid, &attributes, - &size, buf); - if (EFI_ERROR(rc)) { - print(L"Could not get variable \"%s\": %r\n", name, rc); - FreePool(buf); - return rc; - } - *buf_out = buf; - *buf_size_out = size; - *attributes_out = attributes; - return EFI_SUCCESS; -} +#define SECONDS 1000000 static INTN -dp_size(EFI_DEVICE_PATH *dp, INTN limit) +fwup_dp_size(EFI_DEVICE_PATH *dp, INTN limit) { INTN ret = 0; while (1) { @@ -305,288 +57,154 @@ } static EFI_STATUS -get_info(CHAR16 *name, update_table *info_out) +fwup_populate_update_info(CHAR16 *name, FWUP_UPDATE_TABLE *info_out) { EFI_STATUS rc; - update_info *info = NULL; + FWUP_UPDATE_INFO *info = NULL; UINTN info_size = 0; - UINT32 attributes = 0; - void *info_ptr = NULL; + UINT32 attrs = 0; + VOID *info_ptr = NULL; - rc = read_variable(name, fwupdate_guid, &info_ptr, &info_size, - &attributes); + rc = fwup_get_variable(name, &fwupdate_guid, &info_ptr, &info_size, &attrs); if (EFI_ERROR(rc)) return rc; - info = (update_info *)info_ptr; + info = (FWUP_UPDATE_INFO *)info_ptr; - if (info_size < sizeof (*info)) { - print(L"Update \"%s\" is is too small.\n", name); - delete_variable(name, fwupdate_guid, attributes); + if (info_size < sizeof(*info)) { + fwup_warning(L"Update '%s' is is too small", name); return EFI_INVALID_PARAMETER; } - if (info_size - sizeof (EFI_DEVICE_PATH) <= sizeof (*info)) { - print(L"Update \"%s\" is malformed, " - L"and cannot hold a file path.\n", name); - delete_variable(name, fwupdate_guid, attributes); + if (info_size - sizeof(EFI_DEVICE_PATH) <= sizeof(*info)) { + fwup_warning(L"Update '%s' is malformed, " + L"and cannot hold a file path", name); return EFI_INVALID_PARAMETER; } EFI_DEVICE_PATH *hdr = (EFI_DEVICE_PATH *)&info->dp; - INTN is = EFI_FIELD_OFFSET(update_info, dp); + INTN is = EFI_FIELD_OFFSET(FWUP_UPDATE_INFO, dp); if (is > (INTN)info_size) { - print(L"Update \"%s\" has an invalid file path.\n" - L"Device path offset is %d, but total size is %d\n", - name, is, info_size); - delete_variable(name, fwupdate_guid, attributes); + fwup_warning(L"Update '%s' has an invalid file path, " + L"device path offset is %d, but total size is %d", + name, is, info_size); return EFI_INVALID_PARAMETER; } is = info_size - is; - INTN sz = dp_size(hdr, info_size); - if (sz < 0 || is < 0) { -invalid_size: - print(L"Update \"%s\" has an invalid file path.\n" - L"update info size: %d dp size: %d size for dp: %d\n", - name, info_size, sz, is); - delete_variable(name, fwupdate_guid, attributes); + INTN sz = fwup_dp_size(hdr, info_size); + if (sz < 0 || is < 0 || is > (INTN)info_size || is != sz) { + fwup_warning(L"Update '%s' has an invalid file path, " + L"update info size: %d dp size: %d size for dp: %d", + name, info_size, sz, is); return EFI_INVALID_PARAMETER; } - if (is > (INTN)info_size) - goto invalid_size; - if (is != sz) - goto invalid_size; info_out->info = info; info_out->size = info_size; - info_out->attributes = attributes; + info_out->attrs = attrs; + info_out->name = StrDuplicate(name); + if (info_out->name == NULL) { + fwup_warning(L"Could not allocate %d", StrSize(name)); + return EFI_OUT_OF_RESOURCES; + } return EFI_SUCCESS; } static EFI_STATUS -find_updates(UINTN *n_updates_out, update_table ***updates_out) +fwup_populate_update_table(FWUP_UPDATE_TABLE **updates, UINTN *n_updates_out) { + EFI_GUID vendor_guid = empty_guid; EFI_STATUS rc; - update_table **updates = NULL; UINTN n_updates = 0; - UINTN n_updates_allocated = 128; - EFI_STATUS ret = EFI_OUT_OF_RESOURCES; - -#define GNVN_BUF_SIZE 1024 - UINTN variable_name_allocation = GNVN_BUF_SIZE; - UINTN variable_name_size = 0; - CHAR16 *variable_name; - EFI_GUID vendor_guid = empty_guid; - UINTN mult_res; - - if (uintn_mult(sizeof (update_table *), n_updates_allocated, - &mult_res)) { - print(L"Allocation %d * %d would overflow size\n", - sizeof (update_table *), n_updates_allocated); - return EFI_OUT_OF_RESOURCES; - } - - updates = AllocateZeroPool(mult_res); - if (!updates) { - print(L"Tried to allocate %d\n", mult_res); - print(L"Could not allocate memory.\n"); - return EFI_OUT_OF_RESOURCES; - } + _cleanup_free CHAR16 *variable_name = NULL; /* How much do we trust "size of the VariableName buffer" to mean * sizeof(vn) and not sizeof(vn)/sizeof(vn[0]) ? */ - variable_name = AllocateZeroPool(GNVN_BUF_SIZE * 2); - if (!variable_name) { - print(L"Tried to allocate %d\n", GNVN_BUF_SIZE * 2); - print(L"Could not allocate memory.\n"); - FreePool(updates); + variable_name = fwup_malloc0(GNVN_BUF_SIZE * 2); + if (variable_name == NULL) return EFI_OUT_OF_RESOURCES; - } while (1) { - variable_name_size = variable_name_allocation; + UINTN variable_name_size = GNVN_BUF_SIZE; rc = uefi_call_wrapper(RT->GetNextVariableName, 3, &variable_name_size, variable_name, &vendor_guid); - if (rc == EFI_BUFFER_TOO_SMALL) { - /* If we don't have a big enough buffer to hold the - * name, allocate a bigger one and try again */ - UINTN new_allocation; - CHAR16 *new_name; - - new_allocation = variable_name_size; - if (uintn_mult(new_allocation, 2, &mult_res)) { - print(L"%d * 2 would overflow size\n", - new_allocation); - ret = EFI_OUT_OF_RESOURCES; - goto err; - } - new_name = AllocatePool(new_allocation * 2); - if (!new_name) { - print(L"Tried to allocate %d\n", - new_allocation * 2); - print(L"Could not allocate memory.\n"); - ret = EFI_OUT_OF_RESOURCES; - goto err; - } - CopyMem(new_name, variable_name, - variable_name_allocation); - variable_name_allocation = new_allocation; - FreePool(variable_name); - variable_name = new_name; - continue; - } else if (rc == EFI_NOT_FOUND) { + if (rc == EFI_NOT_FOUND) break; - } else if (EFI_ERROR(rc)) { - print(L"Could not get variable name: %r\n", rc); - ret = rc; - goto err; + + /* ignore any huge names */ + if (rc == EFI_BUFFER_TOO_SMALL) + continue; + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not get variable name: %r", rc); + return rc; } - /* - * If it's not one of our state variables, keep going. - */ - if (guid_cmp(&vendor_guid, &fwupdate_guid)) + /* not one of our state variables */ + if (CompareGuid(&vendor_guid, &fwupdate_guid)) continue; - /* - * Don't delete our debugging settings. - */ + /* ignore debugging settings */ if (StrCmp(variable_name, L"FWUPDATE_VERBOSE") == 0 || StrCmp(variable_name, L"FWUPDATE_DEBUG_LOG") == 0) continue; - UINTN vns = StrLen(variable_name); - CHAR16 vn[vns + 1]; - CopyMem(vn, variable_name, vns * sizeof (vn[0])); - vn[vns] = L'\0'; - print(L"Found update %s\n", vn); - - if (n_updates == n_updates_allocated) { - update_table **new_ups; - UINTN mul_a, mul_b; - if (uintn_mult(n_updates_allocated, 2, &mult_res)) { - mul_a = n_updates_allocated; - mul_b = 2; -mult_err: - print(L"Allocation %d * %d would overflow size\n", - mul_a, mul_b); - ret = EFI_OUT_OF_RESOURCES; - goto err; - } - if (uintn_mult(mult_res, sizeof (update_table *), - &mult_res)) { - mul_a = mult_res; - mul_b = sizeof (update_table *); - goto mult_err; - } - - new_ups = AllocateZeroPool(mult_res); - if (!new_ups) { - print(L"Tried to allocate %d\n", mult_res); - print(L"Could not allocate memory.\n"); - ret = EFI_OUT_OF_RESOURCES; - goto err; - } - CopyMem(new_ups, updates, mult_res); - n_updates_allocated *= 2; - FreePool(updates); - updates = new_ups; - } - - update_table *update = AllocatePool(sizeof (update_table)); - if (!update) { - print(L"Tried to allocate %d\n", sizeof (update_table)); - ret = EFI_OUT_OF_RESOURCES; - goto err; - } - - update->name = StrDuplicate(vn); - if (!update->name) { - print(L"Tried to allocate %d\n", StrSize(vn)); - ret = EFI_OUT_OF_RESOURCES; - FreePool(update); - goto err; + if (n_updates > FWUP_NUM_CAPSULE_UPDATES_MAX) { + fwup_warning(L"Ignoring update %s", variable_name); + continue; } - rc = get_info(vn, update); + fwup_info(L"Found update %s", variable_name); + _cleanup_update_table FWUP_UPDATE_TABLE *update = fwup_malloc0(sizeof(FWUP_UPDATE_TABLE)); + if (update == NULL) + return EFI_OUT_OF_RESOURCES; + rc = fwup_populate_update_info(variable_name, update); if (EFI_ERROR(rc)) { - print(L"Could not get update info for \"%s\", aborting.\n", vn); - ret = rc; - FreePool(update->name); - FreePool(update); - goto err; + fwup_delete_variable(variable_name, &fwupdate_guid); + fwup_warning(L"Could not populate update info for '%s'", variable_name); + return rc; } if (update->info->status & FWUPDATE_ATTEMPT_UPDATE) { - EFI_TIME_CAPABILITIES timecaps = { 0, }; - - uefi_call_wrapper(RT->GetTime, 2, - &update->info->time_attempted, - &timecaps); + fwup_time(&update->info->time_attempted); update->info->status = FWUPDATE_ATTEMPTED; - updates[n_updates++] = update; - } else { - FreePool(update->info); - FreePool(update->name); - FreePool(update); + updates[n_updates++] = _steal_pointer(&update); } } - FreePool(variable_name); - *n_updates_out = n_updates; - *updates_out = updates; - return EFI_SUCCESS; -err: - FreePool(variable_name); - - for (unsigned int i = 0; i < n_updates; i++) { - FreePool(updates[i]->name); - FreePool(updates[i]->info); - FreePool(updates[i]); - } - - FreePool(updates); - return ret; } static EFI_STATUS -search_file(EFI_DEVICE_PATH **file_dp, EFI_FILE_HANDLE *fh) +fwup_search_file(EFI_DEVICE_PATH **file_dp, EFI_FILE_HANDLE *fh) { EFI_DEVICE_PATH *dp, *parent_dp; EFI_GUID sfsp = SIMPLE_FILE_SYSTEM_PROTOCOL; EFI_GUID dpp = DEVICE_PATH_PROTOCOL; - EFI_FILE_HANDLE *devices; - UINTN i, n_handles, count; + UINTN n_handles, count; EFI_STATUS rc; + _cleanup_free EFI_FILE_HANDLE *devices = NULL; rc = uefi_call_wrapper(BS->LocateHandleBuffer, 5, ByProtocol, &sfsp, NULL, &n_handles, (EFI_HANDLE **)&devices); if (EFI_ERROR(rc)) { - print(L"Could not find handles.\n"); + fwup_warning(L"Could not find handles"); return rc; } dp = *file_dp; - if (debugging) - print(L"Searching Device Path: %s ...\n", DevicePathToStr(dp)); - + fwup_debug(L"Searching Device Path: %s...", DevicePathToStr(dp)); parent_dp = DuplicateDevicePath(dp); - if (!parent_dp) { - rc = EFI_INVALID_PARAMETER; - goto out; - } + if (parent_dp == NULL) + return EFI_INVALID_PARAMETER; dp = parent_dp; count = 0; while (1) { - if (IsDevicePathEnd(dp)) { - rc = EFI_INVALID_PARAMETER; - goto out; - } + if (IsDevicePathEnd(dp)) + return EFI_INVALID_PARAMETER; if (DevicePathType(dp) == MEDIA_DEVICE_PATH && DevicePathSubType(dp) == MEDIA_FILEPATH_DP) @@ -597,58 +215,45 @@ } SetDevicePathEndNode(dp); + fwup_debug(L"Device Path prepared: %s", DevicePathToStr(parent_dp)); - if (debugging) - print(L"Device Path prepared: %s\n", - DevicePathToStr(parent_dp)); - - for (i = 0; i < n_handles; i++) { + for (UINTN i = 0; i < n_handles; i++) { EFI_DEVICE_PATH *path; rc = uefi_call_wrapper(BS->HandleProtocol, 3, devices[i], &dpp, - (void **)&path); + (VOID **)&path); if (EFI_ERROR(rc)) continue; - if (debugging) - print(L"Device supporting SFSP: %s\n", - DevicePathToStr(path)); + fwup_debug(L"Device supporting SFSP: %s", DevicePathToStr(path)); - rc = EFI_UNSUPPORTED; while (!IsDevicePathEnd(path)) { - if (debugging) - print(L"Comparing: %s and %s\n", - DevicePathToStr(parent_dp), - DevicePathToStr(path)); + fwup_debug(L"Comparing: %s and %s", + DevicePathToStr(parent_dp), + DevicePathToStr(path)); if (LibMatchDevicePaths(path, parent_dp) == TRUE) { *fh = devices[i]; - for (i = 0; i < count; i++) + for (UINTN j = 0; j < count; j++) *file_dp = NextDevicePathNode(*file_dp); - rc = EFI_SUCCESS; - - if (debugging) - print(L"Match up! Returning %s\n", - DevicePathToStr(*file_dp)); - goto out; + fwup_debug(L"Match up! Returning %s", + DevicePathToStr(*file_dp)); + return EFI_SUCCESS; } path = NextDevicePathNode(path); } } -out: - if (!EFI_ERROR(rc)) - print(L"File %s searched\n", DevicePathToStr(*file_dp)); - - uefi_call_wrapper(BS->FreePool, 1, devices); - return rc; + fwup_warning(L"Failed to find '%s' DevicePath", DevicePathToStr(*file_dp)); + return EFI_UNSUPPORTED; } static EFI_STATUS -open_file(EFI_DEVICE_PATH *dp, EFI_FILE_HANDLE *fh) +fwup_open_file(EFI_DEVICE_PATH *dp, EFI_FILE_HANDLE *fh) { + CONST UINTN devpath_max_size = 1024; /* arbitrary limit */ EFI_DEVICE_PATH *file_dp = dp; EFI_GUID sfsp = SIMPLE_FILE_SYSTEM_PROTOCOL; EFI_FILE_HANDLE device; @@ -659,16 +264,16 @@ rc = uefi_call_wrapper(BS->LocateDevicePath, 3, &sfsp, &file_dp, (EFI_HANDLE *)&device); if (EFI_ERROR(rc)) { - rc = search_file(&file_dp, &device); + rc = fwup_search_file(&file_dp, &device); if (EFI_ERROR(rc)) { - print(L"Could not locate device handle: %r\n", rc); + fwup_warning(L"Could not locate device handle: %r", rc); return rc; } } if (DevicePathType(file_dp) != MEDIA_DEVICE_PATH || - DevicePathSubType(file_dp) != MEDIA_FILEPATH_DP) { - print(L"Could not find appropriate device.\n"); + DevicePathSubType(file_dp) != MEDIA_FILEPATH_DP) { + fwup_warning(L"Could not find appropriate device"); return EFI_UNSUPPORTED; } @@ -677,81 +282,65 @@ CopyMem(&sz16, &file_dp->Length[0], sizeof(sz16)); sz = sz16; sz -= 4; - if (sz <= 6 || sz % 2 != 0) { - print(L"Invalid file device path.\n"); + if (sz <= 6 || sz % 2 != 0 || + sz > devpath_max_size * sizeof(CHAR16)) { + fwup_warning(L"Invalid file device path of size %d", sz); return EFI_INVALID_PARAMETER; } - sz /= sizeof (CHAR16); - /* - * check against some arbitrary limit to avoid having a stack - * overflow here. - */ - if (sz > 1024) { - print(L"Invalid file device path.\n"); - return EFI_INVALID_PARAMETER; - } - CHAR16 filename[sz+1]; - CopyMem(filename, (UINT8 *)file_dp + 4, sz * sizeof (CHAR16)); - filename[sz] = L'\0'; + _cleanup_free CHAR16 *filename = fwup_malloc0(sz + sizeof(CHAR16)); + CopyMem(filename, (UINT8 *)file_dp + 4, sz); rc = uefi_call_wrapper(BS->HandleProtocol, 3, device, &sfsp, - (void **)&drive); + (VOID **)&drive); if (EFI_ERROR(rc)) { - print(L"Could not open device interface: %r.\n", rc); + fwup_warning(L"Could not open device interface: %r", rc); return rc; } - dprint(L"Found device\n"); + fwup_debug(L"Found device"); rc = uefi_call_wrapper(drive->OpenVolume, 2, drive, &root); if (EFI_ERROR(rc)) { - print(L"Could not open volume: %r.\n", rc); + fwup_warning(L"Could not open volume: %r", rc); return rc; } - dprint(L"Found volume\n"); + fwup_debug(L"Found volume"); rc = uefi_call_wrapper(root->Open, 5, root, fh, filename, EFI_FILE_MODE_READ, 0); if (EFI_ERROR(rc)) { - print(L"Could not open file \"%s\": %r.\n", filename, rc); + fwup_warning(L"Could not open file '%s': %r", filename, rc); return rc; } - dprint(L"Found file\n"); + fwup_debug(L"Found file"); return EFI_SUCCESS; } static EFI_STATUS -delete_boot_order(CHAR16 *name, EFI_GUID guid) +fwup_delete_boot_order(CHAR16 *name, EFI_GUID guid) { - - UINTN i; UINT16 boot_num; EFI_STATUS rc; UINTN info_size = 0; - UINT32 attributes = 0; - void *info_ptr = NULL; - UINT16 *new_info_ptr = NULL; - BOOLEAN num_found = FALSE; + UINT32 attrs = 0; + _cleanup_free VOID *info_ptr = NULL; + _cleanup_free UINT16 *new_info_ptr = NULL; + UINT8 num_found = FALSE; UINTN new_list_num = 0; /* get boot hex number */ boot_num = xtoi((CHAR16 *)((UINT8 *)name + sizeof(L"Boot"))); - rc = read_variable(L"BootOrder", guid, &info_ptr, &info_size, - &attributes); + rc = fwup_get_variable(L"BootOrder", &guid, &info_ptr, &info_size, &attrs); if (EFI_ERROR(rc)) return rc; - new_info_ptr = AllocatePool(info_size); - if (!new_info_ptr) { - print(L"Tried to allocate %d\n", info_size); - print(L"Could not allocate memory.\n"); - FreePool(info_ptr); + new_info_ptr = fwup_malloc(info_size); + if (new_info_ptr == NULL) return EFI_OUT_OF_RESOURCES; - } - for (i = 0; i < (info_size / sizeof(UINT16)) ; i++) { + for (UINTN i = 0; i < (info_size / sizeof(UINT16)) ; i++) { if (((UINT16 *)info_ptr)[i] != boot_num) { new_info_ptr[i] = ((UINT16 *)info_ptr)[i]; new_list_num++; @@ -762,166 +351,121 @@ } /* if not in the BootOrder list, do not update BootOrder */ - if (!num_found) { - rc = EFI_SUCCESS; - goto out; - } + if (!num_found) + return EFI_SUCCESS; rc = uefi_call_wrapper(RT->SetVariable, 5, L"BootOrder", &guid, - attributes, new_list_num * sizeof(UINT16), + attrs, new_list_num * sizeof(UINT16), new_info_ptr); if (EFI_ERROR(rc)) { - print(L"Could not update variable status for \"%s\": %r\n", - name, rc); - goto out; + fwup_warning(L"Could not update variable status for '%s': %r", + name, rc); + return rc; } - -out: - - FreePool(info_ptr); - FreePool(new_info_ptr); - return rc; } +/* TODO: move to gnu-efi: https://github.com/vathpela/gnu-efi/issues/7 */ +static BOOLEAN +_StrHasPrefix(IN CONST CHAR16 *s1, IN CONST CHAR16 *s2) +{ + while (*s2) { + if (*s1 == L'\0' || *s1 != *s2) + return FALSE; + s1 += 1; + s2 += 1; + } + return TRUE; +} + static EFI_STATUS -delete_boot_entry(void) +fwup_delete_boot_entry(VOID) { EFI_STATUS rc; - - UINTN variable_name_allocation = GNVN_BUF_SIZE; UINTN variable_name_size = 0; - CHAR16 *variable_name; + _cleanup_free CHAR16 *variable_name = NULL; EFI_GUID vendor_guid = empty_guid; - UINTN mult_res; - EFI_STATUS ret = EFI_OUT_OF_RESOURCES; - variable_name = AllocateZeroPool(GNVN_BUF_SIZE * 2); - if (!variable_name) { - print(L"Tried to allocate %d\n", GNVN_BUF_SIZE * 2); - print(L"Could not allocate memory.\n"); + variable_name = fwup_malloc0(GNVN_BUF_SIZE * 2); + if (variable_name == NULL) return EFI_OUT_OF_RESOURCES; - } while (1) { - variable_name_size = variable_name_allocation; + variable_name_size = GNVN_BUF_SIZE; rc = uefi_call_wrapper(RT->GetNextVariableName, 3, &variable_name_size, variable_name, &vendor_guid); - if (rc == EFI_BUFFER_TOO_SMALL) { - - UINTN new_allocation; - CHAR16 *new_name; - - new_allocation = variable_name_size; - if (uintn_mult(new_allocation, 2, &mult_res)) { - print(L"%d * 2 would overflow size\n", - new_allocation); - ret = EFI_OUT_OF_RESOURCES; - goto err; - } - new_name = AllocatePool(new_allocation * 2); - if (!new_name) { - print(L"Tried to allocate %d\n", - new_allocation * 2); - print(L"Could not allocate memory.\n"); - ret = EFI_OUT_OF_RESOURCES; - goto err; - } - CopyMem(new_name, variable_name, - variable_name_allocation); - variable_name_allocation = new_allocation; - FreePool(variable_name); - variable_name = new_name; - continue; - } else if (rc == EFI_NOT_FOUND) { + if (rc == EFI_NOT_FOUND) break; - } else if (EFI_ERROR(rc)) { - print(L"Could not get variable name: %r\n", rc); - ret = rc; - goto err; + /* ignore any huge names */ + if (rc == EFI_BUFFER_TOO_SMALL) + continue; + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not get variable name: %r", rc); + return rc; } /* check if the variable name is Boot#### */ - UINTN vns = StrLen(variable_name); - if (!guid_cmp(&vendor_guid, &global_variable_guid) - && vns == 8 && CompareMem(variable_name, L"Boot", 8) == 0) { - UINTN info_size = 0; - UINT32 attributes = 0; - void *info_ptr = NULL; - CHAR16 *load_op_description = NULL; - CHAR16 target[] = L"Linux Firmware Updater"; + if (CompareGuid(&vendor_guid, &global_variable_guid) != 0) + continue; + if (StrCmp(variable_name, L"Boot") != 0) + continue; - rc = read_variable(variable_name, vendor_guid, - &info_ptr, &info_size, &attributes); - if (EFI_ERROR(rc)) { - ret = rc; - goto err; - } + UINTN info_size = 0; + _cleanup_free VOID *info_ptr = NULL; - /* - * check if the boot path created by fwupdate, - * check with EFI_LOAD_OPTION decription - */ - load_op_description = (CHAR16 *) - ((UINT8 *)info_ptr - + sizeof(UINT32) - + sizeof(UINT16)); - - if (CompareMem(load_op_description, target, - sizeof(target) - 2) == 0) { - /* delete the boot path from BootOrder list */ - rc = delete_boot_order(variable_name, - vendor_guid); - if (EFI_ERROR(rc)) { - print(L"Failed to delete the Linux Firmware Updater boot entry from BootOrder.\n"); - FreePool(info_ptr); - ret = rc; - goto err; - } - - rc = delete_variable(variable_name, - vendor_guid, attributes); - if (EFI_ERROR(rc)) { - print(L"Failed to delete the Linux Firmware Updater boot entry.\n"); - FreePool(info_ptr); - ret = rc; - goto err; - } + /* get the data */ + rc = fwup_get_variable(variable_name, &vendor_guid, + &info_ptr, &info_size, NULL); + if (EFI_ERROR(rc)) + return rc; + if (info_size < sizeof(EFI_LOAD_OPTION)) + continue; - FreePool(info_ptr); - break; + /* + * check if the boot path created by fwupdate, + * check with EFI_LOAD_OPTION decription + */ + EFI_LOAD_OPTION *load_op = (EFI_LOAD_OPTION *) info_ptr; + if (_StrHasPrefix(load_op->description, L"Linux Firmware Updater") || + _StrHasPrefix(load_op->description, L"Linux-Firmware-Updater")) { + /* delete the boot path from BootOrder list */ + rc = fwup_delete_boot_order(variable_name, vendor_guid); + if (EFI_ERROR(rc)) { + fwup_warning(L"Failed to delete boot entry from BootOrder"); + return rc; } - - FreePool(info_ptr); + rc = fwup_delete_variable(variable_name, &vendor_guid); + if (EFI_ERROR(rc)) { + fwup_warning(L"Failed to delete boot entry"); + return rc; + } + break; } } - ret = EFI_SUCCESS; -err: - FreePool(variable_name); - return ret; + return EFI_SUCCESS; } static EFI_STATUS -get_gop_mode(UINT32 *mode, EFI_HANDLE loaded_image) +fwup_get_gop_mode(UINT32 *mode, EFI_HANDLE loaded_image) { EFI_HANDLE *handles, gop_handle; - UINTN num_handles, i; + UINTN num_handles; EFI_STATUS status; EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; EFI_GRAPHICS_OUTPUT_PROTOCOL *gop; - void *iface; + VOID *iface; status = LibLocateHandle(ByProtocol, &gop_guid, NULL, &num_handles, &handles); if (EFI_ERROR(status)) return status; - if (!handles || num_handles == 0) + if (handles == NULL || num_handles == 0) return EFI_UNSUPPORTED; - for (i = 0; i < num_handles; i++) { + for (UINTN i = 0; i < num_handles; i++) { gop_handle = handles[i]; status = uefi_call_wrapper(BS->OpenProtocol, 6, @@ -940,88 +484,24 @@ return EFI_UNSUPPORTED; } -static UINT32 csum(UINT8 *buf, UINTN size) -{ - UINT32 sum = 0; - UINTN i; - - dprint(L"checksumming %d bytes at 0x%08x\n", size, buf); - - for (i = 0; i < size; i++) { - sum += buf[i]; - if (debugging) - Print(L"\rpos:%08lx csum:%d", buf+i, sum); - } - if (debugging) - Print(L"\n"); - - return sum; -} - static EFI_STATUS -do_ux_csum(EFI_HANDLE loaded_image, UINT8 *buf, UINTN size) +fwup_check_gop_for_ux_capsule(EFI_HANDLE loaded_image, + EFI_CAPSULE_HEADER *capsule) { - ux_capsule_header_t *payload_hdr; - EFI_CAPSULE_HEADER *capsule; + UX_CAPSULE_HEADER *payload_hdr; EFI_STATUS rc; - UINTN sum = 0; - - UINT8 *current = buf; - UINTN left = size; - - if (size < sizeof(*capsule)) { - dprint(L"Invalid capsule size %d\n", size); - return EFI_INVALID_PARAMETER; - } - - capsule = (EFI_CAPSULE_HEADER *)buf; - - if (debugging) - hexdump(buf, size <= 0x40 ? size : 0x40); - - dprint(L"size: %d\n", size); - dprint(L"&HeaderSize: 0x%08lx\n", &capsule->HeaderSize); - dprint(L"HeaderSize: %d\n", capsule->HeaderSize); - dprint(L"&CapsuleImageSize: 0x%08lx\n", &capsule->CapsuleImageSize); - dprint(L"CapsuleImageSize: %d\n", capsule->CapsuleImageSize); - if (size < capsule->HeaderSize) { - dprint(L"Invalid capsule header size %d\n", size); - return EFI_INVALID_PARAMETER; - } - - sum += csum(current, capsule->HeaderSize); - current += capsule->HeaderSize; - left -= capsule->HeaderSize; - - payload_hdr = (ux_capsule_header_t *)(buf) + capsule->HeaderSize; - dprint(L"&PayloadHeader: 0x%08lx\n", payload_hdr); - dprint(L"PayloadHeader Size: %d\n", sizeof (*payload_hdr)); - rc = get_gop_mode(&payload_hdr->mode, loaded_image); + payload_hdr = (UX_CAPSULE_HEADER *)((UINT8*) capsule) + capsule->HeaderSize; + rc = fwup_get_gop_mode(&payload_hdr->mode, loaded_image); if (EFI_ERROR(rc)) return EFI_UNSUPPORTED; - payload_hdr->checksum = 0; - sum += csum(current, sizeof(*payload_hdr)); - current += sizeof(*payload_hdr); - left -= sizeof(*payload_hdr); - - sum += csum(current, left); - dprint(L"sum is 0x%02hhx; setting ->checksum to 0x%02hhx\n", - sum & 0xff, (uint8_t)((int8_t)(0 - (sum & 0xff)))); - - payload_hdr->checksum = (uint8_t)((int8_t)(0 - sum)); - dprint(L"checksum is set...\n"); - return EFI_SUCCESS; } -#define is_ux_capsule(guid) (guid_cmp(guid, &ux_capsule_guid) == 0) -#define is_fmp_capsule(guid) (guid_cmp(guid, &fmp_capsule_guid) == 0) - static EFI_STATUS -add_capsule(update_table *update, EFI_CAPSULE_HEADER **capsule_out, - EFI_CAPSULE_BLOCK_DESCRIPTOR *cbd_out, EFI_HANDLE loaded_image) +fwup_add_update_capsule(FWUP_UPDATE_TABLE *update, EFI_CAPSULE_HEADER **capsule_out, + EFI_CAPSULE_BLOCK_DESCRIPTOR *cbd_out, EFI_HANDLE loaded_image) { EFI_STATUS rc; EFI_FILE_HANDLE fh = NULL; @@ -1033,87 +513,42 @@ EFI_PHYSICAL_ADDRESS cbd_data; EFI_CAPSULE_HEADER *cap_out; - rc = open_file((EFI_DEVICE_PATH *)update->info->dp_buf, &fh); + rc = fwup_open_file((EFI_DEVICE_PATH *)update->info->dp_buf, &fh); if (EFI_ERROR(rc)) return rc; - rc = read_file(fh, &fbuf, &fsize); + rc = fwup_read_file(fh, &fbuf, &fsize); if (EFI_ERROR(rc)) return rc; uefi_call_wrapper(fh->Close, 1, fh); - dprint(L"Read file; %d bytes\n", fsize); - dprint(L"updates guid: %g\n", &update->info->guid); - dprint(L"File guid: %g\n", fbuf); - - /* - * See if it has the capsule header, and if not, add one. - * - * Unfortunately there's not a good way to do this, so we're just - * checking if the capsule has the fw_class guid at the right place. - */ - if ((guid_cmp(&update->info->guid, (efi_guid_t *)fbuf) == 0 || - is_fmp_capsule((efi_guid_t *)fbuf)) && - /* - * We're ignoring things that are 40 bytes here, because that's - * the size of the variables used in the test code I wrote for - * edk2 - It's basically a capsule header with no payload, so - * there's nothing real it can do anyway. - * - * At some point I'll update that to be slightly different and - * take the exception out, but it's not pressing. - */ - fsize != 40) { - dprint(L"Image has capsule image embedded\n"); - cbd_len = fsize; - cbd_data = (EFI_PHYSICAL_ADDRESS)(UINTN)fbuf; - capsule = cap_out = (EFI_CAPSULE_HEADER *)fbuf; - if (!cap_out->Flags && !is_ux_capsule(&update->info->guid)) { -#if defined(__aarch64__) - cap_out->Flags |= update->info->capsule_flags; -#else - cap_out->Flags |= update->info->capsule_flags | - CAPSULE_FLAGS_PERSIST_ACROSS_RESET | - CAPSULE_FLAGS_INITIATE_RESET; -#endif - } - } else { - dprint(L"Image does not have embedded header\n"); - dprint(L"Allocating %d for capsule header.\n", - sizeof (*capsule)+fsize); - rc = allocate((void **)&capsule, sizeof (*capsule) + fsize); - if (EFI_ERROR(rc)) { - print(L"Tried to allocate %d\n", - sizeof (*capsule) + fsize); - print(L"Could not allocate space for update: %r.\n", - rc); - return EFI_OUT_OF_RESOURCES; - } - capsule->CapsuleGuid = update->info->guid; - capsule->HeaderSize = sizeof (*capsule); - if (!is_ux_capsule(&update->info->guid)) { + if (fsize < sizeof(EFI_CAPSULE_HEADER)) { + fwup_warning(L"Invalid capsule size %d", fsize); + return EFI_INVALID_PARAMETER; + } + + fwup_debug(L"Read file; %d bytes", fsize); + fwup_debug(L"updates guid: %g", &update->info->guid); + fwup_debug(L"File guid: %g", fbuf); + + cbd_len = fsize; + cbd_data = (EFI_PHYSICAL_ADDRESS)(UINTN)fbuf; + capsule = cap_out = (EFI_CAPSULE_HEADER *)fbuf; + if (cap_out->Flags == 0 && + CompareGuid(&update->info->guid, &ux_capsule_guid) != 0) { #if defined(__aarch64__) - capsule->Flags |= update->info->capsule_flags; + cap_out->Flags |= update->info->capsule_flags; #else - capsule->Flags = update->info->capsule_flags | - CAPSULE_FLAGS_PERSIST_ACROSS_RESET | - CAPSULE_FLAGS_INITIATE_RESET; + cap_out->Flags |= update->info->capsule_flags | + CAPSULE_FLAGS_PERSIST_ACROSS_RESET | + CAPSULE_FLAGS_INITIATE_RESET; #endif - } - capsule->CapsuleImageSize = fsize + sizeof (*capsule); - - UINT8 *buffer = (UINT8 *)capsule + capsule->HeaderSize; - CopyMem(buffer, fbuf, fsize); - cbd_len = capsule->CapsuleImageSize; - cbd_data = (EFI_PHYSICAL_ADDRESS)(UINTN)capsule; - cap_out = capsule; - free(fbuf, fsize); } - if (is_ux_capsule(&update->info->guid)) { - dprint(L"Checksumming ux capsule\n"); - rc = do_ux_csum(loaded_image, (UINT8 *)capsule, cbd_len); + if (CompareGuid(&update->info->guid, &ux_capsule_guid) == 0) { + fwup_debug(L"Checking GOP for ux capsule"); + rc = fwup_check_gop_for_ux_capsule(loaded_image, capsule); if (EFI_ERROR(rc)) return EFI_UNSUPPORTED; } @@ -1125,54 +560,49 @@ return EFI_SUCCESS; } - static EFI_STATUS -apply_capsules(EFI_CAPSULE_HEADER **capsules, - EFI_CAPSULE_BLOCK_DESCRIPTOR *cbd, - UINTN num_updates, EFI_RESET_TYPE *reset) +fwup_apply_capsules(EFI_CAPSULE_HEADER **capsules, + EFI_CAPSULE_BLOCK_DESCRIPTOR *cbd, + UINTN num_updates, EFI_RESET_TYPE *reset) { UINT64 max_capsule_size; EFI_STATUS rc; - rc = delete_boot_entry(); - if (EFI_ERROR(rc)) { - /* - * Print out deleting boot entry error, but still try to apply - * capsule. - */ - dprint(L"Could not delete boot entry: %r\n", - __FILE__, __func__, __LINE__, rc); - } + /* still try to apply capsule on failure */ + rc = fwup_delete_boot_entry(); + if (EFI_ERROR(rc)) + fwup_warning(L"Could not delete boot entry: %r", rc); rc = uefi_call_wrapper(RT->QueryCapsuleCapabilities, 4, capsules, num_updates, &max_capsule_size, reset); - dprint(L"QueryCapsuleCapabilities: %r max: %ld reset:%d\n", - rc, max_capsule_size, *reset); - dprint(L"Capsules: %d\n", num_updates); + fwup_debug(L"QueryCapsuleCapabilities: %r max: %ld reset:%d", + rc, max_capsule_size, *reset); + fwup_debug(L"Capsules: %d", num_updates); - uefi_call_wrapper(BS->Stall, 1, 1 * SECONDS); + fwup_msleep(1 * SECONDS); rc = uefi_call_wrapper(RT->UpdateCapsule, 3, capsules, num_updates, (EFI_PHYSICAL_ADDRESS)(UINTN)cbd); if (EFI_ERROR(rc)) { - print(L"Could not apply capsule update: %r\n", rc); + fwup_warning(L"Could not apply capsule update: %r", rc); return rc; } return EFI_SUCCESS; } -static -EFI_STATUS -set_statuses(UINTN n_updates, update_table **updates) +static EFI_STATUS +fwup_set_update_statuses(FWUP_UPDATE_TABLE **updates) { EFI_STATUS rc; - for (UINTN i = 0; i < n_updates; i++) { - rc = uefi_call_wrapper(RT->SetVariable, 5, updates[i]->name, - &fwupdate_guid, updates[i]->attributes, - updates[i]->size, updates[i]->info); + for (UINTN i = 0; i < FWUP_NUM_CAPSULE_UPDATES_MAX; i++) { + if (updates[i] == NULL || updates[i]->name == NULL) + break; + rc = fwup_set_variable(updates[i]->name, &fwupdate_guid, + updates[i]->info, updates[i]->size, + updates[i]->attrs); if (EFI_ERROR(rc)) { - print(L"Coould not update variable status for \"%s\": %r\n", - updates[i]->name, rc); + fwup_warning(L"Could not update variable status for '%s': %r", + updates[i]->name, rc); return rc; } } @@ -1182,75 +612,56 @@ EFI_GUID SHIM_LOCK_GUID = {0x605dab50,0xe046,0x4300,{0xab,0xb6,0x3d,0xd8,0x10,0xdd,0x8b,0x23}}; -static void +static VOID __attribute__((__optimize__("0"))) -debug_hook(void) +fwup_debug_hook(VOID) { EFI_GUID guid = SHIM_LOCK_GUID; UINTN data = 0; UINTN data_size = 1; EFI_STATUS efi_status; - UINT32 attributes; + UINT32 attrs; register volatile int x = 0; extern char _text UNUSED, _data UNUSED; - /* - * If SHIM_DEBUG is set, we're going to assume shim has done whatever - * is needed to get a debugger attached, and we just need to explain - * who and where we are, and also enable our debugging output. - */ + /* shim has done whatever is needed to get a debugger attached */ efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"SHIM_DEBUG", - &guid, &attributes, &data_size, &data); + &guid, &attrs, &data_size, &data); if (EFI_ERROR(efi_status) || data != 1) { efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"FWUPDATE_VERBOSE", - &fwupdate_guid, &attributes, + &fwupdate_guid, &attrs, &data_size, &data); - if (EFI_ERROR(efi_status) || data != 1) { + if (EFI_ERROR(efi_status) || data != 1) return; - } - debugging = 1; + fwup_debug_set_enabled(TRUE); return; } - debugging = 1; + fwup_debug_set_enabled(TRUE); if (x) return; x = 1; - print(L"add-symbol-file "DEBUGDIR - L"fwupdate.efi.debug %p -s .data %p\n", - &_text, &_data); + fwup_info(L"add-symbol-file "DEBUGDIR + L"fwupdate.efi.debug %p -s .data %p", + &_text, &_data); } EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) { EFI_STATUS rc; - update_table **updates = NULL; - UINTN n_updates = 0; + UINTN i, n_updates = 0; EFI_RESET_TYPE reset_type = EfiResetWarm; + _cleanup_free FWUP_UPDATE_TABLE **updates = NULL; InitializeLib(image, systab); - /* - * if SHIM_DEBUG is set, print info for our attached debugger. - */ - debug_hook(); - - /* - * Basically the workflow here is: - * 1) find and validate any update state variables with the right GUID - * 2) allocate our capsule data structures and add the capsules - * #1 described - * 3) update status variables - * 4) apply the capsule updates - * 5) reboot - */ + /* if SHIM_DEBUG is set, fwup_info info for our attached debugger */ + fwup_debug_hook(); - /* - * Step 1: find and validate update state variables - */ + /* step 1: find and validate update state variables */ /* XXX TODO: * 1) survey the reset types first, and separate into groups * according to them @@ -1258,78 +669,68 @@ * so we can do multiple runs * 3) only select the ones from one type for the first go */ - rc = find_updates(&n_updates, &updates); + updates = fwup_new0(FWUP_UPDATE_TABLE *, FWUP_NUM_CAPSULE_UPDATES_MAX); + if (updates == NULL) + return EFI_OUT_OF_RESOURCES; + rc = fwup_populate_update_table(updates, &n_updates); if (EFI_ERROR(rc)) { - print(L"fwupdate: Could not find updates: %r\n", rc); + fwup_warning(L"Could not find updates: %r", rc); return rc; } if (n_updates == 0) { - print(L"fwupdate: No updates to process. Called in error?\n"); + fwup_warning(L"No updates to process. Called in error?"); return EFI_INVALID_PARAMETER; } - /* - * Step 2: Build our data structure and add the capsules to it. - */ - EFI_CAPSULE_HEADER *capsules[n_updates + 1]; + /* step 2: Build our data structure and add the capsules to it */ + _cleanup_free EFI_CAPSULE_HEADER **capsules = NULL; + capsules = fwup_new0(EFI_CAPSULE_HEADER *, n_updates + 1); EFI_CAPSULE_BLOCK_DESCRIPTOR *cbd_data; - UINTN i, j; - rc = allocate((void **)&cbd_data, - sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR)*(n_updates+1)); - if (EFI_ERROR(rc)) { - print(L"Tried to allocate %d\n", - sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR)*(n_updates+1)); - print(L"fwupdate: Could not allocate memory: %r.\n",rc); - return rc; - } - for (i = 0, j = 0; i < n_updates; i++) { - dprint(L"Adding new capsule\n"); - rc = add_capsule(updates[i], &capsules[j], &cbd_data[j], - image); + UINTN j = 0; + cbd_data = fwup_malloc_raw(sizeof(EFI_CAPSULE_BLOCK_DESCRIPTOR)*(n_updates+1)); + if (cbd_data == NULL) + return EFI_OUT_OF_RESOURCES; + for (i = 0; i < n_updates; i++) { + fwup_info(L"Adding new capsule"); + rc = fwup_add_update_capsule(updates[i], &capsules[j], &cbd_data[j], image); if (EFI_ERROR(rc)) { + /* ignore a failing UX capsule */ if (rc == EFI_UNSUPPORTED && - is_ux_capsule(&updates[i]->info->guid)) + CompareGuid(&updates[i]->info->guid, &ux_capsule_guid) == 0) { + fwup_debug(L"GOP unsuitable: %r", rc); continue; - dprint(L"fwupdate: Could not build update list: %r\n", - rc); + } + fwup_warning(L"Could not build update list: %r", rc); return rc; } j++; } n_updates = j; - dprint(L"n_updates: %d\n", n_updates); + fwup_debug(L"n_updates: %d", n_updates); cbd_data[i].Length = 0; cbd_data[i].Union.ContinuationPointer = 0; - /* - * Step 3: update the state variables. - */ - rc = set_statuses(n_updates, updates); + /* step 3: update the state variables */ + rc = fwup_set_update_statuses(updates); if (EFI_ERROR(rc)) { - print(L"fwupdate: Could not set update status: %r\n", rc); + fwup_warning(L"Could not set update status: %r", rc); return rc; } - /* - * Step 4: apply the capsules. - */ - rc = apply_capsules(capsules, cbd_data, n_updates, &reset_type); + /* step 4: apply the capsules */ + rc = fwup_apply_capsules(capsules, cbd_data, n_updates, &reset_type); if (EFI_ERROR(rc)) { - print(L"fwupdate: Could not apply capsules: %r\n", rc); + fwup_warning(L"Could not apply capsules: %r", rc); return rc; } - /* - * Step 5: if #4 didn't reboot us, do it manually. - */ - dprint(L"fwupdate: Reset System\n"); - if (debugging) - uefi_call_wrapper(BS->Stall, 1, 5 * SECONDS); - - uefi_call_wrapper(BS->Stall, 1, 5 * SECONDS); - uefi_call_wrapper(RT->ResetSystem, 4, reset_type, EFI_SUCCESS, - 0, NULL); + /* step 5: if #4 didn't reboot us, do it manually */ + fwup_info(L"Reset System"); + fwup_msleep(5 * SECONDS); + if (fwup_debug_get_enabled()) + fwup_msleep(30 * SECONDS); + uefi_call_wrapper(RT->ResetSystem, 4, reset_type, EFI_SUCCESS, 0, NULL); return EFI_SUCCESS; } diff -Nru fwupd-1.1.4/plugins/uefi/efi/fwup-debug.c fwupd-1.2.5/plugins/uefi/efi/fwup-debug.c --- fwupd-1.1.4/plugins/uefi/efi/fwup-debug.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/efi/fwup-debug.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include +#include + +#include "fwup-cleanups.h" +#include "fwup-debug.h" +#include "fwup-efi.h" + +static BOOLEAN debugging = FALSE; + +BOOLEAN +fwup_debug_get_enabled(VOID) +{ + return debugging; +} + +VOID +fwup_debug_set_enabled(BOOLEAN val) +{ + debugging = val; +} + +static VOID +fwupd_debug_efivar_append(CHAR16 *out1) +{ + CHAR16 *name = L"FWUPDATE_DEBUG_LOG"; + UINT32 attrs = EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS; + static BOOLEAN once = TRUE; + if (once) { + once = FALSE; + fwup_delete_variable(name, &fwupdate_guid); + } else { + attrs |= EFI_VARIABLE_APPEND_WRITE; + } + fwup_set_variable(name, &fwupdate_guid, out1, StrSize(out1) - sizeof(CHAR16), attrs); +} + +VOID +fwup_log(FwupLogLevel level, const char *func, const char *file, const int line, CHAR16 *fmt, ...) +{ + va_list args; + _cleanup_free CHAR16 *tmp = NULL; + + va_start(args, fmt); + tmp = VPoolPrint(fmt, args); + va_end(args); + if (tmp == NULL) { + Print(L"fwupdate: Allocation for debug log failed!\n"); + return; + } + + if (debugging) { + _cleanup_free CHAR16 *out1 = NULL; + out1 = PoolPrint(L"%a:%d:%a(): %s", file, line, func, tmp); + if (out1 == NULL) { + Print(L"fwupdate: Allocation for debug log failed!\n"); + return; + } + Print(L"%s\n", out1); + fwupd_debug_efivar_append(out1); + } else { + switch (level) { + case FWUP_DEBUG_LEVEL_DEBUG: + break; + case FWUP_DEBUG_LEVEL_WARNING: + Print(L"WARNING: %s\n", tmp); + break; + default: + Print(L"%s\n", tmp); + break; + } + } +} diff -Nru fwupd-1.1.4/plugins/uefi/efi/fwup-debug.h fwupd-1.2.5/plugins/uefi/efi/fwup-debug.h --- fwupd-1.1.4/plugins/uefi/efi/fwup-debug.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/efi/fwup-debug.h 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015-2016 Peter Jones + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +typedef enum { + FWUP_DEBUG_LEVEL_DEBUG, + FWUP_DEBUG_LEVEL_INFO, + FWUP_DEBUG_LEVEL_WARNING, + FWUP_DEBUG_LEVEL_LAST +} FwupLogLevel; + +VOID fwup_log (FwupLogLevel level, + const char *func, + const char *file, + const int line, + CHAR16 *fmt, + ...); + +BOOLEAN fwup_debug_get_enabled (VOID); +VOID fwup_debug_set_enabled (BOOLEAN val); + +#define fwup_debug(fmt, args...) fwup_log(FWUP_DEBUG_LEVEL_DEBUG, __func__, __FILE__, __LINE__, fmt, ## args ) +#define fwup_info(fmt, args...) fwup_log(FWUP_DEBUG_LEVEL_INFO, __func__, __FILE__, __LINE__, fmt, ## args ) +#define fwup_warning(fmt, args...) fwup_log(FWUP_DEBUG_LEVEL_WARNING, __func__, __FILE__, __LINE__, fmt, ## args ) diff -Nru fwupd-1.1.4/plugins/uefi/efi/fwup-efi.c fwupd-1.2.5/plugins/uefi/efi/fwup-efi.c --- fwupd-1.1.4/plugins/uefi/efi/fwup-efi.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/efi/fwup-efi.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include +#include + +#include "fwup-cleanups.h" +#include "fwup-common.h" +#include "fwup-debug.h" +#include "fwup-efi.h" + +EFI_STATUS +fwup_delete_variable(CHAR16 *name, EFI_GUID *guid) +{ + EFI_STATUS rc; + UINT32 attrs = 0; + + /* get the attrs so we can delete it */ + rc = uefi_call_wrapper(RT->GetVariable, 5, name, guid, &attrs, NULL, NULL); + if (EFI_ERROR(rc)) { + if (rc == EFI_NOT_FOUND) { + fwup_debug(L"Not deleting variable '%s' as not found", name); + return EFI_SUCCESS; + } + fwup_debug(L"Could not get variable '%s' for delete: %r", name, rc); + return rc; + } + return uefi_call_wrapper(RT->SetVariable, 5, name, guid, attrs, 0, NULL); +} + +EFI_STATUS +fwup_set_variable(CHAR16 *name, EFI_GUID *guid, VOID *data, UINTN size, UINT32 attrs) +{ + return uefi_call_wrapper(RT->SetVariable, 5, name, guid, attrs, size, data); +} + +EFI_STATUS +fwup_get_variable(CHAR16 *name, EFI_GUID *guid, VOID **buf_out, UINTN *buf_size_out, UINT32 *attrs_out) +{ + EFI_STATUS rc; + UINTN size = 0; + UINT32 attrs; + _cleanup_free VOID *buf = NULL; + + rc = uefi_call_wrapper(RT->GetVariable, 5, name, guid, &attrs, &size, NULL); + if (EFI_ERROR(rc)) { + if (rc == EFI_BUFFER_TOO_SMALL) { + buf = fwup_malloc(size); + if (buf == NULL) + return EFI_OUT_OF_RESOURCES; + } else if (rc != EFI_NOT_FOUND) { + fwup_debug(L"Could not get variable '%s': %r", name, rc); + return rc; + } + } else { + fwup_debug(L"GetVariable(%s) succeeded with size=0", name); + return EFI_INVALID_PARAMETER; + } + rc = uefi_call_wrapper(RT->GetVariable, 5, name, guid, &attrs, &size, buf); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not get variable '%s': %r", name, rc); + return rc; + } + *buf_out = _steal_pointer(&buf); + *buf_size_out = size; + *attrs_out = attrs; + return EFI_SUCCESS; +} diff -Nru fwupd-1.1.4/plugins/uefi/efi/fwup-efi.h fwupd-1.2.5/plugins/uefi/efi/fwup-efi.h --- fwupd-1.1.4/plugins/uefi/efi/fwup-efi.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/efi/fwup-efi.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,48 +4,66 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef _FWUP_EFI_H -#define _FWUP_EFI_H +#pragma once #define FWUPDATE_ATTEMPT_UPDATE 0x00000001 #define FWUPDATE_ATTEMPTED 0x00000002 #define UPDATE_INFO_VERSION 7 -#ifdef _EFI_INCLUDE_ -#define efidp_header EFI_DEVICE_PATH -#define efi_guid_t EFI_GUID -#endif /* _EFI_INCLUDE_ */ +static __attribute__((__unused__)) EFI_GUID empty_guid = + {0x0,0x0,0x0,{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}}; +static __attribute__((__unused__))EFI_GUID fwupdate_guid = + {0x0abba7dc,0xe516,0x4167,{0xbb,0xf5,0x4d,0x9d,0x1c,0x73,0x94,0x16}}; +static __attribute__((__unused__))EFI_GUID ux_capsule_guid = + {0x3b8c8162,0x188c,0x46a4,{0xae,0xc9,0xbe,0x43,0xf1,0xd6,0x56,0x97}}; +static __attribute__((__unused__))EFI_GUID global_variable_guid = EFI_GLOBAL_VARIABLE; typedef struct { - uint8_t version; - uint8_t checksum; - uint8_t image_type; - uint8_t reserved; - uint32_t mode; - uint32_t x_offset; - uint32_t y_offset; -} ux_capsule_header_t; + UINT8 version; + UINT8 checksum; + UINT8 image_type; + UINT8 reserved; + UINT32 mode; + UINT32 x_offset; + UINT32 y_offset; +} __attribute__((__packed__)) UX_CAPSULE_HEADER; -typedef struct update_info_s { - uint32_t update_info_version; +typedef struct { + UINT32 update_info_version; /* stuff we need to apply an update */ - efi_guid_t guid; - uint32_t capsule_flags; - uint64_t hw_inst; + EFI_GUID guid; + UINT32 capsule_flags; + UINT64 hw_inst; - EFI_TIME time_attempted; + EFI_TIME time_attempted; /* our metadata */ - uint32_t status; + UINT32 status; /* variadic device path */ union { - efidp_header *dp_ptr; - efidp_header dp; - uint8_t dp_buf[0]; + EFI_DEVICE_PATH dp; + UINT8 dp_buf[0]; }; -} __attribute__((__packed__)) update_info; +} __attribute__((__packed__)) FWUP_UPDATE_INFO; -#endif /* _FWUP_EFI_H */ +typedef struct { + UINT32 attributes; + UINT16 file_path_list_length; + CHAR16 *description; +} __attribute__((__packed__)) EFI_LOAD_OPTION; + +EFI_STATUS fwup_delete_variable (CHAR16 *name, + EFI_GUID *guid); +EFI_STATUS fwup_set_variable (CHAR16 *name, + EFI_GUID *guid, + VOID *data, + UINTN size, + UINT32 attrs); +EFI_STATUS fwup_get_variable (CHAR16 *name, + EFI_GUID *guid, + VOID **buf_out, + UINTN *buf_size_out, + UINT32 *attrs_out); diff -Nru fwupd-1.1.4/plugins/uefi/efi/hexdump.h fwupd-1.2.5/plugins/uefi/efi/hexdump.h --- fwupd-1.1.4/plugins/uefi/efi/hexdump.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/efi/hexdump.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2015-2016 Peter Jones - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#ifndef STATIC_HEXDUMP_H -#define STATIC_HEXDUMP_H - -static int -__attribute__((__unused__)) -isprint(char c) -{ - if (c < 0x20) - return 0; - if (c > 0x7e) - return 0; - return 1; -} - -static UINTN -__attribute__((__unused__)) -format_hex(UINT8 *data, UINTN size, CHAR16 *buf) -{ - UINTN sz = (UINTN)data % 16; - CHAR16 hexchars[] = L"0123456789abcdef"; - int offset = 0; - unsigned int i; - unsigned int j; - - for (i = 0; i < sz; i++) { - buf[offset++] = L' '; - buf[offset++] = L' '; - buf[offset++] = L' '; - if (i == 7) - buf[offset++] = L' '; - } - for (j = sz; j < 16 && j < size; j++) { - UINT8 d = data[j-sz]; - buf[offset++] = hexchars[(d & 0xf0) >> 4]; - buf[offset++] = hexchars[(d & 0x0f)]; - if (j != 15) - buf[offset++] = L' '; - if (j == 7) - buf[offset++] = L' '; - } - for (i = j; i < 16; i++) { - buf[offset++] = L' '; - buf[offset++] = L' '; - if (i != 15) - buf[offset++] = L' '; - if (i == 7) - buf[offset++] = L' '; - } - buf[offset] = L'\0'; - return j - sz; -} - -static void -__attribute__((__unused__)) -format_text(UINT8 *data, UINTN size, CHAR16 *buf) -{ - UINTN sz = (UINTN)data % 16; - int offset = 0; - unsigned int i; - unsigned int j; - - for (i = 0; i < sz; i++) - buf[offset++] = L' '; - buf[offset++] = L'|'; - for (j = sz; j < 16 && j < size; j++) { - if (isprint(data[j-sz])) - buf[offset++] = data[j-sz]; - else - buf[offset++] = L'.'; - } - buf[offset++] = L'|'; - for (i = j; i < 16; i++) - buf[offset++] = L' '; - buf[offset] = L'\0'; -} - -static void -__attribute__((__unused__)) -hexdump(UINT8 *data, UINTN size) -{ - UINTN display_offset = (UINTN)data & 0xffffffff; - UINTN offset = 0; - //Print(L"hexdump: data=0x%016x size=0x%x\n", data, size); - - while (offset < size) { - CHAR16 hexbuf[49]; - CHAR16 txtbuf[19]; - UINTN sz; - - sz = format_hex(data+offset, size-offset, hexbuf); - if (sz == 0) - return; - uefi_call_wrapper(BS->Stall, 1, 200000); - - format_text(data+offset, size-offset, txtbuf); - Print(L"%08x %s %s\n", display_offset, hexbuf, txtbuf); - uefi_call_wrapper(BS->Stall, 1, 200000); - - display_offset += sz; - offset += sz; - } -} - - -#endif diff -Nru fwupd-1.1.4/plugins/uefi/efi/meson.build fwupd-1.2.5/plugins/uefi/efi/meson.build --- fwupd-1.1.4/plugins/uefi/efi/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/efi/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -53,8 +53,8 @@ '--param=ssp-buffer-size=4', '-fexceptions', '-Wall', - '-Werror', '-Wextra', + '-Wvla', '-std=gnu11', '-fpic', '-fshort-wchar', @@ -65,10 +65,14 @@ '-fno-merge-constants', '-Wsign-compare', '-Wno-missing-field-initializers', + '-Wno-address-of-packed-member', '-grecord-gcc-switches', '-DDEBUGDIR="@0@"'.format(debugdir), '-isystem', efi_incdir, '-isystem', join_paths(efi_incdir, gnu_efi_path_arch)] +if get_option('werror') + compile_args += '-Werror' +endif if efi_arch == 'x86_64' compile_args += ['-mno-red-zone', '-mno-sse', @@ -103,14 +107,29 @@ libgcc_file_name = run_command(efi_cc, '-print-libgcc-file-name').stdout().strip() efi_name = 'fwupd@0@.efi'.format(EFI_MACHINE_TYPE_NAME) -o_file = custom_target('fwupdate.o', +o_file1 = custom_target('fwupdate.o', input : 'fwupdate.c', output : 'fwupdate.o', command : [efi_cc, '-c', '@INPUT@', '-o', '@OUTPUT@'] + compile_args) +o_file2 = custom_target('fwup-debug.o', + input : 'fwup-debug.c', + output : 'fwup-debug.o', + command : [efi_cc, '-c', '@INPUT@', '-o', '@OUTPUT@'] + + compile_args) +o_file3 = custom_target('fwup-efi.o', + input : 'fwup-efi.c', + output : 'fwup-efi.o', + command : [efi_cc, '-c', '@INPUT@', '-o', '@OUTPUT@'] + + compile_args) +o_file4 = custom_target('fwup-common.o', + input : 'fwup-common.c', + output : 'fwup-common.o', + command : [efi_cc, '-c', '@INPUT@', '-o', '@OUTPUT@'] + + compile_args) so = custom_target('fwup.so', - input : o_file, + input : [o_file1, o_file2, o_file3, o_file4], output : 'fwup.so', command : [efi_ld, '-o', '@OUTPUT@'] + efi_ldflags + ['@INPUT@'] + diff -Nru fwupd-1.1.4/plugins/uefi/fu-plugin-uefi.c fwupd-1.2.5/plugins/uefi/fu-plugin-uefi.c --- fwupd-1.1.4/plugins/uefi/fu-plugin-uefi.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/fu-plugin-uefi.c 2019-02-25 09:42:18.000000000 +0000 @@ -38,7 +38,9 @@ FuPluginData *data = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); data->bgrt = fu_uefi_bgrt_new (); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "upower"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.uefi.capsule"); fu_plugin_add_compile_version (plugin, "com.redhat.efivar", EFIVAR_LIBRARY_VERSION); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); } void @@ -157,6 +159,15 @@ return g_bytes_new_take (g_steal_pointer (&buf), buf_idx); } +static guint8 +fu_plugin_uefi_calc_checksum (const guint8 *buf, gsize sz) +{ + guint8 csum = 0; + for (gsize i = 0; i < sz; i++) + csum += buf[i]; + return csum; +} + static gboolean fu_plugin_uefi_write_splash_data (FuPlugin *plugin, GBytes *blob, GError **error) { @@ -165,7 +176,8 @@ gsize buf_size = g_bytes_get_size (blob); gssize size; guint32 height, width; - efi_ux_capsule_header_t header; + guint8 csum = 0; + efi_ux_capsule_header_t header = { 0 }; efi_capsule_header_t capsule_header = { .flags = EFI_CAPSULE_HEADER_FLAGS_PERSIST_ACROSS_RESET, .guid = efi_guid_ux_capsule, @@ -202,9 +214,8 @@ capsule_header.capsule_image_size = g_bytes_get_size (blob) + sizeof(efi_capsule_header_t) + - sizeof(header); + sizeof(efi_ux_capsule_header_t); - memset (&header, '\0', sizeof(header)); header.version = 1; header.image_type = 0; header.reserved = 0; @@ -212,6 +223,15 @@ header.y_offset = fu_uefi_bgrt_get_yoffset (data->bgrt) + fu_uefi_bgrt_get_height (data->bgrt); + /* header, payload and image has to add to zero */ + csum += fu_plugin_uefi_calc_checksum ((guint8 *) &capsule_header, + sizeof(capsule_header)); + csum += fu_plugin_uefi_calc_checksum ((guint8 *) &header, + sizeof(header)); + csum += fu_plugin_uefi_calc_checksum (g_bytes_get_data (blob, NULL), + g_bytes_get_size (blob)); + header.checksum = 0x100 - csum; + /* write capsule file */ size = g_output_stream_write (ostream, &capsule_header, capsule_header.header_size, NULL, error); @@ -377,6 +397,10 @@ if (!fu_device_write_firmware (device, blob_fw, error)) return FALSE; + /* record if we had an invalid header during update */ + str = fu_uefi_missing_capsule_header (device) ? "True" : "False"; + fu_plugin_add_report_metadata (plugin, "MissingCapsuleHeader", str); + /* record boot information to system log for future debugging */ efibootmgr_path = fu_common_find_program_in_path ("efibootmgr", NULL); if (efibootmgr_path != NULL) { @@ -412,7 +436,7 @@ } } -static AsVersionParseFlag +static FuVersionFormat fu_plugin_uefi_get_version_format_for_type (FuPlugin *plugin, FuUefiDeviceKind device_kind) { const gchar *content; @@ -421,21 +445,19 @@ /* we have no information for devices */ if (device_kind == FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE) - return AS_VERSION_PARSE_FLAG_USE_TRIPLET; + return FU_VERSION_FORMAT_TRIPLET; content = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_MANUFACTURER); if (content == NULL) - return AS_VERSION_PARSE_FLAG_USE_TRIPLET; + return FU_VERSION_FORMAT_TRIPLET; /* any quirks match */ group = g_strdup_printf ("SmbiosManufacturer=%s", content); quirk = fu_plugin_lookup_quirk_by_id (plugin, group, FU_QUIRKS_UEFI_VERSION_FORMAT); - if (g_strcmp0 (quirk, "quad") == 0) - return AS_VERSION_PARSE_FLAG_NONE; - - /* fall back */ - return AS_VERSION_PARSE_FLAG_USE_TRIPLET; + if (quirk == NULL) + return FU_VERSION_FORMAT_TRIPLET; + return fu_common_version_format_from_string (quirk); } static const gchar * @@ -478,37 +500,29 @@ fu_plugin_uefi_coldplug_device (FuPlugin *plugin, FuUefiDevice *dev, GError **error) { FuUefiDeviceKind device_kind; - AsVersionParseFlag parse_flags; - guint32 version_raw; - g_autofree gchar *name = NULL; - g_autofree gchar *version_lowest = NULL; - g_autofree gchar *version = NULL; + FuVersionFormat version_format; - /* add details to the device */ + /* set default version format */ device_kind = fu_uefi_device_get_kind (dev); - parse_flags = fu_plugin_uefi_get_version_format_for_type (plugin, device_kind); - version_raw = fu_uefi_device_get_version (dev); - version = as_utils_version_from_uint32 (version_raw, parse_flags); - fu_device_set_version (dev, version); - name = fu_plugin_uefi_get_name_for_type (plugin, fu_uefi_device_get_kind (dev)); - if (name != NULL) - fu_device_set_name (FU_DEVICE (dev), name); - version_raw = fu_uefi_device_get_version_lowest (dev); - if (version_raw != 0) { - version_lowest = as_utils_version_from_uint32 (version_raw, - parse_flags); - fu_device_set_version_lowest (FU_DEVICE (dev), version_lowest); - } - fu_device_add_flag (FU_DEVICE (dev), FWUPD_DEVICE_FLAG_INTERNAL); - fu_device_add_flag (FU_DEVICE (dev), FWUPD_DEVICE_FLAG_NEEDS_REBOOT); - fu_device_add_flag (FU_DEVICE (dev), FWUPD_DEVICE_FLAG_REQUIRE_AC); - if (device_kind == FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE) { - /* nothing better in the icon naming spec */ - fu_device_add_icon (FU_DEVICE (dev), "audio-card"); - } else { - /* this is probably system firmware */ - fu_device_add_icon (FU_DEVICE (dev), "computer"); - fu_device_add_guid (FU_DEVICE (dev), "main-system-firmware"); + version_format = fu_plugin_uefi_get_version_format_for_type (plugin, device_kind); + fu_device_set_version_format (FU_DEVICE (dev), version_format); + + /* probe to get add GUIDs (and hence any quirk fixups) */ + if (!fu_device_probe (FU_DEVICE (dev), error)) + return FALSE; + + /* set this flag for all Lenovo hardware */ + if (fu_plugin_check_hwid (plugin, "6de5d951-d755-576b-bd09-c5cf66b27234")) { + fu_device_set_custom_flags (FU_DEVICE (dev), "use-legacy-bootmgr-desc"); + fu_plugin_add_report_metadata (plugin, "BootMgrDesc", "legacy"); + } + + /* set fallback name if nothing else is set */ + if (fu_device_get_name (FU_DEVICE (dev)) == 0) { + g_autofree gchar *name = NULL; + name = fu_plugin_uefi_get_name_for_type (plugin, fu_uefi_device_get_kind (dev)); + if (name != NULL) + fu_device_set_name (FU_DEVICE (dev), name); } /* success */ @@ -742,7 +756,13 @@ /* add each device */ for (guint i = 0; i < entries->len; i++) { const gchar *path = g_ptr_array_index (entries, i); - g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_entry (path); + g_autoptr(GError) error_parse = NULL; + g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_entry (path, &error_parse); + if (dev == NULL) { + g_warning ("failed to add %s: %s", path, error_parse->message); + continue; + } + fu_device_set_quirks (FU_DEVICE (dev), fu_plugin_get_quirks (plugin)); if (!fu_plugin_uefi_coldplug_device (plugin, dev, error)) return FALSE; if (error_esp != NULL) { diff -Nru fwupd-1.1.4/plugins/uefi/fu-self-test.c fwupd-1.2.5/plugins/uefi/fu-self-test.c --- fwupd-1.1.4/plugins/uefi/fu-self-test.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/fu-self-test.c 2019-02-25 09:42:18.000000000 +0000 @@ -13,9 +13,74 @@ #include "fu-uefi-bgrt.h" #include "fu-uefi-common.h" #include "fu-uefi-device.h" +#include "fu-uefi-pcrs.h" #include "fu-uefi-vars.h" static void +fu_uefi_pcrs_1_2_func (void) +{ + gboolean ret; + g_autoptr(FuUefiPcrs) pcrs = fu_uefi_pcrs_new (); + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) pcr0s = NULL; + g_autoptr(GPtrArray) pcrXs = NULL; + + ret = fu_uefi_pcrs_setup (pcrs, &error); + g_assert_no_error (error); + g_assert_true (ret); + pcr0s = fu_uefi_pcrs_get_checksums (pcrs, 0); + g_assert_nonnull (pcr0s); + g_assert_cmpint (pcr0s->len, ==, 1); + pcrXs = fu_uefi_pcrs_get_checksums (pcrs, 999); + g_assert_nonnull (pcrXs); + g_assert_cmpint (pcrXs->len, ==, 0); +} + +static void +fu_uefi_pcrs_2_0_func (void) +{ + gboolean ret; + g_autoptr(FuUefiPcrs) pcrs = fu_uefi_pcrs_new (); + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) pcr0s = NULL; + g_autoptr(GPtrArray) pcrXs = NULL; + + g_setenv ("FWUPD_UEFI_TPM2_YAML_DATA", + "sha1 :\n" + " 0 : cbd9e4112727bc75761001abcb2dddd87a66caf5\n" + "sha256 :\n" + " 0 : 122de8b579cce17b0703ca9f9716d6f99125af9569e7303f51ea7f85d317f01e\n", TRUE); + + ret = fu_uefi_pcrs_setup (pcrs, &error); + g_assert_no_error (error); + g_assert_true (ret); + pcr0s = fu_uefi_pcrs_get_checksums (pcrs, 0); + g_assert_nonnull (pcr0s); + g_assert_cmpint (pcr0s->len, ==, 2); + pcrXs = fu_uefi_pcrs_get_checksums (pcrs, 999); + g_assert_nonnull (pcrXs); + g_assert_cmpint (pcrXs->len, ==, 0); +} + +static void +fu_uefi_pcrs_2_0_failure_func (void) +{ + gboolean ret; + g_autoptr(FuUefiPcrs) pcrs = fu_uefi_pcrs_new (); + g_autoptr(GError) error = NULL; + + g_setenv ("FWUPD_UEFI_TPM2_YAML_DATA", + "Something is not working properly!\n" + "999:hello\n" + "0:dave\n" + "\n", TRUE); + + ret = fu_uefi_pcrs_setup (pcrs, &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED); + g_assert_false (ret); +} + +static void fu_uefi_ucs2_func (void) { g_autofree guint16 *str1 = NULL; @@ -85,11 +150,13 @@ { g_autofree gchar *fn = NULL; g_autoptr(FuUefiDevice) dev = NULL; + g_autoptr(GError) error = NULL; fn = fu_test_get_filename (TESTDATADIR, "efi/esrt/entries/entry0"); g_assert (fn != NULL); - dev = fu_uefi_device_new_from_entry (fn); + dev = fu_uefi_device_new_from_entry (fn, &error); g_assert_nonnull (dev); + g_assert_no_error (error); g_assert_cmpint (fu_uefi_device_get_kind (dev), ==, FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE); g_assert_cmpstr (fu_uefi_device_get_guid (dev), ==, "ddc0ee61-e7f0-4e7d-acc5-c070a398838e"); @@ -184,7 +251,12 @@ devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); for (guint i = 0; i < entries->len; i++) { const gchar *path = g_ptr_array_index (entries, i); - g_autoptr(FuUefiDevice) dev_tmp = fu_uefi_device_new_from_entry (path); + g_autoptr(GError) error_local = NULL; + g_autoptr(FuUefiDevice) dev_tmp = fu_uefi_device_new_from_entry (path, &error_local); + if (dev_tmp == NULL) { + g_debug ("failed to add %s: %s", path, error_local->message); + continue; + } g_ptr_array_add (devices, g_object_ref (dev_tmp)); } g_assert_cmpint (devices->len, ==, 2); @@ -220,7 +292,8 @@ fn = fu_test_get_filename (TESTDATADIR, "efi/esrt/entries/entry0"); g_assert (fn != NULL); - dev = fu_uefi_device_new_from_entry (fn); + dev = fu_uefi_device_new_from_entry (fn, &error); + g_assert_no_error (error); g_assert_nonnull (dev); g_assert_cmpint (fu_uefi_device_get_kind (dev), ==, FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE); g_assert_cmpstr (fu_uefi_device_get_guid (dev), ==, "ddc0ee61-e7f0-4e7d-acc5-c070a398838e"); @@ -242,11 +315,15 @@ g_test_init (&argc, &argv, NULL); g_setenv ("FWUPD_SYSFSFWDIR", TESTDATADIR, TRUE); g_setenv ("FWUPD_SYSFSDRIVERDIR", TESTDATADIR, TRUE); + g_setenv ("FWUPD_SYSFSTPMDIR", TESTDATADIR, TRUE); /* only critical and error are fatal */ g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); /* tests go here */ + g_test_add_func ("/uefi/pcrs1.2", fu_uefi_pcrs_1_2_func); + g_test_add_func ("/uefi/pcrs2.0", fu_uefi_pcrs_2_0_func); + g_test_add_func ("/uefi/pcrs2.0{failure}", fu_uefi_pcrs_2_0_failure_func); g_test_add_func ("/uefi/ucs2", fu_uefi_ucs2_func); g_test_add_func ("/uefi/variable", fu_uefi_vars_func); g_test_add_func ("/uefi/bgrt", fu_uefi_bgrt_func); diff -Nru fwupd-1.1.4/plugins/uefi/fu-ucs2.h fwupd-1.2.5/plugins/uefi/fu-ucs2.h --- fwupd-1.1.4/plugins/uefi/fu-ucs2.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/fu-ucs2.h 2019-02-25 09:42:18.000000000 +0000 @@ -5,8 +5,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_UCS2_H -#define __FU_UCS2_H +#pragma once #include @@ -16,5 +15,3 @@ gssize max); gchar *fu_ucs2_to_uft8 (const guint16 *str, gssize max); - -#endif /* __FU_UCS2_H */ diff -Nru fwupd-1.1.4/plugins/uefi/fu-uefi-bgrt.c fwupd-1.2.5/plugins/uefi/fu-uefi-bgrt.c --- fwupd-1.1.4/plugins/uefi/fu-uefi-bgrt.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/fu-uefi-bgrt.c 2019-02-25 09:42:18.000000000 +0000 @@ -24,7 +24,6 @@ fu_uefi_bgrt_setup (FuUefiBgrt *self, GError **error) { gsize sz = 0; - guint64 status; guint64 type; guint64 version; g_autofree gchar *bgrtdir = NULL; @@ -43,14 +42,6 @@ "BGRT is not supported"); return FALSE; } - status = fu_uefi_read_file_as_uint64 (bgrtdir, "status"); - if (status != 1) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "BGRT status was %" G_GUINT64_FORMAT, status); - return FALSE; - } type = fu_uefi_read_file_as_uint64 (bgrtdir, "type"); if (type != 0) { g_set_error (error, diff -Nru fwupd-1.1.4/plugins/uefi/fu-uefi-bgrt.h fwupd-1.2.5/plugins/uefi/fu-uefi-bgrt.h --- fwupd-1.1.4/plugins/uefi/fu-uefi-bgrt.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/fu-uefi-bgrt.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_UEFI_BGRT_H -#define __FU_UEFI_BGRT_H +#pragma once G_BEGIN_DECLS @@ -22,5 +21,3 @@ guint32 fu_uefi_bgrt_get_height (FuUefiBgrt *self); G_END_DECLS - -#endif /* __FU_UEFI_BGRT_H */ diff -Nru fwupd-1.1.4/plugins/uefi/fu-uefi-bootmgr.c fwupd-1.2.5/plugins/uefi/fu-uefi-bootmgr.c --- fwupd-1.1.4/plugins/uefi/fu-uefi-bootmgr.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/fu-uefi-bootmgr.c 2019-02-25 09:42:18.000000000 +0000 @@ -108,7 +108,7 @@ efidp found_dp; g_autofree guint8 *var_data_tmp = NULL; - if (efi_guid_cmp (guid, &efi_guid_global)) + if (efi_guid_cmp (guid, &efi_guid_global) != 0) continue; rc = sscanf (name, "Boot%hX%n", &entry, &scanned); if (rc < 0) { @@ -292,7 +292,10 @@ } gboolean -fu_uefi_bootmgr_bootnext (const gchar *esp_path, FuUefiBootmgrFlags flags, GError **error) +fu_uefi_bootmgr_bootnext (const gchar *esp_path, + const gchar *description, + FuUefiBootmgrFlags flags, + GError **error) { gboolean use_fwup_path = FALSE; gsize loader_sz = 0; @@ -382,7 +385,7 @@ return FALSE; } - label = g_strdup ("Linux Firmware Updater"); + label = g_strdup (description); sz = efi_loadopt_create (opt, opt_size, attributes, (efidp)dp_buf, dp_size, (guint8 *)label, diff -Nru fwupd-1.1.4/plugins/uefi/fu-uefi-bootmgr.h fwupd-1.2.5/plugins/uefi/fu-uefi-bootmgr.h --- fwupd-1.1.4/plugins/uefi/fu-uefi-bootmgr.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/fu-uefi-bootmgr.h 2019-02-25 09:42:18.000000000 +0000 @@ -5,8 +5,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_UEFI_BOOTMGR_H -#define __FU_UEFI_BOOTMGR_H +#pragma once #include #include @@ -20,9 +19,8 @@ } FuUefiBootmgrFlags; gboolean fu_uefi_bootmgr_bootnext (const gchar *esp_path, + const gchar *description, FuUefiBootmgrFlags flags, GError **error); G_END_DECLS - -#endif /* __FU_UEFI_BOOTMGR_H */ diff -Nru fwupd-1.1.4/plugins/uefi/fu-uefi-common.c fwupd-1.2.5/plugins/uefi/fu-uefi-common.c --- fwupd-1.1.4/plugins/uefi/fu-uefi-common.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/fu-uefi-common.c 2019-02-25 09:42:18.000000000 +0000 @@ -376,17 +376,14 @@ fu_uefi_prefix_efi_errors (GError **error) { g_autoptr(GString) str = g_string_new (NULL); - gint rc = 1; - for (gint i = 0; rc > 0; i++) { + for (gint i = 0; ; i++) { gchar *filename = NULL; gchar *function = NULL; gchar *message = NULL; gint line = 0; gint err = 0; - - rc = efi_error_get (i, &filename, &function, &line, - &message, &err); - if (rc <= 0) + if (efi_error_get (i, &filename, &function, &line, + &message, &err) <= 0) break; g_string_append_printf (str, "{error #%d} %s:%d %s(): %s: %s\t", i, filename, line, function, diff -Nru fwupd-1.1.4/plugins/uefi/fu-uefi-common.h fwupd-1.2.5/plugins/uefi/fu-uefi-common.h --- fwupd-1.1.4/plugins/uefi/fu-uefi-common.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/fu-uefi-common.h 2019-02-25 09:42:18.000000000 +0000 @@ -5,8 +5,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_UEFI_COMMON_H -#define __FU_UEFI_COMMON_H +#pragma once #include #include @@ -87,5 +86,3 @@ gboolean fu_uefi_prefix_efi_errors (GError **error); G_END_DECLS - -#endif /* __FU_UEFI_COMMON_H */ diff -Nru fwupd-1.1.4/plugins/uefi/fu-uefi-device.c fwupd-1.2.5/plugins/uefi/fu-uefi-device.c --- fwupd-1.1.4/plugins/uefi/fu-uefi-device.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/fu-uefi-device.c 2019-02-25 09:42:18.000000000 +0000 @@ -16,6 +16,7 @@ #include "fu-uefi-common.h" #include "fu-uefi-device.h" #include "fu-uefi-bootmgr.h" +#include "fu-uefi-pcrs.h" #include "fu-uefi-vars.h" struct _FuUefiDevice { @@ -28,6 +29,7 @@ FuUefiDeviceStatus last_attempt_status; guint32 last_attempt_version; guint64 fmp_hardware_instance; + gboolean missing_header; }; G_DEFINE_TYPE (FuUefiDevice, fu_uefi_device, FU_TYPE_DEVICE) @@ -289,16 +291,75 @@ return g_steal_pointer (&dp_buf); } +static GBytes * +fu_uefi_device_fixup_firmware (FuDevice *device, GBytes *fw, GError **error) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (device); + gsize fw_length; + efi_guid_t esrt_guid; + efi_guid_t payload_guid; + const gchar *data = g_bytes_get_data (fw, &fw_length); + self->missing_header = FALSE; + + /* convert to EFI GUIDs */ + if (efi_str_to_guid (fu_uefi_device_get_guid (self), &esrt_guid) < 0) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Invalid ESRT GUID"); + return NULL; + } + if (fw_length < sizeof(efi_guid_t)) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, + "Invalid payload"); + return NULL; + } + memcpy (&payload_guid, data, sizeof(efi_guid_t)); + + /* ESRT header matches payload */ + if (efi_guid_cmp (&esrt_guid, &payload_guid) == 0) { + g_debug ("ESRT matches payload GUID"); + return g_bytes_new_from_bytes (fw, 0, fw_length); + /* FMP payload */ + } else if (fu_uefi_device_get_kind (self) == FU_UEFI_DEVICE_KIND_FMP) { + g_debug ("performing FMP update"); + return g_bytes_new_from_bytes (fw, 0, fw_length); + /* Missing, add a header */ + } else { + guint header_size = getpagesize(); + guint8 *new_data = g_malloc (fw_length + header_size); + guint8 *capsule = new_data + header_size; + efi_capsule_header_t *header = (efi_capsule_header_t *) new_data; + + g_warning ("missing or invalid embedded capsule header"); + self->missing_header = TRUE; + header->flags = self->capsule_flags; + header->header_size = header_size; + header->capsule_image_size = fw_length + header_size; + memcpy (&header->guid, &esrt_guid, sizeof (efi_guid_t)); + memcpy (capsule, data, fw_length); + + return g_bytes_new_take (new_data, fw_length + header_size); + } +} + +gboolean +fu_uefi_missing_capsule_header (FuDevice *device) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (device); + return self->missing_header; +} + static gboolean fu_uefi_device_write_firmware (FuDevice *device, GBytes *fw, GError **error) { FuUefiDevice *self = FU_UEFI_DEVICE (device); FuUefiBootmgrFlags flags = FU_UEFI_BOOTMGR_FLAG_NONE; + const gchar *bootmgr_desc = "Linux Firmware Updater"; const gchar *esp_path = fu_device_get_metadata (device, "EspPath"); efi_guid_t guid; efi_update_info_t info; gsize datasz = 0; gsize dp_bufsz = 0; + g_autoptr(GBytes) fixed_fw = NULL; g_autofree gchar *basename = NULL; g_autofree gchar *directory = NULL; g_autofree gchar *fn = NULL; @@ -320,7 +381,10 @@ fn = g_build_filename (directory, "fw", basename, NULL); if (!fu_common_mkdir_parent (fn, error)) return FALSE; - if (!fu_common_set_contents_bytes (fn, fw, error)) + fixed_fw = fu_uefi_device_fixup_firmware (device, fw, error); + if (fixed_fw == NULL) + return FALSE; + if (!fu_common_set_contents_bytes (fn, fixed_fw, error)) return FALSE; /* set the blob header shared with fwupd.efi */ @@ -360,13 +424,116 @@ /* update the firmware before the bootloader runs */ if (fu_device_get_metadata_boolean (device, "RequireShimForSecureBoot")) flags |= FU_UEFI_BOOTMGR_FLAG_USE_SHIM_FOR_SB; - if (!fu_uefi_bootmgr_bootnext (esp_path, flags, error)) + + /* some legacy devices use the old name to deduplicate boot entries */ + if (fu_device_has_custom_flag (device, "use-legacy-bootmgr-desc")) + bootmgr_desc = "Linux-Firmware-Updater"; + if (!fu_uefi_bootmgr_bootnext (esp_path, bootmgr_desc, flags, error)) return FALSE; /* success! */ return TRUE; } +static gboolean +fu_uefi_device_add_system_checksum (FuDevice *device, GError **error) +{ + g_autoptr(FuUefiPcrs) pcrs = fu_uefi_pcrs_new (); + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) pcr0s = NULL; + + /* get all the PCRs */ + if (!fu_uefi_pcrs_setup (pcrs, &error_local)) { + if (g_error_matches (error_local, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED)) { + g_debug ("%s", error_local->message); + return TRUE; + } + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } + + /* get all the PCR0s */ + pcr0s = fu_uefi_pcrs_get_checksums (pcrs, 0); + if (pcr0s->len == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no PCR0s detected"); + return FALSE; + } + for (guint i = 0; i < pcr0s->len; i++) { + const gchar *checksum = g_ptr_array_index (pcr0s, i); + fu_device_add_checksum (device, checksum); + } + + /* success */ + return TRUE; +} + +static gboolean +fu_uefi_device_probe (FuDevice *device, GError **error) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (device); + FuVersionFormat version_format; + g_autofree gchar *devid = NULL; + g_autofree gchar *guid_strup = NULL; + g_autofree gchar *version_lowest = NULL; + g_autofree gchar *version = NULL; + + /* broken sysfs? */ + if (self->fw_class == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to read fw_class"); + return FALSE; + } + + /* add GUID first, as quirks may set the version format */ + fu_device_add_guid (device, self->fw_class); + + /* set versions */ + version_format = fu_device_get_version_format (device); + version = fu_common_version_from_uint32 (self->fw_version, version_format); + fu_device_set_version (device, version); + if (self->fw_version_lowest != 0) { + version_lowest = fu_common_version_from_uint32 (self->fw_version_lowest, + version_format); + fu_device_set_version_lowest (device, version_lowest); + } + + /* set flags */ + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_REQUIRE_AC); + + /* add icons */ + if (self->kind == FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE) { + /* nothing better in the icon naming spec */ + fu_device_add_icon (device, "audio-card"); + } else { + /* this is probably system firmware */ + fu_device_add_icon (device, "computer"); + fu_device_add_instance_id (device, "main-system-firmware"); + } + + /* set the PCR0 as the device checksum */ + if (self->kind == FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE) { + g_autoptr(GError) error_local = NULL; + if (!fu_uefi_device_add_system_checksum (device, &error_local)) + g_warning ("Failed to get PCR0s: %s", error_local->message); + } + + /* Windows seems to be case insensitive, but for convenience we'll + * match the upper case values typically specified in the .inf file */ + guid_strup = g_ascii_strup (self->fw_class, -1); + devid = g_strdup_printf ("UEFI\\RES_{%s}", guid_strup); + fu_device_add_instance_id (device, devid); + return TRUE; +} + static void fu_uefi_device_init (FuUefiDevice *self) { @@ -389,30 +556,14 @@ FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); object_class->finalize = fu_uefi_device_finalize; klass_device->to_string = fu_uefi_device_to_string; + klass_device->probe = fu_uefi_device_probe; klass_device->write_firmware = fu_uefi_device_write_firmware; } -static void -fu_uefi_device_add_win10_guid (FuUefiDevice *self) -{ - g_autofree gchar *guid_devid = NULL; - g_autofree gchar *guid_strup = NULL; - - /* broken sysfs? */ - if (self->fw_class == NULL) - return; - - /* windows seems to be case insensitive, but for convenience we'll - * match the upper case values typically specified in the .inf file */ - guid_strup = g_ascii_strup (self->fw_class, -1); - guid_devid = g_strdup_printf ("UEFI\\RES_{%s}", guid_strup); - fu_device_add_guid (FU_DEVICE (self), guid_devid); -} - FuUefiDevice * -fu_uefi_device_new_from_entry (const gchar *entry_path) +fu_uefi_device_new_from_entry (const gchar *entry_path, GError **error) { - FuUefiDevice *self; + g_autoptr(FuUefiDevice) self = NULL; g_autofree gchar *fw_class_fn = NULL; g_autofree gchar *id = NULL; @@ -423,10 +574,8 @@ /* read values from sysfs */ fw_class_fn = g_build_filename (entry_path, "fw_class", NULL); - if (g_file_get_contents (fw_class_fn, &self->fw_class, NULL, NULL)) { + if (g_file_get_contents (fw_class_fn, &self->fw_class, NULL, NULL)) g_strdelimit (self->fw_class, "\n", '\0'); - fu_device_add_guid (FU_DEVICE (self), self->fw_class); - } self->capsule_flags = fu_uefi_read_file_as_uint64 (entry_path, "capsule_flags"); self->kind = fu_uefi_read_file_as_uint64 (entry_path, "fw_type"); self->fw_version = fu_uefi_read_file_as_uint64 (entry_path, "fw_version"); @@ -444,10 +593,16 @@ self->fw_class, self->fmp_hardware_instance); fu_device_set_id (FU_DEVICE (self), id); - /* this is the DeviceID used in Windows 10 */ - fu_uefi_device_add_win10_guid (self); + /* this is invalid */ + if (!fwupd_guid_is_valid (self->fw_class)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "ESRT GUID '%s' was not valid", self->fw_class); + return NULL; + } - return self; + return g_steal_pointer (&self); } FuUefiDevice * @@ -464,12 +619,9 @@ self->fw_class = g_strdup (fu_device_get_guid_default (dev)); tmp = fu_device_get_metadata (dev, FU_DEVICE_METADATA_UEFI_DEVICE_KIND); self->kind = fu_uefi_device_kind_from_string (tmp); - self->capsule_flags = 0; /* FIXME? */ - self->fw_version = 0; /* FIXME? */ + self->capsule_flags = fu_device_get_metadata_integer (dev, FU_DEVICE_METADATA_UEFI_CAPSULE_FLAGS); + self->fw_version = fu_device_get_metadata_integer (dev, FU_DEVICE_METADATA_UEFI_FW_VERSION); g_assert (self->fw_class != NULL); - - /* this is the DeviceID used in Windows 10 */ - fu_uefi_device_add_win10_guid (self); return self; } diff -Nru fwupd-1.1.4/plugins/uefi/fu-uefi-device.h fwupd-1.2.5/plugins/uefi/fu-uefi-device.h --- fwupd-1.1.4/plugins/uefi/fu-uefi-device.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/fu-uefi-device.h 2019-02-25 09:42:18.000000000 +0000 @@ -5,8 +5,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_UEFI_DEVICE_H -#define __FU_UEFI_DEVICE_H +#pragma once #include "fu-plugin.h" #include "fu-uefi-device.h" @@ -40,7 +39,8 @@ } FuUefiDeviceStatus; FuUefiDevice *fu_uefi_device_new_from_guid (const gchar *guid); -FuUefiDevice *fu_uefi_device_new_from_entry (const gchar *entry_path); +FuUefiDevice *fu_uefi_device_new_from_entry (const gchar *entry_path, + GError **error); FuUefiDevice *fu_uefi_device_new_from_dev (FuDevice *dev); gboolean fu_uefi_device_clear_status (FuUefiDevice *self, GError **error); @@ -56,7 +56,6 @@ const gchar *fu_uefi_device_status_to_string (FuUefiDeviceStatus status); FuUefiUpdateInfo *fu_uefi_device_load_update_info (FuUefiDevice *self, GError **error); +gboolean fu_uefi_missing_capsule_header (FuDevice *device); G_END_DECLS - -#endif /* __FU_UEFI_DEVICE_H */ diff -Nru fwupd-1.1.4/plugins/uefi/fu-uefi-pcrs.c fwupd-1.2.5/plugins/uefi/fu-uefi-pcrs.c --- fwupd-1.1.4/plugins/uefi/fu-uefi-pcrs.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/fu-uefi-pcrs.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" +#include "fu-uefi-pcrs.h" + +typedef struct { + guint idx; + gchar *checksum; +} FuUefiPcrItem; + +struct _FuUefiPcrs { + GObject parent_instance; + GPtrArray *items; /* of FuUefiPcrItem */ +}; + +G_DEFINE_TYPE (FuUefiPcrs, fu_uefi_pcrs, G_TYPE_OBJECT) + +static void +fu_uefi_pcrs_parse_line (const gchar *line, gpointer user_data) +{ + FuUefiPcrs *self = FU_UEFI_PCRS (user_data); + FuUefiPcrItem *item; + guint64 idx; + g_autofree gchar *idxstr = NULL; + g_auto(GStrv) split = NULL; + g_autoptr(GString) str = NULL; + + /* split into index:hash */ + if (line == NULL || line[0] == '\0') + return; + split = g_strsplit (line, ":", 2); + if (g_strv_length (split) != 2) { + g_debug ("unexpected format, skipping: %s", line); + return; + } + + /* get index */ + idxstr = fu_common_strstrip (split[0]); + idx = fu_common_strtoull (idxstr); + if (idx > 64) { + g_debug ("unexpected index, skipping: %s", idxstr); + return; + } + + /* parse hash */ + str = g_string_new (split[1]); + if (str->len < 16) + return; + fu_common_string_replace (str, " ", ""); + g_string_ascii_down (str); + item = g_new0 (FuUefiPcrItem, 1); + item->idx = idx; + item->checksum = g_string_free (g_steal_pointer (&str), FALSE); + g_ptr_array_add (self->items, item); + g_debug ("added PCR-%02u=%s", item->idx, item->checksum); +} + +static gboolean +fu_uefi_pcrs_setup_dummy (FuUefiPcrs *self, const gchar *test_yaml, GError **error) +{ + g_auto(GStrv) lines = g_strsplit (test_yaml, "\n", -1); + for (guint i = 0; lines[i] != NULL; i++) + fu_uefi_pcrs_parse_line (lines[i], self); + return TRUE; +} + +static gboolean +fu_uefi_pcrs_setup_tpm12 (FuUefiPcrs *self, const gchar *fn_pcrs, GError **error) +{ + g_auto(GStrv) lines = NULL; + g_autofree gchar *buf_pcrs = NULL; + + /* get entire contents */ + if (!g_file_get_contents (fn_pcrs, &buf_pcrs, NULL, error)) + return FALSE; + + /* find PCR lines */ + lines = g_strsplit (buf_pcrs, "\n", -1); + for (guint i = 0; lines[i] != NULL; i++) { + if (g_str_has_prefix (lines[i], "PCR-")) + fu_uefi_pcrs_parse_line (lines[i] + 4, self); + } + return TRUE; +} + +static gboolean +fu_uefi_pcrs_setup_tpm20 (FuUefiPcrs *self, const gchar *argv0, GError **error) +{ + const gchar *argv[] = { argv0, NULL }; + return fu_common_spawn_sync (argv, fu_uefi_pcrs_parse_line, self, NULL, error); +} + +gboolean +fu_uefi_pcrs_setup (FuUefiPcrs *self, GError **error) +{ + g_autofree gchar *devpath = NULL; + g_autofree gchar *sysfstpmdir = NULL; + g_autofree gchar *fn_pcrs = NULL; + const gchar *test_yaml = g_getenv ("FWUPD_UEFI_TPM2_YAML_DATA"); + + g_return_val_if_fail (FU_IS_UEFI_PCRS (self), FALSE); + + /* check the TPM device exists at all */ + sysfstpmdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_TPM); + devpath = g_build_filename (sysfstpmdir, "tpm0", NULL); + if (!g_file_test (devpath, G_FILE_TEST_EXISTS)) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "no TPM device found"); + return FALSE; + } + fn_pcrs = g_build_filename (devpath, "pcrs", NULL); + + /* fake device */ + if (test_yaml != NULL) { + if (!fu_uefi_pcrs_setup_dummy (self, test_yaml, error)) + return FALSE; + + /* look for TPM 1.2 */ + } else if (g_file_test (fn_pcrs, G_FILE_TEST_EXISTS)) { + if (!fu_uefi_pcrs_setup_tpm12 (self, fn_pcrs, error)) + return FALSE; + + /* assume TPM 2.0 */ + } else { + g_autofree gchar *argv0 = NULL; + + /* old name, then new name */ + argv0 = fu_common_find_program_in_path ("tpm2_listpcrs", NULL); + if (argv0 == NULL) + argv0 = fu_common_find_program_in_path ("tpm2_pcrlist", error); + if (argv0 == NULL) + return FALSE; + if (!fu_uefi_pcrs_setup_tpm20 (self, argv0, error)) + return FALSE; + } + + /* check we got anything */ + if (self->items->len == 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "no TPMxx measurements found"); + return FALSE; + } + + /* success */ + return TRUE; +} + +GPtrArray * +fu_uefi_pcrs_get_checksums (FuUefiPcrs *self, guint idx) +{ + g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func (g_free); + g_return_val_if_fail (FU_IS_UEFI_PCRS (self), NULL); + for (guint i = 0; i < self->items->len; i++) { + FuUefiPcrItem *item = g_ptr_array_index (self->items, i); + if (item->idx == idx) + g_ptr_array_add (array, g_strdup (item->checksum)); + } + return g_steal_pointer (&array); +} + +static void +fu_uefi_pcrs_item_free (FuUefiPcrItem *item) +{ + g_free (item->checksum); + g_free (item); +} + +static void +fu_uefi_pcrs_finalize (GObject *object) +{ + FuUefiPcrs *self = FU_UEFI_PCRS (object); + g_ptr_array_unref (self->items); + G_OBJECT_CLASS (fu_uefi_pcrs_parent_class)->finalize (object); +} + +static void +fu_uefi_pcrs_class_init (FuUefiPcrsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_uefi_pcrs_finalize; +} + +static void +fu_uefi_pcrs_init (FuUefiPcrs *self) +{ + self->items = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_uefi_pcrs_item_free); +} + +FuUefiPcrs * +fu_uefi_pcrs_new (void) +{ + FuUefiPcrs *self; + self = g_object_new (FU_TYPE_UEFI_PCRS, NULL); + return FU_UEFI_PCRS (self); +} diff -Nru fwupd-1.1.4/plugins/uefi/fu-uefi-pcrs.h fwupd-1.2.5/plugins/uefi/fu-uefi-pcrs.h --- fwupd-1.1.4/plugins/uefi/fu-uefi-pcrs.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/fu-uefi-pcrs.h 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2017 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +G_BEGIN_DECLS + +#define FU_TYPE_UEFI_PCRS (fu_uefi_pcrs_get_type ()) +G_DECLARE_FINAL_TYPE (FuUefiPcrs, fu_uefi_pcrs, FU, UEFI_PCRS, GObject) + +FuUefiPcrs *fu_uefi_pcrs_new (void); +gboolean fu_uefi_pcrs_setup (FuUefiPcrs *self, + GError **error); +GPtrArray *fu_uefi_pcrs_get_checksums (FuUefiPcrs *self, + guint idx); + +G_END_DECLS diff -Nru fwupd-1.1.4/plugins/uefi/fu-uefi-tool.c fwupd-1.2.5/plugins/uefi/fu-uefi-tool.c --- fwupd-1.1.4/plugins/uefi/fu-uefi-tool.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/fu-uefi-tool.c 2019-02-25 09:42:18.000000000 +0000 @@ -216,7 +216,13 @@ devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); for (guint i = 0; i < entries->len; i++) { const gchar *path = g_ptr_array_index (entries, i); - g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_entry (path); + g_autoptr(GError) error_parse = NULL; + g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_entry (path, &error_parse); + if (dev == NULL) { + g_warning ("failed to parse %s: %s", + path, error_parse->message); + continue; + } fu_device_set_metadata (FU_DEVICE (dev), "EspPath", esp_path); g_ptr_array_add (devices, g_object_ref (dev)); } diff -Nru fwupd-1.1.4/plugins/uefi/fu-uefi-update-info.h fwupd-1.2.5/plugins/uefi/fu-uefi-update-info.h --- fwupd-1.1.4/plugins/uefi/fu-uefi-update-info.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/fu-uefi-update-info.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_UEFI_UPDATE_INFO_H -#define __FU_UEFI_UPDATE_INFO_H +#pragma once G_BEGIN_DECLS @@ -32,5 +31,3 @@ FuUefiUpdateInfoStatus fu_uefi_update_info_get_status (FuUefiUpdateInfo *self); G_END_DECLS - -#endif /* __FU_UEFI_UPDATE_INFO_H */ diff -Nru fwupd-1.1.4/plugins/uefi/fu-uefi-vars.h fwupd-1.2.5/plugins/uefi/fu-uefi-vars.h --- fwupd-1.1.4/plugins/uefi/fu-uefi-vars.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/fu-uefi-vars.h 2019-02-25 09:42:18.000000000 +0000 @@ -5,8 +5,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_UEFI_VARS_H -#define __FU_UEFI_VARS_H +#pragma once #include @@ -47,5 +46,3 @@ GError **error); G_END_DECLS - -#endif /* __FU_UEFI_VARS_H */ diff -Nru fwupd-1.1.4/plugins/uefi/meson.build fwupd-1.2.5/plugins/uefi/meson.build --- fwupd-1.1.4/plugins/uefi/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -3,7 +3,12 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginUefi"'] cargs += '-DEFI_APP_LOCATION_BUILD="' + app.full_path() + '"' +install_data(['uefi.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + shared_module('fu_plugin_uefi', + fu_hash, sources : [ 'fu-plugin-uefi.c', 'fu-uefi-bgrt.c', @@ -11,6 +16,7 @@ 'fu-uefi-bootmgr.c', 'fu-uefi-common.c', 'fu-uefi-device.c', + 'fu-uefi-pcrs.c', 'fu-uefi-update-info.c', 'fu-uefi-vars.c', ], @@ -21,6 +27,9 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, @@ -32,6 +41,7 @@ executable( 'fwupdate', resources_src, + fu_hash, sources : [ 'fu-uefi-tool.c', 'fu-uefi-bgrt.c', @@ -39,6 +49,7 @@ 'fu-uefi-bootmgr.c', 'fu-uefi-common.c', 'fu-uefi-device.c', + 'fu-uefi-pcrs.c', 'fu-uefi-update-info.c', 'fu-uefi-vars.c', ], @@ -48,7 +59,7 @@ include_directories('../../libfwupd'), ], dependencies : [ - appstream_glib, + libxmlb, giounix, gusb, gudev, @@ -56,7 +67,6 @@ efiboot, ], link_with : [ - fwupd, libfwupdprivate, ], install : true, @@ -73,12 +83,14 @@ cargs += '-DTESTDATADIR="' + testdatadir + '"' e = executable( 'uefi-self-test', + fu_hash, sources : [ 'fu-self-test.c', 'fu-uefi-bgrt.c', 'fu-uefi-bootmgr.c', 'fu-uefi-common.c', 'fu-uefi-device.c', + 'fu-uefi-pcrs.c', 'fu-uefi-update-info.c', 'fu-uefi-vars.c', 'fu-ucs2.c', @@ -94,7 +106,6 @@ efiboot, ], link_with : [ - fwupd, libfwupdprivate, ], c_args : cargs diff -Nru fwupd-1.1.4/plugins/uefi/README.md fwupd-1.2.5/plugins/uefi/README.md --- fwupd-1.1.4/plugins/uefi/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -11,6 +11,28 @@ If you don't want or need this functionality you can use the `-Dplugin_uefi=false` option. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +EFI capsule file format. + +See https://www.uefi.org/sites/default/files/resources/UEFI%20Spec%202_6.pdf +for details. + +This plugin supports the following protocol ID: + + * org.uefi.capsule + +GUID Generation +--------------- + +These devices use the UEFI GUID as provided in the ESRT. Additionally, for the +system device the `main-system-firmware` GUID is also added. + +For compatibility with Windows 10, the plugin also adds GUIDs of the form +`UEFI\RES_{$(esrt)}`. + UEFI Unlock Support ------------------- diff -Nru fwupd-1.1.4/plugins/uefi/tests/efi/esrt/entries/entry2/capsule_flags fwupd-1.2.5/plugins/uefi/tests/efi/esrt/entries/entry2/capsule_flags --- fwupd-1.1.4/plugins/uefi/tests/efi/esrt/entries/entry2/capsule_flags 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/tests/efi/esrt/entries/entry2/capsule_flags 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1 @@ +0x8010 diff -Nru fwupd-1.1.4/plugins/uefi/tests/efi/esrt/entries/entry2/fw_class fwupd-1.2.5/plugins/uefi/tests/efi/esrt/entries/entry2/fw_class --- fwupd-1.1.4/plugins/uefi/tests/efi/esrt/entries/entry2/fw_class 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/tests/efi/esrt/entries/entry2/fw_class 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1 @@ +00000000-0000-0000-0000-000000000000 diff -Nru fwupd-1.1.4/plugins/uefi/tests/efi/esrt/entries/entry2/fw_type fwupd-1.2.5/plugins/uefi/tests/efi/esrt/entries/entry2/fw_type --- fwupd-1.1.4/plugins/uefi/tests/efi/esrt/entries/entry2/fw_type 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/tests/efi/esrt/entries/entry2/fw_type 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1 @@ +2 diff -Nru fwupd-1.1.4/plugins/uefi/tests/efi/esrt/entries/entry2/fw_version fwupd-1.2.5/plugins/uefi/tests/efi/esrt/entries/entry2/fw_version --- fwupd-1.1.4/plugins/uefi/tests/efi/esrt/entries/entry2/fw_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/tests/efi/esrt/entries/entry2/fw_version 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1 @@ +3090287969 diff -Nru fwupd-1.1.4/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_status fwupd-1.2.5/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_status --- fwupd-1.1.4/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_status 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_status 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1 @@ +0 diff -Nru fwupd-1.1.4/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_version fwupd-1.2.5/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_version --- fwupd-1.1.4/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_version 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1 @@ +0 diff -Nru fwupd-1.1.4/plugins/uefi/tests/efi/esrt/entries/entry2/lowest_supported_fw_version fwupd-1.2.5/plugins/uefi/tests/efi/esrt/entries/entry2/lowest_supported_fw_version --- fwupd-1.1.4/plugins/uefi/tests/efi/esrt/entries/entry2/lowest_supported_fw_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/tests/efi/esrt/entries/entry2/lowest_supported_fw_version 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.1.4/plugins/uefi/tests/tpm0/active fwupd-1.2.5/plugins/uefi/tests/tpm0/active --- fwupd-1.1.4/plugins/uefi/tests/tpm0/active 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/tests/tpm0/active 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.1.4/plugins/uefi/tests/tpm0/caps fwupd-1.2.5/plugins/uefi/tests/tpm0/caps --- fwupd-1.1.4/plugins/uefi/tests/tpm0/caps 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/tests/tpm0/caps 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,3 @@ +Manufacturer: 0x49465800 +TCG version: 1.2 +Firmware version: 6.40 diff -Nru fwupd-1.1.4/plugins/uefi/tests/tpm0/enabled fwupd-1.2.5/plugins/uefi/tests/tpm0/enabled --- fwupd-1.1.4/plugins/uefi/tests/tpm0/enabled 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/tests/tpm0/enabled 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.1.4/plugins/uefi/tests/tpm0/owned fwupd-1.2.5/plugins/uefi/tests/tpm0/owned --- fwupd-1.1.4/plugins/uefi/tests/tpm0/owned 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/tests/tpm0/owned 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.1.4/plugins/uefi/tests/tpm0/pcrs fwupd-1.2.5/plugins/uefi/tests/tpm0/pcrs --- fwupd-1.1.4/plugins/uefi/tests/tpm0/pcrs 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/tests/tpm0/pcrs 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,24 @@ +PCR-00: 3C 97 99 20 C9 00 99 60 09 27 D5 DA B3 81 EB 95 1E 7F C8 68 +PCR-01: CE 9F A4 B2 01 09 D8 81 14 EA 1A 6D 13 94 CD 45 5F 52 69 23 +PCR-02: 47 09 7A 9A AD C3 26 A4 93 91 26 63 A1 6F DF 53 D7 88 96 8E +PCR-03: B2 A8 3B 0E BF 2F 83 74 29 9A 5B 2B DF C3 1E A9 55 AD 72 36 +PCR-04: A4 A5 87 4C 59 94 8D 9B 93 66 0A F4 19 D8 6F F8 94 36 20 CC +PCR-05: 00 0B 58 00 89 72 EF 6C 2A AC 79 33 C4 AE 67 6B A6 EF CF 6A +PCR-06: B2 A8 3B 0E BF 2F 83 74 29 9A 5B 2B DF C3 1E A9 55 AD 72 36 +PCR-07: 0A 2A 68 15 85 0D AC B2 D1 F4 E0 C1 F4 56 D5 E2 81 08 6D EA +PCR-08: DB A7 29 4E 49 BA D7 9E 53 99 0A 6E 3A CB 52 97 B9 08 3A 66 +PCR-09: 19 F9 6F 10 83 F5 5B 50 98 26 C3 14 73 43 35 21 1F E6 39 E9 +PCR-10: 37 3D 89 9E 10 0D DD 2D 21 B5 F4 96 8D 4F DC A7 6D 1A C7 BD +PCR-11: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-12: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-13: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-14: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-15: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-16: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-17: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-18: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-19: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-20: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-21: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-22: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-23: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 diff -Nru fwupd-1.1.4/plugins/uefi/uefi.quirk fwupd-1.2.5/plugins/uefi/uefi.quirk --- fwupd-1.1.4/plugins/uefi/uefi.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/uefi/uefi.quirk 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,14 @@ +# Lenovo ThinkStation P920/P720 +[Guid=cc850e7a-6713-4fe3-8144-321a9e485ae0] +VersionFormat = intel-me +Name = Intel Management Engine + +# Lenovo ThinkStation P520/P520c +[Guid=e3af51e5-5afb-4b48-b5cb-13bf26becaab] +VersionFormat = intel-me +Name = Intel Management Engine + +# Lenovo ThinkStation P330/P330 Tiny & ThinkCentre M920X/M920q +[Guid=5b92717b-2cad-4a96-a13b-9d65781df8bf] +VersionFormat = intel-me2 +Name = Intel Management Engine diff -Nru fwupd-1.1.4/plugins/unifying/fu-plugin-unifying.c fwupd-1.2.5/plugins/unifying/fu-plugin-unifying.c --- fwupd-1.1.4/plugins/unifying/fu-plugin-unifying.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/unifying/fu-plugin-unifying.c 2019-02-25 09:42:18.000000000 +0000 @@ -88,12 +88,16 @@ /* runtime */ if (fu_device_has_custom_flag (FU_DEVICE (device), "is-receiver")) { - dev = g_object_new (FU_TYPE_UNIFYING_RUNTIME, NULL); + dev = g_object_new (FU_TYPE_UNIFYING_RUNTIME, + "version-format", FU_VERSION_FORMAT_PLAIN, + NULL); fu_device_incorporate (dev, FU_DEVICE (device)); } else { /* create device so we can run ->probe() and add UFY GUIDs */ - dev = g_object_new (FU_TYPE_UNIFYING_PERIPHERAL, NULL); + dev = g_object_new (FU_TYPE_UNIFYING_PERIPHERAL, + "version-format", FU_VERSION_FORMAT_PLAIN, + NULL); fu_device_incorporate (dev, FU_DEVICE (device)); if (!fu_device_probe (dev, error)) return FALSE; @@ -131,10 +135,14 @@ return TRUE; } if (fu_device_has_custom_flag (FU_DEVICE (device), "is-nordic")) { - dev = g_object_new (FU_TYPE_UNIFYING_BOOTLOADER_NORDIC, NULL); + dev = g_object_new (FU_TYPE_UNIFYING_BOOTLOADER_NORDIC, + "version-format", FU_VERSION_FORMAT_PLAIN, + NULL); fu_device_incorporate (dev, FU_DEVICE (device)); } else if (fu_device_has_custom_flag (FU_DEVICE (device), "is-texas")) { - dev = g_object_new (FU_TYPE_UNIFYING_BOOTLOADER_TEXAS, NULL); + dev = g_object_new (FU_TYPE_UNIFYING_BOOTLOADER_TEXAS, + "version-format", FU_VERSION_FORMAT_PLAIN, + NULL); fu_device_incorporate (dev, FU_DEVICE (device)); g_usleep (200*1000); } @@ -173,5 +181,9 @@ void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.logitech.unifying"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.logitech.unifyingsigned"); fu_plugin_add_udev_subsystem (plugin, "hidraw"); } diff -Nru fwupd-1.1.4/plugins/unifying/fu-unifying-bootloader.c fwupd-1.2.5/plugins/unifying/fu-unifying-bootloader.c --- fwupd-1.1.4/plugins/unifying/fu-unifying-bootloader.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/unifying/fu-unifying-bootloader.c 2019-02-25 09:42:18.000000000 +0000 @@ -299,7 +299,10 @@ memcpy (buf_request + 0x04, req->data, 28); /* send request */ - fu_unifying_dump_raw ("host->device", buf_request, sizeof (buf_request)); + if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) { + fu_common_dump_raw (G_LOG_DOMAIN, "host->device", + buf_request, sizeof (buf_request)); + } if (usb_device != NULL) { if (!g_usb_device_control_transfer (usb_device, G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, @@ -332,7 +335,10 @@ &error_ignore)) { g_debug ("ignoring: %s", error_ignore->message); } else { - fu_unifying_dump_raw ("device->host", buf_response, actual_length); + if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) { + fu_common_dump_raw (G_LOG_DOMAIN, "device->host", + buf_response, actual_length); + } } return TRUE; } @@ -365,7 +371,10 @@ } actual_length = sizeof (buf_response); } - fu_unifying_dump_raw ("device->host", buf_response, actual_length); + if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) { + fu_common_dump_raw (G_LOG_DOMAIN, "device->host", + buf_response, actual_length); + } /* parse response */ if ((buf_response[0x00] & 0xf0) != req->cmd) { diff -Nru fwupd-1.1.4/plugins/unifying/fu-unifying-bootloader.h fwupd-1.2.5/plugins/unifying/fu-unifying-bootloader.h --- fwupd-1.1.4/plugins/unifying/fu-unifying-bootloader.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/unifying/fu-unifying-bootloader.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_UNIFYING_BOOTLOADER_H -#define __FU_UNIFYING_BOOTLOADER_H +#pragma once #include "fu-usb-device.h" @@ -79,5 +78,3 @@ guint16 fu_unifying_bootloader_get_blocksize (FuUnifyingBootloader *self); G_END_DECLS - -#endif /* __FU_UNIFYING_BOOTLOADER_H */ diff -Nru fwupd-1.1.4/plugins/unifying/fu-unifying-bootloader-nordic.h fwupd-1.2.5/plugins/unifying/fu-unifying-bootloader-nordic.h --- fwupd-1.1.4/plugins/unifying/fu-unifying-bootloader-nordic.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/unifying/fu-unifying-bootloader-nordic.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_UNIFYING_BOOTLOADER_NORDIC_H -#define __FU_UNIFYING_BOOTLOADER_NORDIC_H +#pragma once #include "fu-unifying-bootloader.h" @@ -15,5 +14,3 @@ G_DECLARE_FINAL_TYPE (FuUnifyingBootloaderNordic, fu_unifying_bootloader_nordic, FU, UNIFYING_BOOTLOADER_NORDIC, FuUnifyingBootloader) G_END_DECLS - -#endif /* __FU_UNIFYING_BOOTLOADER_NORDIC_H */ diff -Nru fwupd-1.1.4/plugins/unifying/fu-unifying-bootloader-texas.h fwupd-1.2.5/plugins/unifying/fu-unifying-bootloader-texas.h --- fwupd-1.1.4/plugins/unifying/fu-unifying-bootloader-texas.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/unifying/fu-unifying-bootloader-texas.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_UNIFYING_BOOTLOADER_TEXAS_H -#define __FU_UNIFYING_BOOTLOADER_TEXAS_H +#pragma once #include "fu-unifying-bootloader.h" @@ -15,5 +14,3 @@ G_DECLARE_FINAL_TYPE (FuUnifyingBootloaderTexas, fu_unifying_bootloader_texas, FU, UNIFYING_BOOTLOADER_TEXAS, FuUnifyingBootloader) G_END_DECLS - -#endif /* __FU_UNIFYING_BOOTLOADER_TEXAS_H */ diff -Nru fwupd-1.1.4/plugins/unifying/fu-unifying-common.c fwupd-1.2.5/plugins/unifying/fu-unifying-common.c --- fwupd-1.1.4/plugins/unifying/fu-unifying-common.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/unifying/fu-unifying-common.c 2019-02-25 09:42:18.000000000 +0000 @@ -33,26 +33,6 @@ return tmp; } -void -fu_unifying_dump_raw (const gchar *title, const guint8 *data, gsize len) -{ - g_autoptr(GString) str = g_string_new (NULL); - if (len == 0) - return; - if (g_getenv ("FWUPD_UNIFYING_VERBOSE") == NULL) - return; - - g_string_append_printf (str, "%s:", title); - for (gsize i = strlen (title); i < 16; i++) - g_string_append (str, " "); - for (gsize i = 0; i < len; i++) { - g_string_append_printf (str, "%02x ", data[i]); - if (i > 0 && i % 32 == 0) - g_string_append (str, "\n"); - } - g_debug ("%s", str->str); -} - gchar * fu_unifying_format_version (const gchar *name, guint8 major, guint8 minor, guint16 build) { @@ -65,152 +45,3 @@ g_string_append_printf (str, "%02x.%02x_B%04x", major, minor, build); return g_string_free (str, FALSE); } - -static gboolean -fu_unifying_nonblock_flush (gint fd, GError **error) -{ - GPollFD poll[] = { - { - .fd = fd, - .events = G_IO_IN | G_IO_OUT | G_IO_ERR, - }, - }; - while (g_poll (poll, G_N_ELEMENTS(poll), 0) > 0) { - gchar c; - gint r = read (fd, &c, 1); - if (r < 0 && errno != EINTR) - break; - } - return TRUE; -} - -gboolean -fu_unifying_nonblock_write (gint fd, - const guint8 *data, - gsize data_sz, - GError **error) -{ - gssize wrote; - - /* sanity check */ - if (fd == 0) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to write: fd is not open"); - return FALSE; - } - - /* flush pending reads */ - if (!fu_unifying_nonblock_flush (fd, error)) - return FALSE; - - /* write */ - wrote = write (fd, data, data_sz); - if (wrote != (gssize) data_sz) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to write: " - "wrote %" G_GSSIZE_FORMAT " of %" G_GSIZE_FORMAT, - wrote, data_sz); - return FALSE; - } - return TRUE; -} - -gboolean -fu_unifying_nonblock_read (gint fd, - guint8 *data, - gsize data_sz, - gsize *data_len, - guint timeout, - GError **error) -{ - gssize len = 0; - gint64 ts_start; - GPollFD poll[] = { - { - .fd = fd, - .events = G_IO_IN | G_IO_OUT | G_IO_ERR, - }, - }; - - /* sanity check */ - if (fd == 0) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to read: fd is not open"); - return FALSE; - } - - /* do a read with a timeout */ - ts_start = g_get_monotonic_time (); - while (1) { - gint rc; - gint ts_remain = ((g_get_monotonic_time () - ts_start) / 1000) + timeout; - if (ts_remain <= 0) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_TIMED_OUT, - "timeout already passed"); - return FALSE; - } - - /* waits for the fd to become ready */ - rc = g_poll (poll, G_N_ELEMENTS (poll), ts_remain); - if (rc < 0) { - if (errno == EINTR) - continue; - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "read interrupted: %s", - g_strerror (errno)); - return FALSE; - } else if (rc == 0) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_TIMED_OUT, - "timeout"); - return FALSE; - } - - /* read data from fd */ - len = read (fd, data, data_sz); - if (len <= 0) { - if (len == -1 && errno == EINTR) - continue; - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to read data: %s", - g_strerror (errno)); - return FALSE; - } - - /* success */ - break; - }; - - /* success */ - if (data_len != NULL) - *data_len = (gsize) len; - return TRUE; -} - -gint -fu_unifying_nonblock_open (const gchar *filename, GError **error) -{ - gint fd; - fd = open (filename, O_RDWR | O_NONBLOCK); - if (fd < 0) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to open %s", filename); - return -1; - } - return fd; -} diff -Nru fwupd-1.1.4/plugins/unifying/fu-unifying-common.h fwupd-1.2.5/plugins/unifying/fu-unifying-common.h --- fwupd-1.1.4/plugins/unifying/fu-unifying-common.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/unifying/fu-unifying-common.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_UNIFYING_COMMON_H -#define __FU_UNIFYING_COMMON_H +#pragma once #include @@ -22,10 +21,6 @@ /* Signed firmware are very long to verify on the device */ #define FU_UNIFYING_DEVICE_TIMEOUT_MS 20000 -void fu_unifying_dump_raw (const gchar *title, - const guint8 *data, - gsize len); - guint8 fu_unifying_buffer_read_uint8 (const gchar *str); guint16 fu_unifying_buffer_read_uint16 (const gchar *str); @@ -34,19 +29,4 @@ guint8 minor, guint16 build); -gint fu_unifying_nonblock_open (const gchar *filename, - GError **error); -gboolean fu_unifying_nonblock_read (gint fd, - guint8 *data, - gsize data_sz, - gsize *data_len, - guint timeout, - GError **error); -gboolean fu_unifying_nonblock_write (gint fd, - const guint8 *data, - gsize data_sz, - GError **error); - G_END_DECLS - -#endif /* __FU_UNIFYING_COMMON_H */ diff -Nru fwupd-1.1.4/plugins/unifying/fu-unifying-hidpp.c fwupd-1.2.5/plugins/unifying/fu-unifying-hidpp.c --- fwupd-1.1.4/plugins/unifying/fu-unifying-hidpp.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/unifying/fu-unifying-hidpp.c 2019-02-25 09:42:18.000000000 +0000 @@ -6,6 +6,7 @@ #include "config.h" +#include "fu-common.h" #include "fu-unifying-common.h" #include "fu-unifying-hidpp.h" @@ -56,29 +57,28 @@ } gboolean -fu_unifying_hidpp_send (gint fd, +fu_unifying_hidpp_send (FuIOChannel *io_channel, FuUnifyingHidppMsg *msg, guint timeout, GError **error) { gsize len = fu_unifying_hidpp_msg_get_payload_length (msg); - g_return_val_if_fail (fd > 0, FALSE); - /* only for HID++2.0 */ if (msg->hidpp_version >= 2.f) msg->function_id |= FU_UNIFYING_HIDPP_MSG_SW_ID; - fu_unifying_dump_raw ("host->device", (guint8 *) msg, len); - /* detailed debugging */ if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) { g_autofree gchar *str = fu_unifying_hidpp_msg_to_string (msg); + fu_common_dump_raw (G_LOG_DOMAIN, "host->device", (guint8 *) msg, len); g_print ("%s", str); } /* HID */ - if (!fu_unifying_nonblock_write (fd, (guint8 *) msg, len, error)) { + if (!fu_io_channel_write_raw (io_channel, (guint8 *) msg, len, 1500, + FU_IO_CHANNEL_FLAG_FLUSH_INPUT | + FU_IO_CHANNEL_FLAG_USE_BLOCKING_IO, error)) { g_prefix_error (error, "failed to send: "); return FALSE; } @@ -88,27 +88,27 @@ } gboolean -fu_unifying_hidpp_receive (gint fd, +fu_unifying_hidpp_receive (FuIOChannel *io_channel, FuUnifyingHidppMsg *msg, guint timeout, GError **error) { gsize read_size = 0; - g_return_val_if_fail (fd > 0, FALSE); - - if (!fu_unifying_nonblock_read (fd, - (guint8 *) msg, - sizeof(FuUnifyingHidppMsg), - &read_size, - timeout, - error)) { + if (!fu_io_channel_read_raw (io_channel, + (guint8 *) msg, + sizeof(FuUnifyingHidppMsg), + &read_size, + timeout, + FU_IO_CHANNEL_FLAG_SINGLE_SHOT, + error)) { g_prefix_error (error, "failed to receive: "); return FALSE; } /* check long enough, but allow returning oversize packets */ - fu_unifying_dump_raw ("device->host", (guint8 *) msg, read_size); + if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "device->host", (guint8 *) msg, read_size); if (read_size < fu_unifying_hidpp_msg_get_payload_length (msg)) { g_set_error (error, G_IO_ERROR, @@ -130,26 +130,24 @@ } gboolean -fu_unifying_hidpp_transfer (gint fd, FuUnifyingHidppMsg *msg, GError **error) +fu_unifying_hidpp_transfer (FuIOChannel *io_channel, FuUnifyingHidppMsg *msg, GError **error) { guint timeout = FU_UNIFYING_DEVICE_TIMEOUT_MS; guint ignore_cnt = 0; g_autoptr(FuUnifyingHidppMsg) msg_tmp = fu_unifying_hidpp_msg_new (); - g_return_val_if_fail (fd > 0, FALSE); - /* increase timeout for some operations */ if (msg->flags & FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT) timeout *= 10; /* send request */ - if (!fu_unifying_hidpp_send (fd, msg, timeout, error)) + if (!fu_unifying_hidpp_send (io_channel, msg, timeout, error)) return FALSE; /* keep trying to receive until we get a valid reply */ while (1) { msg_tmp->hidpp_version = msg->hidpp_version; - if (!fu_unifying_hidpp_receive (fd, msg_tmp, timeout, error)) { + if (!fu_unifying_hidpp_receive (io_channel, msg_tmp, timeout, error)) { g_prefix_error (error, "failed to receive: "); return FALSE; } diff -Nru fwupd-1.1.4/plugins/unifying/fu-unifying-hidpp.h fwupd-1.2.5/plugins/unifying/fu-unifying-hidpp.h --- fwupd-1.1.4/plugins/unifying/fu-unifying-hidpp.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/unifying/fu-unifying-hidpp.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,11 +4,12 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_UNIFYING_HIDPP_H -#define __FU_UNIFYING_HIDPP_H +#pragma once #include +#include "fu-io-channel.h" + G_BEGIN_DECLS /* @@ -136,18 +137,16 @@ #include "fu-unifying-hidpp-msg.h" -gboolean fu_unifying_hidpp_send (gint fd, +gboolean fu_unifying_hidpp_send (FuIOChannel *self, FuUnifyingHidppMsg *msg, guint timeout, GError **error); -gboolean fu_unifying_hidpp_receive (gint fd, +gboolean fu_unifying_hidpp_receive (FuIOChannel *self, FuUnifyingHidppMsg *msg, guint timeout, GError **error); -gboolean fu_unifying_hidpp_transfer (gint fd, +gboolean fu_unifying_hidpp_transfer (FuIOChannel *self, FuUnifyingHidppMsg *msg, GError **error); G_END_DECLS - -#endif /* __FU_UNIFYING_HIDPP_H */ diff -Nru fwupd-1.1.4/plugins/unifying/fu-unifying-hidpp-msg.h fwupd-1.2.5/plugins/unifying/fu-unifying-hidpp-msg.h --- fwupd-1.1.4/plugins/unifying/fu-unifying-hidpp-msg.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/unifying/fu-unifying-hidpp-msg.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_UNIFYING_HIDPP_MSG_H -#define __FU_UNIFYING_HIDPP_MSG_H +#pragma once #include @@ -57,5 +56,3 @@ const gchar *fu_unifying_hidpp_msg_fcn_id_to_string (FuUnifyingHidppMsg *msg); G_END_DECLS - -#endif /* __FU_UNIFYING_HIDPP_MSG_H */ diff -Nru fwupd-1.1.4/plugins/unifying/fu-unifying-peripheral.c fwupd-1.2.5/plugins/unifying/fu-unifying-peripheral.c --- fwupd-1.1.4/plugins/unifying/fu-unifying-peripheral.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/unifying/fu-unifying-peripheral.c 2019-02-25 09:42:18.000000000 +0000 @@ -7,7 +7,6 @@ #include "config.h" #include -#include #include "fu-unifying-common.h" #include "fu-unifying-peripheral.h" @@ -22,7 +21,7 @@ guint8 hidpp_version; gboolean is_updatable; gboolean is_active; - gint udev_fd; + FuIOChannel *io_channel; GPtrArray *feature_index; /* of FuUnifyingHidppMap */ }; @@ -136,7 +135,7 @@ msg->data[1] = 0x00; msg->data[2] = 0xaa; /* user-selected value */ msg->hidpp_version = self->hidpp_version; - if (!fu_unifying_hidpp_transfer (self->udev_fd, msg, &error_local)) { + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, &error_local)) { if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)) { @@ -181,11 +180,9 @@ fu_unifying_peripheral_close (FuDevice *device, GError **error) { FuUnifyingPeripheral *self = FU_UNIFYING_PERIPHERAL (device); - if (self->udev_fd > 0) { - if (!g_close (self->udev_fd, error)) - return FALSE; - self->udev_fd = 0; - } + if (!fu_io_channel_shutdown (self->io_channel, error)) + return FALSE; + g_clear_object (&self->io_channel); return TRUE; } @@ -206,7 +203,7 @@ /* flush pending data */ msg->device_id = self->hidpp_id; msg->hidpp_version = self->hidpp_version; - if (!fu_unifying_hidpp_receive (self->udev_fd, msg, timeout, &error_local)) { + if (!fu_unifying_hidpp_receive (self->io_channel, msg, timeout, &error_local)) { if (!g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) { @@ -242,8 +239,8 @@ const gchar *devpath = g_udev_device_get_device_file (udev_device); /* open */ - self->udev_fd = fu_unifying_nonblock_open (devpath, error); - if (self->udev_fd < 0) + self->io_channel = fu_io_channel_new_file (devpath, error); + if (self->io_channel == NULL) return FALSE; return TRUE; @@ -255,8 +252,6 @@ FuUnifyingPeripheral *self = FU_UNIFYING_PERIPHERAL (device); g_string_append_printf (str, " HidppVersion:\t\t%u\n", self->hidpp_version); - if (self->udev_fd > 0) - g_string_append_printf (str, " UdevDevice:\t\t%i\n", self->udev_fd); if (self->hidpp_id != HIDPP_DEVICE_ID_UNSET) g_string_append_printf (str, " HidppId:\t\t0x%02x\n", (guint) self->hidpp_id); if (self->battery_level != 0) @@ -301,7 +296,7 @@ msg->sub_id = idx; msg->function_id = 0x00 << 4; /* getCount */ msg->hidpp_version = self->hidpp_version; - if (!fu_unifying_hidpp_transfer (self->udev_fd, msg, error)) { + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { g_prefix_error (error, "failed to get firmware count: "); return FALSE; } @@ -319,7 +314,7 @@ msg->sub_id = idx; msg->function_id = 0x01 << 4; /* getInfo */ msg->data[0] = i; - if (!fu_unifying_hidpp_transfer (self->udev_fd, msg, error)) { + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { g_prefix_error (error, "failed to get firmware info: "); return FALSE; } @@ -371,7 +366,7 @@ msg->sub_id = idx; msg->function_id = 0x00; /* GetBatteryLevelStatus */ msg->hidpp_version = self->hidpp_version; - if (!fu_unifying_hidpp_transfer (self->udev_fd, msg, error)) { + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { g_prefix_error (error, "failed to get battery info: "); return FALSE; } @@ -389,7 +384,7 @@ msg->sub_id = HIDPP_SUBID_GET_REGISTER; msg->function_id = HIDPP_REGISTER_BATTERY_MILEAGE; msg->hidpp_version = self->hidpp_version; - if (fu_unifying_hidpp_transfer (self->udev_fd, msg, NULL)) { + if (fu_unifying_hidpp_transfer (self->io_channel, msg, NULL)) { if (msg->data[0] != 0x00) self->battery_level = msg->data[0]; return TRUE; @@ -397,7 +392,7 @@ /* try HID++1.0 battery status instead */ msg->function_id = HIDPP_REGISTER_BATTERY_STATUS; - if (fu_unifying_hidpp_transfer (self->udev_fd, msg, NULL)) { + if (fu_unifying_hidpp_transfer (self->io_channel, msg, NULL)) { switch (msg->data[0]) { case 1: /* 0 - 10 */ self->battery_level = 5; @@ -440,7 +435,7 @@ msg->data[1] = feature; msg->data[2] = 0x00; msg->hidpp_version = self->hidpp_version; - if (!fu_unifying_hidpp_transfer (self->udev_fd, msg, error)) { + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { g_prefix_error (error, "failed to get idx for feature %s [0x%04x]: ", fu_unifying_hidpp_feature_to_string (feature), feature); @@ -470,7 +465,7 @@ static gboolean fu_unifying_peripheral_probe (FuUdevDevice *device, GError **error) { - g_autofree gchar *guid = NULL; + g_autofree gchar *devid = NULL; /* set the physical ID */ if (!fu_udev_device_set_physical_id (device, "hid", error)) @@ -480,10 +475,10 @@ fu_device_set_vendor_id (FU_DEVICE (device), "USB:0x046D"); /* this is a non-standard extension */ - guid = g_strdup_printf ("UFY\\VID_%04X&PID_%04X", - fu_udev_device_get_vendor (device), - fu_udev_device_get_model (device)); - fu_device_add_guid (FU_DEVICE (device), guid); + devid = g_strdup_printf ("UFY\\VID_%04X&PID_%04X", + fu_udev_device_get_vendor (device), + fu_udev_device_get_model (device)); + fu_device_add_instance_id (FU_DEVICE (device), devid); return TRUE; } @@ -551,7 +546,7 @@ msg->sub_id = idx; msg->function_id = 0x02 << 4; /* getDeviceType */ msg->hidpp_version = self->hidpp_version; - if (!fu_unifying_hidpp_transfer (self->udev_fd, msg, error)) { + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { g_prefix_error (error, "failed to get device type: "); return FALSE; } @@ -578,7 +573,7 @@ msg->sub_id = idx; msg->function_id = 0x00 << 4; /* getDfuStatus */ msg->hidpp_version = self->hidpp_version; - if (!fu_unifying_hidpp_transfer (self->udev_fd, msg, error)) { + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { g_prefix_error (error, "failed to get DFU status: "); return FALSE; } @@ -631,7 +626,7 @@ msg->hidpp_version = self->hidpp_version; msg->flags = FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID | FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT; - if (!fu_unifying_hidpp_transfer (self->udev_fd, msg, error)) { + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { g_prefix_error (error, "failed to put device into DFU mode: "); return FALSE; } @@ -654,7 +649,7 @@ msg->data[5] = 'F'; msg->data[6] = 'U'; msg->flags = FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID; - if (!fu_unifying_hidpp_transfer (self->udev_fd, msg, error)) { + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { g_prefix_error (error, "failed to put device into DFU mode: "); return FALSE; } @@ -833,7 +828,7 @@ msg->function_id = cmd << 4; /* dfuStart or dfuCmdDataX */ msg->hidpp_version = self->hidpp_version; memcpy (msg->data, data, 16); - if (!fu_unifying_hidpp_transfer (self->udev_fd, msg, &error_local)) { + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, &error_local)) { g_prefix_error (error, "failed to supply program data: "); return FALSE; } @@ -860,7 +855,7 @@ for (guint retry = 0; retry < 10; retry++) { g_autoptr(FuUnifyingHidppMsg) msg2 = fu_unifying_hidpp_msg_new (); msg2->flags = FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_FNCT_ID; - if (!fu_unifying_hidpp_receive (self->udev_fd, msg2, 15000, error)) + if (!fu_unifying_hidpp_receive (self->io_channel, msg2, 15000, error)) return FALSE; if (fu_unifying_hidpp_msg_is_reply (msg, msg2)) { g_autoptr(GError) error2 = NULL; @@ -956,7 +951,7 @@ msg->flags = FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID | FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SWID | // inferred? FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT; - if (!fu_unifying_hidpp_transfer (self->udev_fd, msg, error)) { + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { g_prefix_error (error, "failed to restart device: "); return FALSE; } diff -Nru fwupd-1.1.4/plugins/unifying/fu-unifying-peripheral.h fwupd-1.2.5/plugins/unifying/fu-unifying-peripheral.h --- fwupd-1.1.4/plugins/unifying/fu-unifying-peripheral.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/unifying/fu-unifying-peripheral.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_UNIFYING_PERIPHERAL_H -#define __FU_UNIFYING_PERIPHERAL_H +#pragma once #include "fu-udev-device.h" @@ -15,5 +14,3 @@ G_DECLARE_FINAL_TYPE (FuUnifyingPeripheral, fu_unifying_peripheral, FU, UNIFYING_PERIPHERAL, FuUdevDevice) G_END_DECLS - -#endif /* __FU_UNIFYING_PERIPHERAL_H */ diff -Nru fwupd-1.1.4/plugins/unifying/fu-unifying-runtime.c fwupd-1.2.5/plugins/unifying/fu-unifying-runtime.c --- fwupd-1.1.4/plugins/unifying/fu-unifying-runtime.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/unifying/fu-unifying-runtime.c 2019-02-25 09:42:18.000000000 +0000 @@ -7,7 +7,6 @@ #include "config.h" #include -#include #include "fu-unifying-common.h" #include "fu-unifying-runtime.h" @@ -18,7 +17,7 @@ FuUdevDevice parent_instance; guint8 version_bl_major; gboolean signed_firmware; - gint udev_fd; + FuIOChannel *io_channel; }; G_DEFINE_TYPE (FuUnifyingRuntime, fu_unifying_runtime, FU_TYPE_UDEV_DEVICE) @@ -31,9 +30,6 @@ fu_unifying_runtime_to_string (FuDevice *device, GString *str) { FuUnifyingRuntime *self = FU_UNIFYING_RUNTIME (device); - - if (self->udev_fd > 0) - g_string_append_printf (str, " UdevDevice:\t\t%i\n", self->udev_fd); g_string_append_printf (str, " SignedFirmware:\t%i\n", self->signed_firmware); } @@ -49,18 +45,16 @@ msg->data[1] = 0x05; /* Wireless + SoftwarePresent */ msg->data[2] = 0x00; msg->hidpp_version = 1; - return fu_unifying_hidpp_transfer (self->udev_fd, msg, error); + return fu_unifying_hidpp_transfer (self->io_channel, msg, error); } static gboolean fu_unifying_runtime_close (FuDevice *device, GError **error) { FuUnifyingRuntime *self = FU_UNIFYING_RUNTIME (device); - if (self->udev_fd > 0) { - if (!g_close (self->udev_fd, error)) - return FALSE; - self->udev_fd = 0; - } + if (!fu_io_channel_shutdown (self->io_channel, error)) + return FALSE; + g_clear_object (&self->io_channel); return TRUE; } @@ -80,7 +74,7 @@ /* is there any pending data to read */ msg->hidpp_version = 1; - if (!fu_unifying_hidpp_receive (self->udev_fd, msg, timeout, &error_local)) { + if (!fu_unifying_hidpp_receive (self->io_channel, msg, timeout, &error_local)) { if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) { @@ -126,8 +120,8 @@ const gchar *devpath = g_udev_device_get_device_file (udev_device); /* open, but don't block */ - self->udev_fd = fu_unifying_nonblock_open (devpath, error); - if (self->udev_fd < 0) + self->io_channel = fu_io_channel_new_file (devpath, error); + if (self->io_channel == NULL) return FALSE; /* poll for notifications */ @@ -208,7 +202,7 @@ msg->function_id = HIDPP_REGISTER_DEVICE_FIRMWARE_INFORMATION; msg->data[0] = i; msg->hidpp_version = 1; - if (!fu_unifying_hidpp_transfer (self->udev_fd, msg, error)) { + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { g_prefix_error (error, "failed to read device config: "); return FALSE; } @@ -286,7 +280,7 @@ msg->data[2] = 'P'; msg->hidpp_version = 1; msg->flags = FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT; - if (!fu_unifying_hidpp_send (self->udev_fd, msg, FU_UNIFYING_DEVICE_TIMEOUT_MS, error)) { + if (!fu_unifying_hidpp_send (self->io_channel, msg, FU_UNIFYING_DEVICE_TIMEOUT_MS, error)) { g_prefix_error (error, "failed to detach to bootloader: "); return FALSE; } diff -Nru fwupd-1.1.4/plugins/unifying/fu-unifying-runtime.h fwupd-1.2.5/plugins/unifying/fu-unifying-runtime.h --- fwupd-1.1.4/plugins/unifying/fu-unifying-runtime.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/unifying/fu-unifying-runtime.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_UNIFYING_DEVICE_RUNTIME_H -#define __FU_UNIFYING_DEVICE_RUNTIME_H +#pragma once #include "fu-udev-device.h" @@ -15,5 +14,3 @@ G_DECLARE_FINAL_TYPE (FuUnifyingRuntime, fu_unifying_runtime, FU, UNIFYING_RUNTIME, FuUdevDevice) G_END_DECLS - -#endif /* __FU_UNIFYING_DEVICE_RUNTIME_H */ diff -Nru fwupd-1.1.4/plugins/unifying/meson.build fwupd-1.2.5/plugins/unifying/meson.build --- fwupd-1.1.4/plugins/unifying/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/unifying/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -8,6 +8,7 @@ shared_module('fu_plugin_unifying', + fu_hash, sources : [ 'fu-plugin-unifying.c', 'fu-unifying-bootloader.c', @@ -26,6 +27,9 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, @@ -35,6 +39,7 @@ if get_option('tests') e = executable( 'unifying-self-test', + fu_hash, sources : [ 'fu-unifying-self-test.c', 'fu-unifying-common.c', @@ -47,7 +52,7 @@ plugin_deps, ], link_with : [ - fwupd, + libfwupdprivate, ], c_args : cargs, ) diff -Nru fwupd-1.1.4/plugins/unifying/README.md fwupd-1.2.5/plugins/unifying/README.md --- fwupd-1.1.4/plugins/unifying/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/unifying/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -16,6 +16,31 @@ Additional constants were taken from the Solaar[2] project. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +a vendor-specific format that appears to be a subset of the Intel HEX format. + +This plugin supports the following protocol IDs: + + * com.logitech.unifying + * com.logitech.unifyingsigned + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values when in DFU mode: + + * `USB\VID_046D&PID_AAAA&REV_0001` + * `USB\VID_046D&PID_AAAA` + * `USB\VID_046D` + +When in runtime mode, the HID raw DeviceInstanceId values are used: + + * `HIDRAW\VEN_046D&DEV_C52B` + * `HIDRAW\VEN_046D` + Design Notes ------------ diff -Nru fwupd-1.1.4/plugins/unifying/unifying.quirk fwupd-1.2.5/plugins/unifying/unifying.quirk --- fwupd-1.1.4/plugins/unifying/unifying.quirk 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/unifying/unifying.quirk 2019-02-25 09:42:18.000000000 +0000 @@ -3,6 +3,7 @@ Plugin = unifying Flags = is-receiver VendorId=USB:0x046D +InstallDuration = 7 # Nordic [DeviceInstanceId=USB\VID_046D&PID_AAAA] @@ -10,6 +11,7 @@ Flags = is-bootloader,is-nordic FirmwareSizeMin = 0x4000 CounterpartGuid = HIDRAW\VEN_046D&DEV_C52B +InstallDuration = 7 # Nordic Pico [DeviceInstanceId=USB\VID_046D&PID_AAAE] @@ -17,6 +19,7 @@ Flags = is-bootloader,is-nordic FirmwareSizeMin = 0x4000 CounterpartGuid = HIDRAW\VEN_046D&DEV_C52B +InstallDuration = 7 # Texas [DeviceInstanceId=USB\VID_046D&PID_AAAC] @@ -24,6 +27,7 @@ Flags = is-bootloader,is-texas FirmwareSizeMin = 0x4000 CounterpartGuid = HIDRAW\VEN_046D&DEV_C52B +InstallDuration = 7 # Texas Pico [DeviceInstanceId=USB\VID_046D&PID_AAAD] @@ -31,3 +35,4 @@ Flags = is-bootloader,is-texas FirmwareSizeMin = 0x4000 CounterpartGuid = HIDRAW\VEN_046D&DEV_C52B +InstallDuration = 7 diff -Nru fwupd-1.1.4/plugins/upower/fu-plugin-upower.c fwupd-1.2.5/plugins/upower/fu-plugin-upower.c --- fwupd-1.1.4/plugins/upower/fu-plugin-upower.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/upower/fu-plugin-upower.c 2019-02-25 09:42:18.000000000 +0000 @@ -8,13 +8,17 @@ #include "fu-plugin-vfuncs.h" +#define MINIMUM_BATTERY_PERCENTAGE 30 + struct FuPluginData { - GDBusProxy *proxy; + GDBusProxy *upower_proxy; + GDBusProxy *display_proxy; }; void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); } @@ -22,15 +26,17 @@ fu_plugin_destroy (FuPlugin *plugin) { FuPluginData *data = fu_plugin_get_data (plugin); - if (data->proxy != NULL) - g_object_unref (data->proxy); + if (data->upower_proxy != NULL) + g_object_unref (data->upower_proxy); + if (data->display_proxy != NULL) + g_object_unref (data->display_proxy); } gboolean fu_plugin_startup (FuPlugin *plugin, GError **error) { FuPluginData *data = fu_plugin_get_data (plugin); - data->proxy = + data->upower_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, NULL, @@ -39,31 +45,87 @@ "org.freedesktop.UPower", NULL, error); - if (data->proxy == NULL) { + if (data->upower_proxy == NULL) { g_prefix_error (error, "failed to connect to upower: "); return FALSE; } + data->display_proxy = + g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + NULL, + "org.freedesktop.UPower", + "/org/freedesktop/UPower/devices/DisplayDevice", + "org.freedesktop.UPower.Device", + NULL, + error); + if (data->display_proxy == NULL) { + g_prefix_error (error, "failed to connect to upower: "); + return FALSE; + } + return TRUE; } +static gboolean +fu_plugin_upower_check_percentage_level (FuPlugin *plugin) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + gdouble level; + guint power_type; + g_autoptr(GVariant) percentage_val = NULL; + g_autoptr(GVariant) type_val = NULL; + + /* check that we "have" a battery */ + type_val = g_dbus_proxy_get_cached_property (data->display_proxy, "Type"); + if (type_val == NULL) { + g_warning ("Failed to query power type, assume AC power"); + return TRUE; + } + power_type = g_variant_get_uint32 (type_val); + if (power_type != 2) { + g_debug ("Not running on battery (Type: %u)", power_type); + return TRUE; + } + + /* check percentage high enough */ + percentage_val = g_dbus_proxy_get_cached_property (data->display_proxy, "Percentage"); + if (percentage_val == NULL) { + g_warning ("Failed to query power percentage level, assume enough charge"); + return TRUE; + } + level = g_variant_get_double (percentage_val); + g_debug ("System power source is %.1f%%", level); + + return level >= MINIMUM_BATTERY_PERCENTAGE; +} + +static gboolean +fu_plugin_upower_check_on_battery (FuPlugin *plugin) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autoptr(GVariant) value = NULL; + + value = g_dbus_proxy_get_cached_property (data->upower_proxy, "OnBattery"); + if (value == NULL) { + g_warning ("failed to get OnBattery value, assume on AC power"); + return FALSE; + } + return g_variant_get_boolean (value); +} + gboolean fu_plugin_update_prepare (FuPlugin *plugin, FwupdInstallFlags flags, FuDevice *device, GError **error) { - FuPluginData *data = fu_plugin_get_data (plugin); - g_autoptr(GVariant) value = NULL; - - /* can we only do this on AC power */ + /* not all devices need this */ if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REQUIRE_AC)) return TRUE; - value = g_dbus_proxy_get_cached_property (data->proxy, "OnBattery"); - if (value == NULL) { - g_warning ("failed to get OnBattery value, assume on AC power"); - return TRUE; - } - if (g_variant_get_boolean (value) && (flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + + /* determine if operating on AC or battery */ + if (fu_plugin_upower_check_on_battery (plugin) && + (flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_AC_POWER_REQUIRED, @@ -71,5 +133,17 @@ "when not on AC power unless forced"); return FALSE; } + + /* deteremine if battery high enough */ + if (!fu_plugin_upower_check_percentage_level (plugin) && + (flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_AC_POWER_REQUIRED, + "Cannot install update when battery " + "is not at least %d%% unless forced", + MINIMUM_BATTERY_PERCENTAGE); + return FALSE; + } return TRUE; } diff -Nru fwupd-1.1.4/plugins/upower/meson.build fwupd-1.2.5/plugins/upower/meson.build --- fwupd-1.1.4/plugins/upower/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/upower/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -1,6 +1,7 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginUpower"'] shared_module('fu_plugin_upower', + fu_hash, sources : [ 'fu-plugin-upower.c', ], @@ -11,6 +12,9 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff -Nru fwupd-1.1.4/plugins/wacomhid/fu-plugin-wacomhid.c fwupd-1.2.5/plugins/wacomhid/fu-plugin-wacomhid.c --- fwupd-1.1.4/plugins/wacomhid/fu-plugin-wacomhid.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/wacomhid/fu-plugin-wacomhid.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include "fu-plugin-vfuncs.h" - -#include "fu-wac-device.h" - -void -fu_plugin_init (FuPlugin *plugin) -{ - fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); -} - -gboolean -fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *device, GError **error) -{ - g_autoptr(FuWacDevice) dev = NULL; - g_autoptr(FuDeviceLocker) locker = NULL; - dev = fu_wac_device_new (device); - locker = fu_device_locker_new (dev, error); - if (locker == NULL) - return FALSE; - fu_plugin_device_add (plugin, FU_DEVICE (dev)); - return TRUE; -} - -gboolean -fu_plugin_update (FuPlugin *plugin, FuDevice *device, GBytes *blob_fw, - FwupdInstallFlags flags, GError **error) -{ - FuDevice *parent = fu_device_get_parent (device); - g_autoptr(FuDeviceLocker) locker = NULL; - locker = fu_device_locker_new (parent != NULL ? parent : device, error); - if (locker == NULL) - return FALSE; - return fu_device_write_firmware (device, blob_fw, error); -} diff -Nru fwupd-1.1.4/plugins/wacomhid/fu-self-test.c fwupd-1.2.5/plugins/wacomhid/fu-self-test.c --- fwupd-1.1.4/plugins/wacomhid/fu-self-test.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/wacomhid/fu-self-test.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include -#include - -#include "fu-common.h" -#include "fu-test.h" -#include "fu-wac-common.h" -#include "fu-wac-firmware.h" - -#include "fwupd-error.h" - -static void -fu_wac_firmware_parse_func (void) -{ - DfuElement *element; - DfuImage *image; - gboolean ret; - g_autofree gchar *fn = NULL; - g_autoptr(DfuFirmware) firmware = dfu_firmware_new (); - g_autoptr(GBytes) blob_block = NULL; - g_autoptr(GBytes) bytes = NULL; - g_autoptr(GError) error = NULL; - - /* parse the test file */ - fn = fu_test_get_filename (TESTDATADIR, "test.wac"); - if (fn == NULL) { - g_test_skip ("no data file found"); - return; - } - bytes = fu_common_get_contents_bytes (fn, &error); - g_assert_no_error (error); - g_assert_nonnull (bytes); - ret = fu_wac_firmware_parse_data (firmware, bytes, - DFU_FIRMWARE_PARSE_FLAG_NONE, &error); - g_assert_no_error (error); - g_assert_true (ret); - - /* get image data */ - image = dfu_firmware_get_image (firmware, 0); - g_assert_nonnull (image); - element = dfu_image_get_element_default (image); - g_assert_nonnull (element); - - /* get block */ - blob_block = dfu_element_get_contents_chunk (element, 0x8008000, - 1024, &error); - g_assert_no_error (error); - g_assert_nonnull (blob_block); - fu_wac_buffer_dump ("IMG", FU_WAC_REPORT_ID_MODULE, - g_bytes_get_data (blob_block, NULL), - g_bytes_get_size (blob_block)); -} - -int -main (int argc, char **argv) -{ - g_test_init (&argc, &argv, NULL); - - /* only critical and error are fatal */ - g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); - - /* log everything */ - g_setenv ("G_MESSAGES_DEBUG", "all", FALSE); - - /* tests go here */ - g_test_add_func ("/wac/firmware{parse}", fu_wac_firmware_parse_func); - return g_test_run (); -} - diff -Nru fwupd-1.1.4/plugins/wacomhid/fu-wac-common.c fwupd-1.2.5/plugins/wacomhid/fu-wac-common.c --- fwupd-1.1.4/plugins/wacomhid/fu-wac-common.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/wacomhid/fu-wac-common.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include - -#include "fu-wac-common.h" - -guint32 -fu_wac_calculate_checksum32le (const guint8 *data, gsize len) -{ - guint32 csum = 0x0; - g_return_val_if_fail (len % 4 == 0, 0xff); - for (guint i = 0; i < len; i += 4) { - guint32 tmp; - memcpy (&tmp, &data[i], sizeof(guint32)); - csum += GUINT32_FROM_LE (tmp); - } - return GUINT32_TO_LE (csum); -} - -guint32 -fu_wac_calculate_checksum32le_bytes (GBytes *blob) -{ - gsize len = 0; - const guint8 *data = g_bytes_get_data (blob, &len); - return fu_wac_calculate_checksum32le (data, len); -} - -const gchar * -fu_wac_report_id_to_string (guint8 report_id) -{ - if (report_id == FU_WAC_REPORT_ID_FW_DESCRIPTOR) - return "FwDescriptor"; - if (report_id == FU_WAC_REPORT_ID_SWITCH_TO_FLASH_LOADER) - return "SwitchToFlashLoader"; - if (report_id == FU_WAC_REPORT_ID_QUIT_AND_RESET) - return "QuitAndReset"; - if (report_id == FU_WAC_REPORT_ID_READ_BLOCK_DATA) - return "ReadBlockData"; - if (report_id == FU_WAC_REPORT_ID_WRITE_BLOCK) - return "WriteBlock"; - if (report_id == FU_WAC_REPORT_ID_ERASE_BLOCK) - return "EraseBlock"; - if (report_id == FU_WAC_REPORT_ID_SET_READ_ADDRESS) - return "SetReadAddress"; - if (report_id == FU_WAC_REPORT_ID_GET_STATUS) - return "GetStatus"; - if (report_id == FU_WAC_REPORT_ID_UPDATE_RESET) - return "UpdateReset"; - if (report_id == FU_WAC_REPORT_ID_WRITE_WORD) - return "WriteWord"; - if (report_id == FU_WAC_REPORT_ID_GET_PARAMETERS) - return "GetParameters"; - if (report_id == FU_WAC_REPORT_ID_GET_FLASH_DESCRIPTOR) - return "GetFlashDescriptor"; - if (report_id == FU_WAC_REPORT_ID_GET_CHECKSUMS) - return "GetChecksums"; - if (report_id == FU_WAC_REPORT_ID_SET_CHECKSUM_FOR_BLOCK) - return "SetChecksumForBlock"; - if (report_id == FU_WAC_REPORT_ID_CALCULATE_CHECKSUM_FOR_BLOCK) - return "CalculateChecksumForBlock"; - if (report_id == FU_WAC_REPORT_ID_WRITE_CHECKSUM_TABLE) - return "WriteChecksumTable"; - if (report_id == FU_WAC_REPORT_ID_GET_CURRENT_FIRMWARE_IDX) - return "GetCurrentFirmwareIdx"; - if (report_id == FU_WAC_REPORT_ID_MODULE) - return "Module"; - return NULL; -} - -void -fu_wac_buffer_dump (const gchar *title, guint8 cmd, const guint8 *buf, gsize sz) -{ - if (g_getenv ("FWUPD_WAC_VERBOSE") == NULL) - return; - g_print ("%s %s (%" G_GSIZE_FORMAT "):\n", - title, fu_wac_report_id_to_string (cmd), sz); - for (gsize i = 0; i < sz; i++) { - g_print ("%02x ", buf[i]); - if (i > 0 && (i + 1) % 256 == 0) - g_print ("\n"); - } - g_print ("\n"); -} diff -Nru fwupd-1.1.4/plugins/wacomhid/fu-wac-common.h fwupd-1.2.5/plugins/wacomhid/fu-wac-common.h --- fwupd-1.1.4/plugins/wacomhid/fu-wac-common.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/wacomhid/fu-wac-common.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#ifndef __FU_WAC_HID_H -#define __FU_WAC_HID_H - -#include - -G_BEGIN_DECLS - -#define FU_WAC_PACKET_LEN 512 - -#define FU_WAC_REPORT_ID_COMMAND 0x01 -#define FU_WAC_REPORT_ID_STATUS 0x02 -#define FU_WAC_REPORT_ID_CONTROL 0x03 - -#define FU_WAC_REPORT_ID_GET_FIRMWARE_VERSION_MAIN 0x07 -#define FU_WAC_REPORT_ID_GET_FIRMWARE_VERSION_TOUCH 0x07 -#define FU_WAC_REPORT_ID_GET_FIRMWARE_VERSION_BLUETOOTH 0x16 - -#define FU_WAC_REPORT_ID_FW_DESCRIPTOR 0xcb /* GET_FEATURE */ -#define FU_WAC_REPORT_ID_SWITCH_TO_FLASH_LOADER 0xcc /* SET_FEATURE */ -#define FU_WAC_REPORT_ID_QUIT_AND_RESET 0xcd /* SET_FEATURE */ -#define FU_WAC_REPORT_ID_READ_BLOCK_DATA 0xd1 /* GET_FEATURE */ -#define FU_WAC_REPORT_ID_WRITE_BLOCK 0xd2 /* SET_FEATURE */ -#define FU_WAC_REPORT_ID_ERASE_BLOCK 0xd3 /* SET_FEATURE */ -#define FU_WAC_REPORT_ID_SET_READ_ADDRESS 0xd4 /* GET_FEATURE */ -#define FU_WAC_REPORT_ID_GET_STATUS 0xd5 /* GET_FEATURE */ -#define FU_WAC_REPORT_ID_UPDATE_RESET 0xd6 /* SET_FEATURE */ -#define FU_WAC_REPORT_ID_WRITE_WORD 0xd7 /* SET_FEATURE */ -#define FU_WAC_REPORT_ID_GET_PARAMETERS 0xd8 /* GET_FEATURE */ -#define FU_WAC_REPORT_ID_GET_FLASH_DESCRIPTOR 0xd9 /* GET_FEATURE */ -#define FU_WAC_REPORT_ID_GET_CHECKSUMS 0xda /* GET_FEATURE */ -#define FU_WAC_REPORT_ID_SET_CHECKSUM_FOR_BLOCK 0xdb /* SET_FEATURE */ -#define FU_WAC_REPORT_ID_CALCULATE_CHECKSUM_FOR_BLOCK 0xdc /* SET_FEATURE */ -#define FU_WAC_REPORT_ID_WRITE_CHECKSUM_TABLE 0xde /* SET_FEATURE */ -#define FU_WAC_REPORT_ID_GET_CURRENT_FIRMWARE_IDX 0xe2 /* GET_FEATURE */ -#define FU_WAC_REPORT_ID_MODULE 0xe4 - -guint32 fu_wac_calculate_checksum32le (const guint8 *data, - gsize len); -guint32 fu_wac_calculate_checksum32le_bytes (GBytes *blob); -const gchar *fu_wac_report_id_to_string (guint8 report_id); -void fu_wac_buffer_dump (const gchar *title, - guint8 cmd, - const guint8 *buf, - gsize sz); - -G_END_DECLS - -#endif /* __FU_WAC_HID_H */ diff -Nru fwupd-1.1.4/plugins/wacomhid/fu-wac-device.c fwupd-1.2.5/plugins/wacomhid/fu-wac-device.c --- fwupd-1.1.4/plugins/wacomhid/fu-wac-device.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/wacomhid/fu-wac-device.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,900 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include - -#include "fu-chunk.h" -#include "fu-wac-device.h" -#include "fu-wac-common.h" -#include "fu-wac-firmware.h" -#include "fu-wac-module-bluetooth.h" -#include "fu-wac-module-touch.h" - -#include "dfu-common.h" -#include "dfu-firmware.h" - -typedef struct __attribute__((packed)) { - guint32 start_addr; - guint32 block_sz; - guint16 write_sz; /* bit 15 is write protection flag */ -} FuWacFlashDescriptor; - -typedef enum { - FU_WAC_STATUS_UNKNOWN = 0, - FU_WAC_STATUS_WRITING = 1 << 0, - FU_WAC_STATUS_ERASING = 1 << 1, - FU_WAC_STATUS_ERROR_WRITE = 1 << 2, - FU_WAC_STATUS_ERROR_ERASE = 1 << 3, - FU_WAC_STATUS_WRITE_PROTECTED = 1 << 4, - FU_WAC_STATUS_LAST -} FuWacStatus; - -#define FU_WAC_DEVICE_TIMEOUT 5000 /* ms */ - -struct _FuWacDevice -{ - FuUsbDevice parent_instance; - GPtrArray *flash_descriptors; - GArray *checksums; - guint32 status_word; - guint16 firmware_index; - guint16 loader_ver; - guint16 read_data_sz; - guint16 write_word_sz; - guint16 write_block_sz; /* usb transfer size */ - guint16 nr_flash_blocks; - guint16 configuration; -}; - -G_DEFINE_TYPE (FuWacDevice, fu_wac_device, FU_TYPE_USB_DEVICE) - -static GString * -fu_wac_device_status_to_string (guint32 status_word) -{ - GString *str = g_string_new (NULL); - if (status_word & FU_WAC_STATUS_WRITING) - g_string_append (str, "writing,"); - if (status_word & FU_WAC_STATUS_ERASING) - g_string_append (str, "erasing,"); - if (status_word & FU_WAC_STATUS_ERROR_WRITE) - g_string_append (str, "error-write,"); - if (status_word & FU_WAC_STATUS_ERROR_ERASE) - g_string_append (str, "error-erase,"); - if (status_word & FU_WAC_STATUS_WRITE_PROTECTED) - g_string_append (str, "write-protected,"); - if (str->len == 0) { - g_string_append (str, "none"); - return str; - } - g_string_truncate (str, str->len - 1); - return str; -} - -static gboolean -fu_wav_device_flash_descriptor_is_wp (const FuWacFlashDescriptor *fd) -{ - return fd->write_sz & 0x8000; -} - -static void -fu_wac_device_to_string (FuDevice *device, GString *str) -{ - GPtrArray *children; - FuWacDevice *self = FU_WAC_DEVICE (device); - g_autoptr(GString) status_str = NULL; - - g_string_append (str, " FuWacDevice:\n"); - if (self->firmware_index != 0xffff) { - g_string_append_printf (str, " fw-index: 0x%04x\n", - self->firmware_index); - } - if (self->loader_ver > 0) { - g_string_append_printf (str, " loader-ver: 0x%04x\n", - (guint) self->loader_ver); - } - if (self->read_data_sz > 0) { - g_string_append_printf (str, " read-data-sz: 0x%04x\n", - (guint) self->read_data_sz); - } - if (self->write_word_sz > 0) { - g_string_append_printf (str, " write-word-sz: 0x%04x\n", - (guint) self->write_word_sz); - } - if (self->write_block_sz > 0) { - g_string_append_printf (str, " write-block-sz: 0x%04x\n", - (guint) self->write_block_sz); - } - if (self->nr_flash_blocks > 0) { - g_string_append_printf (str, " nr-flash-blocks: 0x%04x\n", - (guint) self->nr_flash_blocks); - } - if (self->configuration != 0xffff) { - g_string_append_printf (str, " configuration: 0x%04x\n", - (guint) self->configuration); - } - for (guint i = 0; i < self->flash_descriptors->len; i++) { - FuWacFlashDescriptor *fd = g_ptr_array_index (self->flash_descriptors, i); - g_string_append_printf (str, " flash-descriptor-%02u:\n", i); - g_string_append_printf (str, " start-addr:\t0x%08x\n", - (guint) fd->start_addr); - g_string_append_printf (str, " block-sz:\t0x%08x\n", - (guint) fd->block_sz); - g_string_append_printf (str, " write-sz:\t0x%04x\n", - (guint) fd->write_sz & ~0x8000); - g_string_append_printf (str, " protected:\t%s\n", - fu_wav_device_flash_descriptor_is_wp (fd) ? "yes" : "no"); - } - status_str = fu_wac_device_status_to_string (self->status_word); - g_string_append_printf (str, " status:\t\t%s\n", status_str->str); - - /* print children also */ - children = fu_device_get_children (device); - for (guint i = 0; i < children->len; i++) { - FuDevice *child = g_ptr_array_index (children, i); - g_autofree gchar *tmp = fu_device_to_string (FU_DEVICE (child)); - g_string_append (str, " FuWacDeviceChild:\n"); - g_string_append (str, tmp); - } -} - -gboolean -fu_wac_device_get_feature_report (FuWacDevice *self, - guint8 *buf, gsize bufsz, - FuWacDeviceFeatureFlags flags, - GError **error) -{ - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); - gsize sz = 0; - guint8 cmd = buf[0]; - - /* hit hardware */ - fu_wac_buffer_dump ("GET", cmd, buf, bufsz); - if (!g_usb_device_control_transfer (usb_device, - G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, - G_USB_DEVICE_REQUEST_TYPE_CLASS, - G_USB_DEVICE_RECIPIENT_INTERFACE, - HID_REPORT_GET, /* bRequest */ - HID_FEATURE | cmd, /* wValue */ - 0x0000, /* wIndex */ - buf, bufsz, &sz, - FU_WAC_DEVICE_TIMEOUT, - NULL, error)) { - g_prefix_error (error, "Failed to get feature report: "); - return FALSE; - } - fu_wac_buffer_dump ("GE2", cmd, buf, sz); - - /* check packet */ - if ((flags & FU_WAC_DEVICE_FEATURE_FLAG_ALLOW_TRUNC) == 0 && sz != bufsz) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "packet get bytes %" G_GSIZE_FORMAT - " expected %" G_GSIZE_FORMAT, - sz, bufsz); - return FALSE; - } - if (buf[0] != cmd) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "command response was %i expected %i", - buf[0], cmd); - return FALSE; - } - return TRUE; -} - -gboolean -fu_wac_device_set_feature_report (FuWacDevice *self, - guint8 *buf, gsize bufsz, - FuWacDeviceFeatureFlags flags, - GError **error) -{ - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); - gsize sz = 0; - guint8 cmd = buf[0]; - - /* hit hardware */ - fu_wac_buffer_dump ("SET", cmd, buf, bufsz); - if (g_getenv ("FWUPD_WAC_EMULATE") != NULL) - return TRUE; - if (!g_usb_device_control_transfer (usb_device, - G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, - G_USB_DEVICE_REQUEST_TYPE_CLASS, - G_USB_DEVICE_RECIPIENT_INTERFACE, - HID_REPORT_SET, /* bRequest */ - HID_FEATURE | cmd, /* wValue */ - 0x0000, /* wIndex */ - buf, bufsz, &sz, - FU_WAC_DEVICE_TIMEOUT, - NULL, error)) { - g_prefix_error (error, "Failed to set feature report: "); - return FALSE; - } - - /* check packet */ - if ((flags & FU_WAC_DEVICE_FEATURE_FLAG_ALLOW_TRUNC) == 0 && sz != bufsz) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "packet sent bytes %" G_GSIZE_FORMAT - " expected %" G_GSIZE_FORMAT, - sz, bufsz); - return FALSE; - } - return TRUE; -} - -static gboolean -fu_wac_device_ensure_flash_descriptors (FuWacDevice *self, GError **error) -{ - gsize sz = (self->nr_flash_blocks * 10) + 1; - g_autofree guint8 *buf = NULL; - - /* already done */ - if (self->flash_descriptors->len > 0) - return TRUE; - - /* hit hardware */ - buf = g_malloc (sz); - memset (buf, 0xff, sz); - buf[0] = FU_WAC_REPORT_ID_GET_FLASH_DESCRIPTOR; - if (!fu_wac_device_get_feature_report (self, buf, sz, - FU_WAC_DEVICE_FEATURE_FLAG_NONE, - error)) - return FALSE; - - /* parse */ - for (guint i = 0; i < self->nr_flash_blocks; i++) { - FuWacFlashDescriptor *fd = g_new0 (FuWacFlashDescriptor, 1); - const guint blksz = sizeof(FuWacFlashDescriptor); - fd->start_addr = fu_common_read_uint32 (buf + (i * blksz) + 1, G_LITTLE_ENDIAN); - fd->block_sz = fu_common_read_uint32 (buf + (i * blksz) + 5, G_LITTLE_ENDIAN); - fd->write_sz = fu_common_read_uint16 (buf + (i * blksz) + 9, G_LITTLE_ENDIAN); - g_ptr_array_add (self->flash_descriptors, fd); - } - g_debug ("added %u flash descriptors", self->flash_descriptors->len); - return TRUE; -} - -static gboolean -fu_wac_device_ensure_status (FuWacDevice *self, GError **error) -{ - g_autoptr(GString) str = NULL; - guint8 buf[] = { [0] = FU_WAC_REPORT_ID_GET_STATUS, - [1 ... 4] = 0xff }; - - /* hit hardware */ - buf[0] = FU_WAC_REPORT_ID_GET_STATUS; - if (!fu_wac_device_get_feature_report (self, buf, sizeof(buf), - FU_WAC_DEVICE_FEATURE_FLAG_NONE, - error)) - return FALSE; - - /* parse */ - self->status_word = fu_common_read_uint32 (buf + 1, G_LITTLE_ENDIAN); - str = fu_wac_device_status_to_string (self->status_word); - g_debug ("status now: %s", str->str); - return TRUE; -} - -static gboolean -fu_wac_device_ensure_checksums (FuWacDevice *self, GError **error) -{ - gsize sz = (self->nr_flash_blocks * 4) + 5; - guint32 updater_version; - g_autofree guint8 *buf = g_malloc (sz); - - /* hit hardware */ - memset (buf, 0xff, sz); - buf[0] = FU_WAC_REPORT_ID_GET_CHECKSUMS; - if (!fu_wac_device_get_feature_report (self, buf, sz, - FU_WAC_DEVICE_FEATURE_FLAG_NONE, - error)) - return FALSE; - - /* parse */ - updater_version = fu_common_read_uint32 (buf + 1, G_LITTLE_ENDIAN); - g_debug ("updater-version: %" G_GUINT32_FORMAT, updater_version); - - /* get block checksums */ - g_array_set_size (self->checksums, 0); - for (guint i = 0; i < self->nr_flash_blocks; i++) { - guint32 csum = fu_common_read_uint32 (buf + 5 + (i * 4), G_LITTLE_ENDIAN); - g_debug ("checksum block %02u: 0x%08x", i, (guint) csum); - g_array_append_val (self->checksums, csum); - } - g_debug ("added %u checksums", self->flash_descriptors->len); - - return TRUE; -} - - -static gboolean -fu_wac_device_ensure_firmware_index (FuWacDevice *self, GError **error) -{ - guint8 buf[] = { [0] = FU_WAC_REPORT_ID_GET_CURRENT_FIRMWARE_IDX, - [1 ... 2] = 0xff }; - - /* hit hardware */ - if (!fu_wac_device_get_feature_report (self, buf, sizeof(buf), - FU_WAC_DEVICE_FEATURE_FLAG_NONE, - error)) - return FALSE; - - /* parse */ - self->firmware_index = fu_common_read_uint16 (buf + 1, G_LITTLE_ENDIAN); - return TRUE; -} - -static gboolean -fu_wac_device_ensure_parameters (FuWacDevice *self, GError **error) -{ - guint8 buf[] = { [0] = FU_WAC_REPORT_ID_GET_PARAMETERS, - [1 ... 12] = 0xff }; - - /* hit hardware */ - if (!fu_wac_device_get_feature_report (self, buf, sizeof(buf), - FU_WAC_DEVICE_FEATURE_FLAG_NONE, - error)) - return FALSE; - - /* parse */ - self->loader_ver = fu_common_read_uint16 (buf + 1, G_LITTLE_ENDIAN); - self->read_data_sz = fu_common_read_uint16 (buf + 3, G_LITTLE_ENDIAN); - self->write_word_sz = fu_common_read_uint16 (buf + 5, G_LITTLE_ENDIAN); - self->write_block_sz = fu_common_read_uint16 (buf + 7, G_LITTLE_ENDIAN); - self->nr_flash_blocks = fu_common_read_uint16 (buf + 9, G_LITTLE_ENDIAN); - self->configuration = fu_common_read_uint16 (buf + 11, G_LITTLE_ENDIAN); - return TRUE; -} - -static gboolean -fu_wac_device_write_block (FuWacDevice *self, - guint32 addr, - GBytes *blob, - GError **error) -{ - const guint8 *tmp; - gsize bufsz = self->write_block_sz + 5; - gsize sz = 0; - g_autofree guint8 *buf = NULL; - - /* check size */ - tmp = g_bytes_get_data (blob, &sz); - if (sz > self->write_block_sz) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "packet was too large at %" G_GSIZE_FORMAT " bytes", - sz); - return FALSE; - } - - /* build packet */ - buf = g_malloc (bufsz); - memset (buf, 0xff, bufsz); - buf[0] = FU_WAC_REPORT_ID_WRITE_BLOCK; - fu_common_write_uint32 (buf + 1, addr, G_LITTLE_ENDIAN); - if (sz > 0) - memcpy (buf + 5, tmp, sz); - - /* hit hardware */ - return fu_wac_device_set_feature_report (self, buf, bufsz, - FU_WAC_DEVICE_FEATURE_FLAG_NONE, - error); -} - -static gboolean -fu_wac_device_erase_block (FuWacDevice *self, guint32 addr, GError **error) -{ - guint8 buf[] = { [0] = FU_WAC_REPORT_ID_ERASE_BLOCK, - [1 ... 4] = 0xff }; - - /* build packet */ - fu_common_write_uint32 (buf + 1, addr, G_LITTLE_ENDIAN); - - /* hit hardware */ - return fu_wac_device_set_feature_report (self, buf, sizeof(buf), - FU_WAC_DEVICE_FEATURE_FLAG_NONE, - error); -} - -gboolean -fu_wac_device_update_reset (FuWacDevice *self, GError **error) -{ - guint8 buf[] = { [0] = FU_WAC_REPORT_ID_UPDATE_RESET, - [1 ... 4] = 0xff }; - - /* hit hardware */ - return fu_wac_device_set_feature_report (self, buf, sizeof(buf), - FU_WAC_DEVICE_FEATURE_FLAG_NONE, - error); -} - -static gboolean -fu_wac_device_set_checksum_of_block (FuWacDevice *self, - guint16 block_nr, - guint32 checksum, - GError **error) -{ - guint8 buf[] = { [0] = FU_WAC_REPORT_ID_SET_CHECKSUM_FOR_BLOCK, - [1 ... 6] = 0xff }; - - /* build packet */ - fu_common_write_uint16 (buf + 1, block_nr, G_LITTLE_ENDIAN); - fu_common_write_uint32 (buf + 3, checksum, G_LITTLE_ENDIAN); - - /* hit hardware */ - return fu_wac_device_set_feature_report (self, buf, sizeof(buf), - FU_WAC_DEVICE_FEATURE_FLAG_NONE, - error); -} - -static gboolean -fu_wac_device_calculate_checksum_of_block (FuWacDevice *self, - guint16 block_nr, - GError **error) -{ - guint8 buf[] = { [0] = FU_WAC_REPORT_ID_CALCULATE_CHECKSUM_FOR_BLOCK, - [1 ... 2] = 0xff }; - - /* build packet */ - fu_common_write_uint16 (buf + 1, block_nr, G_LITTLE_ENDIAN); - - /* hit hardware */ - return fu_wac_device_set_feature_report (self, buf, sizeof(buf), - FU_WAC_DEVICE_FEATURE_FLAG_NONE, - error); -} - -static gboolean -fu_wac_device_write_checksum_table (FuWacDevice *self, GError **error) -{ - guint8 buf[] = { [0] = FU_WAC_REPORT_ID_WRITE_CHECKSUM_TABLE, - [1 ... 4] = 0xff }; - - /* hit hardware */ - return fu_wac_device_set_feature_report (self, buf, sizeof(buf), - FU_WAC_DEVICE_FEATURE_FLAG_NONE, - error); -} - -static gboolean -fu_wac_device_switch_to_flash_loader (FuWacDevice *self, GError **error) -{ - guint8 buf[] = { [0] = FU_WAC_REPORT_ID_SWITCH_TO_FLASH_LOADER, - [1] = 0x05, - [2] = 0x6a }; - - /* hit hardware */ - return fu_wac_device_set_feature_report (self, buf, sizeof(buf), - FU_WAC_DEVICE_FEATURE_FLAG_NONE, - error); -} - -static gboolean -fu_wac_device_write_firmware (FuDevice *device, GBytes *blob, GError **error) -{ - DfuElement *element; - DfuImage *image; - FuWacDevice *self = FU_WAC_DEVICE (device); - gsize blocks_done = 0; - gsize blocks_total = 0; - g_autoptr(DfuFirmware) firmware = dfu_firmware_new (); - g_autoptr(GHashTable) fd_blobs = NULL; - g_autofree guint32 *csum_local = NULL; - - /* load .wac file, including metadata */ - if (!fu_wac_firmware_parse_data (firmware, blob, - DFU_FIRMWARE_PARSE_FLAG_NONE, - error)) - return FALSE; - if (dfu_firmware_get_format (firmware) != DFU_FIRMWARE_FORMAT_SREC) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "expected firmware format is 'srec', got '%s'", - dfu_firmware_format_to_string (dfu_firmware_get_format (firmware))); - return FALSE; - } - - /* enter flash mode */ - if (!fu_wac_device_switch_to_flash_loader (self, error)) - return FALSE; - - /* get current selected device */ - if (!fu_wac_device_ensure_firmware_index (self, error)) - return FALSE; - - /* use the correct image from the firmware */ - image = dfu_firmware_get_image (firmware, self->firmware_index == 1 ? 1 : 0); - if (image == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "no firmware image for index %" G_GUINT16_FORMAT, - self->firmware_index); - return FALSE; - } - element = dfu_image_get_element_default (image); - if (element == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "no element in image %" G_GUINT16_FORMAT, - self->firmware_index); - return FALSE; - } - g_debug ("using element at addr 0x%0x", - (guint) dfu_element_get_address (element)); - - /* get firmware parameters (page sz and transfer sz) */ - if (!fu_wac_device_ensure_parameters (self, error)) - return FALSE; - - /* get the current flash descriptors */ - if (!fu_wac_device_ensure_flash_descriptors (self, error)) - return FALSE; - - /* get the updater protocol version */ - if (!fu_wac_device_ensure_checksums (self, error)) - return FALSE; - - /* clear all checksums of pages */ - fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); - for (guint16 i = 0; i < self->flash_descriptors->len; i++) { - FuWacFlashDescriptor *fd = g_ptr_array_index (self->flash_descriptors, i); - if (fu_wav_device_flash_descriptor_is_wp (fd)) - continue; - if (!fu_wac_device_set_checksum_of_block (self, i, 0x0, error)) - return FALSE; - } - - /* get the blobs for each chunk */ - fd_blobs = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, (GDestroyNotify) g_bytes_unref); - for (guint16 i = 0; i < self->flash_descriptors->len; i++) { - FuWacFlashDescriptor *fd = g_ptr_array_index (self->flash_descriptors, i); - GBytes *blob_block; - g_autoptr(GBytes) blob_tmp = NULL; - - if (fu_wav_device_flash_descriptor_is_wp (fd)) - continue; - blob_tmp = dfu_element_get_contents_chunk (element, - fd->start_addr, - fd->block_sz, - NULL); - if (blob_tmp == NULL) - break; - blob_block = dfu_utils_bytes_pad (blob_tmp, fd->block_sz); - g_hash_table_insert (fd_blobs, fd, blob_block); - } - - /* checksum actions post-write */ - blocks_total = g_hash_table_size (fd_blobs) + 2; - - /* write the data into the flash page */ - fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); - csum_local = g_new0 (guint32, self->flash_descriptors->len); - for (guint16 i = 0; i < self->flash_descriptors->len; i++) { - FuWacFlashDescriptor *fd = g_ptr_array_index (self->flash_descriptors, i); - GBytes *blob_block; - g_autoptr(GPtrArray) chunks = NULL; - - /* if page is protected */ - if (fu_wav_device_flash_descriptor_is_wp (fd)) - continue; - - /* get data for page */ - blob_block = g_hash_table_lookup (fd_blobs, fd); - if (blob_block == NULL) - break; - - /* erase entire block */ - if (!fu_wac_device_erase_block (self, i, error)) - return FALSE; - - /* write block in chunks */ - chunks = fu_chunk_array_new_from_bytes (blob_block, - fd->start_addr, - 0, /* page_sz */ - self->write_block_sz); - for (guint j = 0; j < chunks->len; j++) { - FuChunk *chk = g_ptr_array_index (chunks, j); - g_autoptr(GBytes) blob_chunk = g_bytes_new (chk->data, chk->data_sz); - if (!fu_wac_device_write_block (self, chk->address, blob_chunk, error)) - return FALSE; - } - - /* calculate expected checksum and save to device RAM */ - csum_local[i] = fu_wac_calculate_checksum32le_bytes (blob_block); - g_debug ("block checksum %02u: 0x%08x", i, csum_local[i]); - if (!fu_wac_device_set_checksum_of_block (self, i, csum_local[i], error)) - return FALSE; - - /* update device progress */ - fu_device_set_progress_full (device, blocks_done++, blocks_total); - } - - /* calculate CRC inside device */ - for (guint16 i = 0; i < self->flash_descriptors->len; i++) { - if (!fu_wac_device_calculate_checksum_of_block (self, i, error)) - return FALSE; - } - - /* update device progress */ - fu_device_set_progress_full (device, blocks_done++, blocks_total); - - /* read all CRC of all pages and verify with local CRC */ - if (!fu_wac_device_ensure_checksums (self, error)) - return FALSE; - for (guint16 i = 0; i < self->flash_descriptors->len; i++) { - FuWacFlashDescriptor *fd = g_ptr_array_index (self->flash_descriptors, i); - guint32 csum_rom; - - /* if page is protected */ - if (fu_wav_device_flash_descriptor_is_wp (fd)) - continue; - - /* no more written pages */ - if (g_hash_table_lookup (fd_blobs, fd) == NULL) - break; - - /* check checksum matches */ - csum_rom = g_array_index (self->checksums, guint32, i); - if (csum_rom != csum_local[i]) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed local checksum at block %u, " - "got 0x%08x expected 0x%08x", i, - (guint) csum_rom, (guint) csum_local[i]); - return FALSE; - } - g_debug ("matched checksum at block %u of 0x%08x", i, csum_rom); - } - - /* update device progress */ - fu_device_set_progress_full (device, blocks_done++, blocks_total); - - /* store host CRC into flash */ - if (!fu_wac_device_write_checksum_table (self, error)) - return FALSE; - - /* update progress */ - fu_device_set_progress_full (device, blocks_total, blocks_total); - - /* reboot, which switches the boot index of the firmware */ - fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); - return fu_wac_device_update_reset (self, error); -} - -static gboolean -fu_wac_device_add_modules_bluetooth (FuWacDevice *self, GError **error) -{ - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); - g_autofree gchar *name = NULL; - g_autofree gchar *version = NULL; - g_autoptr(FuWacModule) module = NULL; - guint8 buf[] = { [0] = FU_WAC_REPORT_ID_GET_FIRMWARE_VERSION_BLUETOOTH, - [1 ... 14] = 0xff }; - - buf[0] = FU_WAC_REPORT_ID_GET_FIRMWARE_VERSION_BLUETOOTH; - if (!fu_wac_device_get_feature_report (self, buf, sizeof(buf), - FU_WAC_DEVICE_FEATURE_FLAG_NONE, - error)) { - g_prefix_error (error, "Failed to get GetFirmwareVersionBluetooth: "); - return FALSE; - } - - /* success */ - name = g_strdup_printf ("%s [Legacy Bluetooth Module]", - fu_device_get_name (FU_DEVICE (self))); - version = g_strdup_printf ("%x.%x", (guint) buf[2], (guint) buf[1]); - module = fu_wac_module_bluetooth_new (usb_device); - fu_device_add_child (FU_DEVICE (self), FU_DEVICE (module)); - fu_device_set_name (FU_DEVICE (module), name); - fu_device_set_version (FU_DEVICE (module), version); - return TRUE; -} - -static gboolean -fu_wac_device_add_modules_legacy (FuWacDevice *self, GError **error) -{ - g_autoptr(GError) error_bt = NULL; - - /* optional bluetooth */ - if (!fu_wac_device_add_modules_bluetooth (self, &error_bt)) - g_debug ("no bluetooth hardware: %s", error_bt->message); - - return TRUE; -} - -static gboolean -fu_wac_device_add_modules (FuWacDevice *self, GError **error) -{ - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); - g_autofree gchar *version_bootloader = NULL; - guint8 buf[] = { [0] = FU_WAC_REPORT_ID_FW_DESCRIPTOR, - [1 ... 31] = 0xff }; - - if (!fu_wac_device_get_feature_report (self, buf, sizeof(buf), - FU_WAC_DEVICE_FEATURE_FLAG_NONE, - error)) { - g_prefix_error (error, "Failed to get DeviceFirmwareDescriptor: "); - return FALSE; - } - - /* verify bootloader is compatible */ - if (buf[1] != 0x01) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "bootloader major version not compatible"); - return FALSE; - } - - /* verify the number of submodules is possible */ - if (buf[3] > (512 - 4) / 4) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "number of submodules is impossible"); - return FALSE; - } - - /* bootloader version */ - version_bootloader = g_strdup_printf ("%u.%u", buf[1], buf[2]); - fu_device_set_version_bootloader (FU_DEVICE (self), version_bootloader); - - /* get versions of each submodule */ - for (guint8 i = 0; i < buf[3]; i++) { - guint8 fw_type = buf[(i * 4) + 4] & ~0x80; - g_autofree gchar *name = NULL; - g_autofree gchar *version = NULL; - g_autoptr(FuWacModule) module = NULL; - - /* version number is decimal */ - version = g_strdup_printf ("%u.%u", buf[(i * 4) + 5], buf[(i * 4) + 6]); - - switch (fw_type) { - case FU_WAC_MODULE_FW_TYPE_TOUCH: - module = fu_wac_module_touch_new (usb_device); - name = g_strdup_printf ("%s [Touch Module]", - fu_device_get_name (FU_DEVICE (self))); - fu_device_add_child (FU_DEVICE (self), FU_DEVICE (module)); - fu_device_set_name (FU_DEVICE (module), name); - fu_device_set_version (FU_DEVICE (module), version); - break; - case FU_WAC_MODULE_FW_TYPE_BLUETOOTH: - module = fu_wac_module_bluetooth_new (usb_device); - name = g_strdup_printf ("%s [Bluetooth Module]", - fu_device_get_name (FU_DEVICE (self))); - fu_device_add_child (FU_DEVICE (self), FU_DEVICE (module)); - fu_device_set_name (FU_DEVICE (module), name); - fu_device_set_version (FU_DEVICE (module), version); - break; - case FU_WAC_MODULE_FW_TYPE_MAIN: - fu_device_set_version (FU_DEVICE (self), version); - break; - default: - g_warning ("unknown submodule type 0x%0x", fw_type); - break; - } - } - return TRUE; -} - -static gboolean -fu_wac_device_open (FuUsbDevice *device, GError **error) -{ - GUsbDevice *usb_device = fu_usb_device_get_dev (device); - - /* open device */ - if (!g_usb_device_claim_interface (usb_device, 0x00, /* HID */ - G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, - error)) { - g_prefix_error (error, "failed to claim HID interface: "); - return FALSE; - } - - /* success */ - return TRUE; -} - -static gboolean -fu_wac_device_setup (FuDevice *device, GError **error) -{ - FuWacDevice *self = FU_WAC_DEVICE (device); - - /* get current status */ - if (!fu_wac_device_ensure_status (self, error)) - return FALSE; - - /* get version of each sub-module */ - if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_USE_RUNTIME_VERSION)) { - if (!fu_wac_device_add_modules_legacy (self, error)) - return FALSE; - } else { - if (!fu_wac_device_add_modules (self, error)) - return FALSE; - } - - /* success */ - return TRUE; -} - -static gboolean -fu_wac_device_close (FuUsbDevice *device, GError **error) -{ - GUsbDevice *usb_device = fu_usb_device_get_dev (device); - - /* reattach wacom.ko */ - if (!g_usb_device_release_interface (usb_device, 0x00, /* HID */ - G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, - error)) { - g_prefix_error (error, "failed to re-attach interface: "); - return FALSE; - } - - /* The hidcore subsystem uses a generic power_supply that has a deferred - * work item that will lock the device. When removing the power_supply, - * we take the lock, then cancel the work item which needs to take the - * lock too. This needs to be fixed in the kernel, but for the moment - * this should let the kernel unstick itself. */ - g_usleep (20 * 1000); - - /* success */ - return TRUE; -} - -static void -fu_wac_device_init (FuWacDevice *self) -{ - self->flash_descriptors = g_ptr_array_new_with_free_func (g_free); - self->checksums = g_array_new (FALSE, FALSE, sizeof(guint32)); - self->configuration = 0xffff; - self->firmware_index = 0xffff; - fu_device_add_icon (FU_DEVICE (self), "input-tablet"); - fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); -} - -static void -fu_wac_device_finalize (GObject *object) -{ - FuWacDevice *self = FU_WAC_DEVICE (object); - - g_ptr_array_unref (self->flash_descriptors); - g_array_unref (self->checksums); - - G_OBJECT_CLASS (fu_wac_device_parent_class)->finalize (object); -} - -static void -fu_wac_device_class_init (FuWacDeviceClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); - object_class->finalize = fu_wac_device_finalize; - klass_device->write_firmware = fu_wac_device_write_firmware; - klass_device->to_string = fu_wac_device_to_string; - klass_device->setup = fu_wac_device_setup; - klass_usb_device->open = fu_wac_device_open; - klass_usb_device->close = fu_wac_device_close; -} - -FuWacDevice * -fu_wac_device_new (FuUsbDevice *device) -{ - FuWacDevice *self = g_object_new (FU_TYPE_WAC_DEVICE, NULL); - fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); - return self; -} diff -Nru fwupd-1.1.4/plugins/wacomhid/fu-wac-device.h fwupd-1.2.5/plugins/wacomhid/fu-wac-device.h --- fwupd-1.1.4/plugins/wacomhid/fu-wac-device.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/wacomhid/fu-wac-device.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#ifndef __FU_WAC_DEVICE_H -#define __FU_WAC_DEVICE_H - -#include "fu-plugin.h" - -G_BEGIN_DECLS - -#define FU_TYPE_WAC_DEVICE (fu_wac_device_get_type ()) -G_DECLARE_FINAL_TYPE (FuWacDevice, fu_wac_device, FU, WAC_DEVICE, FuUsbDevice) - -typedef enum { - FU_WAC_DEVICE_FEATURE_FLAG_NONE = 0, - FU_WAC_DEVICE_FEATURE_FLAG_ALLOW_TRUNC = 1 << 0, - FU_WAC_DEVICE_FEATURE_FLAG_LAST -} FuWacDeviceFeatureFlags; - -FuWacDevice *fu_wac_device_new (FuUsbDevice *device); -gboolean fu_wac_device_update_reset (FuWacDevice *self, - GError **error); -gboolean fu_wac_device_get_feature_report (FuWacDevice *self, - guint8 *buf, - gsize bufsz, - FuWacDeviceFeatureFlags flags, - GError **error); -gboolean fu_wac_device_set_feature_report (FuWacDevice *self, - guint8 *buf, - gsize bufsz, - FuWacDeviceFeatureFlags flags, - GError **error); - -G_END_DECLS - -#endif /* __FU_WAC_DEVICE_H */ diff -Nru fwupd-1.1.4/plugins/wacomhid/fu-wac-firmware.c fwupd-1.2.5/plugins/wacomhid/fu-wac-firmware.c --- fwupd-1.1.4/plugins/wacomhid/fu-wac-firmware.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/wacomhid/fu-wac-firmware.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,231 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include - -#include "dfu-element.h" -#include "dfu-format-srec.h" -#include "dfu-image.h" - -#include "fu-wac-firmware.h" - -#include "fwupd-error.h" - -typedef struct { - guint32 addr; - guint32 sz; - guint32 prog_start_addr; -} DfuFirmwareWacHeaderRecord; - -/** - * fu_wac_firmware_parse_data: - * @firmware: a #DfuFirmware - * @bytes: data to parse - * @flags: some #DfuFirmwareParseFlags - * @error: a #GError, or %NULL - * - * Unpacks into a firmware object from DfuSe data. - * - * Returns: %TRUE for success - **/ -gboolean -fu_wac_firmware_parse_data (DfuFirmware *firmware, - GBytes *bytes, - DfuFirmwareParseFlags flags, - GError **error) -{ - gsize len; - guint8 *data; - g_auto(GStrv) lines = NULL; - g_autoptr(GString) image_buffer = NULL; - g_autofree gchar *data_str = NULL; - guint8 images_cnt = 0; - g_autoptr(GPtrArray) header_infos = g_ptr_array_new_with_free_func (g_free); - - /* check the prefix (BE) */ - data = (guint8 *) g_bytes_get_data (bytes, &len); - if (memcmp (data, "WACOM", 5) != 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "invalid .wac prefix"); - return FALSE; - } - - /* parse each line */ - data_str = g_strndup ((const gchar *) data, len); - lines = g_strsplit (data_str, "\n", -1); - for (guint i = 0; lines[i] != NULL; i++) { - g_autofree gchar *cmd = g_strndup (lines[i], 2); - - /* remove windows line endings */ - g_strdelimit (lines[i], "\r", '\0'); - - /* Wacom-specific metadata */ - if (g_strcmp0 (cmd, "WA") == 0) { - guint cmdlen = strlen (lines[i]); - - /* header info record */ - if (memcmp (lines[i] + 2, "COM", 3) == 0) { - guint8 header_image_cnt = 0; - if (cmdlen != 40) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "invalid header, got %u bytes", - cmdlen); - return FALSE; - } - header_image_cnt = dfu_utils_buffer_parse_uint4 (lines[i] + 5); - for (guint j = 0; j < header_image_cnt; j++) { - DfuFirmwareWacHeaderRecord *hdr = g_new0 (DfuFirmwareWacHeaderRecord, 1); - hdr->addr = dfu_utils_buffer_parse_uint32 (lines[i] + (j * 16) + 6); - hdr->sz = dfu_utils_buffer_parse_uint32 (lines[i] + (j * 16) + 14); - g_ptr_array_add (header_infos, hdr); - g_debug ("header_fw%u_addr: 0x%x", j, hdr->addr); - g_debug ("header_fw%u_sz: 0x%x", j, hdr->sz); - } - continue; - } - - /* firmware headline record */ - if (cmdlen == 13) { - DfuFirmwareWacHeaderRecord *hdr; - guint8 idx = dfu_utils_buffer_parse_uint4 (lines[i] + 2); - if (idx == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "headline %u invalid", - idx); - return FALSE; - } - if (idx > header_infos->len) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "headline %u exceeds header count %u", - idx, header_infos->len); - return FALSE; - } - hdr = g_ptr_array_index (header_infos, idx - 1); - hdr->prog_start_addr = dfu_utils_buffer_parse_uint32 (lines[i] + 3); - if (hdr->prog_start_addr != hdr->addr) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "programming address 0x%x != " - "base address 0x%0x for idx %u", - hdr->prog_start_addr, - hdr->addr, - idx); - return FALSE; - } - g_debug ("programing-start-address: 0x%x", hdr->prog_start_addr); - continue; - } - - g_debug ("unknown Wacom-specific metadata"); - continue; - } - - /* start */ - if (g_strcmp0 (cmd, "S0") == 0) { - if (image_buffer != NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "duplicate S0 without S7"); - return FALSE; - } - image_buffer = g_string_new (NULL); - } - - /* these are things we want to include in the image */ - if (g_strcmp0 (cmd, "S0") == 0 || - g_strcmp0 (cmd, "S1") == 0 || - g_strcmp0 (cmd, "S2") == 0 || - g_strcmp0 (cmd, "S3") == 0 || - g_strcmp0 (cmd, "S5") == 0 || - g_strcmp0 (cmd, "S7") == 0 || - g_strcmp0 (cmd, "S8") == 0 || - g_strcmp0 (cmd, "S9") == 0) { - if (image_buffer == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "%s without S0", cmd); - return FALSE; - } - g_string_append_printf (image_buffer, "%s\n", lines[i]); - } - - /* end */ - if (g_strcmp0 (cmd, "S7") == 0) { - g_autoptr(GBytes) blob = NULL; - g_autoptr(DfuImage) image = dfu_image_new (); - DfuFirmwareWacHeaderRecord *hdr; - - /* get the correct relocated start address */ - if (images_cnt >= header_infos->len) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "%s without header", cmd); - return FALSE; - } - hdr = g_ptr_array_index (header_infos, images_cnt); - - if (image_buffer == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "%s with missing image buffer", cmd); - return FALSE; - } - - /* parse SREC file and add as image */ - blob = g_bytes_new (image_buffer->str, image_buffer->len); - if (!dfu_image_from_srec (image, blob, hdr->addr, flags, error)) - return FALSE; - - /* the alt-setting is used for the firmware index */ - dfu_image_set_alt_setting (image, images_cnt); - dfu_firmware_add_image (firmware, image); - images_cnt++; - - /* clear the image buffer */ - g_string_free (image_buffer, TRUE); - image_buffer = NULL; - } - } - - /* verify data is complete */ - if (image_buffer != NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "truncated data: no S7"); - return FALSE; - } - - /* ensure this matched the header */ - if (header_infos->len != images_cnt) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "not enough images %u for header count %u", - images_cnt, - header_infos->len); - return FALSE; - } - - /* success */ - dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_SREC); - return TRUE; -} diff -Nru fwupd-1.1.4/plugins/wacomhid/fu-wac-firmware.h fwupd-1.2.5/plugins/wacomhid/fu-wac-firmware.h --- fwupd-1.1.4/plugins/wacomhid/fu-wac-firmware.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/wacomhid/fu-wac-firmware.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#ifndef __FU_WAC_FIRMWARE_H -#define __FU_WAC_FIRMWARE_H - -#include - -#include "dfu-firmware.h" - -G_BEGIN_DECLS - -gboolean fu_wac_firmware_parse_data (DfuFirmware *firmware, - GBytes *bytes, - DfuFirmwareParseFlags flags, - GError **error); - -G_END_DECLS - -#endif /* __FU_WAC_FIRMWARE_H */ diff -Nru fwupd-1.1.4/plugins/wacomhid/fu-wac-module-bluetooth.c fwupd-1.2.5/plugins/wacomhid/fu-wac-module-bluetooth.c --- fwupd-1.1.4/plugins/wacomhid/fu-wac-module-bluetooth.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/wacomhid/fu-wac-module-bluetooth.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,188 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include - -#include "fu-wac-common.h" -#include "fu-wac-device.h" -#include "fu-wac-module-bluetooth.h" - -struct _FuWacModuleBluetooth -{ - FuWacModule parent_instance; -}; - -G_DEFINE_TYPE (FuWacModuleBluetooth, fu_wac_module_bluetooth, FU_TYPE_WAC_MODULE) - -#define FU_WAC_MODULE_BLUETOOTH_PAYLOAD_SZ 256 -#define FU_WAC_MODULE_BLUETOOTH_ADDR_USERDATA_START 0x3000 -#define FU_WAC_MODULE_BLUETOOTH_ADDR_USERDATA_STOP 0x8000 - -typedef struct { - guint8 preamble[7]; - guint8 addr[3]; - guint8 crc; - guint8 cdata[FU_WAC_MODULE_BLUETOOTH_PAYLOAD_SZ]; -} FuWacModuleBluetoothBlockData; - -static void -fu_wac_module_bluetooth_calculate_crc_byte (guint8 *crc, guint8 data) -{ - guint8 c[8]; - guint8 m[8]; - guint8 r[8]; - - /* find out what bits are set */ - for (guint i = 0; i < 8; i++) { - c[i] = (*crc & 1 << i) > 0; - m[i] = (data & 1 << i) > 0; - } - - /* do CRC on byte */ - r[7] = (c[7] ^ m[4] ^ c[3] ^ m[3] ^ c[4] ^ m[6] ^ c[1] ^ m[0]); - r[6] = (c[6] ^ m[5] ^ c[2] ^ m[4] ^ c[3] ^ m[7] ^ c[0] ^ m[1]); - r[5] = (c[5] ^ m[6] ^ c[1] ^ m[5] ^ c[2] ^ m[2]); - r[4] = (c[4] ^ m[7] ^ c[0] ^ m[6] ^ c[1] ^ m[3]); - r[3] = (m[7] ^ m[0] ^ c[7] ^ c[0] ^ m[3] ^ c[4] ^ m[6] ^ c[1]); - r[2] = (m[1] ^ c[6] ^ m[0] ^ c[7] ^ m[3] ^ c[4] ^ m[7] ^ c[0] ^ m[6] ^ c[1]); - r[1] = (m[2] ^ c[5] ^ m[1] ^ c[6] ^ m[4] ^ c[3] ^ m[7] ^ c[0]); - r[0] = (m[3] ^ c[4] ^ m[2] ^ c[5] ^ m[5] ^ c[2]); - - /* copy back into CRC */ - *crc = 0; - for (guint i = 0; i < 8; i++) { - if (r[i] == 0) - continue; - *crc |= (1 << i); - } -} - -static guint8 -fu_wac_module_bluetooth_calculate_crc (const guint8 *data, gsize sz) -{ - guint8 crc = 0; - for (gsize i = 0; i < sz; i++) - fu_wac_module_bluetooth_calculate_crc_byte (&crc, data[i]); - return crc; -} - -static GPtrArray * -fu_wac_module_bluetooth_parse_blocks (const guint8 *data, gsize sz, gboolean skip_user_data) -{ - const guint8 preamble[] = {0x02, 0x00, 0x0f, 0x06, 0x01, 0x08, 0x01}; - GPtrArray *blocks = g_ptr_array_new_with_free_func (g_free); - for (guint addr = 0x0; addr < sz; addr += FU_WAC_MODULE_BLUETOOTH_PAYLOAD_SZ) { - FuWacModuleBluetoothBlockData *bd; - gsize cdata_sz = FU_WAC_MODULE_BLUETOOTH_PAYLOAD_SZ; - - /* user data area */ - if (skip_user_data && - addr >= FU_WAC_MODULE_BLUETOOTH_ADDR_USERDATA_START && - addr < FU_WAC_MODULE_BLUETOOTH_ADDR_USERDATA_STOP) - continue; - - bd = g_new0 (FuWacModuleBluetoothBlockData, 1); - memcpy (bd->preamble, preamble, sizeof (preamble)); - bd->addr[0] = (addr >> 16) & 0xff; - bd->addr[1] = (addr >> 8) & 0xff; - bd->addr[2] = addr & 0xff; - memset (bd->cdata, 0xff, FU_WAC_MODULE_BLUETOOTH_PAYLOAD_SZ); - - /* if file is not in multiples of payload size */ - if (addr + FU_WAC_MODULE_BLUETOOTH_PAYLOAD_SZ >= sz) - cdata_sz = sz - addr; - memcpy (bd->cdata, data + addr, cdata_sz); - bd->crc = fu_wac_module_bluetooth_calculate_crc (bd->cdata, - FU_WAC_MODULE_BLUETOOTH_PAYLOAD_SZ); - g_ptr_array_add (blocks, bd); - } - return blocks; -} - -static gboolean -fu_wac_module_bluetooth_write_firmware (FuDevice *device, GBytes *blob, GError **error) -{ - FuWacDevice *parent = FU_WAC_DEVICE (fu_device_get_parent (device)); - FuWacModule *self = FU_WAC_MODULE (device); - const guint8 *data; - gsize len = 0; - gsize blocks_total = 0; - const guint8 buf_start[] = { 0x00 }; - g_autoptr(GPtrArray) blocks = NULL; - g_autoptr(GBytes) blob_start = g_bytes_new_static (buf_start, 1); - - /* build each data packet */ - data = g_bytes_get_data (blob, &len); - blocks = fu_wac_module_bluetooth_parse_blocks (data, len, TRUE); - blocks_total = blocks->len + 2; - - /* start, which will erase the module */ - fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); - if (!fu_wac_module_set_feature (self, FU_WAC_MODULE_COMMAND_START, blob_start, error)) - return FALSE; - - /* update progress */ - fu_device_set_progress_full (device, 1, blocks_total); - - /* data */ - fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); - for (guint i = 0; i < blocks->len; i++) { - FuWacModuleBluetoothBlockData *bd = g_ptr_array_index (blocks, i); - guint8 buf[256+11]; - g_autoptr(GBytes) blob_chunk = NULL; - - /* build data packet */ - memset (buf, 0xff, sizeof(buf)); - memcpy(&buf[0], bd->preamble, 7); - memcpy(&buf[7], bd->addr, 3); - buf[10] = bd->crc; - memcpy (&buf[11], bd->cdata, sizeof(bd->cdata)); - blob_chunk = g_bytes_new (buf, sizeof(buf)); - if (!fu_wac_module_set_feature (self, FU_WAC_MODULE_COMMAND_DATA, - blob_chunk, error)) - return FALSE; - - /* update progress */ - fu_device_set_progress_full (device, i + 1, blocks_total); - } - - /* end */ - if (!fu_wac_module_set_feature (self, FU_WAC_MODULE_COMMAND_END, NULL, error)) - return FALSE; - - /* update progress */ - fu_device_set_progress_full (device, blocks_total, blocks_total); - - /* reboot */ - fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); - return fu_wac_device_update_reset (parent, error); -} - -static void -fu_wac_module_bluetooth_init (FuWacModuleBluetooth *self) -{ - fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); -} - -static void -fu_wac_module_bluetooth_class_init (FuWacModuleBluetoothClass *klass) -{ - FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - klass_device->write_firmware = fu_wac_module_bluetooth_write_firmware; -} - -FuWacModule * -fu_wac_module_bluetooth_new (GUsbDevice *usb_device) -{ - FuWacModule *module = NULL; - module = g_object_new (FU_TYPE_WAC_MODULE_BLUETOOTH, - "usb-device", usb_device, - "fw-type", FU_WAC_MODULE_FW_TYPE_BLUETOOTH, - NULL); - return module; -} diff -Nru fwupd-1.1.4/plugins/wacomhid/fu-wac-module-bluetooth.h fwupd-1.2.5/plugins/wacomhid/fu-wac-module-bluetooth.h --- fwupd-1.1.4/plugins/wacomhid/fu-wac-module-bluetooth.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/wacomhid/fu-wac-module-bluetooth.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#ifndef __FU_WAC_MODULE_BLUETOOTH_H -#define __FU_WAC_MODULE_BLUETOOTH_H - -#include "fu-wac-module.h" - -G_BEGIN_DECLS - -#define FU_TYPE_WAC_MODULE_BLUETOOTH (fu_wac_module_bluetooth_get_type ()) -G_DECLARE_FINAL_TYPE (FuWacModuleBluetooth, fu_wac_module_bluetooth, FU, WAC_MODULE_BLUETOOTH, FuWacModule) - -FuWacModule *fu_wac_module_bluetooth_new (GUsbDevice *usb_device); - -G_END_DECLS - -#endif /* __FU_WAC_MODULE_BLUETOOTH_H */ diff -Nru fwupd-1.1.4/plugins/wacomhid/fu-wac-module.c fwupd-1.2.5/plugins/wacomhid/fu-wac-module.c --- fwupd-1.1.4/plugins/wacomhid/fu-wac-module.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/wacomhid/fu-wac-module.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,355 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include - -#include "fu-wac-module.h" -#include "fu-wac-common.h" -#include "fu-wac-device.h" - -#include "dfu-common.h" -#include "dfu-firmware.h" - -#define FU_WAC_MODLE_STATUS_OK 0 -#define FU_WAC_MODLE_STATUS_BUSY 1 -#define FU_WAC_MODLE_STATUS_ERR_CRC 2 -#define FU_WAC_MODLE_STATUS_ERR_CMD 3 -#define FU_WAC_MODLE_STATUS_ERR_HW_ACCESS_FAIL 4 -#define FU_WAC_MODLE_STATUS_ERR_FLASH_NO_SUPPORT 5 -#define FU_WAC_MODLE_STATUS_ERR_MODE_WRONG 6 -#define FU_WAC_MODLE_STATUS_ERR_MPU_NO_SUPPORT 7 -#define FU_WAC_MODLE_STATUS_ERR_VERSION_NO_SUPPORT 8 -#define FU_WAC_MODLE_STATUS_ERR_ERASE 9 -#define FU_WAC_MODLE_STATUS_ERR_WRITE 10 -#define FU_WAC_MODLE_STATUS_ERR_EXIT 11 -#define FU_WAC_MODLE_STATUS_ERR 12 -#define FU_WAC_MODLE_STATUS_ERR_INVALID_OP 13 -#define FU_WAC_MODLE_STATUS_ERR_WRONG_IMAGE 14 - -typedef struct { - GUsbDevice *usb_device; - guint8 fw_type; - guint8 command; - guint8 status; -} FuWacModulePrivate; - -G_DEFINE_TYPE_WITH_PRIVATE (FuWacModule, fu_wac_module, FU_TYPE_DEVICE) -#define GET_PRIVATE(o) (fu_wac_module_get_instance_private (o)) - -enum { - PROP_0, - PROP_FW_TYPE, - PROP_USB_DEVICE, - PROP_LAST -}; - -static const gchar * -fu_wac_module_fw_type_to_string (guint8 fw_type) -{ - if (fw_type == FU_WAC_MODULE_FW_TYPE_TOUCH) - return "touch"; - if (fw_type == FU_WAC_MODULE_FW_TYPE_BLUETOOTH) - return "bluetooth"; - if (fw_type == FU_WAC_MODULE_FW_TYPE_EMR_CORRECTION) - return "emr-correction"; - if (fw_type == FU_WAC_MODULE_FW_TYPE_BLUETOOTH_HID) - return "bluetooth-hid"; - return NULL; -} - -static const gchar * -fu_wac_module_command_to_string (guint8 command) -{ - if (command == FU_WAC_MODULE_COMMAND_START) - return "start"; - if (command == FU_WAC_MODULE_COMMAND_DATA) - return "data"; - if (command == FU_WAC_MODULE_COMMAND_END) - return "end"; - return NULL; -} - -static const gchar * -fu_wac_module_status_to_string (guint8 status) -{ - if (status == FU_WAC_MODLE_STATUS_OK) - return "ok"; - if (status == FU_WAC_MODLE_STATUS_BUSY) - return "busy"; - if (status == FU_WAC_MODLE_STATUS_ERR_CRC) - return "err-crc"; - if (status == FU_WAC_MODLE_STATUS_ERR_CMD) - return "err-cmd"; - if (status == FU_WAC_MODLE_STATUS_ERR_HW_ACCESS_FAIL) - return "err-hw-access-fail"; - if (status == FU_WAC_MODLE_STATUS_ERR_FLASH_NO_SUPPORT) - return "err-flash-no-support"; - if (status == FU_WAC_MODLE_STATUS_ERR_MODE_WRONG) - return "err-mode-wrong"; - if (status == FU_WAC_MODLE_STATUS_ERR_MPU_NO_SUPPORT) - return "err-mpu-no-support"; - if (status == FU_WAC_MODLE_STATUS_ERR_VERSION_NO_SUPPORT) - return "erro-version-no-support"; - if (status == FU_WAC_MODLE_STATUS_ERR_ERASE) - return "err-erase"; - if (status == FU_WAC_MODLE_STATUS_ERR_WRITE) - return "err-write"; - if (status == FU_WAC_MODLE_STATUS_ERR_EXIT) - return "err-exit"; - if (status == FU_WAC_MODLE_STATUS_ERR) - return "err-err"; - if (status == FU_WAC_MODLE_STATUS_ERR_INVALID_OP) - return "err-invalid-op"; - if (status == FU_WAC_MODLE_STATUS_ERR_WRONG_IMAGE) - return "err-wrong-image"; - return NULL; -} - -static void -fu_wac_module_to_string (FuDevice *device, GString *str) -{ - FuWacModule *self = FU_WAC_MODULE (device); - FuWacModulePrivate *priv = GET_PRIVATE (self); - g_string_append (str, " FuWacSubModule:\n"); - g_string_append_printf (str, " fw-type:\t\t%s\n", - fu_wac_module_fw_type_to_string (priv->fw_type)); - g_string_append_printf (str, " status:\t\t%s\n", - fu_wac_module_status_to_string (priv->status)); - g_string_append_printf (str, " command:\t\t%s\n", - fu_wac_module_command_to_string (priv->command)); -} - -static gboolean -fu_wac_module_refresh (FuWacModule *self, GError **error) -{ - FuWacDevice *parent_device = FU_WAC_DEVICE (fu_device_get_parent (FU_DEVICE (self))); - FuWacModulePrivate *priv = GET_PRIVATE (self); - guint8 buf[] = { [0] = FU_WAC_REPORT_ID_MODULE, - [1 ... FU_WAC_PACKET_LEN - 1] = 0xff }; - - /* get from hardware */ - if (!fu_wac_device_get_feature_report (parent_device, buf, sizeof(buf), - FU_WAC_DEVICE_FEATURE_FLAG_ALLOW_TRUNC, - error)) { - g_prefix_error (error, "failed to refresh status: "); - return FALSE; - } - - /* check fw type */ - if (priv->fw_type != buf[1]) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Submodule GetFeature fw_Type invalid " - "got 0x%02x expected 0x%02x", - (guint) buf[1], (guint) priv->fw_type); - return FALSE; - } - - /* current phase */ - priv->command = buf[2]; - g_debug ("command: %s", fu_wac_module_command_to_string (priv->command)); - - /* current status */ - priv->status = buf[3]; - g_debug ("status: %s", fu_wac_module_status_to_string (priv->status)); - - /* success */ - return TRUE; -} - -gboolean -fu_wac_module_set_feature (FuWacModule *self, - guint8 command, - GBytes *blob, /* optional */ - GError **error) -{ - FuWacDevice *parent_device = FU_WAC_DEVICE (fu_device_get_parent (FU_DEVICE (self))); - FuWacModulePrivate *priv = GET_PRIVATE (self); - const guint8 *data; - gsize len = 0; - guint busy_poll_loops = 100; /* 1s */ - guint8 buf[] = { [0] = FU_WAC_REPORT_ID_MODULE, - [1] = priv->fw_type, - [2] = command, - [3 ... FU_WAC_PACKET_LEN - 1] = 0xff }; - - /* verify the size of the blob */ - if (blob != NULL) { - data = g_bytes_get_data (blob, &len); - if (len > 509) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Submodule SetFeature blob larger than " - "buffer %" G_GSIZE_FORMAT, len); - return FALSE; - } - } - - /* build packet */ - if (len > 0) - memcpy (&buf[3], data, len); - - /* tell the daemon the current status */ - switch (command) { - case FU_WAC_MODULE_COMMAND_START: - fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_ERASE); - break; - case FU_WAC_MODULE_COMMAND_DATA: - fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_WRITE); - break; - case FU_WAC_MODULE_COMMAND_END: - fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_VERIFY); - break; - default: - break; - } - - /* send to hardware */ - if (!fu_wac_device_set_feature_report (parent_device, buf, sizeof(buf), - FU_WAC_DEVICE_FEATURE_FLAG_ALLOW_TRUNC, - error)) { - g_prefix_error (error, "failed to set module feature: "); - return FALSE; - } - - /* special case StartProgram, as it can take much longer as it is - * erasing the blocks (15s) */ - if (command == FU_WAC_MODULE_COMMAND_START) - busy_poll_loops *= 15; - - /* wait for hardware */ - for (guint i = 0; i < busy_poll_loops; i++) { - if (!fu_wac_module_refresh (self, error)) - return FALSE; - if (priv->status == FU_WAC_MODLE_STATUS_BUSY) { - g_usleep (10000); /* 10ms */ - continue; - } - if (priv->status == FU_WAC_MODLE_STATUS_OK) - return TRUE; - } - - /* the hardware never responded */ - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Failed to SetFeature: %s", - fu_wac_module_status_to_string (priv->status)); - return FALSE; -} - -static void -fu_wac_module_get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - FuWacModule *self = FU_WAC_MODULE (object); - FuWacModulePrivate *priv = GET_PRIVATE (self); - switch (prop_id) { - case PROP_FW_TYPE: - g_value_set_uint (value, priv->fw_type); - break; - case PROP_USB_DEVICE: - g_value_set_object (value, priv->usb_device); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -fu_wac_module_set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - FuWacModule *self = FU_WAC_MODULE (object); - FuWacModulePrivate *priv = GET_PRIVATE (self); - switch (prop_id) { - case PROP_FW_TYPE: - priv->fw_type = g_value_get_uint (value); - break; - case PROP_USB_DEVICE: - g_set_object (&priv->usb_device, g_value_get_object (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -fu_wac_module_init (FuWacModule *self) -{ -} - -static void -fu_wac_module_constructed (GObject *object) -{ - FuWacModule *self = FU_WAC_MODULE (object); - FuWacModulePrivate *priv = GET_PRIVATE (self); - g_autofree gchar *devid = NULL; - g_autofree gchar *vendor_id = NULL; - - /* set vendor ID */ - vendor_id = g_strdup_printf ("USB:0x%04X", g_usb_device_get_vid (priv->usb_device)); - fu_device_set_vendor_id (FU_DEVICE (self), vendor_id); - - /* set USB physical and logical IDs */ - fu_device_set_physical_id (FU_DEVICE (self), - g_usb_device_get_platform_id (priv->usb_device)); - fu_device_set_logical_id (FU_DEVICE (self), - fu_wac_module_fw_type_to_string (priv->fw_type)); - - /* append the firmware kind to the generated GUID */ - devid = g_strdup_printf ("USB\\VID_%04X&PID_%04X-%s", - g_usb_device_get_vid (priv->usb_device), - g_usb_device_get_pid (priv->usb_device), - fu_wac_module_fw_type_to_string (priv->fw_type)); - fu_device_add_guid (FU_DEVICE (self), devid); - - G_OBJECT_CLASS (fu_wac_module_parent_class)->constructed (object); -} - -static void -fu_wac_module_finalize (GObject *object) -{ - FuWacModule *self = FU_WAC_MODULE (object); - FuWacModulePrivate *priv = GET_PRIVATE (self); - if (priv->usb_device != NULL) - g_object_unref (priv->usb_device); - G_OBJECT_CLASS (fu_wac_module_parent_class)->finalize (object); -} - -static void -fu_wac_module_class_init (FuWacModuleClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GParamSpec *pspec; - FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - - /* properties */ - object_class->get_property = fu_wac_module_get_property; - object_class->set_property = fu_wac_module_set_property; - pspec = g_param_spec_object ("usb-device", NULL, NULL, - G_USB_TYPE_DEVICE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT | - G_PARAM_STATIC_NAME); - g_object_class_install_property (object_class, PROP_USB_DEVICE, pspec); - pspec = g_param_spec_uint ("fw-type", NULL, NULL, - 0, G_MAXUINT, 0, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_NAME); - g_object_class_install_property (object_class, PROP_FW_TYPE, pspec); - - object_class->constructed = fu_wac_module_constructed; - object_class->finalize = fu_wac_module_finalize; - klass_device->to_string = fu_wac_module_to_string; -} diff -Nru fwupd-1.1.4/plugins/wacomhid/fu-wac-module.h fwupd-1.2.5/plugins/wacomhid/fu-wac-module.h --- fwupd-1.1.4/plugins/wacomhid/fu-wac-module.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/wacomhid/fu-wac-module.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#ifndef __FU_WAC_MODULE_H -#define __FU_WAC_MODULE_H - -#include "fu-plugin.h" - -G_BEGIN_DECLS - -#define FU_TYPE_WAC_MODULE (fu_wac_module_get_type ()) -G_DECLARE_DERIVABLE_TYPE (FuWacModule, fu_wac_module, FU, WAC_MODULE, FuDevice) - -struct _FuWacModuleClass -{ - FuDeviceClass parent_class; -}; - -#define FU_WAC_MODULE_FW_TYPE_TOUCH 0x00 -#define FU_WAC_MODULE_FW_TYPE_BLUETOOTH 0x01 -#define FU_WAC_MODULE_FW_TYPE_EMR_CORRECTION 0x02 -#define FU_WAC_MODULE_FW_TYPE_BLUETOOTH_HID 0x03 -#define FU_WAC_MODULE_FW_TYPE_MAIN 0x3f - -#define FU_WAC_MODULE_COMMAND_START 0x01 -#define FU_WAC_MODULE_COMMAND_DATA 0x02 -#define FU_WAC_MODULE_COMMAND_END 0x03 - -gboolean fu_wac_module_set_feature (FuWacModule *self, - guint8 command, - GBytes *blob, - GError **error); - -G_END_DECLS - -#endif /* __FU_WAC_MODULE_H */ diff -Nru fwupd-1.1.4/plugins/wacomhid/fu-wac-module-touch.c fwupd-1.2.5/plugins/wacomhid/fu-wac-module-touch.c --- fwupd-1.1.4/plugins/wacomhid/fu-wac-module-touch.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/wacomhid/fu-wac-module-touch.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include - -#include "fu-wac-device.h" -#include "fu-wac-module-touch.h" - -#include "fu-chunk.h" - -struct _FuWacModuleTouch -{ - FuWacModule parent_instance; -}; - -G_DEFINE_TYPE (FuWacModuleTouch, fu_wac_module_touch, FU_TYPE_WAC_MODULE) - -static gboolean -fu_wac_module_touch_write_firmware (FuDevice *device, GBytes *blob, GError **error) -{ - FuWacDevice *parent = FU_WAC_DEVICE (fu_device_get_parent (device)); - FuWacModule *self = FU_WAC_MODULE (device); - const guint8 *data; - gsize blocks_total = 0; - gsize len = 0; - g_autoptr(GPtrArray) chunks = NULL; - - /* build each data packet */ - data = g_bytes_get_data (blob, &len); - if (len % 128 != 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "firmware has to be padded to 128b"); - return FALSE; - } - chunks = fu_chunk_array_new (data, (guint32) len, - 0x0, /* addr_start */ - 0x0, /* page_sz */ - 128); /* packet_sz */ - blocks_total = chunks->len + 2; - - /* start, which will erase the module */ - fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); - if (!fu_wac_module_set_feature (self, FU_WAC_MODULE_COMMAND_START, NULL, error)) - return FALSE; - - /* update progress */ - fu_device_set_progress_full (device, 1, blocks_total); - - /* data */ - fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); - for (guint i = 0; i < chunks->len; i++) { - FuChunk *chk = g_ptr_array_index (chunks, i); - guint8 buf[128+7]; - g_autoptr(GBytes) blob_chunk = NULL; - - /* build G11T data packet */ - memset (buf, 0xff, sizeof(buf)); - buf[0] = 0x01; /* writing */ - fu_common_write_uint32 (&buf[1], chk->address, G_LITTLE_ENDIAN); - buf[5] = chk->idx; - memcpy (&buf[6], chk->data, chk->data_sz); - blob_chunk = g_bytes_new (buf, sizeof(buf)); - if (!fu_wac_module_set_feature (self, FU_WAC_MODULE_COMMAND_DATA, - blob_chunk, error)) - return FALSE; - - /* update progress */ - fu_device_set_progress_full (device, i + 1, blocks_total); - } - - /* end */ - if (!fu_wac_module_set_feature (self, FU_WAC_MODULE_COMMAND_END, NULL, error)) - return FALSE; - - /* update progress */ - fu_device_set_progress_full (device, blocks_total, blocks_total); - - /* reboot */ - fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); - return fu_wac_device_update_reset (parent, error); -} - -static void -fu_wac_module_touch_init (FuWacModuleTouch *self) -{ - fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); -} - -static void -fu_wac_module_touch_class_init (FuWacModuleTouchClass *klass) -{ - FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - klass_device->write_firmware = fu_wac_module_touch_write_firmware; -} - -FuWacModule * -fu_wac_module_touch_new (GUsbDevice *usb_device) -{ - FuWacModule *module = NULL; - module = g_object_new (FU_TYPE_WAC_MODULE_TOUCH, - "usb-device", usb_device, - "fw-type", FU_WAC_MODULE_FW_TYPE_TOUCH, - NULL); - return module; -} diff -Nru fwupd-1.1.4/plugins/wacomhid/fu-wac-module-touch.h fwupd-1.2.5/plugins/wacomhid/fu-wac-module-touch.h --- fwupd-1.1.4/plugins/wacomhid/fu-wac-module-touch.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/wacomhid/fu-wac-module-touch.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#ifndef __FU_WAC_MODULE_TOUCH_H -#define __FU_WAC_MODULE_TOUCH_H - -#include "fu-wac-module.h" - -G_BEGIN_DECLS - -#define FU_TYPE_WAC_MODULE_TOUCH (fu_wac_module_touch_get_type ()) -G_DECLARE_FINAL_TYPE (FuWacModuleTouch, fu_wac_module_touch, FU, WAC_MODULE_TOUCH, FuWacModule) - -FuWacModule *fu_wac_module_touch_new (GUsbDevice *usb_device); - -G_END_DECLS - -#endif /* __FU_WAC_MODULE_TOUCH_H */ diff -Nru fwupd-1.1.4/plugins/wacomhid/meson.build fwupd-1.2.5/plugins/wacomhid/meson.build --- fwupd-1.1.4/plugins/wacomhid/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/wacomhid/meson.build 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -cargs = ['-DG_LOG_DOMAIN="FuPluginWac"'] - -install_data(['wacomhid.quirk'], - install_dir: join_paths(datadir, 'fwupd', 'quirks.d') -) - -shared_module('fu_plugin_wacomhid', - sources : [ - 'fu-wac-common.c', - 'fu-wac-device.c', - 'fu-wac-firmware.c', - 'fu-wac-module.c', - 'fu-wac-module-bluetooth.c', - 'fu-wac-module-touch.c', - 'fu-plugin-wacomhid.c', - ], - include_directories : [ - include_directories('../..'), - include_directories('../dfu'), - include_directories('../../src'), - include_directories('../../libfwupd'), - ], - install : true, - install_dir: plugin_dir, - c_args : cargs, - dependencies : [ - plugin_deps, - ], - link_with : [ - dfu, - ], -) - -if get_option('tests') - testdatadir = join_paths(meson.current_source_dir(), 'tests') - cargs += '-DTESTDATADIR="' + testdatadir + '"' - e = executable( - 'wacomhid-self-test', - sources : [ - 'fu-self-test.c', - 'fu-wac-common.c', - 'fu-wac-firmware.c', - ], - include_directories : [ - include_directories('..'), - include_directories('../dfu'), - include_directories('../..'), - include_directories('../../libfwupd'), - include_directories('../../src'), - ], - dependencies : [ - appstream_glib, - gio, - gusb, - gudev, - libm, - ], - link_with : [ - dfu, - fwupd, - libfwupdprivate, - ], - c_args : cargs - ) - test('wacomhid-self-test', e) -endif diff -Nru fwupd-1.1.4/plugins/wacomhid/README.md fwupd-1.2.5/plugins/wacomhid/README.md --- fwupd-1.1.4/plugins/wacomhid/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/wacomhid/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -Wacom HID Support -================= - -Introduction ------------- - -Wacom provides interactive pen displays, pen tablets, and styluses to equip and -inspire everyone make the world a more creative place. - -From 2016 Wacom has been using a HID-based proprietary flashing algorithm which -has been documented by support team at Wacom and provided under NDA under the -understanding it would be used to build a plugin under a LGPLv2+ licence. - -Wacom devices are actually composite devices, with the main ARM CPU being -programmed using a more complicated erase, write, verify algorithm based -on a historical update protocol. The "sub-module" devices use a newer protocol, -again based on HID, but are handled differently depending on thier type. diff -Nru fwupd-1.1.4/plugins/wacomhid/wacomhid.quirk fwupd-1.2.5/plugins/wacomhid/wacomhid.quirk --- fwupd-1.1.4/plugins/wacomhid/wacomhid.quirk 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/plugins/wacomhid/wacomhid.quirk 1970-01-01 00:00:00.000000000 +0000 @@ -1,99 +0,0 @@ -# MobileStudio Pro 13 (touch) [DTH-W1320] -[DeviceInstanceId=USB\VID_056A&PID_034A] -Plugin = wacomhid -Flags = use-runtime-version - -# MobileStudio Pro 16 (touch) [DTH-W1620] -[DeviceInstanceId=USB\VID_056A&PID_034B] -Plugin = wacomhid -Flags = use-runtime-version - -# MobileStudio Pro 13 (pen/pad) [DTH-W1320] -[DeviceInstanceId=USB\VID_056A&PID_034D] -Plugin = wacomhid -Flags = use-runtime-version - -# MobileStudio Pro 16 (pen/pad) [DTH-W1620] -[DeviceInstanceId=USB\VID_056A&PID_034E] -Plugin = wacomhid -Flags = use-runtime-version - -# Intuos Pro medium (2nd-gen BT) [PTH-660] -[DeviceInstanceId=USB\VID_056A&PID_0360] -Plugin = wacomhid -Flags = use-runtime-version - -# Intuos Pro large (2nd-gen BT) [PTH-860] -[DeviceInstanceId=USB\VID_056A&PID_0361] -Plugin = wacomhid -Flags = use-runtime-version - -# Intuos BT S (3rd-gen BT) [CTL-4100WL] -[DeviceInstanceId=USB\VID_056A&PID_0377] -Plugin = wacomhid -Flags = use-runtime-version - -# Intuos BT M (3rd-gen BT) [CTL-6100WL] -[DeviceInstanceId=USB\VID_056A&PID_0379] -Plugin = wacomhid -Flags = use-runtime-version - -# Cintiq Pro 13 (pen/pad) [DTH-1320] -[DeviceInstanceId=USB\VID_056A&PID_034F] -Plugin = wacomhid -Flags = use-runtime-version - -# Cintiq Pro 16 (pen/pad) [DTH-1620] -[DeviceInstanceId=USB\VID_056A&PID_0350] -Plugin = wacomhid -Flags = use-runtime-version - -# Cintiq Pro 13 (touch) [DTH-1320] -[DeviceInstanceId=USB\VID_056A&PID_0353] -Plugin = wacomhid -Flags = use-runtime-version - -# Cintiq Pro 16 (touch) [DTH-1620] -[DeviceInstanceId=USB\VID_056A&PID_0354] -Plugin = wacomhid -Flags = use-runtime-version - -# Intuos Pro medium (2nd-gen USB) [PTH-660] -[DeviceInstanceId=USB\VID_056A&PID_0357] -Plugin = wacomhid -Flags = use-runtime-version - -# Intuos Pro large (2nd-gen USB) [PTH-860] -[DeviceInstanceId=USB\VID_056A&PID_0358] -Plugin = wacomhid -Flags = use-runtime-version - -# Pen [DTH-1152] -[DeviceInstanceId=USB\VID_056A&PID_035A] -Plugin = wacomhid -Flags = use-runtime-version - -# Touch [DTH-1152] -[DeviceInstanceId=USB\VID_056A&PID_0368] -Plugin = wacomhid -Flags = use-runtime-version - -# Intuos S 3rd-gen (USB) [CTL-4100] -[DeviceInstanceId=USB\VID_056A&PID_0374] -Plugin = wacomhid -Flags = use-runtime-version - -# Intuos M 3rd-gen (USB) [NA] -[DeviceInstanceId=USB\VID_056A&PID_0375] -Plugin = wacomhid -Flags = use-runtime-version - -# Intuos BT S 3rd-gen (USB) [CTL-4100WL] -[DeviceInstanceId=USB\VID_056A&PID_0376] -Plugin = wacomhid -Flags = use-runtime-version - -# Intuos BT M 3rd-gen (USB) [CTL-6100WL] -[DeviceInstanceId=USB\VID_056A&PID_0378] -Plugin = wacomhid -Flags = use-runtime-version diff -Nru fwupd-1.1.4/plugins/wacom-raw/data/hid-recorder.txt fwupd-1.2.5/plugins/wacom-raw/data/hid-recorder.txt --- fwupd-1.1.4/plugins/wacom-raw/data/hid-recorder.txt 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-raw/data/hid-recorder.txt 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,470 @@ +# WCOM4875:00 056A:4875 +# 0x05, 0x0d, // Usage Page (Digitizers) 0 +# 0x09, 0x04, // Usage (Touch Screen) 2 +# 0xa1, 0x01, // Collection (Application) 4 +# 0x85, 0x0c, // Report ID (12) 6 +# 0x95, 0x01, // Report Count (1) 8 +# 0x75, 0x08, // Report Size (8) 10 +# 0x26, 0xff, 0x00, // Logical Maximum (255) 12 +# 0x15, 0x00, // Logical Minimum (0) 15 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 17 +# 0x09, 0x54, // Usage (Contact Count) 19 +# 0x81, 0x02, // Input (Data,Var,Abs) 21 +# 0x05, 0x0d, // Usage Page (Digitizers) 23 +# 0x09, 0x22, // Usage (Finger) 25 +# 0xa1, 0x02, // Collection (Logical) 27 +# 0x09, 0x42, // Usage (Tip Switch) 29 +# 0x15, 0x00, // Logical Minimum (0) 31 +# 0x25, 0x01, // Logical Maximum (1) 33 +# 0x75, 0x01, // Report Size (1) 35 +# 0x95, 0x01, // Report Count (1) 37 +# 0x81, 0x02, // Input (Data,Var,Abs) 39 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 41 +# 0x09, 0x47, // Usage (Confidence) 43 +# 0x81, 0x02, // Input (Data,Var,Abs) 45 +# 0x95, 0x05, // Report Count (5) 47 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 49 +# 0x75, 0x10, // Report Size (16) 51 +# 0x09, 0x51, // Usage (Contact Id) 53 +# 0x95, 0x01, // Report Count (1) 55 +# 0x81, 0x02, // Input (Data,Var,Abs) 57 +# 0x05, 0x01, // Usage Page (Generic Desktop) 59 +# 0x75, 0x10, // Report Size (16) 61 +# 0x95, 0x01, // Report Count (1) 63 +# 0x55, 0x0e, // Unit Exponent (-2) 65 +# 0x65, 0x11, // Unit (Centimeter,SILinear) 67 +# 0x09, 0x30, // Usage (X) 69 +# 0x26, 0xc8, 0x35, // Logical Maximum (13768) 71 +# 0x35, 0x00, // Physical Minimum (0) 74 +# 0x46, 0x72, 0x0d, // Physical Maximum (3442) 76 +# 0x81, 0x02, // Input (Data,Var,Abs) 79 +# 0x46, 0x90, 0x07, // Physical Maximum (1936) 81 +# 0x09, 0x31, // Usage (Y) 84 +# 0x26, 0x40, 0x1e, // Logical Maximum (7744) 86 +# 0x81, 0x02, // Input (Data,Var,Abs) 89 +# 0xc0, // End Collection 91 +# 0x05, 0x0d, // Usage Page (Digitizers) 92 +# 0x09, 0x22, // Usage (Finger) 94 +# 0xa1, 0x02, // Collection (Logical) 96 +# 0x09, 0x42, // Usage (Tip Switch) 98 +# 0x15, 0x00, // Logical Minimum (0) 100 +# 0x25, 0x01, // Logical Maximum (1) 102 +# 0x75, 0x01, // Report Size (1) 104 +# 0x95, 0x01, // Report Count (1) 106 +# 0x81, 0x02, // Input (Data,Var,Abs) 108 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 110 +# 0x09, 0x47, // Usage (Confidence) 112 +# 0x81, 0x02, // Input (Data,Var,Abs) 114 +# 0x95, 0x05, // Report Count (5) 116 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 118 +# 0x75, 0x10, // Report Size (16) 120 +# 0x09, 0x51, // Usage (Contact Id) 122 +# 0x95, 0x01, // Report Count (1) 124 +# 0x81, 0x02, // Input (Data,Var,Abs) 126 +# 0x05, 0x01, // Usage Page (Generic Desktop) 128 +# 0x75, 0x10, // Report Size (16) 130 +# 0x95, 0x01, // Report Count (1) 132 +# 0x55, 0x0e, // Unit Exponent (-2) 134 +# 0x65, 0x11, // Unit (Centimeter,SILinear) 136 +# 0x09, 0x30, // Usage (X) 138 +# 0x26, 0xc8, 0x35, // Logical Maximum (13768) 140 +# 0x35, 0x00, // Physical Minimum (0) 143 +# 0x46, 0x72, 0x0d, // Physical Maximum (3442) 145 +# 0x81, 0x02, // Input (Data,Var,Abs) 148 +# 0x46, 0x90, 0x07, // Physical Maximum (1936) 150 +# 0x09, 0x31, // Usage (Y) 153 +# 0x26, 0x40, 0x1e, // Logical Maximum (7744) 155 +# 0x81, 0x02, // Input (Data,Var,Abs) 158 +# 0xc0, // End Collection 160 +# 0x05, 0x0d, // Usage Page (Digitizers) 161 +# 0x09, 0x22, // Usage (Finger) 163 +# 0xa1, 0x02, // Collection (Logical) 165 +# 0x09, 0x42, // Usage (Tip Switch) 167 +# 0x15, 0x00, // Logical Minimum (0) 169 +# 0x25, 0x01, // Logical Maximum (1) 171 +# 0x75, 0x01, // Report Size (1) 173 +# 0x95, 0x01, // Report Count (1) 175 +# 0x81, 0x02, // Input (Data,Var,Abs) 177 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 179 +# 0x09, 0x47, // Usage (Confidence) 181 +# 0x81, 0x02, // Input (Data,Var,Abs) 183 +# 0x95, 0x05, // Report Count (5) 185 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 187 +# 0x75, 0x10, // Report Size (16) 189 +# 0x09, 0x51, // Usage (Contact Id) 191 +# 0x95, 0x01, // Report Count (1) 193 +# 0x81, 0x02, // Input (Data,Var,Abs) 195 +# 0x05, 0x01, // Usage Page (Generic Desktop) 197 +# 0x75, 0x10, // Report Size (16) 199 +# 0x95, 0x01, // Report Count (1) 201 +# 0x55, 0x0e, // Unit Exponent (-2) 203 +# 0x65, 0x11, // Unit (Centimeter,SILinear) 205 +# 0x09, 0x30, // Usage (X) 207 +# 0x26, 0xc8, 0x35, // Logical Maximum (13768) 209 +# 0x35, 0x00, // Physical Minimum (0) 212 +# 0x46, 0x72, 0x0d, // Physical Maximum (3442) 214 +# 0x81, 0x02, // Input (Data,Var,Abs) 217 +# 0x46, 0x90, 0x07, // Physical Maximum (1936) 219 +# 0x09, 0x31, // Usage (Y) 222 +# 0x26, 0x40, 0x1e, // Logical Maximum (7744) 224 +# 0x81, 0x02, // Input (Data,Var,Abs) 227 +# 0xc0, // End Collection 229 +# 0x05, 0x0d, // Usage Page (Digitizers) 230 +# 0x09, 0x22, // Usage (Finger) 232 +# 0xa1, 0x02, // Collection (Logical) 234 +# 0x09, 0x42, // Usage (Tip Switch) 236 +# 0x15, 0x00, // Logical Minimum (0) 238 +# 0x25, 0x01, // Logical Maximum (1) 240 +# 0x75, 0x01, // Report Size (1) 242 +# 0x95, 0x01, // Report Count (1) 244 +# 0x81, 0x02, // Input (Data,Var,Abs) 246 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 248 +# 0x09, 0x47, // Usage (Confidence) 250 +# 0x81, 0x02, // Input (Data,Var,Abs) 252 +# 0x95, 0x05, // Report Count (5) 254 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 256 +# 0x75, 0x10, // Report Size (16) 258 +# 0x09, 0x51, // Usage (Contact Id) 260 +# 0x95, 0x01, // Report Count (1) 262 +# 0x81, 0x02, // Input (Data,Var,Abs) 264 +# 0x05, 0x01, // Usage Page (Generic Desktop) 266 +# 0x75, 0x10, // Report Size (16) 268 +# 0x95, 0x01, // Report Count (1) 270 +# 0x55, 0x0e, // Unit Exponent (-2) 272 +# 0x65, 0x11, // Unit (Centimeter,SILinear) 274 +# 0x09, 0x30, // Usage (X) 276 +# 0x26, 0xc8, 0x35, // Logical Maximum (13768) 278 +# 0x35, 0x00, // Physical Minimum (0) 281 +# 0x46, 0x72, 0x0d, // Physical Maximum (3442) 283 +# 0x81, 0x02, // Input (Data,Var,Abs) 286 +# 0x46, 0x90, 0x07, // Physical Maximum (1936) 288 +# 0x09, 0x31, // Usage (Y) 291 +# 0x26, 0x40, 0x1e, // Logical Maximum (7744) 293 +# 0x81, 0x02, // Input (Data,Var,Abs) 296 +# 0xc0, // End Collection 298 +# 0x05, 0x0d, // Usage Page (Digitizers) 299 +# 0x09, 0x22, // Usage (Finger) 301 +# 0xa1, 0x02, // Collection (Logical) 303 +# 0x09, 0x42, // Usage (Tip Switch) 305 +# 0x15, 0x00, // Logical Minimum (0) 307 +# 0x25, 0x01, // Logical Maximum (1) 309 +# 0x75, 0x01, // Report Size (1) 311 +# 0x95, 0x01, // Report Count (1) 313 +# 0x81, 0x02, // Input (Data,Var,Abs) 315 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 317 +# 0x09, 0x47, // Usage (Confidence) 319 +# 0x81, 0x02, // Input (Data,Var,Abs) 321 +# 0x95, 0x05, // Report Count (5) 323 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 325 +# 0x75, 0x10, // Report Size (16) 327 +# 0x09, 0x51, // Usage (Contact Id) 329 +# 0x95, 0x01, // Report Count (1) 331 +# 0x81, 0x02, // Input (Data,Var,Abs) 333 +# 0x05, 0x01, // Usage Page (Generic Desktop) 335 +# 0x75, 0x10, // Report Size (16) 337 +# 0x95, 0x01, // Report Count (1) 339 +# 0x55, 0x0e, // Unit Exponent (-2) 341 +# 0x65, 0x11, // Unit (Centimeter,SILinear) 343 +# 0x09, 0x30, // Usage (X) 345 +# 0x26, 0xc8, 0x35, // Logical Maximum (13768) 347 +# 0x35, 0x00, // Physical Minimum (0) 350 +# 0x46, 0x72, 0x0d, // Physical Maximum (3442) 352 +# 0x81, 0x02, // Input (Data,Var,Abs) 355 +# 0x46, 0x90, 0x07, // Physical Maximum (1936) 357 +# 0x09, 0x31, // Usage (Y) 360 +# 0x26, 0x40, 0x1e, // Logical Maximum (7744) 362 +# 0x81, 0x02, // Input (Data,Var,Abs) 365 +# 0xc0, // End Collection 367 +# 0x05, 0x0d, // Usage Page (Digitizers) 368 +# 0x27, 0xff, 0xff, 0x00, 0x00, // Logical Maximum (65535) 370 +# 0x75, 0x10, // Report Size (16) 375 +# 0x95, 0x01, // Report Count (1) 377 +# 0x09, 0x56, // Usage (Scan Time) 379 +# 0x81, 0x02, // Input (Data,Var,Abs) 381 +# 0x85, 0x0c, // Report ID (12) 383 +# 0x09, 0x55, // Usage (Contact Max) 385 +# 0x75, 0x08, // Report Size (8) 387 +# 0x95, 0x01, // Report Count (1) 389 +# 0x26, 0xff, 0x00, // Logical Maximum (255) 391 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 394 +# 0x85, 0x0a, // Report ID (10) 396 +# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 398 +# 0x09, 0xc5, // Usage (Vendor Usage 0xc5) 401 +# 0x96, 0x00, 0x01, // Report Count (256) 403 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 406 +# 0xc0, // End Collection 408 +# 0x06, 0x11, 0xff, // Usage Page (Vendor Usage Page 0xff11) 409 +# 0x09, 0x11, // Usage (Vendor Usage 0x11) 412 +# 0xa1, 0x01, // Collection (Application) 414 +# 0x85, 0x03, // Report ID (3) 416 +# 0xa1, 0x02, // Collection (Logical) 418 +# 0x09, 0x00, // Usage (Vendor Usage 0x00) 420 +# 0x75, 0x08, // Report Size (8) 422 +# 0x15, 0x00, // Logical Minimum (0) 424 +# 0x26, 0xff, 0x00, // Logical Maximum (255) 426 +# 0x95, 0x27, // Report Count (39) 429 +# 0x81, 0x02, // Input (Data,Var,Abs) 431 +# 0xc0, // End Collection 433 +# 0x85, 0x02, // Report ID (2) 434 +# 0x09, 0x00, // Usage (Vendor Usage 0x00) 436 +# 0x95, 0x01, // Report Count (1) 438 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 440 +# 0x85, 0x03, // Report ID (3) 442 +# 0x09, 0x00, // Usage (Vendor Usage 0x00) 444 +# 0x95, 0x3f, // Report Count (63) 446 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 448 +# 0x85, 0x04, // Report ID (4) 450 +# 0x09, 0x00, // Usage (Vendor Usage 0x00) 452 +# 0x95, 0x0f, // Report Count (15) 454 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 456 +# 0x85, 0x07, // Report ID (7) 458 +# 0x09, 0x00, // Usage (Vendor Usage 0x00) 460 +# 0x96, 0x00, 0x01, // Report Count (256) 462 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 465 +# 0x85, 0x08, // Report ID (8) 467 +# 0x09, 0x00, // Usage (Vendor Usage 0x00) 469 +# 0x96, 0x87, 0x00, // Report Count (135) 471 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 474 +# 0x85, 0x09, // Report ID (9) 476 +# 0x09, 0x00, // Usage (Vendor Usage 0x00) 478 +# 0x96, 0x3f, 0x00, // Report Count (63) 480 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 483 +# 0x85, 0x0d, // Report ID (13) 485 +# 0x09, 0x00, // Usage (Vendor Usage 0x00) 487 +# 0x95, 0x07, // Report Count (7) 489 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 491 +# 0xc0, // End Collection 493 +# 0x05, 0x0d, // Usage Page (Digitizers) 494 +# 0x09, 0x0e, // Usage (Device Configuration) 496 +# 0xa1, 0x01, // Collection (Application) 498 +# 0x85, 0x0e, // Report ID (14) 500 +# 0x09, 0x23, // Usage (Device Settings) 502 +# 0xa1, 0x02, // Collection (Logical) 504 +# 0x09, 0x52, // Usage (Inputmode) 506 +# 0x09, 0x53, // Usage (Device Index) 508 +# 0x15, 0x00, // Logical Minimum (0) 510 +# 0x25, 0x0a, // Logical Maximum (10) 512 +# 0x75, 0x08, // Report Size (8) 514 +# 0x95, 0x02, // Report Count (2) 516 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 518 +# 0xc0, // End Collection 520 +# 0xc0, // End Collection 521 +# 0x05, 0x0d, // Usage Page (Digitizers) 522 +# 0x09, 0x02, // Usage (Pen) 524 +# 0xa1, 0x01, // Collection (Application) 526 +# 0x85, 0x06, // Report ID (6) 528 +# 0xa4, // Push 530 +# 0x09, 0x20, // Usage (Stylus) 531 +# 0xa1, 0x00, // Collection (Physical) 533 +# 0x09, 0x42, // Usage (Tip Switch) 535 +# 0x09, 0x44, // Usage (Barrel Switch) 537 +# 0x09, 0x45, // Usage (Eraser) 539 +# 0x09, 0x3c, // Usage (Invert) 541 +# 0x09, 0x5a, // Usage (Secondary Barrel Switch) 543 +# 0x09, 0x32, // Usage (In Range) 545 +# 0x15, 0x00, // Logical Minimum (0) 547 +# 0x25, 0x01, // Logical Maximum (1) 549 +# 0x75, 0x01, // Report Size (1) 551 +# 0x95, 0x06, // Report Count (6) 553 +# 0x81, 0x02, // Input (Data,Var,Abs) 555 +# 0x95, 0x02, // Report Count (2) 557 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 559 +# 0x05, 0x01, // Usage Page (Generic Desktop) 561 +# 0x09, 0x30, // Usage (X) 563 +# 0x27, 0x70, 0x86, 0x00, 0x00, // Logical Maximum (34416) 565 +# 0x47, 0x70, 0x86, 0x00, 0x00, // Physical Maximum (34416) 570 +# 0x65, 0x11, // Unit (Centimeter,SILinear) 575 +# 0x55, 0x0d, // Unit Exponent (-3) 577 +# 0x75, 0x10, // Report Size (16) 579 +# 0x95, 0x01, // Report Count (1) 581 +# 0x81, 0x02, // Input (Data,Var,Abs) 583 +# 0x09, 0x31, // Usage (Y) 585 +# 0x27, 0x9f, 0x4b, 0x00, 0x00, // Logical Maximum (19359) 587 +# 0x47, 0x9f, 0x4b, 0x00, 0x00, // Physical Maximum (19359) 592 +# 0x81, 0x02, // Input (Data,Var,Abs) 597 +# 0x45, 0x00, // Physical Maximum (0) 599 +# 0x65, 0x00, // Unit (None) 601 +# 0x55, 0x00, // Unit Exponent (0) 603 +# 0x05, 0x0d, // Usage Page (Digitizers) 605 +# 0x09, 0x30, // Usage (Tip Pressure) 607 +# 0x26, 0xff, 0x0f, // Logical Maximum (4095) 609 +# 0x75, 0x10, // Report Size (16) 612 +# 0x81, 0x02, // Input (Data,Var,Abs) 614 +# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 616 +# 0x09, 0x5b, // Usage (Vendor Usage 0x5b) 619 +# 0x16, 0x00, 0x80, // Logical Minimum (-32768) 621 +# 0x26, 0xff, 0x7f, // Logical Maximum (32767) 624 +# 0x75, 0x10, // Report Size (16) 627 +# 0x81, 0x02, // Input (Data,Var,Abs) 629 +# 0x05, 0x0d, // Usage Page (Digitizers) 631 +# 0x09, 0x5b, // Usage (Transducer Serial Number) 633 +# 0x17, 0x00, 0x00, 0x00, 0x80, // Logical Minimum (-2147483648) 635 +# 0x27, 0xff, 0xff, 0xff, 0x7f, // Logical Maximum (2147483647) 640 +# 0x75, 0x20, // Report Size (32) 645 +# 0x81, 0x02, // Input (Data,Var,Abs) 647 +# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 649 +# 0x09, 0x00, // Usage (Undefined) 652 +# 0x75, 0x08, // Report Size (8) 654 +# 0x26, 0xff, 0x00, // Logical Maximum (255) 656 +# 0x15, 0x00, // Logical Minimum (0) 659 +# 0x81, 0x02, // Input (Data,Var,Abs) 661 +# 0x05, 0x0d, // Usage Page (Digitizers) 663 +# 0x09, 0x3b, // Usage (Battery Strength) 665 +# 0x81, 0x02, // Input (Data,Var,Abs) 667 +# 0x65, 0x14, // Unit (Degrees,EngRotation) 669 +# 0x55, 0x00, // Unit Exponent (0) 671 +# 0x16, 0xa6, 0xff, // Logical Minimum (-90) 673 +# 0x26, 0x5a, 0x00, // Logical Maximum (90) 676 +# 0x36, 0xa6, 0xff, // Physical Minimum (-90) 679 +# 0x46, 0x5a, 0x00, // Physical Maximum (90) 682 +# 0x75, 0x08, // Report Size (8) 685 +# 0x09, 0x3d, // Usage (X Tilt) 687 +# 0x81, 0x02, // Input (Data,Var,Abs) 689 +# 0x09, 0x3e, // Usage (Y Tilt) 691 +# 0x81, 0x02, // Input (Data,Var,Abs) 693 +# 0xc0, // End Collection 695 +# 0xb4, // Pop 696 +# 0x85, 0x13, // Report ID (19) 697 +# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 699 +# 0x09, 0xc5, // Usage (Vendor Usage 0xc5) 702 +# 0x96, 0x00, 0x01, // Report Count (256) 704 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 707 +# 0xc0, // End Collection 709 +# 0x06, 0x11, 0xff, // Usage Page (Vendor Usage Page 0xff11) 710 +# 0x09, 0x02, // Usage (Vendor Usage 0x02) 713 +# 0xa1, 0x01, // Collection (Application) 715 +# 0x85, 0x0b, // Report ID (11) 717 +# 0xa4, // Push 719 +# 0x09, 0x20, // Usage (Vendor Usage 0x20) 720 +# 0xa1, 0x00, // Collection (Physical) 722 +# 0x09, 0x42, // Usage (Vendor Usage 0x42) 724 +# 0x09, 0x44, // Usage (Vendor Usage 0x44) 726 +# 0x09, 0x45, // Usage (Vendor Usage 0x45) 728 +# 0x09, 0x3c, // Usage (Vendor Usage 0x3c) 730 +# 0x09, 0x5a, // Usage (Vendor Usage 0x5a) 732 +# 0x09, 0x32, // Usage (Vendor Usage 0x32) 734 +# 0x15, 0x00, // Logical Minimum (0) 736 +# 0x25, 0x01, // Logical Maximum (1) 738 +# 0x75, 0x01, // Report Size (1) 740 +# 0x95, 0x06, // Report Count (6) 742 +# 0x81, 0x02, // Input (Data,Var,Abs) 744 +# 0x95, 0x02, // Report Count (2) 746 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 748 +# 0x05, 0x01, // Usage Page (Generic Desktop) 750 +# 0x09, 0x30, // Usage (X) 752 +# 0x27, 0x70, 0x86, 0x00, 0x00, // Logical Maximum (34416) 754 +# 0x47, 0x70, 0x86, 0x00, 0x00, // Physical Maximum (34416) 759 +# 0x65, 0x11, // Unit (Centimeter,SILinear) 764 +# 0x55, 0x0d, // Unit Exponent (-3) 766 +# 0x75, 0x10, // Report Size (16) 768 +# 0x95, 0x01, // Report Count (1) 770 +# 0x81, 0x02, // Input (Data,Var,Abs) 772 +# 0x09, 0x31, // Usage (Y) 774 +# 0x27, 0x9f, 0x4b, 0x00, 0x00, // Logical Maximum (19359) 776 +# 0x47, 0x9f, 0x4b, 0x00, 0x00, // Physical Maximum (19359) 781 +# 0x81, 0x02, // Input (Data,Var,Abs) 786 +# 0x45, 0x00, // Physical Maximum (0) 788 +# 0x65, 0x00, // Unit (None) 790 +# 0x55, 0x00, // Unit Exponent (0) 792 +# 0x05, 0x0d, // Usage Page (Digitizers) 794 +# 0x09, 0x30, // Usage (Tip Pressure) 796 +# 0x26, 0xff, 0x0f, // Logical Maximum (4095) 798 +# 0x75, 0x10, // Report Size (16) 801 +# 0x81, 0x02, // Input (Data,Var,Abs) 803 +# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 805 +# 0x09, 0x5b, // Usage (Vendor Usage 0x5b) 808 +# 0x16, 0x00, 0x80, // Logical Minimum (-32768) 810 +# 0x26, 0xff, 0x7f, // Logical Maximum (32767) 813 +# 0x75, 0x10, // Report Size (16) 816 +# 0x81, 0x02, // Input (Data,Var,Abs) 818 +# 0x05, 0x0d, // Usage Page (Digitizers) 820 +# 0x09, 0x5b, // Usage (Transducer Serial Number) 822 +# 0x17, 0x00, 0x00, 0x00, 0x80, // Logical Minimum (-2147483648) 824 +# 0x27, 0xff, 0xff, 0xff, 0x7f, // Logical Maximum (2147483647) 829 +# 0x75, 0x20, // Report Size (32) 834 +# 0x81, 0x02, // Input (Data,Var,Abs) 836 +# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 838 +# 0x09, 0x00, // Usage (Undefined) 841 +# 0x75, 0x08, // Report Size (8) 843 +# 0x26, 0xff, 0x00, // Logical Maximum (255) 845 +# 0x15, 0x00, // Logical Minimum (0) 848 +# 0x81, 0x02, // Input (Data,Var,Abs) 850 +# 0x05, 0x0d, // Usage Page (Digitizers) 852 +# 0x09, 0x3b, // Usage (Battery Strength) 854 +# 0x81, 0x02, // Input (Data,Var,Abs) 856 +# 0x65, 0x14, // Unit (Degrees,EngRotation) 858 +# 0x55, 0x00, // Unit Exponent (0) 860 +# 0x16, 0xa6, 0xff, // Logical Minimum (-90) 862 +# 0x26, 0x5a, 0x00, // Logical Maximum (90) 865 +# 0x36, 0xa6, 0xff, // Physical Minimum (-90) 868 +# 0x46, 0x5a, 0x00, // Physical Maximum (90) 871 +# 0x75, 0x08, // Report Size (8) 874 +# 0x09, 0x3d, // Usage (X Tilt) 876 +# 0x81, 0x02, // Input (Data,Var,Abs) 878 +# 0x09, 0x3e, // Usage (Y Tilt) 880 +# 0x81, 0x02, // Input (Data,Var,Abs) 882 +# 0xc0, // End Collection 884 +# 0xb4, // Pop 885 +# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 886 +# 0x75, 0x08, // Report Size (8) 889 +# 0x15, 0x00, // Logical Minimum (0) 891 +# 0x26, 0xff, 0x00, // Logical Maximum (255) 893 +# 0x85, 0x05, // Report ID (5) 896 +# 0x09, 0x00, // Usage (Undefined) 898 +# 0x95, 0x3a, // Report Count (58) 900 +# 0x81, 0x02, // Input (Data,Var,Abs) 902 +# 0x85, 0x10, // Report ID (16) 904 +# 0x09, 0x00, // Usage (Undefined) 906 +# 0x95, 0x14, // Report Count (20) 908 +# 0x81, 0x02, // Input (Data,Var,Abs) 910 +# 0x85, 0x0f, // Report ID (15) 912 +# 0x09, 0x00, // Usage (Undefined) 914 +# 0x95, 0x28, // Report Count (40) 916 +# 0x81, 0x02, // Input (Data,Var,Abs) 918 +# 0x85, 0x0f, // Report ID (15) 920 +# 0x09, 0x00, // Usage (Undefined) 922 +# 0x95, 0x07, // Report Count (7) 924 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 926 +# 0x85, 0x11, // Report ID (17) 928 +# 0x09, 0x00, // Usage (Undefined) 930 +# 0x95, 0x09, // Report Count (9) 932 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 934 +# 0x85, 0x05, // Report ID (5) 936 +# 0x09, 0x00, // Usage (Undefined) 938 +# 0x95, 0x08, // Report Count (8) 940 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 942 +# 0x85, 0x10, // Report ID (16) 944 +# 0x09, 0x00, // Usage (Undefined) 946 +# 0x96, 0x3f, 0x00, // Report Count (63) 948 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 951 +# 0x85, 0x0b, // Report ID (11) 953 +# 0x09, 0x00, // Usage (Undefined) 955 +# 0x96, 0x3f, 0x00, // Report Count (63) 957 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 960 +# 0xc0, // End Collection 962 +# 0x05, 0x01, // Usage Page (Generic Desktop) 963 +# 0x09, 0x02, // Usage (Mouse) 965 +# 0xa1, 0x01, // Collection (Application) 967 +# 0x85, 0x01, // Report ID (1) 969 +# 0x09, 0x01, // Usage (Pointer) 971 +# 0xa1, 0x00, // Collection (Physical) 973 +# 0x05, 0x09, // Usage Page (Button) 975 +# 0x19, 0x01, // Usage Minimum (1) 977 +# 0x29, 0x02, // Usage Maximum (2) 979 +# 0x15, 0x00, // Logical Minimum (0) 981 +# 0x25, 0x01, // Logical Maximum (1) 983 +# 0x95, 0x02, // Report Count (2) 985 +# 0x75, 0x01, // Report Size (1) 987 +# 0x81, 0x02, // Input (Data,Var,Abs) 989 +# 0x95, 0x01, // Report Count (1) 991 +# 0x75, 0x06, // Report Size (6) 993 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 995 +# 0x05, 0x01, // Usage Page (Generic Desktop) 997 +# 0x09, 0x30, // Usage (X) 999 +# 0x09, 0x31, // Usage (Y) 1001 +# 0x26, 0xff, 0x7f, // Logical Maximum (32767) 1003 +# 0x75, 0x10, // Report Size (16) 1006 +# 0x95, 0x02, // Report Count (2) 1008 +# 0x81, 0x02, // Input (Data,Var,Abs) 1010 +# 0xc0, // End Collection 1012 +# 0xc0, // End Collection 1013 diff -Nru fwupd-1.1.4/plugins/wacom-raw/fu-plugin-wacom-raw.c fwupd-1.2.5/plugins/wacom-raw/fu-plugin-wacom-raw.c --- fwupd-1.1.4/plugins/wacom-raw/fu-plugin-wacom-raw.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-raw/fu-plugin-wacom-raw.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-wacom-aes-device.h" +#include "fu-wacom-emr-device.h" +#include "fu-wacom-common.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.wacom.raw"); + fu_plugin_add_udev_subsystem (plugin, "hidraw"); +} + +gboolean +fu_plugin_update_detach (FuPlugin *plugin, FuDevice *device, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) + return TRUE; + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_detach (device, error); +} + +gboolean +fu_plugin_update_attach (FuPlugin *plugin, FuDevice *device, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_attach (device, error); +} + +gboolean +fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **error) +{ + /* interesting device? */ + if (g_strcmp0 (fu_udev_device_get_subsystem (device), "hidraw") != 0) + return TRUE; + + /* wacom */ + if (fu_udev_device_get_vendor (device) != FU_WACOM_DEVICE_VID) + return TRUE; + + /* no actual device to open */ + if (g_udev_device_get_device_file (fu_udev_device_get_dev (device)) == NULL) + return TRUE; + + /* EMR */ + if (fu_device_has_instance_id (FU_DEVICE (device), "WacomEMR")) { + g_autoptr(FuWacomEmrDevice) dev = fu_wacom_emr_device_new (device); + g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (dev, error); + if (locker == NULL) + return FALSE; + fu_plugin_device_add (plugin, FU_DEVICE (dev)); + } + + /* AES */ + if (fu_device_has_instance_id (FU_DEVICE (device), "WacomAES")) { + g_autoptr(FuWacomAesDevice) dev = fu_wacom_aes_device_new (device); + g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (dev, error); + if (locker == NULL) + return FALSE; + fu_plugin_device_add (plugin, FU_DEVICE (dev)); + } + + /* not supported */ + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Only EMR or AES devices are supported"); + return FALSE; +} + +gboolean +fu_plugin_update (FuPlugin *plugin, + FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_write_firmware (device, blob_fw, error); +} diff -Nru fwupd-1.1.4/plugins/wacom-raw/fu-wacom-aes-device.c fwupd-1.2.5/plugins/wacom-raw/fu-wacom-aes-device.c --- fwupd-1.1.4/plugins/wacom-raw/fu-wacom-aes-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-raw/fu-wacom-aes-device.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-chunk.h" +#include "fu-wacom-common.h" +#include "fu-wacom-aes-device.h" + +struct _FuWacomAesDevice { + FuWacomDevice parent_instance; + guint32 hwid; +}; + +G_DEFINE_TYPE (FuWacomAesDevice, fu_wacom_aes_device, FU_TYPE_WACOM_DEVICE) + +static gboolean +fu_wacom_aes_device_obtain_hwid (FuWacomAesDevice *self, GError **error) +{ + guint8 cmd[FU_WACOM_RAW_FW_MAINTAIN_REPORT_SZ] = { 0x0 }; + guint8 buf[FU_WACOM_RAW_FW_MAINTAIN_REPORT_SZ] = { 0x0 }; + + cmd[0] = FU_WACOM_RAW_FW_MAINTAIN_REPORT_ID; + cmd[1] = 0x01; /* ?? */ + cmd[2] = 0x01; /* ?? */ + cmd[3] = 0x0f; /* ?? */ + + if (!fu_wacom_device_set_feature (FU_WACOM_DEVICE (self), + cmd, sizeof(cmd), error)) { + g_prefix_error (error, "failed to send: "); + return FALSE; + } + buf[0] = FU_WACOM_RAW_FW_MAINTAIN_REPORT_ID; + if (!fu_wacom_device_get_feature (FU_WACOM_DEVICE (self), + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to receive: "); + return FALSE; + } + if (buf[1] == 0xff) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "firmware does not support this feature"); + return FALSE; + } + + /* check magic number */ + if (memcmp (buf, "\x34\x12\x78\x56\x65\x87\x21\x43", 8) != 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "incorrect magic number"); + return FALSE; + } + + /* format the value */ + self->hwid = ((guint32) buf[9]) << 24 | + ((guint32) buf[8]) << 16 | + ((guint32) buf[11]) << 8 | + ((guint32) buf[10]); + return TRUE; + +} + +static gboolean +fu_wacom_aes_query_operation_mode (FuWacomAesDevice *self, GError **error) +{ + guint8 buf[FU_WACOM_RAW_FW_REPORT_SZ] = { + FU_WACOM_RAW_FW_REPORT_ID, + FU_WACOM_RAW_FW_CMD_QUERY_MODE, + }; + + /* 0x00=runtime, 0x02=bootloader */ + if (!fu_wacom_device_get_feature (FU_WACOM_DEVICE (self), buf, sizeof(buf), error)) + return FALSE; + if (buf[1] == 0x00) { + fu_device_remove_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + return TRUE; + } + if (buf[1] == 0x02) { + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + return TRUE; + } + + /* unsupported */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "Failed to query operation mode, got 0x%x", + buf[1]); + return FALSE; +} + +static gboolean +fu_wacom_aes_device_setup (FuDevice *device, GError **error) +{ + FuWacomAesDevice *self = FU_WACOM_AES_DEVICE (device); + + /* find out if in bootloader mode already */ + if (!fu_wacom_aes_query_operation_mode (self, error)) + return FALSE; + + /* get firmware version */ + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + fu_device_set_version (device, "0.0"); + } else { + guint32 fw_ver; + guint8 data[FU_WACOM_RAW_STATUS_REPORT_SZ] = { + FU_WACOM_RAW_STATUS_REPORT_ID, + 0x0 + }; + g_autofree gchar *version = NULL; + g_autoptr(GError) error_local = NULL; + + if (!fu_wacom_device_get_feature (FU_WACOM_DEVICE (self), + data, sizeof(data), error)) + return FALSE; + fw_ver = fu_common_read_uint16 (data + 11, G_LITTLE_ENDIAN); + version = g_strdup_printf ("%04x.%02x", fw_ver, data[13]); + fu_device_set_version (device, version); + + /* get the optional 32 byte HWID and add it as a GUID */ + if (!fu_wacom_aes_device_obtain_hwid (self, &error_local)) { + g_debug ("failed to get HwID: %s", error_local->message); + } else { + g_autofree gchar *devid = NULL; + devid = g_strdup_printf ("WACOM\\HWID_%04X", self->hwid); + fu_device_add_instance_id (device, devid); + } + } + + /* success */ + return TRUE; +} + +static gboolean +fu_wacom_aes_device_erase_all (FuWacomAesDevice *self, GError **error) +{ + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_ALL_ERASE, + .echo = FU_WACOM_RAW_ECHO_DEFAULT, + 0x00 + }; + FuWacomRawResponse rsp = { 0x00 }; + if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, + 2000 * 1000, /* this takes a long time */ + FU_WACOM_DEVICE_CMD_FLAG_POLL_ON_WAITING, error)) { + g_prefix_error (error, "failed to send eraseall command: "); + return FALSE; + } + g_usleep (2 * G_USEC_PER_SEC); + return TRUE; +} + +static gboolean +fu_wacom_aes_device_write_block (FuWacomAesDevice *self, + guint32 idx, + guint32 address, + const guint8 *data, + guint16 datasz, + GError **error) +{ + guint blocksz = fu_wacom_device_get_block_sz (FU_WACOM_DEVICE (self)); + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_WRITE_FLASH, + .echo = (guint8) idx + 1, + .addr = GUINT32_TO_LE(address), + .size8 = datasz / 8, + .data = { 0x00 }, + }; + FuWacomRawResponse rsp = { 0x00 }; + + /* check size */ + if (datasz != blocksz) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "block size 0x%x != 0x%x untested", + datasz, (guint) blocksz); + return FALSE; + } + memcpy (&req.data, data, datasz); + + /* write */ + if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, 1000, + FU_WACOM_DEVICE_CMD_FLAG_NONE, error)) { + g_prefix_error (error, "failed to write block %u: ", idx); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_wacom_aes_device_write_firmware (FuDevice *device, GPtrArray *chunks, GError **error) +{ + FuWacomAesDevice *self = FU_WACOM_AES_DEVICE (device); + + /* erase */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + if (!fu_wacom_aes_device_erase_all (self, error)) + return FALSE; + + /* write */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + if (!fu_wacom_aes_device_write_block (self, + chk->idx, + chk->address, + chk->data, + chk->data_sz, + error)) + return FALSE; + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len); + } + return TRUE; +} + +static void +fu_wacom_aes_device_init (FuWacomAesDevice *self) +{ + fu_device_set_name (FU_DEVICE (self), "Embedded Wacom AES Device"); +} + +static void +fu_wacom_aes_device_class_init (FuWacomAesDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuWacomDeviceClass *klass_wac_device = FU_WACOM_DEVICE_CLASS (klass); + klass_device->setup = fu_wacom_aes_device_setup; + klass_wac_device->write_firmware = fu_wacom_aes_device_write_firmware; +} + +FuWacomAesDevice * +fu_wacom_aes_device_new (FuUdevDevice *device) +{ + FuWacomAesDevice *self = g_object_new (FU_TYPE_WACOM_AES_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return self; +} diff -Nru fwupd-1.1.4/plugins/wacom-raw/fu-wacom-aes-device.h fwupd-1.2.5/plugins/wacom-raw/fu-wacom-aes-device.h --- fwupd-1.1.4/plugins/wacom-raw/fu-wacom-aes-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-raw/fu-wacom-aes-device.h 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-wacom-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_WACOM_AES_DEVICE (fu_wacom_aes_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuWacomAesDevice, fu_wacom_aes_device, FU, WACOM_AES_DEVICE, FuWacomDevice) + +FuWacomAesDevice *fu_wacom_aes_device_new (FuUdevDevice *device); + +G_END_DECLS diff -Nru fwupd-1.1.4/plugins/wacom-raw/fu-wacom-common.c fwupd-1.2.5/plugins/wacom-raw/fu-wacom-common.c --- fwupd-1.1.4/plugins/wacom-raw/fu-wacom-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-raw/fu-wacom-common.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-wacom-common.h" + +gboolean +fu_wacom_common_check_reply (const FuWacomRawRequest *req, + const FuWacomRawResponse *rsp, + GError **error) +{ + if (rsp->report_id != FU_WACOM_RAW_BL_REPORT_ID_GET) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "report ID failed, expected 0x%02x, got 0x%02x", + (guint) FU_WACOM_RAW_BL_REPORT_ID_GET, + req->report_id); + return FALSE; + } + if (req->cmd != rsp->cmd) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "cmd failed, expected 0x%02x, got 0x%02x", + req->cmd, rsp->cmd); + return FALSE; + } + if (req->echo != rsp->echo) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "echo failed, expected 0x%02x, got 0x%02x", + req->echo, rsp->echo); + return FALSE; + } + return TRUE; +} + +gboolean +fu_wacom_common_rc_set_error (const FuWacomRawResponse *rsp, GError **error) +{ + if (rsp->resp == FU_WACOM_RAW_RC_OK) + return TRUE; + if (rsp->resp == FU_WACOM_RAW_RC_BUSY) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_BUSY, + "device is busy"); + return FALSE; + } + if (rsp->resp == FU_WACOM_RAW_RC_MCUTYPE) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "MCU type does not match"); + return FALSE; + } + if (rsp->resp == FU_WACOM_RAW_RC_PID) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "PID does not match"); + return FALSE; + } + if (rsp->resp == FU_WACOM_RAW_RC_CHECKSUM1) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "checksum1 does not match"); + return FALSE; + } + if (rsp->resp == FU_WACOM_RAW_RC_CHECKSUM2) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "checksum2 does not match"); + return FALSE; + } + if (rsp->resp == FU_WACOM_RAW_RC_TIMEOUT) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_TIMED_OUT, + "command timed out"); + return FALSE; + } + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "unknown error 0x%02x", rsp->resp); + return FALSE; +} + +gboolean +fu_wacom_common_block_is_empty (const guint8 *data, guint16 datasz) +{ + for (guint16 i = 0; i < datasz; i++) { + if (data[i] != 0xff) + return FALSE; + } + return TRUE; +} diff -Nru fwupd-1.1.4/plugins/wacom-raw/fu-wacom-common.h fwupd-1.2.5/plugins/wacom-raw/fu-wacom-common.h --- fwupd-1.1.4/plugins/wacom-raw/fu-wacom-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-raw/fu-wacom-common.h 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define FU_WACOM_DEVICE_VID 0x056A +#define FU_WACOM_RAW_CMD_RETRIES 1000 + +#define FU_WACOM_RAW_STATUS_REPORT_ID 0x04 +#define FU_WACOM_RAW_STATUS_REPORT_SZ 16 + +#define FU_WACOM_RAW_FW_REPORT_ID 0x02 +#define FU_WACOM_RAW_FW_CMD_QUERY_MODE 0x00 +#define FU_WACOM_RAW_FW_CMD_DETACH 0x02 +#define FU_WACOM_RAW_FW_REPORT_SZ 2 + +#define FU_WACOM_RAW_FW_MAINTAIN_REPORT_ID 0x09 +#define FU_WACOM_RAW_FW_MAINTAIN_REPORT_SZ 64 + +#define FU_WACOM_RAW_BL_REPORT_ID_SET 0x07 +#define FU_WACOM_RAW_BL_REPORT_ID_GET 0x08 + +#define FU_WACOM_RAW_BL_CMD_ERASE_FLASH 0x00 +#define FU_WACOM_RAW_BL_CMD_WRITE_FLASH 0x01 +#define FU_WACOM_RAW_BL_CMD_VERIFY_FLASH 0x02 +#define FU_WACOM_RAW_BL_CMD_ATTACH 0x03 +#define FU_WACOM_RAW_BL_CMD_GET_BLVER 0x04 +#define FU_WACOM_RAW_BL_CMD_GET_MPUTYPE 0x05 +#define FU_WACOM_RAW_BL_CMD_CHECK_MODE 0x07 +#define FU_WACOM_RAW_BL_CMD_ERASE_DATAMEM 0x0e +#define FU_WACOM_RAW_BL_CMD_ALL_ERASE 0x90 + +#define FU_WACOM_RAW_RC_OK 0x00 +#define FU_WACOM_RAW_RC_BUSY 0x80 +#define FU_WACOM_RAW_RC_MCUTYPE 0x0c +#define FU_WACOM_RAW_RC_PID 0x0d +#define FU_WACOM_RAW_RC_CHECKSUM1 0x81 +#define FU_WACOM_RAW_RC_CHECKSUM2 0x82 +#define FU_WACOM_RAW_RC_TIMEOUT 0x87 +#define FU_WACOM_RAW_RC_IN_PROGRESS 0xff + +#define FU_WACOM_RAW_ECHO_DEFAULT g_random_int_range(0xa0,0xfe) + +typedef struct __attribute__((packed)) { + guint8 report_id; + guint8 cmd; + guint8 echo; + guint32 addr; + guint8 size8; + guint8 data[128]; + guint8 data_unused[121]; +} FuWacomRawRequest; + +typedef struct __attribute__((packed)) { + guint8 report_id; + guint8 cmd; + guint8 echo; + guint8 resp; + guint8 data_unused[132]; +} FuWacomRawResponse; + +gboolean fu_wacom_common_rc_set_error (const FuWacomRawResponse *rsp, + GError **error); +gboolean fu_wacom_common_check_reply (const FuWacomRawRequest *req, + const FuWacomRawResponse *rsp, + GError **error); +gboolean fu_wacom_common_block_is_empty (const guint8 *data, + guint16 datasz); + +G_END_DECLS diff -Nru fwupd-1.1.4/plugins/wacom-raw/fu-wacom-device.c fwupd-1.2.5/plugins/wacom-raw/fu-wacom-device.c --- fwupd-1.1.4/plugins/wacom-raw/fu-wacom-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-raw/fu-wacom-device.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,420 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include +#include + +#include + +#include "fu-chunk.h" +#include "fu-wacom-common.h" +#include "fu-wacom-device.h" +#include "dfu-firmware.h" + +typedef struct +{ + gint fd; + guint flash_block_size; + guint32 flash_base_addr; + guint32 flash_size; +} FuWacomDevicePrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (FuWacomDevice, fu_wacom_device, FU_TYPE_UDEV_DEVICE) + +#define GET_PRIVATE(o) (fu_wacom_device_get_instance_private (o)) + +static void +fu_wacom_device_to_string (FuDevice *device, GString *str) +{ + FuWacomDevice *self = FU_WACOM_DEVICE (device); + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + g_string_append (str, " FuWacomDevice:\n"); + g_string_append_printf (str, " fd:\t\t\t%i\n", priv->fd); + g_string_append_printf (str, " flash-block-size:\t0x%04x\n", priv->flash_block_size); + g_string_append_printf (str, " flash-base-addr:\t0x%04x\n", priv->flash_base_addr); + g_string_append_printf (str, " flash-size:\t\t0x%04x\n", priv->flash_size); +} + +guint +fu_wacom_device_get_block_sz (FuWacomDevice *self) +{ + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + return priv->flash_block_size; +} + +guint +fu_wacom_device_get_base_addr (FuWacomDevice *self) +{ + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + return priv->flash_base_addr; +} + +gboolean +fu_wacom_device_check_mpu (FuWacomDevice *self, GError **error) +{ + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_GET_MPUTYPE, + .echo = FU_WACOM_RAW_ECHO_DEFAULT, + 0x00 + }; + FuWacomRawResponse rsp = { 0x00 }; + if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, 0, + FU_WACOM_DEVICE_CMD_FLAG_NO_ERROR_CHECK, error)) { + g_prefix_error (error, "failed to get MPU type: "); + return FALSE; + } + + /* W9013 */ + if (rsp.resp == 0x2e) { + fu_device_add_instance_id (FU_DEVICE (self), "WacomEMR_W9013"); + return TRUE; + } + + /* W9021 */ + if (rsp.resp == 0x45) { + fu_device_add_instance_id (FU_DEVICE (self), "WacomEMR_W9021"); + return TRUE; + } + + /* unsupported */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "MPU is not W9013 or W9021: 0x%x", + rsp.resp); + return FALSE; +} + +static gboolean +fu_wacom_device_open (FuDevice *device, GError **error) +{ + FuWacomDevice *self = FU_WACOM_DEVICE (device); + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (device)); + + /* open device */ + priv->fd = g_open (g_udev_device_get_device_file (udev_device), O_RDWR); + if (priv->fd < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to open %s", + g_udev_device_get_device_file (udev_device)); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_wacom_device_close (FuDevice *device, GError **error) +{ + FuWacomDevice *self = FU_WACOM_DEVICE (device); + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + if (!g_close (priv->fd, error)) + return FALSE; + priv->fd = 0; + return TRUE; +} + +static gboolean +fu_wacom_device_probe (FuUdevDevice *device, GError **error) +{ + /* set the physical ID */ + if (!fu_udev_device_set_physical_id (device, "hid", error)) + return FALSE; + return TRUE; +} + +static gboolean +fu_wacom_device_detach (FuDevice *device, GError **error) +{ + FuWacomDevice *self = FU_WACOM_DEVICE (device); + guint8 buf[FU_WACOM_RAW_FW_REPORT_SZ] = { + FU_WACOM_RAW_FW_REPORT_ID, + FU_WACOM_RAW_FW_CMD_DETACH, + }; + if (!fu_wacom_device_set_feature (self, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to switch to bootloader mode: "); + return FALSE; + } + g_usleep (300 * 1000); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + return TRUE; +} + +static gboolean +fu_wacom_device_attach (FuDevice *device, GError **error) +{ + FuWacomDevice *self = FU_WACOM_DEVICE (device); + FuWacomRawRequest req = { + .report_id = FU_WACOM_RAW_BL_REPORT_ID_SET, + .cmd = FU_WACOM_RAW_BL_CMD_ATTACH, + .echo = FU_WACOM_RAW_ECHO_DEFAULT, + 0x00 + }; + if (!fu_wacom_device_set_feature (self, (const guint8 *) &req, sizeof(req), error)) { + g_prefix_error (error, "failed to switch to runtime mode: "); + return FALSE; + } + /* only required on AES, but harmless for EMR */ + g_usleep (300 * 1000); + fu_device_remove_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + return TRUE; +} + +static gboolean +fu_wacom_device_check_mode (FuWacomDevice *self, GError **error) +{ + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_CHECK_MODE, + .echo = FU_WACOM_RAW_ECHO_DEFAULT, + 0x00 + }; + FuWacomRawResponse rsp = { 0x00 }; + if (!fu_wacom_device_cmd (self, &req, &rsp, 0, + FU_WACOM_DEVICE_CMD_FLAG_NO_ERROR_CHECK, error)) { + g_prefix_error (error, "failed to check mode: "); + return FALSE; + } + if (rsp.resp != 0x06) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "check mode failed, mode=0x%02x", + rsp.resp); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_wacom_device_set_version_bootloader (FuWacomDevice *self, GError **error) +{ + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_GET_BLVER, + .echo = FU_WACOM_RAW_ECHO_DEFAULT, + 0x00 + }; + FuWacomRawResponse rsp = { 0x00 }; + g_autofree gchar *version = NULL; + if (!fu_wacom_device_cmd (self, &req, &rsp, 0, + FU_WACOM_DEVICE_CMD_FLAG_NO_ERROR_CHECK, error)) { + g_prefix_error (error, "failed to get bootloader version: "); + return FALSE; + } + version = g_strdup_printf ("%u", rsp.resp); + fu_device_set_version_bootloader (FU_DEVICE (self), version); + return TRUE; +} + +static gboolean +fu_wacom_device_write_firmware (FuDevice *device, GBytes *fw, GError **error) +{ + FuWacomDevice *self = FU_WACOM_DEVICE (device); + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + FuWacomDeviceClass *klass = FU_WACOM_DEVICE_GET_CLASS (device); + DfuElement *element; + DfuImage *image; + GBytes *fw_new; + g_autoptr(DfuFirmware) firmware = dfu_firmware_new (); + g_autoptr(GPtrArray) chunks = NULL; + + /* parse hex file */ + if (!dfu_firmware_parse_data (firmware, fw, DFU_FIRMWARE_PARSE_FLAG_NONE, error)) + return FALSE; + if (dfu_firmware_get_format (firmware) != DFU_FIRMWARE_FORMAT_INTEL_HEX) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "expected firmware format is 'ihex', got '%s'", + dfu_firmware_format_to_string (dfu_firmware_get_format (firmware))); + return FALSE; + } + + /* use the correct image from the firmware */ + image = dfu_firmware_get_image_default (firmware); + if (image == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no firmware image"); + return FALSE; + } + element = dfu_image_get_element_default (image); + if (element == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no element in image"); + return FALSE; + } + g_debug ("using element at addr 0x%0x", + (guint) dfu_element_get_address (element)); + + /* check start address and size */ + if (dfu_element_get_address (element) != priv->flash_base_addr) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "base addr invalid: 0x%05x", + (guint) dfu_element_get_address (element)); + return FALSE; + } + fw_new = dfu_element_get_contents (element); + if (g_bytes_get_size (fw_new) > priv->flash_size) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "size is invalid: 0x%05x", + (guint) g_bytes_get_size (fw_new)); + return FALSE; + } + + /* we're in bootloader mode now */ + if (!fu_wacom_device_check_mode (self, error)) + return FALSE; + if (!fu_wacom_device_set_version_bootloader (self, error)) + return FALSE; + + /* flash chunks */ + chunks = fu_chunk_array_new_from_bytes (fw_new, priv->flash_base_addr, + 0x00, /* page_sz */ + priv->flash_block_size); + return klass->write_firmware (device, chunks, error); +} + +gboolean +fu_wacom_device_set_feature (FuWacomDevice *self, + const guint8 *data, + guint datasz, + GError **error) +{ + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + + /* Set Feature */ + fu_common_dump_raw (G_LOG_DOMAIN, "SetFeature", data, datasz); + if (ioctl (priv->fd, HIDIOCSFEATURE(datasz), data) < 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to SetFeature"); + return FALSE; + } + return TRUE; +} + +gboolean +fu_wacom_device_get_feature (FuWacomDevice *self, + guint8 *data, + guint datasz, + GError **error) +{ + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + if (ioctl (priv->fd, HIDIOCGFEATURE(datasz), data) < 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to GetFeature"); + return FALSE; + } + fu_common_dump_raw (G_LOG_DOMAIN, "GetFeature", data, datasz); + return TRUE; +} + +gboolean +fu_wacom_device_cmd (FuWacomDevice *self, + FuWacomRawRequest *req, FuWacomRawResponse *rsp, + gulong delay_us, FuWacomDeviceCmdFlags flags, + GError **error) +{ + req->report_id = FU_WACOM_RAW_BL_REPORT_ID_SET; + if (!fu_wacom_device_set_feature (self, (const guint8 *)req, sizeof(*req), error)) { + g_prefix_error (error, "failed to send: "); + return FALSE; + } + if (delay_us > 0) + g_usleep (delay_us); + rsp->report_id = FU_WACOM_RAW_BL_REPORT_ID_GET; + if (!fu_wacom_device_get_feature (self, (guint8 *)rsp, sizeof(*rsp), error)) { + g_prefix_error (error, "failed to receive: "); + return FALSE; + } + if (flags & FU_WACOM_DEVICE_CMD_FLAG_NO_ERROR_CHECK) + return TRUE; + if (!fu_wacom_common_check_reply (req, rsp, error)) + return FALSE; + + /* wait for the command to complete */ + if (flags & FU_WACOM_DEVICE_CMD_FLAG_POLL_ON_WAITING && + rsp->resp != FU_WACOM_RAW_RC_OK) { + for (guint i = 0; i < FU_WACOM_RAW_CMD_RETRIES; i++) { + if (delay_us > 0) + g_usleep (delay_us); + if (!fu_wacom_device_get_feature (self, (guint8 *)rsp, sizeof(*rsp), error)) + return FALSE; + if (!fu_wacom_common_check_reply (req, rsp, error)) + return FALSE; + if (rsp->resp != FU_WACOM_RAW_RC_IN_PROGRESS && + rsp->resp != FU_WACOM_RAW_RC_BUSY) + break; + } + } + return fu_wacom_common_rc_set_error (rsp, error); +} + +static gboolean +fu_wacom_device_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuWacomDevice *self = FU_WACOM_DEVICE (device); + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + if (g_strcmp0 (key, "WacomI2cFlashBlockSize") == 0) { + priv->flash_block_size = fu_common_strtoull (value); + return TRUE; + } + if (g_strcmp0 (key, "WacomI2cFlashBaseAddr") == 0) { + priv->flash_base_addr = fu_common_strtoull (value); + return TRUE; + } + if (g_strcmp0 (key, "WacomI2cFlashSize") == 0) { + priv->flash_size = fu_common_strtoull (value); + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + +static void +fu_wacom_device_init (FuWacomDevice *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); +} + +static void +fu_wacom_device_class_init (FuWacomDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUdevDeviceClass *klass_device_udev = FU_UDEV_DEVICE_CLASS (klass); + klass_device->to_string = fu_wacom_device_to_string; + klass_device->open = fu_wacom_device_open; + klass_device->close = fu_wacom_device_close; + klass_device->write_firmware = fu_wacom_device_write_firmware; + klass_device->attach = fu_wacom_device_attach; + klass_device->detach = fu_wacom_device_detach; + klass_device->set_quirk_kv = fu_wacom_device_set_quirk_kv; + klass_device_udev->probe = fu_wacom_device_probe; +} diff -Nru fwupd-1.1.4/plugins/wacom-raw/fu-wacom-device.h fwupd-1.2.5/plugins/wacom-raw/fu-wacom-device.h --- fwupd-1.1.4/plugins/wacom-raw/fu-wacom-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-raw/fu-wacom-device.h 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-wacom-common.h" +#include "fu-udev-device.h" +#include "dfu-element.h" + +G_BEGIN_DECLS + +#define FU_TYPE_WACOM_DEVICE (fu_wacom_device_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FuWacomDevice, fu_wacom_device, FU, WACOM_DEVICE, FuUdevDevice) + +struct _FuWacomDeviceClass +{ + FuUdevDeviceClass parent_class; + gboolean (*write_firmware) (FuDevice *self, + GPtrArray *chunks, + GError **error); +}; + +typedef enum { + FU_WACOM_DEVICE_CMD_FLAG_NONE = 0, + FU_WACOM_DEVICE_CMD_FLAG_POLL_ON_WAITING = 1 << 0, + FU_WACOM_DEVICE_CMD_FLAG_NO_ERROR_CHECK = 1 << 1, +} FuWacomDeviceCmdFlags; + +gboolean fu_wacom_device_set_feature (FuWacomDevice *self, + const guint8 *data, + guint datasz, + GError **error); +gboolean fu_wacom_device_get_feature (FuWacomDevice *self, + guint8 *data, + guint datasz, + GError **error); +gboolean fu_wacom_device_cmd (FuWacomDevice *self, + FuWacomRawRequest *req, + FuWacomRawResponse *rsp, + gulong delay_us, + FuWacomDeviceCmdFlags flags, + GError **error); +gboolean fu_wacom_device_erase_all (FuWacomDevice *self, + GError **error); +gboolean fu_wacom_device_check_mpu (FuWacomDevice *self, + GError **error); +guint fu_wacom_device_get_block_sz (FuWacomDevice *self); +guint fu_wacom_device_get_base_addr (FuWacomDevice *self); + +G_END_DECLS diff -Nru fwupd-1.1.4/plugins/wacom-raw/fu-wacom-emr-device.c fwupd-1.2.5/plugins/wacom-raw/fu-wacom-emr-device.c --- fwupd-1.1.4/plugins/wacom-raw/fu-wacom-emr-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-raw/fu-wacom-emr-device.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-chunk.h" +#include "fu-wacom-common.h" +#include "fu-wacom-emr-device.h" + +struct _FuWacomEmrDevice { + FuWacomDevice parent_instance; +}; + +G_DEFINE_TYPE (FuWacomEmrDevice, fu_wacom_emr_device, FU_TYPE_WACOM_DEVICE) + +static gboolean +fu_wacom_emr_device_setup (FuDevice *device, GError **error) +{ + FuWacomEmrDevice *self = FU_WACOM_EMR_DEVICE (device); + + /* check MPU type */ + if (!fu_wacom_device_check_mpu (FU_WACOM_DEVICE (self), error)) + return FALSE; + + /* get firmware version */ + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + fu_device_set_version (device, "0.0"); + } else { + guint16 fw_ver; + guint8 data[19] = { 0x03, 0x0 }; /* 0x03 is an unknown ReportID */ + g_autofree gchar *version = NULL; + if (!fu_wacom_device_get_feature (FU_WACOM_DEVICE (self), + data, sizeof(data), error)) + return FALSE; + fw_ver = fu_common_read_uint16 (data + 11, G_LITTLE_ENDIAN); + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + version = fu_common_version_from_uint16 (fw_ver, FU_VERSION_FORMAT_PAIR); + fu_device_set_version (device, version); + } + + /* success */ + return TRUE; +} + +static guint8 +fu_wacom_emr_device_calc_checksum (guint8 init1, const guint8 *buf, guint8 bufsz) +{ + guint8 sum = 0; + sum += init1; + for (guint i = 0; i < bufsz; i++) + sum += buf[i]; + return ~sum + 1; +} + +static gboolean +fu_wacom_emr_device_w9013_erase_data (FuWacomEmrDevice *self, GError **error) +{ + FuWacomRawResponse rsp = { 0x00 }; + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_ERASE_DATAMEM, + .echo = FU_WACOM_RAW_ECHO_DEFAULT, + 0x00 + }; + guint8 *buf = (guint8 *) &req.addr; + buf[0] = 0x00; /* erased block */ + buf[1] = fu_wacom_emr_device_calc_checksum (0x05 + 0x00 + 0x07 + 0x00, + (const guint8 *) &req, 4); + if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, 50, + FU_WACOM_DEVICE_CMD_FLAG_POLL_ON_WAITING, error)) { + g_prefix_error (error, "failed to erase datamem: "); + return FALSE; + } + g_usleep (50); + return TRUE; +} + +static gboolean +fu_wacom_emr_device_w9013_erase_code (FuWacomEmrDevice *self, + guint8 idx, + guint8 block_nr, + GError **error) +{ + FuWacomRawResponse rsp = { 0x00 }; + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_ERASE_FLASH, + .echo = idx, + 0x00 + }; + guint8 *buf = (guint8 *) &req.addr; + buf[0] = block_nr; + buf[1] = fu_wacom_emr_device_calc_checksum (0x05 + 0x00 + 0x07 + 0x00, + (const guint8 *) &req, 4); + if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, 50, + FU_WACOM_DEVICE_CMD_FLAG_POLL_ON_WAITING, error)) { + g_prefix_error (error, "failed to erase codemem: "); + return FALSE; + } + g_usleep (50); + return TRUE; +} + +static gboolean +fu_wacom_device_w9021_erase_all (FuWacomEmrDevice *self, GError **error) +{ + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_ALL_ERASE, + .echo = 0x01, + .addr = 0x00, + }; + FuWacomRawResponse rsp = { 0x00 }; + if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, + 2000 * 1000, /* this takes a long time */ + FU_WACOM_DEVICE_CMD_FLAG_POLL_ON_WAITING, error)) { + g_prefix_error (error, "failed to send eraseall command: "); + return FALSE; + } + if (!fu_wacom_common_rc_set_error (&rsp, error)) { + g_prefix_error (error, "failed to erase"); + return FALSE; + } + g_usleep (50); + return TRUE; +} + +static gboolean +fu_wacom_emr_device_write_block (FuWacomEmrDevice *self, + guint32 idx, + guint32 address, + const guint8 *data, + guint16 datasz, + GError **error) +{ + guint blocksz = fu_wacom_device_get_block_sz (FU_WACOM_DEVICE (self)); + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_WRITE_FLASH, + .echo = (guint8) idx + 1, + .addr = GUINT32_TO_LE(address), + .size8 = datasz / 8, + .data = { 0x00 }, + }; + FuWacomRawResponse rsp = { 0x00 }; + + /* check size */ + if (datasz > sizeof(req.data)) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "data size 0x%x too large for packet", + datasz); + return FALSE; + } + if (datasz != blocksz) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "block size 0x%x != 0x%x untested", + datasz, (guint) blocksz); + return FALSE; + } + + /* data */ + memcpy (&req.data, data, datasz); + + /* cmd and data checksums */ + req.data[blocksz + 0] = fu_wacom_emr_device_calc_checksum (0x05 + 0x00 + 0x4c + 0x00, + (const guint8 *) &req, 8); + req.data[blocksz + 1] = fu_wacom_emr_device_calc_checksum (0x00, data, datasz); + if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, 50, + FU_WACOM_DEVICE_CMD_FLAG_NONE, error)) { + g_prefix_error (error, "failed to write at 0x%x: ", address); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_wacom_emr_device_write_firmware (FuDevice *device, GPtrArray *chunks, GError **error) +{ + FuWacomEmrDevice *self = FU_WACOM_EMR_DEVICE (device); + guint8 idx = 0; + + /* erase W9013 */ + if (fu_device_has_instance_id (device, "WacomEMR_W9013")) { + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + if (!fu_wacom_emr_device_w9013_erase_data (self, error)) + return FALSE; + for (guint i = 127; i >= 8; i--) { + if (!fu_wacom_emr_device_w9013_erase_code (self, idx++, i, error)) + return FALSE; + } + } + + /* erase W9021 */ + if (fu_device_has_instance_id (device, "WacomEMR_W9021")) { + if (!fu_wacom_device_w9021_erase_all (self, error)) + return FALSE; + } + + /* write */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + if (fu_wacom_common_block_is_empty (chk->data, chk->data_sz)) + continue; + if (!fu_wacom_emr_device_write_block (self, + chk->idx, + chk->address, + chk->data, + chk->data_sz, + error)) + return FALSE; + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len); + } + + fu_device_set_progress (device, 100); + return TRUE; +} + +static void +fu_wacom_emr_device_init (FuWacomEmrDevice *self) +{ + fu_device_set_name (FU_DEVICE (self), "Embedded Wacom EMR Device"); +} + +static void +fu_wacom_emr_device_class_init (FuWacomEmrDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuWacomDeviceClass *klass_wac_device = FU_WACOM_DEVICE_CLASS (klass); + klass_device->setup = fu_wacom_emr_device_setup; + klass_wac_device->write_firmware = fu_wacom_emr_device_write_firmware; +} + +FuWacomEmrDevice * +fu_wacom_emr_device_new (FuUdevDevice *device) +{ + FuWacomEmrDevice *self = g_object_new (FU_TYPE_WACOM_EMR_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return self; +} diff -Nru fwupd-1.1.4/plugins/wacom-raw/fu-wacom-emr-device.h fwupd-1.2.5/plugins/wacom-raw/fu-wacom-emr-device.h --- fwupd-1.1.4/plugins/wacom-raw/fu-wacom-emr-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-raw/fu-wacom-emr-device.h 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-wacom-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_WACOM_EMR_DEVICE (fu_wacom_emr_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuWacomEmrDevice, fu_wacom_emr_device, FU, WACOM_EMR_DEVICE, FuUdevDevice) + +FuWacomEmrDevice *fu_wacom_emr_device_new (FuUdevDevice *device); + +G_END_DECLS diff -Nru fwupd-1.1.4/plugins/wacom-raw/meson.build fwupd-1.2.5/plugins/wacom-raw/meson.build --- fwupd-1.1.4/plugins/wacom-raw/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-raw/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,31 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginWacomRaw"'] + +install_data(['wacom-raw.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_wacom_raw', + fu_hash, + sources : [ + 'fu-plugin-wacom-raw.c', + 'fu-wacom-common.c', + 'fu-wacom-device.c', + 'fu-wacom-aes-device.c', + 'fu-wacom-emr-device.c', + ], + include_directories : [ + include_directories('../..'), + include_directories('../dfu'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + install : true, + install_dir: plugin_dir, + c_args : cargs, + dependencies : [ + plugin_deps, + ], + link_with : [ + dfu, + ], +) diff -Nru fwupd-1.1.4/plugins/wacom-raw/README.md fwupd-1.2.5/plugins/wacom-raw/README.md --- fwupd-1.1.4/plugins/wacom-raw/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-raw/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,36 @@ +Wacom RAW Support +================= + +Introduction +------------ + +This plugin updates integrated Wacom AES and EMR devices. They are typically +connected using I²C and not USB. + +GUID Generation +--------------- + +The HID DeviceInstanceId values are used, e.g. `HIDRAW\VEN_056A&DEV_4875`. + +Additionally, for supported AES devices an extra GUID is added for the hardware +ID (e.g. `WACOM\HWID_%04X`) to further disambiguate the panels. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +Intel HEX file format. + +This plugin supports the following protocol ID: + + * com.wacom.raw + +Quirk use +--------- +This plugin uses the following plugin-specific quirks: + +| Quirk | Description | Minimum fwupd version | +|-------------------------|-------------------------------------|-----------------------| +| `WacomI2cFlashBlockSize`| Block size to transfer firmware | 1.2.4 | +| `WacomI2cFlashBaseAddr` | Base address for firmware | 1.2.4 | +| `WacomI2cFlashSize` | Maximum size of the firmware zone | 1.2.4 | diff -Nru fwupd-1.1.4/plugins/wacom-raw/wacom-raw.quirk fwupd-1.2.5/plugins/wacom-raw/wacom-raw.quirk --- fwupd-1.1.4/plugins/wacom-raw/wacom-raw.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-raw/wacom-raw.quirk 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,35 @@ +# Devices that do "replug" and thus don't change VID:PID to the bootloader +# need to have an extra GUID of WacomAES or WacomEMR added so that the flash +# constants are set correctly. + +# Dell XPS-15 9575 +[DeviceInstanceId=HIDRAW\VEN_056A&DEV_4875] +Plugin = wacom_raw +Guid = WacomAES + +# AES bootloader mode +[DeviceInstanceId=HIDRAW\VEN_056A&DEV_0094] +Plugin = wacom_raw +Guid = WacomAES +Flags = is-bootloader + +# EMR bootloader mode +[DeviceInstanceId=HIDRAW\VEN_056A&DEV_012B] +Plugin = wacom_raw +Guid = WacomEMR +Flags = is-bootloader + +[Guid=WacomEMR_W9013] +WacomI2cFlashBlockSize=64 +WacomI2cFlashBaseAddr=0x2000 +WacomI2cFlashSize=0x1e000 + +[Guid=WacomEMR_W9021] +WacomI2cFlashBlockSize=256 +WacomI2cFlashBaseAddr=0x3000 +WacomI2cFlashSize=0x3c000 + +[Guid=WacomAES] +WacomI2cFlashBlockSize=128 +WacomI2cFlashBaseAddr=0x8000 +WacomI2cFlashSize=0x24000 diff -Nru fwupd-1.1.4/plugins/wacom-usb/data/lsusb.txt fwupd-1.2.5/plugins/wacom-usb/data/lsusb.txt --- fwupd-1.1.4/plugins/wacom-usb/data/lsusb.txt 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-usb/data/lsusb.txt 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,58 @@ +Bus 001 Device 023: ID 056a:0378 Wacom Co., Ltd CTL-6100WL [Intuos BT (M)] +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x056a Wacom Co., Ltd + idProduct 0x0378 CTL-6100WL [Intuos BT (M)] + bcdDevice 1.66 + iManufacturer 1 Wacom Co.,Ltd. + iProduct 2 Intuos BT M + iSerial 3 8BH00U2012294 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0022 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 500mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 3 Human Interface Device + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + HID Device Descriptor: + bLength 9 + bDescriptorType 33 + bcdHID 1.10 + bCountryCode 0 Not supported + bNumDescriptors 1 + bDescriptorType 34 Report + wDescriptorLength 759 + Report Descriptors: + ** UNAVAILABLE ** + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 +Device Status: 0x0000 + (Bus Powered) diff -Nru fwupd-1.1.4/plugins/wacom-usb/fu-plugin-wacom-usb.c fwupd-1.2.5/plugins/wacom-usb/fu-plugin-wacom-usb.c --- fwupd-1.1.4/plugins/wacom-usb/fu-plugin-wacom-usb.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-usb/fu-plugin-wacom-usb.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + +#include "fu-wac-device.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.wacom.usb"); +} + +gboolean +fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *device, GError **error) +{ + g_autoptr(FuWacDevice) dev = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + dev = fu_wac_device_new (device); + locker = fu_device_locker_new (dev, error); + if (locker == NULL) + return FALSE; + fu_plugin_device_add (plugin, FU_DEVICE (dev)); + return TRUE; +} + +gboolean +fu_plugin_update (FuPlugin *plugin, FuDevice *device, GBytes *blob_fw, + FwupdInstallFlags flags, GError **error) +{ + FuDevice *parent = fu_device_get_parent (device); + g_autoptr(FuDeviceLocker) locker = NULL; + locker = fu_device_locker_new (parent != NULL ? parent : device, error); + if (locker == NULL) + return FALSE; + return fu_device_write_firmware (device, blob_fw, error); +} + +static FuDevice * +fu_plugin_wacom_usb_get_device (GPtrArray *devices) +{ + for (guint i = 0; i < devices->len; i++) { + FuDevice *dev = g_ptr_array_index (devices, i); + if (FU_IS_WAC_DEVICE (dev)) + return dev; + } + return NULL; +} + +gboolean +fu_plugin_composite_cleanup (FuPlugin *plugin, + GPtrArray *devices, + GError **error) +{ + FuDevice *device = fu_plugin_wacom_usb_get_device (devices); + g_autoptr(FuDeviceLocker) locker = NULL; + + /* not us */ + if (device == NULL) + return TRUE; + + /* reboot, which switches the boot index of the firmware */ + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + return fu_wac_device_update_reset (FU_WAC_DEVICE (device), error); +} diff -Nru fwupd-1.1.4/plugins/wacom-usb/fu-self-test.c fwupd-1.2.5/plugins/wacom-usb/fu-self-test.c --- fwupd-1.1.4/plugins/wacom-usb/fu-self-test.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-usb/fu-self-test.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-common.h" +#include "fu-test.h" +#include "fu-wac-common.h" +#include "fu-wac-firmware.h" + +#include "fwupd-error.h" + +static void +fu_wac_firmware_parse_func (void) +{ + DfuElement *element; + DfuImage *image; + gboolean ret; + g_autofree gchar *fn = NULL; + g_autoptr(DfuFirmware) firmware = dfu_firmware_new (); + g_autoptr(GBytes) blob_block = NULL; + g_autoptr(GBytes) bytes = NULL; + g_autoptr(GError) error = NULL; + + /* parse the test file */ + fn = fu_test_get_filename (TESTDATADIR, "test.wac"); + if (fn == NULL) { + g_test_skip ("no data file found"); + return; + } + bytes = fu_common_get_contents_bytes (fn, &error); + g_assert_no_error (error); + g_assert_nonnull (bytes); + ret = fu_wac_firmware_parse_data (firmware, bytes, + DFU_FIRMWARE_PARSE_FLAG_NONE, &error); + g_assert_no_error (error); + g_assert_true (ret); + + /* get image data */ + image = dfu_firmware_get_image (firmware, 0); + g_assert_nonnull (image); + element = dfu_image_get_element_default (image); + g_assert_nonnull (element); + + /* get block */ + blob_block = dfu_element_get_contents_chunk (element, 0x8008000, + 1024, &error); + g_assert_no_error (error); + g_assert_nonnull (blob_block); + fu_wac_buffer_dump ("IMG", FU_WAC_REPORT_ID_MODULE, + g_bytes_get_data (blob_block, NULL), + g_bytes_get_size (blob_block)); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + + /* log everything */ + g_setenv ("G_MESSAGES_DEBUG", "all", FALSE); + + /* tests go here */ + g_test_add_func ("/wac/firmware{parse}", fu_wac_firmware_parse_func); + return g_test_run (); +} + diff -Nru fwupd-1.1.4/plugins/wacom-usb/fu-wac-common.c fwupd-1.2.5/plugins/wacom-usb/fu-wac-common.c --- fwupd-1.1.4/plugins/wacom-usb/fu-wac-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-usb/fu-wac-common.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-wac-common.h" + +guint32 +fu_wac_calculate_checksum32le (const guint8 *data, gsize len) +{ + guint32 csum = 0x0; + g_return_val_if_fail (len % 4 == 0, 0xff); + for (guint i = 0; i < len; i += 4) { + guint32 tmp; + memcpy (&tmp, &data[i], sizeof(guint32)); + csum += GUINT32_FROM_LE (tmp); + } + return GUINT32_TO_LE (csum); +} + +guint32 +fu_wac_calculate_checksum32le_bytes (GBytes *blob) +{ + gsize len = 0; + const guint8 *data = g_bytes_get_data (blob, &len); + return fu_wac_calculate_checksum32le (data, len); +} + +const gchar * +fu_wac_report_id_to_string (guint8 report_id) +{ + if (report_id == FU_WAC_REPORT_ID_FW_DESCRIPTOR) + return "FwDescriptor"; + if (report_id == FU_WAC_REPORT_ID_SWITCH_TO_FLASH_LOADER) + return "SwitchToFlashLoader"; + if (report_id == FU_WAC_REPORT_ID_QUIT_AND_RESET) + return "QuitAndReset"; + if (report_id == FU_WAC_REPORT_ID_READ_BLOCK_DATA) + return "ReadBlockData"; + if (report_id == FU_WAC_REPORT_ID_WRITE_BLOCK) + return "WriteBlock"; + if (report_id == FU_WAC_REPORT_ID_ERASE_BLOCK) + return "EraseBlock"; + if (report_id == FU_WAC_REPORT_ID_SET_READ_ADDRESS) + return "SetReadAddress"; + if (report_id == FU_WAC_REPORT_ID_GET_STATUS) + return "GetStatus"; + if (report_id == FU_WAC_REPORT_ID_UPDATE_RESET) + return "UpdateReset"; + if (report_id == FU_WAC_REPORT_ID_WRITE_WORD) + return "WriteWord"; + if (report_id == FU_WAC_REPORT_ID_GET_PARAMETERS) + return "GetParameters"; + if (report_id == FU_WAC_REPORT_ID_GET_FLASH_DESCRIPTOR) + return "GetFlashDescriptor"; + if (report_id == FU_WAC_REPORT_ID_GET_CHECKSUMS) + return "GetChecksums"; + if (report_id == FU_WAC_REPORT_ID_SET_CHECKSUM_FOR_BLOCK) + return "SetChecksumForBlock"; + if (report_id == FU_WAC_REPORT_ID_CALCULATE_CHECKSUM_FOR_BLOCK) + return "CalculateChecksumForBlock"; + if (report_id == FU_WAC_REPORT_ID_WRITE_CHECKSUM_TABLE) + return "WriteChecksumTable"; + if (report_id == FU_WAC_REPORT_ID_GET_CURRENT_FIRMWARE_IDX) + return "GetCurrentFirmwareIdx"; + if (report_id == FU_WAC_REPORT_ID_MODULE) + return "Module"; + return NULL; +} + +void +fu_wac_buffer_dump (const gchar *title, guint8 cmd, const guint8 *buf, gsize sz) +{ + g_autofree gchar *tmp = NULL; + if (g_getenv ("FWUPD_WACOM_USB_VERBOSE") == NULL) + return; + tmp = g_strdup_printf ("%s %s (%" G_GSIZE_FORMAT ")", + title, fu_wac_report_id_to_string (cmd), sz); + fu_common_dump_raw (G_LOG_DOMAIN, tmp, buf, sz); +} diff -Nru fwupd-1.1.4/plugins/wacom-usb/fu-wac-common.h fwupd-1.2.5/plugins/wacom-usb/fu-wac-common.h --- fwupd-1.1.4/plugins/wacom-usb/fu-wac-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-usb/fu-wac-common.h 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define FU_WAC_PACKET_LEN 512 + +#define FU_WAC_REPORT_ID_COMMAND 0x01 +#define FU_WAC_REPORT_ID_STATUS 0x02 +#define FU_WAC_REPORT_ID_CONTROL 0x03 + +#define FU_WAC_REPORT_ID_GET_FIRMWARE_VERSION_MAIN 0x07 +#define FU_WAC_REPORT_ID_GET_FIRMWARE_VERSION_TOUCH 0x07 +#define FU_WAC_REPORT_ID_GET_FIRMWARE_VERSION_BLUETOOTH 0x16 + +#define FU_WAC_REPORT_ID_FW_DESCRIPTOR 0xcb /* GET_FEATURE */ +#define FU_WAC_REPORT_ID_SWITCH_TO_FLASH_LOADER 0xcc /* SET_FEATURE */ +#define FU_WAC_REPORT_ID_QUIT_AND_RESET 0xcd /* SET_FEATURE */ +#define FU_WAC_REPORT_ID_READ_BLOCK_DATA 0xd1 /* GET_FEATURE */ +#define FU_WAC_REPORT_ID_WRITE_BLOCK 0xd2 /* SET_FEATURE */ +#define FU_WAC_REPORT_ID_ERASE_BLOCK 0xd3 /* SET_FEATURE */ +#define FU_WAC_REPORT_ID_SET_READ_ADDRESS 0xd4 /* GET_FEATURE */ +#define FU_WAC_REPORT_ID_GET_STATUS 0xd5 /* GET_FEATURE */ +#define FU_WAC_REPORT_ID_UPDATE_RESET 0xd6 /* SET_FEATURE */ +#define FU_WAC_REPORT_ID_WRITE_WORD 0xd7 /* SET_FEATURE */ +#define FU_WAC_REPORT_ID_GET_PARAMETERS 0xd8 /* GET_FEATURE */ +#define FU_WAC_REPORT_ID_GET_FLASH_DESCRIPTOR 0xd9 /* GET_FEATURE */ +#define FU_WAC_REPORT_ID_GET_CHECKSUMS 0xda /* GET_FEATURE */ +#define FU_WAC_REPORT_ID_SET_CHECKSUM_FOR_BLOCK 0xdb /* SET_FEATURE */ +#define FU_WAC_REPORT_ID_CALCULATE_CHECKSUM_FOR_BLOCK 0xdc /* SET_FEATURE */ +#define FU_WAC_REPORT_ID_WRITE_CHECKSUM_TABLE 0xde /* SET_FEATURE */ +#define FU_WAC_REPORT_ID_GET_CURRENT_FIRMWARE_IDX 0xe2 /* GET_FEATURE */ +#define FU_WAC_REPORT_ID_MODULE 0xe4 + +guint32 fu_wac_calculate_checksum32le (const guint8 *data, + gsize len); +guint32 fu_wac_calculate_checksum32le_bytes (GBytes *blob); +const gchar *fu_wac_report_id_to_string (guint8 report_id); +void fu_wac_buffer_dump (const gchar *title, + guint8 cmd, + const guint8 *buf, + gsize sz); + +G_END_DECLS diff -Nru fwupd-1.1.4/plugins/wacom-usb/fu-wac-device.c fwupd-1.2.5/plugins/wacom-usb/fu-wac-device.c --- fwupd-1.1.4/plugins/wacom-usb/fu-wac-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-usb/fu-wac-device.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,911 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-chunk.h" +#include "fu-wac-device.h" +#include "fu-wac-common.h" +#include "fu-wac-firmware.h" +#include "fu-wac-module-bluetooth.h" +#include "fu-wac-module-touch.h" + +#include "dfu-common.h" +#include "dfu-firmware.h" + +typedef struct __attribute__((packed)) { + guint32 start_addr; + guint32 block_sz; + guint16 write_sz; /* bit 15 is write protection flag */ +} FuWacFlashDescriptor; + +typedef enum { + FU_WAC_STATUS_UNKNOWN = 0, + FU_WAC_STATUS_WRITING = 1 << 0, + FU_WAC_STATUS_ERASING = 1 << 1, + FU_WAC_STATUS_ERROR_WRITE = 1 << 2, + FU_WAC_STATUS_ERROR_ERASE = 1 << 3, + FU_WAC_STATUS_WRITE_PROTECTED = 1 << 4, + FU_WAC_STATUS_LAST +} FuWacStatus; + +#define FU_WAC_DEVICE_TIMEOUT 5000 /* ms */ + +struct _FuWacDevice +{ + FuUsbDevice parent_instance; + GPtrArray *flash_descriptors; + GArray *checksums; + guint32 status_word; + guint16 firmware_index; + guint16 loader_ver; + guint16 read_data_sz; + guint16 write_word_sz; + guint16 write_block_sz; /* usb transfer size */ + guint16 nr_flash_blocks; + guint16 configuration; +}; + +G_DEFINE_TYPE (FuWacDevice, fu_wac_device, FU_TYPE_USB_DEVICE) + +static GString * +fu_wac_device_status_to_string (guint32 status_word) +{ + GString *str = g_string_new (NULL); + if (status_word & FU_WAC_STATUS_WRITING) + g_string_append (str, "writing,"); + if (status_word & FU_WAC_STATUS_ERASING) + g_string_append (str, "erasing,"); + if (status_word & FU_WAC_STATUS_ERROR_WRITE) + g_string_append (str, "error-write,"); + if (status_word & FU_WAC_STATUS_ERROR_ERASE) + g_string_append (str, "error-erase,"); + if (status_word & FU_WAC_STATUS_WRITE_PROTECTED) + g_string_append (str, "write-protected,"); + if (str->len == 0) { + g_string_append (str, "none"); + return str; + } + g_string_truncate (str, str->len - 1); + return str; +} + +static gboolean +fu_wav_device_flash_descriptor_is_wp (const FuWacFlashDescriptor *fd) +{ + return fd->write_sz & 0x8000; +} + +static void +fu_wac_device_to_string (FuDevice *device, GString *str) +{ + GPtrArray *children; + FuWacDevice *self = FU_WAC_DEVICE (device); + g_autoptr(GString) status_str = NULL; + + g_string_append (str, " FuWacDevice:\n"); + if (self->firmware_index != 0xffff) { + g_string_append_printf (str, " fw-index: 0x%04x\n", + self->firmware_index); + } + if (self->loader_ver > 0) { + g_string_append_printf (str, " loader-ver: 0x%04x\n", + (guint) self->loader_ver); + } + if (self->read_data_sz > 0) { + g_string_append_printf (str, " read-data-sz: 0x%04x\n", + (guint) self->read_data_sz); + } + if (self->write_word_sz > 0) { + g_string_append_printf (str, " write-word-sz: 0x%04x\n", + (guint) self->write_word_sz); + } + if (self->write_block_sz > 0) { + g_string_append_printf (str, " write-block-sz: 0x%04x\n", + (guint) self->write_block_sz); + } + if (self->nr_flash_blocks > 0) { + g_string_append_printf (str, " nr-flash-blocks: 0x%04x\n", + (guint) self->nr_flash_blocks); + } + if (self->configuration != 0xffff) { + g_string_append_printf (str, " configuration: 0x%04x\n", + (guint) self->configuration); + } + for (guint i = 0; i < self->flash_descriptors->len; i++) { + FuWacFlashDescriptor *fd = g_ptr_array_index (self->flash_descriptors, i); + g_string_append_printf (str, " flash-descriptor-%02u:\n", i); + g_string_append_printf (str, " start-addr:\t0x%08x\n", + (guint) fd->start_addr); + g_string_append_printf (str, " block-sz:\t0x%08x\n", + (guint) fd->block_sz); + g_string_append_printf (str, " write-sz:\t0x%04x\n", + (guint) fd->write_sz & ~0x8000); + g_string_append_printf (str, " protected:\t%s\n", + fu_wav_device_flash_descriptor_is_wp (fd) ? "yes" : "no"); + } + status_str = fu_wac_device_status_to_string (self->status_word); + g_string_append_printf (str, " status:\t\t%s\n", status_str->str); + + /* print children also */ + children = fu_device_get_children (device); + for (guint i = 0; i < children->len; i++) { + FuDevice *child = g_ptr_array_index (children, i); + g_autofree gchar *tmp = fu_device_to_string (FU_DEVICE (child)); + g_string_append (str, " FuWacDeviceChild:\n"); + g_string_append (str, tmp); + } +} + +gboolean +fu_wac_device_get_feature_report (FuWacDevice *self, + guint8 *buf, gsize bufsz, + FuWacDeviceFeatureFlags flags, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + gsize sz = 0; + guint8 cmd = buf[0]; + + /* hit hardware */ + if ((flags & FU_WAC_DEVICE_FEATURE_FLAG_NO_DEBUG) == 0) + fu_wac_buffer_dump ("GET", cmd, buf, bufsz); + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, + HID_REPORT_GET, /* bRequest */ + HID_FEATURE | cmd, /* wValue */ + 0x0000, /* wIndex */ + buf, bufsz, &sz, + FU_WAC_DEVICE_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "Failed to get feature report: "); + return FALSE; + } + if ((flags & FU_WAC_DEVICE_FEATURE_FLAG_NO_DEBUG) == 0) + fu_wac_buffer_dump ("GE2", cmd, buf, sz); + + /* check packet */ + if ((flags & FU_WAC_DEVICE_FEATURE_FLAG_ALLOW_TRUNC) == 0 && sz != bufsz) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "packet get bytes %" G_GSIZE_FORMAT + " expected %" G_GSIZE_FORMAT, + sz, bufsz); + return FALSE; + } + if (buf[0] != cmd) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "command response was %i expected %i", + buf[0], cmd); + return FALSE; + } + return TRUE; +} + +gboolean +fu_wac_device_set_feature_report (FuWacDevice *self, + guint8 *buf, gsize bufsz, + FuWacDeviceFeatureFlags flags, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + gsize sz = 0; + guint8 cmd = buf[0]; + + /* hit hardware */ + fu_wac_buffer_dump ("SET", cmd, buf, bufsz); + if (g_getenv ("FWUPD_WAC_EMULATE") != NULL) + return TRUE; + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, + HID_REPORT_SET, /* bRequest */ + HID_FEATURE | cmd, /* wValue */ + 0x0000, /* wIndex */ + buf, bufsz, &sz, + FU_WAC_DEVICE_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "Failed to set feature report: "); + return FALSE; + } + + /* check packet */ + if ((flags & FU_WAC_DEVICE_FEATURE_FLAG_ALLOW_TRUNC) == 0 && sz != bufsz) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "packet sent bytes %" G_GSIZE_FORMAT + " expected %" G_GSIZE_FORMAT, + sz, bufsz); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_wac_device_ensure_flash_descriptors (FuWacDevice *self, GError **error) +{ + gsize sz = (self->nr_flash_blocks * 10) + 1; + g_autofree guint8 *buf = NULL; + + /* already done */ + if (self->flash_descriptors->len > 0) + return TRUE; + + /* hit hardware */ + buf = g_malloc (sz); + memset (buf, 0xff, sz); + buf[0] = FU_WAC_REPORT_ID_GET_FLASH_DESCRIPTOR; + if (!fu_wac_device_get_feature_report (self, buf, sz, + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error)) + return FALSE; + + /* parse */ + for (guint i = 0; i < self->nr_flash_blocks; i++) { + FuWacFlashDescriptor *fd = g_new0 (FuWacFlashDescriptor, 1); + const guint blksz = sizeof(FuWacFlashDescriptor); + fd->start_addr = fu_common_read_uint32 (buf + (i * blksz) + 1, G_LITTLE_ENDIAN); + fd->block_sz = fu_common_read_uint32 (buf + (i * blksz) + 5, G_LITTLE_ENDIAN); + fd->write_sz = fu_common_read_uint16 (buf + (i * blksz) + 9, G_LITTLE_ENDIAN); + g_ptr_array_add (self->flash_descriptors, fd); + } + g_debug ("added %u flash descriptors", self->flash_descriptors->len); + return TRUE; +} + +static gboolean +fu_wac_device_ensure_status (FuWacDevice *self, GError **error) +{ + g_autoptr(GString) str = NULL; + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_GET_STATUS, + [1 ... 4] = 0xff }; + + /* hit hardware */ + buf[0] = FU_WAC_REPORT_ID_GET_STATUS; + if (!fu_wac_device_get_feature_report (self, buf, sizeof(buf), + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error)) + return FALSE; + + /* parse */ + self->status_word = fu_common_read_uint32 (buf + 1, G_LITTLE_ENDIAN); + str = fu_wac_device_status_to_string (self->status_word); + g_debug ("status now: %s", str->str); + return TRUE; +} + +static gboolean +fu_wac_device_ensure_checksums (FuWacDevice *self, GError **error) +{ + gsize sz = (self->nr_flash_blocks * 4) + 5; + guint32 updater_version; + g_autofree guint8 *buf = g_malloc (sz); + + /* hit hardware */ + memset (buf, 0xff, sz); + buf[0] = FU_WAC_REPORT_ID_GET_CHECKSUMS; + if (!fu_wac_device_get_feature_report (self, buf, sz, + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error)) + return FALSE; + + /* parse */ + updater_version = fu_common_read_uint32 (buf + 1, G_LITTLE_ENDIAN); + g_debug ("updater-version: %" G_GUINT32_FORMAT, updater_version); + + /* get block checksums */ + g_array_set_size (self->checksums, 0); + for (guint i = 0; i < self->nr_flash_blocks; i++) { + guint32 csum = fu_common_read_uint32 (buf + 5 + (i * 4), G_LITTLE_ENDIAN); + g_debug ("checksum block %02u: 0x%08x", i, (guint) csum); + g_array_append_val (self->checksums, csum); + } + g_debug ("added %u checksums", self->flash_descriptors->len); + + return TRUE; +} + + +static gboolean +fu_wac_device_ensure_firmware_index (FuWacDevice *self, GError **error) +{ + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_GET_CURRENT_FIRMWARE_IDX, + [1 ... 2] = 0xff }; + + /* hit hardware */ + if (!fu_wac_device_get_feature_report (self, buf, sizeof(buf), + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error)) + return FALSE; + + /* parse */ + self->firmware_index = fu_common_read_uint16 (buf + 1, G_LITTLE_ENDIAN); + return TRUE; +} + +static gboolean +fu_wac_device_ensure_parameters (FuWacDevice *self, GError **error) +{ + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_GET_PARAMETERS, + [1 ... 12] = 0xff }; + + /* hit hardware */ + if (!fu_wac_device_get_feature_report (self, buf, sizeof(buf), + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error)) + return FALSE; + + /* parse */ + self->loader_ver = fu_common_read_uint16 (buf + 1, G_LITTLE_ENDIAN); + self->read_data_sz = fu_common_read_uint16 (buf + 3, G_LITTLE_ENDIAN); + self->write_word_sz = fu_common_read_uint16 (buf + 5, G_LITTLE_ENDIAN); + self->write_block_sz = fu_common_read_uint16 (buf + 7, G_LITTLE_ENDIAN); + self->nr_flash_blocks = fu_common_read_uint16 (buf + 9, G_LITTLE_ENDIAN); + self->configuration = fu_common_read_uint16 (buf + 11, G_LITTLE_ENDIAN); + return TRUE; +} + +static gboolean +fu_wac_device_write_block (FuWacDevice *self, + guint32 addr, + GBytes *blob, + GError **error) +{ + const guint8 *tmp; + gsize bufsz = self->write_block_sz + 5; + gsize sz = 0; + g_autofree guint8 *buf = NULL; + + /* check size */ + tmp = g_bytes_get_data (blob, &sz); + if (sz > self->write_block_sz) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "packet was too large at %" G_GSIZE_FORMAT " bytes", + sz); + return FALSE; + } + + /* build packet */ + buf = g_malloc (bufsz); + memset (buf, 0xff, bufsz); + buf[0] = FU_WAC_REPORT_ID_WRITE_BLOCK; + fu_common_write_uint32 (buf + 1, addr, G_LITTLE_ENDIAN); + if (sz > 0) + memcpy (buf + 5, tmp, sz); + + /* hit hardware */ + return fu_wac_device_set_feature_report (self, buf, bufsz, + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error); +} + +static gboolean +fu_wac_device_erase_block (FuWacDevice *self, guint32 addr, GError **error) +{ + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_ERASE_BLOCK, + [1 ... 4] = 0xff }; + + /* build packet */ + fu_common_write_uint32 (buf + 1, addr, G_LITTLE_ENDIAN); + + /* hit hardware */ + return fu_wac_device_set_feature_report (self, buf, sizeof(buf), + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error); +} + +gboolean +fu_wac_device_update_reset (FuWacDevice *self, GError **error) +{ + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_UPDATE_RESET, + [1 ... 4] = 0xff }; + + /* hit hardware */ + return fu_wac_device_set_feature_report (self, buf, sizeof(buf), + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error); +} + +static gboolean +fu_wac_device_set_checksum_of_block (FuWacDevice *self, + guint16 block_nr, + guint32 checksum, + GError **error) +{ + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_SET_CHECKSUM_FOR_BLOCK, + [1 ... 6] = 0xff }; + + /* build packet */ + fu_common_write_uint16 (buf + 1, block_nr, G_LITTLE_ENDIAN); + fu_common_write_uint32 (buf + 3, checksum, G_LITTLE_ENDIAN); + + /* hit hardware */ + return fu_wac_device_set_feature_report (self, buf, sizeof(buf), + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error); +} + +static gboolean +fu_wac_device_calculate_checksum_of_block (FuWacDevice *self, + guint16 block_nr, + GError **error) +{ + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_CALCULATE_CHECKSUM_FOR_BLOCK, + [1 ... 2] = 0xff }; + + /* build packet */ + fu_common_write_uint16 (buf + 1, block_nr, G_LITTLE_ENDIAN); + + /* hit hardware */ + return fu_wac_device_set_feature_report (self, buf, sizeof(buf), + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error); +} + +static gboolean +fu_wac_device_write_checksum_table (FuWacDevice *self, GError **error) +{ + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_WRITE_CHECKSUM_TABLE, + [1 ... 4] = 0xff }; + + /* hit hardware */ + return fu_wac_device_set_feature_report (self, buf, sizeof(buf), + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error); +} + +static gboolean +fu_wac_device_switch_to_flash_loader (FuWacDevice *self, GError **error) +{ + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_SWITCH_TO_FLASH_LOADER, + [1] = 0x05, + [2] = 0x6a }; + + /* hit hardware */ + return fu_wac_device_set_feature_report (self, buf, sizeof(buf), + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error); +} + +static gboolean +fu_wac_device_write_firmware (FuDevice *device, GBytes *blob, GError **error) +{ + DfuElement *element; + DfuImage *image; + FuWacDevice *self = FU_WAC_DEVICE (device); + gsize blocks_done = 0; + gsize blocks_total = 0; + g_autoptr(DfuFirmware) firmware = dfu_firmware_new (); + g_autoptr(GHashTable) fd_blobs = NULL; + g_autofree guint32 *csum_local = NULL; + + /* load .wac file, including metadata */ + if (!fu_wac_firmware_parse_data (firmware, blob, + DFU_FIRMWARE_PARSE_FLAG_NONE, + error)) + return FALSE; + if (dfu_firmware_get_format (firmware) != DFU_FIRMWARE_FORMAT_SREC) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "expected firmware format is 'srec', got '%s'", + dfu_firmware_format_to_string (dfu_firmware_get_format (firmware))); + return FALSE; + } + + /* enter flash mode */ + if (!fu_wac_device_switch_to_flash_loader (self, error)) + return FALSE; + + /* get current selected device */ + if (!fu_wac_device_ensure_firmware_index (self, error)) + return FALSE; + + /* use the correct image from the firmware */ + image = dfu_firmware_get_image (firmware, self->firmware_index == 1 ? 1 : 0); + if (image == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no firmware image for index %" G_GUINT16_FORMAT, + self->firmware_index); + return FALSE; + } + element = dfu_image_get_element_default (image); + if (element == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no element in image %" G_GUINT16_FORMAT, + self->firmware_index); + return FALSE; + } + g_debug ("using element at addr 0x%0x", + (guint) dfu_element_get_address (element)); + + /* get firmware parameters (page sz and transfer sz) */ + if (!fu_wac_device_ensure_parameters (self, error)) + return FALSE; + + /* get the current flash descriptors */ + if (!fu_wac_device_ensure_flash_descriptors (self, error)) + return FALSE; + + /* get the updater protocol version */ + if (!fu_wac_device_ensure_checksums (self, error)) + return FALSE; + + /* clear all checksums of pages */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + for (guint16 i = 0; i < self->flash_descriptors->len; i++) { + FuWacFlashDescriptor *fd = g_ptr_array_index (self->flash_descriptors, i); + if (fu_wav_device_flash_descriptor_is_wp (fd)) + continue; + if (!fu_wac_device_set_checksum_of_block (self, i, 0x0, error)) + return FALSE; + } + + /* get the blobs for each chunk */ + fd_blobs = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify) g_bytes_unref); + for (guint16 i = 0; i < self->flash_descriptors->len; i++) { + FuWacFlashDescriptor *fd = g_ptr_array_index (self->flash_descriptors, i); + GBytes *blob_block; + g_autoptr(GBytes) blob_tmp = NULL; + + if (fu_wav_device_flash_descriptor_is_wp (fd)) + continue; + blob_tmp = dfu_element_get_contents_chunk (element, + fd->start_addr, + fd->block_sz, + NULL); + if (blob_tmp == NULL) + break; + blob_block = dfu_utils_bytes_pad (blob_tmp, fd->block_sz); + g_hash_table_insert (fd_blobs, fd, blob_block); + } + + /* checksum actions post-write */ + blocks_total = g_hash_table_size (fd_blobs) + 2; + + /* write the data into the flash page */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + csum_local = g_new0 (guint32, self->flash_descriptors->len); + for (guint16 i = 0; i < self->flash_descriptors->len; i++) { + FuWacFlashDescriptor *fd = g_ptr_array_index (self->flash_descriptors, i); + GBytes *blob_block; + g_autoptr(GPtrArray) chunks = NULL; + + /* if page is protected */ + if (fu_wav_device_flash_descriptor_is_wp (fd)) + continue; + + /* get data for page */ + blob_block = g_hash_table_lookup (fd_blobs, fd); + if (blob_block == NULL) + break; + + /* ignore empty blocks */ + if (dfu_utils_bytes_is_empty (blob_block)) { + g_debug ("empty block, ignoring"); + fu_device_set_progress_full (device, blocks_done++, blocks_total); + continue; + } + + /* erase entire block */ + if (!fu_wac_device_erase_block (self, i, error)) + return FALSE; + + /* write block in chunks */ + chunks = fu_chunk_array_new_from_bytes (blob_block, + fd->start_addr, + 0, /* page_sz */ + self->write_block_sz); + for (guint j = 0; j < chunks->len; j++) { + FuChunk *chk = g_ptr_array_index (chunks, j); + g_autoptr(GBytes) blob_chunk = g_bytes_new (chk->data, chk->data_sz); + if (!fu_wac_device_write_block (self, chk->address, blob_chunk, error)) + return FALSE; + } + + /* calculate expected checksum and save to device RAM */ + csum_local[i] = fu_wac_calculate_checksum32le_bytes (blob_block); + g_debug ("block checksum %02u: 0x%08x", i, csum_local[i]); + if (!fu_wac_device_set_checksum_of_block (self, i, csum_local[i], error)) + return FALSE; + + /* update device progress */ + fu_device_set_progress_full (device, blocks_done++, blocks_total); + } + + /* calculate CRC inside device */ + for (guint16 i = 0; i < self->flash_descriptors->len; i++) { + if (!fu_wac_device_calculate_checksum_of_block (self, i, error)) + return FALSE; + } + + /* update device progress */ + fu_device_set_progress_full (device, blocks_done++, blocks_total); + + /* read all CRC of all pages and verify with local CRC */ + if (!fu_wac_device_ensure_checksums (self, error)) + return FALSE; + for (guint16 i = 0; i < self->flash_descriptors->len; i++) { + FuWacFlashDescriptor *fd = g_ptr_array_index (self->flash_descriptors, i); + GBytes *blob_block; + guint32 csum_rom; + + /* if page is protected */ + if (fu_wav_device_flash_descriptor_is_wp (fd)) + continue; + + /* no more written pages */ + blob_block = g_hash_table_lookup (fd_blobs, fd); + if (blob_block == NULL) + continue; + if (dfu_utils_bytes_is_empty (blob_block)) + continue; + + /* check checksum matches */ + csum_rom = g_array_index (self->checksums, guint32, i); + if (csum_rom != csum_local[i]) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed local checksum at block %u, " + "got 0x%08x expected 0x%08x", i, + (guint) csum_rom, (guint) csum_local[i]); + return FALSE; + } + g_debug ("matched checksum at block %u of 0x%08x", i, csum_rom); + } + + /* update device progress */ + fu_device_set_progress_full (device, blocks_done++, blocks_total); + + /* store host CRC into flash */ + if (!fu_wac_device_write_checksum_table (self, error)) + return FALSE; + + /* update progress */ + fu_device_set_progress_full (device, blocks_total, blocks_total); + return TRUE; +} + +static gboolean +fu_wac_device_add_modules_bluetooth (FuWacDevice *self, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + g_autofree gchar *name = NULL; + g_autofree gchar *version = NULL; + g_autoptr(FuWacModule) module = NULL; + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_GET_FIRMWARE_VERSION_BLUETOOTH, + [1 ... 14] = 0xff }; + + buf[0] = FU_WAC_REPORT_ID_GET_FIRMWARE_VERSION_BLUETOOTH; + if (!fu_wac_device_get_feature_report (self, buf, sizeof(buf), + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error)) { + g_prefix_error (error, "Failed to get GetFirmwareVersionBluetooth: "); + return FALSE; + } + + /* success */ + name = g_strdup_printf ("%s [Legacy Bluetooth Module]", + fu_device_get_name (FU_DEVICE (self))); + version = g_strdup_printf ("%x.%x", (guint) buf[2], (guint) buf[1]); + module = fu_wac_module_bluetooth_new (usb_device); + fu_device_add_child (FU_DEVICE (self), FU_DEVICE (module)); + fu_device_set_name (FU_DEVICE (module), name); + fu_device_set_version (FU_DEVICE (module), version); + return TRUE; +} + +static gboolean +fu_wac_device_add_modules_legacy (FuWacDevice *self, GError **error) +{ + g_autoptr(GError) error_bt = NULL; + + /* optional bluetooth */ + if (!fu_wac_device_add_modules_bluetooth (self, &error_bt)) + g_debug ("no bluetooth hardware: %s", error_bt->message); + + return TRUE; +} + +static gboolean +fu_wac_device_add_modules (FuWacDevice *self, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + g_autofree gchar *version_bootloader = NULL; + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_FW_DESCRIPTOR, + [1 ... 31] = 0xff }; + + if (!fu_wac_device_get_feature_report (self, buf, sizeof(buf), + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error)) { + g_prefix_error (error, "Failed to get DeviceFirmwareDescriptor: "); + return FALSE; + } + + /* verify bootloader is compatible */ + if (buf[1] != 0x01) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "bootloader major version not compatible"); + return FALSE; + } + + /* verify the number of submodules is possible */ + if (buf[3] > (512 - 4) / 4) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "number of submodules is impossible"); + return FALSE; + } + + /* bootloader version */ + version_bootloader = g_strdup_printf ("%u.%u", buf[1], buf[2]); + fu_device_set_version_bootloader (FU_DEVICE (self), version_bootloader); + + /* get versions of each submodule */ + for (guint8 i = 0; i < buf[3]; i++) { + guint8 fw_type = buf[(i * 4) + 4] & ~0x80; + g_autofree gchar *name = NULL; + g_autofree gchar *version = NULL; + g_autoptr(FuWacModule) module = NULL; + + /* version number is decimal */ + version = g_strdup_printf ("%u.%u", buf[(i * 4) + 5], buf[(i * 4) + 6]); + + switch (fw_type) { + case FU_WAC_MODULE_FW_TYPE_TOUCH: + module = fu_wac_module_touch_new (usb_device); + name = g_strdup_printf ("%s [Touch Module]", + fu_device_get_name (FU_DEVICE (self))); + fu_device_add_child (FU_DEVICE (self), FU_DEVICE (module)); + fu_device_set_name (FU_DEVICE (module), name); + fu_device_set_version (FU_DEVICE (module), version); + break; + case FU_WAC_MODULE_FW_TYPE_BLUETOOTH: + module = fu_wac_module_bluetooth_new (usb_device); + name = g_strdup_printf ("%s [Bluetooth Module]", + fu_device_get_name (FU_DEVICE (self))); + fu_device_add_child (FU_DEVICE (self), FU_DEVICE (module)); + fu_device_set_name (FU_DEVICE (module), name); + fu_device_set_version (FU_DEVICE (module), version); + break; + case FU_WAC_MODULE_FW_TYPE_MAIN: + fu_device_set_version (FU_DEVICE (self), version); + break; + default: + g_warning ("unknown submodule type 0x%0x", fw_type); + break; + } + } + return TRUE; +} + +static gboolean +fu_wac_device_open (FuUsbDevice *device, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (device); + + /* open device */ + if (!g_usb_device_claim_interface (usb_device, 0x00, /* HID */ + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error)) { + g_prefix_error (error, "failed to claim HID interface: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_wac_device_setup (FuDevice *device, GError **error) +{ + FuWacDevice *self = FU_WAC_DEVICE (device); + + /* get current status */ + if (!fu_wac_device_ensure_status (self, error)) + return FALSE; + + /* get version of each sub-module */ + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_USE_RUNTIME_VERSION)) { + if (!fu_wac_device_add_modules_legacy (self, error)) + return FALSE; + } else { + if (!fu_wac_device_add_modules (self, error)) + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_wac_device_close (FuUsbDevice *device, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (device); + + /* reattach wacom.ko */ + if (!g_usb_device_release_interface (usb_device, 0x00, /* HID */ + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error)) { + g_prefix_error (error, "failed to re-attach interface: "); + return FALSE; + } + + /* The hidcore subsystem uses a generic power_supply that has a deferred + * work item that will lock the device. When removing the power_supply, + * we take the lock, then cancel the work item which needs to take the + * lock too. This needs to be fixed in the kernel, but for the moment + * this should let the kernel unstick itself. */ + g_usleep (20 * 1000); + + /* success */ + return TRUE; +} + +static void +fu_wac_device_init (FuWacDevice *self) +{ + self->flash_descriptors = g_ptr_array_new_with_free_func (g_free); + self->checksums = g_array_new (FALSE, FALSE, sizeof(guint32)); + self->configuration = 0xffff; + self->firmware_index = 0xffff; + fu_device_add_icon (FU_DEVICE (self), "input-tablet"); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_install_duration (FU_DEVICE (self), 10); +} + +static void +fu_wac_device_finalize (GObject *object) +{ + FuWacDevice *self = FU_WAC_DEVICE (object); + + g_ptr_array_unref (self->flash_descriptors); + g_array_unref (self->checksums); + + G_OBJECT_CLASS (fu_wac_device_parent_class)->finalize (object); +} + +static void +fu_wac_device_class_init (FuWacDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); + object_class->finalize = fu_wac_device_finalize; + klass_device->write_firmware = fu_wac_device_write_firmware; + klass_device->to_string = fu_wac_device_to_string; + klass_device->setup = fu_wac_device_setup; + klass_usb_device->open = fu_wac_device_open; + klass_usb_device->close = fu_wac_device_close; +} + +FuWacDevice * +fu_wac_device_new (FuUsbDevice *device) +{ + FuWacDevice *self = g_object_new (FU_TYPE_WAC_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return self; +} diff -Nru fwupd-1.1.4/plugins/wacom-usb/fu-wac-device.h fwupd-1.2.5/plugins/wacom-usb/fu-wac-device.h --- fwupd-1.1.4/plugins/wacom-usb/fu-wac-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-usb/fu-wac-device.h 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +G_BEGIN_DECLS + +#define FU_TYPE_WAC_DEVICE (fu_wac_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuWacDevice, fu_wac_device, FU, WAC_DEVICE, FuUsbDevice) + +typedef enum { + FU_WAC_DEVICE_FEATURE_FLAG_NONE = 0, + FU_WAC_DEVICE_FEATURE_FLAG_ALLOW_TRUNC = 1 << 0, + FU_WAC_DEVICE_FEATURE_FLAG_NO_DEBUG = 1 << 1, + FU_WAC_DEVICE_FEATURE_FLAG_LAST +} FuWacDeviceFeatureFlags; + +FuWacDevice *fu_wac_device_new (FuUsbDevice *device); +gboolean fu_wac_device_update_reset (FuWacDevice *self, + GError **error); +gboolean fu_wac_device_get_feature_report (FuWacDevice *self, + guint8 *buf, + gsize bufsz, + FuWacDeviceFeatureFlags flags, + GError **error); +gboolean fu_wac_device_set_feature_report (FuWacDevice *self, + guint8 *buf, + gsize bufsz, + FuWacDeviceFeatureFlags flags, + GError **error); + +G_END_DECLS diff -Nru fwupd-1.1.4/plugins/wacom-usb/fu-wac-firmware.c fwupd-1.2.5/plugins/wacom-usb/fu-wac-firmware.c --- fwupd-1.1.4/plugins/wacom-usb/fu-wac-firmware.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-usb/fu-wac-firmware.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "dfu-element.h" +#include "dfu-format-srec.h" +#include "dfu-image.h" + +#include "fu-wac-firmware.h" + +#include "fwupd-error.h" + +typedef struct { + guint32 addr; + guint32 sz; + guint32 prog_start_addr; +} DfuFirmwareWacHeaderRecord; + +/** + * fu_wac_firmware_parse_data: + * @firmware: a #DfuFirmware + * @bytes: data to parse + * @flags: some #DfuFirmwareParseFlags + * @error: a #GError, or %NULL + * + * Unpacks into a firmware object from DfuSe data. + * + * Returns: %TRUE for success + **/ +gboolean +fu_wac_firmware_parse_data (DfuFirmware *firmware, + GBytes *bytes, + DfuFirmwareParseFlags flags, + GError **error) +{ + gsize len; + guint8 *data; + g_auto(GStrv) lines = NULL; + g_autoptr(GString) image_buffer = NULL; + g_autofree gchar *data_str = NULL; + guint8 images_cnt = 0; + g_autoptr(GPtrArray) header_infos = g_ptr_array_new_with_free_func (g_free); + + /* check the prefix (BE) */ + data = (guint8 *) g_bytes_get_data (bytes, &len); + if (memcmp (data, "WACOM", 5) != 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid .wac prefix"); + return FALSE; + } + + /* parse each line */ + data_str = g_strndup ((const gchar *) data, len); + lines = g_strsplit (data_str, "\n", -1); + for (guint i = 0; lines[i] != NULL; i++) { + g_autofree gchar *cmd = g_strndup (lines[i], 2); + + /* remove windows line endings */ + g_strdelimit (lines[i], "\r", '\0'); + + /* Wacom-specific metadata */ + if (g_strcmp0 (cmd, "WA") == 0) { + guint cmdlen = strlen (lines[i]); + + /* header info record */ + if (memcmp (lines[i] + 2, "COM", 3) == 0) { + guint8 header_image_cnt = 0; + if (cmdlen != 40) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid header, got %u bytes", + cmdlen); + return FALSE; + } + header_image_cnt = dfu_utils_buffer_parse_uint4 (lines[i] + 5); + for (guint j = 0; j < header_image_cnt; j++) { + DfuFirmwareWacHeaderRecord *hdr = g_new0 (DfuFirmwareWacHeaderRecord, 1); + hdr->addr = dfu_utils_buffer_parse_uint32 (lines[i] + (j * 16) + 6); + hdr->sz = dfu_utils_buffer_parse_uint32 (lines[i] + (j * 16) + 14); + g_ptr_array_add (header_infos, hdr); + g_debug ("header_fw%u_addr: 0x%x", j, hdr->addr); + g_debug ("header_fw%u_sz: 0x%x", j, hdr->sz); + } + continue; + } + + /* firmware headline record */ + if (cmdlen == 13) { + DfuFirmwareWacHeaderRecord *hdr; + guint8 idx = dfu_utils_buffer_parse_uint4 (lines[i] + 2); + if (idx == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "headline %u invalid", + idx); + return FALSE; + } + if (idx > header_infos->len) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "headline %u exceeds header count %u", + idx, header_infos->len); + return FALSE; + } + hdr = g_ptr_array_index (header_infos, idx - 1); + hdr->prog_start_addr = dfu_utils_buffer_parse_uint32 (lines[i] + 3); + if (hdr->prog_start_addr != hdr->addr) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "programming address 0x%x != " + "base address 0x%0x for idx %u", + hdr->prog_start_addr, + hdr->addr, + idx); + return FALSE; + } + g_debug ("programing-start-address: 0x%x", hdr->prog_start_addr); + continue; + } + + g_debug ("unknown Wacom-specific metadata"); + continue; + } + + /* start */ + if (g_strcmp0 (cmd, "S0") == 0) { + if (image_buffer != NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "duplicate S0 without S7"); + return FALSE; + } + image_buffer = g_string_new (NULL); + } + + /* these are things we want to include in the image */ + if (g_strcmp0 (cmd, "S0") == 0 || + g_strcmp0 (cmd, "S1") == 0 || + g_strcmp0 (cmd, "S2") == 0 || + g_strcmp0 (cmd, "S3") == 0 || + g_strcmp0 (cmd, "S5") == 0 || + g_strcmp0 (cmd, "S7") == 0 || + g_strcmp0 (cmd, "S8") == 0 || + g_strcmp0 (cmd, "S9") == 0) { + if (image_buffer == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "%s without S0", cmd); + return FALSE; + } + g_string_append_printf (image_buffer, "%s\n", lines[i]); + } + + /* end */ + if (g_strcmp0 (cmd, "S7") == 0) { + g_autoptr(GBytes) blob = NULL; + g_autoptr(DfuImage) image = dfu_image_new (); + DfuFirmwareWacHeaderRecord *hdr; + + /* get the correct relocated start address */ + if (images_cnt >= header_infos->len) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "%s without header", cmd); + return FALSE; + } + hdr = g_ptr_array_index (header_infos, images_cnt); + + if (image_buffer == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "%s with missing image buffer", cmd); + return FALSE; + } + + /* parse SREC file and add as image */ + blob = g_bytes_new (image_buffer->str, image_buffer->len); + if (!dfu_image_from_srec (image, blob, hdr->addr, flags, error)) + return FALSE; + + /* the alt-setting is used for the firmware index */ + dfu_image_set_alt_setting (image, images_cnt); + dfu_firmware_add_image (firmware, image); + images_cnt++; + + /* clear the image buffer */ + g_string_free (image_buffer, TRUE); + image_buffer = NULL; + } + } + + /* verify data is complete */ + if (image_buffer != NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "truncated data: no S7"); + return FALSE; + } + + /* ensure this matched the header */ + if (header_infos->len != images_cnt) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "not enough images %u for header count %u", + images_cnt, + header_infos->len); + return FALSE; + } + + /* success */ + dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_SREC); + return TRUE; +} diff -Nru fwupd-1.1.4/plugins/wacom-usb/fu-wac-firmware.h fwupd-1.2.5/plugins/wacom-usb/fu-wac-firmware.h --- fwupd-1.1.4/plugins/wacom-usb/fu-wac-firmware.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-usb/fu-wac-firmware.h 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#include "dfu-firmware.h" + +G_BEGIN_DECLS + +gboolean fu_wac_firmware_parse_data (DfuFirmware *firmware, + GBytes *bytes, + DfuFirmwareParseFlags flags, + GError **error); + +G_END_DECLS diff -Nru fwupd-1.1.4/plugins/wacom-usb/fu-wac-module-bluetooth.c fwupd-1.2.5/plugins/wacom-usb/fu-wac-module-bluetooth.c --- fwupd-1.1.4/plugins/wacom-usb/fu-wac-module-bluetooth.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-usb/fu-wac-module-bluetooth.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-wac-common.h" +#include "fu-wac-device.h" +#include "fu-wac-module-bluetooth.h" + +struct _FuWacModuleBluetooth +{ + FuWacModule parent_instance; +}; + +G_DEFINE_TYPE (FuWacModuleBluetooth, fu_wac_module_bluetooth, FU_TYPE_WAC_MODULE) + +#define FU_WAC_MODULE_BLUETOOTH_PAYLOAD_SZ 256 +#define FU_WAC_MODULE_BLUETOOTH_ADDR_USERDATA_START 0x3000 +#define FU_WAC_MODULE_BLUETOOTH_ADDR_USERDATA_STOP 0x8000 + +typedef struct { + guint8 preamble[7]; + guint8 addr[3]; + guint8 crc; + guint8 cdata[FU_WAC_MODULE_BLUETOOTH_PAYLOAD_SZ]; +} FuWacModuleBluetoothBlockData; + +static void +fu_wac_module_bluetooth_calculate_crc_byte (guint8 *crc, guint8 data) +{ + guint8 c[8]; + guint8 m[8]; + guint8 r[8]; + + /* find out what bits are set */ + for (guint i = 0; i < 8; i++) { + c[i] = (*crc & (1 << i)) != 0; + m[i] = (data & (1 << i)) != 0; + } + + /* do CRC on byte */ + r[7] = (c[7] ^ m[4] ^ c[3] ^ m[3] ^ c[4] ^ m[6] ^ c[1] ^ m[0]); + r[6] = (c[6] ^ m[5] ^ c[2] ^ m[4] ^ c[3] ^ m[7] ^ c[0] ^ m[1]); + r[5] = (c[5] ^ m[6] ^ c[1] ^ m[5] ^ c[2] ^ m[2]); + r[4] = (c[4] ^ m[7] ^ c[0] ^ m[6] ^ c[1] ^ m[3]); + r[3] = (m[7] ^ m[0] ^ c[7] ^ c[0] ^ m[3] ^ c[4] ^ m[6] ^ c[1]); + r[2] = (m[1] ^ c[6] ^ m[0] ^ c[7] ^ m[3] ^ c[4] ^ m[7] ^ c[0] ^ m[6] ^ c[1]); + r[1] = (m[2] ^ c[5] ^ m[1] ^ c[6] ^ m[4] ^ c[3] ^ m[7] ^ c[0]); + r[0] = (m[3] ^ c[4] ^ m[2] ^ c[5] ^ m[5] ^ c[2]); + + /* copy back into CRC */ + *crc = 0; + for (guint i = 0; i < 8; i++) { + if (r[i] == 0) + continue; + *crc |= (1 << i); + } +} + +static guint8 +fu_wac_module_bluetooth_calculate_crc (const guint8 *data, gsize sz) +{ + guint8 crc = 0; + for (gsize i = 0; i < sz; i++) + fu_wac_module_bluetooth_calculate_crc_byte (&crc, data[i]); + return crc; +} + +static GPtrArray * +fu_wac_module_bluetooth_parse_blocks (const guint8 *data, gsize sz, gboolean skip_user_data) +{ + const guint8 preamble[] = {0x02, 0x00, 0x0f, 0x06, 0x01, 0x08, 0x01}; + GPtrArray *blocks = g_ptr_array_new_with_free_func (g_free); + for (guint addr = 0x0; addr < sz; addr += FU_WAC_MODULE_BLUETOOTH_PAYLOAD_SZ) { + FuWacModuleBluetoothBlockData *bd; + gsize cdata_sz = FU_WAC_MODULE_BLUETOOTH_PAYLOAD_SZ; + + /* user data area */ + if (skip_user_data && + addr >= FU_WAC_MODULE_BLUETOOTH_ADDR_USERDATA_START && + addr < FU_WAC_MODULE_BLUETOOTH_ADDR_USERDATA_STOP) + continue; + + bd = g_new0 (FuWacModuleBluetoothBlockData, 1); + memcpy (bd->preamble, preamble, sizeof (preamble)); + bd->addr[0] = (addr >> 16) & 0xff; + bd->addr[1] = (addr >> 8) & 0xff; + bd->addr[2] = addr & 0xff; + memset (bd->cdata, 0xff, FU_WAC_MODULE_BLUETOOTH_PAYLOAD_SZ); + + /* if file is not in multiples of payload size */ + if (addr + FU_WAC_MODULE_BLUETOOTH_PAYLOAD_SZ >= sz) + cdata_sz = sz - addr; + memcpy (bd->cdata, data + addr, cdata_sz); + bd->crc = fu_wac_module_bluetooth_calculate_crc (bd->cdata, + FU_WAC_MODULE_BLUETOOTH_PAYLOAD_SZ); + g_ptr_array_add (blocks, bd); + } + return blocks; +} + +static gboolean +fu_wac_module_bluetooth_write_firmware (FuDevice *device, GBytes *blob, GError **error) +{ + FuWacModule *self = FU_WAC_MODULE (device); + const guint8 *data; + gsize len = 0; + gsize blocks_total = 0; + const guint8 buf_start[] = { 0x00 }; + g_autoptr(GPtrArray) blocks = NULL; + g_autoptr(GBytes) blob_start = g_bytes_new_static (buf_start, 1); + + /* build each data packet */ + data = g_bytes_get_data (blob, &len); + blocks = fu_wac_module_bluetooth_parse_blocks (data, len, TRUE); + blocks_total = blocks->len + 2; + + /* start, which will erase the module */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + if (!fu_wac_module_set_feature (self, FU_WAC_MODULE_COMMAND_START, blob_start, error)) + return FALSE; + + /* update progress */ + fu_device_set_progress_full (device, 1, blocks_total); + + /* data */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (guint i = 0; i < blocks->len; i++) { + FuWacModuleBluetoothBlockData *bd = g_ptr_array_index (blocks, i); + guint8 buf[256+11]; + g_autoptr(GBytes) blob_chunk = NULL; + + /* build data packet */ + memset (buf, 0xff, sizeof(buf)); + memcpy(&buf[0], bd->preamble, 7); + memcpy(&buf[7], bd->addr, 3); + buf[10] = bd->crc; + memcpy (&buf[11], bd->cdata, sizeof(bd->cdata)); + blob_chunk = g_bytes_new (buf, sizeof(buf)); + if (!fu_wac_module_set_feature (self, FU_WAC_MODULE_COMMAND_DATA, + blob_chunk, error)) + return FALSE; + + /* update progress */ + fu_device_set_progress_full (device, i + 1, blocks_total); + } + + /* end */ + if (!fu_wac_module_set_feature (self, FU_WAC_MODULE_COMMAND_END, NULL, error)) + return FALSE; + + /* update progress */ + fu_device_set_progress_full (device, blocks_total, blocks_total); + return TRUE; +} + +static void +fu_wac_module_bluetooth_init (FuWacModuleBluetooth *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_install_duration (FU_DEVICE (self), 30); +} + +static void +fu_wac_module_bluetooth_class_init (FuWacModuleBluetoothClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + klass_device->write_firmware = fu_wac_module_bluetooth_write_firmware; +} + +FuWacModule * +fu_wac_module_bluetooth_new (GUsbDevice *usb_device) +{ + FuWacModule *module = NULL; + module = g_object_new (FU_TYPE_WAC_MODULE_BLUETOOTH, + "usb-device", usb_device, + "fw-type", FU_WAC_MODULE_FW_TYPE_BLUETOOTH, + NULL); + return module; +} diff -Nru fwupd-1.1.4/plugins/wacom-usb/fu-wac-module-bluetooth.h fwupd-1.2.5/plugins/wacom-usb/fu-wac-module-bluetooth.h --- fwupd-1.1.4/plugins/wacom-usb/fu-wac-module-bluetooth.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-usb/fu-wac-module-bluetooth.h 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-wac-module.h" + +G_BEGIN_DECLS + +#define FU_TYPE_WAC_MODULE_BLUETOOTH (fu_wac_module_bluetooth_get_type ()) +G_DECLARE_FINAL_TYPE (FuWacModuleBluetooth, fu_wac_module_bluetooth, FU, WAC_MODULE_BLUETOOTH, FuWacModule) + +FuWacModule *fu_wac_module_bluetooth_new (GUsbDevice *usb_device); + +G_END_DECLS diff -Nru fwupd-1.1.4/plugins/wacom-usb/fu-wac-module.c fwupd-1.2.5/plugins/wacom-usb/fu-wac-module.c --- fwupd-1.1.4/plugins/wacom-usb/fu-wac-module.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-usb/fu-wac-module.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,369 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-wac-module.h" +#include "fu-wac-common.h" +#include "fu-wac-device.h" + +#include "dfu-common.h" +#include "dfu-firmware.h" + +#define FU_WAC_MODULE_STATUS_OK 0 +#define FU_WAC_MODULE_STATUS_BUSY 1 +#define FU_WAC_MODULE_STATUS_ERR_CRC 2 +#define FU_WAC_MODULE_STATUS_ERR_CMD 3 +#define FU_WAC_MODULE_STATUS_ERR_HW_ACCESS_FAIL 4 +#define FU_WAC_MODULE_STATUS_ERR_FLASH_NO_SUPPORT 5 +#define FU_WAC_MODULE_STATUS_ERR_MODE_WRONG 6 +#define FU_WAC_MODULE_STATUS_ERR_MPU_NO_SUPPORT 7 +#define FU_WAC_MODULE_STATUS_ERR_VERSION_NO_SUPPORT 8 +#define FU_WAC_MODULE_STATUS_ERR_ERASE 9 +#define FU_WAC_MODULE_STATUS_ERR_WRITE 10 +#define FU_WAC_MODULE_STATUS_ERR_EXIT 11 +#define FU_WAC_MODULE_STATUS_ERR 12 +#define FU_WAC_MODULE_STATUS_ERR_INVALID_OP 13 +#define FU_WAC_MODULE_STATUS_ERR_WRONG_IMAGE 14 + +typedef struct { + GUsbDevice *usb_device; + guint8 fw_type; + guint8 command; + guint8 status; +} FuWacModulePrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (FuWacModule, fu_wac_module, FU_TYPE_DEVICE) +#define GET_PRIVATE(o) (fu_wac_module_get_instance_private (o)) + +enum { + PROP_0, + PROP_FW_TYPE, + PROP_USB_DEVICE, + PROP_LAST +}; + +static const gchar * +fu_wac_module_fw_type_to_string (guint8 fw_type) +{ + if (fw_type == FU_WAC_MODULE_FW_TYPE_TOUCH) + return "touch"; + if (fw_type == FU_WAC_MODULE_FW_TYPE_BLUETOOTH) + return "bluetooth"; + if (fw_type == FU_WAC_MODULE_FW_TYPE_EMR_CORRECTION) + return "emr-correction"; + if (fw_type == FU_WAC_MODULE_FW_TYPE_BLUETOOTH_HID) + return "bluetooth-hid"; + return NULL; +} + +static const gchar * +fu_wac_module_command_to_string (guint8 command) +{ + if (command == FU_WAC_MODULE_COMMAND_START) + return "start"; + if (command == FU_WAC_MODULE_COMMAND_DATA) + return "data"; + if (command == FU_WAC_MODULE_COMMAND_END) + return "end"; + return NULL; +} + +static const gchar * +fu_wac_module_status_to_string (guint8 status) +{ + if (status == FU_WAC_MODULE_STATUS_OK) + return "ok"; + if (status == FU_WAC_MODULE_STATUS_BUSY) + return "busy"; + if (status == FU_WAC_MODULE_STATUS_ERR_CRC) + return "err-crc"; + if (status == FU_WAC_MODULE_STATUS_ERR_CMD) + return "err-cmd"; + if (status == FU_WAC_MODULE_STATUS_ERR_HW_ACCESS_FAIL) + return "err-hw-access-fail"; + if (status == FU_WAC_MODULE_STATUS_ERR_FLASH_NO_SUPPORT) + return "err-flash-no-support"; + if (status == FU_WAC_MODULE_STATUS_ERR_MODE_WRONG) + return "err-mode-wrong"; + if (status == FU_WAC_MODULE_STATUS_ERR_MPU_NO_SUPPORT) + return "err-mpu-no-support"; + if (status == FU_WAC_MODULE_STATUS_ERR_VERSION_NO_SUPPORT) + return "erro-version-no-support"; + if (status == FU_WAC_MODULE_STATUS_ERR_ERASE) + return "err-erase"; + if (status == FU_WAC_MODULE_STATUS_ERR_WRITE) + return "err-write"; + if (status == FU_WAC_MODULE_STATUS_ERR_EXIT) + return "err-exit"; + if (status == FU_WAC_MODULE_STATUS_ERR) + return "err-err"; + if (status == FU_WAC_MODULE_STATUS_ERR_INVALID_OP) + return "err-invalid-op"; + if (status == FU_WAC_MODULE_STATUS_ERR_WRONG_IMAGE) + return "err-wrong-image"; + return NULL; +} + +static void +fu_wac_module_to_string (FuDevice *device, GString *str) +{ + FuWacModule *self = FU_WAC_MODULE (device); + FuWacModulePrivate *priv = GET_PRIVATE (self); + g_string_append (str, " FuWacSubModule:\n"); + g_string_append_printf (str, " fw-type:\t\t%s\n", + fu_wac_module_fw_type_to_string (priv->fw_type)); + g_string_append_printf (str, " status:\t\t%s\n", + fu_wac_module_status_to_string (priv->status)); + g_string_append_printf (str, " command:\t\t%s\n", + fu_wac_module_command_to_string (priv->command)); +} + +static gboolean +fu_wac_module_refresh (FuWacModule *self, GError **error) +{ + FuWacDevice *parent_device = FU_WAC_DEVICE (fu_device_get_parent (FU_DEVICE (self))); + FuWacModulePrivate *priv = GET_PRIVATE (self); + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_MODULE, + [1 ... FU_WAC_PACKET_LEN - 1] = 0xff }; + + /* get from hardware */ + if (!fu_wac_device_get_feature_report (parent_device, buf, sizeof(buf), + FU_WAC_DEVICE_FEATURE_FLAG_ALLOW_TRUNC | + FU_WAC_DEVICE_FEATURE_FLAG_NO_DEBUG, + error)) { + g_prefix_error (error, "failed to refresh status: "); + return FALSE; + } + + /* check fw type */ + if (priv->fw_type != buf[1]) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Submodule GetFeature fw_Type invalid " + "got 0x%02x expected 0x%02x", + (guint) buf[1], (guint) priv->fw_type); + return FALSE; + } + + /* current phase and status */ + if (priv->command != buf[2] || priv->status != buf[3]) { + priv->command = buf[2]; + priv->status = buf[3]; + g_debug ("command: %s, status: %s", + fu_wac_module_command_to_string (priv->command), + fu_wac_module_status_to_string (priv->status)); + } + + /* success */ + return TRUE; +} + +gboolean +fu_wac_module_set_feature (FuWacModule *self, + guint8 command, + GBytes *blob, /* optional */ + GError **error) +{ + FuWacDevice *parent_device = FU_WAC_DEVICE (fu_device_get_parent (FU_DEVICE (self))); + FuWacModulePrivate *priv = GET_PRIVATE (self); + const guint8 *data; + gsize len = 0; + guint busy_poll_loops = 100; /* 1s */ + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_MODULE, + [1] = priv->fw_type, + [2] = command, + [3 ... FU_WAC_PACKET_LEN - 1] = 0xff }; + + /* verify the size of the blob */ + if (blob != NULL) { + data = g_bytes_get_data (blob, &len); + if (len > 509) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Submodule SetFeature blob larger than " + "buffer %" G_GSIZE_FORMAT, len); + return FALSE; + } + } + + /* build packet */ + if (len > 0) + memcpy (&buf[3], data, len); + + /* tell the daemon the current status */ + switch (command) { + case FU_WAC_MODULE_COMMAND_START: + fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_ERASE); + break; + case FU_WAC_MODULE_COMMAND_DATA: + fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_WRITE); + break; + case FU_WAC_MODULE_COMMAND_END: + fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_VERIFY); + break; + default: + break; + } + + /* send to hardware */ + if (!fu_wac_device_set_feature_report (parent_device, buf, len + 3, + FU_WAC_DEVICE_FEATURE_FLAG_ALLOW_TRUNC, + error)) { + g_prefix_error (error, "failed to set module feature: "); + return FALSE; + } + + /* special case StartProgram, as it can take much longer as it is + * erasing the blocks (15s) */ + if (command == FU_WAC_MODULE_COMMAND_START) + busy_poll_loops *= 15; + + /* wait for hardware */ + for (guint i = 0; i < busy_poll_loops; i++) { + if (!fu_wac_module_refresh (self, error)) + return FALSE; + if (priv->status == FU_WAC_MODULE_STATUS_BUSY) { + g_usleep (10000); /* 10ms */ + continue; + } + if (priv->status == FU_WAC_MODULE_STATUS_OK) + break; + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Failed to SetFeature: %s", + fu_wac_module_status_to_string (priv->status)); + return FALSE; + } + + /* too many retries */ + if (priv->status != FU_WAC_MODULE_STATUS_OK) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Timed out after %u loops with status %s", + busy_poll_loops, + fu_wac_module_status_to_string (priv->status)); + return FALSE; + } + + /* success */ + return TRUE; +} + +static void +fu_wac_module_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + FuWacModule *self = FU_WAC_MODULE (object); + FuWacModulePrivate *priv = GET_PRIVATE (self); + switch (prop_id) { + case PROP_FW_TYPE: + g_value_set_uint (value, priv->fw_type); + break; + case PROP_USB_DEVICE: + g_value_set_object (value, priv->usb_device); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +fu_wac_module_set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + FuWacModule *self = FU_WAC_MODULE (object); + FuWacModulePrivate *priv = GET_PRIVATE (self); + switch (prop_id) { + case PROP_FW_TYPE: + priv->fw_type = g_value_get_uint (value); + break; + case PROP_USB_DEVICE: + g_set_object (&priv->usb_device, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +fu_wac_module_init (FuWacModule *self) +{ +} + +static void +fu_wac_module_constructed (GObject *object) +{ + FuWacModule *self = FU_WAC_MODULE (object); + FuWacModulePrivate *priv = GET_PRIVATE (self); + g_autofree gchar *devid = NULL; + g_autofree gchar *vendor_id = NULL; + + /* set vendor ID */ + vendor_id = g_strdup_printf ("USB:0x%04X", g_usb_device_get_vid (priv->usb_device)); + fu_device_set_vendor_id (FU_DEVICE (self), vendor_id); + + /* set USB physical and logical IDs */ + fu_device_set_physical_id (FU_DEVICE (self), + g_usb_device_get_platform_id (priv->usb_device)); + fu_device_set_logical_id (FU_DEVICE (self), + fu_wac_module_fw_type_to_string (priv->fw_type)); + + /* append the firmware kind to the generated GUID */ + devid = g_strdup_printf ("USB\\VID_%04X&PID_%04X-%s", + g_usb_device_get_vid (priv->usb_device), + g_usb_device_get_pid (priv->usb_device), + fu_wac_module_fw_type_to_string (priv->fw_type)); + fu_device_add_instance_id (FU_DEVICE (self), devid); + + G_OBJECT_CLASS (fu_wac_module_parent_class)->constructed (object); +} + +static void +fu_wac_module_finalize (GObject *object) +{ + FuWacModule *self = FU_WAC_MODULE (object); + FuWacModulePrivate *priv = GET_PRIVATE (self); + if (priv->usb_device != NULL) + g_object_unref (priv->usb_device); + G_OBJECT_CLASS (fu_wac_module_parent_class)->finalize (object); +} + +static void +fu_wac_module_class_init (FuWacModuleClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + + /* properties */ + object_class->get_property = fu_wac_module_get_property; + object_class->set_property = fu_wac_module_set_property; + pspec = g_param_spec_object ("usb-device", NULL, NULL, + G_USB_TYPE_DEVICE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_USB_DEVICE, pspec); + pspec = g_param_spec_uint ("fw-type", NULL, NULL, + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_FW_TYPE, pspec); + + object_class->constructed = fu_wac_module_constructed; + object_class->finalize = fu_wac_module_finalize; + klass_device->to_string = fu_wac_module_to_string; +} diff -Nru fwupd-1.1.4/plugins/wacom-usb/fu-wac-module.h fwupd-1.2.5/plugins/wacom-usb/fu-wac-module.h --- fwupd-1.1.4/plugins/wacom-usb/fu-wac-module.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-usb/fu-wac-module.h 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +G_BEGIN_DECLS + +#define FU_TYPE_WAC_MODULE (fu_wac_module_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FuWacModule, fu_wac_module, FU, WAC_MODULE, FuDevice) + +struct _FuWacModuleClass +{ + FuDeviceClass parent_class; +}; + +#define FU_WAC_MODULE_FW_TYPE_TOUCH 0x00 +#define FU_WAC_MODULE_FW_TYPE_BLUETOOTH 0x01 +#define FU_WAC_MODULE_FW_TYPE_EMR_CORRECTION 0x02 +#define FU_WAC_MODULE_FW_TYPE_BLUETOOTH_HID 0x03 +#define FU_WAC_MODULE_FW_TYPE_MAIN 0x3f + +#define FU_WAC_MODULE_COMMAND_START 0x01 +#define FU_WAC_MODULE_COMMAND_DATA 0x02 +#define FU_WAC_MODULE_COMMAND_END 0x03 + +gboolean fu_wac_module_set_feature (FuWacModule *self, + guint8 command, + GBytes *blob, + GError **error); + +G_END_DECLS diff -Nru fwupd-1.1.4/plugins/wacom-usb/fu-wac-module-touch.c fwupd-1.2.5/plugins/wacom-usb/fu-wac-module-touch.c --- fwupd-1.1.4/plugins/wacom-usb/fu-wac-module-touch.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-usb/fu-wac-module-touch.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-wac-device.h" +#include "fu-wac-module-touch.h" + +#include "fu-chunk.h" +#include "dfu-firmware.h" + +struct _FuWacModuleTouch +{ + FuWacModule parent_instance; +}; + +G_DEFINE_TYPE (FuWacModuleTouch, fu_wac_module_touch, FU_TYPE_WAC_MODULE) + +static gboolean +fu_wac_module_touch_write_firmware (FuDevice *device, GBytes *blob, GError **error) +{ + DfuElement *element; + DfuImage *image; + FuWacModule *self = FU_WAC_MODULE (device); + gsize blocks_total = 0; + g_autoptr(GPtrArray) chunks = NULL; + g_autoptr(DfuFirmware) firmware = dfu_firmware_new (); + + /* load .hex file */ + if (!dfu_firmware_parse_data (firmware, blob, DFU_FIRMWARE_PARSE_FLAG_NONE, error)) + return FALSE; + + /* check type */ + if (dfu_firmware_get_format (firmware) != DFU_FIRMWARE_FORMAT_INTEL_HEX) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "expected firmware format is 'ihex', got '%s'", + dfu_firmware_format_to_string (dfu_firmware_get_format (firmware))); + return FALSE; + } + + /* use the correct image from the firmware */ + image = dfu_firmware_get_image (firmware, 0); + if (image == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no firmware image"); + return FALSE; + } + element = dfu_image_get_element_default (image); + if (element == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no firmware element"); + return FALSE; + } + g_debug ("using element at addr 0x%0x", + (guint) dfu_element_get_address (element)); + blob = dfu_element_get_contents (element); + + /* build each data packet */ + chunks = fu_chunk_array_new_from_bytes (blob, + dfu_element_get_address (element), + 0x0, /* page_sz */ + 128); /* packet_sz */ + blocks_total = chunks->len + 2; + + /* start, which will erase the module */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + if (!fu_wac_module_set_feature (self, FU_WAC_MODULE_COMMAND_START, NULL, error)) + return FALSE; + + /* update progress */ + fu_device_set_progress_full (device, 1, blocks_total); + + /* data */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + guint8 buf[128+7] = { 0xff }; + g_autoptr(GBytes) blob_chunk = NULL; + + /* build G11T data packet */ + memset (buf, 0xff, sizeof(buf)); + buf[0] = 0x01; /* writing */ + buf[1] = chk->idx + 1; + fu_common_write_uint32 (&buf[2], chk->address, G_LITTLE_ENDIAN); + buf[6] = 0x10; /* no idea! */ + memcpy (&buf[7], chk->data, chk->data_sz); + blob_chunk = g_bytes_new (buf, sizeof(buf)); + if (!fu_wac_module_set_feature (self, FU_WAC_MODULE_COMMAND_DATA, + blob_chunk, error)) { + g_prefix_error (error, "failed to write block %u: ", chk->idx); + return FALSE; + } + + /* update progress */ + fu_device_set_progress_full (device, i + 1, blocks_total); + } + + /* end */ + if (!fu_wac_module_set_feature (self, FU_WAC_MODULE_COMMAND_END, NULL, error)) + return FALSE; + + /* update progress */ + fu_device_set_progress_full (device, blocks_total, blocks_total); + return TRUE; +} + +static void +fu_wac_module_touch_init (FuWacModuleTouch *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_install_duration (FU_DEVICE (self), 30); +} + +static void +fu_wac_module_touch_class_init (FuWacModuleTouchClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + klass_device->write_firmware = fu_wac_module_touch_write_firmware; +} + +FuWacModule * +fu_wac_module_touch_new (GUsbDevice *usb_device) +{ + FuWacModule *module = NULL; + module = g_object_new (FU_TYPE_WAC_MODULE_TOUCH, + "usb-device", usb_device, + "fw-type", FU_WAC_MODULE_FW_TYPE_TOUCH, + NULL); + return module; +} diff -Nru fwupd-1.1.4/plugins/wacom-usb/fu-wac-module-touch.h fwupd-1.2.5/plugins/wacom-usb/fu-wac-module-touch.h --- fwupd-1.1.4/plugins/wacom-usb/fu-wac-module-touch.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-usb/fu-wac-module-touch.h 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-wac-module.h" + +G_BEGIN_DECLS + +#define FU_TYPE_WAC_MODULE_TOUCH (fu_wac_module_touch_get_type ()) +G_DECLARE_FINAL_TYPE (FuWacModuleTouch, fu_wac_module_touch, FU, WAC_MODULE_TOUCH, FuWacModule) + +FuWacModule *fu_wac_module_touch_new (GUsbDevice *usb_device); + +G_END_DECLS diff -Nru fwupd-1.1.4/plugins/wacom-usb/meson.build fwupd-1.2.5/plugins/wacom-usb/meson.build --- fwupd-1.1.4/plugins/wacom-usb/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-usb/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,68 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginWacomUsb"'] + +install_data(['wacom-usb.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_wacom_usb', + fu_hash, + sources : [ + 'fu-wac-common.c', + 'fu-wac-device.c', + 'fu-wac-firmware.c', + 'fu-wac-module.c', + 'fu-wac-module-bluetooth.c', + 'fu-wac-module-touch.c', + 'fu-plugin-wacom-usb.c', + ], + include_directories : [ + include_directories('../..'), + include_directories('../dfu'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + install : true, + install_dir: plugin_dir, + c_args : cargs, + dependencies : [ + plugin_deps, + ], + link_with : [ + libfwupdprivate, + dfu, + ], +) + +if get_option('tests') + testdatadir = join_paths(meson.current_source_dir(), 'tests') + cargs += '-DTESTDATADIR="' + testdatadir + '"' + e = executable( + 'wacom-usb-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-wac-common.c', + 'fu-wac-firmware.c', + ], + include_directories : [ + include_directories('..'), + include_directories('../dfu'), + include_directories('../..'), + include_directories('../../libfwupd'), + include_directories('../../src'), + ], + dependencies : [ + libxmlb, + gio, + gusb, + gudev, + libm, + ], + link_with : [ + dfu, + libfwupdprivate, + ], + c_args : cargs + ) + test('wacom-usb-self-test', e) +endif diff -Nru fwupd-1.1.4/plugins/wacom-usb/README.md fwupd-1.2.5/plugins/wacom-usb/README.md --- fwupd-1.1.4/plugins/wacom-usb/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-usb/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,41 @@ +Wacom USB Support +================= + +Introduction +------------ + +Wacom provides interactive pen displays, pen tablets, and styluses to equip and +inspire everyone make the world a more creative place. + +From 2016 Wacom has been using a HID-based proprietary flashing algorithm which +has been documented by support team at Wacom and provided under NDA under the +understanding it would be used to build a plugin under a LGPLv2+ licence. + +Wacom devices are actually composite devices, with the main ARM CPU being +programmed using a more complicated erase, write, verify algorithm based +on a historical update protocol. The "sub-module" devices use a newer protocol, +again based on HID, but are handled differently depending on thier type. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +the following formats: + + * Touch module: Intel HEX file format + * Bluetooth module: Unknown airoflash file format + * EMR module: Plain SREC file format + * Main module: SREC file format, with a custom `WACOM` vendor header + +This plugin supports the following protocol ID: + + * com.wacom.usb + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_056A&PID_0378&REV_0001` + * `USB\VID_056A&PID_0378` + * `USB\VID_056A` diff -Nru fwupd-1.1.4/plugins/wacom-usb/wacom-usb.quirk fwupd-1.2.5/plugins/wacom-usb/wacom-usb.quirk --- fwupd-1.1.4/plugins/wacom-usb/wacom-usb.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/plugins/wacom-usb/wacom-usb.quirk 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,58 @@ + +# Intuos Pro medium (2nd-gen BT) [PTH-660] +[DeviceInstanceId=USB\VID_056A&PID_0360] +Plugin = wacom_usb +Flags = use-runtime-version + +# Intuos Pro large (2nd-gen BT) [PTH-860] +[DeviceInstanceId=USB\VID_056A&PID_0361] +Plugin = wacom_usb +Flags = use-runtime-version + +# Intuos BT S (3rd-gen BT) [CTL-4100WL] +[DeviceInstanceId=USB\VID_056A&PID_0377] +Plugin = wacom_usb +Flags = use-runtime-version + +# Intuos BT M (3rd-gen BT) [CTL-6100WL] +[DeviceInstanceId=USB\VID_056A&PID_0379] +Plugin = wacom_usb +Flags = use-runtime-version + +# Intuos Pro medium (2nd-gen USB) [PTH-660] +[DeviceInstanceId=USB\VID_056A&PID_0357] +Plugin = wacom_usb +Flags = use-runtime-version + +# Intuos Pro large (2nd-gen USB) [PTH-860] +[DeviceInstanceId=USB\VID_056A&PID_0358] +Plugin = wacom_usb +Flags = use-runtime-version + +# Intuos S 3rd-gen (USB) [CTL-4100] +[DeviceInstanceId=USB\VID_056A&PID_0374] +Plugin = wacom_usb +Flags = use-runtime-version + +# Intuos M 3rd-gen (USB) [NA] +[DeviceInstanceId=USB\VID_056A&PID_0375] +Plugin = wacom_usb +Flags = use-runtime-version + +# Intuos BT S 3rd-gen (USB) [CTL-4100WL] +[DeviceInstanceId=USB\VID_056A&PID_0376] +Plugin = wacom_usb +Flags = use-runtime-version + +# Intuos BT M 3rd-gen (USB) [CTL-6100WL] +[DeviceInstanceId=USB\VID_056A&PID_0378] +Plugin = wacom_usb +Flags = use-runtime-version + +# Intuos Pro Small (2nd-gen USB) [PTH-460] +[DeviceInstanceId=USB\VID_056A&PID_0392] +Plugin = wacom_usb + +# Intuos Pro Small (2nd-gen Bluetooth) [PTH-460] +[DeviceInstanceId=USB\VID_056A&PID_0393] +Plugin = wacom_usb diff -Nru fwupd-1.1.4/po/af.po fwupd-1.2.5/po/af.po --- fwupd-1.1.4/po/af.po 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/po/af.po 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,417 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the fwupd package. +# +# Translators: +# F Wolff , 2019 +msgid "" +msgstr "" +"Project-Id-Version: fwupd\n" +"Report-Msgid-Bugs-To: \n" +"Language-Team: Afrikaans (http://www.transifex.com/freedesktop/fwupd/language/af/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: af\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "%.0f minuut oor" +msgstr[1] "%.0f minute oor" + +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u dag" +msgstr[1] "%u dae" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u uur" +msgstr[1] "%u ure" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u minuut" +msgstr[1] "%u minute" + +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u sekonde" +msgstr[1] "%u sekondes" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Bygevoeg" + +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Ouderdom" + +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "’n Bywerking vereis dat die stelsel herbegin om te voltooi." + +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "Antwoord ja op alle vrae" + +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "Attribute" + +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Kanselleer" + +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Gekanselleer" + +#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: this is when the daemon state changes +msgid "Changed" +msgstr "Verander" + +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Kontrolesom" + +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "Vlokkie-ID" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Kies 'n toestel:" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Kies 'n vrystelling:" + +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Opdrag nie gevind nie" + +msgid "DFU" +msgstr "DFU" + +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Pak tans uit…" + +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Beskrywing" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Toestel bygevoeg:" + +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Toestel verander:" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Toestel verwyder:" + +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Toestelle wat suksesvol bygewerk is:" + +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "Toestelle wat nie korrek bygewerk is nie:" + +msgid "Done!" +msgstr "Klaar!" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Gradeer tans %s af vanaf %s na %s… " + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Gradeer tans %s af…" + +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Laai tans af…" + +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Geaktiveer" + +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "Vee tans uit…" + +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "Kon nie aflaai nie a.g.v. bedienerlimiet" + +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "Kry tans lêer" + +#. TRANSLATORS: downloading new metadata file +msgid "Fetching metadata" +msgstr "Kry tans metadata" + +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "Kry tans handtekening" + +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Lêernaam" + +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "Lêernaamhandtekening" + +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Gevind" + +msgid "GUID" +msgstr "GUID" + +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "ID" + +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "Ledig…" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "Installeer tans op %s…" + +msgid "Keyring" +msgstr "Sleutelring" + +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Minder as een minuut oor" + +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "Laai tans…" + +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "Metadata-URI" + +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "Metadata-URI-handtekening" + +msgid "Mode" +msgstr "Modus" + +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Naam" + +msgid "OK" +msgstr "Goed" + +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Wagwoord" + +msgid "Permission denied" +msgstr "Toestemming gewyer" + +msgid "Print the version number" +msgstr "Druk die weergawenommer" + +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "Prioriteit" + +msgid "Proceed with upload?" +msgstr "Gaan voort met oplaai?" + +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Protokol" + +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Lees tans…" + +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Streek" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "Herinstalleer tans %s met %s… " + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Verwyder" + +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Internetverbinding is nodig" + +#. TRANSLATORS: reboot to apply the update +msgid "Restart now?" +msgstr "Herbegin nou?" + +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Herbegin tans toestel…" + +#. TRANSLATORS: command line option +msgid "Schedule installation for next reboot when possible" +msgstr "Skeduleer die installasie vir die volgende herbegin indien moontlik" + +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "Skeduleer tans…" + +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Reeksnommer" + +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Wys toestelle wat nie bygewerk kan word nie" + +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Toestand" + +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Status" + +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "Opsomming" + +msgid "Target" +msgstr "Teiken" + +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "Titel" + +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Oordraggrootte" + +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Tipe" + +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "URI" + +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Onbekend" + +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "Bywerking se kontrolesom" + +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "Bywerking se beskrywing" + +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Bywerking se duur" + +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "Bywerking se ligging" + +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "Bywerking se naam" + +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "Bywerking se opsomming" + +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "Bywerking se weergawe" + +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Werk nou by?" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "Werk tans %s by vanaf %s na %s… " + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Werk tans %s by…" + +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "Oplaaiboodskap:" + +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Laai verslag nou op?" + +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Gebruikernaam" + +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Verifieer tans…" + +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "Weergawe" + +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "Wag tans…" + +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Skryf tans…" diff -Nru fwupd-1.1.4/po/ast.po fwupd-1.2.5/po/ast.po --- fwupd-1.1.4/po/ast.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/ast.po 2019-02-25 09:42:18.000000000 +0000 @@ -8,8 +8,6 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Asturian (http://www.transifex.com/freedesktop/fwupd/language/ast/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -77,15 +75,6 @@ msgid "Status" msgstr "Estáu" -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Esti proyeutu tien l'oxetivu d'anovar automáticamente'l firmware en Linux d'un mou seguru y fiable. Pues usar un xestor de software GUI como Gnome Software pa ver y aplicar los anovamientos, la ferramienta en llinia de comandos o la interfaz D-Bus direutamente." - #. TRANSLATORS: transfer size in bytes msgid "Transfer Size" msgstr "Tamañu de tresferencia" - -msgid "Update device firmware on Linux" -msgstr "Anueva'l firmware de preseos en Linux" - -msgid "fwupd" -msgstr "fwupd" diff -Nru fwupd-1.1.4/po/ca.po fwupd-1.2.5/po/ca.po --- fwupd-1.1.4/po/ca.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/ca.po 2019-02-25 09:42:18.000000000 +0000 @@ -3,14 +3,12 @@ # This file is distributed under the same license as the fwupd package. # # Translators: -# Antoni Bella Pérez , 2017-2018 +# Antoni Bella Pérez , 2017-2019 # Robert Antoni Buj Gelonch , 2017 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Catalan (http://www.transifex.com/freedesktop/fwupd/language/ca/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -30,6 +28,34 @@ msgid "%s has firmware updates:" msgstr "%s té actualitzacions de microprogramari:" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u dia" +msgstr[1] "%u dies" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u hora" +msgstr[1] "%u hores" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u minut" +msgstr[1] "%u minuts" + +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u segon" +msgstr[1] "%u segons" + #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "S'ha afegit" @@ -55,10 +81,14 @@ msgid "Allow re-installing existing firmware versions" msgstr "Permet tornar a instal·lar les versions de microprogramari existents" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Una actualització requereix un reinici per a completar-se." +#. TRANSLATORS: explain why we want to shutdown +msgid "An update requires the system to shutdown to complete." +msgstr "Una actualització requereix que s'aturi el sistema per a finalitzar." + #. TRANSLATORS: command line option msgid "Answer yes to all questions" msgstr "Respon sí a totes les preguntes" @@ -266,6 +296,11 @@ msgid "Downgrading %s from %s to %s... " msgstr "S'està desactualitzant %s des de %s a %s... " +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "S'està desactualitzant %s…" + #. TRANSLATORS: downloading from a remote server msgid "Downloading…" msgstr "S'està descarregant..." @@ -397,6 +432,9 @@ msgid "Firmware updates are supported on this machine." msgstr "Les actualitzacions de microprogramari estan admeses en aquesta màquina." +msgid "Force the action ignoring all warnings" +msgstr "Força l'acció ignorant tots els avisos" + #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "S'ha trobat" @@ -475,12 +513,6 @@ msgid "Install unsigned system firmware" msgstr "Instal·la microprogramari sense signar per al sistema" -#. show message in progressbar -#. TRANSLATORS: %1 is a device name -#, c-format -msgid "Installing %s" -msgstr "S'està instal·lant %s" - #. TRANSLATORS: this is shown when updating the firmware after the reboot msgid "Installing firmware update…" msgstr "S'està instal·lant l'actualització de microprogramari..." @@ -597,6 +629,12 @@ msgid "Please enter a number from 0 to %u: " msgstr "Introduïu un número del 0 al %u: " +msgid "Print the version number" +msgstr "Imprimeix el número de versió" + +msgid "Print verbose debug statements" +msgstr "Imprimeix les sentències detallades de la depuració" + #. TRANSLATORS: the numeric priority msgid "Priority" msgstr "Prioritat" @@ -743,6 +781,10 @@ msgid "Show client and daemon versions" msgstr "Mostra les versions del client i el dimoni" +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information" +msgstr "Mostra la informació detallada del dimoni" + #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Mostra la informació de depuració per a tots els fitxers" @@ -775,6 +817,16 @@ msgid "Show the information of firmware update status" msgstr "Mostra la informació sobre l'estat de l'actualització del microprogramari" +#. TRANSLATORS: shutdown to apply the update +msgid "Shutdown now?" +msgstr "Aturar-lo ara?" + +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Especifiqueu el proveïdor/ID del producte del dispositiu DFU" + +msgid "Specify the number of bytes per USB transfer" +msgstr "Especifiqueu el nombre de bytes per a la transferència USB" + #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Estat" @@ -796,20 +848,10 @@ msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "El LVFS és un servei gratuït que funciona com una entitat legal independent i no té cap vincle amb la $OS_RELEASE:NAME$. És possible que el vostre distribuïdor no hagi verificat cap de les actualitzacions del microprogramari per a la compatibilitat amb el vostre sistema o els dispositius connectats. Tot el microprogramari només és proporcionat pel fabricant original dels equips." -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "El procés del «fwupd» és un dimoni senzill, el qual permet que una sessió de programari actualitzi el microprogramari del dispositiu a la màquina local. Està dissenyat per a equips d'escriptori, però aquest projecte també és usable a telèfons, tauletes i servidors sense perifèrics." - -#. TRANSLATORS: exactly one update needs this -msgid "The update requires a reboot to complete." -msgstr "L'actualització requereix un reinici per a completar-se." - #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "Aquest programa només pot funcionar correctament com a «root»" -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Aquest projecte pretén fer que actualitzar automàticament el microprogramari a Linux, sigui segur i fiable. Com a IGU, podeu usar un gestor de programari com el Programari GNOME per a veure i aplicar les actualitzacions, directament l'eina de la línia d'ordres o la interfície de D-Bus." - msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "Aquest remot conté el microprogramari que no està embargat, però encara l'ha provat el proveïdor del maquinari. Haureu d'assegurar-vos que teniu una manera de baixar manualment el microprogramari si l'actualització del microprogramari no funciona." @@ -856,6 +898,11 @@ msgid "Update Description" msgstr "Descripció de l'actualització" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Durada de l'actualització" + #. TRANSLATORS: section header for firmware remote http:// msgid "Update Location" msgstr "Ubicació de l'actualització" @@ -876,8 +923,9 @@ msgid "Update Version" msgstr "Versió de l'actualització" -msgid "Update device firmware on Linux" -msgstr "Actualitza el microprogramari del dispositiu a Linux" +#. TRANSLATORS: command description +msgid "Update all devices that match local metadata" +msgstr "Actualitza tots els dispositius que coincideixin amb les metadades locals" #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" @@ -905,6 +953,11 @@ msgid "Updating %s from %s to %s... " msgstr "S'està actualitzant %s des de %s a %s... " +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "S'està actualitzant %s…" + #. TRANSLATORS: the server sent the user a small message msgid "Upload message:" msgstr "Missatge de la pujada:" @@ -956,6 +1009,3 @@ #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "És possible que el vostre distribuïdor no hagi verificat cap de les actualitzacions del microprogramari per a la compatibilitat amb el vostre sistema o els dispositius connectats." - -msgid "fwupd" -msgstr "fwupd" diff -Nru fwupd-1.1.4/po/cs.po fwupd-1.2.5/po/cs.po --- fwupd-1.1.4/po/cs.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/cs.po 2019-02-25 09:42:18.000000000 +0000 @@ -3,15 +3,13 @@ # This file is distributed under the same license as the fwupd package. # # Translators: -# Daniel Rusek , 2017 -# Daniel Rusek , 2017 +# Ascii Wolf , 2017 +# Ascii Wolf , 2017 # Marek Černocký , 2016,2018 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Czech (http://www.transifex.com/freedesktop/fwupd/language/cs/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -58,7 +56,7 @@ msgid "Allow re-installing existing firmware versions" msgstr "Povolit reinstalaci stávající verze firmwaru" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Některá z aktualizací vyžaduje pro dokončení restart." @@ -480,12 +478,6 @@ msgid "Install unsigned system firmware" msgstr "Instalace nepodepsaného systémového firmwaru" -#. show message in progressbar -#. TRANSLATORS: %1 is a device name -#, c-format -msgid "Installing %s" -msgstr "Instaluje se zařízení %s" - #. TRANSLATORS: this is shown when updating the firmware after the reboot msgid "Installing firmware update…" msgstr "Instaluje se aktualizace firmwaru…" @@ -801,20 +793,10 @@ msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS je svobodná služba, které funguje jako nezávislý právní subjekt a nemá žádné vazby na systém $OS_RELEASE:NAME$. Váš distributor nemusí některé z aktualizací firmwaru schválit kvůli kompatibilitě s vaším systémem nebo připojenými zařízeními. Veškerý firmware je poskytován pouze přímo výrobci daných zařízení." -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "Proces fwupd je jednoduchý démon, který umožňuje softwaru sezení aktualizovat firmware zařízení na vašem počítači. Je navržen pro stolní počítače, ale je možné jej používat i na telefonech, tabletech a serverech bez monitoru." - -#. TRANSLATORS: exactly one update needs this -msgid "The update requires a reboot to complete." -msgstr "Pro dokončení aktualizace je potřeba provést restart." - #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "Tento program může správně fungovat jen pod uživatelem root" -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Cílem tohoto projektu je, aby aktualizace firmwaru na Linuxu probíhala automaticky, bezpečně a spolehlivě. Pro zobrazení a nasazení aktualizací můžete použít správce softwaru s grafickým rozhraním, jako je třeba Software GNOME, nebo nástroj pro příkazovou řádku či přímo rozhraní D-Bus." - msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "Tento zdroj obsahuje firmware, který není zakázaný, ale zatím je u výrobce stále ve stádiu testování. Měli byste se ujistit, že znáte způsob, jak se vrátit k předchozí verzi firmwaru, kdyby došlo k selhání." @@ -881,9 +863,6 @@ msgid "Update Version" msgstr "Verze aktualizace" -msgid "Update device firmware on Linux" -msgstr "Aktualizace firmwaru zařízení na Linuxu" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "O selhání aktualizace se ví, více informací najdete na této adrese:" @@ -961,6 +940,3 @@ #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Váš distributor nemusí schválit některé aktualizace firmwaru kvůli kompatibilitě s vaším systémem nebo připojenými zařízeními." - -msgid "fwupd" -msgstr "fwupd" diff -Nru fwupd-1.1.4/po/de.po fwupd-1.2.5/po/de.po --- fwupd-1.1.4/po/de.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/de.po 2019-02-25 09:42:18.000000000 +0000 @@ -3,14 +3,13 @@ # This file is distributed under the same license as the fwupd package. # # Translators: +# Ettore Atalan , 2018 # Marco Tedaldi , 2015 # Wolfgang Stöggl , 2015 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: German (http://www.transifex.com/freedesktop/fwupd/language/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,15 +17,26 @@ "Language: de\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "%.0f Minute verbleibt" +msgstr[1] "%.0f Minuten verbleiben" + #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" -msgstr "Firmwareaktualisierungen für %s verfügbar:" +msgstr "Firmware-Aktualisierungen für %s verfügbar:" #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Hinzugefügt" +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Alter" + #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" @@ -34,23 +44,48 @@ #. TRANSLATORS: command line option msgid "Allow downgrading firmware versions" -msgstr "Einspielen niedrigerer Firmwareversionen zulassen (Downgrade)" +msgstr "Herabstufung von Firmware-Versionen zulassen" #. TRANSLATORS: command line option msgid "Allow re-installing existing firmware versions" msgstr "Erneute Installation vorhandener Firmware-Versionen erlauben" +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "Ein Neustart ist erforderlich, um eine Aktualisierung abzuschließen." + +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "Alle Fragen mit Ja beantworten" + +#. TRANSLATORS: command description +msgid "Apply a binary patch" +msgstr "Binären Patch anwenden" + +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "Firmware-Aktualisierungen anwenden" + #. TRANSLATORS: command description msgid "Attach DFU capable device back to runtime" msgstr "DFU-fähiges Gerät wieder zurück in Laufzeit einhängen" +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "Attribute" + +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "Authentifizierung …" + #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on a removable device" -msgstr "Legitimierung ist erforderlich, um das Firmware-Downgrade auf einem entfernbaren Gerät durchzuführen" +msgstr "Für eine Herabstufung der Firmware auf einem entfernbaren Gerät ist eine Authentifizierung erforderlich" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "Auf diesem System ist eine Legitimierung erforderlich, um das Firmware-Downgrade durchzuführen" +msgstr "Für eine Herabstufung der Firmware auf diesem System ist eine Authentifizierung erforderlich" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" @@ -58,11 +93,23 @@ #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on a removable device" -msgstr "Legitimierung ist notwendig, um die Firmware auf einem entfernbaren Gerät zu aktualisieren" +msgstr "Für die Aktualisierung der Firmware auf einem entfernbaren Gerät ist eine Authentifizierung erforderlich" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on this machine" -msgstr "Auf diesem System ist eine Authentifizierung notwendig, um das Firmware Update durch zu führen" +msgstr "Für die Aktualisierung der Firmware auf diesem System ist eine Authentifizierung erforderlich" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "Eine Authentifizierung ist erforderlich, um die gespeicherten Prüfsummen für das Gerät zu aktualisieren" + +#. TRANSLATORS: command description +msgid "Build firmware using a sandbox" +msgstr "Firmware mit Hilfe einer Sandbox erstellen" + +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Abbrechen" #. TRANSLATORS: this is when a device ctrl+c's a watch msgid "Cancelled" @@ -78,6 +125,18 @@ msgid "Checksum" msgstr "Prüfsumme" +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "Chip-Kennung" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Wählen Sie ein Gerät aus:" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Wählen Sie eine Version aus:" + #. TRANSLATORS: this is the encryption method used when writing msgid "Cipher" msgstr "Verschlüsselungsverfahren" @@ -94,9 +153,16 @@ msgid "Convert firmware to DFU format" msgstr "Firmware in das DFU-Format konvertieren" +#. TRANSLATORS: command description +msgid "Create a binary patch using two files" +msgstr "Binären Patch aus zwei Dateien erstellen" + +msgid "DFU" +msgstr "DFU" + #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" -msgstr "DFU-Werkzeug" +msgstr "DFU-Dienstprogramm" #. TRANSLATORS: for the --verbose arg msgid "Debugging Options" @@ -108,7 +174,7 @@ #. TRANSLATORS: command description msgid "Decrypt firmware data" -msgstr "Firmwaredaten entschlüsseln" +msgstr "Firmware-Daten entschlüsseln" #. TRANSLATORS: section header for firmware description msgid "Description" @@ -130,23 +196,101 @@ msgid "Device removed:" msgstr "Gerät entfernt:" +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Erfolgreich aktualisierte Geräte:" + +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "Nicht korrekt aktualisierte Geräte:" + +msgid "Disabled fwupdate debugging" +msgstr "fwupdate-Defektlokalisierung deaktivieren" + +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Version anzeigen" + +#. TRANSLATORS: command line option +msgid "Do not check for old metadata" +msgstr "Nicht auf alte Metadaten prüfen" + +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "Nach der Aktualisierung nicht auf einen Neustart prüfen" + +#. TRANSLATORS: command line option +msgid "Do not check for unreported history" +msgstr "Nicht auf nicht erfassten Verlauf prüfen" + +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "Nicht in die Verlaufsdatenbank schreiben" + msgid "Done!" msgstr "Fertig." +#. TRANSLATORS: command description +msgid "Downgrades the firmware on a device" +msgstr "Stuft die Firmware auf einem Gerät herab" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" #, c-format msgid "Downgrading %s from %s to %s... " -msgstr "Downgrade für %s von %s auf %s wird eingespielt …" +msgstr "Herabstufung für %s von %s auf %s wird eingespielt…" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "%s wird herabgestuft …" + +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Herunterladen …" + +#. TRANSLATORS: command description +msgid "Dump SMBIOS data from a file" +msgstr "SMBIOS-Daten aus einer Datei ausgeben" #. TRANSLATORS: command description msgid "Dump details about a firmware file" msgstr "Details zu einer Firmware-Datei ausgeben" #. TRANSLATORS: command description +msgid "Dump information about a binary patch to the screen" +msgstr "Informationen über einen binären Patch auf dem Bildschirm ausgeben" + +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "Das angegebene ESP war nicht gültig" + +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "Firmware-Aktualisierungsunterstützung auf unterstützten Systemen aktivieren" + +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Aktiviert" + +msgid "Enabled fwupdate debugging" +msgstr "fwupdate-Defektlokalisierung aktivieren" + +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "Die Aktivierung dieser Funktionalität erfolgt auf eigene Gefahr, d.h. Sie müssen sich bei Problemen, die durch diese Aktualisierungen verursacht werden, an Ihren Erstausrüster wenden. Nur Probleme mit dem Aktualisierungsprozess selbst sollten unter $OS_RELEASE:BUG_REPORT_URL$ eingereicht werden." + +#. TRANSLATORS: command description msgid "Encrypt firmware data" -msgstr "Firmwaredaten verschlüsseln" +msgstr "Firmware-Daten verschlüsseln" + +#. TRANSLATORS: command description +msgid "Erase all firmware update history" +msgstr "Gesamten Firmware-Aktualisierungsverlauf löschen" + +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "Löschen …" #. TRANSLATORS: exit after we've started up, used for user profiling msgid "Exit after a small delay" @@ -160,17 +304,61 @@ msgid "Failed to parse arguments" msgstr "Verarbeitung der Argumente schlug fehl" +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "Datei wird abgerufen" + +#. TRANSLATORS: downloading new firmware file +msgid "Fetching firmware" +msgstr "Firmware wird abgerufen" + +#. TRANSLATORS: downloading new metadata file +msgid "Fetching metadata" +msgstr "Metadaten werden abgerufen" + +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "Signatur wird abgerufen" + +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Dateiname" + +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "Signatur des Dateinamens" + +#. TRANSLATORS: remote URI +msgid "Firmware Base URI" +msgstr "Firmware Basis-URI" + #. TRANSLATORS: program summary msgid "Firmware Update D-Bus Service" msgstr "D-Bus-Dienst für Firmware-Aktualisierung" #. TRANSLATORS: program name msgid "Firmware Update Daemon" -msgstr "Dienst für Firmware-Aktualisierung" +msgstr "Hintergrundprogramm für Firmware-Aktualisierung" #. TRANSLATORS: program name msgid "Firmware Utility" -msgstr "Firmware-Werkzeug" +msgstr "Firmware-Dienstprogramm" + +#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 +#, c-format +msgid "Firmware metadata has not been updated for %u day and may not be up to date." +msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." +msgstr[0] "Firmware-Metadaten wurden seit %u Tag nicht aktualisiert und sind möglicherweise nicht auf dem neuesten Stand." +msgstr[1] "Firmware-Metadaten wurden seit %u Tagen nicht aktualisiert und sind möglicherweise nicht auf dem neuesten Stand." + +msgid "Firmware updates are not supported on this machine." +msgstr "Firmware-Aktualisierungen werden auf diesem System nicht unterstützt." + +msgid "Firmware updates are supported on this machine." +msgstr "Firmware-Aktualisierungen werden auf diesem System unterstützt." + +msgid "Force the action ignoring all warnings" +msgstr "Aktion erzwingen, bei der alle Warnungen ignoriert werden" #. TRANSLATORS: detected a DFU device msgid "Found" @@ -180,10 +368,18 @@ msgstr "GUID" #. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "Ermittelt alle Geräte gemäß der Systemtopologie" + +#. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Alle Geräte ermitteln, die Firmware-Aktualisierungen unterstützen" #. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "Alle aktivierten und im System registrierten Plugins ermitteln" + +#. TRANSLATORS: command description msgid "Gets details about a firmware file" msgstr "Ermittelt Details über eine Firmware-Datei" @@ -196,6 +392,10 @@ msgstr "Ermittelt die Liste der Aktualisierungen für angeschlossene Hardware" #. TRANSLATORS: command description +msgid "Gets the releases for a device" +msgstr "Ermittelt die Versionen für ein Gerät" + +#. TRANSLATORS: command description msgid "Gets the results from the last update" msgstr "Ermittelt die Ergebnisse der letzten Aktualisierung" @@ -208,6 +408,10 @@ msgstr "Bereit …" #. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "Firmware-Blob auf einem Gerät installieren" + +#. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "Eine Firmware-Datei auf dieser Hardware installieren" @@ -230,10 +434,36 @@ msgid "Install unsigned system firmware" msgstr "Nicht-signierte System-Firmware installieren" +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "Firmware-Aktualisierung wird installiert …" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "Wird auf %s installiert …" + +msgid "Keyring" +msgstr "Schlüsselbund" + +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Weniger als eine Minute verbleiben" + +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Linux Vendor Firmware Service (stabile Firmware)" + +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Linux Vendor Firmware Service (Test-Firmware)" + #. TRANSLATORS: command description msgid "List currently attached DFU capable devices" msgstr "Derzeit angeschlossene DFU-fähige Geräte auflisten" +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "Unterstützte Firmware-Aktualisierungen auflisten" + #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "Laden …" @@ -242,12 +472,24 @@ msgid "Merge multiple firmware files into one" msgstr "Mehrere Firmware-Dateien in eine zusammenführen" +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "Metadaten-URI" + +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "Metadaten URI-Signatur" + +#. TRANSLATORS: explain why no metadata available +msgid "Metadata can be obtained from the Linux Vendor Firmware Service." +msgstr "Metadaten können über den Linux Vendor Firmware Service bezogen werden." + msgid "Mode" msgstr "Modus" #. TRANSLATORS: command description msgid "Monitor the daemon for events" -msgstr "Den Daemon auf Ereignisse überwachen" +msgstr "Hintergrundprogramm auf Ereignisse überwachen" #. TRANSLATORS: interface name, e.g. "Flash" #. TRANSLATORS: device name, e.g. 'ColorHug2' @@ -255,18 +497,65 @@ msgid "Name" msgstr "Name" +msgid "No action specified!" +msgstr "Keine Aktion angegeben!" + #. TRANSLATORS: nothing attached #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "Es wurde keine Hardware erkannt, deren Firmware aktualisiert werden kann" +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "Keine Plugins gefunden" + msgid "OK" msgstr "Ok" +#. TRANSLATORS: command line option +msgid "Override plugin warning" +msgstr "Plugin-Warnung überschreiben" + +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "Standard-ESP-Pfad überschreiben" + +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Passwort" + +msgid "Payload" +msgstr "Nutzdaten" + +msgid "Permission denied" +msgstr "Berechtigung verweigert" + +#. TRANSLATORS: the user isn't reading the question +#, c-format +msgid "Please enter a number from 0 to %u: " +msgstr "Bitte geben Sie eine Zahl von 0 bis %u ein: " + +msgid "Print the version number" +msgstr "Versionsnummer ausgeben" + +msgid "Print verbose debug statements" +msgstr "Ausführliche Debug-Anweisungen ausgeben" + +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "Priorität" + +msgid "Proceed with upload?" +msgstr "Mit dem Hochladen fortfahren?" + #. TRANSLATORS: DFU protocol version, e.g. 1.1 msgid "Protocol" msgstr "Protokoll" +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "Abfrage der Unterstützung für Firmware-Aktualisierungen" + #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" @@ -280,6 +569,10 @@ msgid "Read firmware from one partition into a file" msgstr "Firmware von einzelner Partition in Datei lesen" +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Lesen …" + #. TRANSLATORS: command description msgid "Refresh metadata from remote server" msgstr "Metadaten von entferntem Server aktualisieren" @@ -299,10 +592,41 @@ msgid "Removed" msgstr "Entfernt" +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "Daten in einer bestehenden Firmware-Datei ersetzen" + +#. TRANSLATORS: URI to send success/failure reports +msgid "Report URI" +msgstr "Bericht-URI" + +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Erfordert Internetverbindung" + +#. TRANSLATORS: command description +msgid "Reset a DFU device" +msgstr "DFU-Gerät zurücksetzen" + +#. TRANSLATORS: reboot to apply the update +msgid "Restart now?" +msgstr "Jetzt neu starten?" + #. TRANSLATORS: restarting the device to pick up new F/W msgid "Restarting device…" msgstr "Gerät wird neu gestartet …" +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "Alle Hardware-Kennungen für das System zurückgeben" + +msgid "Runtime" +msgstr "Laufzeit" + +#. TRANSLATORS: command line option +msgid "Schedule installation for next reboot when possible" +msgstr "Installation für den nächsten Neustart planen, falls möglich" + #. TRANSLATORS: scheduing an update to be done on the next boot msgid "Scheduling…" msgstr "Einplanen …" @@ -333,7 +657,7 @@ #. TRANSLATORS: command description msgid "Set the firmware size for the target" -msgstr "Die Firmware-Größe für das Ziel festlegen" +msgstr "Firmware-Größe für das Ziel festlegen" #. TRANSLATORS: command description msgid "Set vendor ID on firmware file" @@ -343,6 +667,18 @@ msgid "Sets metadata on a firmware file" msgstr "Metadaten einer Firmware-Datei festlegen" +#. TRANSLATORS: command description +msgid "Share firmware history with the developers" +msgstr "Firmware-Verlauf mit den Entwicklern teilen" + +#. TRANSLATORS: command line option +msgid "Show client and daemon versions" +msgstr "Client- und Hintergrundprogramm-Versionen anzeigen" + +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information" +msgstr "Ausführliche Informationen zum Dienstprogramm anzeigen" + #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Debuginformationen für alle Dateien anzeigen" @@ -352,9 +688,32 @@ msgstr "Debug Optionen anzeigen" #. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Nicht aktualisierbare Geräte anzeigen" + +#. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "Zusätzliche Informationen zur Fehlerdiagnose anzeigen" +#. TRANSLATORS: command description +msgid "Show history of firmware updates" +msgstr "Verlauf von Firmware-Aktualisierungen anzeigen" + +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "Ausführliche Informationen zum Plugin anzeigen" + +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "Fehlerprotokoll der letzten versuchten Aktualisierung anzeigen" + +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "Informationen über den Firmware-Aktualisierungsstatus anzeigen" + +msgid "Specify the number of bytes per USB transfer" +msgstr "Geben Sie die Anzahl der Bytes pro USB-Übertragung an" + #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Zustand" @@ -365,6 +724,41 @@ msgid "Status" msgstr "Status" +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "Zusammenfassung" + +msgid "Target" +msgstr "Ziel" + +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "Der LVFS ist ein kostenloser Dienst, der als unabhängige juristische Person arbeitet und keine Verbindung zu $OS_RELEASE:NAME$ hat. Möglicherweise hat Ihr Lieferant eine der Firmware-Aktualisierungen nicht auf Kompatibilität mit Ihrem System oder angeschlossenen Geräten überprüft. Die gesamte Firmware wird nur vom Originalhersteller zur Verfügung gestellt." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "Dieses Programm funktioniert möglicherweise nur als root korrekt" + +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "Titel" + +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Übertragungsgröße" + +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Typ" + +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "UEFI-Firmware-Dienstprogramm" + +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "URI" + #. TRANSLATORS: currect daemon status is unknown msgid "Unknown" msgstr "Unbekannt" @@ -388,10 +782,29 @@ msgid "Update Location" msgstr "Ort aktualisieren" +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "Aktualisierungsname" + +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "Aktualisierungszusammenfassung" + #. TRANSLATORS: section header for firmware version msgid "Update Version" msgstr "Version aktualisieren" +#. TRANSLATORS: the server sent the user a small message +msgid "Update failure is a known issue, visit this URL for more information:" +msgstr "Der Aktualisierungsfehler ist ein bekanntes Problem, besuchen Sie diese URL für weitere Informationen:" + +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Jetzt aktualisieren?" + +msgid "Update the stored device verification information" +msgstr "Gespeicherte Geräteverifizierungsinformationen aktualisieren" + #. TRANSLATORS: command description msgid "Update the stored metadata with current ROM contents" msgstr "Gespeicherte Metadaten mit dem aktuellen ROM-Inhalt aktualisieren" @@ -407,19 +820,48 @@ msgid "Updating %s from %s to %s... " msgstr "Aktualisieren von %s von %s nach %s …" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "%s wird aktualisiert …" + +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "Nachricht beim Hochladen:" + +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Bericht jetzt hochladen?" + +#. TRANSLATORS: explain why we want to upload +msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +msgstr "Das Hochladen von Firmware-Berichten hilft Hardwareherstellern, fehlerhafte und erfolgreiche Aktualisierungen auf realen Geräten schnell zu erkennen." + +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Benutzername" + #. TRANSLATORS: verifying we wrote the firmware correctly msgid "Verifying…" -msgstr "Überprüfung läuft …" +msgstr "Überprüfung …" #. TRANSLATORS: section header for release version number msgid "Version" msgstr "Version" +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "Warten …" + #. TRANSLATORS: command description msgid "Watch DFU devices being hotplugged" msgstr "Geräteanschluss von DFU-Geräten überwachen" #. TRANSLATORS: command description +msgid "Watch for hardware changes" +msgstr "Auf Hardware-Änderungen achten" + +#. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "Firmware von Datei auf Gerät schreiben" @@ -430,3 +872,7 @@ #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Schreiben …" + +#. TRANSLATORS: show the user a warning +msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." +msgstr "Möglicherweise hat Ihr Lieferant eine der Firmware-Aktualisierungen nicht auf Kompatibilität mit Ihrem System oder angeschlossenen Geräten überprüft." diff -Nru fwupd-1.1.4/po/en_GB.po fwupd-1.2.5/po/en_GB.po --- fwupd-1.1.4/po/en_GB.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/en_GB.po 2019-02-25 09:42:18.000000000 +0000 @@ -8,8 +8,6 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: English (United Kingdom) (http://www.transifex.com/freedesktop/fwupd/language/en_GB/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -609,12 +607,6 @@ msgid "Target" msgstr "Target" -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." - -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." - #. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" msgid "Title" msgstr "Title" @@ -670,9 +662,6 @@ msgid "Update Version" msgstr "Update Version" -msgid "Update device firmware on Linux" -msgstr "Update device firmware on Linux" - #. TRANSLATORS: ask the user if we can update the metadata msgid "Update now?" msgstr "Update now?" @@ -730,6 +719,3 @@ #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Writing…" - -msgid "fwupd" -msgstr "fwupd" diff -Nru fwupd-1.1.4/po/eo.po fwupd-1.2.5/po/eo.po --- fwupd-1.1.4/po/eo.po 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/po/eo.po 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,94 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the fwupd package. +# +# Translators: +# kristjan , 2019 +msgid "" +msgstr "" +"Project-Id-Version: fwupd\n" +"Report-Msgid-Bugs-To: \n" +"Language-Team: Esperanto (http://www.transifex.com/freedesktop/fwupd/language/eo/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: eo\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u sekundo" +msgstr[1] "%u sekundoj" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Aldonita" + +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Nuligi" + +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Nuligita" + +#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: this is when the daemon state changes +msgid "Changed" +msgstr "Ŝanĝita" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Elektu aparaton:" + +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Priskribo" + +msgid "Done!" +msgstr "Farita!" + +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Trovita" + +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "ID" + +msgid "Mode" +msgstr "Reĝimo" + +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Nomo" + +msgid "OK" +msgstr "Bone" + +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Protokolo" + +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Regiono" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Forigita" + +msgid "Target" +msgstr "Celo" + +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Nekonata" + +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "Versio" diff -Nru fwupd-1.1.4/po/eu.po fwupd-1.2.5/po/eu.po --- fwupd-1.1.4/po/eu.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/eu.po 2019-02-25 09:42:18.000000000 +0000 @@ -8,9 +8,6 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-06 14:54+0100\n" -"PO-Revision-Date: 2018-06-06 14:00+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Basque (http://www.transifex.com/freedesktop/fwupd/language/eu/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff -Nru fwupd-1.1.4/po/fi.po fwupd-1.2.5/po/fi.po --- fwupd-1.1.4/po/fi.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/fi.po 2019-02-25 09:42:18.000000000 +0000 @@ -4,12 +4,11 @@ # # Translators: # Jiri Grönroos , 2017-2018 +# Kimmo Kujansuu , 2019 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Finnish (http://www.transifex.com/freedesktop/fwupd/language/fi/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -21,11 +20,41 @@ msgid "Added" msgstr "Lisätty" +#. TRANSLATORS: this is a command alias, e.g. 'get-devices' +#, c-format +msgid "Alias to %s" +msgstr "Peitenimi %s" + +#. TRANSLATORS: command description +msgid "Apply a binary patch" +msgstr "Käytä binääristä korjaustiedostoa" + +#. TRANSLATORS: command description +msgid "Attach DFU capable device back to runtime" +msgstr "Kiinnitä DFU-kykyinen laite takaisin ajoon" + +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "Määritteet" + #. TRANSLATORS: waiting for user to authenticate msgid "Authenticating…" msgstr "Tunnistaudutaan…" #. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on a removable device" +msgstr "Todennus on tarpeen, jotta firmware voidaan alentaa siirrettävällä laitteelta" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on this machine" +msgstr "Todennus on tarpeen tämän laitteen firmwaren alentamiseksi" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify a configured remote used for firmware updates" +msgstr "Todennusta tarvitaan firmware-päivityksiin käytettävän konfiguroidun etä-ohjaimen muokkaamisessa" + +#. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" msgstr "Laitteen lukituksen avaaminen vaatii tunnistautumisen" @@ -37,6 +66,10 @@ msgid "Authentication is required to update the firmware on this machine" msgstr "Tämän laitteen firmwaren päivittäminen vaatii tunnistautumisen" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "Todennus edellyttää laitteen tallennettujen tarkistussummien päivittämistä" + #. TRANSLATORS: this is when a device ctrl+c's a watch msgid "Cancelled" msgstr "Peruttu" @@ -51,6 +84,10 @@ msgid "Checksum" msgstr "Tarkistussumma" +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "Chip-tunnus" + #. TRANSLATORS: get interactive prompt msgid "Choose a device:" msgstr "Valitse laite:" @@ -59,10 +96,29 @@ msgid "Choose a release:" msgstr "Valitse julkaisu:" +#. TRANSLATORS: this is the encryption method used when writing +msgid "Cipher" +msgstr "Salaus" + #. TRANSLATORS: error message msgid "Command not found" msgstr "Komentoa ei löytynyt" +#. TRANSLATORS: command description +msgid "Convert firmware to DFU format" +msgstr "Muunna firmware DFU-muotoon" + +#. TRANSLATORS: command description +msgid "Create a binary patch using two files" +msgstr "Luo binäärinen korjaustiedosto käyttäen kahta tiedostoa" + +msgid "DFU" +msgstr "DFU" + +#. TRANSLATORS: DFU stands for device firmware update +msgid "DFU Utility" +msgstr "DFU-apuohjelma" + #. TRANSLATORS: for the --verbose arg msgid "Debugging Options" msgstr "Vianjäljitysvalinnat" @@ -71,10 +127,18 @@ msgid "Decompressing…" msgstr "Puretaan…" +#. TRANSLATORS: command description +msgid "Decrypt firmware data" +msgstr "Pura firmwaren data" + #. TRANSLATORS: section header for firmware description msgid "Description" msgstr "Kuvaus" +#. TRANSLATORS: command description +msgid "Detach currently attached DFU capable device" +msgstr "Irrota tällä hetkellä liitetty DFU-laite" + #. TRANSLATORS: this is when a device is hotplugged msgid "Device added:" msgstr "Laite lisätty:" @@ -87,6 +151,10 @@ msgid "Device removed:" msgstr "Laite poistettu:" +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Näytä versio" + msgid "Done!" msgstr "Valmis!" @@ -94,6 +162,21 @@ msgid "Downloading…" msgstr "Ladataan…" +#. TRANSLATORS: command description +msgid "Dump details about a firmware file" +msgstr "Tyhjennä laiteohjelmiston tiedot" + +#. TRANSLATORS: command description +msgid "Dump information about a binary patch to the screen" +msgstr "Tulosta tiedot binäärisestä korjaustiedostosta näytölle" + +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "Tämän toiminnon käyttöönotto tapahtuu omalla vastuullasi, joten sinun on otettava yhteyttä alkuperäiseen laitevalmistajaan näiden päivitysten aiheuttamista ongelmista. Vain päivitysprosessiin liittyvät ongelmat pitäisi jättää osoitteeseen $OS_RELEASE:BUG_REPORT_URL$." + +#. TRANSLATORS: command description +msgid "Encrypt firmware data" +msgstr "Salaa firmwaren data" + #. TRANSLATORS: erasing contents of the flash chips msgid "Erasing…" msgstr "Poistetaan…" @@ -102,6 +185,14 @@ msgid "Exit after a small delay" msgstr "Poistu pienen viiveen jälkeen" +#. TRANSLATORS: quirks are device-specific workarounds +msgid "Failed to load quirks" +msgstr "Quirksin lataaminen epäonnistui" + +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse arguments" +msgstr "Argumenttien jäsentäminen epäonnistui" + #. TRANSLATORS: downloading unknown file msgid "Fetching file" msgstr "Noudetaan tiedosto" @@ -126,18 +217,64 @@ msgid "Firmware Utility" msgstr "Firmware-työkalu" +msgid "Force the action ignoring all warnings" +msgstr "Pakota toimenpide huomioimatta kaikki varoitukset" + +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Löydetty" + +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "Henkilöllisyys" + #. TRANSLATORS: daemon is inactive msgid "Idle…" msgstr "Jouten…" +msgid "Install old version of system firmware" +msgstr "Asenna vanha firmware versio" + +msgid "Install signed device firmware" +msgstr "Asenna allekirjoitettu laitteen firmware" + +msgid "Install signed system firmware" +msgstr "Asenna allekirjoitettu järjestelmän firmware" + +msgid "Install unsigned device firmware" +msgstr "Asenna allekirjoittamattoman laitteen firmware" + +msgid "Install unsigned system firmware" +msgstr "Asenna allekirjoittamaton järjestelmän firmware" + #. TRANSLATORS: this is shown when updating the firmware after the reboot msgid "Installing firmware update…" msgstr "Asennetaan firmware-päivitystä…" +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Linux-toimittajan laiteohjelmisto (vakaa firmware)" + +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Linux-toimittajan laiteohjelmisto (firmware testaus)" + +#. TRANSLATORS: command description +msgid "List currently attached DFU capable devices" +msgstr "Luettelo tällä hetkellä liitetyistä DFU-laitteista" + #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "Ladataan…" +#. TRANSLATORS: command description +msgid "Merge multiple firmware files into one" +msgstr "Yhdistä useita firmware-tiedostoja yhteen" + +msgid "Mode" +msgstr "Malli" + +msgid "Modify a configured remote" +msgstr "Muokkaa määritettyä etänä" + #. TRANSLATORS: interface name, e.g. "Flash" #. TRANSLATORS: device name, e.g. 'ColorHug2' #. TRANSLATORS: section header for the release name @@ -151,26 +288,138 @@ msgid "Password" msgstr "Salasana" +msgid "Permission denied" +msgstr "Lupa kielletty" + +msgid "Print the version number" +msgstr "Tulosta versionumero" + +msgid "Print verbose debug statements" +msgstr "Tulosta virheelliset virheilmoitukset" + +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Protokolla" + +#. TRANSLATORS: device quirks, i.e. things that +#. * it does that we have to work around +msgid "Quirks" +msgstr "Merkintä" + +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "Lue firmware laitteesta tiedostoon" + +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "Lue firmware osiolta tiedostoon" + #. TRANSLATORS: reading from the flash chips msgid "Reading…" msgstr "Luetaan…" +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Alue" + #. TRANSLATORS: this is when a device is hotplugged msgid "Removed" msgstr "Poistettu" +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "Vaihda tiedot olemassa olevaan firmware-tiedostoon" + +#. TRANSLATORS: command description +msgid "Reset a DFU device" +msgstr "Nollaa DFU-laite" + #. TRANSLATORS: restarting the device to pick up new F/W msgid "Restarting device…" msgstr "Käynnistetään laite uudelleen…" +msgid "Runtime" +msgstr "Käyttöaika" + #. TRANSLATORS: scheduing an update to be done on the next boot msgid "Scheduling…" msgstr "Ajoitetaan…" +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Sarjanumero" + +#. TRANSLATORS: command description +msgid "Set alternative name on firmware file" +msgstr "Aseta vaihtoehtoinen nimi firmware-tiedostolle" + +#. TRANSLATORS: command description +msgid "Set alternative number on firmware file" +msgstr "Aseta vaihtoehtoinen numero firmware-tiedostolle" + +#. TRANSLATORS: command description +msgid "Set element address on firmware file" +msgstr "Aseta elementin osoite firmware tiedostoon" + +#. TRANSLATORS: command description +msgid "Set product ID on firmware file" +msgstr "Aseta tuotetunnus firmware tiedostoon" + +#. TRANSLATORS: command description +msgid "Set release version on firmware file" +msgstr "Aseta julkaisuversio firmware-tiedostosta" + +#. TRANSLATORS: command description +msgid "Set the firmware size for the target" +msgstr "Määritä firmwaren kohteen koko" + +#. TRANSLATORS: command description +msgid "Set vendor ID on firmware file" +msgstr "Aseta toimittajan tunnus firmware tiedostoon" + +#. TRANSLATORS: command description +msgid "Sets metadata on a firmware file" +msgstr "Asetta metatiedot firmware -tiedostoon" + #. TRANSLATORS: for the --verbose arg msgid "Show debugging options" msgstr "Näytä vianjäljitysvalinnat" +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "Näytä ylimääräiset virheenkorjaustiedot" + +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "Näytä virheenkorjausloki viimeisestä päivitysyrityksestä" + +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Määritä DFU laitteen toimittaja/tuotetunnus(s)" + +msgid "Specify the number of bytes per USB transfer" +msgstr "Määritä tavujen määrä USB-siirtoa kohti" + +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Osavaltio" + +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Tila" + +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "LVFS on ilmainen palvelu, joka toimii itsenäisenä oikeushenkilönä eikä sillä ole yhteyttä $OS_RELEASE:NAME$. Jakelijasi ei ehkä ole tarkistanut mitään laiteohjelmistopäivityksiä, jotka ovat yhteensopivia järjestelmän tai liitettyjen laitteiden kanssa. Kaikki laiteohjelmistot on tarkoitettu vain alkuperäisen laitteen valmistajalle." + +msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +msgstr "Tämä sisältää firmwaren, jota ei ole vientikiellossa, mutta jota laitteistotoimittaja testaa edelleen. Varmista, että voit päivittää firmwaren manuaalisesti, jos päivitys epäonnistuu." + +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Siirron koko" + #. TRANSLATORS: remote type, e.g. remote or local msgid "Type" msgstr "Tyyppi" @@ -179,8 +428,11 @@ msgid "Unknown" msgstr "Tuntematon" -msgid "Update device firmware on Linux" -msgstr "Päivitä laitteiden firmware-laiteohjelmistoja Linuxilla" +msgid "Unlock the device to allow access" +msgstr "Sallia pääsy laitteeseen" + +msgid "Update the stored device verification information" +msgstr "Päivitä laitteen tallennetut vahvistustiedot" #. TRANSLATORS: remote filename base msgid "Username" @@ -198,9 +450,18 @@ msgid "Waiting…" msgstr "Odotetaan…" +#. TRANSLATORS: command description +msgid "Watch DFU devices being hotplugged" +msgstr "Katso, että DFU-laitteet on kytketty" + +#. TRANSLATORS: command description +msgid "Write firmware from file into device" +msgstr "Kirjoita firmware tiedostosta laitteeseen" + +#. TRANSLATORS: command description +msgid "Write firmware from file into one partition" +msgstr "Kirjoita firmware tiedostosta osioon" + #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Kirjoitetaan…" - -msgid "fwupd" -msgstr "fwupd" diff -Nru fwupd-1.1.4/po/fr.po fwupd-1.2.5/po/fr.po --- fwupd-1.1.4/po/fr.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/fr.po 2019-02-25 09:42:18.000000000 +0000 @@ -8,8 +8,6 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: French (http://www.transifex.com/freedesktop/fwupd/language/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff -Nru fwupd-1.1.4/po/fur.po fwupd-1.2.5/po/fur.po --- fwupd-1.1.4/po/fur.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/fur.po 2019-02-25 09:42:18.000000000 +0000 @@ -8,8 +8,6 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Friulian (http://www.transifex.com/freedesktop/fwupd/language/fur/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -43,7 +41,7 @@ msgid "Allow re-installing existing firmware versions" msgstr "Permet di tornâ a instalâ lis versions dai firmware esistentis" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Un inzornament al à bisugne che si torni a inviâ il computer par finî." @@ -561,9 +559,6 @@ msgid "Summary" msgstr "Sintesi" -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "Il procès fwupd al è un sempliç demoni par permeti al software de session di inzornâ i firmware dai dispositîfs su la machine locâl. Al è progjetât pai scritoris, ma chest progjet si pues doprâ ancje sui telefonins, tablet e sui servidôrs cence visôr." - #. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" msgid "Title" msgstr "Titul" @@ -615,9 +610,6 @@ msgid "Update Version" msgstr "Inzorne version" -msgid "Update device firmware on Linux" -msgstr "Inzorne il firmware dal dispositîf su Linux" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "Il faliment dal inzornament al è un probleme cognossût, visite chest URL par vê plui informazions:" @@ -671,6 +663,3 @@ #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Daûr a scrivi…" - -msgid "fwupd" -msgstr "fwupd" diff -Nru fwupd-1.1.4/po/he.po fwupd-1.2.5/po/he.po --- fwupd-1.1.4/po/he.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/he.po 2019-02-25 09:42:18.000000000 +0000 @@ -9,8 +9,6 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Hebrew (http://www.transifex.com/freedesktop/fwupd/language/he/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff -Nru fwupd-1.1.4/po/hi.po fwupd-1.2.5/po/hi.po --- fwupd-1.1.4/po/hi.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/hi.po 2019-02-25 09:42:18.000000000 +0000 @@ -8,8 +8,6 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Hindi (http://www.transifex.com/freedesktop/fwupd/language/hi/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff -Nru fwupd-1.1.4/po/hr.po fwupd-1.2.5/po/hr.po --- fwupd-1.1.4/po/hr.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/hr.po 2019-02-25 09:42:18.000000000 +0000 @@ -10,8 +10,6 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Croatian (http://www.transifex.com/freedesktop/fwupd/language/hr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -45,7 +43,7 @@ msgid "Allow re-installing existing firmware versions" msgstr "Dopusti ponovnu instalaciju frimvera postojeće inačice" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Nadopuna zahtijeva ponovno pokretanje za završetak." @@ -637,12 +635,6 @@ msgid "Target" msgstr "Odredište" -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "fwupd je jednostavan pozadinski program koji omogućuje softveru sesije nadopunu frimvera uređaja na vašem lokalnom računalu. Dizajniran je za stolna računala, ali ovaj projekt se može koristiti i na mobilnim telefonima, tabletima i poslužiteljima." - -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Svrha ovog projekta je automatsko, sigurno i pouzdano nadopunjivanje frimvera na linuxu. Kako bi vidjeli i primijenili nadopune frimvera možete koristiti upravitelja softverom poput GNOME Softvera, alat naredbenog redka ili izravno D-Bus sučelje." - #. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" msgid "Title" msgstr "Naziv" @@ -698,9 +690,6 @@ msgid "Update Version" msgstr "Inačica nadopune" -msgid "Update device firmware on Linux" -msgstr "Nadopunite frimvere uređaja na Linuxu" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "Neuspješna nadopuna je poznat problem, posjetite ovaj URL za više informacija:" @@ -766,6 +755,3 @@ #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Zapisivanje..." - -msgid "fwupd" -msgstr "fwupd" diff -Nru fwupd-1.1.4/po/hu.po fwupd-1.2.5/po/hu.po --- fwupd-1.1.4/po/hu.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/hu.po 2019-02-25 09:42:18.000000000 +0000 @@ -11,8 +11,6 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Hungarian (http://www.transifex.com/freedesktop/fwupd/language/hu/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -20,11 +18,46 @@ "Language: hu\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "%.0f perc van hátra" +msgstr[1] "%.0f perc van hátra" + #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" msgstr "%s firmware frissítésekkel rendelkezik:" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u nap" +msgstr[1] "%u nap" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u óra" +msgstr[1] "%u óra" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u perc" +msgstr[1] "%u perc" + +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u másodperc" +msgstr[1] "%u másodperc" + #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Hozzáadva" @@ -33,6 +66,10 @@ msgid "Age" msgstr "Kor" +#. TRANSLATORS: should the remote still be enabled +msgid "Agree and enable the remote?" +msgstr "Beleegyezik és engedélyezi a távoli tárolót?" + #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" @@ -46,7 +83,7 @@ msgid "Allow re-installing existing firmware versions" msgstr "Meglévő firmware verziók újratelepítésének engedélyezése" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Egy frissítés újraindítást igényel a befejezéshez." @@ -58,10 +95,18 @@ msgid "Apply a binary patch" msgstr "Bináris folt alkalmazása" +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "Firmware-frissítések alkalmazása" + #. TRANSLATORS: command description msgid "Attach DFU capable device back to runtime" msgstr "DFU-képes eszköz visszacsatolása a futtatókörnyezethez" +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "Csatlakoztatás a firmware módhoz" + #. TRANSLATORS: device attributes, i.e. things that #. * the device can do msgid "Attributes" @@ -184,6 +229,10 @@ msgid "Detach currently attached DFU capable device" msgstr "Jelenleg csatlakoztatott DFU-képes eszközök leválasztása" +#. TRANSLATORS: command description +msgid "Detach to bootloader mode" +msgstr "Leválasztás a indítóbetöltő módhoz" + #. TRANSLATORS: this is when a device is hotplugged msgid "Device added:" msgstr "Eszköz hozzáadva:" @@ -204,6 +253,17 @@ msgid "Devices that were not updated correctly:" msgstr "Eszközök, melyek nem lettek helyesen frissítve:" +msgid "Disabled fwupdate debugging" +msgstr "Fwupdate hibakeresés letiltva" + +#. TRANSLATORS: command description +msgid "Disables a given remote" +msgstr "Letiltja az adott távoli tárolót" + +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Verzió megjelenítése" + #. TRANSLATORS: command line option msgid "Do not check for old metadata" msgstr "Ne ellenőrizze a régi metaadatokat" @@ -216,6 +276,10 @@ msgid "Do not check for unreported history" msgstr "Ne ellenőrizze a nem jelentett előzményeket" +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "Ne írjon az előzmények adatbázisába" + msgid "Done!" msgstr "Kész!" @@ -230,6 +294,11 @@ msgid "Downgrading %s from %s to %s... " msgstr "%s visszafejlesztése: %s -> %s…" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "%s visszaállítása…" + #. TRANSLATORS: downloading from a remote server msgid "Downloading…" msgstr "Letöltés…" @@ -246,10 +315,36 @@ msgid "Dump information about a binary patch to the screen" msgstr "Információk kiírása a képernyőre a bináris foltról" +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "A megadott ESP érvénytelen" + +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "Firmware frissítési támogatás engedélyezése a támogatott rendszereken" + +#. TRANSLATORS: Turn on the remote +msgid "Enable this remote?" +msgstr "Engedélyezi ezt a távoli tárolót?" + #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Engedélyezve" +msgid "Enabled fwupdate debugging" +msgstr "Fwupdate hibakeresés engedélyezve" + +#. TRANSLATORS: command description +msgid "Enables a given remote" +msgstr "Engedélyezi az adott távoli tárolót" + +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "Csak a saját felelősségére engedélyezze ezt a funkciót, amely azt jelenti, hogy az eredeti termék gyártójával kell kapcsolatba lépnie, ha problémát okoz a frissítés. Csak a frissítési folyamattal kapcsolatos problémákat jelentse itt be: $OS_RELEASE:BUG_REPORT_URL$." + +#. TRANSLATORS: show the user a warning +msgid "Enabling this remote is done at your own risk." +msgstr "A saját felelősségére engedélyezze ezt a távoli tárolót." + #. TRANSLATORS: command description msgid "Encrypt firmware data" msgstr "Firmware adatok titkosítása" @@ -270,6 +365,10 @@ msgid "Exit after the engine has loaded" msgstr "Kilépés a motor betöltődése után" +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "A letöltés kiszolgálókorlát miatt meghiúsult" + #. TRANSLATORS: quirks are device-specific workarounds msgid "Failed to load quirks" msgstr "A trükkök betöltése sikertelen" @@ -325,6 +424,15 @@ msgstr[0] "A firmware metaadatok %u napja nem lettek frissítve, és lehet hogy elavultak." msgstr[1] "A firmware metaadatok %u napja nem lettek frissítve, és lehet hogy elavultak." +msgid "Firmware updates are not supported on this machine." +msgstr "A firmware frissítések nem támogatottak ezen a gépen." + +msgid "Firmware updates are supported on this machine." +msgstr "A firmware frissítések támogatottak ezen a gépen." + +msgid "Force the action ignoring all warnings" +msgstr "A művelet erőltetése, az összes figyelmeztetés mellőzése" + #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Megtalálva" @@ -333,10 +441,18 @@ msgstr "GUID" #. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "Az összes eszköz lekérdezése a rendszer topológiájának megfelelően" + +#. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Minden eszköz lekérése, amelyek támogatják a firmware frissítéseket" #. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "Az összes rendszeren regisztrált és engedélyezett bővítmény lekérdezése" + +#. TRANSLATORS: command description msgid "Gets details about a firmware file" msgstr "Részleteket kér le egy firmware fájlról" @@ -369,6 +485,10 @@ msgstr "Üresjárat…" #. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "Firmware blob telepítése egy eszközre" + +#. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "Egy firmware fájl telepítése ezen a hardveren" @@ -395,17 +515,40 @@ msgid "Installing firmware update…" msgstr "Firmware frissítés telepítése…" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "%s telepítése…" + msgid "Keyring" msgstr "Kulcstartó" +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Kevesebb mint egy perc van hátra" + +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Linux gyártói firmware szolgáltatás (stabil firmware)" + +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Linux gyártói firmware szolgáltatás (teszt firmware)" + #. TRANSLATORS: command description msgid "List currently attached DFU capable devices" msgstr "Jelenleg csatlakoztatott DFU-képes eszközök felsorolása" +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "A támogatott firmware-frissítések listázása" + #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "Betöltés…" +#. TRANSLATORS: command line option +msgid "Manually whitelist specific plugins" +msgstr "Egyes bővítmények kézi fehérlistára tétele" + #. TRANSLATORS: command description msgid "Merge multiple firmware files into one" msgstr "Több firmware fájl egyesítése" @@ -418,6 +561,10 @@ msgid "Metadata URI Signature" msgstr "Metaadat URI aláírása" +#. TRANSLATORS: explain why no metadata available +msgid "Metadata can be obtained from the Linux Vendor Firmware Service." +msgstr "A metaadatok nem szerezhetőek be a Linux gyártói firmware szolgáltatásból." + msgid "Mode" msgstr "Mód" @@ -438,11 +585,22 @@ msgid "Name" msgstr "Név" +msgid "No action specified!" +msgstr "Nincs művelet megadva!" + #. TRANSLATORS: nothing attached #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "Nem észlelhető firmware frissítési képességgel rendelkező hardver" +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "Nem található bővítmény" + +#. TRANSLATORS: explain why no metadata available +msgid "No remotes are currently enabled so no metadata is available." +msgstr "Jelenleg nincsenek engedélyezett távoli tárolók, így nem érhetőek el metaadatok." + msgid "OK" msgstr "OK" @@ -450,6 +608,10 @@ msgid "Override plugin warning" msgstr "Bővítmény figyelmeztetés felülbírálása" +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "Az alapértelmezett ESP útvonal felülbírálása" + #. TRANSLATORS: remote filename base msgid "Password" msgstr "Jelszó" @@ -465,6 +627,12 @@ msgid "Please enter a number from 0 to %u: " msgstr "Adjon meg egy számot 0 és %u között:" +msgid "Print the version number" +msgstr "A verziószám kiírása." + +msgid "Print verbose debug statements" +msgstr "Részletes hibakeresési utasítások kiírása" + #. TRANSLATORS: the numeric priority msgid "Priority" msgstr "Prioritás" @@ -476,6 +644,10 @@ msgid "Protocol" msgstr "Protokoll" +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "Firmware frissítési támogatás lekérdezése" + #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" @@ -546,7 +718,7 @@ #. TRANSLATORS: command description msgid "Return all the hardware IDs for the machine" -msgstr "A géphez tartoó összes hardverazonosító visszaadása" +msgstr "A géphez tartozó összes hardverazonosító visszaadása" msgid "Runtime" msgstr "Futtatókörnyezet" @@ -583,6 +755,10 @@ msgid "Set release version on firmware file" msgstr "Kiadási verzió beállítása a firmware fájlon" +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "A hibakeresési jelző beállítása frissítéskor" + #. TRANSLATORS: command description msgid "Set the firmware size for the target" msgstr "A firmware méretének beállítása a célhoz" @@ -603,6 +779,10 @@ msgid "Show client and daemon versions" msgstr "Ügyfél és démon verziók megjelenítése" +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information" +msgstr "A démon részletes információinak megjelenítése" + #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Hibakeresési információk megjelenítése minden fájlnál" @@ -612,6 +792,10 @@ msgstr "Hibakeresési beállítások megjelenítése" #. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Eszközök, melyek nem frissíthetőek" + +#. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "További hibakeresési információk megjelenítése" @@ -623,6 +807,20 @@ msgid "Show plugin verbose information" msgstr "Bővítmény bőbeszédű információinak megjelenítése" +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "A legutóbb megpróbált frissítés hibakeresési naplójának megjelenítése" + +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "A firmware frissítési állapot információinak megjelenítése" + +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Adja meg a DFU eszköz gyártó-/termékazonosítóját" + +msgid "Specify the number of bytes per USB transfer" +msgstr "Adja meg az USB átvitelek bájtjainak számát" + #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Állapot" @@ -640,11 +838,16 @@ msgid "Target" msgstr "Cél" -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "A fwupd folyamat egy egyszerű démon, amely lehetővé teszi más szoftvereknek a számítógép eszközeinek firmware-jének frissítését. Asztali számítógépekre lett tervezve, de használható telefonokon, táblagépeken és képernyő nélküli kiszolgálókon is. " +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "Az LVFS egy ingyenes szolgáltatás, amely független jogi entitásként működik, és nincs kapcsolata a $OS_RELEASE:NAME$ operációs rendszerrel. A disztribúció szállítója nem biztos, hogy ellenőrízte kompatibilitási szempontból a firmware frissítést. Mindent firmware-t csak az eredeti termék gyártója biztosít." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "Ez a program jelenleg lehet, hogy csak rendszergazdaként működik" -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "A projekt célja a firmwarek frissítését automatikussá, biztonságossá és megbízhatóvá tétele Linuxon. Használhat grafikus szoftverkezelőket, mint a GNOME Szoftverek a frissítések megtekintéséhez és alkalmazásához, használhatja a parancssoros eszközt, vagy közvetlenül a D-Bus interfészt." +msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +msgstr "Ez a távoli tároló olyan firmware-t tartalmaz, amelyre nem vonatkozik embargó, de még teszteli a harvergyártó. Érdemes biztosítani a firmware kézi visszaállításáról, ha a firmware frissítése meghiúsul." #. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" msgid "Title" @@ -658,6 +861,10 @@ msgid "Type" msgstr "Típus" +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "UEFI firmware segédprogram" + #. TRANSLATORS: section header for firmware URI msgid "URI" msgstr "URI" @@ -673,6 +880,10 @@ msgid "Unlocks the device for firmware access" msgstr "Eszköz feloldása a firmware eléréséhez" +#. TRANSLATORS: command line option +msgid "Unset the debugging flag during update" +msgstr "A hibakeresési jelző kikapcsolása frissítéskor" + #. TRANSLATORS: section header for firmware checksum msgid "Update Checksum" msgstr "Frissítés ellenőrzőösszege" @@ -681,6 +892,11 @@ msgid "Update Description" msgstr "Frissítés leírása" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Frissítés hossza" + #. TRANSLATORS: section header for firmware remote http:// msgid "Update Location" msgstr "Frissítés helye" @@ -701,9 +917,6 @@ msgid "Update Version" msgstr "Frissítés verziója" -msgid "Update device firmware on Linux" -msgstr "Eszköz firmware frissítése Linuxon" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "A feltöltési hiba ismert probléma, további információkért látogassa meg ezt az URL-t:" @@ -730,6 +943,11 @@ msgid "Updating %s from %s to %s... " msgstr "%s frissítése: %s -> %s…" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "%s frissítése…" + #. TRANSLATORS: the server sent the user a small message msgid "Upload message:" msgstr "Feltöltési üzenet:" @@ -738,6 +956,10 @@ msgid "Upload report now?" msgstr "Feltölti most a jelentést?" +#. TRANSLATORS: explain why we want to upload +msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +msgstr "A firmware jelentések segítenek a hardvergyártóknak, hogy gyorsan azonosítsák a hibás és sikeres frissítéseket valós eszközökön." + #. TRANSLATORS: remote filename base msgid "Username" msgstr "Felhasználónév" @@ -759,6 +981,10 @@ msgstr "DFU-eszközök menet közbeni csatlakoztatásának figyelése" #. TRANSLATORS: command description +msgid "Watch for hardware changes" +msgstr "Hardverváltozások figyelése" + +#. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "Firmware írása fájlból egy eszközre" @@ -770,5 +996,6 @@ msgid "Writing…" msgstr "Írás…" -msgid "fwupd" -msgstr "fwupd" +#. TRANSLATORS: show the user a warning +msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." +msgstr "A disztribúció szállítója nem biztos, hogy ellenőrízte a firmware frissítés kompatibilitását a rendszerével és a kapcsolódó eszközeivel." diff -Nru fwupd-1.1.4/po/id.po fwupd-1.2.5/po/id.po --- fwupd-1.1.4/po/id.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/id.po 2019-02-25 09:42:18.000000000 +0000 @@ -8,8 +8,6 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Indonesian (http://www.transifex.com/freedesktop/fwupd/language/id/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -43,7 +41,7 @@ msgid "Allow re-installing existing firmware versions" msgstr "Izinkan pemasangan ulang versi firmware yang telah ada" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Suatu pembaruan memerlukan boot ulang agar lengkap." @@ -627,12 +625,6 @@ msgid "Target" msgstr "Target" -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "Proses fwupd adalah sebuah daemon sederhana yang memungkinkan perangkat lunak sesi memperbarui firmware peranti pada mesin lokal Anda. Ini dirancang untuk desktop, tapi proyek ini juga dapat dipakai pada telepon, tablet, dan server headless." - -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Proyek ini bertujuan membuat pemutakhiran firmware pada Linux otomatis, aman, dan handal. Anda dapat memakai manajer perangkat lunak GUI seperti GNOME Perangkat Lunak untuk melihat dan menerapkan pembaruan, perkakas perintah baris, atau antar muka D-Bus secara langsung." - #. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" msgid "Title" msgstr "Judul" @@ -688,9 +680,6 @@ msgid "Update Version" msgstr "Mutakhirkan Versi" -msgid "Update device firmware on Linux" -msgstr "Perbarui firmware peranti pada Linux" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "Kegagalan pembaruan adalah masalah yang telah diketahui, kunjungi URL ini untuk informasi lebih lanjut:" @@ -756,6 +745,3 @@ #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Menulis..." - -msgid "fwupd" -msgstr "fwupd" diff -Nru fwupd-1.1.4/po/it.po fwupd-1.2.5/po/it.po --- fwupd-1.1.4/po/it.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/it.po 2019-02-25 09:42:18.000000000 +0000 @@ -4,13 +4,11 @@ # # Translators: # Gianvito Cavasoli , 2016 -# Milo Casagrande , 2017-2018 +# Milo Casagrande , 2017-2019 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Italian (http://www.transifex.com/freedesktop/fwupd/language/it/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -30,6 +28,34 @@ msgid "%s has firmware updates:" msgstr "%s ha degli aggiornamenti del firmware:" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u giorno" +msgstr[1] "%u giorni" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u ora" +msgstr[1] "%u ore" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u minuto" +msgstr[1] "%u minuti" + +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u secondo" +msgstr[1] "%u secondi" + #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Aggiunto" @@ -55,10 +81,14 @@ msgid "Allow re-installing existing firmware versions" msgstr "Consente di reinstallare versioni del firmware esistenti" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Per essere completato, un aggiornamento richiede un riavvio." +#. TRANSLATORS: explain why we want to shutdown +msgid "An update requires the system to shutdown to complete." +msgstr "Per essere completato, un aggiornamento richiede lo spegnimento del sistema." + #. TRANSLATORS: command line option msgid "Answer yes to all questions" msgstr "Risponde affermativamente a tutte le domande" @@ -266,6 +296,11 @@ msgid "Downgrading %s from %s to %s... " msgstr "Arretramento di %s da %s a %s..." +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Arretramento di %s…" + #. TRANSLATORS: downloading from a remote server msgid "Downloading…" msgstr "Scaricamento…" @@ -397,6 +432,9 @@ msgid "Firmware updates are supported on this machine." msgstr "Gli aggiornamenti firmware sono supportati su questo dispositivo." +msgid "Force the action ignoring all warnings" +msgstr "Forza l'azione ignorando gli avvisi" + #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Trovato" @@ -475,12 +513,6 @@ msgid "Install unsigned system firmware" msgstr "Installa firmware non firmato di sistema" -#. show message in progressbar -#. TRANSLATORS: %1 is a device name -#, c-format -msgid "Installing %s" -msgstr "Installazione di %s" - #. TRANSLATORS: this is shown when updating the firmware after the reboot msgid "Installing firmware update…" msgstr "Installazione aggiornamento firmware…" @@ -597,6 +629,12 @@ msgid "Please enter a number from 0 to %u: " msgstr "Inserire un numero tra 0 e %u:" +msgid "Print the version number" +msgstr "Stampa il numero di versione" + +msgid "Print verbose debug statements" +msgstr "Stampa messaggi di debug prolissi" + #. TRANSLATORS: the numeric priority msgid "Priority" msgstr "Priorità" @@ -743,6 +781,10 @@ msgid "Show client and daemon versions" msgstr "Mostra la versione del client e del demone" +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information" +msgstr "Mostra informazioni prolisse del demone" + #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Mostra le informazioni di debug per tutti i file" @@ -775,6 +817,16 @@ msgid "Show the information of firmware update status" msgstr "Mostra informazioni sullo stato degli aggiornamenti firmware" +#. TRANSLATORS: shutdown to apply the update +msgid "Shutdown now?" +msgstr "Spegnere ora?" + +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Specifica vendor/ID prodotto di un dispositivo DFU" + +msgid "Specify the number of bytes per USB transfer" +msgstr "Specifica il numero di byte per trasferimento USB" + #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Stato" @@ -796,20 +848,10 @@ msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS è un servizio gratuito che opera come entità legale indipendente e non ha alcun legame con $OS_RELEASE:NAME$. Il distributore potrebbe non aver verificato la compatibilità degli aggiornamenti firmware col proprio sistema o con i propri dispositivi collegati. Il firmware viene fornito solamente dall'OEM." -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "Il processo fwupd è un demone che consente di aggiornare il firmware di un dispositivo sul proprio computer. È progettato per un ambiente desktop, ma è possibile utilizzarlo anche su telefonini, tablet e server." - -#. TRANSLATORS: exactly one update needs this -msgid "The update requires a reboot to complete." -msgstr "Per essere completato, l'aggiornamento richiede un riavvio." - #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "Questo programma può funzionare correttamente solo come utente root" -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Questo progetto vuole rendere l'aggiornamento di firmware su Linux un processo automatico, sicuro e affidabile. È possibile usare uno strumento grafico come GNOME Software per visualizzare e applicare gli aggiornamenti, oppure lo strumento a riga di comando o l'interfaccia D-Bus." - msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "Questo remoto contiene firmware che non è bloccato, ma è ancora in fase di verifica dal produttore hardware. Assicurarsi di poter ripristinare, manualmente o con altre procedure, il vecchio firmware nel caso in cui l'aggiornamento non riuscisse." @@ -856,6 +898,11 @@ msgid "Update Description" msgstr "Descrizione aggiornamento" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Durata aggiornamento" + #. TRANSLATORS: section header for firmware remote http:// msgid "Update Location" msgstr "Posizione aggiornamento" @@ -876,8 +923,9 @@ msgid "Update Version" msgstr "Versione aggiornamento" -msgid "Update device firmware on Linux" -msgstr "Aggiorna firmware dispositivi su Linux" +#. TRANSLATORS: command description +msgid "Update all devices that match local metadata" +msgstr "Aggiorna tutti i dispositivi corrispondenti ai metadati locali" #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" @@ -905,6 +953,11 @@ msgid "Updating %s from %s to %s... " msgstr "Aggiornamento di %s da %s a %s..." +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Aggiornamento di %s…" + #. TRANSLATORS: the server sent the user a small message msgid "Upload message:" msgstr "Messaggio di caricamento:" @@ -956,6 +1009,3 @@ #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "La propria distribuzione potrebbe non aver verificato la compatibilità degli aggiornamenti firmware col proprio sistema o col dispositivo collegato." - -msgid "fwupd" -msgstr "fwupd" diff -Nru fwupd-1.1.4/po/kk.po fwupd-1.2.5/po/kk.po --- fwupd-1.1.4/po/kk.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/kk.po 2019-02-25 09:42:18.000000000 +0000 @@ -8,9 +8,6 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-09-01 14:26+0100\n" -"PO-Revision-Date: 2017-09-01 13:27+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Kazakh (http://www.transifex.com/freedesktop/fwupd/language/kk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff -Nru fwupd-1.1.4/po/ko.po fwupd-1.2.5/po/ko.po --- fwupd-1.1.4/po/ko.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/ko.po 2019-02-25 09:42:18.000000000 +0000 @@ -9,8 +9,6 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Korean (http://www.transifex.com/freedesktop/fwupd/language/ko/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -48,7 +46,7 @@ msgid "Allow re-installing existing firmware versions" msgstr "기존 펌웨어 버전 재설치를 허용합니다" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "업데이트를 완료하려면 다시 시작해야 합니다." @@ -769,16 +767,10 @@ msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS는 $OS_RELEASE:NAME$와(과) 별개로 운영되는 독립된 법적 단체에서 운영하는 무료 서비스입니다. 배포판 개발사에서 펌웨어 업데이트와 시스템 및 연결된 장치간의 호환성을 검증한다는 보장이 없습니다. 모든 펌웨어는 원 장치 제조사(OEM)에서 직접 제공합니다." -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "fwupd 프로세스는 로컬 머신의 장치 펌웨어를 세션 프로그램에서 업데이트할 수 있게 하는 간단한 데몬입니다. 데스크톱용으로 설계했지만, 전화기, 태블릿, 헤드리스 서버에서도 사용할 수 있습니다." - #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "이 프로그램은 루트 권한으로만 올바르게 작동할 수도 있습니다" -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "이 프로젝트에서는 리눅스에서 자동으로 안전하고 믿을 수 있게 펌웨어를 업데이트할 수 있게 하려고 합니다. 그놈 소프트웨어와 같은 GUI 도구로 업데이트를 보고 적용하거나, 명령행 도구 및 D-Bus 인터페이스를 직접 사용할 수 있습니다." - msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "이 원격 저장소에서는 하드웨어 제조사에서 검증 단계를 진행 중인 펌웨어를 배포합니다. 펌웨어 업데이트 도중 및 이후 문제가 발생했을 때 수동으로 펌웨어를 다운그레이드할 방법을 찾아 두는 것을 추천합니다." @@ -845,9 +837,6 @@ msgid "Update Version" msgstr "업데이트 버전" -msgid "Update device firmware on Linux" -msgstr "리눅스에서 장치 펌웨어를 업데이트합니다" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "알 수 없는 이유로 업데이트가 실패했습니다. 더 많은 정보를 보려면 다음 URL을 참조가힙시오:" @@ -925,6 +914,3 @@ #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "배포판 개발사에서 펌웨어 업데이트와 시스템 및 연결된 장치간의 호환성을 검증한다는 보장이 없습니다." - -msgid "fwupd" -msgstr "fwupd" diff -Nru fwupd-1.1.4/po/ky.po fwupd-1.2.5/po/ky.po --- fwupd-1.1.4/po/ky.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/ky.po 2019-02-25 09:42:18.000000000 +0000 @@ -8,8 +8,6 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Kyrgyz (http://www.transifex.com/freedesktop/fwupd/language/ky/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff -Nru fwupd-1.1.4/po/LINGUAS fwupd-1.2.5/po/LINGUAS --- fwupd-1.1.4/po/LINGUAS 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/LINGUAS 2019-02-25 09:42:18.000000000 +0000 @@ -1,8 +1,10 @@ +af ast ca cs de en_GB +eo eu fi fr diff -Nru fwupd-1.1.4/po/nl.po fwupd-1.2.5/po/nl.po --- fwupd-1.1.4/po/nl.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/nl.po 2019-02-25 09:42:18.000000000 +0000 @@ -8,8 +8,6 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Dutch (http://www.transifex.com/freedesktop/fwupd/language/nl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff -Nru fwupd-1.1.4/po/oc.po fwupd-1.2.5/po/oc.po --- fwupd-1.1.4/po/oc.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/oc.po 2019-02-25 09:42:18.000000000 +0000 @@ -9,8 +9,6 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Occitan (post 1500) (http://www.transifex.com/freedesktop/fwupd/language/oc/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff -Nru fwupd-1.1.4/po/pl.po fwupd-1.2.5/po/pl.po --- fwupd-1.1.4/po/pl.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/pl.po 2019-02-25 09:42:18.000000000 +0000 @@ -3,13 +3,11 @@ # This file is distributed under the same license as the fwupd package. # # Translators: -# Piotr Drąg , 2015-2018 +# Piotr Drąg , 2015-2019 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Polish (http://www.transifex.com/freedesktop/fwupd/language/pl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -31,6 +29,42 @@ msgid "%s has firmware updates:" msgstr "Dostępne są aktualizacje oprogramowania sprzętowego dla urządzenia %s:" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u dzień" +msgstr[1] "%u dni" +msgstr[2] "%u dni" +msgstr[3] "%u dni" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u godzina" +msgstr[1] "%u godziny" +msgstr[2] "%u godzin" +msgstr[3] "%u godzin" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u minuta" +msgstr[1] "%u minuty" +msgstr[2] "%u minut" +msgstr[3] "%u minut" + +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u sekunda" +msgstr[1] "%u sekundy" +msgstr[2] "%u sekund" +msgstr[3] "%u sekund" + #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Dodano" @@ -56,10 +90,14 @@ msgid "Allow re-installing existing firmware versions" msgstr "Umożliwia ponowne instalowanie istniejących wersji oprogramowania sprzętowego" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Ukończenie aktualizacji wymaga ponownego uruchomienia." +#. TRANSLATORS: explain why we want to shutdown +msgid "An update requires the system to shutdown to complete." +msgstr "Ukończenie aktualizacji wymaga wyłączenia komputera." + #. TRANSLATORS: command line option msgid "Answer yes to all questions" msgstr "Odpowiada tak na wszystkie pytania" @@ -267,6 +305,11 @@ msgid "Downgrading %s from %s to %s... " msgstr "Instalowanie poprzedniej wersji %s z %s do %s… " +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Instalowanie poprzedniej wersji urządzenia %s…" + #. TRANSLATORS: downloading from a remote server msgid "Downloading…" msgstr "Pobieranie…" @@ -400,6 +443,9 @@ msgid "Firmware updates are supported on this machine." msgstr "Aktualizacje oprogramowania sprzętowego są obsługiwane na tym komputerze." +msgid "Force the action ignoring all warnings" +msgstr "Wymusza działanie ignorując wszystkie ostrzeżenia" + #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Odnaleziono" @@ -478,12 +524,6 @@ msgid "Install unsigned system firmware" msgstr "Instalacja niepodpisanego oprogramowania sprzętowego komputera" -#. show message in progressbar -#. TRANSLATORS: %1 is a device name -#, c-format -msgid "Installing %s" -msgstr "Instalowanie urządzenia %s" - #. TRANSLATORS: this is shown when updating the firmware after the reboot msgid "Installing firmware update…" msgstr "Instalowanie aktualizacji oprogramowania sprzętowego…" @@ -600,6 +640,12 @@ msgid "Please enter a number from 0 to %u: " msgstr "Proszę podać liczbę od 0 do %u:" +msgid "Print the version number" +msgstr "Wyświetla numer wersji" + +msgid "Print verbose debug statements" +msgstr "Wyświetla więcej komunikatów debugowania" + #. TRANSLATORS: the numeric priority msgid "Priority" msgstr "Priorytet" @@ -746,6 +792,10 @@ msgid "Show client and daemon versions" msgstr "Wyświetla wersje klienta i usługi" +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information" +msgstr "Wyświetla więcej informacji o usłudze" + #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Wyświetla informacje o debugowaniu dla wszystkich plików" @@ -778,6 +828,16 @@ msgid "Show the information of firmware update status" msgstr "Wyświetla informacje o stanie aktualizacji oprogramowania sprzętowego" +#. TRANSLATORS: shutdown to apply the update +msgid "Shutdown now?" +msgstr "Wyłączyć teraz?" + +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Podaje identyfikatory dostawcy/produktu urządzenia DFU" + +msgid "Specify the number of bytes per USB transfer" +msgstr "Podaje liczbę bajtów na przesyłanie USB" + #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Stan" @@ -799,20 +859,10 @@ msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS to wolny serwis działający jako niezależny podmiot prawny niemający związków z systemem $OS_RELEASE:NAME$. Dystrybutor używanego systemu mógł nie zweryfikować żadnych aktualizacji oprogramowania sprzętowego pod kątem zgodności z używanym komputerem lub podłączonymi urządzeniami. Każde oprogramowanie sprzętowe jest dostarczane wyłącznie przez oryginalnego producenta sprzętu." -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "Proces fwupd to prosta usługa umożliwiająca aktualizowanie oprogramowania sprzętowego komputera w sesji użytkownika. Jest zaprojektowana dla komputerów osobistych, ale można jej używać także na telefonach, tabletach i serwerach bez monitorów." - -#. TRANSLATORS: exactly one update needs this -msgid "The update requires a reboot to complete." -msgstr "Ukończenie aktualizacji wymaga ponownego uruchomienia." - #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "Ten program może działać poprawnie tylko jako root" -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Celem projektu jest automatyczne, bezpieczne i pewne aktualizowanie oprogramowania sprzętowego w systemie Linux. Można używać graficznego menedżera oprogramowania, takiego jak Menedżer oprogramowania GNOME do wyświetlania i zastosowywania aktualizacji, narzędzia wiersza poleceń lub bezpośrednio interfejsu D-Bus." - msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "To repozytorium zawiera oprogramowanie sprzętowe nieobjęte embargo, ale nadal testowane przez dostawcę sprzętu. Należy upewnić się, że istnieje możliwość ręcznego zainstalowania poprzedniej wersji oprogramowania sprzętowego w razie niepowodzenia aktualizacji." @@ -859,6 +909,11 @@ msgid "Update Description" msgstr "Opis aktualizacji" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Czas trwania aktualizacji" + #. TRANSLATORS: section header for firmware remote http:// msgid "Update Location" msgstr "Położenie aktualizacji" @@ -879,8 +934,9 @@ msgid "Update Version" msgstr "Wersja aktualizacji" -msgid "Update device firmware on Linux" -msgstr "Aktualizowanie oprogramowania sprzętowego w systemie Linux" +#. TRANSLATORS: command description +msgid "Update all devices that match local metadata" +msgstr "Aktualizuje wszystkie urządzenia pasujące do lokalnych metadanych" #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" @@ -908,6 +964,11 @@ msgid "Updating %s from %s to %s... " msgstr "Aktualizowanie %s z wersji %s do %s… " +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Aktualizowanie urządzenia %s…" + #. TRANSLATORS: the server sent the user a small message msgid "Upload message:" msgstr "Komunikat wysyłania:" @@ -959,6 +1020,3 @@ #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Używana dystrybucja mogła nie sprawdzić zgodności aktualizacji oprogramowania sprzętowego z komputerem i podłączonymi urządzeniami." - -msgid "fwupd" -msgstr "fwupd" diff -Nru fwupd-1.1.4/po/POTFILES.in fwupd-1.2.5/po/POTFILES.in --- fwupd-1.1.4/po/POTFILES.in 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/POTFILES.in 2019-02-25 09:42:18.000000000 +0000 @@ -1,4 +1,3 @@ -data/org.freedesktop.fwupd.metainfo.xml data/remotes.d/lvfs.metainfo.xml data/remotes.d/lvfs-testing.metainfo.xml policy/org.freedesktop.fwupd.policy.in diff -Nru fwupd-1.1.4/po/POTFILES.skip fwupd-1.2.5/po/POTFILES.skip --- fwupd-1.1.4/po/POTFILES.skip 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/po/POTFILES.skip 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1 @@ +data/org.freedesktop.fwupd.metainfo.xml diff -Nru fwupd-1.1.4/po/pt_BR.po fwupd-1.2.5/po/pt_BR.po --- fwupd-1.1.4/po/pt_BR.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/pt_BR.po 2019-02-25 09:42:18.000000000 +0000 @@ -6,14 +6,12 @@ # Derek W. Stavis , 2015 # Derek W. Stavis , 2016 # Derek W. Stavis , 2015-2016 -# Rafael Fontenelle , 2017 -# Rafael Fontenelle , 2015-2018 +# Rafael Fontenelle , 2017-2018 +# Rafael Fontenelle , 2015-2019 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Portuguese (Brazil) (http://www.transifex.com/freedesktop/fwupd/language/pt_BR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -21,11 +19,46 @@ "Language: pt_BR\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "%.0f minuto restante" +msgstr[1] "%.0f minutos restantes" + #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" msgstr "%s tem atualizações de firmware:" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u dia" +msgstr[1] "%u dias" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u hora" +msgstr[1] "%u horas" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u minuto" +msgstr[1] "%u minutos" + +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u segundo" +msgstr[1] "%u segundos" + #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Adicionado" @@ -45,16 +78,20 @@ #. TRANSLATORS: command line option msgid "Allow downgrading firmware versions" -msgstr "Permite reverter versões de firmware" +msgstr "Permite fazer downgrade de versões de firmware" #. TRANSLATORS: command line option msgid "Allow re-installing existing firmware versions" msgstr "Permite reinstalar versões existentes de firmware" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Uma atualização requer uma reinicialização para completar." +#. TRANSLATORS: explain why we want to shutdown +msgid "An update requires the system to shutdown to complete." +msgstr "Uma atualização requer que o sistema seja desligado por completo." + #. TRANSLATORS: command line option msgid "Answer yes to all questions" msgstr "Responde sim para todas as perguntas" @@ -86,11 +123,11 @@ #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on a removable device" -msgstr "É requerida autenticação para voltar a versão do firmware em um dispositivo removível" +msgstr "É requerida autenticação para fazer downgrade da versão do firmware em um dispositivo removível" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "É requerida autenticação para voltar a versão do firmware nesta máquina" +msgstr "É requerida autenticação para fazer downgrade da versão do firmware nesta máquina" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to modify a configured remote used for firmware updates" @@ -253,14 +290,19 @@ #. TRANSLATORS: command description msgid "Downgrades the firmware on a device" -msgstr "Retrocede a versão do firmware em um dispositivo" +msgstr "Faz downgrade da versão do firmware em um dispositivo" #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" #, c-format msgid "Downgrading %s from %s to %s... " -msgstr "Revertendo %s de %s para %s… " +msgstr "Fazendo downgrade de %s de %s para %s… " + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Fazendo downgrade %s…" #. TRANSLATORS: downloading from a remote server msgid "Downloading…" @@ -393,6 +435,9 @@ msgid "Firmware updates are supported on this machine." msgstr "Há suporte a atualizações de firmware nesta máquina." +msgid "Force the action ignoring all warnings" +msgstr "Força a ação ignorando todos avisos" + #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Encontrado" @@ -471,19 +516,22 @@ msgid "Install unsigned system firmware" msgstr "Instalar firmware não assinado no sistema" -#. show message in progressbar -#. TRANSLATORS: %1 is a device name -#, c-format -msgid "Installing %s" -msgstr "Instalando %s" - #. TRANSLATORS: this is shown when updating the firmware after the reboot msgid "Installing firmware update…" msgstr "Instalando atualização de firmware…" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "Instalando em %s…" + msgid "Keyring" msgstr "Chaveiro" +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Menos que um minuto restante" + msgid "Linux Vendor Firmware Service (stable firmware)" msgstr "Linux Vendor Firmware Service (firmware estável)" @@ -584,6 +632,12 @@ msgid "Please enter a number from 0 to %u: " msgstr "Por favor, insira um número de 0 a %u: " +msgid "Print the version number" +msgstr "Imprime o número de versão" + +msgid "Print verbose debug statements" +msgstr "Imprime instruções de depuração verbosas" + #. TRANSLATORS: the numeric priority msgid "Priority" msgstr "Prioridade" @@ -730,6 +784,10 @@ msgid "Show client and daemon versions" msgstr "Mostra as versões do cliente e do daemon" +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information" +msgstr "Mostra informações verbosas de daemon" + #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Mostrar informações de depuração para todos os arquivos" @@ -762,6 +820,16 @@ msgid "Show the information of firmware update status" msgstr "Mostra as informações do status de atualização de firmware" +#. TRANSLATORS: shutdown to apply the update +msgid "Shutdown now?" +msgstr "Desligar agora?" + +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Especifica ID(s) de Fornecedor/Produto de dispositivo DFU" + +msgid "Specify the number of bytes per USB transfer" +msgstr "Especifica o número de bytes por transferência USB" + #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Estado" @@ -783,16 +851,10 @@ msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "O LVFS é um serviço livre que opera como uma entidade legal independente e tem nenhuma conexão com $OS_RELEASE:NAME$. Seu distribuidor pode não ter verificado alguma das atualizações de firmware por compatibilidade com seu sistema ou dispositivos conectados. Todos os firmwares são fornecidos apenas pelo fabricante do equipamento original." -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "O fwupd processa é um daemon simples para permitir que software sessão atualizem firmware de dispositivo em seu computador local. É projetado para computadores de mesa, mas esse projeto também é usável em telefones, tablets e em servidores “headless” (sem monitor, teclado e mouse)." - #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "Esse programa só pode funcionar corretamente como root" -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Esse projeto visa tornar a atualização de firmware no Linux automática, segura e confiável. você pode usar um gerenciador de software GUI, como o GNOME Software, para ver e aplicar atualizações, a ferramenta de linha de comando ou a interface D-Bus diretamente." - msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "Este remoto contém firmware que não está embargado, mas ainda está sendo testado pelo fornecedor do hardware. Você deve garantir que você tenha uma maneira de fazer downgrade manual do firmware se a atualização do firmware falhar." @@ -839,6 +901,11 @@ msgid "Update Description" msgstr "Descrição da atualização" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Duração da atualização" + #. TRANSLATORS: section header for firmware remote http:// msgid "Update Location" msgstr "Local da atualização" @@ -859,8 +926,9 @@ msgid "Update Version" msgstr "Versão da atualização" -msgid "Update device firmware on Linux" -msgstr "Atualize firmware de dispositivos no Linux" +#. TRANSLATORS: command description +msgid "Update all devices that match local metadata" +msgstr "Atualiza todos os dispositivos que correspondem aos metadados locais" #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" @@ -888,6 +956,11 @@ msgid "Updating %s from %s to %s... " msgstr "Atualizando %s de %s para %s… " +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Atualizando %s…" + #. TRANSLATORS: the server sent the user a small message msgid "Upload message:" msgstr "Mensagem enviada:" @@ -939,6 +1012,3 @@ #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Seu distribuidor pode não ter verificado qualquer das atualizações de firmware para compatibilidade com seu sistema ou dispositivos conectados." - -msgid "fwupd" -msgstr "fwupd" diff -Nru fwupd-1.1.4/po/ru.po fwupd-1.2.5/po/ru.po --- fwupd-1.1.4/po/ru.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/ru.po 2019-02-25 09:42:18.000000000 +0000 @@ -9,8 +9,6 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Russian (http://www.transifex.com/freedesktop/fwupd/language/ru/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -547,12 +545,6 @@ msgid "Status" msgstr "Статус" -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "Процесс fwupd является простой фоновой службой, позволяющей сеансовому программному обеспечению обновлять микропрограммы устройств на вашем компьютере. Он разработан для настольных компьютеров, но этот проект также годен для использования на телефонах, планшетах и безмониторных серверах." - -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Целью этого проекта является безопасная и надёжная автоматизация обновления микропрограмм в Linux. Для просмотра и применения обновлений вы можете использовать как графический диспетчер программного обеспечения, такой как GNOME Software, так и инструментарий командной строки или даже непосредственно D-Bus интерфейс." - #. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" msgid "Title" msgstr "Заголовок" @@ -600,9 +592,6 @@ msgid "Update Version" msgstr "Версия обновления" -msgid "Update device firmware on Linux" -msgstr "Обновить микропрограмму устройства на Linux" - msgid "Update the stored device verification information" msgstr "Обновление хранимой проверочной информации устройства" @@ -652,6 +641,3 @@ #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Запись…" - -msgid "fwupd" -msgstr "fwupd" diff -Nru fwupd-1.1.4/po/sk.po fwupd-1.2.5/po/sk.po --- fwupd-1.1.4/po/sk.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/sk.po 2019-02-25 09:42:18.000000000 +0000 @@ -8,8 +8,6 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Slovak (http://www.transifex.com/freedesktop/fwupd/language/sk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff -Nru fwupd-1.1.4/po/sr.po fwupd-1.2.5/po/sr.po --- fwupd-1.1.4/po/sr.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/sr.po 2019-02-25 09:42:18.000000000 +0000 @@ -10,8 +10,6 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Serbian (http://www.transifex.com/freedesktop/fwupd/language/sr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -45,7 +43,7 @@ msgid "Allow re-installing existing firmware versions" msgstr "Дозволи поновно инсталирање већ постојећих издања фирмвера" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Потребно је поново покретање да би се исправка применила." @@ -631,12 +629,6 @@ msgid "Target" msgstr "Мета" -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "Fwupd процес је једноставан демно који омогућава програмиму у сесији да ажурира фирмвер уређаја на вашој локалној машини. Намењен је за стоне рачунаре али је овај пројекат могуће користити на телефонима, таблетима и безглавим серверима." - -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Сврха овог пројекта је да учини ажурирање фирмвера на Линуксу лаким, безбедним и поузданим. Можете користити графичког управника програма као што су то Гномови Програми да бисте гледали и примењивали исправке, командну алатку или D-Bus интерфејс директно." - #. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" msgid "Title" msgstr "Наслов" @@ -692,9 +684,6 @@ msgid "Update Version" msgstr "Верзија ажурирања" -msgid "Update device firmware on Linux" -msgstr "Ажурирајте фирмвер уређаја на Линуксу" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "Узрок неуспеха ажурирања је познат, погледајте ову адресу за више података:" @@ -760,6 +749,3 @@ #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Пишем…" - -msgid "fwupd" -msgstr "fwupd" diff -Nru fwupd-1.1.4/po/sv.po fwupd-1.2.5/po/sv.po --- fwupd-1.1.4/po/sv.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/sv.po 2019-02-25 09:42:18.000000000 +0000 @@ -3,17 +3,15 @@ # This file is distributed under the same license as the fwupd package. # # Translators: -# Anders Jonsson , 2017 +# Anders Jonsson , 2017,2019 # Andreas Henriksson , 2017 # Josef Andersson , 2015,2017-2018 # Josef Andersson , 2015,2017 -# sebras , 2018 +# Sebastian Rasmussen , 2018 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Swedish (http://www.transifex.com/freedesktop/fwupd/language/sv/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -21,11 +19,46 @@ "Language: sv\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "%.0fminut kvarstår" +msgstr[1] "%.0f minuter kvarstår" + #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" msgstr "%s har uppdateringar för fast programvara:" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u dag" +msgstr[1] "%u dagar" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u timme" +msgstr[1] "%u timmar" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%uminut" +msgstr[1] "%u minuter" + +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u sekund" +msgstr[1] "%u sekunder" + #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Tillagd" @@ -51,7 +84,7 @@ msgid "Allow re-installing existing firmware versions" msgstr "Tillåt att installera om befintliga versioner av fast programvara" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "En uppdatering kräver en omstart för att färdigställas." @@ -63,10 +96,18 @@ msgid "Apply a binary patch" msgstr "Applicera en binär lagning" +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "Tillämpa uppdateringar för fast programvara" + #. TRANSLATORS: command description msgid "Attach DFU capable device back to runtime" msgstr "Anslut DFU-kapabel enhet till körtid" +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "Fäst till fast programvaruläge" + #. TRANSLATORS: device attributes, i.e. things that #. * the device can do msgid "Attributes" @@ -189,6 +230,10 @@ msgid "Detach currently attached DFU capable device" msgstr "Koppla från anslutna DFU-kapabla enheter" +#. TRANSLATORS: command description +msgid "Detach to bootloader mode" +msgstr "Koppla från till starthanterarläge" + #. TRANSLATORS: this is when a device is hotplugged msgid "Device added:" msgstr "Enhet tillagd:" @@ -209,11 +254,18 @@ msgid "Devices that were not updated correctly:" msgstr "Enheter som inte uppdaterades korrekt:" +msgid "Disabled fwupdate debugging" +msgstr "Inaktiverade fwupdate-felsökning" + #. TRANSLATORS: command description msgid "Disables a given remote" msgstr "Inaktiverar en given fjärr." #. TRANSLATORS: command line option +msgid "Display version" +msgstr "Visa version" + +#. TRANSLATORS: command line option msgid "Do not check for old metadata" msgstr "Kontrollera inte gammal metadata" @@ -225,6 +277,10 @@ msgid "Do not check for unreported history" msgstr "Kontrollera inte ej rapporterad historik" +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "Skriv inte till historikdatabasen" + msgid "Done!" msgstr "Klar!" @@ -239,6 +295,11 @@ msgid "Downgrading %s from %s to %s... " msgstr "Nedgraderar %s från %s till %s… " +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Nedgraderar %s…" + #. TRANSLATORS: downloading from a remote server msgid "Downloading…" msgstr "Laddar ner..." @@ -255,6 +316,14 @@ msgid "Dump information about a binary patch to the screen" msgstr "Dumpa informationen om en binär lagning till skärmen" +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "Angiven ESP var inte giltig" + +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "Aktivera stöd för uppdatering av fast programvara på system som stöds" + #. TRANSLATORS: Turn on the remote msgid "Enable this remote?" msgstr "Aktivera denna fjärr?" @@ -263,10 +332,16 @@ msgid "Enabled" msgstr "Aktiverad" +msgid "Enabled fwupdate debugging" +msgstr "Aktiverade fwupdate-felsökning" + #. TRANSLATORS: command description msgid "Enables a given remote" msgstr "Aktiverar en given fjärr." +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "Att aktivera denna funktionalitet görs på egen risk, vilket betyder att du måste kontakta den ursprungliga tillverkaren av din utrustning om problem som orsakas av dessa uppdateringar. Endast problem med själva uppdateringsprocessen ska rapporteras på $OS_RELEASE:BUG_REPORT_URL$." + #. TRANSLATORS: show the user a warning msgid "Enabling this remote is done at your own risk." msgstr "Att aktivera denna fjärr görs på egen risk." @@ -291,6 +366,10 @@ msgid "Exit after the engine has loaded" msgstr "Avsluta efter att motorn har lästs in" +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "Misslyckades med hämtning på grund av servergräns" + #. TRANSLATORS: quirks are device-specific workarounds msgid "Failed to load quirks" msgstr "Misslyckades med att läsa in speciallösning" @@ -346,6 +425,15 @@ msgstr[0] "Metadata för fast programvara har inte uppdaterats på %udag och kan vara utdaterad." msgstr[1] "Metadata för fast programvara har inte uppdaterats på %udagar och kan vara utdaterad." +msgid "Firmware updates are not supported on this machine." +msgstr "Uppdateringar av fast programvara stöds inte på denna maskin." + +msgid "Firmware updates are supported on this machine." +msgstr "Uppdateringar av fast programvara stöds på denna maskin." + +msgid "Force the action ignoring all warnings" +msgstr "Tvinga åtgärden, ignorera alla varningar" + #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Hittad" @@ -354,10 +442,18 @@ msgstr "GUID" #. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "Hämta alla enheter enligt systemets topologi" + +#. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Hämta alla enheter som stödjer uppdateringar av fast programvara" #. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "Erhåll alla aktiverade insticksmoduler som är registrerade i systemet" + +#. TRANSLATORS: command description msgid "Gets details about a firmware file" msgstr "Hämtar detaljer om en fast programvarufil" @@ -390,6 +486,10 @@ msgstr "Väntar…" #. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "Installera en fast programvaru-blob på en enhet" + +#. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "Installera en fast programvarufil på denna hårdvara" @@ -416,9 +516,18 @@ msgid "Installing firmware update…" msgstr "Installerar uppdatering för fast programvara…" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "Installerar på %s…" + msgid "Keyring" msgstr "Nyckelring" +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Mindre än en minut kvarstår" + msgid "Linux Vendor Firmware Service (stable firmware)" msgstr "Linux Vendor Firmware Service (stabil fastprogramvara)" @@ -429,10 +538,18 @@ msgid "List currently attached DFU capable devices" msgstr "Lista aktuella anslutna DFU-kapabla enheter" +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "Lista uppdateringar för fast programvara som stöds" + #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "Läser in…" +#. TRANSLATORS: command line option +msgid "Manually whitelist specific plugins" +msgstr "Vitlista manuellt specifika insticksmoduler" + #. TRANSLATORS: command description msgid "Merge multiple firmware files into one" msgstr "Sammanfoga flera fasta programvaror till en" @@ -469,11 +586,18 @@ msgid "Name" msgstr "Namn" +msgid "No action specified!" +msgstr "Ingen åtgärd angiven!" + #. TRANSLATORS: nothing attached #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "Ingen uppdateringsbar hårdvara upptäcktes" +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "Inga insticksmoduler hittades" + #. TRANSLATORS: explain why no metadata available msgid "No remotes are currently enabled so no metadata is available." msgstr "Inga fjärrar är aktiverade för närvarande, så ingen metadata är tillgänglig." @@ -483,7 +607,11 @@ #. TRANSLATORS: command line option msgid "Override plugin warning" -msgstr "Åsidosätt tilläggsvarning" +msgstr "Åsidosätt insticksmodulvarning" + +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "Åsidosätt standardsökväg för ESP" #. TRANSLATORS: remote filename base msgid "Password" @@ -500,6 +628,12 @@ msgid "Please enter a number from 0 to %u: " msgstr "Ange en siffra mellan 0 och %u: " +msgid "Print the version number" +msgstr "Skriv ut versionsnumret" + +msgid "Print verbose debug statements" +msgstr "Skriv ut utförliga felsökningssatser" + #. TRANSLATORS: the numeric priority msgid "Priority" msgstr "Prioritet" @@ -511,6 +645,10 @@ msgid "Protocol" msgstr "Protokoll" +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "Fråga efter stöd för uppdatering av fast programvara" + #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" @@ -618,6 +756,10 @@ msgid "Set release version on firmware file" msgstr "Ange utgåveversion för den fasta programvarufilen" +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "Ställ in felsökningsflaggan under uppdatering" + #. TRANSLATORS: command description msgid "Set the firmware size for the target" msgstr "Ange fast programvarustorlek för målet" @@ -638,6 +780,10 @@ msgid "Show client and daemon versions" msgstr "Visa klient- och demon-version" +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information" +msgstr "Visa utförlig information om demon" + #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Visa felsökningsinformation för alla filer" @@ -647,17 +793,35 @@ msgstr "Visa felsökningsalternativ" #. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Visa enheter som inte kan uppdateras" + +#. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "Visa extra felsökningsinformation" #. TRANSLATORS: command description msgid "Show history of firmware updates" -msgstr "Visa historik över fasta programvaruupdateringar" +msgstr "Visa historik över fasta programvaruuppdateringar" #. TRANSLATORS: this is for plugin development msgid "Show plugin verbose information" msgstr "Visa utförlig information om insticksmodul" +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "Visa felsökningsloggen från det senaste uppdateringsförsöket" + +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "Visa information om uppdateringsstatus för fast programvara" + +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Ange Tillverkar-/Produkt-ID för DFU-enhet" + +msgid "Specify the number of bytes per USB transfer" +msgstr "Ange antalet byte per USB-överföring" + #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Tillstånd" @@ -675,11 +839,16 @@ msgid "Target" msgstr "Mål" -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "Fwupd-processen är en enkel demon som tillåter sessions-programvara att uppdatera enheters fasta programvara på din lokala maskin. Det är utformat för skrivbordsmiljöer, men detta projekt är också användbart på telefoner, surfplattor och skärmlösa servrar." +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "LVFS är en fri tjänst som fungerar som en oberoende juridisk person och har ingen koppling till $OS_RELEASE:NAME$. Din distributör kanske inte har bekräftat att någon av de fasta programvaruuppdateringarna är kompatibla med ditt system eller anslutna enheter. All fast programvara tillhandahålls endast av den ursprungliga tillverkaren av utrustning." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "Detta program kommer endast fungera korrekt som root" -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Detta projekt strävar efter att göra uppdatering av fast programvara på Linux automatisk, säker och pålitlig. Du kan antingen använda ett grafiskt användargränssnitt som GNOME Programvara för att granska och applicera uppdateringar, ett kommandoradsverktyg eller direkt mot D-Bus gränssnittet." +msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +msgstr "Denna fjärrkälla innehåller fast programvara som inte är under embargo, men fortfarande testas av hårdvarutillverkare. Du bör säkerställa att du har ett sätt att manuellt nedgradera den fasta programvaran om uppdateringen misslyckas." #. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" msgid "Title" @@ -693,6 +862,10 @@ msgid "Type" msgstr "Typ" +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "Verktyg för fast UEFI-programvara" + #. TRANSLATORS: section header for firmware URI msgid "URI" msgstr "URI" @@ -708,6 +881,10 @@ msgid "Unlocks the device for firmware access" msgstr "Låser upp enheten för fast programvaruåtkomst" +#. TRANSLATORS: command line option +msgid "Unset the debugging flag during update" +msgstr "Ta bort felsökningsflaggan under uppdatering" + #. TRANSLATORS: section header for firmware checksum msgid "Update Checksum" msgstr "Uppdateringskontrollsumma" @@ -716,6 +893,11 @@ msgid "Update Description" msgstr "Uppdateringsbeskrivning" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Uppdateringslängd" + #. TRANSLATORS: section header for firmware remote http:// msgid "Update Location" msgstr "Uppdateringsplats" @@ -736,9 +918,6 @@ msgid "Update Version" msgstr "Uppdateringsversion" -msgid "Update device firmware on Linux" -msgstr "Uppdatera enhetens fasta programvara på Linux" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "Misslyckad uppdatering är ett känt fel, besök denna url för mer information:" @@ -765,6 +944,11 @@ msgid "Updating %s from %s to %s... " msgstr "Uppdaterar %s från %s till %s... " +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Uppdaterar %s…" + #. TRANSLATORS: the server sent the user a small message msgid "Upload message:" msgstr "Uppladdningsmeddelande:" @@ -798,6 +982,10 @@ msgstr "Övervaka anslutna DFU-enheter" #. TRANSLATORS: command description +msgid "Watch for hardware changes" +msgstr "Övervaka hårdvaruändringar" + +#. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "Skriv fast programvara från fil till enhet" @@ -812,6 +1000,3 @@ #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Din distributör kanske inte har verifierat någon av uppdateringarna av fastprogramvara för kompatibilitet med ditt system eller anslutna enheter." - -msgid "fwupd" -msgstr "fwupd" diff -Nru fwupd-1.1.4/po/tr.po fwupd-1.2.5/po/tr.po --- fwupd-1.1.4/po/tr.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/tr.po 2019-02-25 09:42:18.000000000 +0000 @@ -8,8 +8,6 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Turkish (http://www.transifex.com/freedesktop/fwupd/language/tr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff -Nru fwupd-1.1.4/po/uk.po fwupd-1.2.5/po/uk.po --- fwupd-1.1.4/po/uk.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/uk.po 2019-02-25 09:42:18.000000000 +0000 @@ -3,13 +3,11 @@ # This file is distributed under the same license as the fwupd package. # # Translators: -# Yuri Chornoivan , 2015-2018 +# Yuri Chornoivan , 2015-2019 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Ukrainian (http://www.transifex.com/freedesktop/fwupd/language/uk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -31,6 +29,42 @@ msgid "%s has firmware updates:" msgstr "%s має такі оновлення мікропрограми:" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u день" +msgstr[1] "%u дні" +msgstr[2] "%u днів" +msgstr[3] "%u день" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u година" +msgstr[1] "%u години" +msgstr[2] "%u годин" +msgstr[3] "%u година" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u хвилина" +msgstr[1] "%u хвилини" +msgstr[2] "%u хвилин" +msgstr[3] "%u хвилина" + +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u секунда" +msgstr[1] "%u секунди" +msgstr[2] "%u секунд" +msgstr[3] "%u секунда" + #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Додано" @@ -56,10 +90,14 @@ msgid "Allow re-installing existing firmware versions" msgstr "Дозволити повторне встановлення наявних версій мікропрограми" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Для завершення оновлення слід перезавантажити систему." +#. TRANSLATORS: explain why we want to shutdown +msgid "An update requires the system to shutdown to complete." +msgstr "Для завершення оновлення систему слід вимкнути." + #. TRANSLATORS: command line option msgid "Answer yes to all questions" msgstr "Відповідати «так» на усі питання" @@ -267,6 +305,11 @@ msgid "Downgrading %s from %s to %s... " msgstr "Знижуємо версію %s з %s до %s... " +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Знижуємо версію %s…" + #. TRANSLATORS: downloading from a remote server msgid "Downloading…" msgstr "Отримуємо дані…" @@ -400,6 +443,9 @@ msgid "Firmware updates are supported on this machine." msgstr "На цьому комп'ютері передбачено підтримку оновлень мікропрограми." +msgid "Force the action ignoring all warnings" +msgstr "Виконати дію примусово, ігноруючи усі попередження" + #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Знайдено" @@ -478,12 +524,6 @@ msgid "Install unsigned system firmware" msgstr "Встановити непідписану мікропрограму системи" -#. show message in progressbar -#. TRANSLATORS: %1 is a device name -#, c-format -msgid "Installing %s" -msgstr "Встановлюємо %s" - #. TRANSLATORS: this is shown when updating the firmware after the reboot msgid "Installing firmware update…" msgstr "Встановлюємо оновлення мікропрограми…" @@ -600,6 +640,12 @@ msgid "Please enter a number from 0 to %u: " msgstr "Будь ласка, введіть число від 0 до %u: " +msgid "Print the version number" +msgstr "Вивести номер версії" + +msgid "Print verbose debug statements" +msgstr "Вивести докладні діагностичні повідомлення" + #. TRANSLATORS: the numeric priority msgid "Priority" msgstr "Пріоритетність" @@ -746,6 +792,10 @@ msgid "Show client and daemon versions" msgstr "Вивести дані щодо версій клієнат і фонової служби" +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information" +msgstr "Показати докладні відомості щодо фонової служби" + #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Показувати діагностичні дані для всіх файлів" @@ -778,6 +828,16 @@ msgid "Show the information of firmware update status" msgstr "Показати дані щодо стану оновлення мікропрограми" +#. TRANSLATORS: shutdown to apply the update +msgid "Shutdown now?" +msgstr "Вимкнути зараз?" + +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Вказати ідентифікатори виробника/продукту пристрою DFU" + +msgid "Specify the number of bytes per USB transfer" +msgstr "Вказати кількість байтів на один пакет передавання даних USB" + #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Стан" @@ -799,20 +859,10 @@ msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS є безкоштовною службою, яка працює як незалежна юридична одиниця і не має зв'язку з $OS_RELEASE:NAME$. Розробники вашої операційної системи, можливо, не перевіряли жодні з цих оновлень на сумісність із системою або з'єднаними із комп'ютером пристроями. Усі мікропрограми надаються лише самими виробниками обладнання." -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "Процес fwupd є простою фоновою службою, яка надає змогу оновлювати мікропрограми пристроїв на вашому локальному комп’ютері у межах сеансу користування. Програму розроблено для робочих станцій, але нею можна скористатися на телефонах, планшетах та серверах без дисплеїв." - -#. TRANSLATORS: exactly one update needs this -msgid "The update requires a reboot to complete." -msgstr "Для завершення оновлення потрібне перезавантаження." - #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "Програма зможе працювати належними чином лише від імені користувача root" -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Метою цього проекту є автоматизація оновлення мікропрограм обладнання у Linux, безпечно і надійно. Для перегляду і застосування оновлень ви можете скористатися або програмою для керування програмним забезпеченням, зокрема Програмними засобами GNOME, або інструментом командного рядка, або безпосередньо інтерфейсом D-Bus." - msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "У цьому сховищі міститься мікропрограма, встановлювати яку не заборонено, але яка усе ще перебуває у процесі тестування виробником обладнання. Вам слід переконатися, що ви зможете встановити стабільну версію мікропрограми, якщо процедура оновлення зазнає невдачі." @@ -859,6 +909,11 @@ msgid "Update Description" msgstr "Опис оновлення" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Тривалість оновлення" + #. TRANSLATORS: section header for firmware remote http:// msgid "Update Location" msgstr "Місце оновлення" @@ -879,8 +934,9 @@ msgid "Update Version" msgstr "Версія оновлення" -msgid "Update device firmware on Linux" -msgstr "Оновлення мікропрограм пристроїв у Linux" +#. TRANSLATORS: command description +msgid "Update all devices that match local metadata" +msgstr "Оновити усі пристрої, які відповідають локальним метаданим" #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" @@ -908,6 +964,11 @@ msgid "Updating %s from %s to %s... " msgstr "Оновлюємо %s з %s до %s... " +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Оновлюємо %s…" + #. TRANSLATORS: the server sent the user a small message msgid "Upload message:" msgstr "Повідомлення про вивантаження:" @@ -959,6 +1020,3 @@ #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Виробник вашого дистрибутива може не перевіряти усі оновлення мікропрограми на сумісність із вашою системою або з’єднаними із нею пристроями." - -msgid "fwupd" -msgstr "fwupd" diff -Nru fwupd-1.1.4/po/zh_CN.po fwupd-1.2.5/po/zh_CN.po --- fwupd-1.1.4/po/zh_CN.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/zh_CN.po 2019-02-25 09:42:18.000000000 +0000 @@ -12,8 +12,6 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Chinese (China) (http://www.transifex.com/freedesktop/fwupd/language/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -51,7 +49,7 @@ msgid "Allow re-installing existing firmware versions" msgstr "允许重新安装现有的固件版本" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "更新需要重启设备才能完成。" @@ -682,12 +680,6 @@ msgid "Target" msgstr "目标" -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "fwupd 的进程作为一个简单的守护程序,可以让会话软件更新您本地机器的设备固件。它为桌面环境设计,但该项目可以应用在手机、平板电脑和服务器上。" - -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "本项目的目标是让 Linux 上更新固件的流程变得自动化、安全又可靠。您既可以使用如 GNOME 软件这样的软件包管理器查看和应用更新,也可以直接使用命令行工具或者 D-Bus 接口。" - #. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" msgid "Title" msgstr "标题" @@ -743,9 +735,6 @@ msgid "Update Version" msgstr "更新版本" -msgid "Update device firmware on Linux" -msgstr "更新 Linux 上的设备固件" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "更新失败为已知问题,请访问此 URL 以获取详情:" @@ -819,6 +808,3 @@ #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "您的发行商可能尚未认证任何固件的系统及设备兼容性。" - -msgid "fwupd" -msgstr "fwupd" diff -Nru fwupd-1.1.4/po/zh_TW.po fwupd-1.2.5/po/zh_TW.po --- fwupd-1.1.4/po/zh_TW.po 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/po/zh_TW.po 2019-02-25 09:42:18.000000000 +0000 @@ -8,8 +8,6 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Chinese (Taiwan) (http://www.transifex.com/freedesktop/fwupd/language/zh_TW/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -53,7 +51,7 @@ msgid "Allow re-installing existing firmware versions" msgstr "允許重新安裝既有的韌體版本" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "有更新必須重新開機才能完成。" @@ -472,12 +470,6 @@ msgid "Install unsigned system firmware" msgstr "安裝未簽署的系統韌體" -#. show message in progressbar -#. TRANSLATORS: %1 is a device name -#, c-format -msgid "Installing %s" -msgstr "正安裝 %s" - #. TRANSLATORS: this is shown when updating the firmware after the reboot msgid "Installing firmware update…" msgstr "安裝韌體更新中…" @@ -793,20 +785,10 @@ msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS(Linux 廠商韌體服務,Linux Vendor Firmware Service)是由獨立法人運作的免費服務,而與 $OS_RELEASE:NAME$ 沒有關聯。您的系統散布商可能尚未驗證過任何韌體更新與您系統間或連接裝置上的相容性。所有本服務中的韌體僅由原始設備製造商提供。" -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "fwupd 程序是個簡易幕後程式,允許工作階段軟體更新您本地端機器上的裝置韌體。它主要設計給桌面電腦使用,但本專案也能用於手機、平板,或是指令列介面伺服器。" - -#. TRANSLATORS: exactly one update needs this -msgid "The update requires a reboot to complete." -msgstr "更新必須重新開機才能完成。" - #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "此程式僅有 root 身份才能正常運作" -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "本專案宗旨在於讓 Linux 上的韌體更新能自動、安全、可靠。您可以使用圖形介面的軟體管理員,如《GNOME 軟體》來檢視並套用更新,或用指令列工具,或甚至直接用 D-Bus 介面。" - msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "這個遠端站點包含未列入禁運,但仍處於硬體廠商測試階段的韌體。您應該確保自己在韌體更新失敗時有方法能夠手動降級韌體。" @@ -873,9 +855,6 @@ msgid "Update Version" msgstr "更新版本" -msgid "Update device firmware on Linux" -msgstr "在 Linux 上更新裝置韌體" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "更新失敗是已知議題,請造訪此 URL 瞭解更多資訊:" @@ -953,6 +932,3 @@ #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "您的系統散布商可能尚未驗證過任何韌體更新與您系統間或連接裝置上的相容性。" - -msgid "fwupd" -msgstr "fwupd" diff -Nru fwupd-1.1.4/README.md fwupd-1.2.5/README.md --- fwupd-1.1.4/README.md 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -3,6 +3,8 @@ [![Build Status](https://travis-ci.org/hughsie/fwupd.png?branch=master)](https://travis-ci.org/hughsie/fwupd) [![Coverity Scan Build Status](https://scan.coverity.com/projects/10744/badge.svg)](https://scan.coverity.com/projects/10744) +[![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-white.svg)](https://snapcraft.io/fwupd) + This project aims to make updating firmware on Linux automatic, safe and reliable. Additional information is available at the website: https://fwupd.org @@ -73,14 +75,19 @@ Other frontends ------------------- -Currently [GNOME Software](https://wiki.gnome.org/Apps/Software) is the only graphical -frontend available. When compiled with firmware support, it will check for updates -periodically and automatically download firmware in the background. - -After the firmware has been downloaded a popup will be displayed in Gnome Software -to perform the update. - -On Dell IoT gateways, [Wyse Cloud Client Manager (CCM)](http://www.dell.com/us/business/p/wyse-cloud-client-manager/pd) -has been built with fwupd support. -The remote administration interface can be used to download and deploy -firmware updates. + 1. [GNOME Software](https://wiki.gnome.org/Apps/Software) is the graphical + frontend available. When compiled with firmware support, it will check for + updates periodically and automatically download firmware in the background. + After the firmware has been downloaded a popup will be displayed in Gnome + Software to perform the update. + +2. [KDE Discover](https://userbase.kde.org/Discover) is the software centre, + generally bundled with KDE Plasma. With the release of + [KDE Plasma 5.14](https://www.kde.org/announcements/plasma-5.14.0.php), + a new fwupd backend has been implemented in KDE Discover for firmware updates. + These firmware updates are shown with other system updates. + +3. [Wyse Management Suite](https://www.dell.com/en-us/work/shop/wyse-endpoints-and-software/wyse-management-suite/spd/wyse-wms) + A software suite available on Dell IoT gateways and Wyse thin clients with built-in fwupd support. + The remote administration interface can be used to download and deploy firmware + updates. diff -Nru fwupd-1.1.4/RELEASE fwupd-1.2.5/RELEASE --- fwupd-1.1.4/RELEASE 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/RELEASE 2019-02-25 09:42:18.000000000 +0000 @@ -1,20 +1,23 @@ fwupd Release Notes -1. Write NEWS entries for fwupd in the same format as usual. +Write release entries: -git shortlog 1.1.3.. | grep -i -v trivial | grep -v Merge > NEWS.new - -Version 1.1.4 -~~~~~~~~~~~~~ -Released: 2018-xx-xx - -New Features: -Bugfixes: +git log --format="%s" --cherry-pick --right-only 1.2.4... | grep -i -v trivial | grep -v Merge | sort | uniq +Add any user visible changes into ../data/org.freedesktop.fwupd.metainfo.xml +appstream-util appdata-to-news ../data/org.freedesktop.fwupd.metainfo.xml > NEWS + +Update translations: + +ninja-build fwupd-pot +tx push --source +tx pull --all --force --minimum-perc=5 +../contrib/fix_translations.py ../po +git add ../po/*.po 2. Commit changes to git: -# MAKE SURE THESE ARE CORRECT -export release_ver="1.1.4" +# MAKE SURE THIS IS CORRECT +export release_ver="1.2.5" git commit -a -m "Release fwupd ${release_ver}" git tag -s -f -m "Release fwupd ${release_ver}" "${release_ver}" diff -Nru fwupd-1.1.4/snap/snapcraft.yaml fwupd-1.2.5/snap/snapcraft.yaml --- fwupd-1.1.4/snap/snapcraft.yaml 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/snap/snapcraft.yaml 2019-02-25 09:42:18.000000000 +0000 @@ -33,7 +33,7 @@ make-parameters: - prefix=/ - libdir=/lib - source: https://github.com/rhboot/efivar/releases/download/35/efivar-35.tar.bz2 + source: https://github.com/rhboot/efivar/releases/download/37/efivar-37.tar.bz2 build-packages: - libpopt-dev prime: @@ -68,7 +68,7 @@ - -lib/*.a meson: plugin: python - source: https://github.com/mesonbuild/meson/releases/download/0.46.1/meson-0.46.1.tar.gz + source: https://github.com/mesonbuild/meson/releases/download/0.47.2/meson-0.47.2.tar.gz build-packages: - ninja-build prime: @@ -77,53 +77,6 @@ - -lib - -share - -usr - appstream-glib-dev: - plugin: meson - meson-parameters: [--prefix=/usr, -Dgtk-doc=false, -Dintrospection=false, -Dman=false, -Drpm=false] - source: https://github.com/hughsie/appstream-glib/archive/appstream_glib_0_7_9.tar.gz - build-packages: - - python3-pip - - gperf - - intltool - - libarchive-dev - - libgcab-dev - - libgdk-pixbuf2.0-dev - - libgirepository1.0-dev - - libglib2.0-dev - - libgtk-3-dev - - libjson-glib-dev - - libsoup2.4-dev - - libsqlite3-dev - - libyaml-dev - - libstemmer-dev - - uuid-dev - stage-packages: - - libarchive13 - - libgcab-1.0-0 - - libsoup2.4-1 - - libstemmer0d - - libgdk-pixbuf2.0-0 - prime: - - -usr/bin - - -usr/include - - -usr/share/doc - - -usr/lib/*/asb-plugins-5 - - -usr/share/bash-completion - - -usr/share/aclocal - - -usr/lib/*/pkgconfig - - -usr/share/installed-tests - - -usr/lib/systemd - - -usr/lib/glib-networking - - -usr/lib/dconf - - -usr/share/X11 - - -usr/share/GConf - - -usr/share/dbus-1 - - -usr/share/glib-2.0/schemas - - -usr/share/lintian - - -usr/share/man - - -usr/lib/*/gdk-pixbuf-2.0 - - -usr/share/gettext - after: [meson] gudev: plugin: autotools source: https://github.com/GNOME/libgudev/archive/232.tar.gz @@ -233,6 +186,8 @@ -Dintrospection=false, -Dman=false, -Dudevdir=$SNAPCRAFT_STAGE/lib/udev, + "-Dlibxmlb:gtkdoc=false", + "-Dlibxmlb:introspection=false", -Dpkcs7=false] source: . source-type: git @@ -305,7 +260,7 @@ - -usr/share/gir-1.0 - -usr/share/upstart - -usr/lib/*/pkgconfig - after: [appstream-glib-dev, gudev, gusb, gnu-efi, libefivar-fixpkgconfig, libsmbios, build-introspection, gettext] + after: [gudev, gusb, gnu-efi, libefivar-fixpkgconfig, libsmbios, build-introspection, gettext] fix-bash-completion: plugin: make source: contrib/snap/fix-bash-completion diff -Nru fwupd-1.1.4/src/fu-archive.c fwupd-1.2.5/src/fu-archive.c --- fwupd-1.1.4/src/fu-archive.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/src/fu-archive.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuArchive" + +#include "config.h" + +#include +#include +#include + +#include "fu-archive.h" + +/** + * SECTION:fu-archive + * @title: FuArchive + * @short_description: an in-memory archive decompressor + */ + +struct _FuArchive { + GObject parent_instance; + GHashTable *entries; +}; + +G_DEFINE_TYPE (FuArchive, fu_archive, G_TYPE_OBJECT) + +static void +fu_archive_finalize (GObject *obj) +{ + FuArchive *self = FU_ARCHIVE (obj); + + g_hash_table_unref (self->entries); + G_OBJECT_CLASS (fu_archive_parent_class)->finalize (obj); +} + +static void +fu_archive_class_init (FuArchiveClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_archive_finalize; +} + +static void +fu_archive_init (FuArchive *self) +{ + self->entries = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, (GDestroyNotify) g_bytes_unref); +} + +/** + * fu_archive_lookup_by_fn: + * @self: A #FuArchive + * @fn: A filename + * @error: A #GError, or %NULL + * + * Finds the blob referenced by filename + * + * Returns: (transfer none): a #GBytes, or %NULL if the filename was not found + **/ +GBytes * +fu_archive_lookup_by_fn (FuArchive *self, const gchar *fn, GError **error) +{ + GBytes *fw; + + g_return_val_if_fail (FU_IS_ARCHIVE (self), NULL); + g_return_val_if_fail (fn != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + fw = g_hash_table_lookup (self->entries, fn); + if (fw == NULL) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "no blob for %s", fn); + } + return fw; +} + +/** + * fu_archive_iterate: + * @self: A #FuArchive + * @callback: A #FuArchiveIterateFunc. + * @user_data: User data. + * + * Iterates over the archive contents, calling the given function for each + * of the files found. + */ +void +fu_archive_iterate (FuArchive *self, FuArchiveIterateFunc callback, gpointer user_data) +{ + GHashTableIter iter; + gpointer key, value; + + g_return_if_fail (FU_IS_ARCHIVE (self)); + g_return_if_fail (callback != NULL); + + g_hash_table_iter_init (&iter, self->entries); + while (g_hash_table_iter_next (&iter, &key, &value)) + callback (self, (const gchar *)key, (GBytes *)value, user_data); +} + +/* workaround the struct types of libarchive */ +typedef struct archive _archive_read_ctx; + +static void +_archive_read_ctx_free (_archive_read_ctx *arch) +{ + archive_read_close (arch); + archive_read_free (arch); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(_archive_read_ctx, _archive_read_ctx_free) + +static gboolean +fu_archive_load (FuArchive *self, GBytes *blob, FuArchiveFlags flags, GError **error) +{ + int r; + g_autoptr(_archive_read_ctx) arch = NULL; + + /* decompress anything matching either glob */ + arch = archive_read_new (); + if (arch == NULL) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "libarchive startup failed"); + return FALSE; + } + archive_read_support_format_all (arch); + archive_read_support_filter_all (arch); + r = archive_read_open_memory (arch, + (void *) g_bytes_get_data (blob, NULL), + (size_t) g_bytes_get_size (blob)); + if (r != 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "cannot open: %s", + archive_error_string (arch)); + return FALSE; + } + while (TRUE) { + const gchar *fn; + gint64 bufsz; + gssize rc; + struct archive_entry *entry; + g_autofree gchar *fn_key = NULL; + g_autofree guint8 *buf = NULL; + + r = archive_read_next_header (arch, &entry); + if (r == ARCHIVE_EOF) + break; + if (r != ARCHIVE_OK) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "cannot read header: %s", + archive_error_string (arch)); + return FALSE; + } + + /* only extract if valid */ + fn = archive_entry_pathname (entry); + if (fn == NULL) + continue; + bufsz = archive_entry_size (entry); + if (bufsz > 1024 * 1024 * 1024) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "cannot read huge files"); + return FALSE; + } + buf = g_malloc (bufsz); + rc = archive_read_data (arch, buf, (gsize) bufsz); + if (rc < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "cannot read data: %s", + archive_error_string (arch)); + return FALSE; + } + if (rc != bufsz) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "read %" G_GSSIZE_FORMAT " of %" G_GINT64_FORMAT, + rc, bufsz); + return FALSE; + } + if (flags & FU_ARCHIVE_FLAG_IGNORE_PATH) { + fn_key = g_path_get_basename (fn); + } else { + fn_key = g_strdup (fn); + } + g_debug ("adding %s [%" G_GINT64_FORMAT "]", fn_key, bufsz); + g_hash_table_insert (self->entries, + g_steal_pointer (&fn_key), + g_bytes_new_take (g_steal_pointer (&buf), bufsz)); + } + + /* success */ + return TRUE; +} + +/** + * fu_archive_new: + * @data: A #GBytes + * @flags: A #FuArchiveFlags, e.g. %FU_ARCHIVE_FLAG_NONE + * @error: A #GError, or %NULL + * + * Parses @data as an archive and decompresses all files to memory blobs. + * + * Returns: a #FuArchive, or %NULL if the archive was invalid in any way. + **/ +FuArchive * +fu_archive_new (GBytes *data, FuArchiveFlags flags, GError **error) +{ + g_autoptr(FuArchive) self = g_object_new (FU_TYPE_ARCHIVE, NULL); + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + if (!fu_archive_load (self, data, flags, error)) + return NULL; + return g_steal_pointer (&self); +} diff -Nru fwupd-1.1.4/src/fu-archive.h fwupd-1.2.5/src/fu-archive.h --- fwupd-1.1.4/src/fu-archive.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/src/fu-archive.h 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define FU_TYPE_ARCHIVE (fu_archive_get_type ()) + +G_DECLARE_FINAL_TYPE (FuArchive, fu_archive, FU, ARCHIVE, GObject) + +/** + * FwupdError: + * @FU_ARCHIVE_FLAG_NONE: No flags set + * @FU_ARCHIVE_FLAG_IGNORE_PATH: Ignore any path component + * + * The flags to use when loading the archive. + **/ +typedef enum { + FU_ARCHIVE_FLAG_NONE = 0, + FU_ARCHIVE_FLAG_IGNORE_PATH = 1 << 0, + /*< private >*/ + FU_ARCHIVE_FLAG_LAST +} FuArchiveFlags; + +/** + * FuArchiveIterateFunc: + * @self: A #FuArchive. + * @filename: A filename. + * @blob: The blob referenced by @filename. + * @user_data: User data. + * + * Specifies the type of archive iteration function. + */ +typedef void (*FuArchiveIterateFunc) (FuArchive *self, + const gchar *filename, + GBytes *bytes, + gpointer user_data); + +FuArchive *fu_archive_new (GBytes *data, + FuArchiveFlags flags, + GError **error); +GBytes *fu_archive_lookup_by_fn (FuArchive *self, + const gchar *fn, + GError **error); +void fu_archive_iterate (FuArchive *self, + FuArchiveIterateFunc callback, + gpointer user_data); + +G_END_DECLS diff -Nru fwupd-1.1.4/src/fu-chunk.h fwupd-1.2.5/src/fu-chunk.h --- fwupd-1.1.4/src/fu-chunk.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-chunk.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_CHUNK_H -#define __FU_CHUNK_H +#pragma once #include #include @@ -39,5 +38,3 @@ guint32 packet_sz); G_END_DECLS - -#endif /* __FU_CHUNK_H */ diff -Nru fwupd-1.1.4/src/fu-common.c fwupd-1.2.5/src/fu-common.c --- fwupd-1.1.4/src/fu-common.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-common.c 2019-02-25 09:42:18.000000000 +0000 @@ -928,6 +928,12 @@ if (tmp != NULL) return g_strdup (tmp); return g_strdup ("/sys/firmware"); + /* /sys/firmware */ + case FU_PATH_KIND_SYSFSDIR_TPM: + tmp = g_getenv ("FWUPD_SYSFSTPMDIR"); + if (tmp != NULL) + return g_strdup (tmp); + return g_strdup ("/sys/class/tpm"); /* /sys/bus/platform/drivers */ case FU_PATH_KIND_SYSFSDIR_DRIVERS: tmp = g_getenv ("FWUPD_SYSFSDRIVERDIR"); @@ -993,3 +999,217 @@ return NULL; } + +/** + * fu_common_string_replace: + * @string: The #GString to operate on + * @search: The text to search for + * @replace: The text to use for substitutions + * + * Performs multiple search and replace operations on the given string. + * + * Returns: the number of replacements done, or 0 if @search is not found. + * + * Since: 1.2.0 + **/ +guint +fu_common_string_replace (GString *string, const gchar *search, const gchar *replace) +{ + gchar *tmp; + guint count = 0; + gsize search_idx = 0; + gsize replace_len; + gsize search_len; + + g_return_val_if_fail (string != NULL, 0); + g_return_val_if_fail (search != NULL, 0); + g_return_val_if_fail (replace != NULL, 0); + + /* nothing to do */ + if (string->len == 0) + return 0; + + search_len = strlen (search); + replace_len = strlen (replace); + + do { + tmp = g_strstr_len (string->str + search_idx, -1, search); + if (tmp == NULL) + break; + + /* advance the counter in case @replace contains @search */ + search_idx = (gsize) (tmp - string->str); + + /* reallocate the string if required */ + if (search_len > replace_len) { + g_string_erase (string, + (gssize) search_idx, + (gssize) (search_len - replace_len)); + memcpy (tmp, replace, replace_len); + } else if (search_len < replace_len) { + g_string_insert_len (string, + (gssize) search_idx, + replace, + (gssize) (replace_len - search_len)); + /* we have to treat this specially as it could have + * been reallocated when the insertion happened */ + memcpy (string->str + search_idx, replace, replace_len); + } else { + /* just memcmp in the new string */ + memcpy (tmp, replace, replace_len); + } + search_idx += replace_len; + count++; + } while (TRUE); + + return count; +} + +/** + * fu_common_dump_full: + * @log_domain: log domain, typically %G_LOG_DOMAIN or %NULL + * @title: prefix title, or %NULL + * @data: buffer to print + * @len: the size of @data + * @columns: break new lines after this many bytes + * @flags: some #FuDumpFlags, e.g. %FU_DUMP_FLAGS_SHOW_ASCII + * + * Dumps a raw buffer to the screen. + * + * Since: 1.2.4 + **/ +void +fu_common_dump_full (const gchar *log_domain, + const gchar *title, + const guint8 *data, + gsize len, + guint columns, + FuDumpFlags flags) +{ + g_autoptr(GString) str = g_string_new (NULL); + + /* optional */ + if (title != NULL) + g_string_append_printf (str, "%s:", title); + + /* if more than can fit on one line then start afresh */ + if (len > columns || flags & FU_DUMP_FLAGS_SHOW_ADDRESSES) { + g_string_append (str, "\n"); + } else { + for (gsize i = str->len; i < 16; i++) + g_string_append (str, " "); + } + + /* offset line */ + if (flags & FU_DUMP_FLAGS_SHOW_ADDRESSES) { + g_string_append (str, " │ "); + for (gsize i = 0; i < columns; i++) + g_string_append_printf (str, "%02x ", (guint) i); + g_string_append (str, "\n───────┼"); + for (gsize i = 0; i < columns; i++) + g_string_append (str, "───"); + g_string_append_printf (str, "\n0x%04x │ ", (guint) 0); + } + + /* print each row */ + for (gsize i = 0; i < len; i++) { + g_string_append_printf (str, "%02x ", data[i]); + + /* optionally print ASCII char */ + if (flags & FU_DUMP_FLAGS_SHOW_ASCII) { + if (g_ascii_isprint (data[i])) + g_string_append_printf (str, "[%c] ", data[i]); + else + g_string_append (str, "[?] "); + } + + /* new row required */ + if (i > 0 && i != len - 1 && (i + 1) % columns == 0) { + g_string_append (str, "\n"); + if (flags & FU_DUMP_FLAGS_SHOW_ADDRESSES) + g_string_append_printf (str, "0x%04x │ ", (guint) i + 1); + } + } + g_log (log_domain, G_LOG_LEVEL_DEBUG, "%s", str->str); +} + +/** + * fu_common_dump_raw: + * @log_domain: log domain, typically %G_LOG_DOMAIN or %NULL + * @title: prefix title, or %NULL + * @data: buffer to print + * @len: the size of @data + * + * Dumps a raw buffer to the screen. + * + * Since: 1.2.2 + **/ +void +fu_common_dump_raw (const gchar *log_domain, + const gchar *title, + const guint8 *data, + gsize len) +{ + FuDumpFlags flags = FU_DUMP_FLAGS_NONE; + if (len > 64) + flags |= FU_DUMP_FLAGS_SHOW_ADDRESSES; + fu_common_dump_full (log_domain, title, data, len, 32, flags); +} + +/** + * fu_common_dump_raw: + * @log_domain: log domain, typically %G_LOG_DOMAIN or %NULL + * @title: prefix title, or %NULL + * @bytes: a #GBytes + * + * Dumps a byte buffer to the screen. + * + * Since: 1.2.2 + **/ +void +fu_common_dump_bytes (const gchar *log_domain, + const gchar *title, + GBytes *bytes) +{ + gsize len = 0; + const guint8 *data = g_bytes_get_data (bytes, &len); + fu_common_dump_raw (log_domain, title, data, len); +} + +/** + * fu_common_bytes_align: + * @bytes: a #GBytes + * @blksz: block size in bytes + * @padval: the byte used to pad the byte buffer + * + * Aligns a block of memory to @blksize using the @padval value; if + * the block is already aligned then the original @bytes is returned. + * + * Returns: (transfer full): a #GBytes, possibly @bytes + * + * Since: 1.2.4 + **/ +GBytes * +fu_common_bytes_align (GBytes *bytes, gsize blksz, gchar padval) +{ + const guint8 *data; + gsize sz; + + g_return_val_if_fail (bytes != NULL, NULL); + g_return_val_if_fail (blksz > 0, NULL); + + /* pad */ + data = g_bytes_get_data (bytes, &sz); + if (sz % blksz != 0) { + gsize sz_align = ((sz / blksz) + 1) * blksz; + guint8 *data_align = g_malloc (sz_align); + memcpy (data_align, data, sz); + memset (data_align + sz, padval, sz_align - sz); + g_debug ("aligning 0x%x bytes to 0x%x", + (guint) sz, (guint) sz_align); + return g_bytes_new_take (data_align, sz_align); + } + + /* perfectly aligned */ + return g_bytes_ref (bytes); +} diff -Nru fwupd-1.1.4/src/fu-common-cab.c fwupd-1.2.5/src/fu-common-cab.c --- fwupd-1.1.4/src/fu-common-cab.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-common-cab.c 2019-02-25 09:42:18.000000000 +0000 @@ -15,7 +15,9 @@ #include "fwupd-error.h" -#ifdef HAVE_GCAB_1_0 +#ifndef HAVE_GCAB_1_0 +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GCabCabinet, g_object_unref) +#endif static GCabFile * _gcab_cabinet_get_file_by_name (GCabCabinet *cabinet, const gchar *basename) @@ -23,50 +25,82 @@ GPtrArray *folders = gcab_cabinet_get_folders (cabinet); for (guint i = 0; i < folders->len; i++) { GCabFolder *cabfolder = GCAB_FOLDER (g_ptr_array_index (folders, i)); +#ifdef HAVE_GCAB_1_0 GCabFile *cabfile = gcab_folder_get_file_by_name (cabfolder, basename); if (cabfile != NULL) return cabfile; +#else + g_autoptr(GSList) files = gcab_folder_get_files (cabfolder); + for (GSList *l = files; l != NULL; l = l->next) { + GCabFile *cabfile = GCAB_FILE (l->data); + if (g_strcmp0 (gcab_file_get_extract_name (cabfile), basename) == 0) + return cabfile; + } +#endif } return NULL; } -/* sets the firmware and signature blobs on AsRelease */ +#ifndef HAVE_GCAB_1_0 +static GBytes * +_gcab_file_get_bytes (GCabFile *cabfile) +{ + GBytes *blob = NULL; + g_autofree gchar *fn = NULL; + g_autoptr(GError) error_local = NULL; + + fn = g_build_filename (g_object_get_data (G_OBJECT (cabfile), + "fwupd::DecompressPath"), + gcab_file_get_extract_name (cabfile), + NULL); + blob = fu_common_get_contents_bytes (fn, &error_local); + if (blob == NULL) { + g_warning ("failed to read temp file: %s", error_local->message); + return NULL; + } + return blob; +} +#endif + +/* sets the firmware and signature blobs on XbNode */ static gboolean -fu_common_store_from_cab_release (AsRelease *release, GCabCabinet *cabinet, GError **error) +fu_common_store_from_cab_release (XbNode *release, GCabCabinet *cabinet, GError **error) { - AsChecksum *csum_tmp; GCabFile *cabfile; GBytes *blob; - guint64 size; - g_autofree gchar *basename = NULL; - g_autofree gchar *checksum = NULL; + const gchar *csum_filename = NULL; const gchar *suffixes[] = { "asc", "p7b", "p7c", NULL }; + g_autofree gchar *basename = NULL; + g_autofree gchar *release_key = NULL; + g_autoptr(XbNode) csum_tmp = NULL; + g_autoptr(XbNode) nsize = NULL; /* ensure we always have a content checksum */ - csum_tmp = as_release_get_checksum_by_target (release, AS_CHECKSUM_TARGET_CONTENT); - if (csum_tmp == NULL) { - g_autoptr(AsChecksum) csum = as_checksum_new (); - as_checksum_set_target (csum, AS_CHECKSUM_TARGET_CONTENT); - /* if this isn't true, a firmware needs to set in - * the metainfo.xml file something like: - * */ - as_checksum_set_filename (csum, "firmware.bin"); - as_release_add_checksum (release, csum); - csum_tmp = csum; - } + csum_tmp = xb_node_query_first (release, "checksum[@target='content']", NULL); + if (csum_tmp != NULL) + csum_filename = xb_node_get_attr (csum_tmp, "filename"); + + /* if this isn't true, a firmware needs to set in the metainfo.xml file + * something like: */ + if (csum_filename == NULL) + csum_filename = "firmware.bin"; /* get the main firmware file */ - basename = g_path_get_basename (as_checksum_get_filename (csum_tmp)); + basename = g_path_get_basename (csum_filename); cabfile = _gcab_cabinet_get_file_by_name (cabinet, basename); if (cabfile == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "cannot find %s in archive", - as_checksum_get_filename (csum_tmp)); + basename); return FALSE; } +#ifdef HAVE_GCAB_1_0 blob = gcab_file_get_bytes (cabfile); +#else + blob = _gcab_file_get_bytes (cabfile); +#endif if (blob == NULL) { g_set_error_literal (error, FWUPD_ERROR, @@ -76,35 +110,41 @@ } /* set the blob */ - as_release_set_blob (release, basename, blob); + release_key = g_strdup_printf ("fwupd::ReleaseBlob(%s)", basename); + xb_node_set_data (release, release_key, blob); - /* set if unspecified, but error out if specified and incorrect */ - size = as_release_get_size (release, AS_SIZE_KIND_INSTALLED); - if (size == 0) { - as_release_set_size (release, AS_SIZE_KIND_INSTALLED, - g_bytes_get_size (blob)); - } else if (size != g_bytes_get_size (blob)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "contents size invalid, expected " - "%" G_GSIZE_FORMAT ", got %" G_GUINT64_FORMAT, - g_bytes_get_size (blob), size); - return FALSE; + /* set as metadata if unset, but error if specified and incorrect */ + nsize = xb_node_query_first (release, "size[@type='installed']", NULL); + if (nsize != NULL) { + guint64 size = fu_common_strtoull (xb_node_get_text (nsize)); + if (size != g_bytes_get_size (blob)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "contents size invalid, expected " + "%" G_GSIZE_FORMAT ", got %" G_GUINT64_FORMAT, + g_bytes_get_size (blob), size); + return FALSE; + } + } else { + guint64 size = g_bytes_get_size (blob); + g_autoptr(GBytes) blob_sz = g_bytes_new (&size, sizeof(guint64)); + xb_node_set_data (release, "fwupd::ReleaseSize", blob_sz); } /* set if unspecified, but error out if specified and incorrect */ - checksum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, blob); - if (as_checksum_get_value (csum_tmp) == NULL) { - as_checksum_set_value (csum_tmp, checksum); - } else if (g_strcmp0 (checksum, as_checksum_get_value (csum_tmp)) != 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "contents checksum invalid, expected %s, got %s", - checksum, - as_checksum_get_value (csum_tmp)); - return FALSE; + if (csum_tmp != NULL && xb_node_get_text (csum_tmp) != NULL) { + g_autofree gchar *checksum = NULL; + checksum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, blob); + if (g_strcmp0 (checksum, xb_node_get_text (csum_tmp)) != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "contents checksum invalid, expected %s, got %s", + checksum, + xb_node_get_text (csum_tmp)); + return FALSE; + } } /* if the signing file exists, set that too */ @@ -113,7 +153,12 @@ basename_sig = g_strdup_printf ("%s.%s", basename, suffixes[i]); cabfile = _gcab_cabinet_get_file_by_name (cabinet, basename_sig); if (cabfile != NULL) { + g_autofree gchar *release_key_sig = NULL; +#ifdef HAVE_GCAB_1_0 blob = gcab_file_get_bytes (cabfile); +#else + blob = _gcab_file_get_bytes (cabfile); +#endif if (blob == NULL) { g_set_error (error, FWUPD_ERROR, @@ -122,7 +167,9 @@ basename_sig); return FALSE; } - as_release_set_blob (release, basename_sig, blob); + release_key_sig = g_strdup_printf ("fwupd::ReleaseBlob(%s)", + basename_sig); + xb_node_set_data (release, release_key_sig, blob); } } @@ -130,22 +177,24 @@ return TRUE; } -/* adds each GCabFile to the store */ +/* adds each GCabFile to the silo */ static gboolean -fu_common_store_from_cab_file (AsStore *store, GCabCabinet *cabinet, +fu_common_store_from_cab_file (XbBuilder *builder, GCabCabinet *cabinet, GCabFile *cabfile, GError **error) { GBytes *blob; - GPtrArray *releases; - g_autoptr(AsApp) app = NULL; g_autoptr(GError) error_local = NULL; -#if !AS_CHECK_VERSION(0,7,5) - g_autofree gchar *cache_fn = NULL; - g_autofree gchar *cachedir = NULL; -#endif + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + + /* rewrite to be under a components root */ + xb_builder_source_set_prefix (source, "components"); /* parse file */ +#ifdef HAVE_GCAB_1_0 blob = gcab_file_get_bytes (cabfile); +#else + blob = _gcab_file_get_bytes (cabfile); +#endif if (blob == NULL) { g_set_error_literal (error, FWUPD_ERROR, @@ -153,9 +202,10 @@ "no GBytes from GCabFile"); return FALSE; } - app = as_app_new (); -#if AS_CHECK_VERSION(0,7,5) - if (!as_app_parse_data (app, blob, AS_APP_PARSE_FLAG_NONE, &error_local)) { + if (!xb_builder_source_load_xml (source, + g_bytes_get_data (blob, NULL), + XB_BUILDER_SOURCE_FLAG_NONE, + &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, @@ -163,54 +213,15 @@ error_local->message); return FALSE; } -#else - cachedir = fu_common_get_path (FU_PATH_KIND_CACHEDIR_PKG); - cache_fn = g_build_filename (cachedir, gcab_file_get_extract_name (cabfile), NULL); - if (!fu_common_mkdir_parent (cache_fn, error)) - return FALSE; - if (!g_file_set_contents (cache_fn, g_bytes_get_data (blob, NULL), - g_bytes_get_size (blob), &error_local)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_WRITE, - "could not save temporary MetaInfo XML to %s: %s", - cache_fn, error_local->message); - return FALSE; - } - if (!as_app_parse_file (app, cache_fn, AS_APP_PARSE_FLAG_NONE, &error_local)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "could not parse MetaInfo XML: %s", - error_local->message); - return FALSE; - } -#endif - - /* process each listed release */ - releases = as_app_get_releases (app); - if (releases->len == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "no releases in metainfo file"); - return FALSE; - } - for (guint i = 0; i < releases->len; i++) { - AsRelease *release = g_ptr_array_index (releases, i); - g_debug ("processing release: %s", as_release_get_version (release)); - if (!fu_common_store_from_cab_release (release, cabinet, error)) - return FALSE; - } + xb_builder_import_source (builder, source); /* success */ - as_store_add_app (store, app); return TRUE; } -/* adds each GCabFolder to the store */ +/* adds each GCabFolder to the silo */ static gboolean -fu_common_store_from_cab_folder (AsStore *store, GCabCabinet *cabinet, +fu_common_store_from_cab_folder (XbBuilder *builder, GCabCabinet *cabinet, GCabFolder *cabfolder, GError **error) { g_autoptr(GSList) cabfiles = gcab_folder_get_files (cabfolder); @@ -218,8 +229,8 @@ GCabFile *cabfile = GCAB_FILE (l->data); const gchar *fn = gcab_file_get_extract_name (cabfile); g_debug ("processing file: %s", fn); - if (as_format_guess_kind (fn) == AS_FORMAT_KIND_METAINFO) { - if (!fu_common_store_from_cab_file (store, cabinet, cabfile, error)) { + if (g_str_has_suffix (fn, ".metainfo.xml")) { + if (!fu_common_store_from_cab_file (builder, cabinet, cabfile, error)) { g_prefix_error (error, "%s could not be loaded: ", gcab_file_get_extract_name (cabfile)); return FALSE; @@ -232,11 +243,12 @@ typedef struct { guint64 size_total; guint64 size_max; + const gchar *decompress_path; GError *error; } FuCommonCabHelper; static gboolean -as_cab_store_file_cb (GCabFile *file, gpointer user_data) +fu_common_store_file_cb (GCabFile *file, gpointer user_data) { FuCommonCabHelper *helper = (FuCommonCabHelper *) user_data; g_autofree gchar *basename = NULL; @@ -279,34 +291,135 @@ /* ignore the dirname completely */ basename = g_path_get_basename (name); gcab_file_set_extract_name (file, basename); + +#ifndef HAVE_GCAB_1_0 + /* set this for old versions of GCab */ + g_object_set_data_full (G_OBJECT (file), + "fwupd::DecompressPath", + g_strdup (helper->decompress_path), + g_free); +#endif + + return TRUE; +} + +static gint +fu_common_cab_sort_cb (XbBuilderNode *bn1, XbBuilderNode *bn2, gpointer user_data) +{ + guint64 prio1 = xb_builder_node_get_attr_as_uint (bn1, "priority"); + guint64 prio2 = xb_builder_node_get_attr_as_uint (bn2, "priority"); + if (prio1 > prio2) + return -1; + if (prio1 < prio2) + return 1; + return 0; +} + +static gboolean +fu_common_cab_sort_priority_cb (XbBuilderFixup *self, + XbBuilderNode *bn, + gpointer user_data, + GError **error) +{ + xb_builder_node_sort_children (bn, fu_common_cab_sort_cb, user_data); + return TRUE; +} + +static XbBuilderNode * +_xb_builder_node_get_child_by_element_attr (XbBuilderNode *bn, + const gchar *element, + const gchar *attr_name, + const gchar *attr_value) +{ + GPtrArray *bcs = xb_builder_node_get_children (bn); + for (guint i = 0; i < bcs->len; i++) { + XbBuilderNode *bc = g_ptr_array_index (bcs, i); + if (g_strcmp0 (xb_builder_node_get_element (bc), element) != 0) + continue; + if (g_strcmp0 (xb_builder_node_get_attr (bc, "type"), "container") == 0) + return g_object_ref (bc); + } + return NULL; +} + +static gboolean +fu_common_cab_set_container_checksum_cb (XbBuilderFixup *self, + XbBuilderNode *bn, + gpointer user_data, + GError **error) +{ + + const gchar *container_checksum = (const gchar *) user_data; + g_autoptr(XbBuilderNode) csum = NULL; + + /* not us */ + if (g_strcmp0 (xb_builder_node_get_element (bn), "release") != 0) + return TRUE; + + /* verify it exists */ + csum = _xb_builder_node_get_child_by_element_attr (bn, "checksum", + "target", "container"); + if (csum == NULL) { + csum = xb_builder_node_insert (bn, "checksum", + "target", "container", + NULL); + } + + /* verify it is correct */ + if (g_strcmp0 (xb_builder_node_get_text (csum), container_checksum) != 0) { + g_debug ("invalid container checksum %s, fixing up to %s", + xb_builder_node_get_text (csum), container_checksum); + xb_builder_node_set_text (csum, container_checksum, -1); + } return TRUE; } /** - * fu_common_store_from_cab_bytes: + * fu_common_cab_build_silo: * @blob: A readable blob * @size_max: The maximum size of the archive * @error: A #FuEndianType, e.g. %G_LITTLE_ENDIAN * - * Create an AppStream store from a cabinet archive. + * Create an AppStream silo from a cabinet archive. * - * Returns: a store, or %NULL on error + * Returns: a #XbSilo, or %NULL on error **/ -AsStore * -fu_common_store_from_cab_bytes (GBytes *blob, guint64 size_max, GError **error) +XbSilo * +fu_common_cab_build_silo (GBytes *blob, guint64 size_max, GError **error) { - FuCommonCabHelper helper = { 0 }; + FuCommonCabHelper helper = { + .size_total = 0, + .size_max = size_max, + .error = NULL, + }; GPtrArray *folders; - g_autoptr(AsStore) store = as_store_new (); + g_autofree gchar *container_checksum = NULL; +#ifndef HAVE_GCAB_1_0 + g_autofree gchar *tmp_path = NULL; + g_autoptr(GFile) tmp_file = NULL; +#endif + g_autoptr(XbSilo) silo = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); + g_autoptr(XbBuilderFixup) fixup = NULL; + g_autoptr(XbBuilderFixup) fixup2 = NULL; g_autoptr(GCabCabinet) cabinet = gcab_cabinet_new (); g_autoptr(GError) error_local = NULL; g_autoptr(GInputStream) ip = NULL; + g_autoptr(GPtrArray) components = NULL; + + /* sort the components by priority */ + fixup = xb_builder_fixup_new ("OrderByPriority", + fu_common_cab_sort_priority_cb, + NULL, NULL); + xb_builder_fixup_set_max_depth (fixup, 0); + xb_builder_add_fixup (builder, fixup); /* load from a seekable stream */ ip = g_memory_input_stream_new_from_bytes (blob); if (!gcab_cabinet_load (cabinet, ip, NULL, error)) return NULL; +#ifdef HAVE_GCAB_1_0 /* check the size is sane */ if (gcab_cabinet_get_size (cabinet) > size_max) { g_autofree gchar *sz_val = g_format_size (gcab_cabinet_get_size (cabinet)); @@ -320,9 +433,8 @@ } /* decompress the file to memory */ - helper.size_max = size_max; if (!gcab_cabinet_extract_simple (cabinet, NULL, - as_cab_store_file_cb, &helper, + fu_common_store_file_cb, &helper, NULL, &error_local)) { g_set_error_literal (error, FWUPD_ERROR, @@ -330,6 +442,29 @@ error_local->message); return NULL; } +#else + /* decompress to /tmp */ + tmp_path = g_dir_make_tmp ("fwupd-XXXXXX", &error_local); + if (tmp_path == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to create temp dir: %s", + error_local->message); + return NULL; + } + helper.decompress_path = tmp_path; + tmp_file = g_file_new_for_path (tmp_path); + if (!gcab_cabinet_extract_simple (cabinet, tmp_file, + fu_common_store_file_cb, &helper, + NULL, &error_local)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + error_local->message); + return NULL; + } +#endif /* the file callback set an error */ if (helper.error != NULL) { @@ -337,53 +472,65 @@ return NULL; } + /* verbose profiling */ + if (g_getenv ("FWUPD_VERBOSE") != NULL) { + xb_builder_set_profile_flags (builder, + XB_SILO_PROFILE_FLAG_XPATH | + XB_SILO_PROFILE_FLAG_DEBUG); + } + /* look at each folder */ folders = gcab_cabinet_get_folders (cabinet); for (guint i = 0; i < folders->len; i++) { GCabFolder *cabfolder = GCAB_FOLDER (g_ptr_array_index (folders, i)); g_debug ("processing folder: %u/%u", i + 1, folders->len); - if (!fu_common_store_from_cab_folder (store, cabinet, cabfolder, error)) + if (!fu_common_store_from_cab_folder (builder, cabinet, cabfolder, error)) return NULL; } - /* did we get any valid AsApps */ - if (as_store_get_size (store) == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "archive contained no valid metadata"); + /* ensure the container checksum is always set */ + container_checksum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, blob); + fixup2 = xb_builder_fixup_new ("SetContainerChecksum", + fu_common_cab_set_container_checksum_cb, + container_checksum, NULL); + xb_builder_add_fixup (builder, fixup2); + + /* did we get any valid files */ + silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_NONE, NULL, error); + if (silo == NULL) return NULL; - } - /* success */ - return g_steal_pointer (&store); -} - -#else - -AsStore * -fu_common_store_from_cab_bytes (GBytes *blob, guint64 size_max, GError **error) -{ - g_autoptr(AsStore) store = as_store_new (); - g_autoptr(GError) error_local = NULL; - - /* this is klunky as we have to write actual files to /tmp */ - if (!as_store_from_bytes (store, blob, NULL, &error_local)) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - error_local->message); + components = xb_silo_query (silo, "components/component", 0, &error_local); + if (components == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "archive contained no valid metadata: %s", + error_local->message); return NULL; } - /* did we get any valid AsApps */ - if (as_store_get_size (store) == 0) { - g_set_error_literal (error, + /* process each listed release */ + for (guint i = 0; i < components->len; i++) { + XbNode *component = g_ptr_array_index (components, i); + g_autoptr(GPtrArray) releases = NULL; + releases = xb_node_query (component, "releases/release", 0, &error_local); + if (releases == NULL) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "archive contained no valid metadata"); - return NULL; + "no releases in metainfo file: %s", + error_local->message); + return NULL; + } + for (guint j = 0; j < releases->len; j++) { + XbNode *rel = g_ptr_array_index (releases, j); + g_debug ("processing release: %s", xb_node_get_attr (rel, "version")); + if (!fu_common_store_from_cab_release (rel, cabinet, error)) + return NULL; + } } - return g_steal_pointer (&store); + + /* success */ + return g_steal_pointer (&silo); } -#endif diff -Nru fwupd-1.1.4/src/fu-common-cab.h fwupd-1.2.5/src/fu-common-cab.h --- fwupd-1.1.4/src/fu-common-cab.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-common-cab.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,13 +4,14 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_COMMON_CAB_H -#define __FU_COMMON_CAB_H +#pragma once -#include +#include -AsStore *fu_common_store_from_cab_bytes (GBytes *blob, +G_BEGIN_DECLS + +XbSilo *fu_common_cab_build_silo (GBytes *blob, guint64 size_max, GError **error); -#endif /* __FU_COMMON_CAB_H */ +G_END_DECLS diff -Nru fwupd-1.1.4/src/fu-common-guid.c fwupd-1.2.5/src/fu-common-guid.c --- fwupd-1.1.4/src/fu-common-guid.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/src/fu-common-guid.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuCommon" + +#include + +#include "fu-common-guid.h" + +/** + * fu_common_guid_is_plausible: + * @buf: a buffer of data + * + * Checks whether a chunk of memory looks like it could be a GUID. + * + * Returns: TRUE if it looks like a GUID, FALSE if not + * + * Since: 1.2.5 + **/ +gboolean +fu_common_guid_is_plausible (const guint8 *buf) +{ + guint guint_sum = 0; + + for (guint i = 0; i < 16; i++) + guint_sum += buf[i]; + if (guint_sum == 0x00) + return FALSE; + if (guint_sum < 0xff) + return FALSE; + return TRUE; +} diff -Nru fwupd-1.1.4/src/fu-common-guid.h fwupd-1.2.5/src/fu-common-guid.h --- fwupd-1.1.4/src/fu-common-guid.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/src/fu-common-guid.h 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +gboolean fu_common_guid_is_plausible (const guint8 *buf); + +G_END_DECLS diff -Nru fwupd-1.1.4/src/fu-common.h fwupd-1.2.5/src/fu-common.h --- fwupd-1.1.4/src/fu-common.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-common.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,11 +4,12 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_COMMON_H__ -#define __FU_COMMON_H__ +#pragma once #include +G_BEGIN_DECLS + typedef enum { FU_APP_FLAGS_NONE = 0, FU_APP_FLAGS_NO_IDLE_SOURCES = 1 << 0, @@ -16,6 +17,13 @@ } FuAppFlags; typedef enum { + FU_DUMP_FLAGS_NONE = 0, + FU_DUMP_FLAGS_SHOW_ASCII = 1 << 0, + FU_DUMP_FLAGS_SHOW_ADDRESSES = 1 << 1, + FU_DUMP_FLAGS_LAST +} FuDumpFlags; + +typedef enum { FU_PATH_KIND_CACHEDIR_PKG, FU_PATH_KIND_DATADIR_PKG, FU_PATH_KIND_EFIAPPDIR, @@ -26,6 +34,7 @@ FU_PATH_KIND_SYSCONFDIR_PKG, FU_PATH_KIND_SYSFSDIR_FW, FU_PATH_KIND_SYSFSDIR_DRIVERS, + FU_PATH_KIND_SYSFSDIR_TPM, FU_PATH_KIND_LAST } FuPathKind; @@ -65,6 +74,22 @@ gchar *fu_common_find_program_in_path (const gchar *basename, GError **error); gchar *fu_common_strstrip (const gchar *str); +void fu_common_dump_raw (const gchar *log_domain, + const gchar *title, + const guint8 *data, + gsize len); +void fu_common_dump_full (const gchar *log_domain, + const gchar *title, + const guint8 *data, + gsize len, + guint columns, + FuDumpFlags flags); +void fu_common_dump_bytes (const gchar *log_domain, + const gchar *title, + GBytes *bytes); +GBytes *fu_common_bytes_align (GBytes *bytes, + gsize blksz, + gchar padval); typedef guint FuEndianType; @@ -79,4 +104,8 @@ guint32 fu_common_read_uint32 (const guint8 *buf, FuEndianType endian); -#endif /* __FU_COMMON_H__ */ +guint fu_common_string_replace (GString *string, + const gchar *search, + const gchar *replace); + +G_END_DECLS diff -Nru fwupd-1.1.4/src/fu-common-version.c fwupd-1.2.5/src/fu-common-version.c --- fwupd-1.1.4/src/fu-common-version.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/src/fu-common-version.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,389 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuCommon" + +#include + +#include + +#include "fwupd-error.h" + +#include "fu-common-version.h" + +#define FU_COMMON_VERSION_DECODE_BCD(val) ((((val) >> 4) & 0x0f) * 10 + ((val) & 0x0f)) + +/** + * fu_common_version_format_from_string: + * @str: A string, e.g. `quad` + * + * Converts text to a display version type. + * + * Returns: A #FuVersionFormat, e.g. %FU_VERSION_FORMAT_TRIPLET + * + * Since: 1.2.0 + **/ +FuVersionFormat +fu_common_version_format_from_string (const gchar *str) +{ + if (g_strcmp0 (str, "triplet") == 0) + return FU_VERSION_FORMAT_TRIPLET; + if (g_strcmp0 (str, "quad") == 0) + return FU_VERSION_FORMAT_QUAD; + if (g_strcmp0 (str, "intel-me2") == 0) + return FU_VERSION_FORMAT_INTEL_ME2; + if (g_strcmp0 (str, "bcd") == 0) + return FU_VERSION_FORMAT_BCD; + if (g_strcmp0 (str, "plain") == 0) + return FU_VERSION_FORMAT_PLAIN; + if (g_strcmp0 (str, "intel-me") == 0) + return FU_VERSION_FORMAT_INTEL_ME; + return FU_VERSION_FORMAT_QUAD; +} + +/** + * fu_common_version_format_to_string: + * @str: A #FuVersionFormat, e.g. %FU_VERSION_FORMAT_TRIPLET + * + * Converts a display version type to text. + * + * Returns: A string, e.g. `quad`, or %NULL if not known + * + * Since: 1.2.0 + **/ +const gchar * +fu_common_version_format_to_string (FuVersionFormat kind) +{ + if (kind == FU_VERSION_FORMAT_TRIPLET) + return "triplet"; + if (kind == FU_VERSION_FORMAT_QUAD) + return "quad"; + if (kind == FU_VERSION_FORMAT_INTEL_ME2) + return "intel-me2"; + if (kind == FU_VERSION_FORMAT_BCD) + return "bcd"; + if (kind == FU_VERSION_FORMAT_PLAIN) + return "plain"; + if (kind == FU_VERSION_FORMAT_INTEL_ME) + return "intel-me"; + return NULL; +} + +/** + * fu_common_version_from_uint32: + * @val: A uint32le version number + * @kind: version kind used for formatting, e.g. %FU_VERSION_FORMAT_TRIPLET + * + * Returns a dotted decimal version string from a 32 bit number. + * + * Returns: A version number, e.g. "1.0.3", or %NULL if not supported + * + * Since: 1.2.0 + **/ +gchar * +fu_common_version_from_uint32 (guint32 val, FuVersionFormat kind) +{ + if (kind == FU_VERSION_FORMAT_QUAD) { + /* AA.BB.CC.DD */ + return g_strdup_printf ("%u.%u.%u.%u", + (val >> 24) & 0xff, + (val >> 16) & 0xff, + (val >> 8) & 0xff, + val & 0xff); + } + if (kind == FU_VERSION_FORMAT_TRIPLET) { + /* AA.BB.CCDD */ + return g_strdup_printf ("%u.%u.%u", + (val >> 24) & 0xff, + (val >> 16) & 0xff, + val & 0xffff); + } + if (kind == FU_VERSION_FORMAT_PAIR) { + /* AABB.CCDD */ + return g_strdup_printf ("%u.%u", + (val >> 16) & 0xffff, + val & 0xffff); + } + if (kind == FU_VERSION_FORMAT_PLAIN) { + /* AABBCCDD */ + return g_strdup_printf ("%" G_GUINT32_FORMAT, val); + } + if (kind == FU_VERSION_FORMAT_BCD) { + /* AA.BB.CC.DD, but BCD */ + return g_strdup_printf ("%u.%u.%u.%u", + FU_COMMON_VERSION_DECODE_BCD(val >> 24), + FU_COMMON_VERSION_DECODE_BCD(val >> 16), + FU_COMMON_VERSION_DECODE_BCD(val >> 8), + FU_COMMON_VERSION_DECODE_BCD(val)); + } + if (kind == FU_VERSION_FORMAT_INTEL_ME) { + /* aaa+11.bbbbb.cccccccc.dddddddddddddddd */ + return g_strdup_printf ("%u.%u.%u.%u", + ((val >> 29) & 0x07) + 0x0b, + (val >> 24) & 0x1f, + (val >> 16) & 0xff, + val & 0xffff); + } + if (kind == FU_VERSION_FORMAT_INTEL_ME2) { + /* A.B.CC.DDDD */ + return g_strdup_printf ("%u.%u.%u.%u", + (val >> 28) & 0x0f, + (val >> 24) & 0x0f, + (val >> 16) & 0xff, + val & 0xffff); + } + return NULL; +} + +/** + * fu_common_version_from_uint16: + * @val: A uint16le version number + * @kind: version kind used for formatting, e.g. %FU_VERSION_FORMAT_TRIPLET + * + * Returns a dotted decimal version string from a 16 bit number. + * + * Returns: A version number, e.g. "1.3", or %NULL if not supported + * + * Since: 1.2.0 + **/ +gchar * +fu_common_version_from_uint16 (guint16 val, FuVersionFormat kind) +{ + if (kind == FU_VERSION_FORMAT_BCD) { + return g_strdup_printf ("%i.%i", + FU_COMMON_VERSION_DECODE_BCD(val >> 8), + FU_COMMON_VERSION_DECODE_BCD(val)); + } + if (kind == FU_VERSION_FORMAT_PAIR) { + return g_strdup_printf ("%u.%u", + (guint) (val >> 8) & 0xff, + (guint) val & 0xff); + } + if (kind == FU_VERSION_FORMAT_PLAIN) { + return g_strdup_printf ("%" G_GUINT16_FORMAT, val); + } + return NULL; +} + +static gint +fu_common_vercmp_char (gchar chr1, gchar chr2) +{ + if (chr1 == chr2) + return 0; + if (chr1 == '~') + return -1; + if (chr2 == '~') + return 1; + return chr1 < chr2 ? -1 : 1; +} + +static gint +fu_common_vercmp_chunk (const gchar *str1, const gchar *str2) +{ + guint i; + + /* trivial */ + if (g_strcmp0 (str1, str2) == 0) + return 0; + if (str1 == NULL) + return 1; + if (str2 == NULL) + return -1; + + /* check each char of the chunk */ + for (i = 0; str1[i] != '\0' && str2[i] != '\0'; i++) { + gint rc = fu_common_vercmp_char (str1[i], str2[i]); + if (rc != 0) + return rc; + } + return fu_common_vercmp_char (str1[i], str2[i]); +} + +static gboolean +_g_ascii_is_digits (const gchar *str) +{ + g_return_val_if_fail (str != NULL, FALSE); + for (gsize i = 0; str[i] != '\0'; i++) { + if (!g_ascii_isdigit (str[i])) + return FALSE; + } + return TRUE; +} + +/** + * fu_common_version_parse: + * @version: A version number + * + * Returns a dotted decimal version string from a version string. The supported + * formats are: + * + * - Dotted decimal, e.g. "1.2.3" + * - Base 16, a hex number *with* a 0x prefix, e.g. "0x10203" + * - Base 10, a string containing just [0-9], e.g. "66051" + * - Date in YYYYMMDD format, e.g. 20150915 + * + * Anything with a '.' or that doesn't match [0-9] or 0x[a-f,0-9] is considered + * a string and returned without modification. + * + * Returns: A version number, e.g. "1.0.3" + * + * Since: 1.2.0 + */ +gchar * +fu_common_version_parse (const gchar *version) +{ + const gchar *version_noprefix = version; + gchar *endptr = NULL; + guint64 tmp; + guint base; + + /* already dotted decimal */ + if (g_strstr_len (version, -1, ".") != NULL) + return g_strdup (version); + + /* is a date */ + if (g_str_has_prefix (version, "20") && + strlen (version) == 8) + return g_strdup (version); + + /* convert 0x prefixed strings to dotted decimal */ + if (g_str_has_prefix (version, "0x")) { + version_noprefix += 2; + base = 16; + } else { + /* for non-numeric content, just return the string */ + if (!_g_ascii_is_digits (version)) + return g_strdup (version); + base = 10; + } + + /* convert */ + tmp = g_ascii_strtoull (version_noprefix, &endptr, base); + if (endptr != NULL && endptr[0] != '\0') + return g_strdup (version); + if (tmp == 0) + return g_strdup (version); + return fu_common_version_from_uint32 ((guint32) tmp, FU_VERSION_FORMAT_TRIPLET); +} + +/** + * fu_common_version_guess_format: + * @version: A version number, e.g. "1.2.3" + * + * Guesses the version format from the version number. This is only a heuristic + * and plugins and components should explicitly set the version format whenever + * possible. + * + * If the version format cannot be guessed with any degree of accuracy, the + * %FU_VERSION_FORMAT_UNKNOWN constant is returned. + * + * Returns: A #FuVersionFormat, e.g. %FU_VERSION_FORMAT_QUAD + * + * Since: 1.2.0 + */ +FuVersionFormat +fu_common_version_guess_format (const gchar *version) +{ + guint sz; + g_auto(GStrv) split = NULL; + + /* nothing to use */ + if (version == NULL || version[0] == '\0') + return FU_VERSION_FORMAT_UNKNOWN; + + /* no dots, assume just text */ + split = g_strsplit (version, ".", -1); + sz = g_strv_length (split); + if (sz == 1) + return FU_VERSION_FORMAT_PLAIN; + + /* check for only-digit semver version */ + for (guint i = 0; split[i] != NULL; i++) { + /* check sections are plain numbers */ + if (!_g_ascii_is_digits (split[i])) + return FU_VERSION_FORMAT_UNKNOWN; + } + + /* the most common formats */ + if (sz == 2) + return FU_VERSION_FORMAT_PAIR; + if (sz == 3) + return FU_VERSION_FORMAT_TRIPLET; + if (sz == 4) + return FU_VERSION_FORMAT_QUAD; + + /* unknown! */ + return FU_VERSION_FORMAT_UNKNOWN; +} + +/** + * fu_common_vercmp: + * @version_a: the release version, e.g. 1.2.3 + * @version_b: the release version, e.g. 1.2.3.1 + * + * Compares version numbers for sorting. + * + * Returns: -1 if a < b, +1 if a > b, 0 if they are equal, and %G_MAXINT on error + * + * Since: 0.3.5 + */ +gint +fu_common_vercmp (const gchar *version_a, const gchar *version_b) +{ + guint longest_split; + g_autofree gchar *str_a = NULL; + g_autofree gchar *str_b = NULL; + g_auto(GStrv) split_a = NULL; + g_auto(GStrv) split_b = NULL; + + /* sanity check */ + if (version_a == NULL || version_b == NULL) + return G_MAXINT; + + /* optimisation */ + if (g_strcmp0 (version_a, version_b) == 0) + return 0; + + /* split into sections, and try to parse */ + str_a = fu_common_version_parse (version_a); + str_b = fu_common_version_parse (version_b); + split_a = g_strsplit (str_a, ".", -1); + split_b = g_strsplit (str_b, ".", -1); + longest_split = MAX (g_strv_length (split_a), g_strv_length (split_b)); + for (guint i = 0; i < longest_split; i++) { + gchar *endptr_a = NULL; + gchar *endptr_b = NULL; + gint64 ver_a; + gint64 ver_b; + + /* we lost or gained a dot */ + if (split_a[i] == NULL) + return -1; + if (split_b[i] == NULL) + return 1; + + /* compare integers */ + ver_a = g_ascii_strtoll (split_a[i], &endptr_a, 10); + ver_b = g_ascii_strtoll (split_b[i], &endptr_b, 10); + if (ver_a < ver_b) + return -1; + if (ver_a > ver_b) + return 1; + + /* compare strings */ + if ((endptr_a != NULL && endptr_a[0] != '\0') || + (endptr_b != NULL && endptr_b[0] != '\0')) { + gint rc = fu_common_vercmp_chunk (endptr_a, endptr_b); + if (rc < 0) + return -1; + if (rc > 0) + return 1; + } + } + + /* we really shouldn't get here */ + return 0; +} diff -Nru fwupd-1.1.4/src/fu-common-version.h fwupd-1.2.5/src/fu-common-version.h --- fwupd-1.1.4/src/fu-common-version.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/src/fu-common-version.h 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +/** + * FuVersionFormat: + * @FU_VERSION_FORMAT_UNKNOWN: Unknown version format + * @FU_VERSION_FORMAT_PLAIN: Use plain integer version numbers + * @FU_VERSION_FORMAT_QUAD: Use Dell-style AA.BB.CC.DD version numbers + * @FU_VERSION_FORMAT_TRIPLET: Use Microsoft-style AA.BB.CCDD version numbers + * @FU_VERSION_FORMAT_PAIR: Use two AABB.CCDD version numbers + * @FU_VERSION_FORMAT_BCD: Use binary coded decimal notation + * @FU_VERSION_FORMAT_INTEL_ME: Use Intel ME-style bitshifted notation + * @FU_VERSION_FORMAT_INTEL_ME2: Use Intel ME-style A.B.CC.DDDD notation notation + * + * The flags used when parsing version numbers. + **/ +typedef enum { + FU_VERSION_FORMAT_UNKNOWN, /* Since: 1.2.0 */ + FU_VERSION_FORMAT_PLAIN, /* Since: 1.2.0 */ + FU_VERSION_FORMAT_QUAD, /* Since: 1.2.0 */ + FU_VERSION_FORMAT_TRIPLET, /* Since: 1.2.0 */ + FU_VERSION_FORMAT_PAIR, /* Since: 1.2.0 */ + FU_VERSION_FORMAT_BCD, /* Since: 1.2.0 */ + FU_VERSION_FORMAT_INTEL_ME, /* Since: 1.2.0 */ + FU_VERSION_FORMAT_INTEL_ME2, /* Since: 1.2.0 */ + /*< private >*/ + FU_VERSION_FORMAT_LAST +} FuVersionFormat; + +FuVersionFormat fu_common_version_format_from_string (const gchar *str); +const gchar *fu_common_version_format_to_string (FuVersionFormat kind); + +gint fu_common_vercmp (const gchar *version_a, + const gchar *version_b); +gchar *fu_common_version_from_uint32 (guint32 val, + FuVersionFormat flags); +gchar *fu_common_version_from_uint16 (guint16 val, + FuVersionFormat flags); +gchar *fu_common_version_parse (const gchar *version); +FuVersionFormat fu_common_version_guess_format (const gchar *version); + +G_END_DECLS diff -Nru fwupd-1.1.4/src/fu-config.c fwupd-1.2.5/src/fu-config.c --- fwupd-1.1.4/src/fu-config.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-config.c 2019-02-25 09:42:18.000000000 +0000 @@ -8,7 +8,7 @@ #include "config.h" -#include +#include #include #include #include @@ -31,7 +31,8 @@ GPtrArray *blacklist_devices; GPtrArray *blacklist_plugins; guint64 archive_size_max; - AsStore *store_remotes; + guint idle_timeout; + XbSilo *silo; GHashTable *os_release; }; @@ -132,70 +133,26 @@ } static GString * -fu_config_get_remote_agreement_for_app (FwupdRemote *self, AsApp *app, GError **error) +fu_config_get_remote_agreement_for_app (FwupdRemote *self, XbNode *component, GError **error) { -#if AS_CHECK_VERSION(0,7,8) - const gchar *tmp = NULL; - AsAgreement *agreement; - AsAgreementSection *section; - - /* get the default agreement section */ - agreement = as_app_get_agreement_default (app); - if (agreement == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No agreement found"); - return NULL; - } - section = as_agreement_get_section_default (agreement); - if (section == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No default section for agreement found"); - return NULL; - } - tmp = as_agreement_section_get_description (section, NULL); - if (tmp == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No description found in agreement section"); - return NULL; - } - return g_string_new (tmp); -#else - AsFormat *format; - GNode *n; - g_autoptr(AsNode) root = NULL; - g_autoptr(GFile) file = NULL; - - /* parse the XML file */ - format = as_app_get_format_default (app); - if (format == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No format for Metainfo file"); - return NULL; - } - file = g_file_new_for_path (as_format_get_filename (format)); - root = as_node_from_file (file, AS_NODE_FROM_XML_FLAG_NONE, NULL, error); - if (root == NULL) - return NULL; + XbNode *n; + g_autofree gchar *tmp = NULL; + g_autoptr(GError) error_local = NULL; /* manually find the first agreement section */ - n = as_node_find (root, "component/agreement/agreement_section/description"); + n = xb_node_query_first (component, "agreement/agreement_section/description/*", &error_local); if (n == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No agreement description found"); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "No agreement description found: %s", + error_local->message); return NULL; } - return as_node_to_xml (n->children, AS_NODE_TO_XML_FLAG_INCLUDE_SIBLINGS); -#endif + tmp = xb_node_export (n, XB_NODE_EXPORT_FLAG_INCLUDE_SIBLINGS, error); + if (tmp == NULL) + return NULL; + return g_string_new (tmp); } static gchar * @@ -213,8 +170,10 @@ g_autoptr(GDir) dir = NULL; path_remotes = g_build_filename (path, "remotes.d", NULL); - if (!g_file_test (path_remotes, G_FILE_TEST_EXISTS)) + if (!g_file_test (path_remotes, G_FILE_TEST_EXISTS)) { + g_debug ("path %s does not exist", path_remotes); return TRUE; + } if (!fu_config_add_inotify (self, path_remotes, error)) return FALSE; dir = g_dir_open (path_remotes, 0, error); @@ -248,9 +207,13 @@ if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DOWNLOAD) { g_autoptr(GString) agreement_markup = NULL; g_autofree gchar *component_id = fu_config_build_remote_component_id (remote); - AsApp *app = as_store_get_app_by_id (self->store_remotes, component_id); - if (app != NULL) { - agreement_markup = fu_config_get_remote_agreement_for_app (remote, app, error); + g_autoptr(XbNode) component = NULL; + g_autofree gchar *xpath = NULL; + + xpath = g_strdup_printf ("component/id[text()='%s']/..", component_id); + component = xb_silo_query_first (self->silo, xpath, NULL); + if (component != NULL) { + agreement_markup = fu_config_get_remote_agreement_for_app (remote, component, error); } else { agreement_markup = fu_config_get_remote_agreement_default (remote, error); } @@ -261,11 +224,11 @@ tmp = g_hash_table_lookup (self->os_release, "NAME"); if (tmp == NULL) tmp = "this distribution"; - as_utils_string_replace (agreement_markup, "$OS_RELEASE:NAME$", tmp); + fu_common_string_replace (agreement_markup, "$OS_RELEASE:NAME$", tmp); tmp = g_hash_table_lookup (self->os_release, "BUG_REPORT_URL"); if (tmp == NULL) tmp = "https://github.com/hughsie/fwupd/issues"; - as_utils_string_replace (agreement_markup, "$OS_RELEASE:BUG_REPORT_URL$", tmp); + fu_common_string_replace (agreement_markup, "$OS_RELEASE:BUG_REPORT_URL$", tmp); fwupd_remote_set_agreement (remote, agreement_markup->str); } @@ -393,6 +356,7 @@ { GFileMonitor *monitor; guint64 archive_size_max; + guint idle_timeout; g_auto(GStrv) devices = NULL; g_auto(GStrv) plugins = NULL; g_autoptr(GFile) file = NULL; @@ -450,16 +414,60 @@ NULL); if (archive_size_max > 0) self->archive_size_max = archive_size_max *= 0x100000; + + /* get idle timeout */ + idle_timeout = g_key_file_get_uint64 (self->keyfile, + "fwupd", + "IdleTimeout", + NULL); + if (idle_timeout > 0) + self->idle_timeout = idle_timeout; + return TRUE; +} + +static gboolean +fu_config_load_metainfos (XbBuilder *builder, GError **error) +{ + const gchar *fn; + g_autofree gchar *datadir = NULL; + g_autofree gchar *metainfo_path = NULL; + g_autoptr(GDir) dir = NULL; + + /* pkg metainfo dir */ + datadir = fu_common_get_path (FU_PATH_KIND_DATADIR_PKG); + metainfo_path = g_build_filename (datadir, "metainfo", NULL); + if (!g_file_test (metainfo_path, G_FILE_TEST_EXISTS)) + return TRUE; + + g_debug ("loading %s", metainfo_path); + dir = g_dir_open (metainfo_path, 0, error); + if (dir == NULL) + return FALSE; + while ((fn = g_dir_read_name (dir)) != NULL) { + if (g_str_has_suffix (fn, ".metainfo.xml")) { + g_autofree gchar *filename = g_build_filename (metainfo_path, fn, NULL); + g_autoptr(GFile) file = g_file_new_for_path (filename); + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + if (!xb_builder_source_load_file (source, file, + XB_BUILDER_SOURCE_FLAG_NONE, + NULL, error)) + return FALSE; + xb_builder_import_source (builder, source); + } + } return TRUE; } gboolean fu_config_load (FuConfig *self, GError **error) { - g_autofree gchar *datadir = NULL; + const gchar *const *locales = g_get_language_names (); g_autofree gchar *configdir = NULL; - g_autofree gchar *metainfo_path = NULL; g_autofree gchar *config_file = NULL; + g_autofree gchar *cachedirpkg = NULL; + g_autofree gchar *xmlbfn = NULL; + g_autoptr(GFile) xmlb = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); g_return_val_if_fail (FU_IS_CONFIG (self), FALSE); @@ -477,16 +485,23 @@ self->os_release = fwupd_get_os_release (error); if (self->os_release == NULL) return FALSE; - as_store_add_filter (self->store_remotes, AS_APP_KIND_SOURCE); - datadir = fu_common_get_path (FU_PATH_KIND_DATADIR_PKG); - metainfo_path = g_build_filename (datadir, "metainfo", NULL); - if (g_file_test (metainfo_path, G_FILE_TEST_EXISTS)) { - if (!as_store_load_path (self->store_remotes, - metainfo_path, - NULL, /* cancellable */ - error)) - return FALSE; - } + if (!fu_config_load_metainfos (builder, error)) + return FALSE; + + /* add the locales, which is really only going to be 'C' or 'en' */ + for (guint i = 0; locales[i] != NULL; i++) + xb_builder_add_locale (builder, locales[i]); + + /* build the metainfo silo */ + cachedirpkg = fu_common_get_path (FU_PATH_KIND_CACHEDIR_PKG); + xmlbfn = g_build_filename (cachedirpkg, "metainfo.xmlb", NULL); + xmlb = g_file_new_for_path (xmlbfn); + self->silo = xb_builder_ensure (builder, xmlb, + XB_BUILDER_COMPILE_FLAG_SINGLE_LANG | + XB_BUILDER_COMPILE_FLAG_IGNORE_INVALID, + NULL, error); + if (self->silo == NULL) + return FALSE; /* load remotes */ if (!fu_config_load_remotes (self, error)) @@ -503,6 +518,13 @@ return self->remotes; } +guint +fu_config_get_idle_timeout (FuConfig *self) +{ + g_return_val_if_fail (FU_IS_CONFIG (self), 0); + return self->idle_timeout; +} + FwupdRemote * fu_config_get_remote_by_id (FuConfig *self, const gchar *remote_id) { @@ -547,7 +569,6 @@ self->blacklist_plugins = g_ptr_array_new_with_free_func (g_free); self->remotes = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); self->monitors = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - self->store_remotes = as_store_new (); } static void @@ -557,12 +578,13 @@ if (self->os_release != NULL) g_hash_table_unref (self->os_release); + if (self->silo != NULL) + g_object_unref (self->silo); g_key_file_unref (self->keyfile); g_ptr_array_unref (self->blacklist_devices); g_ptr_array_unref (self->blacklist_plugins); g_ptr_array_unref (self->remotes); g_ptr_array_unref (self->monitors); - g_object_unref (self->store_remotes); G_OBJECT_CLASS (fu_config_parent_class)->finalize (obj); } diff -Nru fwupd-1.1.4/src/fu-config.h fwupd-1.2.5/src/fu-config.h --- fwupd-1.1.4/src/fu-config.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-config.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,15 +4,14 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_CONFIG_H -#define __FU_CONFIG_H - -G_BEGIN_DECLS +#pragma once #include #include "fwupd-remote.h" +G_BEGIN_DECLS + #define FU_TYPE_CONFIG (fu_config_get_type ()) G_DECLARE_FINAL_TYPE (FuConfig, fu_config, FU, CONFIG, GObject) @@ -21,6 +20,7 @@ GError **error); guint64 fu_config_get_archive_size_max (FuConfig *self); +guint fu_config_get_idle_timeout (FuConfig *self); GPtrArray *fu_config_get_blacklist_devices (FuConfig *self); GPtrArray *fu_config_get_blacklist_plugins (FuConfig *self); GPtrArray *fu_config_get_remotes (FuConfig *self); @@ -28,6 +28,3 @@ const gchar *remote_id); G_END_DECLS - -#endif /* __FU_CONFIG_H */ - diff -Nru fwupd-1.1.4/src/fu-debug.c fwupd-1.2.5/src/fu-debug.c --- fwupd-1.1.4/src/fu-debug.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-debug.c 2019-02-25 09:42:18.000000000 +0000 @@ -14,6 +14,7 @@ #include typedef struct { + GOptionGroup *group; gboolean verbose; gboolean console; gchar **plugin_verbose; @@ -23,6 +24,8 @@ static void fu_debug_free (FuDebug *self) { + g_option_group_set_parse_hooks (self->group, NULL, NULL); + g_option_group_unref (self->group); g_strfreev (self->plugin_verbose); g_strfreev (self->daemon_verbose); g_free (self); @@ -174,19 +177,19 @@ return TRUE; } +/*(transfer): full */ GOptionGroup * fu_debug_get_option_group (void) { - GOptionGroup *group; FuDebug *self = g_new0 (FuDebug, 1); - group = g_option_group_new ("debug", - /* TRANSLATORS: for the --verbose arg */ - _("Debugging Options"), - /* TRANSLATORS: for the --verbose arg */ - _("Show debugging options"), - self, (GDestroyNotify) fu_debug_free); - g_option_group_set_parse_hooks (group, + self->group = g_option_group_new ("debug", + /* TRANSLATORS: for the --verbose arg */ + _("Debugging Options"), + /* TRANSLATORS: for the --verbose arg */ + _("Show debugging options"), + self, (GDestroyNotify) fu_debug_free); + g_option_group_set_parse_hooks (self->group, fu_debug_pre_parse_hook, fu_debug_post_parse_hook); - return group; + return g_option_group_ref (self->group); } diff -Nru fwupd-1.1.4/src/fu-debug.h fwupd-1.2.5/src/fu-debug.h --- fwupd-1.1.4/src/fu-debug.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-debug.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,11 +4,12 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_DEBUG_H__ -#define __FU_DEBUG_H__ +#pragma once #include +G_BEGIN_DECLS + GOptionGroup *fu_debug_get_option_group (void); -#endif /* __FU_DEBUG_H__ */ +G_END_DECLS diff -Nru fwupd-1.1.4/src/fu-device.c fwupd-1.2.5/src/fu-device.c --- fwupd-1.1.4/src/fu-device.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-device.c 2019-02-25 09:42:18.000000000 +0000 @@ -9,14 +9,15 @@ #include "config.h" #include -#include #include #include #include "fu-common.h" +#include "fu-common-version.h" #include "fu-device-private.h" #include "fu-mutex.h" +#include "fwupd-common.h" #include "fwupd-device-private.h" /** @@ -43,6 +44,7 @@ GPtrArray *children; guint remove_delay; /* ms */ FwupdStatus status; + FuVersionFormat version_format; guint progress; guint order; guint priority; @@ -61,6 +63,7 @@ PROP_PHYSICAL_ID, PROP_LOGICAL_ID, PROP_QUIRKS, + PROP_VERSION_FORMAT, PROP_LAST }; @@ -80,6 +83,9 @@ case PROP_PROGRESS: g_value_set_uint (value, priv->progress); break; + case PROP_VERSION_FORMAT: + g_value_set_uint (value, priv->version_format); + break; case PROP_PHYSICAL_ID: g_value_set_string (value, fu_device_get_physical_id (self)); break; @@ -107,6 +113,9 @@ case PROP_PROGRESS: fu_device_set_progress (self, g_value_get_uint (value)); break; + case PROP_VERSION_FORMAT: + fu_device_set_version_format (self, g_value_get_uint (value)); + break; case PROP_PHYSICAL_ID: fu_device_set_physical_id (self, g_value_get_string (value)); break; @@ -535,8 +544,8 @@ g_return_if_fail (guid != NULL); /* make valid */ - if (!as_utils_guid_is_valid (guid)) { - g_autofree gchar *tmp = as_utils_guid_from_string (guid); + if (!fwupd_guid_is_valid (guid)) { + g_autofree gchar *tmp = fwupd_guid_hash_string (guid); if (fu_device_has_parent_guid (self, tmp)) return; g_debug ("using %s for %s", tmp, guid); @@ -571,6 +580,7 @@ return FALSE; if (!fu_device_probe (child, error)) return FALSE; + fu_device_convert_instance_ids (child); fu_device_add_child (self, child); return TRUE; } @@ -676,6 +686,10 @@ fu_device_set_install_duration (self, fu_common_strtoull (value)); return TRUE; } + if (g_strcmp0 (key, FU_QUIRKS_VERSION_FORMAT) == 0) { + fu_device_set_version_format (self, fu_common_version_format_from_string (value)); + return TRUE; + } if (g_strcmp0 (key, FU_QUIRKS_CHILDREN) == 0) { g_auto(GStrv) sections = g_strsplit (value, ",", -1); for (guint i = 0; sections[i] != NULL; i++) { @@ -765,27 +779,74 @@ } /** + * fu_device_has_guid: + * @self: A #FuDevice + * @guid: A GUID, e.g. `WacomAES` + * + * Finds out if the device has a specific GUID. + * + * Returns: %TRUE if the GUID is found + * + * Since: 1.2.2 + **/ +gboolean +fu_device_has_guid (FuDevice *self, const gchar *guid) +{ + /* make valid */ + if (!fwupd_guid_is_valid (guid)) { + g_autofree gchar *tmp = fwupd_guid_hash_string (guid); + return fwupd_device_has_guid (FWUPD_DEVICE (self), tmp); + } + + /* already valid */ + return fwupd_device_has_guid (FWUPD_DEVICE (self), guid); +} + +/** + * fu_device_add_instance_id: + * @self: A #FuDevice + * @instance_id: the InstanceID, e.g. `PCI\VEN_10EC&DEV_525A` + * + * Adds an instance ID to the device. If the @instance_id argument is already a + * valid GUID then fu_device_add_guid() should be used instead. + * + * Since: 1.2.5 + **/ +void +fu_device_add_instance_id (FuDevice *self, const gchar *instance_id) +{ + g_autofree gchar *guid = NULL; + if (fwupd_guid_is_valid (instance_id)) { + g_warning ("use fu_device_add_guid(\"%s\") instead!", instance_id); + fu_device_add_guid_safe (self, instance_id); + return; + } + /* it seems odd adding the instance ID and the GUID quirks and not just + * calling fu_device_add_guid_safe() -- but we want the quirks to match + * so the plugin is set, but not the LVFS metadata to match firmware + * until we're sure the device isn't using _NO_AUTO_INSTANCE_IDS */ + guid = fwupd_guid_hash_string (instance_id); + fu_device_add_guid_quirks (self, guid); + fwupd_device_add_instance_id (FWUPD_DEVICE (self), instance_id); +} + +/** * fu_device_add_guid: * @self: A #FuDevice * @guid: A GUID, e.g. `2082b5e0-7a64-478a-b1b2-e3404fab6dad` * * Adds a GUID to the device. If the @guid argument is not a valid GUID then it - * is converted to a GUID using as_utils_guid_from_string(). + * is converted to a GUID using fwupd_guid_hash_string(). * * Since: 0.7.2 **/ void fu_device_add_guid (FuDevice *self, const gchar *guid) { - /* make valid */ - if (!as_utils_guid_is_valid (guid)) { - g_autofree gchar *tmp = as_utils_guid_from_string (guid); - g_debug ("using %s for %s", tmp, guid); - fu_device_add_guid_safe (self, tmp); + if (!fwupd_guid_is_valid (guid)) { + fu_device_add_instance_id (self, guid); return; } - - /* already valid */ fu_device_add_guid_safe (self, guid); } @@ -795,7 +856,7 @@ * @guid: A GUID, e.g. `2082b5e0-7a64-478a-b1b2-e3404fab6dad` * * Adds a GUID to the device. If the @guid argument is not a valid GUID then it - * is converted to a GUID using as_utils_guid_from_string(). + * is converted to a GUID using fwupd_guid_hash_string(). * * A counterpart GUID is typically the GUID of the same device in bootloader * or runtime mode, if they have a different device PCI or USB ID. Adding this @@ -807,9 +868,8 @@ fu_device_add_counterpart_guid (FuDevice *self, const gchar *guid) { /* make valid */ - if (!as_utils_guid_is_valid (guid)) { - g_autofree gchar *tmp = as_utils_guid_from_string (guid); - g_debug ("using %s for counterpart %s", tmp, guid); + if (!fwupd_guid_is_valid (guid)) { + g_autofree gchar *tmp = fwupd_guid_hash_string (guid); fwupd_device_add_guid (FWUPD_DEVICE (self), tmp); return; } @@ -1011,7 +1071,7 @@ } g_strdelimit (new->str, "_", ' '); - as_utils_string_replace (new, "(TM)", "™"); + fu_common_string_replace (new, "(TM)", "™"); fwupd_device_set_name (FWUPD_DEVICE (self), new->str); } @@ -1041,6 +1101,56 @@ fwupd_device_set_id (FWUPD_DEVICE (self), id_hash); } +static gboolean +fu_device_is_valid_semver_char (gchar c) +{ + if (g_ascii_isdigit (c)) + return TRUE; + if (c == '.') + return TRUE; + return FALSE; +} + +/** + * fu_device_set_version: + * @self: A #FuDevice + * @version: a string, e.g. `1.2.3` + * + * Sets the device version, autodetecting the version format if required. + * + * Since: 1.2.1 + **/ +void +fu_device_set_version (FuDevice *self, const gchar *version) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_autoptr(GString) version_safe = NULL; + + g_return_if_fail (FU_IS_DEVICE (self)); + g_return_if_fail (version != NULL); + + /* sanitize if required */ + if (priv->version_format != FU_VERSION_FORMAT_UNKNOWN && + priv->version_format != FU_VERSION_FORMAT_PLAIN) { + version_safe = g_string_new (NULL); + for (guint i = 0; version[i] != '\0'; i++) { + if (fu_device_is_valid_semver_char (version[i])) + g_string_append_c (version_safe, version[i]); + } + if (g_strcmp0 (version, version_safe->str) != 0) { + g_debug ("converted '%s' to '%s'", + version, version_safe->str); + } + } else { + version_safe = g_string_new (version); + } + + /* try to autodetect the version-format */ + if (priv->version_format == FU_VERSION_FORMAT_UNKNOWN) + priv->version_format = fu_common_version_guess_format (version_safe->str); + fwupd_device_set_version (FWUPD_DEVICE (self), version_safe->str); +} + /** * fu_device_ensure_id: * @self: A #FuDevice @@ -1352,6 +1462,43 @@ } /** + * fu_device_get_version_format: + * @self: A #FuDevice + * + * Returns how the device version should be formatted. + * + * Returns: the version format, e.g. %FU_VERSION_FORMAT_TRIPLET + * + * Since: 1.2.0 + **/ +FuVersionFormat +fu_device_get_version_format (FuDevice *self) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DEVICE (self), 0); + return priv->version_format; +} + +/** + * fu_device_set_version_format: + * @self: A #FuDevice + * @version_format: the version_format value, e.g. %FU_VERSION_FORMAT_TRIPLET + * + * Sets how the version should be formatted. + * + * Since: 1.2.0 + **/ +void +fu_device_set_version_format (FuDevice *self, FuVersionFormat version_format) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DEVICE (self)); + if (priv->version_format == version_format) + return; + priv->version_format = version_format; +} + +/** * fu_device_get_progress: * @self: A #FuDevice * @@ -1435,6 +1582,10 @@ tmp = fwupd_device_to_string (FWUPD_DEVICE (self)); if (tmp != NULL && tmp[0] != '\0') g_string_append (str, tmp); + if (priv->version_format != FU_VERSION_FORMAT_UNKNOWN) { + fwupd_pad_kv_str (str, "VersionFormat", + fu_common_version_format_to_string (priv->version_format)); + } if (priv->alternate_id != NULL) fwupd_pad_kv_str (str, "AlternateId", priv->alternate_id); if (priv->equivalent_id != NULL) @@ -1859,6 +2010,42 @@ } /** + * fu_device_convert_instance_ids: + * @self: A #FuDevice + * + * Converts all the Device Instance IDs added using fu_device_add_instance_id() + * into actual GUIDs, **unless** %FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS has + * been set. + * + * Plugins will only need to need to call this manually when adding child + * devices, as fu_device_setup() automatically calls this after the + * fu_device_probe() and fu_device_setup() virtual functions have been run. + * + * Since: 1.2.5 + **/ +void +fu_device_convert_instance_ids (FuDevice *self) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + GPtrArray *instance_ids = fwupd_device_get_instance_ids (FWUPD_DEVICE (self)); + + /* OEM specific hardware */ + if (fu_device_has_flag (self, FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS)) + return; + for (guint i = 0; i < instance_ids->len; i++) { + const gchar *instance_id = g_ptr_array_index (instance_ids, i); + g_autofree gchar *guid = fwupd_guid_hash_string (instance_id); + fwupd_device_add_guid (FWUPD_DEVICE (self), guid); + } + + /* convert all children too */ + for (guint i = 0; i < priv->children->len; i++) { + FuDevice *devtmp = g_ptr_array_index (priv->children, i); + fu_device_convert_instance_ids (devtmp); + } +} + +/** * fu_device_setup: * @self: A #FuDevice * @error: A #GError, or %NULL @@ -1889,6 +2076,10 @@ if (!klass->setup (self, error)) return FALSE; } + + /* convert the instance IDs to GUIDs */ + fu_device_convert_instance_ids (self); + priv->done_setup = TRUE; return TRUE; } @@ -1968,6 +2159,24 @@ klass->incorporate (self, donor); } +/** + * fu_device_incorporate_from_component: + * @self: A #FuDevice + * @component: A #XbNode + * + * Copy all properties from the donor AppStream component. + * + * Since: 1.2.4 + **/ +void +fu_device_incorporate_from_component (FuDevice *device, XbNode *component) +{ + const gchar *tmp; + tmp = xb_node_query_text (component, "custom/value[@key='LVFS::UpdateMessage']", NULL); + if (tmp != NULL) + fwupd_device_set_update_message (FWUPD_DEVICE (device), tmp); +} + static void fu_device_class_init (FuDeviceClass *klass) { @@ -2001,6 +2210,14 @@ G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_PROGRESS, pspec); + pspec = g_param_spec_uint ("version-format", NULL, NULL, + FU_VERSION_FORMAT_UNKNOWN, + FU_VERSION_FORMAT_LAST, + FU_VERSION_FORMAT_UNKNOWN, + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_VERSION_FORMAT, pspec); + pspec = g_param_spec_object ("quirks", NULL, NULL, FU_TYPE_QUIRKS, G_PARAM_READWRITE | diff -Nru fwupd-1.1.4/src/fu-device.h fwupd-1.2.5/src/fu-device.h --- fwupd-1.1.4/src/fu-device.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-device.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,13 +4,13 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_DEVICE_H -#define __FU_DEVICE_H +#pragma once #include #include #include "fu-quirks.h" +#include "fu-common-version.h" G_BEGIN_DECLS @@ -78,13 +78,13 @@ #define fu_device_add_flag(d,v) fwupd_device_add_flag(FWUPD_DEVICE(d),v) #define fu_device_remove_flag(d,v) fwupd_device_remove_flag(FWUPD_DEVICE(d),v) #define fu_device_has_flag(d,v) fwupd_device_has_flag(FWUPD_DEVICE(d),v) +#define fu_device_has_instance_id(d,v) fwupd_device_has_instance_id(FWUPD_DEVICE(d),v) #define fu_device_add_checksum(d,v) fwupd_device_add_checksum(FWUPD_DEVICE(d),v) #define fu_device_add_release(d,v) fwupd_device_add_release(FWUPD_DEVICE(d),v) #define fu_device_add_icon(d,v) fwupd_device_add_icon(FWUPD_DEVICE(d),v) #define fu_device_set_created(d,v) fwupd_device_set_created(FWUPD_DEVICE(d),v) #define fu_device_set_description(d,v) fwupd_device_set_description(FWUPD_DEVICE(d),v) #define fu_device_set_flags(d,v) fwupd_device_set_flags(FWUPD_DEVICE(d),v) -#define fu_device_has_guid(d,v) fwupd_device_has_guid(FWUPD_DEVICE(d),v) #define fu_device_set_modified(d,v) fwupd_device_set_modified(FWUPD_DEVICE(d),v) #define fu_device_set_plugin(d,v) fwupd_device_set_plugin(FWUPD_DEVICE(d),v) #define fu_device_set_serial(d,v) fwupd_device_set_serial(FWUPD_DEVICE(d),v) @@ -93,7 +93,6 @@ #define fu_device_set_update_state(d,v) fwupd_device_set_update_state(FWUPD_DEVICE(d),v) #define fu_device_set_vendor(d,v) fwupd_device_set_vendor(FWUPD_DEVICE(d),v) #define fu_device_set_vendor_id(d,v) fwupd_device_set_vendor_id(FWUPD_DEVICE(d),v) -#define fu_device_set_version(d,v) fwupd_device_set_version(FWUPD_DEVICE(d),v) #define fu_device_set_version_lowest(d,v) fwupd_device_set_version_lowest(FWUPD_DEVICE(d),v) #define fu_device_set_version_bootloader(d,v) fwupd_device_set_version_bootloader(FWUPD_DEVICE(d),v) #define fu_device_set_flashes_left(d,v) fwupd_device_set_flashes_left(FWUPD_DEVICE(d),v) @@ -130,6 +129,10 @@ const gchar *equivalent_id); void fu_device_add_guid (FuDevice *self, const gchar *guid); +gboolean fu_device_has_guid (FuDevice *self, + const gchar *guid); +void fu_device_add_instance_id (FuDevice *self, + const gchar *instance_id); gchar *fu_device_get_guids_as_str (FuDevice *self); FuDevice *fu_device_get_alternate (FuDevice *self); FuDevice *fu_device_get_parent (FuDevice *self); @@ -157,6 +160,8 @@ guint value); void fu_device_set_id (FuDevice *self, const gchar *id); +void fu_device_set_version (FuDevice *self, + const gchar *version); const gchar *fu_device_get_physical_id (FuDevice *self); void fu_device_set_physical_id (FuDevice *self, const gchar *physical_id); @@ -176,6 +181,9 @@ FwupdStatus fu_device_get_status (FuDevice *self); void fu_device_set_status (FuDevice *self, FwupdStatus status); +FuVersionFormat fu_device_get_version_format (FuDevice *self); +void fu_device_set_version_format (FuDevice *self, + FuVersionFormat version_format); void fu_device_set_firmware_size_min (FuDevice *self, guint64 size_min); void fu_device_set_firmware_size_max (FuDevice *self, @@ -219,6 +227,3 @@ guint interval); G_END_DECLS - -#endif /* __FU_DEVICE_H */ - diff -Nru fwupd-1.1.4/src/fu-device-list.c fwupd-1.2.5/src/fu-device-list.c --- fwupd-1.1.4/src/fu-device-list.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-device-list.c 2019-02-25 09:42:18.000000000 +0000 @@ -468,6 +468,12 @@ fu_device_set_version (device, version); } + /* allow another plugin to handle the write too */ + if (fu_device_has_flag (item->device, FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED)) { + g_debug ("copying another-write-required to new device"); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED); + } + /* copy the parent if not already set */ if (fu_device_get_parent (item->device) != NULL && fu_device_get_parent (device) == NULL) { diff -Nru fwupd-1.1.4/src/fu-device-list.h fwupd-1.2.5/src/fu-device-list.h --- fwupd-1.1.4/src/fu-device-list.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-device-list.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,15 +4,14 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_DEVICE_LIST_H -#define __FU_DEVICE_LIST_H - -G_BEGIN_DECLS +#pragma once #include #include "fu-device.h" +G_BEGIN_DECLS + #define FU_TYPE_DEVICE_LIST (fu_device_list_get_type ()) G_DECLARE_FINAL_TYPE (FuDeviceList, fu_device_list, FU, DEVICE_LIST, GObject) @@ -36,6 +35,3 @@ GError **error); G_END_DECLS - -#endif /* __FU_DEVICE_LIST_H */ - diff -Nru fwupd-1.1.4/src/fu-device-locker.h fwupd-1.2.5/src/fu-device-locker.h --- fwupd-1.1.4/src/fu-device-locker.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-device-locker.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_DEVICE_LOCKER_H -#define __FU_DEVICE_LOCKER_H +#pragma once #include @@ -26,5 +25,3 @@ GError **error); G_END_DECLS - -#endif /* __FU_DEVICE_LOCKER_H */ diff -Nru fwupd-1.1.4/src/fu-device-metadata.h fwupd-1.2.5/src/fu-device-metadata.h --- fwupd-1.1.4/src/fu-device-metadata.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-device-metadata.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,11 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_DEVICE_METADATA_H__ -#define __FU_DEVICE_METADATA_H__ +#pragma once + +#include + +G_BEGIN_DECLS /** * SECTION:fu-device-metadata @@ -42,4 +45,23 @@ */ #define FU_DEVICE_METADATA_UEFI_DEVICE_KIND "UefiDeviceKind" -#endif /* __FU_DEVICE_METADATA_H__ */ +/** + * FU_DEVICE_METADATA_UEFI_FW_VERSION: + * + * The firmware version of the UEFI device specified as a 32 bit unsigned + * integer. + * Consumed by the uefi plugin when other devices register fake devices that + * need to be handled as a capsule update. + */ +#define FU_DEVICE_METADATA_UEFI_FW_VERSION "UefiFwVersion" + +/** + * FU_DEVICE_METADATA_UEFI_CAPSULE_FLAGS: + * + * The capsule flags for the UEFI device, e.g. %EFI_CAPSULE_HEADER_FLAGS_PERSIST_ACROSS_RESET + * Consumed by the uefi plugin when other devices register fake devices that + * need to be handled as a capsule update. + */ +#define FU_DEVICE_METADATA_UEFI_CAPSULE_FLAGS "UefiCapsuleFlags" + +G_END_DECLS diff -Nru fwupd-1.1.4/src/fu-device-private.h fwupd-1.2.5/src/fu-device-private.h --- fwupd-1.1.4/src/fu-device-private.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-device-private.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,10 +4,10 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_DEVICE_PRIVATE_H -#define __FU_DEVICE_PRIVATE_H +#pragma once #include +#include G_BEGIN_DECLS @@ -26,8 +26,8 @@ FuDevice *alternate); gboolean fu_device_ensure_id (FuDevice *self, GError **error); +void fu_device_incorporate_from_component (FuDevice *device, + XbNode *component); +void fu_device_convert_instance_ids (FuDevice *self); G_END_DECLS - -#endif /* __FU_DEVICE_PRIVATE_H */ - diff -Nru fwupd-1.1.4/src/fu-engine.c fwupd-1.2.5/src/fu-engine.c --- fwupd-1.1.4/src/fu-engine.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-engine.c 2019-02-25 09:42:18.000000000 +0000 @@ -8,7 +8,6 @@ #include "config.h" -#include #include #include #include @@ -32,7 +31,9 @@ #include "fu-device-private.h" #include "fu-engine.h" #include "fu-hwids.h" +#include "fu-idle.h" #include "fu-keyring-utils.h" +#include "fu-hash.h" #include "fu-history.h" #include "fu-mutex.h" #include "fu-plugin.h" @@ -54,21 +55,23 @@ FuConfig *config; FuDeviceList *device_list; FwupdStatus status; + gboolean tainted; guint percentage; FuHistory *history; - AsStore *store; + FuIdle *idle; + XbSilo *silo; gboolean coldplug_running; guint coldplug_id; guint coldplug_delay; FuPluginList *plugin_list; GPtrArray *plugin_filter; - GPtrArray *supported_guids; GPtrArray *udev_subsystems; FuSmbios *smbios; FuHwids *hwids; FuQuirks *quirks; GHashTable *runtime_versions; GHashTable *compile_versions; + gboolean loaded; }; enum { @@ -89,6 +92,7 @@ fu_engine_emit_changed (FuEngine *self) { g_signal_emit (self, signals[SIGNAL_CHANGED], 0); + fu_engine_idle_reset (self); } static void @@ -139,6 +143,8 @@ static void fu_engine_progress_notify_cb (FuDevice *device, GParamSpec *pspec, FuEngine *self) { + if (fu_device_get_status (device) == FWUPD_STATUS_UNKNOWN) + return; fu_engine_set_percentage (self, fu_device_get_progress (device)); fu_engine_emit_device_changed (self, device); } @@ -200,53 +206,98 @@ fu_engine_emit_device_changed (self, device); } -static const gchar * -_as_release_get_metadata_item (AsRelease *release, const gchar *key) +/* convert hex and decimal versions to dotted style */ +static gchar * +fu_engine_get_release_version (FuEngine *self, XbNode *component, XbNode *rel) { - GBytes *blob = as_release_get_blob (release, key); - if (blob == NULL) + FuVersionFormat fmt = FU_VERSION_FORMAT_TRIPLET; + const gchar *version; + const gchar *version_format; + guint64 ver_uint32; + + /* get version */ + version = xb_node_get_attr (rel, "version"); + if (version == NULL) return NULL; - return (const gchar *) g_bytes_get_data (blob, NULL); + + /* already dotted notation */ + if (g_strstr_len (version, -1, ".") != NULL) + return g_strdup (version); + + /* specified in metadata */ + version_format = xb_node_query_text (component, + "custom/value[@key='LVFS::VersionFormat']", + NULL); + if (version_format != NULL) + fmt = fu_common_version_format_from_string (version_format); + + /* don't touch my version! */ + if (fmt == FU_VERSION_FORMAT_PLAIN) + return g_strdup (version); + + /* parse as integer */ + ver_uint32 = fu_common_strtoull (version); + if (ver_uint32 == 0 || ver_uint32 > G_MAXUINT32) + return g_strdup (version); + + /* convert to dotted decimal */ + return fu_common_version_from_uint32 ((guint32) ver_uint32, fmt); } static void fu_engine_set_release_from_appstream (FuEngine *self, FwupdRelease *rel, - AsApp *app, - AsRelease *release) + XbNode *component, + XbNode *release) { - AsChecksum *csum; FwupdRemote *remote = NULL; const gchar *tmp; const gchar *remote_id; + guint64 tmp64; + g_autofree gchar *version_rel = NULL; + g_autoptr(XbNode) description = NULL; + + /* set from the component */ + tmp = xb_node_query_text (component, "id", NULL); + if (tmp != NULL) + fwupd_release_set_appstream_id (rel, tmp); + tmp = xb_node_query_text (component, "url[@type='homepage']", NULL); + if (tmp != NULL) + fwupd_release_set_homepage (rel, tmp); + tmp = xb_node_query_text (component, "project_license", NULL); + if (tmp != NULL) + fwupd_release_set_license (rel, tmp); + tmp = xb_node_query_text (component, "name", NULL); + if (tmp != NULL) + fwupd_release_set_name (rel, tmp); + tmp = xb_node_query_text (component, "summary", NULL); + if (tmp != NULL) + fwupd_release_set_summary (rel, tmp); + tmp = xb_node_query_text (component, "developer_name", NULL); + if (tmp != NULL) + fwupd_release_set_vendor (rel, tmp); - /* set from the AsApp */ - fwupd_release_set_appstream_id (rel, as_app_get_id (app)); - fwupd_release_set_homepage (rel, as_app_get_url_item (app, AS_URL_KIND_HOMEPAGE)); - fwupd_release_set_license (rel, as_app_get_project_license (app)); - fwupd_release_set_name (rel, as_app_get_name (app, NULL)); - fwupd_release_set_summary (rel, as_app_get_comment (app, NULL)); - fwupd_release_set_vendor (rel, as_app_get_developer_name (app, NULL)); - fwupd_release_set_appstream_id (rel, as_app_get_id (app)); + /* the version is fixed up at runtime */ + version_rel = fu_engine_get_release_version (self, component, release); + if (version_rel != NULL) + fwupd_release_set_version (rel, version_rel); /* find the remote */ - remote_id = _as_release_get_metadata_item (release, "fwupd::RemoteId"); + remote_id = xb_node_query_text (component, "../custom/value[@key='fwupd::RemoteId']", NULL); if (remote_id != NULL) { fwupd_release_set_remote_id (rel, remote_id); remote = fu_config_get_remote_by_id (self->config, remote_id); - if (remote == NULL) { - g_warning ("no remote found for release %s", - as_release_get_version (release)); - } + if (remote == NULL) + g_warning ("no remote found for release %s", version_rel); } - - tmp = as_release_get_version (release); - if (tmp != NULL) - fwupd_release_set_version (rel, tmp); - tmp = as_release_get_description (release, NULL); - if (tmp != NULL) - fwupd_release_set_description (rel, tmp); - tmp = as_release_get_location_default (release); + description = xb_node_query_first (release, "description", NULL); + if (description != NULL) { + g_autofree gchar *xml = NULL; + xml = xb_node_export (description, XB_NODE_EXPORT_FLAG_ONLY_CHILDREN, NULL); + if (xml != NULL) + fwupd_release_set_description (rel, xml); + } + tmp = xb_node_query_text (release, "location", NULL); if (tmp != NULL) { g_autofree gchar *uri = NULL; if (remote != NULL) @@ -254,43 +305,62 @@ if (uri == NULL) uri = g_strdup (tmp); fwupd_release_set_uri (rel, uri); + } else if (remote != NULL && + fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DIRECTORY) { + g_autofree gchar *uri = NULL; + tmp = xb_node_query_text (component, "../custom/value[@key='fwupd::FilenameCache']", NULL); + if (tmp != NULL) { + uri = g_strdup_printf ("file://%s", tmp); + fwupd_release_set_uri (rel, uri); + } } - csum = as_release_get_checksum_by_target (release, AS_CHECKSUM_TARGET_CONTENT); - if (csum != NULL) { - tmp = as_checksum_get_filename (csum); - if (tmp != NULL) - fwupd_release_set_filename (rel, tmp); - } - csum = as_release_get_checksum_by_target (release, AS_CHECKSUM_TARGET_CONTAINER); - if (csum != NULL) { - tmp = as_checksum_get_value (csum); - if (tmp != NULL) - fwupd_release_add_checksum (rel, tmp); + tmp = xb_node_query_text (release, "checksum[@target='content']", NULL); + if (tmp != NULL) + fwupd_release_set_filename (rel, tmp); + tmp = xb_node_query_text (release, "url[@type='details']", NULL); + if (tmp != NULL) + fwupd_release_set_details_url (rel, tmp); + tmp = xb_node_query_text (release, "url[@type='source']", NULL); + if (tmp != NULL) + fwupd_release_set_source_url (rel, tmp); + tmp = xb_node_query_text (release, "checksum[@target='container']", NULL); + if (tmp != NULL) + fwupd_release_add_checksum (rel, tmp); + tmp64 = xb_node_query_text_as_uint (release, "size[@type='installed']", NULL); + if (tmp64 != G_MAXUINT64) { + fwupd_release_set_size (rel, tmp64); + } else { + GBytes *sz = xb_node_get_data (release, "fwupd::ReleaseSize"); + if (sz != NULL) { + const guint64 *sizeptr = g_bytes_get_data (sz, NULL); + fwupd_release_set_size (rel, *sizeptr); + } } - fwupd_release_set_size (rel, as_release_get_size (release, AS_SIZE_KIND_INSTALLED)); + tmp64 = xb_node_get_attr_as_uint (release, "install_duration"); + if (tmp64 != G_MAXUINT64) + fwupd_release_set_install_duration (rel, tmp64); + tmp = xb_node_query_text (component, "custom/value[@key='LVFS::UpdateProtocol']", NULL); + if (tmp != NULL) + fwupd_release_set_protocol (rel, tmp); + tmp = xb_node_query_text (component, "custom/value[@key='LVFS::UpdateMessage']", NULL); + if (tmp != NULL) + fwupd_release_set_update_message (rel, tmp); } -/* finds the remote-id for the first firmware in the store that matches this +/* finds the remote-id for the first firmware in the silo that matches this * container checksum */ static const gchar * fu_engine_get_remote_id_for_checksum (FuEngine *self, const gchar *csum) { - GPtrArray *array = as_store_get_apps (self->store); - for (guint i = 0; i < array->len; i++) { - AsApp *app = g_ptr_array_index (array, i); - GPtrArray *releases = as_app_get_releases (app); - for (guint j = 0; j < releases->len; j++) { - AsRelease *release = g_ptr_array_index (releases, j); - AsChecksum *checksum; - checksum = as_release_get_checksum_by_target (release, - AS_CHECKSUM_TARGET_CONTAINER); - if (checksum == NULL) - continue; - if (g_strcmp0 (csum, as_checksum_get_value (checksum)) == 0) - return _as_release_get_metadata_item (release, "fwupd::RemoteId"); - } - } - return NULL; + g_autofree gchar *xpath = NULL; + g_autoptr(XbNode) key = NULL; + xpath = g_strdup_printf ("components/component/releases/release/" + "checksum[@target='container'][text()='%s']/../../" + "../../custom/value[@key='fwupd::RemoteId']", csum); + key = xb_silo_query_first (self->silo, xpath, NULL); + if (key == NULL) + return NULL; + return xb_node_get_text (key); } /** @@ -335,63 +405,6 @@ return TRUE; } -static AsApp * -fu_engine_verify_update_device_to_app (FuDevice *device) -{ - AsApp *app = NULL; - GPtrArray *checksums; - g_autofree gchar *id = NULL; - g_autoptr(AsFormat) format = NULL; - g_autoptr(AsProvide) prov = NULL; - g_autoptr(AsRelease) rel = NULL; - - /* make a plausible ID */ - id = g_strdup_printf ("%s.firmware", fu_device_get_guid_default (device)); - - /* add app to store */ - app = as_app_new (); - as_app_set_id (app, id); - as_app_set_kind (app, AS_APP_KIND_FIRMWARE); - rel = as_release_new (); - as_release_set_version (rel, fu_device_get_version (device)); - checksums = fu_device_get_checksums (device); - for (guint j = 0; j < checksums->len; j++) { - const gchar *checksum = g_ptr_array_index (checksums, j); - g_autoptr(AsChecksum) csum = as_checksum_new (); - as_checksum_set_kind (csum, fwupd_checksum_guess_kind (checksum)); - as_checksum_set_value (csum, checksum); - as_checksum_set_target (csum, AS_CHECKSUM_TARGET_CONTENT); - as_release_add_checksum (rel, csum); - } - as_app_add_release (app, rel); - prov = as_provide_new (); - as_provide_set_kind (prov, AS_PROVIDE_KIND_FIRMWARE_FLASHED); - as_provide_set_value (prov, fu_device_get_guid_default (device)); - as_app_add_provide (app, prov); - format = as_format_new (); - as_format_set_kind (format, AS_FORMAT_KIND_UNKNOWN); - as_app_add_format (app, format); - return app; -} - -static AsStore * -fu_engine_load_verify_store (GError **error) -{ - const gchar *fn = "/var/lib/fwupd/verify.xml"; - g_autoptr(AsStore) store = NULL; - g_autoptr(GFile) file = NULL; - - /* load existing store */ - store = as_store_new (); - as_store_set_api_version (store, 0.9); - file = g_file_new_for_path (fn); - if (g_file_query_exists (file, NULL)) { - if (!as_store_from_file (store, file, NULL, NULL, error)) - return NULL; - } - return g_steal_pointer (&store); -} - /** * fu_engine_modify_remote: * @self: A #FuEngine @@ -400,7 +413,7 @@ * @value: the key, e.g. `true` * @error: A #GError, or %NULL * - * Updates the verification store entry for a specific device. + * Updates the verification silo entry for a specific device. * * Returns: %TRUE for success **/ @@ -507,13 +520,25 @@ return FALSE; } +static const gchar * +fu_engine_checksum_type_to_string (GChecksumType checksum_type) +{ + if (checksum_type == G_CHECKSUM_SHA1) + return "sha1"; + if (checksum_type == G_CHECKSUM_SHA256) + return "sha256"; + if (checksum_type == G_CHECKSUM_SHA512) + return "sha512"; + return "sha1"; +} + /** * fu_engine_verify_update: * @self: A #FuEngine * @device_id: A device ID * @error: A #GError, or %NULL * - * Updates the verification store entry for a specific device. + * Updates the verification silo entry for a specific device. * * Returns: %TRUE for success **/ @@ -522,11 +547,17 @@ { FuPlugin *plugin; GPtrArray *checksums; - const gchar *fn = "/var/lib/fwupd/verify.xml"; - g_autoptr(AsApp) app = NULL; - g_autoptr(AsStore) store = NULL; + GPtrArray *guids; + g_autofree gchar *fn = NULL; + g_autofree gchar *localstatedir = NULL; g_autoptr(FuDevice) device = NULL; g_autoptr(GFile) file = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); + g_autoptr(XbBuilderNode) component = NULL; + g_autoptr(XbBuilderNode) provides = NULL; + g_autoptr(XbBuilderNode) release = NULL; + g_autoptr(XbBuilderNode) releases = NULL; + g_autoptr(XbSilo) silo = NULL; g_return_val_if_fail (FU_IS_ENGINE (self), FALSE); g_return_val_if_fail (device_id != NULL, FALSE); @@ -563,38 +594,68 @@ return FALSE; } - /* load existing store */ - store = fu_engine_load_verify_store (error); - if (store == NULL) + /* build XML */ + component = xb_builder_node_insert (NULL, "component", + "type", "firmware", + NULL); + provides = xb_builder_node_insert (component, "provides", NULL); + guids = fu_device_get_guids (device); + for (guint i = 0; i < guids->len; i++) { + const gchar *guid = g_ptr_array_index (guids, i); + g_autoptr(XbBuilderNode) provide = NULL; + provide = xb_builder_node_insert (provides, "firmware", + "type", "flashed", + NULL); + xb_builder_node_set_text (provide, guid, -1); + } + releases = xb_builder_node_insert (component, "releases", NULL); + release = xb_builder_node_insert (releases, "release", + "version", fu_device_get_version (device), + NULL); + for (guint i = 0; i < checksums->len; i++) { + const gchar *checksum = g_ptr_array_index (checksums, i); + GChecksumType kind = fwupd_checksum_guess_kind (checksum); + g_autoptr(XbBuilderNode) csum = NULL; + csum = xb_builder_node_insert (release, "checksum", + "type", fu_engine_checksum_type_to_string (kind), + "target", "content", + NULL); + xb_builder_node_set_text (csum, checksum, -1); + } + xb_builder_import_node (builder, component); + + /* save silo */ + localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); + fn = g_strdup_printf ("%s/verify/%s.xml", localstatedir, device_id); + file = g_file_new_for_path (fn); + silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_NONE, NULL, error); + if (silo == NULL) + return FALSE; + if (!xb_silo_export_file (silo, file, + XB_NODE_EXPORT_FLAG_FORMAT_MULTILINE, + NULL, error)) return FALSE; - /* add to store */ - app = fu_engine_verify_update_device_to_app (device); - as_store_remove_app_by_id (store, as_app_get_id (app)); - as_store_add_app (store, app); - - /* write */ - g_debug ("writing %s", fn); - file = g_file_new_for_path (fn); - return as_store_to_file (store, file, - AS_NODE_TO_XML_FLAG_ADD_HEADER | - AS_NODE_TO_XML_FLAG_FORMAT_INDENT | - AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE, - NULL, error); + /* success */ + return TRUE; } -static AsApp * -fu_engine_store_get_app_by_guids (AsStore *store, FuDevice *device) +XbNode * +fu_engine_get_component_by_guids (FuEngine *self, FuDevice *device) { GPtrArray *guids = fu_device_get_guids (device); + g_autoptr(GString) xpath = g_string_new (NULL); + g_autoptr(XbNode) component = NULL; for (guint i = 0; i < guids->len; i++) { - AsApp *app = NULL; - app = as_store_get_app_by_provide (store, - AS_PROVIDE_KIND_FIRMWARE_FLASHED, - g_ptr_array_index (guids, i)); - if (app != NULL) - return app; - } + const gchar *guid = g_ptr_array_index (guids, i); + xb_string_append_union (xpath, + "components/component/" + "provides/firmware[@type='flashed'][text()='%s']/" + "../..", guid); + } + component = xb_silo_query_first (self->silo, xpath->str, NULL); + if (component != NULL) + return g_steal_pointer (&component); return NULL; } @@ -604,22 +665,24 @@ * @device_id: A device ID * @error: A #GError, or %NULL * - * Verifies a device firmware checksum using the verification store entry. + * Verifies a device firmware checksum using the verification silo entry. * * Returns: %TRUE for success **/ gboolean fu_engine_verify (FuEngine *self, const gchar *device_id, GError **error) { - AsApp *app; - AsChecksum *csum; - AsRelease *release; FuPlugin *plugin; GPtrArray *checksums; - const gchar *hash = NULL; - const gchar *version = NULL; - g_autoptr(AsStore) store = NULL; + const gchar *version; + g_autofree gchar *fn = NULL; + g_autofree gchar *localstatedir = NULL; g_autoptr(FuDevice) device = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(GString) xpath_csum = g_string_new (NULL); + g_autoptr(XbNode) csum = NULL; + g_autoptr(XbNode) release = NULL; + g_autoptr(XbSilo) silo = xb_silo_new (); g_return_val_if_fail (FU_IS_ENGINE (self), FALSE); g_return_val_if_fail (device_id != NULL, FALSE); @@ -643,32 +706,42 @@ return FALSE; /* find component in metadata */ - store = fu_engine_load_verify_store (error); - if (store == NULL) - return FALSE; - app = fu_engine_store_get_app_by_guids (store, device); - if (app == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No metadata"); - return FALSE; + version = fu_device_get_version (device); + localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); + fn = g_strdup_printf ("%s/verify/%s.xml", localstatedir, device_id); + file = g_file_new_for_path (fn); + if (g_file_query_exists (file, NULL)) { + g_autofree gchar *xpath = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + if (!xb_builder_source_load_file (source, file, + XB_BUILDER_SOURCE_FLAG_NONE, + NULL, error)) + return FALSE; + xb_builder_import_source (builder, source); + silo = xb_builder_compile (builder, + XB_BUILDER_COMPILE_FLAG_NONE, + NULL, error); + if (silo == NULL) + return FALSE; + xpath = g_strdup_printf ("component/releases/release[@version='%s']", version); + release = xb_silo_query_first (silo, xpath, NULL); } - /* find version in metadata */ - version = fu_device_get_version (device); - release = as_app_get_release (app, version); + /* try again with the system metadata */ if (release == NULL) { - /* try again with the system metadata */ - app = fu_engine_store_get_app_by_guids (self->store, device); - if (app == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No system metadata"); - return FALSE; + GPtrArray *guids = fu_device_get_guids (device); + for (guint i = 0; i < guids->len; i++) { + const gchar *guid = g_ptr_array_index (guids, i); + g_autofree gchar *xpath2 = NULL; + xpath2 = g_strdup_printf ("components/component/" + "provides/firmware[@type='flashed'][text()='%s']/" + "../../releases/release[@version='%s']", + guid, version); + release = xb_silo_query_first (self->silo, xpath2, NULL); + if (release != NULL) + break; } - release = as_app_get_release (app, version); } if (release == NULL) { g_set_error (error, @@ -678,16 +751,6 @@ return FALSE; } - /* find checksum */ - csum = as_release_get_checksum_by_target (release, AS_CHECKSUM_TARGET_CONTENT); - if (csum == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No content checksum for %s", version); - return FALSE; - } - /* get the matching checksum */ checksums = fu_device_get_checksums (device); if (checksums->len == 0) { @@ -697,29 +760,52 @@ "No device checksums for %s", version); return FALSE; } + + /* do any of the checksums in the release match any in the device */ for (guint j = 0; j < checksums->len; j++) { const gchar *hash_tmp = g_ptr_array_index (checksums, j); - GChecksumType hash_kind = fwupd_checksum_guess_kind (hash_tmp); - if (as_checksum_get_kind (csum) == hash_kind) { - hash = hash_tmp; - break; - } + xb_string_append_union (xpath_csum, + "checksum[@target='device'][text()='%s']", + hash_tmp); + xb_string_append_union (xpath_csum, + "checksum[@target='content'][text()='%s']", + hash_tmp); } - if (hash == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No matching hash kind for %s", version); - return FALSE; - } - if (g_strcmp0 (as_checksum_get_value (csum), hash) != 0) { + csum = xb_node_query_first (release, xpath_csum->str, NULL); + if (csum == NULL) { + g_autoptr(GString) checksums_device = g_string_new (NULL); + g_autoptr(GString) checksums_metadata = g_string_new (NULL); + g_autoptr(GPtrArray) csums = NULL; + g_autoptr(GString) xpath = g_string_new (NULL); + + /* get all checksums to display a useful error */ + xb_string_append_union (xpath, "checksum[@target='device']"); + xb_string_append_union (xpath, "checksum[@target='content']"); + csums = xb_node_query (release, xpath->str, 0, NULL); + if (csums == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "No device or content checksum for %s", + version); + return FALSE; + } + for (guint i = 0; i < csums->len; i++) { + XbNode *csum_tmp = g_ptr_array_index (csums, i); + xb_string_append_union (checksums_metadata, + "%s", xb_node_get_text (csum_tmp)); + } + for (guint i = 0; i < checksums->len; i++) { + const gchar *hash_tmp = g_ptr_array_index (checksums, i); + xb_string_append_union (checksums_device, "%s", hash_tmp); + } g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "For v%s expected %s, got %s", version, - as_checksum_get_value (csum), - hash); + checksums_metadata->str, + checksums_device->str); return FALSE; } @@ -727,46 +813,73 @@ return TRUE; } -static GPtrArray * -_as_store_get_apps_by_provide (AsStore *store, AsProvideKind kind, const gchar *value) +static gboolean +fu_engine_require_vercmp (XbNode *req, const gchar *version, GError **error) { -#if AS_CHECK_VERSION(0,7,5) - return as_store_get_apps_by_provide (store, kind, value); -#else - GPtrArray *apps = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - GPtrArray *array = as_store_get_apps (store); - for (guint i = 0; i < array->len; i++) { - AsApp *app = g_ptr_array_index (array, i); - GPtrArray *provides = as_app_get_provides (app); - for (guint j = 0; j < provides->len; j++) { - AsProvide *tmp = g_ptr_array_index (provides, j); - if (kind != as_provide_get_kind (tmp)) - continue; - if (g_strcmp0 (as_provide_get_value (tmp), value) != 0) - continue; - g_ptr_array_add (apps, g_object_ref (app)); - } + gboolean ret = FALSE; + gint rc = 0; + const gchar *tmp = xb_node_get_attr (req, "compare"); + const gchar *version_req = xb_node_get_attr (req, "version"); + + if (g_strcmp0 (tmp, "eq") == 0) { + rc = fu_common_vercmp (version, version_req); + ret = rc == 0; + } else if (g_strcmp0 (tmp, "ne") == 0) { + rc = fu_common_vercmp (version, version_req); + ret = rc != 0; + } else if (g_strcmp0 (tmp, "lt") == 0) { + rc = fu_common_vercmp (version, version_req); + ret = rc < 0; + } else if (g_strcmp0 (tmp, "gt") == 0) { + rc = fu_common_vercmp (version, version_req); + ret = rc > 0; + } else if (g_strcmp0 (tmp, "le") == 0) { + rc = fu_common_vercmp (version, version_req); + ret = rc <= 0; + } else if (g_strcmp0 (tmp, "ge") == 0) { + rc = fu_common_vercmp (version, version_req); + ret = rc >= 0; + } else if (g_strcmp0 (tmp, "glob") == 0) { + ret = fnmatch (version_req, version, 0) == 0; + } else if (g_strcmp0 (tmp, "regex") == 0) { + ret = g_regex_match_simple (version_req, version, 0, 0); + } else { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to compare [%s] and [%s]", + version_req, + version); + return FALSE; } - return apps; -#endif + + /* set error */ + if (!ret) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed predicate [%s %s %s]", + version_req, tmp, version); + } + return ret; } static gboolean -fu_engine_check_requirement_firmware (FuEngine *self, AsRequire *req, +fu_engine_check_requirement_firmware (FuEngine *self, XbNode *req, FuDevice *device, GError **error) { g_autoptr(GError) error_local = NULL; /* old firmware version */ - if (as_require_get_value (req) == NULL) { + if (xb_node_get_text (req) == NULL) { const gchar *version = fu_device_get_version (device); - if (!as_require_version_compare (req, version, &error_local)) { - if (as_require_get_compare (req) == AS_REQUIRE_COMPARE_GE) { + if (!fu_engine_require_vercmp (req, version, &error_local)) { + if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Not compatible with firmware version %s, requires >= %s", - version, as_require_get_version (req)); + version, xb_node_get_attr (req, "version")); } else { g_set_error (error, FWUPD_ERROR, @@ -780,15 +893,15 @@ } /* bootloader version */ - if (g_strcmp0 (as_require_get_value (req), "bootloader") == 0) { + if (g_strcmp0 (xb_node_get_text (req), "bootloader") == 0) { const gchar *version = fu_device_get_version_bootloader (device); - if (!as_require_version_compare (req, version, &error_local)) { - if (as_require_get_compare (req) == AS_REQUIRE_COMPARE_GE) { + if (!fu_engine_require_vercmp (req, version, &error_local)) { + if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Not compatible with bootloader version %s, requires >= %s", - version, as_require_get_version (req)); + version, xb_node_get_attr (req, "version")); } else { g_set_error (error, FWUPD_ERROR, @@ -802,15 +915,15 @@ } /* vendor ID */ - if (g_strcmp0 (as_require_get_value (req), "vendor-id") == 0) { + if (g_strcmp0 (xb_node_get_text (req), "vendor-id") == 0) { const gchar *version = fu_device_get_vendor_id (device); - if (!as_require_version_compare (req, version, &error_local)) { - if (as_require_get_compare (req) == AS_REQUIRE_COMPARE_GE) { + if (!fu_engine_require_vercmp (req, version, &error_local)) { + if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Not compatible with vendor %s, requires >= %s", - version, as_require_get_version (req)); + version, xb_node_get_attr (req, "version")); } else { g_set_error (error, FWUPD_ERROR, @@ -824,8 +937,8 @@ } /* another device */ - if (as_utils_guid_is_valid (as_require_get_value (req))) { - const gchar *guid = as_require_get_value (req); + if (fwupd_guid_is_valid (xb_node_get_text (req))) { + const gchar *guid = xb_node_get_text (req); const gchar *version; g_autoptr(FuDevice) device2 = NULL; @@ -836,15 +949,15 @@ /* get the version of the other device */ version = fu_device_get_version (device2); - if (!as_require_version_compare (req, version, &error_local)) { - if (as_require_get_compare (req) == AS_REQUIRE_COMPARE_GE) { + if (!fu_engine_require_vercmp (req, version, &error_local)) { + if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Not compatible with %s version %s, requires >= %s", fu_device_get_name (device2), version, - as_require_get_version (req)); + xb_node_get_attr (req, "version")); } else { g_set_error (error, FWUPD_ERROR, @@ -863,57 +976,57 @@ g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, - "cannot handle firmware requirement %s", - as_require_get_value (req)); + "cannot handle firmware requirement '%s'", + xb_node_get_text (req)); return FALSE; } static gboolean -fu_engine_check_requirement_id (FuEngine *self, AsRequire *req, GError **error) +fu_engine_check_requirement_id (FuEngine *self, XbNode *req, GError **error) { g_autoptr(GError) error_local = NULL; const gchar *version = g_hash_table_lookup (self->runtime_versions, - as_require_get_value (req)); + xb_node_get_text (req)); if (version == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "no version available for %s", - as_require_get_value (req)); + xb_node_get_text (req)); return FALSE; } - if (!as_require_version_compare (req, version, &error_local)) { - if (as_require_get_compare (req) == AS_REQUIRE_COMPARE_GE) { + if (!fu_engine_require_vercmp (req, version, &error_local)) { + if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Not compatible with %s version %s, requires >= %s", - as_require_get_value (req), version, - as_require_get_version (req)); + xb_node_get_text (req), version, + xb_node_get_attr (req, "version")); } else { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Not compatible with %s version: %s", - as_require_get_value (req), error_local->message); + xb_node_get_text (req), error_local->message); } return FALSE; } g_debug ("requirement %s %s %s on %s passed", - as_require_get_version (req), - as_require_compare_to_string (as_require_get_compare (req)), - version, as_require_get_value (req)); + xb_node_get_attr (req, "version"), + xb_node_get_attr (req, "compare"), + version, xb_node_get_text (req)); return TRUE; } static gboolean -fu_engine_check_requirement_hardware (FuEngine *self, AsRequire *req, GError **error) +fu_engine_check_requirement_hardware (FuEngine *self, XbNode *req, GError **error) { g_auto(GStrv) hwid_split = NULL; /* split and treat as OR */ - hwid_split = g_strsplit (as_require_get_value (req), "|", -1); + hwid_split = g_strsplit (xb_node_get_text (req), "|", -1); for (guint i = 0; hwid_split[i] != NULL; i++) { if (fu_hwids_has_guid (self->hwids, hwid_split[i])) { g_debug ("HWID provided %s", hwid_split[i]); @@ -926,26 +1039,26 @@ FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "no HWIDs matched %s", - as_require_get_value (req)); + xb_node_get_text (req)); return FALSE; } static gboolean -fu_engine_check_requirement (FuEngine *self, AsRequire *req, FuDevice *device, GError **error) +fu_engine_check_requirement (FuEngine *self, XbNode *req, FuDevice *device, GError **error) { /* ensure component requirement */ - if (as_require_get_kind (req) == AS_REQUIRE_KIND_ID) + if (g_strcmp0 (xb_node_get_element (req), "id") == 0) return fu_engine_check_requirement_id (self, req, error); /* ensure firmware requirement */ - if (as_require_get_kind (req) == AS_REQUIRE_KIND_FIRMWARE) { + if (g_strcmp0 (xb_node_get_element (req), "firmware") == 0) { if (device == NULL) return TRUE; return fu_engine_check_requirement_firmware (self, req, device, error); } /* ensure hardware requirement */ - if (as_require_get_kind (req) == AS_REQUIRE_KIND_HARDWARE) + if (g_strcmp0 (xb_node_get_element (req), "hardware") == 0) return fu_engine_check_requirement_hardware (self, req, error); /* not supported */ @@ -953,7 +1066,7 @@ FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "cannot handle requirement type %s", - as_require_kind_to_string (as_require_get_kind (req))); + xb_node_get_element (req)); return FALSE; } @@ -961,8 +1074,9 @@ fu_engine_check_requirements (FuEngine *self, FuInstallTask *task, FwupdInstallFlags flags, GError **error) { - GPtrArray *reqs = as_app_get_requires (fu_install_task_get_app (task)); FuDevice *device = fu_install_task_get_device (task); + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) reqs = NULL; /* all install task checks require a device */ if (device != NULL) { @@ -971,121 +1085,28 @@ } /* do engine checks */ + reqs = xb_node_query (fu_install_task_get_component (task), + "requires/*", 0, &error_local); + if (reqs == NULL) { + if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + return TRUE; + if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) + return TRUE; + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } for (guint i = 0; i < reqs->len; i++) { - AsRequire *req = g_ptr_array_index (reqs, i); + XbNode *req = g_ptr_array_index (reqs, i); if (!fu_engine_check_requirement (self, req, device, error)) return FALSE; } return TRUE; } -static void -fu_engine_vendor_fixup_provide_value (AsApp *app) -{ - GPtrArray *provides; - - /* no quirk required */ - if (as_app_get_kind (app) != AS_APP_KIND_FIRMWARE) - return; - - /* fix each provide to be a GUID */ - provides = as_app_get_provides (app); - for (guint i = 0; i < provides->len; i++) { - AsProvide *prov = g_ptr_array_index (provides, i); - const gchar *value = as_provide_get_value (prov); - g_autofree gchar *guid = NULL; - if (as_provide_get_kind (prov) != AS_PROVIDE_KIND_FIRMWARE_FLASHED) - continue; - if (as_utils_guid_is_valid (value)) - continue; - guid = as_utils_guid_from_string (value); - as_provide_set_value (prov, guid); - } -} - -static void -fu_engine_vendor_quirk_release_version (FuEngine *self, AsApp *app) -{ - AsVersionParseFlag flags = AS_VERSION_PARSE_FLAG_USE_TRIPLET; - GPtrArray *releases; - const gchar *quirk; - const gchar *version_format; - - /* no quirk required */ - if (as_app_get_kind (app) != AS_APP_KIND_FIRMWARE) - return; - - /* fall back to the quirk database until all files have metadata */ - quirk = fu_quirks_lookup_by_id (self->quirks, - "DaemonVersionFormat=quad", - FU_QUIRKS_DAEMON_VERSION_FORMAT); - if (quirk != NULL) { - g_auto(GStrv) globs = g_strsplit (quirk, ",", -1); - for (guint i = 0; globs[i] != NULL; i++) { - if (fnmatch (globs[i], as_app_get_id (app), 0) == 0) { - flags = AS_VERSION_PARSE_FLAG_NONE; - break; - } - } - } - - /* specified in metadata */ - version_format = as_app_get_metadata_item (app, "LVFS::VersionFormat"); - if (g_strcmp0 (version_format, "quad") == 0) - flags = AS_VERSION_PARSE_FLAG_NONE; - - /* fix each release */ - releases = as_app_get_releases (app); - for (guint i = 0; i < releases->len; i++) { - AsRelease *rel; - const gchar *version; - guint64 ver_uint32; - g_autofree gchar *version_new = NULL; - - rel = g_ptr_array_index (releases, i); - version = as_release_get_version (rel); - if (version == NULL) - continue; - if (g_strstr_len (version, -1, ".") != NULL) - continue; - - /* metainfo files use hex and the LVFS uses decimal */ - ver_uint32 = fu_common_strtoull (version); - if (ver_uint32 == 0) - continue; - - /* convert to dotted decimal */ - version_new = as_utils_version_from_uint32 ((guint32) ver_uint32, flags); - as_release_set_version (rel, version_new); - } -} - -static gchar * -fu_engine_get_guids_from_store (AsStore *store) +void +fu_engine_idle_reset (FuEngine *self) { - AsProvide *prov; - GPtrArray *provides; - GPtrArray *apps; - GString *str = g_string_new (""); - - /* return a string with all the firmware apps in the store */ - apps = as_store_get_apps (store); - for (guint i = 0; i < apps->len; i++) { - AsApp *app = AS_APP (g_ptr_array_index (apps, i)); - provides = as_app_get_provides (app); - for (guint j = 0; j < provides->len; j++) { - prov = AS_PROVIDE (g_ptr_array_index (provides, j)); - if (as_provide_get_kind (prov) != AS_PROVIDE_KIND_FIRMWARE_FLASHED) - continue; - g_string_append_printf (str, "%s,", as_provide_get_value (prov)); - } - } - if (str->len == 0) { - g_string_free (str, TRUE); - return NULL; - } - g_string_truncate (str, str->len - 1); - return g_string_free (str, FALSE); + fu_idle_reset (self->idle); } static gchar * @@ -1217,9 +1238,14 @@ FwupdInstallFlags flags, GError **error) { + g_autoptr(FuIdleLocker) locker = NULL; g_autoptr(GPtrArray) devices = NULL; g_autoptr(GPtrArray) devices_new = NULL; + /* do not allow auto-shutdown during this time */ + locker = fu_idle_locker_new (self->idle, "performing update"); + g_assert (locker != NULL); + /* notify the plugins about the composite action */ devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); for (guint i = 0; i < install_tasks->len; i++) { @@ -1244,6 +1270,13 @@ } } + /* set all the device statuses back to unknown */ + for (guint i = 0; i < install_tasks->len; i++) { + FuInstallTask *task = g_ptr_array_index (install_tasks, i); + FuDevice *device = fu_install_task_get_device (task); + fu_device_set_status (device, FWUPD_STATUS_UNKNOWN); + } + /* get a new list of devices in case they replugged */ devices_new = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); for (guint i = 0; i < devices->len; i++) { @@ -1295,27 +1328,30 @@ FwupdInstallFlags flags, GError **error) { - AsApp *app = fu_install_task_get_app (task); - AsChecksum *csum_tmp; - AsRelease *rel; + XbNode *component = fu_install_task_get_component (task); FuDevice *device = fu_install_task_get_device (task); + FuPlugin *plugin; GBytes *blob_fw; - const gchar *tmp; - const gchar *version; + const gchar *tmp = NULL; + g_autofree gchar *release_key = NULL; + g_autofree gchar *version_orig = NULL; + g_autofree gchar *version_rel = NULL; g_autoptr(GBytes) blob_fw2 = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(XbNode) rel = NULL; g_return_val_if_fail (FU_IS_ENGINE (self), FALSE); g_return_val_if_fail (FU_IS_DEVICE (device), FALSE); - g_return_val_if_fail (AS_IS_APP (app), FALSE); + g_return_val_if_fail (XB_IS_NODE (component), FALSE); g_return_val_if_fail (blob_cab != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* not in bootloader mode */ if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER)) { const gchar *caption = NULL; - AsScreenshot *ss = as_app_get_screenshot_default (app); - if (ss != NULL) - caption = as_screenshot_get_caption (ss, NULL); + caption = xb_node_query_text (component, + "screenshots/screenshot/caption", + NULL); if (caption != NULL) { g_set_error (error, FWUPD_ERROR, @@ -1333,40 +1369,36 @@ } /* parse the DriverVer */ - rel = as_app_get_release_default (app); + rel = xb_node_query_first (component, "releases/release", &error_local); if (rel == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "No releases in the firmware component"); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "No releases in the firmware component: %s", + error_local->message); return FALSE; } /* get the blob */ - csum_tmp = as_release_get_checksum_by_target (rel, AS_CHECKSUM_TARGET_CONTENT); - tmp = as_checksum_get_filename (csum_tmp); - if (tmp == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "No checksum filename"); - return FALSE; - } + tmp = xb_node_query_attr (rel, "checksum[@target='content']", "filename", NULL); + if (tmp == NULL) + tmp = "firmware.bin"; /* not all devices have to use the same blob */ - blob_fw = as_release_get_blob (rel, tmp); + release_key = g_strdup_printf ("fwupd::ReleaseBlob(%s)", tmp); + blob_fw = xb_node_get_data (rel, release_key); if (blob_fw == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "Failed to get firmware blob"); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "Failed to get firmware blob using %s", tmp); return FALSE; } /* use a bubblewrap helper script to build the firmware */ - tmp = as_app_get_metadata_item (app, "fwupd::BuilderScript"); + tmp = g_object_get_data (G_OBJECT (component), "fwupd::BuilderScript"); if (tmp != NULL) { - const gchar *tmp2 = as_app_get_metadata_item (app, "fwupd::BuilderOutput"); + const gchar *tmp2 = g_object_get_data (G_OBJECT (component), "fwupd::BuilderOutput"); if (tmp2 == NULL) tmp2 = "firmware.bin"; blob_fw2 = fu_common_firmware_builder (blob_fw, tmp, tmp2, error); @@ -1376,10 +1408,134 @@ blob_fw2 = g_bytes_ref (blob_fw); } + /* get the plugin */ + plugin = fu_plugin_list_find_by_name (self->plugin_list, + fu_device_get_plugin (device), + error); + if (plugin == NULL) + return FALSE; + + /* add device to database */ + version_rel = fu_engine_get_release_version (self, component, rel); + if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0) { + g_autoptr(FwupdRelease) release_history = fwupd_release_new (); + g_autoptr(GHashTable) metadata_hash = NULL; + g_autoptr(GHashTable) os_release = NULL; + + /* add release data from os-release */ + os_release = fwupd_get_os_release (error); + if (os_release == NULL) + return FALSE; + + /* build the version metadata */ + metadata_hash = fu_engine_get_report_metadata (self); + fwupd_release_add_metadata (release_history, metadata_hash); + fwupd_release_add_metadata (release_history, + fu_plugin_get_report_metadata (plugin)); + tmp = xb_node_query_text (component, + "releases/release/checksum[@target='container']", + NULL); + if (tmp != NULL) { + fwupd_release_add_metadata_item (release_history, + "DistroId", tmp); + } + fwupd_release_add_checksum (release_history, tmp); + fwupd_release_set_version (release_history, version_rel); + fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED); + + /* add details from os-release as metadata */ + tmp = g_hash_table_lookup (os_release, "ID"); + if (tmp != NULL) { + fwupd_release_add_metadata_item (release_history, + "DistroId", tmp); + } + tmp = g_hash_table_lookup (os_release, "VERSION_ID"); + if (tmp != NULL) { + fwupd_release_add_metadata_item (release_history, + "DistroVersion", tmp); + } + tmp = g_hash_table_lookup (os_release, "VARIANT_ID"); + if (tmp != NULL) { + fwupd_release_add_metadata_item (release_history, + "DistroVariant", tmp); + } + if (!fu_history_add_device (self->history, device, release_history, error)) + return FALSE; + } + + /* just schedule this for the next reboot */ + if (flags & FWUPD_INSTALL_FLAG_OFFLINE) { + if (blob_cab == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "No cabinet archive to schedule"); + return FALSE; + } + return fu_plugin_runner_schedule_update (plugin, device, blob_cab, error); + } + /* install firmware blob */ - version = as_release_get_version (rel); - return fu_engine_install_blob (self, device, blob_cab, blob_fw2, - version, flags, error); + version_orig = g_strdup (fu_device_get_version (device)); + if (!fu_engine_install_blob (self, device, blob_fw2, flags, &error_local)) { + fu_device_set_status (device, FWUPD_STATUS_IDLE); + fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED); + fu_device_set_update_error (device, error_local->message); + if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0 && + !fu_history_modify_device (self->history, device, + FU_HISTORY_FLAGS_MATCH_OLD_VERSION | + FU_HISTORY_FLAGS_MATCH_NEW_VERSION, + error)) { + return FALSE; + } + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } + + /* update database */ + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT) || + fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) { + fu_device_set_update_state (device, FWUPD_UPDATE_STATE_NEEDS_REBOOT); + if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0 && + !fu_history_modify_device (self->history, device, + FU_HISTORY_FLAGS_MATCH_OLD_VERSION, + error)) + return FALSE; + /* success */ + return TRUE; + } + + /* for online updates, verify the version changed if not a re-install */ + if (version_rel != NULL && + g_strcmp0 (version_orig, version_rel) != 0 && + g_strcmp0 (version_orig, fu_device_get_version (device)) == 0) { + fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED); + fu_device_set_update_error (device, "device version not updated on success"); + if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0 && + !fu_history_modify_device (self->history, device, + FU_HISTORY_FLAGS_MATCH_OLD_VERSION, + error)) + return FALSE; + /* success */ + return TRUE; + } + + /* ensure the new version matched what we expected */ + if (version_rel != NULL && + g_strcmp0 (fu_device_get_version (device), version_rel) != 0) { + g_warning ("new device version '%s' was is not '%s', fixing up", + fu_device_get_version (device), version_rel); + fu_device_set_version (device, version_rel); + } + + /* success */ + fu_device_set_update_state (device, FWUPD_UPDATE_STATE_SUCCESS); + if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0 && + !fu_history_modify_device (self->history, device, + FU_HISTORY_FLAGS_MATCH_NEW_VERSION, + error)) + return FALSE; + return TRUE; } /** @@ -1399,278 +1555,257 @@ return fu_plugin_list_get_all (self->plugin_list); } -gboolean -fu_engine_install_blob (FuEngine *self, - FuDevice *device_orig, - GBytes *blob_cab, - GBytes *blob_fw2, - const gchar *version, - FwupdInstallFlags flags, - GError **error) +static FuDevice * +fu_engine_get_device_by_id (FuEngine *self, const gchar *device_id, GError **error) { - FuPlugin *plugin; - GPtrArray *plugins; - g_autofree gchar *device_id_orig = NULL; - g_autofree gchar *version_orig = NULL; - g_autoptr(FuDevice) device = g_object_ref (device_orig); - g_autoptr(FwupdRelease) release_history = fwupd_release_new (); - g_autoptr(GError) error_local = NULL; - g_autoptr(GHashTable) metadata_hash = NULL; - g_autoptr(GTimer) timer = g_timer_new (); + g_autoptr(FuDevice) device1 = NULL; + g_autoptr(FuDevice) device2 = NULL; - /* test the firmware is not an empty blob */ - if (g_bytes_get_size (blob_fw2) == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Firmware is invalid as has zero size"); - return FALSE; + /* find device */ + device1 = fu_device_list_get_by_id (self->device_list, device_id, error); + if (device1 == NULL) + return NULL; + + /* no replug required */ + if (!fu_device_has_flag (device1, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG)) + return g_steal_pointer (&device1); + + /* wait for device to disconnect and reconnect */ + if (!fu_device_list_wait_for_replug (self->device_list, device1, error)) { + g_prefix_error (error, "failed to wait for detach replug: "); + return NULL; } - /* we can only write history if we're providing a version number */ - if (version == NULL && (flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Version required if writing history"); - return FALSE; + /* get the new device */ + device2 = fu_device_list_get_by_id (self->device_list, device_id, error); + if (device2 == NULL) { + g_prefix_error (error, "failed to get device after replug: "); + return NULL; } - /* get the plugin */ - plugin = fu_plugin_list_find_by_name (self->plugin_list, - fu_device_get_plugin (device), - error); - if (plugin == NULL) - return FALSE; + /* success */ + return g_steal_pointer (&device2); +} - /* compare the versions of what we have installed */ - version_orig = g_strdup (fu_device_get_version (device)); +static gboolean +fu_engine_update_prepare (FuEngine *self, + FwupdInstallFlags flags, + const gchar *device_id, + GError **error) +{ + GPtrArray *plugins = fu_plugin_list_get_all (self->plugin_list); + g_autoptr(FuDevice) device = NULL; - /* signal to all the plugins the update is about to happen */ - plugins = fu_plugin_list_get_all (self->plugin_list); + /* the device and plugin both may have changed */ + device = fu_engine_get_device_by_id (self, device_id, error); + if (device == NULL) + return FALSE; for (guint j = 0; j < plugins->len; j++) { FuPlugin *plugin_tmp = g_ptr_array_index (plugins, j); if (!fu_plugin_runner_update_prepare (plugin_tmp, flags, device, error)) return FALSE; } + return TRUE; +} - /* save the chosen device ID in case the device goes away */ - device_id_orig = g_strdup (fu_device_get_id (device)); +static gboolean +fu_engine_update_cleanup (FuEngine *self, + FwupdInstallFlags flags, + const gchar *device_id, + GError **error) +{ + GPtrArray *plugins = fu_plugin_list_get_all (self->plugin_list); + g_autoptr(FuDevice) device = NULL; - /* in case another device caused us to go into replug before starting */ - g_clear_object (&device); - device = fu_device_list_get_by_id (self->device_list, device_id_orig, error); - if (device == NULL) { - g_prefix_error (error, "failed to get device ID after detach: "); - return FALSE; - } - if (!fu_device_list_wait_for_replug (self->device_list, device, error)) { - g_prefix_error (error, "failed to wait for detach replug: "); - return FALSE; - } - g_clear_object (&device); - device = fu_device_list_get_by_id (self->device_list, device_id_orig, error); - if (device == NULL) { - g_prefix_error (error, "failed to get device ID after detach replug: "); + /* the device and plugin both may have changed */ + device = fu_engine_get_device_by_id (self, device_id, error); + if (device == NULL) return FALSE; + for (guint j = 0; j < plugins->len; j++) { + FuPlugin *plugin_tmp = g_ptr_array_index (plugins, j); + if (!fu_plugin_runner_update_cleanup (plugin_tmp, flags, device, error)) + return FALSE; } + return TRUE; +} - /* mark this as modified even if we actually fail to do the update */ - fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC); +static gboolean +fu_engine_update_detach (FuEngine *self, const gchar *device_id, GError **error) +{ + FuPlugin *plugin; + g_autoptr(FuDevice) device = NULL; - /* build the version metadata */ - metadata_hash = fu_engine_get_report_metadata (self); - fwupd_release_add_metadata (release_history, metadata_hash); - fwupd_release_add_metadata (release_history, - fu_plugin_get_report_metadata (plugin)); + /* the device and plugin both may have changed */ + device = fu_engine_get_device_by_id (self, device_id, error); + if (device == NULL) + return FALSE; + plugin = fu_plugin_list_find_by_name (self->plugin_list, + fu_device_get_plugin (device), + error); + if (plugin == NULL) + return FALSE; + if (!fu_plugin_runner_update_detach (plugin, device, error)) + return FALSE; + return TRUE; +} - /* add device to database */ - if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0) { - g_autofree gchar *checksum = NULL; - checksum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, blob_cab); - fwupd_release_set_version (release_history, version); - fwupd_release_add_checksum (release_history, checksum); - fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED); - if (!fu_history_add_device (self->history, device, release_history, error)) - return FALSE; - } +static gboolean +fu_engine_update_attach (FuEngine *self, const gchar *device_id, GError **error) +{ + FuPlugin *plugin; + g_autoptr(FuDevice) device = NULL; - /* do the update */ - if (!fu_plugin_runner_update_detach (plugin, device, &error_local)) { - fu_device_set_update_error (device, error_local->message); - if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0 && - !fu_history_modify_device (self->history, device, - FU_HISTORY_FLAGS_MATCH_OLD_VERSION, - error)) { - return FALSE; - } - g_propagate_error (error, g_steal_pointer (&error_local)); + /* the device and plugin both may have changed */ + device = fu_engine_get_device_by_id (self, device_id, error); + if (device == NULL) { + g_prefix_error (error, "failed to get device after update: "); return FALSE; } - g_clear_object (&device); - device = fu_device_list_get_by_id (self->device_list, device_id_orig, error); + plugin = fu_plugin_list_find_by_name (self->plugin_list, + fu_device_get_plugin (device), + error); + if (plugin == NULL) + return FALSE; + if (!fu_plugin_runner_update_attach (plugin, device, error)) + return FALSE; + return TRUE; +} + +static gboolean +fu_engine_update_reload (FuEngine *self, const gchar *device_id, GError **error) +{ + FuPlugin *plugin; + g_autoptr(FuDevice) device = NULL; + + /* the device and plugin both may have changed */ + device = fu_engine_get_device_by_id (self, device_id, error); if (device == NULL) { - g_prefix_error (error, "failed to get device ID after detach: "); + g_prefix_error (error, "failed to get device after update: "); return FALSE; } - if (!fu_device_list_wait_for_replug (self->device_list, device, error)) { - g_prefix_error (error, "failed to wait for detach replug: "); + plugin = fu_plugin_list_find_by_name (self->plugin_list, + fu_device_get_plugin (device), + error); + if (plugin == NULL) + return FALSE; + if (!fu_plugin_runner_update_reload (plugin, device, error)) { + g_prefix_error (error, "failed to reload device: "); return FALSE; } - g_clear_object (&device); - device = fu_device_list_get_by_id (self->device_list, device_id_orig, error); + return TRUE; +} + +static gboolean +fu_engine_update (FuEngine *self, + const gchar *device_id, + GBytes *blob_fw2, + FwupdInstallFlags flags, + GError **error) +{ + FuPlugin *plugin; + g_autoptr(FuDevice) device = NULL; + + /* the device and plugin both may have changed */ + device = fu_engine_get_device_by_id (self, device_id, error); if (device == NULL) { - g_prefix_error (error, "failed to get device ID after detach replug: "); + g_prefix_error (error, "failed to get device after detach: "); return FALSE; } - if (!fu_plugin_runner_update (plugin, - device, - blob_cab, - blob_fw2, - flags, - &error_local)) { + plugin = fu_plugin_list_find_by_name (self->plugin_list, + fu_device_get_plugin (device), + error); + if (plugin == NULL) + return FALSE; + if (!fu_plugin_runner_update (plugin, device, blob_fw2, flags, error)) { g_autoptr(GError) error_attach = NULL; + g_autoptr(GError) error_cleanup = NULL; - /* save to database */ - fu_device_set_update_error (device, error_local->message); - if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0 && - !fu_history_modify_device (self->history, device, - FU_HISTORY_FLAGS_MATCH_OLD_VERSION, - error)) { - return FALSE; - } - g_propagate_error (error, g_steal_pointer (&error_local)); - - /* attack back into runtime */ + /* attack back into runtime then cleanup */ if (!fu_plugin_runner_update_attach (plugin, device, &error_attach)) { g_warning ("failed to attach device after failed update: %s", error_attach->message); } - for (guint j = 0; j < plugins->len; j++) { - FuPlugin *plugin_tmp = g_ptr_array_index (plugins, j); - g_autoptr(GError) error_cleanup = NULL; - if (!fu_plugin_runner_update_cleanup (plugin_tmp, - flags, - device, - &error_cleanup)) { - g_warning ("failed to update-cleanup " - "after failed update: %s", - error_cleanup->message); - } + if (!fu_engine_update_cleanup (self, flags, device_id, &error_cleanup)) { + g_warning ("failed to update-cleanup after failed update: %s", + error_cleanup->message); } - fu_device_set_status (device, FWUPD_STATUS_IDLE); - return FALSE; - } - g_clear_object (&device); - device = fu_device_list_get_by_id (self->device_list, device_id_orig, error); - if (device == NULL) { - g_prefix_error (error, "failed to get device ID after update: "); - return FALSE; - } - if (!fu_device_list_wait_for_replug (self->device_list, device, error)) { - g_prefix_error (error, "failed to wait for replug after update: "); return FALSE; } - g_clear_object (&device); - device = fu_device_list_get_by_id (self->device_list, device_id_orig, error); - if (device == NULL) { - g_prefix_error (error, "failed to get device ID after post-update restart: "); + return TRUE; +} + +gboolean +fu_engine_install_blob (FuEngine *self, + FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + guint retries = 0; + g_autofree gchar *device_id = NULL; + g_autoptr(GTimer) timer = g_timer_new (); + + /* test the firmware is not an empty blob */ + if (g_bytes_get_size (blob_fw) == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Firmware is invalid as has zero size"); return FALSE; } - if (!fu_plugin_runner_update_attach (plugin, device, &error_local)) { - fu_device_set_update_error (device, error_local->message); - if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0 && - !fu_history_modify_device (self->history, device, - FU_HISTORY_FLAGS_MATCH_OLD_VERSION | - FU_HISTORY_FLAGS_MATCH_NEW_VERSION, - error)) { + + /* mark this as modified even if we actually fail to do the update */ + fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC); + + /* plugins can set FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED to run again, but they + * must return TRUE rather than an error */ + device_id = g_strdup (fu_device_get_id (device)); + do { + /* check for a loop */ + if (++retries > 5) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "aborting device write loop, limit 5"); return FALSE; } - g_propagate_error (error, g_steal_pointer (&error_local)); - return FALSE; - } - g_clear_object (&device); - device = fu_device_list_get_by_id (self->device_list, device_id_orig, error); - if (device == NULL) { - g_prefix_error (error, "failed to get device ID after attach: "); - return FALSE; - } - if (!fu_device_list_wait_for_replug (self->device_list, device, error)) { - g_prefix_error (error, "failed to wait for replug after attach: "); - return FALSE; - } - /* get the new version number */ - g_clear_object (&device); - device = fu_device_list_get_by_id (self->device_list, device_id_orig, error); - if (device == NULL) { - g_prefix_error (error, "failed to get device ID after attach replug: "); - return FALSE; - } - if (!fu_plugin_runner_update_reload (plugin, device, error)) { - g_prefix_error (error, "failed to reload device: "); + /* don't rely on a plugin clearing this */ + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED); + + /* signal to all the plugins the update is about to happen */ + if (!fu_engine_update_prepare (self, flags, device_id, error)) + return FALSE; + + /* detach to bootloader mode */ + if (!fu_engine_update_detach (self, device_id, error)) + return FALSE; + + /* install */ + if (!fu_engine_update (self, device_id, blob_fw, flags, error)) + return FALSE; + + /* attach into runtime mode */ + if (!fu_engine_update_attach (self, device_id, error)) + return FALSE; + + } while (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED)); + + /* get the new version number */ + if (!fu_engine_update_reload (self, device_id, error)) return FALSE; - } /* signal to all the plugins the update has happened */ - for (guint j = 0; j < plugins->len; j++) { - FuPlugin *plugin_tmp = g_ptr_array_index (plugins, j); - g_autoptr(GError) error_cleanup = NULL; - if (!fu_plugin_runner_update_cleanup (plugin_tmp, flags, device, &error_cleanup)) { - g_warning ("failed to update-cleanup: %s", - error_cleanup->message); - } - } + if (!fu_engine_update_cleanup (self, flags, device_id, error)) + return FALSE; /* make the UI update */ fu_engine_set_status (self, FWUPD_STATUS_IDLE); fu_engine_emit_changed (self); g_debug ("Updating %s took %f seconds", fu_device_get_name (device), g_timer_elapsed (timer, NULL)); - - /* update database */ - if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT)) { - fu_device_set_update_state (device, FWUPD_UPDATE_STATE_NEEDS_REBOOT); - if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0 && - !fu_history_modify_device (self->history, device, - FU_HISTORY_FLAGS_MATCH_OLD_VERSION, - error)) - return FALSE; - /* success */ - return TRUE; - } - - /* for online updates, verify the version changed if not a re-install */ - if (version != NULL && - g_strcmp0 (version_orig, version) != 0 && - g_strcmp0 (version_orig, fu_device_get_version (device)) == 0) { - fu_device_set_update_error (device, "device version not updated on success"); - if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0 && - !fu_history_modify_device (self->history, device, - FU_HISTORY_FLAGS_MATCH_OLD_VERSION, - error)) - return FALSE; - /* success */ - return TRUE; - } - - /* ensure the new version matched what we expected */ - if (version != NULL && - g_strcmp0 (fu_device_get_version (device), version) != 0) { - g_warning ("new device version '%s' was is not '%s', fixing up", - fu_device_get_version (device), version); - fu_device_set_version (device, version); - } - - /* success */ - if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0 && - !fu_history_modify_device (self->history, device, - FU_HISTORY_FLAGS_MATCH_NEW_VERSION, - error)) - return FALSE; - fu_device_set_update_state (device, FWUPD_UPDATE_STATE_SUCCESS); return TRUE; } @@ -1727,98 +1862,125 @@ return NULL; } -/* add releases that do not exist from a higher priority remote */ -static void -fu_engine_merge_component_releases (AsApp *app_old, AsApp *app) +/* for the self tests */ +void +fu_engine_set_silo (FuEngine *self, XbSilo *silo) { - GPtrArray *releases = as_app_get_releases (app); - for (guint j = 0; j < releases->len; j++) { - AsRelease *release = g_ptr_array_index (releases, j); - AsRelease *release_old; - const gchar *version = as_release_get_version (release); - release_old = as_app_get_release_by_version (app_old, version); - if (release_old != NULL) - continue; - g_debug ("adding release %s to existing %s", - version, as_app_get_id (app_old)); - as_app_add_release (app_old, release); - } + g_return_if_fail (FU_IS_ENGINE (self)); + g_return_if_fail (XB_IS_SILO (silo)); + g_set_object (&self->silo, silo); } -gboolean -fu_engine_load_metadata_from_file (FuEngine *self, - const gchar *path, - const gchar *remote_id, - GError **error) +static gboolean +fu_engine_is_device_supported (FuEngine *self, FuDevice *device) { - GPtrArray *apps; - g_autoptr(AsStore) store = NULL; - g_autoptr(GFile) file = NULL; - g_autoptr(GBytes) remote_blob = NULL; - g_autoptr(GPtrArray) apps_new = NULL; + g_autoptr(XbNode) component = NULL; - /* load the store locally until we know it is valid */ - store = as_store_new (); - file = g_file_new_for_path (path); - if (!as_store_from_file (store, file, NULL, NULL, error)) + /* sanity check */ + if (self->silo == NULL) { + g_critical ("FuEngine silo not set up"); return FALSE; + } - /* save the remote to the release */ - if (remote_id != NULL && remote_id[0] != '\0') - remote_blob = g_bytes_new (remote_id, strlen (remote_id) + 1); + /* no device version */ + if (fu_device_get_version (device) == NULL) + return FALSE; - /* add the new application from the store */ - apps = as_store_get_apps (store); - apps_new = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - for (guint i = 0; i < apps->len; i++) { - AsApp *app = g_ptr_array_index (apps, i); - AsApp *app_old = as_store_get_app_by_id (self->store, as_app_get_id (app)); + /* match the GUIDs in the XML */ + component = fu_engine_get_component_by_guids (self, device); + if (component == NULL) + return FALSE; - /* save the remote-id to all the releases for this component */ - if (remote_blob != NULL) { - GPtrArray *releases = as_app_get_releases (app); - for (guint j = 0; j < releases->len; j++) { - AsRelease *release = g_ptr_array_index (releases, j); - as_release_set_blob (release, - "fwupd::RemoteId", - remote_blob); - } - } + /* success */ + return TRUE; +} - /* possibly convert the version from 0x to dotted */ - fu_engine_vendor_quirk_release_version (self, app); +static gboolean +fu_engine_appstream_upgrade_cb (XbBuilderFixup *self, + XbBuilderNode *bn, + gpointer user_data, + GError **error) +{ + if (g_strcmp0 (xb_builder_node_get_element (bn), "metadata") == 0) + xb_builder_node_set_element (bn, "custom"); + return TRUE; +} - /* possibly convert the flashed provide to a GUID */ - fu_engine_vendor_fixup_provide_value (app); +static XbBuilderSource * +fu_engine_create_metadata_builder_source (FuEngine *self, + const gchar *fn, + GError **error) +{ + g_autoptr(GBytes) blob = NULL; + g_autoptr(XbSilo) silo = NULL; + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + g_autofree gchar *xml = NULL; - /* merge in new releases if already known */ - if (app_old != NULL) { - fu_engine_merge_component_releases (app_old, app); - continue; - } - g_ptr_array_add (apps_new, g_object_ref (app)); - } + g_debug ("building metadata for %s", fn); + blob = fu_common_get_contents_bytes (fn, error); + if (blob == NULL) + return NULL; - /* add in one operation to avoid 'n' "Emitting ::changed()" events */ - as_store_add_apps (self->store, apps_new); - return TRUE; + /* convert the silo for the CAB into a XbBuilderSource */ + silo = fu_engine_get_silo_from_blob (self, blob, error); + if (silo == NULL) + return NULL; + xml = xb_silo_export (silo, XB_NODE_EXPORT_FLAG_NONE, error); + if (xml == NULL) + return NULL; + if (!xb_builder_source_load_xml (source, xml, + XB_BUILDER_SOURCE_FLAG_NONE, + error)) + return NULL; + return g_steal_pointer (&source); } static gboolean -fu_engine_is_device_supported (FuEngine *self, FuDevice *device) +fu_engine_create_metadata (FuEngine *self, XbBuilder *builder, + FwupdRemote *remote, GError **error) { - AsApp *app; + g_autoptr(GPtrArray) files = NULL; + const gchar *path; - /* no device version */ - if (fu_device_get_version (device) == NULL) - return FALSE; + /* find all files in directory */ + path = fwupd_remote_get_filename_cache (remote); + files = fu_common_get_files_recursive (path, error); + if (files == NULL) + return FALSE; + + /* add each source */ + for (guint i = 0; i < files->len; i++) { + g_autoptr(XbBuilderNode) custom = NULL; + g_autoptr(XbBuilderSource) source = NULL; + g_autoptr(GError) error_local = NULL; + const gchar *fn = g_ptr_array_index (files, i); - /* match the GUIDs in the XML */ - app = fu_engine_store_get_app_by_guids (self->store, device); - if (app == NULL) - return FALSE; + /* check is cab file */ + if (!g_str_has_suffix (fn, ".cab")) { + g_debug ("ignoring: %s", fn); + continue; + } - /* success */ + /* build source for file */ + source = fu_engine_create_metadata_builder_source (self, fn, &error_local); + if (source == NULL) { + g_warning ("%s", error_local->message); + continue; + } + + /* add metadata */ + custom = xb_builder_node_new ("custom"); + xb_builder_node_insert_text (custom, + "value", fn, + "key", "fwupd::FilenameCache", + NULL); + xb_builder_node_insert_text (custom, + "value", fwupd_remote_get_id (remote), + "key", "fwupd::RemoteId", + NULL); + xb_builder_source_set_info (source, custom); + xb_builder_import_source (builder, source); + } return TRUE; } @@ -1826,17 +1988,33 @@ fu_engine_load_metadata_store (FuEngine *self, GError **error) { GPtrArray *remotes; - g_autofree gchar *guids_str = NULL; + g_autofree gchar *cachedirpkg = NULL; + g_autofree gchar *xmlbfn = NULL; + g_autoptr(GFile) xmlb = NULL; g_autoptr(GPtrArray) devices = NULL; + g_autoptr(GPtrArray) components = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); + + /* clear existing silo */ + g_clear_object (&self->silo); - /* clear existing store */ - as_store_remove_all (self->store); + /* verbose profiling */ + if (g_getenv ("FWUPD_VERBOSE") != NULL) { + xb_builder_set_profile_flags (builder, + XB_SILO_PROFILE_FLAG_XPATH | + XB_SILO_PROFILE_FLAG_DEBUG); + } /* load each enabled metadata file */ remotes = fu_config_get_remotes (self->config); for (guint i = 0; i < remotes->len; i++) { const gchar *path = NULL; g_autoptr(GError) error_local = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(XbBuilderFixup) fixup = NULL; + g_autoptr(XbBuilderNode) custom = NULL; + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + FwupdRemote *remote = g_ptr_array_index (remotes, i); if (!fwupd_remote_get_enabled (remote)) { g_debug ("remote %s not enabled, so skipping", @@ -1848,29 +2026,77 @@ g_debug ("no %s, so skipping", path); continue; } - if (!fu_engine_load_metadata_from_file (self, path, - fwupd_remote_get_id (remote), - &error_local)) { + + /* generate all metadata on demand */ + if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DIRECTORY) { + g_debug ("building metadata for remote '%s'", + fwupd_remote_get_id (remote)); + if (!fu_engine_create_metadata (self, builder, remote, &error_local)) { + g_warning ("failed to generate remote %s: %s", + fwupd_remote_get_id (remote), + error_local->message); + } + continue; + } + + /* save the remote-id in the custom metadata space */ + file = g_file_new_for_path (path); + if (!xb_builder_source_load_file (source, file, + XB_BUILDER_SOURCE_FLAG_NONE, + NULL, &error_local)) { g_warning ("failed to load remote %s: %s", fwupd_remote_get_id (remote), error_local->message); continue; } - } - /* print what we've got */ - g_debug ("%u components now in store", as_store_get_size (self->store)); + /* fix up any legacy installed files */ + fixup = xb_builder_fixup_new ("AppStreamUpgrade", + fu_engine_appstream_upgrade_cb, + self, NULL); + xb_builder_fixup_set_max_depth (fixup, 3); + xb_builder_source_add_fixup (source, fixup); + + /* add metadata */ + custom = xb_builder_node_new ("custom"); + xb_builder_node_insert_text (custom, + "value", path, + "key", "fwupd::FilenameCache", + NULL); + xb_builder_node_insert_text (custom, + "value", fwupd_remote_get_id (remote), + "key", "fwupd::RemoteId", + NULL); + xb_builder_source_set_info (source, custom); + + /* we need to watch for changes? */ + xb_builder_import_source (builder, source); + } + + /* ensure silo is up to date */ + cachedirpkg = fu_common_get_path (FU_PATH_KIND_CACHEDIR_PKG); + xmlbfn = g_build_filename (cachedirpkg, "metadata.xmlb", NULL); + xmlb = g_file_new_for_path (xmlbfn); + self->silo = xb_builder_ensure (builder, xmlb, + XB_BUILDER_COMPILE_FLAG_IGNORE_INVALID, + NULL, error); + if (self->silo == NULL) + return FALSE; - /* update the list of supported GUIDs */ - g_ptr_array_set_size (self->supported_guids, 0); - guids_str = fu_engine_get_guids_from_store (self->store); - if (guids_str != NULL) { - g_auto(GStrv) guids = g_strsplit (guids_str, ",", -1); - for (guint i = 0; guids[i] != NULL; i++) { - g_ptr_array_add (self->supported_guids, - g_steal_pointer (&guids[i])); - } - } + /* print what we've got */ + components = xb_silo_query (self->silo, "components/component", 0, NULL); + if (components != NULL) + g_debug ("%u components now in silo", components->len); + + /* build the index */ + if (!xb_silo_query_build_index (self->silo, + "components/component/provides/firmware", + "type", error)) + return FALSE; + if (!xb_silo_query_build_index (self->silo, + "components/component/provides/firmware", + NULL, error)) + return FALSE; /* did any devices SUPPORTED state change? */ devices = fu_device_list_get_all (self->device_list); @@ -2044,21 +2270,19 @@ } /** - * fu_engine_get_store_from_blob: + * fu_engine_get_silo_from_blob: * @self: A #FuEngine * @blob_cab: A #GBytes * @error: A #GError, or %NULL * - * Creates an AppStream store from a .cab file blob. + * Creates a silo from a .cab file blob. * - * Returns: (transfer container): a #AsStore, or %NULL + * Returns: (transfer container): a #XbSilo, or %NULL **/ -AsStore * -fu_engine_get_store_from_blob (FuEngine *self, GBytes *blob_cab, GError **error) +XbSilo * +fu_engine_get_silo_from_blob (FuEngine *self, GBytes *blob_cab, GError **error) { - GPtrArray *apps; - g_autofree gchar *checksum = NULL; - g_autoptr(AsStore) store = NULL; + g_autoptr(XbSilo) silo = NULL; g_return_val_if_fail (FU_IS_ENGINE (self), NULL); g_return_val_if_fail (blob_cab != NULL, NULL); @@ -2066,56 +2290,47 @@ /* load file */ fu_engine_set_status (self, FWUPD_STATUS_DECOMPRESSING); - store = fu_common_store_from_cab_bytes (blob_cab, - fu_engine_get_archive_size_max (self), - error); - if (store == NULL) + silo = fu_common_cab_build_silo (blob_cab, + fu_engine_get_archive_size_max (self), + error); + if (silo == NULL) return NULL; - /* fix all the apps */ - apps = as_store_get_apps (store); - for (guint i = 0; i < apps->len; i++) { - AsApp *app = g_ptr_array_index (apps, i); - - /* possibly convert the version from 0x to dotted */ - fu_engine_vendor_quirk_release_version (self, app); - - /* possibly convert the flashed provide to a GUID */ - fu_engine_vendor_fixup_provide_value (app); - } - - /* get a checksum of the file and use it as the origin */ - checksum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA256, blob_cab); - as_store_set_origin (store, checksum); - fu_engine_set_status (self, FWUPD_STATUS_IDLE); - return g_steal_pointer (&store); + return g_steal_pointer (&silo); } static FwupdDevice * -fu_engine_get_result_from_app (FuEngine *self, AsApp *app, GError **error) +fu_engine_get_result_from_component (FuEngine *self, XbNode *component, GError **error) { FwupdTrustFlags trust_flags = FWUPD_TRUST_FLAG_NONE; - AsRelease *release; - GPtrArray *provides; g_autoptr(FuInstallTask) task = NULL; g_autoptr(FwupdDevice) dev = NULL; g_autoptr(FwupdRelease) rel = NULL; g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) provides = NULL; + g_autoptr(XbNode) description = NULL; + g_autoptr(XbNode) release = NULL; dev = fwupd_device_new (); - provides = as_app_get_provides (app); + provides = xb_node_query (component, + "provides/firmware[@type=$'flashed']", + 0, &error_local); + if (provides == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to get release: %s", + error_local->message); + return NULL; + } for (guint i = 0; i < provides->len; i++) { - AsProvide *prov = AS_PROVIDE (g_ptr_array_index (provides, i)); + XbNode *prov = XB_NODE (g_ptr_array_index (provides, i)); const gchar *guid; g_autoptr(FuDevice) device = NULL; - /* not firmware */ - if (as_provide_get_kind (prov) != AS_PROVIDE_KIND_FIRMWARE_FLASHED) - continue; - /* is a online or offline update appropriate */ - guid = as_provide_get_value (prov); + guid = xb_node_get_text (prov); if (guid == NULL) continue; device = fu_device_list_get_by_guid (self->device_list, guid, NULL); @@ -2137,14 +2352,24 @@ } /* check we can install it */ - task = fu_install_task_new (NULL, app); + task = fu_install_task_new (NULL, component); if (!fu_engine_check_requirements (self, task, FWUPD_INSTALL_FLAG_NONE, error)) return NULL; /* verify trust */ - release = as_app_get_release_default (app); + release = xb_node_query_first (component, + "releases/release", + &error_local); + if (release == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to get release: %s", + error_local->message); + return NULL; + } if (!fu_keyring_get_release_trust_flags (release, &trust_flags, &error_local)) { @@ -2160,10 +2385,18 @@ } /* create a result with all the metadata in */ - fwupd_device_set_description (dev, as_app_get_description (app, NULL)); + description = xb_node_query_first (component, "description", NULL); + if (description != NULL) { + g_autofree gchar *xml = NULL; + xml = xb_node_export (description, + XB_NODE_EXPORT_FLAG_ONLY_CHILDREN, + NULL); + if (xml != NULL) + fwupd_device_set_description (dev, xml); + } rel = fwupd_release_new (); fwupd_release_set_trust_flags (rel, trust_flags); - fu_engine_set_release_from_appstream (self, rel, app, release); + fu_engine_set_release_from_appstream (self, rel, component, release); fwupd_device_add_release (dev, rel); return g_steal_pointer (&dev); } @@ -2183,53 +2416,61 @@ GPtrArray * fu_engine_get_details (FuEngine *self, gint fd, GError **error) { - GPtrArray *apps; const gchar *remote_id; g_autofree gchar *csum = NULL; - g_autoptr(AsStore) store = NULL; g_autoptr(GBytes) blob = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) components = NULL; g_autoptr(GPtrArray) details = NULL; + g_autoptr(XbSilo) silo = NULL; g_return_val_if_fail (FU_IS_ENGINE (self), NULL); g_return_val_if_fail (fd > 0, NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); - /* get all apps */ + /* get all components */ blob = fu_common_get_contents_fd (fd, fu_engine_get_archive_size_max (self), error); if (blob == NULL) return NULL; - store = fu_engine_get_store_from_blob (self, blob, error); - if (store == NULL) + silo = fu_engine_get_silo_from_blob (self, blob, error); + if (silo == NULL) return NULL; - apps = as_store_get_apps (store); - if (apps->len == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "no components"); + components = xb_silo_query (silo, "components/component", 0, &error_local); + if (components == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no components: %s", + error_local->message); return NULL; } + /* build the index */ + if (!xb_silo_query_build_index (silo, "components/component/provides/firmware", + "type", error)) + return FALSE; + if (!xb_silo_query_build_index (silo, "components/component/provides/firmware", + NULL, error)) + return FALSE; + /* does this exist in any enabled remote */ csum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, blob); remote_id = fu_engine_get_remote_id_for_checksum (self, csum); /* create results with all the metadata in */ details = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - for (guint i = 0; i < apps->len; i++) { - AsApp *app = g_ptr_array_index (apps, i); + for (guint i = 0; i < components->len; i++) { + XbNode *component = g_ptr_array_index (components, i); FwupdDevice *dev; - - as_app_set_origin (app, as_store_get_origin (store)); - dev = fu_engine_get_result_from_app (self, app, error); + dev = fu_engine_get_result_from_component (self, component, error); if (dev == NULL) return NULL; if (remote_id != NULL) { FwupdRelease *rel = fwupd_device_get_release_default (dev); fwupd_release_set_remote_id (rel, remote_id); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_SUPPORTED); + fwupd_device_add_flag (dev, FWUPD_DEVICE_FLAG_SUPPORTED); } g_ptr_array_add (details, dev); } @@ -2384,44 +2625,106 @@ return g_ptr_array_ref (remotes); } +/** + * fu_engine_get_remote_by_id: + * @self: A #FuEngine + * @remote_id: A string representation of a remote + * @error: A #GError, or %NULL + * + * Gets the FwupdRemote object. + * + * Returns: FwupdRemote + **/ +FwupdRemote * +fu_engine_get_remote_by_id (FuEngine *self, const gchar *remote_id, GError **error) +{ + g_autoptr(GPtrArray) remotes = NULL; + + remotes = fu_engine_get_remotes (self, error); + if (remotes == NULL) + return NULL; + + for (guint i = 0; i < remotes->len; i++) { + FwupdRemote *remote = g_ptr_array_index (remotes, i); + if (g_strcmp0 (remote_id, fwupd_remote_get_id (remote)) == 0) + return remote; + } + + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Couldn't find remote %s", remote_id); + + return NULL; +} + + static gint fu_engine_sort_releases_cb (gconstpointer a, gconstpointer b) { FwupdRelease *rel_a = FWUPD_RELEASE (*((FwupdRelease **) a)); FwupdRelease *rel_b = FWUPD_RELEASE (*((FwupdRelease **) b)); - return as_utils_vercmp (fwupd_release_get_version (rel_b), + return fu_common_vercmp (fwupd_release_get_version (rel_b), fwupd_release_get_version (rel_a)); } -static AsApp * -fu_engine_filter_apps_by_requirements (FuEngine *self, GPtrArray *apps, - FuDevice *device, GError **error) +static gboolean +fu_engine_add_releases_for_device_component (FuEngine *self, + FuDevice *device, + XbNode *component, + GPtrArray *releases, + GError **error) { - g_autoptr(GError) error_all = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(FuInstallTask) task = fu_install_task_new (device, component); + g_autoptr(GPtrArray) releases_tmp = NULL; - /* find the first component that passes all the requirements */ - for (guint i = 0; i < apps->len; i++) { - AsApp *app_tmp = AS_APP (g_ptr_array_index (apps, i)); - g_autoptr(GError) error_local = NULL; - g_autoptr(FuInstallTask) task = fu_install_task_new (device, app_tmp); - if (!fu_engine_check_requirements (self, task, - FWUPD_INSTALL_FLAG_ALLOW_REINSTALL | - FWUPD_INSTALL_FLAG_ALLOW_OLDER, - &error_local)) { - if (error_all == NULL) { - error_all = g_steal_pointer (&error_local); - continue; - } - /* assume the domain and code is the same */ - g_prefix_error (&error_all, "%s, ", error_local->message); + if (!fu_engine_check_requirements (self, task, + FWUPD_INSTALL_FLAG_ALLOW_REINSTALL | + FWUPD_INSTALL_FLAG_ALLOW_OLDER, + error)) + return FALSE; + + /* get all releases */ + releases_tmp = xb_node_query (component, "releases/release", 0, &error_local); + if (releases_tmp == NULL) { + if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + return TRUE; + if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) + return TRUE; + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } + for (guint i = 0; i < releases_tmp->len; i++) { + XbNode *release = g_ptr_array_index (releases_tmp, i); + const gchar *update_message; + GPtrArray *checksums; + g_autoptr(FwupdRelease) rel = fwupd_release_new (); + + /* create new FwupdRelease for the XbNode */ + fu_engine_set_release_from_appstream (self, rel, component, release); + + /* fall back to quirk-provided value */ + if (fwupd_release_get_install_duration (rel) == 0) + fwupd_release_set_install_duration (rel, fu_device_get_install_duration (device)); + + /* invalid */ + if (fwupd_release_get_uri (rel) == NULL) continue; + checksums = fwupd_release_get_checksums (rel); + if (checksums->len == 0) + continue; + + /* add update message if exists but device doesn't already have one */ + update_message = fwupd_release_get_update_message (rel); + if (fwupd_device_get_update_message (FWUPD_DEVICE (device)) == NULL && + update_message != NULL) { + fwupd_device_set_update_message (FWUPD_DEVICE (device), update_message); } - return g_object_ref (app_tmp); + /* success */ + g_ptr_array_add (releases, g_steal_pointer (&rel)); } - /* return the compound error */ - g_propagate_error (error, g_steal_pointer (&error_all)); - return NULL; + /* success */ + return TRUE; } static GPtrArray * @@ -2430,6 +2733,10 @@ GPtrArray *device_guids; GPtrArray *releases; const gchar *version; + g_autoptr(GError) error_all = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) components = NULL; + g_autoptr(GString) xpath = g_string_new (NULL); /* get device version */ version = fu_device_get_version (device); @@ -2452,46 +2759,61 @@ return NULL; } - releases = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + /* get all the components that provide any of these GUIDs */ device_guids = fu_device_get_guids (device); for (guint i = 0; i < device_guids->len; i++) { - GPtrArray *releases_tmp; - g_autoptr(AsApp) app = NULL; - g_autoptr(GPtrArray) apps = NULL; const gchar *guid = g_ptr_array_index (device_guids, i); - - /* get all the components that provide this GUID */ - apps = _as_store_get_apps_by_provide (self->store, - AS_PROVIDE_KIND_FIRMWARE_FLASHED, - guid); - if (apps->len == 0) - continue; - - /* filter by requirements */ - app = fu_engine_filter_apps_by_requirements (self, apps, device, error); - if (app == NULL) + xb_string_append_union (xpath, + "components/component/" + "provides/firmware[@type=$'flashed'][text()=$'%s']/" + "../..", guid); + } + components = xb_silo_query (self->silo, xpath->str, 0, &error_local); + if (components == NULL) { + if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) || + g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "No releases for %s", + fu_device_get_name (device)); return NULL; + } + g_propagate_error (error, g_steal_pointer (&error_local)); + return NULL; + } - /* get all releases */ - releases_tmp = as_app_get_releases (app); - for (guint j = 0; j < releases_tmp->len; j++) { - AsRelease *release = g_ptr_array_index (releases_tmp, j); - GPtrArray *checksums; - g_autoptr(FwupdRelease) rel = fwupd_release_new (); - - /* create new FwupdRelease for the AsRelease */ - fu_engine_set_release_from_appstream (self, rel, app, release); - - /* invalid */ - if (fwupd_release_get_uri (rel) == NULL) - continue; - checksums = fwupd_release_get_checksums (rel); - if (checksums->len == 0) + /* find all the releases that pass all the requirements */ + releases = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + for (guint i = 0; i < components->len; i++) { + XbNode *component = XB_NODE (g_ptr_array_index (components, i)); + g_autoptr(GError) error_tmp = NULL; + if (!fu_engine_add_releases_for_device_component (self, + device, + component, + releases, + &error_tmp)) { + if (error_all == NULL) { + error_all = g_steal_pointer (&error_tmp); continue; + } + + /* assume the domain and code is the same */ + g_prefix_error (&error_all, "%s, ", error_tmp->message); + } + } - /* success */ - g_ptr_array_add (releases, g_steal_pointer (&rel)); + /* return the compound error */ + if (releases->len == 0) { + if (error_all != NULL) { + g_propagate_error (error, g_steal_pointer (&error_all)); + return NULL; } + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "No valid releases found for device"); + return NULL; } return releases; } @@ -2573,7 +2895,7 @@ gint vercmp; /* only include older firmware */ - vercmp = as_utils_vercmp (fwupd_release_get_version (rel_tmp), + vercmp = fu_common_vercmp (fwupd_release_get_version (rel_tmp), fu_device_get_version (device)); if (vercmp == 0) { g_string_append_printf (error_str, "%s=same, ", @@ -2594,7 +2916,7 @@ /* don't show releases we are not allowed to dowgrade to */ if (fu_device_get_version_lowest (device) != NULL) { - if (as_utils_vercmp (fwupd_release_get_version (rel_tmp), + if (fu_common_vercmp (fwupd_release_get_version (rel_tmp), fu_device_get_version_lowest (device)) <= 0) { g_string_append_printf (error_str, "%s=lowest, ", fwupd_release_get_version (rel_tmp)); @@ -2676,7 +2998,7 @@ gint vercmp; /* only include older firmware */ - vercmp = as_utils_vercmp (fwupd_release_get_version (rel_tmp), + vercmp = fu_common_vercmp (fwupd_release_get_version (rel_tmp), fu_device_get_version (device)); if (vercmp == 0) { g_string_append_printf (error_str, "%s=same, ", @@ -3014,12 +3336,15 @@ /* if this device is locked get some metadata from AppStream */ if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_LOCKED)) { - AsApp *app = fu_engine_store_get_app_by_guids (self->store, device); - if (app != NULL) { - AsRelease *release = as_app_get_release_default (app); + g_autoptr(XbNode) component = fu_engine_get_component_by_guids (self, device); + if (component != NULL) { + g_autoptr(XbNode) release = NULL; + release = xb_node_query_first (component, + "releases/release", + NULL); if (release != NULL) { g_autoptr(FwupdRelease) rel = fwupd_release_new (); - fu_engine_set_release_from_appstream (self, rel, app, release); + fu_engine_set_release_from_appstream (self, rel, component, release); fu_device_add_release (device, rel); } } @@ -3042,13 +3367,24 @@ if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REGISTERED)) fu_engine_plugin_device_register (self, device); + /* create new device */ + fu_device_list_add (self->device_list, device); + /* match the metadata at this point so clients can tell if the * device is worthy */ if (fu_engine_is_device_supported (self, device)) fu_device_add_flag (device, FWUPD_DEVICE_FLAG_SUPPORTED); +} - /* create new device */ - fu_device_list_add (self->device_list, device); +static void +fu_engine_plugin_rules_changed_cb (FuPlugin *plugin, gpointer user_data) +{ + FuEngine *self = FU_ENGINE (user_data); + GPtrArray *rules = fu_plugin_get_rules (plugin, FU_PLUGIN_RULE_INHIBITS_IDLE); + for (guint j = 0; j < rules->len; j++) { + const gchar *tmp = g_ptr_array_index (rules, j); + fu_idle_inhibit (self->idle, tmp); + } } static void @@ -3250,10 +3586,22 @@ duration, self->coldplug_delay); } -/* for the self tests to use */ +/* this is called by the self tests as well */ void fu_engine_add_plugin (FuEngine *self, FuPlugin *plugin) { + /* plugin does not match built version */ + if (fu_plugin_get_build_hash (plugin) == NULL) { + const gchar *name = fu_plugin_get_name (plugin); + g_warning ("%s should call fu_plugin_set_build_hash()", name); + self->tainted = TRUE; + } else if (g_strcmp0 (fu_plugin_get_build_hash (plugin), FU_BUILD_HASH) != 0) { + const gchar *name = fu_plugin_get_name (plugin); + g_warning ("%s has incorrect built version %s", + name, fu_plugin_get_build_hash (plugin)); + self->tainted = TRUE; + } + fu_plugin_list_add (self->plugin_list, plugin); } @@ -3290,6 +3638,24 @@ g_ptr_array_add (self->plugin_filter, g_strdup (plugin_glob)); } +static gboolean +fu_engine_plugin_check_supported_cb (FuPlugin *plugin, const gchar *guid, FuEngine *self) +{ + g_autoptr(XbNode) n = NULL; + g_autofree gchar *xpath = NULL; + xpath = g_strdup_printf ("components/component/" + "provides/firmware[@type='flashed'][text()='%s']", + guid); + n = xb_silo_query_first (self->silo, xpath, NULL); + return n != NULL; +} + +gboolean +fu_engine_get_tainted (FuEngine *self) +{ + return self->tainted; +} + gboolean fu_engine_load_plugins (FuEngine *self, GError **error) { @@ -3332,7 +3698,6 @@ fu_plugin_set_usb_context (plugin, self->usb_ctx); fu_plugin_set_hwids (plugin, self->hwids); fu_plugin_set_smbios (plugin, self->smbios); - fu_plugin_set_supported (plugin, self->supported_guids); fu_plugin_set_udev_subsystems (plugin, self->udev_subsystems); fu_plugin_set_quirks (plugin, self->quirks); fu_plugin_set_runtime_versions (plugin, self->runtime_versions); @@ -3371,9 +3736,15 @@ g_signal_connect (plugin, "set-coldplug-delay", G_CALLBACK (fu_engine_plugin_set_coldplug_delay_cb), self); + g_signal_connect (plugin, "check-supported", + G_CALLBACK (fu_engine_plugin_check_supported_cb), + self); + g_signal_connect (plugin, "rules-changed", + G_CALLBACK (fu_engine_plugin_rules_changed_cb), + self); /* add */ - fu_plugin_list_add (self->plugin_list, plugin); + fu_engine_add_plugin (self, plugin); } /* depsolve into the correct order */ @@ -3562,9 +3933,17 @@ /* the system is running with the new firmware version */ if (g_strcmp0 (fu_device_get_version (dev), fwupd_release_get_version (rel_history)) == 0) { + GPtrArray *checksums; g_debug ("installed version %s matching history %s", fu_device_get_version (dev), fwupd_release_get_version (rel_history)); + + /* copy over runtime checksums if set from probe() */ + checksums = fu_device_get_checksums (dev); + for (guint i = 0; i < checksums->len; i++) { + const gchar *csum = g_ptr_array_index (checksums, i); + fu_device_add_checksum (dev_history, csum); + } fu_device_set_update_state (dev_history, FWUPD_UPDATE_STATE_SUCCESS); return fu_history_modify_device (self->history, dev_history, FU_HISTORY_FLAGS_MATCH_NEW_VERSION, @@ -3652,19 +4031,26 @@ g_return_val_if_fail (FU_IS_ENGINE (self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + /* avoid re-loading a second time if fu-tool or fu-util request to */ + if (self->loaded) + return TRUE; + /* read config file */ if (!fu_config_load (self->config, error)) { g_prefix_error (error, "Failed to load config: "); return FALSE; } + /* set up idle exit */ + if ((self->app_flags & FU_APP_FLAGS_NO_IDLE_SOURCES) == 0) + fu_idle_set_timeout (self->idle, fu_config_get_idle_timeout (self->config)); + /* load quirks, SMBIOS and the hwids */ fu_engine_load_smbios (self); fu_engine_load_hwids (self); fu_engine_load_quirks (self); /* load AppStream metadata */ - as_store_add_filter (self->store, AS_APP_KIND_FIRMWARE); if (!fu_engine_load_metadata_store (self, error)) { g_prefix_error (error, "Failed to load AppStream data: "); return FALSE; @@ -3735,6 +4121,7 @@ return FALSE; fu_engine_set_status (self, FWUPD_STATUS_IDLE); + self->loaded = TRUE; /* success */ return TRUE; @@ -3789,6 +4176,14 @@ } static void +fu_engine_idle_status_notify_cb (FuIdle *idle, GParamSpec *pspec, FuEngine *self) +{ + FwupdStatus status = fu_idle_get_status (idle); + if (status == FWUPD_STATUS_SHUTDOWN) + fu_engine_set_status (self, status); +} + +static void fu_engine_init (FuEngine *self) { self->percentage = 0; @@ -3797,22 +4192,22 @@ self->device_list = fu_device_list_new (); self->smbios = fu_smbios_new (); self->hwids = fu_hwids_new (); + self->idle = fu_idle_new (); self->quirks = fu_quirks_new (); self->history = fu_history_new (); self->plugin_list = fu_plugin_list_new (); - self->store = as_store_new (); self->plugin_filter = g_ptr_array_new_with_free_func (g_free); - self->supported_guids = g_ptr_array_new_with_free_func (g_free); self->udev_subsystems = g_ptr_array_new_with_free_func (g_free); self->runtime_versions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); self->compile_versions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + g_signal_connect (self->idle, "notify::status", + G_CALLBACK (fu_engine_idle_status_notify_cb), self); + /* add some runtime versions of things the daemon depends on */ fu_engine_add_runtime_version (self, "org.freedesktop.fwupd", VERSION); fu_engine_add_runtime_version (self, "com.redhat.fwupdate", "12"); -#if AS_CHECK_VERSION(0,7,8) - fu_engine_add_runtime_version (self, "org.freedesktop.appstream-glib", as_version_string ()); -#endif + fu_engine_add_runtime_version (self, "org.freedesktop.appstream-glib", "0.7.14"); #if G_USB_CHECK_VERSION(0,3,1) fu_engine_add_runtime_version (self, "org.freedesktop.gusb", g_usb_version_string ()); #endif @@ -3824,12 +4219,6 @@ g_strdup ("org.freedesktop.fwupd"), g_strdup (VERSION)); g_hash_table_insert (self->compile_versions, - g_strdup ("org.freedesktop.appstream-glib"), - g_strdup_printf ("%i.%i.%i", - AS_MAJOR_VERSION, - AS_MINOR_VERSION, - AS_MICRO_VERSION)); - g_hash_table_insert (self->compile_versions, g_strdup ("org.freedesktop.gusb"), g_strdup_printf ("%i.%i.%i", G_USB_MAJOR_VERSION, @@ -3845,19 +4234,20 @@ if (self->usb_ctx != NULL) g_object_unref (self->usb_ctx); + if (self->silo != NULL) + g_object_unref (self->silo); if (self->gudev_client != NULL) g_object_unref (self->gudev_client); if (self->coldplug_id != 0) g_source_remove (self->coldplug_id); + g_object_unref (self->idle); g_object_unref (self->config); g_object_unref (self->smbios); g_object_unref (self->quirks); g_object_unref (self->hwids); g_object_unref (self->history); - g_object_unref (self->store); g_object_unref (self->device_list); - g_ptr_array_unref (self->supported_guids); g_ptr_array_unref (self->plugin_filter); g_ptr_array_unref (self->udev_subsystems); g_hash_table_unref (self->runtime_versions); diff -Nru fwupd-1.1.4/src/fu-engine.h fwupd-1.2.5/src/fu-engine.h --- fwupd-1.1.4/src/fu-engine.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-engine.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,12 +4,9 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_ENGINE_H -#define __FU_ENGINE_H +#pragma once -G_BEGIN_DECLS - -#include +#include #include #include "fwupd-device.h" @@ -19,18 +16,22 @@ #include "fu-install-task.h" #include "fu-plugin.h" +G_BEGIN_DECLS + #define FU_TYPE_ENGINE (fu_engine_get_type ()) G_DECLARE_FINAL_TYPE (FuEngine, fu_engine, FU, ENGINE, GObject) FuEngine *fu_engine_new (FuAppFlags app_flags); void fu_engine_add_plugin_filter (FuEngine *self, const gchar *plugin_glob); +void fu_engine_idle_reset (FuEngine *self); gboolean fu_engine_load (FuEngine *self, GError **error); gboolean fu_engine_load_plugins (FuEngine *self, GError **error); +gboolean fu_engine_get_tainted (FuEngine *self); FwupdStatus fu_engine_get_status (FuEngine *self); -AsStore *fu_engine_get_store_from_blob (FuEngine *self, +XbSilo *fu_engine_get_silo_from_blob (FuEngine *self, GBytes *blob_cab, GError **error); guint64 fu_engine_get_archive_size_max (FuEngine *self); @@ -42,6 +43,9 @@ GError **error); GPtrArray *fu_engine_get_history (FuEngine *self, GError **error); +FwupdRemote *fu_engine_get_remote_by_id (FuEngine *self, + const gchar *remote_id, + GError **error); GPtrArray *fu_engine_get_remotes (FuEngine *self, GError **error); GPtrArray *fu_engine_get_releases (FuEngine *self, @@ -96,9 +100,7 @@ GError **error); gboolean fu_engine_install_blob (FuEngine *self, FuDevice *device, - GBytes *blob_cab, GBytes *blob_fw, - const gchar *version, FwupdInstallFlags flags, GError **error); gboolean fu_engine_install_tasks (FuEngine *self, @@ -122,12 +124,9 @@ FuInstallTask *task, FwupdInstallFlags flags, GError **error); -gboolean fu_engine_load_metadata_from_file (FuEngine *self, - const gchar *path, - const gchar *remote_id, - GError **error); +void fu_engine_set_silo (FuEngine *self, + XbSilo *silo); +XbNode *fu_engine_get_component_by_guids (FuEngine *self, + FuDevice *device); G_END_DECLS - -#endif /* __FU_ENGINE_H */ - diff -Nru fwupd-1.1.4/src/fu-hash.py fwupd-1.2.5/src/fu-hash.py --- fwupd-1.1.4/src/fu-hash.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/src/fu-hash.py 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,32 @@ +#!/usr/bin/python3 +""" Builds a header for the plugins to include """ + +# pylint: disable=invalid-name,wrong-import-position,pointless-string-statement + +""" +SPDX-License-Identifier: LGPL-2.1+ +""" + +import sys +import hashlib + +def usage(return_code): + """ print usage and exit with the supplied return code """ + if return_code == 0: + out = sys.stdout + else: + out = sys.stderr + out.write("usage: fu-hash.py
") + sys.exit(return_code) + +if __name__ == '__main__': + if {'-?', '--help', '--usage'}.intersection(set(sys.argv)): + usage(0) + if len(sys.argv) != 3: + usage(1) + with open(sys.argv[1], 'rb') as f: + buf = f.read() + csum = hashlib.sha256(buf).hexdigest() + with open(sys.argv[2], 'w') as f2: + f2.write('#pragma once\n') + f2.write('#define FU_BUILD_HASH "%s"\n' % csum) diff -Nru fwupd-1.1.4/src/fu-history.c fwupd-1.2.5/src/fu-history.c --- fwupd-1.1.4/src/fu-history.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-history.c 2019-02-25 09:42:18.000000000 +0000 @@ -113,6 +113,16 @@ tmp = (const gchar *) sqlite3_column_text (stmt, 13); if (tmp != NULL) fu_device_set_version (device, tmp); + + /* checksum_device */ + tmp = (const gchar *) sqlite3_column_text (stmt, 14); + if (tmp != NULL) + fu_device_add_checksum (device, tmp); + + /* protocol */ + tmp = (const gchar *) sqlite3_column_text (stmt, 15); + if (tmp != NULL) + fwupd_release_set_protocol (release, tmp); return device; } @@ -147,7 +157,7 @@ "CREATE TABLE schema (" "created timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP," "version INTEGER DEFAULT 0);" - "INSERT INTO schema (version) VALUES (2);" + "INSERT INTO schema (version) VALUES (4);" "CREATE TABLE history (" "device_id TEXT," "update_state INTEGER DEFAULT 0," @@ -162,7 +172,9 @@ "metadata TEXT DEFAULT NULL," "guid_default TEXT DEFAULT NULL," "version_old TEXT," - "version_new TEXT);" + "version_new TEXT," + "checksum_device TEXT DEFAULT NULL," + "protocol TEXT DEFAULT NULL);" "COMMIT;", NULL, NULL, NULL); if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -193,7 +205,11 @@ /* migrate the old entries to the new table */ rc = sqlite3_exec (self->db, - "INSERT INTO history SELECT * FROM history_old;" + "INSERT INTO history SELECT " + "device_id, update_state, update_error, filename, " + "display_name, plugin, device_created, device_modified, " + "checksum, flags, metadata, guid_default, version_old, " + "version_new, NULL, NULL FROM history_old;" "DROP TABLE history_old;", NULL, NULL, NULL); if (rc != SQLITE_OK) { @@ -203,6 +219,57 @@ return TRUE; } +static gboolean +fu_history_migrate_database_v2 (FuHistory *self, GError **error) +{ + gint rc; + + /* rename the table to something out the way */ + rc = sqlite3_exec (self->db, + "ALTER TABLE history ADD COLUMN checksum_device TEXT DEFAULT NULL;" + "ALTER TABLE history ADD COLUMN protocol TEXT DEFAULT NULL;", + NULL, NULL, NULL); + if (rc != SQLITE_OK) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Failed to alter database: %s", + sqlite3_errmsg (self->db)); + return FALSE; + } + + /* update version */ + rc = sqlite3_exec (self->db, "UPDATE schema SET version=4;", NULL, NULL, NULL); + if (rc != SQLITE_OK) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Failed to migrate database: %s", + sqlite3_errmsg (self->db)); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_history_migrate_database_v3 (FuHistory *self, GError **error) +{ + gint rc; + + /* rename the table to something out the way */ + rc = sqlite3_exec (self->db, + "ALTER TABLE history ADD COLUMN protocol TEXT DEFAULT NULL;", + NULL, NULL, NULL); + if (rc != SQLITE_OK) + g_debug ("ignoring database error: %s", sqlite3_errmsg (self->db)); + + /* update version */ + rc = sqlite3_exec (self->db, "UPDATE schema SET version=4;", NULL, NULL, NULL); + if (rc != SQLITE_OK) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Failed to update schema version: %s", + sqlite3_errmsg (self->db)); + return FALSE; + } + return TRUE; +} + /* returns 0 if database is not initialised */ static guint fu_history_get_schema_version (FuHistory *self) @@ -286,6 +353,14 @@ g_debug ("migrating v%u database", schema_ver); if (!fu_history_migrate_database_v1 (self, error)) return FALSE; + } else if (schema_ver == 2) { + g_debug ("migrating v%u database", schema_ver); + if (!fu_history_migrate_database_v2 (self, error)) + return FALSE; + } else if (schema_ver == 3) { + g_debug ("migrating v%u database", schema_ver); + if (!fu_history_migrate_database_v3 (self, error)) + return FALSE; } return TRUE; @@ -344,6 +419,7 @@ "UPDATE history SET " "update_state = ?1, " "update_error = ?2, " + "checksum_device = ?6, " "flags = ?3 " "WHERE device_id = ?4;", -1, &stmt, NULL); @@ -356,6 +432,7 @@ "UPDATE history SET " "update_state = ?1, " "update_error = ?2, " + "checksum_device = ?6, " "flags = ?3 " "WHERE device_id = ?4 AND version_old = ?5;", -1, &stmt, NULL); @@ -368,6 +445,7 @@ "UPDATE history SET " "update_state = ?1, " "update_error = ?2, " + "checksum_device = ?6, " "flags = ?3 " "WHERE device_id = ?4 AND version_new = ?5;", -1, &stmt, NULL); @@ -380,17 +458,21 @@ sqlite3_errmsg (self->db)); return FALSE; } + sqlite3_bind_int (stmt, 1, fu_device_get_update_state (device)); sqlite3_bind_text (stmt, 2, fu_device_get_update_error (device), -1, SQLITE_STATIC); sqlite3_bind_int64 (stmt, 3, fu_history_get_device_flags_filtered (device)); sqlite3_bind_text (stmt, 4, fu_device_get_id (device), -1, SQLITE_STATIC); sqlite3_bind_text (stmt, 5, fu_device_get_version (device), -1, SQLITE_STATIC); + sqlite3_bind_text (stmt, 6, fwupd_checksum_get_by_kind (fu_device_get_checksums (device), + G_CHECKSUM_SHA1), -1, SQLITE_STATIC); return fu_history_stmt_exec (self, stmt, NULL, error); } gboolean fu_history_add_device (FuHistory *self, FuDevice *device, FwupdRelease *release, GError **error) { + const gchar *checksum_device; const gchar *checksum = NULL; gint rc; g_autofree gchar *metadata = NULL; @@ -416,6 +498,8 @@ GPtrArray *checksums = fwupd_release_get_checksums (release); checksum = fwupd_checksum_get_by_kind (checksums, G_CHECKSUM_SHA1); } + checksum_device = fwupd_checksum_get_by_kind (fu_device_get_checksums (device), + G_CHECKSUM_SHA1); /* metadata is stored as a simple string */ metadata = _convert_hash_to_string (fwupd_release_get_metadata (release)); @@ -437,9 +521,11 @@ "device_created," "device_modified," "version_old," - "version_new) " + "version_new," + "checksum_device," + "protocol) " "VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9,?10," - "?11,?12,?13,?14)", -1, &stmt, NULL); + "?11,?12,?13,?14,?15,?16)", -1, &stmt, NULL); if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "Failed to prepare SQL: %s", @@ -460,6 +546,8 @@ sqlite3_bind_int64 (stmt, 12, fu_device_get_modified (device)); sqlite3_bind_text (stmt, 13, fu_device_get_version (device), -1, SQLITE_STATIC); sqlite3_bind_text (stmt, 14, fwupd_release_get_version (release), -1, SQLITE_STATIC); + sqlite3_bind_text (stmt, 15, checksum_device, -1, SQLITE_STATIC); + sqlite3_bind_text (stmt, 16, fwupd_release_get_protocol (release), -1, SQLITE_STATIC); return fu_history_stmt_exec (self, stmt, NULL, error); } @@ -594,7 +682,9 @@ "update_state, " "update_error, " "version_new, " - "version_old FROM history WHERE " + "version_old, " + "checksum_device, " + "protocol FROM history WHERE " "device_id = ?1 LIMIT 1", -1, &stmt, NULL); if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -650,7 +740,9 @@ "update_state, " "update_error, " "version_new, " - "version_old FROM history " + "version_old, " + "checksum_device, " + "protocol FROM history " "ORDER BY device_modified ASC;", -1, &stmt, NULL); if (rc != SQLITE_OK) { diff -Nru fwupd-1.1.4/src/fu-history.h fwupd-1.2.5/src/fu-history.h --- fwupd-1.1.4/src/fu-history.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-history.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_HISTORY_H -#define __FU_HISTORY_H +#pragma once #include @@ -58,6 +57,3 @@ GError **error); G_END_DECLS - -#endif /* __FU_HISTORY_H */ - diff -Nru fwupd-1.1.4/src/fu-hwids.c fwupd-1.2.5/src/fu-hwids.c --- fwupd-1.1.4/src/fu-hwids.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-hwids.c 2019-02-25 09:42:18.000000000 +0000 @@ -11,10 +11,10 @@ #include #include #include -#include #include "fu-common.h" #include "fu-hwids.h" +#include "fwupd-common.h" #include "fwupd-error.h" struct _FuHwids { @@ -75,7 +75,6 @@ static gchar * fu_hwids_get_guid_for_str (const gchar *str, GError **error) { - const gchar *namespace_id = "70ffd812-4c7f-4c7d-0000-000000000000"; glong items_written = 0; g_autofree gunichar2 *data = NULL; @@ -97,10 +96,8 @@ data[i] = GUINT16_TO_LE(data[i]); /* convert to a GUID */ - return as_utils_guid_from_data (namespace_id, - (guint8*) data, - items_written * 2, - error); + return fwupd_guid_hash_data ((guint8*) data, items_written * 2, + FWUPD_GUID_FLAG_NAMESPACE_MICROSOFT); } /** @@ -394,7 +391,6 @@ for (guint i = 0; i < 15; i++) { g_autofree gchar *guid = NULL; g_autofree gchar *key = NULL; - g_autofree gchar *values = NULL; g_autoptr(GError) error_local = NULL; /* get the GUID and add to hash */ @@ -407,11 +403,7 @@ g_hash_table_insert (self->hash_guid, g_strdup (guid), GUINT_TO_POINTER (1)); - g_ptr_array_add (self->array_guids, g_strdup (guid)); - - /* show what makes up the GUID */ - values = fu_hwids_get_replace_values (self, key, NULL); - g_debug ("{%s} <- %s", guid, values); + g_ptr_array_add (self->array_guids, g_steal_pointer (&guid)); } return TRUE; diff -Nru fwupd-1.1.4/src/fu-hwids.h fwupd-1.2.5/src/fu-hwids.h --- fwupd-1.1.4/src/fu-hwids.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-hwids.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_HWIDS_H -#define __FU_HWIDS_H +#pragma once #include @@ -49,5 +48,3 @@ GError **error); G_END_DECLS - -#endif /* __FU_HWIDS_H */ diff -Nru fwupd-1.1.4/src/fu-idle.c fwupd-1.2.5/src/fu-idle.c --- fwupd-1.1.4/src/fu-idle.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/src/fu-idle.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuIdle" + +#include "config.h" + +#include + +#include "fu-idle.h" +#include "fu-mutex.h" + +static void fu_idle_finalize (GObject *obj); + +struct _FuIdle +{ + GObject parent_instance; + GPtrArray *items; /* of FuIdleItem */ + FuMutex *items_mutex; + guint idle_id; + guint timeout; + FwupdStatus status; +}; + +enum { + PROP_0, + PROP_STATUS, + PROP_LAST +}; + +static void +fu_idle_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + FuIdle *self = FU_IDLE (object); + switch (prop_id) { + case PROP_STATUS: + g_value_set_uint (value, self->status); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +fu_idle_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +typedef struct { + gchar *reason; + guint32 token; +} FuIdleItem; + +G_DEFINE_TYPE (FuIdle, fu_idle, G_TYPE_OBJECT) + +FwupdStatus +fu_idle_get_status (FuIdle *self) +{ + g_return_val_if_fail (FU_IS_IDLE (self), FWUPD_STATUS_UNKNOWN); + return self->status; +} + +static void +fu_idle_set_status (FuIdle *self, FwupdStatus status) +{ + if (self->status == status) + return; + self->status = status; + g_debug ("status now %s", fwupd_status_to_string (status)); + g_object_notify (G_OBJECT (self), "status"); +} + +static gboolean +fu_idle_check_cb (gpointer user_data) +{ + FuIdle *self = FU_IDLE (user_data); + fu_idle_set_status (self, FWUPD_STATUS_SHUTDOWN); + return G_SOURCE_CONTINUE; +} + +static void +fu_idle_start (FuIdle *self) +{ + if (self->idle_id != 0) + return; + if (self->timeout == 0) + return; + self->idle_id = g_timeout_add_seconds (self->timeout, fu_idle_check_cb, self); +} + +static void +fu_idle_stop (FuIdle *self) +{ + if (self->idle_id == 0) + return; + g_source_remove (self->idle_id); + self->idle_id = 0; +} + +void +fu_idle_reset (FuIdle *self) +{ + g_return_if_fail (FU_IS_IDLE (self)); + fu_idle_stop (self); + if (self->items->len == 0) + fu_idle_start (self); +} + +void +fu_idle_uninhibit (FuIdle *self, guint32 token) +{ + g_autoptr(FuMutexLocker) locker = fu_mutex_write_locker_new (self->items_mutex); + + g_return_if_fail (FU_IS_IDLE (self)); + g_return_if_fail (token != 0); + g_return_if_fail (locker != NULL); + + for (guint i = 0; i < self->items->len; i++) { + FuIdleItem *item = g_ptr_array_index (self->items, i); + if (item->token == token) { + g_debug ("uninhibiting: %s", item->reason); + g_ptr_array_remove_index (self->items, i); + break; + } + } + fu_idle_reset (self); +} + +guint32 +fu_idle_inhibit (FuIdle *self, const gchar *reason) +{ + FuIdleItem *item; + g_autoptr(FuMutexLocker) locker = fu_mutex_write_locker_new (self->items_mutex); + + g_return_val_if_fail (FU_IS_IDLE (self), 0); + g_return_val_if_fail (reason != NULL, 0); + g_return_val_if_fail (locker != NULL, 0); + + g_debug ("inhibiting: %s", reason); + item = g_new0 (FuIdleItem, 1); + item->reason = g_strdup (reason); + item->token = g_random_int_range (1, G_MAXINT); + g_ptr_array_add (self->items, item); + fu_idle_reset (self); + return item->token; +} + +void +fu_idle_set_timeout (FuIdle *self, guint timeout) +{ + g_return_if_fail (FU_IS_IDLE (self)); + g_debug ("setting timeout to %us", timeout); + self->timeout = timeout; + fu_idle_reset (self); +} + +static void +fu_idle_item_free (FuIdleItem *item) +{ + g_free (item->reason); + g_free (item); +} + +FuIdleLocker * +fu_idle_locker_new (FuIdle *self, const gchar *reason) +{ + FuIdleLocker *locker = g_new0 (FuIdleLocker, 1); + locker->idle = g_object_ref (self); + locker->token = fu_idle_inhibit (self, reason); + return locker; +} + +void +fu_idle_locker_free (FuIdleLocker *locker) +{ + if (locker == NULL) + return; + fu_idle_uninhibit (locker->idle, locker->token); + g_object_unref (locker->idle); + g_free (locker); +} + +static void +fu_idle_class_init (FuIdleClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + + object_class->finalize = fu_idle_finalize; + object_class->get_property = fu_idle_get_property; + object_class->set_property = fu_idle_set_property; + + pspec = g_param_spec_uint ("status", NULL, NULL, + FWUPD_STATUS_UNKNOWN, + FWUPD_STATUS_LAST, + FWUPD_STATUS_UNKNOWN, + G_PARAM_READABLE | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_STATUS, pspec); +} + +static void +fu_idle_init (FuIdle *self) +{ + self->status = FWUPD_STATUS_IDLE; + self->items = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_idle_item_free); + self->items_mutex = fu_mutex_new (G_OBJECT_TYPE_NAME(self), "items"); +} + +static void +fu_idle_finalize (GObject *obj) +{ + FuIdle *self = FU_IDLE (obj); + + fu_idle_stop (self); + g_ptr_array_unref (self->items); + g_object_unref (self->items_mutex); + + G_OBJECT_CLASS (fu_idle_parent_class)->finalize (obj); +} + +FuIdle * +fu_idle_new (void) +{ + FuIdle *self; + self = g_object_new (FU_TYPE_IDLE, NULL); + return FU_IDLE (self); +} diff -Nru fwupd-1.1.4/src/fu-idle.h fwupd-1.2.5/src/fu-idle.h --- fwupd-1.1.4/src/fu-idle.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/src/fu-idle.h 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include + +#include "fu-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_IDLE (fu_idle_get_type ()) +G_DECLARE_FINAL_TYPE (FuIdle, fu_idle, FU, IDLE, GObject) + +FuIdle *fu_idle_new (void); +guint32 fu_idle_inhibit (FuIdle *self, + const gchar *reason); +void fu_idle_uninhibit (FuIdle *self, + guint32 token); +void fu_idle_set_timeout (FuIdle *self, + guint timeout); +void fu_idle_reset (FuIdle *self); +FwupdStatus fu_idle_get_status (FuIdle *self); + +typedef struct { + FuIdle *idle; + guint32 token; +} FuIdleLocker; + +FuIdleLocker *fu_idle_locker_new (FuIdle *self, + const gchar *reason); +void fu_idle_locker_free (FuIdleLocker *locker); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuIdleLocker, fu_idle_locker_free) + +G_END_DECLS diff -Nru fwupd-1.1.4/src/fu-install-task.c fwupd-1.2.5/src/fu-install-task.c --- fwupd-1.1.4/src/fu-install-task.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-install-task.c 2019-02-25 09:42:18.000000000 +0000 @@ -10,6 +10,7 @@ #include +#include "fu-common-version.h" #include "fu-device-private.h" #include "fu-install-task.h" #include "fu-keyring-utils.h" @@ -18,7 +19,7 @@ { GObject parent_instance; FuDevice *device; - AsApp *app; + XbNode *component; FwupdTrustFlags trust_flags; gboolean is_downgrade; }; @@ -41,18 +42,18 @@ } /** - * fu_install_task_get_app: + * fu_install_task_get_component: * @self: A #FuInstallTask * * Gets the component for this task. * * Returns: (transfer none): the component **/ -AsApp * -fu_install_task_get_app (FuInstallTask *self) +XbNode * +fu_install_task_get_component (FuInstallTask *self) { g_return_val_if_fail (FU_IS_INSTALL_TASK (self), NULL); - return self->app; + return self->component; } /** @@ -108,25 +109,33 @@ FwupdInstallFlags flags, GError **error) { - AsRelease *release; - GPtrArray *provides; const gchar *version; const gchar *version_release; const gchar *version_lowest; gboolean matches_guid = FALSE; gint vercmp; g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) provides = NULL; + g_autoptr(XbNode) release = NULL; g_return_val_if_fail (FU_IS_INSTALL_TASK (self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - /* does this app provide a GUID the device has */ - provides = as_app_get_provides (self->app); + /* does this component provide a GUID the device has */ + provides = xb_node_query (self->component, + "provides/firmware[@type='flashed']", + 0, &error_local); + if (provides == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "No supported devices found: %s", + error_local->message); + return FALSE; + } for (guint i = 0; i < provides->len; i++) { - AsProvide *provide = g_ptr_array_index (provides, i); - if (as_provide_get_kind (provide) != AS_PROVIDE_KIND_FIRMWARE_FLASHED) - continue; - if (fu_device_has_guid (self->device, as_provide_get_value (provide))) { + XbNode *provide = g_ptr_array_index (provides, i); + if (fu_device_has_guid (self->device, xb_node_get_text (provide))) { matches_guid = TRUE; break; } @@ -186,7 +195,7 @@ } /* get latest release */ - release = as_app_get_release_default (self->app); + release = xb_node_query_first (self->component, "releases/release", NULL); if (release == NULL) { g_set_error (error, FWUPD_ERROR, @@ -198,7 +207,7 @@ } /* is this a downgrade or re-install */ - version_release = as_release_get_version (release); + version_release = xb_node_get_attr (release, "version"); if (version_release == NULL) { g_set_error_literal (error, FWUPD_ERROR, @@ -210,7 +219,7 @@ /* compare to the lowest supported version, if it exists */ version_lowest = fu_device_get_version_lowest (self->device); if (version_lowest != NULL && - as_utils_vercmp (version_lowest, version) > 0 && + fu_common_vercmp (version_lowest, version) > 0 && (flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { g_set_error (error, FWUPD_ERROR, @@ -221,7 +230,7 @@ } /* check semver */ - vercmp = as_utils_vercmp (version, version_release); + vercmp = fu_common_vercmp (version, version_release); if (vercmp == 0 && (flags & FWUPD_INSTALL_FLAG_ALLOW_REINSTALL) == 0) { g_set_error (error, FWUPD_ERROR, @@ -293,7 +302,7 @@ { FuInstallTask *self = FU_INSTALL_TASK (object); - g_object_unref (self->app); + g_object_unref (self->component); if (self->device != NULL) g_object_unref (self->device); @@ -331,18 +340,18 @@ /** * fu_install_task_new: * @device: A #FuDevice - * @app: a #AsApp + * @component: a #XbNode * * Creates a new install task that may or may not be valid. * * Returns: (transfer full): the #FuInstallTask **/ FuInstallTask * -fu_install_task_new (FuDevice *device, AsApp *app) +fu_install_task_new (FuDevice *device, XbNode *component) { FuInstallTask *self; self = g_object_new (FU_TYPE_TASK, NULL); - self->app = g_object_ref (app); + self->component = g_object_ref (component); if (device != NULL) self->device = g_object_ref (device); return FU_INSTALL_TASK (self); diff -Nru fwupd-1.1.4/src/fu-install-task.h fwupd-1.2.5/src/fu-install-task.h --- fwupd-1.1.4/src/fu-install-task.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-install-task.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,11 +4,10 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_INSTALL_TASK_H -#define __FU_INSTALL_TASK_H +#pragma once #include -#include +#include #include "fu-device.h" @@ -18,9 +17,9 @@ G_DECLARE_FINAL_TYPE (FuInstallTask, fu_install_task, FU, INSTALL_TASK, GObject) FuInstallTask *fu_install_task_new (FuDevice *device, - AsApp *app); + XbNode *component); FuDevice *fu_install_task_get_device (FuInstallTask *self); -AsApp *fu_install_task_get_app (FuInstallTask *self); +XbNode *fu_install_task_get_component (FuInstallTask *self); FwupdTrustFlags fu_install_task_get_trust_flags (FuInstallTask *self); gboolean fu_install_task_get_is_downgrade (FuInstallTask *self); gboolean fu_install_task_check_requirements (FuInstallTask *self, @@ -31,6 +30,3 @@ FuInstallTask *task2); G_END_DECLS - -#endif /* __FU_INSTALL_TASK_H */ - diff -Nru fwupd-1.1.4/src/fu-io-channel.c fwupd-1.2.5/src/fu-io-channel.c --- fwupd-1.1.4/src/fu-io-channel.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/src/fu-io-channel.c 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,437 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuIOChannel" + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "fwupd-error.h" +#include "fu-common.h" +#include "fu-io-channel.h" + +struct _FuIOChannel { + GObject parent_instance; + gint fd; +}; + +G_DEFINE_TYPE (FuIOChannel, fu_io_channel, G_TYPE_OBJECT) + +/** + * fu_io_channel_unix_get_fd: + * @self: a #FuIOChannel + * + * Gets the file descriptor for the device. + * + * Returns: fd, or -1 for not open. + * + * Since: 1.2.2 + **/ +gint +fu_io_channel_unix_get_fd (FuIOChannel *self) +{ + g_return_val_if_fail (FU_IS_IO_CHANNEL (self), -1); + return self->fd; +} + +/** + * fu_io_channel_shutdown: + * @self: a #FuIOChannel + * @error: a #GError, or %NULL + * + * Closes the file descriptor for the device. + * + * Returns: %TRUE if all the FD was closed. + * + * Since: 1.2.2 + **/ +gboolean +fu_io_channel_shutdown (FuIOChannel *self, GError **error) +{ + g_return_val_if_fail (FU_IS_IO_CHANNEL (self), FALSE); + if (!g_close (self->fd, error)) + return FALSE; + self->fd = -1; + return TRUE; +} + +static gboolean +fu_io_channel_flush_input (FuIOChannel *self, GError **error) +{ + GPollFD poll = { + .fd = self->fd, + .events = G_IO_IN | G_IO_ERR, + }; + while (g_poll (&poll, 1, 0) > 0) { + gchar c; + gint r = read (self->fd, &c, 1); + if (r < 0 && errno != EINTR) + break; + } + return TRUE; +} + +/** + * fu_io_channel_write_bytes: + * @self: a #FuIOChannel + * @bytes: buffer to write + * @timeout_ms: timeout in ms + * @flags: some #FuIOChannelFlags, e.g. %FU_IO_CHANNEL_FLAG_SINGLE_SHOT + * @error: a #GError, or %NULL + * + * Writes bytes to the TTY, that will fail if exceeding @timeout_ms. + * + * Returns: %TRUE if all the bytes was written + * + * Since: 1.2.2 + **/ +gboolean +fu_io_channel_write_bytes (FuIOChannel *self, + GBytes *bytes, + guint timeout_ms, + FuIOChannelFlags flags, + GError **error) +{ + gsize bufsz = 0; + const guint8 *buf = g_bytes_get_data (bytes, &bufsz); + return fu_io_channel_write_raw (self, buf, bufsz, timeout_ms, flags, error); +} + +/** + * fu_io_channel_write_raw: + * @self: a #FuIOChannel + * @data: buffer to write + * @datasz: size of @data + * @timeout_ms: timeout in ms + * @flags: some #FuIOChannelFlags, e.g. %FU_IO_CHANNEL_FLAG_SINGLE_SHOT + * @error: a #GError, or %NULL + * + * Writes bytes to the TTY, that will fail if exceeding @timeout_ms. + * + * Returns: %TRUE if all the bytes was written + * + * Since: 1.2.2 + **/ +gboolean +fu_io_channel_write_raw (FuIOChannel *self, + const guint8 *data, + gsize datasz, + guint timeout_ms, + FuIOChannelFlags flags, + GError **error) +{ + gsize idx = 0; + + g_return_val_if_fail (FU_IS_IO_CHANNEL (self), FALSE); + + /* flush pending reads */ + if (flags & FU_IO_CHANNEL_FLAG_FLUSH_INPUT) { + if (!fu_io_channel_flush_input (self, error)) + return FALSE; + } + + /* blocking IO */ + if (flags & FU_IO_CHANNEL_FLAG_USE_BLOCKING_IO) { + gssize wrote = write (self->fd, data, datasz); + if (wrote != (gssize) datasz) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to write: " + "wrote %" G_GSSIZE_FORMAT " of %" G_GSIZE_FORMAT, + wrote, datasz); + return FALSE; + } + return TRUE; + } + + /* nonblocking IO */ + while (idx < datasz) { + gint rc; + GPollFD fds = { + .fd = self->fd, + .events = G_IO_OUT | G_IO_ERR, + }; + + /* wait for data to be allowed to write without blocking */ + rc = g_poll (&fds, 1, (gint) timeout_ms); + if (rc == 0) + break; + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "failed to poll %i", + self->fd); + return FALSE; + } + + /* we can write data */ + if (fds.revents & G_IO_OUT) { + gssize len = write (self->fd, data + idx, datasz - idx); + if (len < 0) { + if (errno == EAGAIN) { + g_debug ("got EAGAIN, trying harder"); + continue; + } + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "failed to write %" G_GSIZE_FORMAT + " bytes to %i: %s" , + datasz, + self->fd, + strerror (errno)); + return FALSE; + } + if (flags & FU_IO_CHANNEL_FLAG_SINGLE_SHOT) + break; + idx += len; + } + } + + return TRUE; +} + +/** + * fu_io_channel_read_bytes: + * @self: a #FuIOChannel + * @max_size: maximum size of the returned blob, or -1 for no limit + * @timeout_ms: timeout in ms + * @flags: some #FuIOChannelFlags, e.g. %FU_IO_CHANNEL_FLAG_SINGLE_SHOT + * @error: a #GError, or %NULL + * + * Reads bytes from the TTY, that will fail if exceeding @timeout_ms. + * + * Returns: a #GBytes, or %NULL for error + * + * Since: 1.2.2 + **/ +GBytes * +fu_io_channel_read_bytes (FuIOChannel *self, + gssize max_size, + guint timeout_ms, + FuIOChannelFlags flags, + GError **error) +{ + GPollFD fds = { + .fd = self->fd, + .events = G_IO_IN | G_IO_PRI | G_IO_ERR, + }; + g_autoptr(GString) str = g_string_new (NULL); + + g_return_val_if_fail (FU_IS_IO_CHANNEL (self), NULL); + + /* blocking IO */ + if (flags & FU_IO_CHANNEL_FLAG_USE_BLOCKING_IO) { + guint8 buf[1024]; + gssize len = read (self->fd, buf, sizeof (buf)); + if (len < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "failed to read %i: %s", self->fd, + strerror (errno)); + return NULL; + } + if (len > 0) + g_string_append_len (str, (gchar *) buf, len); + return g_bytes_new (str->str, str->len); + } + + /* nonblocking IO */ + while (TRUE) { + /* wait for data to appear */ + gint rc = g_poll (&fds, 1, (gint) timeout_ms); + if (rc == 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_TIMED_OUT, + "timeout"); + return FALSE; + } + if (rc < 0) { + if (errno == EINTR) + continue; + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "failed to poll %i", self->fd); + return NULL; + } + + /* we have data to read */ + if (fds.revents & G_IO_IN) { + guint8 buf[1024]; + gssize len = read (self->fd, buf, sizeof (buf)); + if (len < 0) { + if (errno == EINTR) + continue; + if (errno == EAGAIN) + continue; + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "failed to read %i: %s", self->fd, + strerror (errno)); + return NULL; + } + if (len > 0) + g_string_append_len (str, (gchar *) buf, len); + + /* check maximum size */ + if (max_size > 0 && str->len >= (guint) max_size) + break; + if (flags & FU_IO_CHANNEL_FLAG_SINGLE_SHOT) + break; + continue; + } + if (fds.revents & G_IO_ERR) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "error condition"); + return NULL; + } + if (fds.revents & G_IO_HUP) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "connection hung up"); + return NULL; + } + if (fds.revents & G_IO_NVAL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "invalid request"); + return NULL; + } + } + + /* no data */ + if (str->len == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "no data received from device in %ums", + timeout_ms); + return NULL; + } + + /* return blob */ + return g_bytes_new (str->str, str->len); +} + +/** + * fu_io_channel_read_raw: + * @self: a #FuIOChannel + * @buf: buffer, or %NULL + * @bufsz: size of @buf + * @bytes_read: (out): data written to @buf, or %NULL + * @timeout_ms: timeout in ms + * @flags: some #FuIOChannelFlags, e.g. %FU_IO_CHANNEL_FLAG_SINGLE_SHOT + * @error: a #GError, or %NULL + * + * Reads bytes from the TTY, that will fail if exceeding @timeout_ms. + * + * Returns: a #GBytes, or %NULL for error + * + * Since: 1.2.2 + **/ +gboolean +fu_io_channel_read_raw (FuIOChannel *self, + guint8 *buf, + gsize bufsz, + gsize *bytes_read, + guint timeout_ms, + FuIOChannelFlags flags, + GError **error) +{ + const guint8 *tmpbuf = NULL; + gsize bytes_read_tmp; + g_autoptr(GBytes) tmp = NULL; + + g_return_val_if_fail (FU_IS_IO_CHANNEL (self), FALSE); + + tmp = fu_io_channel_read_bytes (self, bufsz, timeout_ms, flags, error); + if (tmp == NULL) + return FALSE; + tmpbuf = g_bytes_get_data (tmp, &bytes_read_tmp); + if (tmpbuf != NULL) + memcpy (buf, tmpbuf, bytes_read_tmp); + if (bytes_read != NULL) + *bytes_read = bytes_read_tmp; + return TRUE; +} + +static void +fu_io_channel_finalize (GObject *object) +{ + FuIOChannel *self = FU_IO_CHANNEL (object); + if (self->fd != -1) + g_close (self->fd, NULL); + G_OBJECT_CLASS (fu_io_channel_parent_class)->finalize (object); +} + +static void +fu_io_channel_class_init (FuIOChannelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_io_channel_finalize; +} + +static void +fu_io_channel_init (FuIOChannel *self) +{ + self->fd = -1; +} + +/** + * fu_io_channel_unix_new: + * @fd: file descriptor + * + * Creates a new object to write and read from. + * + * Returns: a #FuIOChannel + **/ +FuIOChannel * +fu_io_channel_unix_new (gint fd) +{ + FuIOChannel *self; + self = g_object_new (FU_TYPE_IO_CHANNEL, NULL); + self->fd = fd; + return FU_IO_CHANNEL (self); +} + +/** + * fu_io_channel_new_file: + * @filename: device file + * @error: a #GError, or %NULL + * + * Creates a new object to write and read from. + * + * Returns: a #FuIOChannel + **/ +FuIOChannel * +fu_io_channel_new_file (const gchar *filename, GError **error) +{ + gint fd = g_open (filename, O_RDWR | O_NONBLOCK, S_IRWXU); + if (fd < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to open %s", filename); + return NULL; + } + return fu_io_channel_unix_new (fd); +} diff -Nru fwupd-1.1.4/src/fu-io-channel.h fwupd-1.2.5/src/fu-io-channel.h --- fwupd-1.1.4/src/fu-io-channel.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/src/fu-io-channel.h 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define FU_TYPE_IO_CHANNEL (fu_io_channel_get_type ()) + +G_DECLARE_FINAL_TYPE (FuIOChannel, fu_io_channel, FU, IO_CHANNEL, GObject) + +/** + * FuIOChannelFlags: + * @FU_IO_CHANNEL_FLAG_NONE: No flags are set + * @FU_IO_CHANNEL_FLAG_SINGLE_SHOT: Only one read or write is expected + * @FU_IO_CHANNEL_FLAG_FLUSH_INPUT: Flush pending input before writing + * @FU_IO_CHANNEL_FLAG_USE_BLOCKING_IO: Block waiting for the TTY + * + * The flags used when reading data from the TTY. + **/ +typedef enum { + FU_IO_CHANNEL_FLAG_NONE = 0, /* Since: 1.2.2 */ + FU_IO_CHANNEL_FLAG_SINGLE_SHOT = 1 << 0, /* Since: 1.2.2 */ + FU_IO_CHANNEL_FLAG_FLUSH_INPUT = 1 << 1, /* Since: 1.2.2 */ + FU_IO_CHANNEL_FLAG_USE_BLOCKING_IO = 1 << 2, /* Since: 1.2.2 */ + /*< private >*/ + FU_IO_CHANNEL_FLAG_LAST +} FuIOChannelFlags; + +FuIOChannel *fu_io_channel_unix_new (gint fd); +FuIOChannel *fu_io_channel_new_file (const gchar *filename, + GError **error); + +gint fu_io_channel_unix_get_fd (FuIOChannel *self); +gboolean fu_io_channel_shutdown (FuIOChannel *self, + GError **error); +gboolean fu_io_channel_write_raw (FuIOChannel *self, + const guint8 *data, + gsize datasz, + guint timeout_ms, + FuIOChannelFlags flags, + GError **error); +gboolean fu_io_channel_read_raw (FuIOChannel *self, + guint8 *buf, + gsize bufsz, + gsize *bytes_read, + guint timeout_ms, + FuIOChannelFlags flags, + GError **error); +gboolean fu_io_channel_write_bytes (FuIOChannel *self, + GBytes *bytes, + guint timeout_ms, + FuIOChannelFlags flags, + GError **error); +GBytes *fu_io_channel_read_bytes (FuIOChannel *self, + gssize max_size, + guint timeout_ms, + FuIOChannelFlags flags, + GError **error); + +G_END_DECLS diff -Nru fwupd-1.1.4/src/fu-keyring-gpg.h fwupd-1.2.5/src/fu-keyring-gpg.h --- fwupd-1.1.4/src/fu-keyring-gpg.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-keyring-gpg.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_KEYRING_GPG_H -#define __FU_KEYRING_GPG_H +#pragma once #include "fu-keyring.h" @@ -18,5 +17,3 @@ FuKeyring *fu_keyring_gpg_new (void); G_END_DECLS - -#endif /* __FU_KEYRING_GPG_H */ diff -Nru fwupd-1.1.4/src/fu-keyring.h fwupd-1.2.5/src/fu-keyring.h --- fwupd-1.1.4/src/fu-keyring.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-keyring.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_KEYRING_H -#define __FU_KEYRING_H +#pragma once #include #include @@ -45,5 +44,3 @@ const gchar *name); G_END_DECLS - -#endif /* __FU_KEYRING_H */ diff -Nru fwupd-1.1.4/src/fu-keyring-pkcs7.h fwupd-1.2.5/src/fu-keyring-pkcs7.h --- fwupd-1.1.4/src/fu-keyring-pkcs7.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-keyring-pkcs7.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_KEYRING_PKCS7_H -#define __FU_KEYRING_PKCS7_H +#pragma once #include "fu-keyring.h" @@ -18,5 +17,3 @@ FuKeyring *fu_keyring_pkcs7_new (void); G_END_DECLS - -#endif /* __FU_KEYRING_PKCS7_H */ diff -Nru fwupd-1.1.4/src/fu-keyring-result.c fwupd-1.2.5/src/fu-keyring-result.c --- fwupd-1.1.4/src/fu-keyring-result.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-keyring-result.c 2019-02-25 09:42:18.000000000 +0000 @@ -98,11 +98,15 @@ pspec = g_param_spec_int64 ("timestamp", NULL, NULL, 0, G_MAXINT64, 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_TIMESTAMP, pspec); pspec = g_param_spec_string ("authority", NULL, NULL, NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_AUTHORITY, pspec); } diff -Nru fwupd-1.1.4/src/fu-keyring-result.h fwupd-1.2.5/src/fu-keyring-result.h --- fwupd-1.1.4/src/fu-keyring-result.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-keyring-result.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_KEYRING_RESULT_H -#define __FU_KEYRING_RESULT_H +#pragma once #include @@ -19,5 +18,3 @@ const gchar *fu_keyring_result_get_authority (FuKeyringResult *self); G_END_DECLS - -#endif /* __FU_KEYRING_RESULT_H */ diff -Nru fwupd-1.1.4/src/fu-keyring-utils.c fwupd-1.2.5/src/fu-keyring-utils.c --- fwupd-1.1.4/src/fu-keyring-utils.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-keyring-utils.c 2019-02-25 09:42:18.000000000 +0000 @@ -67,7 +67,7 @@ /** * fu_keyring_get_release_trust_flags: - * @release: A #AsRelease, e.g. %FWUPD_KEYRING_KIND_GPG + * @release: A #XbNode, e.g. %FWUPD_KEYRING_KIND_GPG * @trust_flags: A #FwupdTrustFlags, e.g. %FWUPD_TRUST_FLAG_PAYLOAD * @error: A #GError, or %NULL * @@ -76,16 +76,16 @@ * Returns: %TRUE if @trust_flags has been set **/ gboolean -fu_keyring_get_release_trust_flags (AsRelease *release, +fu_keyring_get_release_trust_flags (XbNode *release, FwupdTrustFlags *trust_flags, GError **error) { - AsChecksum *csum_tmp; FwupdKeyringKind keyring_kind = FWUPD_KEYRING_KIND_UNKNOWN; GBytes *blob_payload; GBytes *blob_signature; const gchar *fn; g_autofree gchar *pki_dir = NULL; + g_autofree gchar *release_key = NULL; g_autofree gchar *sysconfdir = NULL; g_autoptr(GError) error_local = NULL; g_autoptr(FuKeyring) kr = NULL; @@ -100,28 +100,17 @@ { FWUPD_KEYRING_KIND_NONE, NULL } }; - /* no filename? */ - csum_tmp = as_release_get_checksum_by_target (release, AS_CHECKSUM_TARGET_CONTENT); - if (csum_tmp == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "no content checksum for release"); - return FALSE; - } - fn = as_checksum_get_filename (csum_tmp); - if (fn == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "no filename"); - return FALSE; - } + /* custom filename specified */ + fn = xb_node_query_attr (release, "checksum[@target='content']", "filename", NULL); + if (fn == NULL) + fn = "filename.bin"; /* no signature == no trust */ for (guint i = 0; keyrings[i].ext != NULL; i++) { - g_autofree gchar *fn_tmp = g_strdup_printf ("%s.%s", fn, keyrings[i].ext); - blob_signature = as_release_get_blob (release, fn_tmp); + g_autofree gchar *fn_tmp = NULL; + fn_tmp = g_strdup_printf ("fwupd::ReleaseBlob(%s.%s)", + fn, keyrings[i].ext); + blob_signature = g_object_get_data (G_OBJECT (release), fn_tmp); if (blob_signature != NULL) { keyring_kind = keyrings[i].kind; break; @@ -133,7 +122,8 @@ } /* get payload */ - blob_payload = as_release_get_blob (release, fn); + release_key = g_strdup_printf ("fwupd::ReleaseBlob(%s)", fn); + blob_payload = g_object_get_data (G_OBJECT (release), release_key); if (blob_payload == NULL) { g_set_error_literal (error, FWUPD_ERROR, @@ -145,6 +135,7 @@ /* check we were installed correctly */ sysconfdir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR); pki_dir = g_build_filename (sysconfdir, "pki", PACKAGE_NAME, NULL); +#if defined(ENABLE_PKCS7) || defined(ENABLE_PKCS7) if (!g_file_test (pki_dir, G_FILE_TEST_EXISTS)) { g_set_error (error, FWUPD_ERROR, @@ -152,6 +143,7 @@ "PKI directory %s not found", pki_dir); return FALSE; } +#endif /* verify against the system trusted keys */ kr = fu_keyring_create_for_kind (keyring_kind, error); diff -Nru fwupd-1.1.4/src/fu-keyring-utils.h fwupd-1.2.5/src/fu-keyring-utils.h --- fwupd-1.1.4/src/fu-keyring-utils.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-keyring-utils.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,18 +4,19 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_KEYRING_UTILS_H__ -#define __FU_KEYRING_UTILS_H__ +#pragma once -#include +#include #include "fu-keyring.h" #include "fwupd-enums.h" +G_BEGIN_DECLS + FuKeyring *fu_keyring_create_for_kind (FwupdKeyringKind kind, GError **error); -gboolean fu_keyring_get_release_trust_flags (AsRelease *release, +gboolean fu_keyring_get_release_trust_flags (XbNode *release, FwupdTrustFlags *trust_flags, GError **error); -#endif /* __FU_KEYRING_UTILS_H__ */ +G_END_DECLS diff -Nru fwupd-1.1.4/src/fu-main.c fwupd-1.2.5/src/fu-main.c --- fwupd-1.1.4/src/fu-main.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-main.c 2019-02-25 09:42:18.000000000 +0000 @@ -8,10 +8,11 @@ #include "config.h" -#include +#include #include #include #include +#include #include #include #include @@ -43,8 +44,23 @@ PolkitAuthority *authority; guint owner_id; FuEngine *engine; + gboolean update_in_progress; + gboolean pending_sigterm; } FuMainPrivate; +static gboolean +fu_main_sigterm_cb (gpointer user_data) +{ + FuMainPrivate *priv = (FuMainPrivate *) user_data; + if (!priv->update_in_progress) { + g_main_loop_quit (priv->loop); + return G_SOURCE_REMOVE; + } + g_warning ("Received SIGTERM during a firmware update, ignoring"); + priv->pending_sigterm = TRUE; + return G_SOURCE_CONTINUE; +} + static void fu_main_engine_changed_cb (FuEngine *engine, FuMainPrivate *priv) { @@ -166,6 +182,10 @@ FuMainPrivate *priv) { fu_main_set_status (priv, status); + + /* engine has gone idle */ + if (status == FWUPD_STATUS_SHUTDOWN) + g_main_loop_quit (priv->loop); } static void @@ -282,6 +302,7 @@ gchar *remote_id; gchar *key; gchar *value; + XbSilo *silo; } FuMainAuthHelper; static void @@ -291,6 +312,8 @@ g_bytes_unref (helper->blob_cab); if (helper->subject != NULL) g_object_unref (helper->subject); + if (helper->silo != NULL) + g_object_unref (helper->silo); if (helper->install_tasks != NULL) g_ptr_array_unref (helper->install_tasks); if (helper->action_ids != NULL) @@ -447,6 +470,7 @@ FuMainPrivate *priv = helper_ref->priv; g_autoptr(FuMainAuthHelper) helper = helper_ref; g_autoptr(GError) error = NULL; + gboolean ret; /* still more things to to authenticate */ if (helper->action_ids->len > 0) { @@ -463,11 +487,16 @@ } /* all authenticated, so install all the things */ - if (!fu_engine_install_tasks (helper->priv->engine, - helper->install_tasks, - helper->blob_cab, - helper->flags, - &error)) { + priv->update_in_progress = TRUE; + ret = fu_engine_install_tasks (helper->priv->engine, + helper->install_tasks, + helper->blob_cab, + helper->flags, + &error); + priv->update_in_progress = FALSE; + if (priv->pending_sigterm) + g_main_loop_quit (priv->loop); + if (!ret) { g_dbus_method_invocation_return_gerror (helper->invocation, error); return; } @@ -546,9 +575,8 @@ fu_main_install_with_helper (FuMainAuthHelper *helper_ref, GError **error) { FuMainPrivate *priv = helper_ref->priv; - GPtrArray *apps; - g_autoptr(AsStore) store = NULL; g_autoptr(FuMainAuthHelper) helper = helper_ref; + g_autoptr(GPtrArray) components = NULL; g_autoptr(GPtrArray) devices_possible = NULL; g_autoptr(GPtrArray) errors = NULL; @@ -563,20 +591,22 @@ return FALSE; } - /* parse store */ - store = fu_engine_get_store_from_blob (priv->engine, - helper->blob_cab, - error); - if (store == NULL) + /* parse silo */ + helper->silo = fu_engine_get_silo_from_blob (priv->engine, + helper->blob_cab, + error); + if (helper->silo == NULL) return FALSE; - /* for each component in the store */ - apps = as_store_get_apps (store); + /* for each component in the silo */ + components = xb_silo_query (helper->silo, "components/component", 0, error); + if (components == NULL) + return FALSE; helper->action_ids = g_ptr_array_new_with_free_func (g_free); helper->install_tasks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); errors = g_ptr_array_new_with_free_func ((GDestroyNotify) g_error_free); - for (guint i = 0; i < apps->len; i++) { - AsApp *app = g_ptr_array_index (apps, i); + for (guint i = 0; i < components->len; i++) { + XbNode *component = g_ptr_array_index (components, i); /* do any devices pass the requirements */ for (guint j = 0; j < devices_possible->len; j++) { @@ -586,19 +616,22 @@ g_autoptr(GError) error_local = NULL; /* is this component valid for the device */ - task = fu_install_task_new (device, app); + task = fu_install_task_new (device, component); if (!fu_engine_check_requirements (priv->engine, task, helper->flags, &error_local)) { g_debug ("requirement on %s:%s failed: %s", fu_device_get_id (device), - as_app_get_id (app), + xb_node_query_text (component, "id", NULL), error_local->message); g_ptr_array_add (errors, g_steal_pointer (&error_local)); continue; } + /* if component should have an update message from CAB */ + fu_device_incorporate_from_component (device, component); + /* get the action IDs for the valid device */ action_id = fu_install_task_get_action_id (task); if (!g_ptr_array_find (helper->action_ids, action_id, NULL)) @@ -648,6 +681,9 @@ GVariant *val = NULL; g_autoptr(GError) error = NULL; + /* activity */ + fu_engine_idle_reset (priv->engine); + if (g_strcmp0 (method_name, "GetDevices") == 0) { g_autoptr(GPtrArray) devices = NULL; g_debug ("Called %s()", method_name); @@ -1076,9 +1112,15 @@ { FuMainPrivate *priv = (FuMainPrivate *) user_data; + /* activity */ + fu_engine_idle_reset (priv->engine); + if (g_strcmp0 (property_name, "DaemonVersion") == 0) return g_variant_new_string (VERSION); + if (g_strcmp0 (property_name, "Tainted") == 0) + return g_variant_new_boolean (fu_engine_get_tainted (priv->engine)); + if (g_strcmp0 (property_name, "Status") == 0) return g_variant_new_uint32 (fu_engine_get_status (priv->engine)); @@ -1267,6 +1309,10 @@ return EXIT_FAILURE; } + g_unix_signal_add_full (G_PRIORITY_DEFAULT, + SIGTERM, fu_main_sigterm_cb, + priv, NULL); + /* load introspection from file */ priv->introspection_daemon = fu_main_load_introspection (FWUPD_DBUS_INTERFACE ".xml", &error); @@ -1299,6 +1345,8 @@ else if (timed_exit) g_timeout_add_seconds (5, fu_main_timed_exit_cb, priv->loop); + g_debug ("Started with locale %s", g_getenv ("LANG")); + /* wait */ g_message ("Daemon ready for requests"); g_main_loop_run (priv->loop); diff -Nru fwupd-1.1.4/src/fu-mutex.h fwupd-1.2.5/src/fu-mutex.h --- fwupd-1.1.4/src/fu-mutex.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-mutex.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_MUTEX_H -#define __FU_MUTEX_H +#pragma once #include @@ -64,5 +63,3 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuMutexLocker, fu_mutex_locker_free) G_END_DECLS - -#endif /* __FU_MUTEX_H */ diff -Nru fwupd-1.1.4/src/fu-plugin.c fwupd-1.2.5/src/fu-plugin.c --- fwupd-1.1.4/src/fu-plugin.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-plugin.c 2019-02-25 09:42:18.000000000 +0000 @@ -44,11 +44,11 @@ guint priority; GPtrArray *rules[FU_PLUGIN_RULE_LAST]; gchar *name; + gchar *build_hash; FuHwids *hwids; FuQuirks *quirks; GHashTable *runtime_versions; GHashTable *compile_versions; - GPtrArray *supported_guids; GPtrArray *udev_subsystems; FuSmbios *smbios; GHashTable *devices; /* platform_id:GObject */ @@ -61,8 +61,10 @@ SIGNAL_DEVICE_ADDED, SIGNAL_DEVICE_REMOVED, SIGNAL_DEVICE_REGISTER, + SIGNAL_RULES_CHANGED, SIGNAL_RECOLDPLUG, SIGNAL_SET_COLDPLUG_DELAY, + SIGNAL_CHECK_SUPPORTED, SIGNAL_LAST }; @@ -132,6 +134,34 @@ } /** + * fu_plugin_set_build_hash: + * @self: A #FuPlugin + * @build_hash: A checksum + * + * Sets the plugin build hash, typically a SHA256 checksum. All plugins must + * set the correct checksum to avoid the daemon being marked as tainted. + * + * Since: 1.2.4 + **/ +void +fu_plugin_set_build_hash (FuPlugin *self, const gchar *build_hash) +{ + FuPluginPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_PLUGIN (self)); + g_return_if_fail (build_hash != NULL); + g_free (priv->build_hash); + priv->build_hash = g_strdup (build_hash); +} + +const gchar * +fu_plugin_get_build_hash (FuPlugin *self) +{ + FuPluginPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_PLUGIN (self), NULL); + return priv->build_hash; +} + +/** * fu_plugin_cache_lookup: * @self: A #FuPlugin * @id: the key @@ -514,15 +544,9 @@ gboolean fu_plugin_check_supported (FuPlugin *self, const gchar *guid) { - FuPluginPrivate *priv = GET_PRIVATE (self); - if (priv->supported_guids == NULL) - return FALSE; - for (guint i = 0; i < priv->supported_guids->len; i++) { - const gchar *guid_tmp = g_ptr_array_index (priv->supported_guids, i); - if (g_strcmp0 (guid, guid_tmp) == 0) - return TRUE; - } - return FALSE; + gboolean retval = FALSE; + g_signal_emit (self, signals[SIGNAL_CHECK_SUPPORTED], 0, guid, &retval); + return retval; } /** @@ -597,15 +621,6 @@ } void -fu_plugin_set_supported (FuPlugin *self, GPtrArray *supported_guids) -{ - FuPluginPrivate *priv = GET_PRIVATE (self); - if (priv->supported_guids != NULL) - g_ptr_array_unref (priv->supported_guids); - priv->supported_guids = g_ptr_array_ref (supported_guids); -} - -void fu_plugin_set_udev_subsystems (FuPlugin *self, GPtrArray *udev_subsystems) { FuPluginPrivate *priv = GET_PRIVATE (self); @@ -741,23 +756,6 @@ return fu_common_strtoull (fu_plugin_lookup_quirk_by_id (self, group, key)); } -/** - * fu_plugin_get_supported: - * @self: A #FuPlugin - * - * Gets all the device GUIDs supported by the daemon. - * - * Returns: (element-type utf8) (transfer none): GUIDs - * - * Since: 1.0.0 - **/ -GPtrArray * -fu_plugin_get_supported (FuPlugin *self) -{ - FuPluginPrivate *priv = GET_PRIVATE (self); - return priv->supported_guids; -} - void fu_plugin_set_smbios (FuPlugin *self, FuSmbios *smbios) { @@ -807,6 +805,7 @@ { FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginStartupFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -821,8 +820,18 @@ if (func == NULL) return TRUE; g_debug ("performing startup() on %s", priv->name); - if (!func (self, error)) { - g_prefix_error (error, "failed to startup %s: ", priv->name); + if (!func (self, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for startup()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to startup using %s: ", + priv->name); return FALSE; } return TRUE; @@ -878,6 +887,7 @@ { FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginDeviceFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -892,10 +902,18 @@ if (func == NULL) return TRUE; g_debug ("performing %s() on %s", symbol_name + 10, priv->name); - if (!func (self, device, error)) { - g_prefix_error (error, "failed to run %s() on %s: ", - symbol_name + 10, - priv->name); + if (!func (self, device, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for %s()", + priv->name, symbol_name + 10); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to %s using %s: ", + symbol_name + 10, priv->name); return FALSE; } return TRUE; @@ -908,6 +926,7 @@ { FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginFlaggedDeviceFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -922,10 +941,18 @@ if (func == NULL) return TRUE; g_debug ("performing %s() on %s", symbol_name + 10, priv->name); - if (!func (self, flags, device, error)) { - g_prefix_error (error, "failed to run %s() on %s: ", - symbol_name + 10, - priv->name); + if (!func (self, flags, device, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for %s()", + priv->name, symbol_name + 10); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to %s using %s: ", + symbol_name + 10, priv->name); return FALSE; } return TRUE; @@ -938,6 +965,7 @@ { FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginDeviceArrayFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -952,10 +980,18 @@ if (func == NULL) return TRUE; g_debug ("performing %s() on %s", symbol_name + 10, priv->name); - if (!func (self, devices, error)) { - g_prefix_error (error, "failed to run %s() on %s: ", - symbol_name + 10, - priv->name); + if (!func (self, devices, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for %s()", + priv->name, symbol_name + 10); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to %s using %s: ", + symbol_name + 10, priv->name); return FALSE; } return TRUE; @@ -966,6 +1002,7 @@ { FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginStartupFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -980,8 +1017,17 @@ if (func == NULL) return TRUE; g_debug ("performing coldplug() on %s", priv->name); - if (!func (self, error)) { - g_prefix_error (error, "failed to coldplug %s: ", priv->name); + if (!func (self, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for coldplug()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to coldplug using %s: ", priv->name); return FALSE; } return TRUE; @@ -992,6 +1038,7 @@ { FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginStartupFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -1006,8 +1053,18 @@ if (func == NULL) return TRUE; g_debug ("performing recoldplug() on %s", priv->name); - if (!func (self, error)) { - g_prefix_error (error, "failed to recoldplug %s: ", priv->name); + if (!func (self, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for recoldplug()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to recoldplug using %s: ", + priv->name); return FALSE; } return TRUE; @@ -1018,6 +1075,7 @@ { FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginStartupFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -1032,8 +1090,18 @@ if (func == NULL) return TRUE; g_debug ("performing coldplug_prepare() on %s", priv->name); - if (!func (self, error)) { - g_prefix_error (error, "failed to prepare for coldplug %s: ", priv->name); + if (!func (self, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for coldplug_prepare()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to coldplug_prepare using %s: ", + priv->name); return FALSE; } return TRUE; @@ -1044,6 +1112,7 @@ { FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginStartupFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -1058,8 +1127,18 @@ if (func == NULL) return TRUE; g_debug ("performing coldplug_cleanup() on %s", priv->name); - if (!func (self, error)) { - g_prefix_error (error, "failed to cleanup coldplug %s: ", priv->name); + if (!func (self, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for coldplug_cleanup()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to coldplug_cleanup using %s: ", + priv->name); return FALSE; } return TRUE; @@ -1147,6 +1226,7 @@ { FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginUsbDeviceAddedFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -1158,9 +1238,22 @@ /* optional */ g_module_symbol (priv->module, "fu_plugin_usb_device_added", (gpointer *) &func); - if (func != NULL) { - g_debug ("performing usb_device_added() on %s", priv->name); - return func (self, device, error); + if (func == NULL) + return TRUE; + g_debug ("performing usb_device_added() on %s", priv->name); + if (!func (self, device, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for usb_device_added()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to add device using on %s: ", + priv->name); + return FALSE; } return TRUE; } @@ -1170,6 +1263,7 @@ { FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginUdevDeviceAddedFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -1181,9 +1275,22 @@ /* optional */ g_module_symbol (priv->module, "fu_plugin_udev_device_added", (gpointer *) &func); - if (func != NULL) { - g_debug ("performing udev_device_added() on %s", priv->name); - return func (self, device, error); + if (func == NULL) + return TRUE; + g_debug ("performing udev_device_added() on %s", priv->name); + if (!func (self, device, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for udev_device_added()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to add device using on %s: ", + priv->name); + return FALSE; } return TRUE; } @@ -1223,7 +1330,7 @@ } } -static gboolean +gboolean fu_plugin_runner_schedule_update (FuPlugin *self, FuDevice *device, GBytes *blob_cab, @@ -1296,6 +1403,7 @@ FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginVerifyFunc func = NULL; GPtrArray *checksums; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -1305,17 +1413,29 @@ if (priv->module == NULL) return TRUE; - /* clear any existing verification checksums */ - checksums = fu_device_get_checksums (device); - g_ptr_array_set_size (checksums, 0); - /* optional */ g_module_symbol (priv->module, "fu_plugin_verify", (gpointer *) &func); if (func == NULL) return TRUE; + + /* clear any existing verification checksums */ + checksums = fu_device_get_checksums (device); + g_ptr_array_set_size (checksums, 0); + + /* run vfunc */ g_debug ("performing verify() on %s", priv->name); - if (!func (self, device, flags, error)) { - g_prefix_error (error, "failed to verify %s: ", priv->name); + if (!func (self, device, flags, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for verify()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to verify using %s: ", + priv->name); return FALSE; } return TRUE; @@ -1352,7 +1472,6 @@ gboolean fu_plugin_runner_update (FuPlugin *self, FuDevice *device, - GBytes *blob_cab, GBytes *blob_fw, FwupdInstallFlags flags, GError **error) @@ -1361,8 +1480,7 @@ FuPluginUpdateFunc update_func; g_autoptr(FuHistory) history = NULL; g_autoptr(FuDevice) device_pending = NULL; - GError *error_update = NULL; - GPtrArray *checksums; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) { @@ -1386,21 +1504,6 @@ return FALSE; } - /* just schedule this for the next reboot */ - if (flags & FWUPD_INSTALL_FLAG_OFFLINE) { - if (blob_cab == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "No cabinet archive to schedule"); - return FALSE; - } - return fu_plugin_runner_schedule_update (self, - device, - blob_cab, - error); - } - /* cancel the pending action */ if (!fu_plugin_runner_offline_invalidate (error)) return FALSE; @@ -1408,24 +1511,27 @@ /* online */ history = fu_history_new (); device_pending = fu_history_get_device_by_id (history, fu_device_get_id (device), NULL); - if (!update_func (self, device, blob_fw, flags, &error_update)) { - if (error_update == NULL) { - g_critical ("plugin %s returned FALSE from UpdateFunc " - "but did not set error!", - fu_plugin_get_name (self)); - g_set_error_literal (&error_update, + if (!update_func (self, device, blob_fw, flags, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for update()", + priv->name); + g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "unspecified error"); + return FALSE; } - fu_device_set_update_error (device, error_update->message); - g_propagate_error (error, error_update); + fu_device_set_update_error (device, error_local->message); + g_propagate_error (error, g_steal_pointer (&error_local)); return FALSE; } /* no longer valid */ - checksums = fu_device_get_checksums (device); - g_ptr_array_set_size (checksums, 0); + if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT) && + !fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) { + GPtrArray *checksums = fu_device_get_checksums (device); + g_ptr_array_set_size (checksums, 0); + } /* cleanup */ if (device_pending != NULL) { @@ -1443,15 +1549,15 @@ release = fu_device_get_release_default (device_pending); tmp = fwupd_release_get_filename (release); if (tmp != NULL && g_str_has_prefix (tmp, LIBEXECDIR)) { - g_autoptr(GError) error_local = NULL; + g_autoptr(GError) error_delete = NULL; g_autoptr(GFile) file = NULL; file = g_file_new_for_path (tmp); - if (!g_file_delete (file, NULL, &error_local)) { + if (!g_file_delete (file, NULL, &error_delete)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Failed to delete %s: %s", - tmp, error_local->message); + tmp, error_delete->message); return FALSE; } } @@ -1464,6 +1570,7 @@ { FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginDeviceFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -1478,8 +1585,18 @@ if (func == NULL) return TRUE; g_debug ("performing clear_result() on %s", priv->name); - if (!func (self, device, error)) { - g_prefix_error (error, "failed to clear_result %s: ", priv->name); + if (!func (self, device, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for clear_result()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to clear_result using %s: ", + priv->name); return FALSE; } return TRUE; @@ -1490,6 +1607,7 @@ { FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginDeviceFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -1504,8 +1622,18 @@ if (func == NULL) return TRUE; g_debug ("performing get_results() on %s", priv->name); - if (!func (self, device, error)) { - g_prefix_error (error, "failed to get_results %s: ", priv->name); + if (!func (self, device, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for get_results()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to get_results using %s: ", + priv->name); return FALSE; } return TRUE; @@ -1589,6 +1717,7 @@ { FuPluginPrivate *priv = fu_plugin_get_instance_private (self); g_ptr_array_add (priv->rules[rule], g_strdup (name)); + g_signal_emit (self, signals[SIGNAL_RULES_CHANGED], 0); } /** @@ -1767,6 +1896,18 @@ G_STRUCT_OFFSET (FuPluginClass, set_coldplug_delay), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); + signals[SIGNAL_CHECK_SUPPORTED] = + g_signal_new ("check-supported", + G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (FuPluginClass, check_supported), + NULL, NULL, g_cclosure_marshal_generic, + G_TYPE_BOOLEAN, 1, G_TYPE_STRING); + signals[SIGNAL_RULES_CHANGED] = + g_signal_new ("rules-changed", + G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (FuPluginClass, rules_changed), + NULL, NULL, g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); } static void @@ -1807,8 +1948,6 @@ g_object_unref (priv->hwids); if (priv->quirks != NULL) g_object_unref (priv->quirks); - if (priv->supported_guids != NULL) - g_ptr_array_unref (priv->supported_guids); if (priv->udev_subsystems != NULL) g_ptr_array_unref (priv->udev_subsystems); if (priv->smbios != NULL) diff -Nru fwupd-1.1.4/src/fu-plugin.h fwupd-1.2.5/src/fu-plugin.h --- fwupd-1.1.4/src/fu-plugin.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-plugin.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,21 +4,22 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_PLUGIN_H -#define __FU_PLUGIN_H +#pragma once -#include #include #include #include #include "fu-common.h" +#include "fu-common-guid.h" +#include "fu-common-version.h" #include "fu-device.h" #include "fu-device-locker.h" #include "fu-quirks.h" #include "fu-hwids.h" #include "fu-usb-device.h" #include "fu-udev-device.h" +#include "fwupd-common.h" G_BEGIN_DECLS @@ -42,8 +43,11 @@ guint duration); void (* device_register) (FuPlugin *self, FuDevice *device); + gboolean (* check_supported) (FuPlugin *self, + const gchar *guid); + void (* rules_changed) (FuPlugin *self); /*< private >*/ - gpointer padding[24]; + gpointer padding[22]; }; /** @@ -65,6 +69,8 @@ * @FU_PLUGIN_RULE_RUN_BEFORE: Order the plugin before another * @FU_PLUGIN_RULE_REQUIRES_QUIRK: Requires a specific quirk * @FU_PLUGIN_RULE_BETTER_THAN: Is better than another plugin + * @FU_PLUGIN_RULE_INHIBITS_IDLE: The plugin inhibits the idle shutdown + * @FU_PLUGIN_RULE_SUPPORTS_PROTOCOL: The plugin supports a well known protocol * * The rules used for ordering plugins. * Plugins are expected to add rules in fu_plugin_initialize(). @@ -75,6 +81,8 @@ FU_PLUGIN_RULE_RUN_BEFORE, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_PLUGIN_RULE_BETTER_THAN, + FU_PLUGIN_RULE_INHIBITS_IDLE, + FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, /*< private >*/ FU_PLUGIN_RULE_LAST } FuPluginRule; @@ -89,8 +97,9 @@ gboolean fu_plugin_get_enabled (FuPlugin *self); void fu_plugin_set_enabled (FuPlugin *self, gboolean enabled); +void fu_plugin_set_build_hash (FuPlugin *self, + const gchar *build_hash); GUsbContext *fu_plugin_get_usb_context (FuPlugin *self); -GPtrArray *fu_plugin_get_supported (FuPlugin *self); void fu_plugin_device_add (FuPlugin *self, FuDevice *device); void fu_plugin_device_remove (FuPlugin *self, @@ -144,6 +153,3 @@ const gchar *version); G_END_DECLS - -#endif /* __FU_PLUGIN_H */ - diff -Nru fwupd-1.1.4/src/fu-plugin-list.h fwupd-1.2.5/src/fu-plugin-list.h --- fwupd-1.1.4/src/fu-plugin-list.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-plugin-list.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,15 +4,14 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_PLUGIN_LIST_H -#define __FU_PLUGIN_LIST_H - -G_BEGIN_DECLS +#pragma once #include #include "fu-plugin.h" +G_BEGIN_DECLS + #define FU_TYPE_PLUGIN_LIST (fu_plugin_list_get_type ()) G_DECLARE_FINAL_TYPE (FuPluginList, fu_plugin_list, FU, PLUGIN_LIST, GObject) @@ -27,6 +26,3 @@ GError **error); G_END_DECLS - -#endif /* __FU_PLUGIN_LIST_H */ - diff -Nru fwupd-1.1.4/src/fu-plugin-private.h fwupd-1.2.5/src/fu-plugin-private.h --- fwupd-1.1.4/src/fu-plugin-private.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-plugin-private.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_PLUGIN_PRIVATE_H -#define __FU_PLUGIN_PRIVATE_H +#pragma once #include "fu-quirks.h" #include "fu-plugin.h" @@ -20,8 +19,6 @@ GUsbContext *usb_ctx); void fu_plugin_set_hwids (FuPlugin *self, FuHwids *hwids); -void fu_plugin_set_supported (FuPlugin *self, - GPtrArray *supported_guids); void fu_plugin_set_udev_subsystems (FuPlugin *self, GPtrArray *udev_subsystems); void fu_plugin_set_quirks (FuPlugin *self, @@ -40,6 +37,7 @@ guint priority); void fu_plugin_set_name (FuPlugin *self, const gchar *name); +const gchar *fu_plugin_get_build_hash (FuPlugin *self); GPtrArray *fu_plugin_get_rules (FuPlugin *self, FuPluginRule rule); gboolean fu_plugin_has_rule (FuPlugin *self, @@ -94,7 +92,6 @@ FuDevice *device); gboolean fu_plugin_runner_update (FuPlugin *self, FuDevice *device, - GBytes *blob_cab, GBytes *blob_fw, FwupdInstallFlags flags, GError **error); @@ -111,6 +108,10 @@ gboolean fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error); +gboolean fu_plugin_runner_schedule_update (FuPlugin *self, + FuDevice *device, + GBytes *blob_cab, + GError **error); gint fu_plugin_name_compare (FuPlugin *plugin1, FuPlugin *plugin2); gint fu_plugin_order_compare (FuPlugin *plugin1, @@ -120,5 +121,3 @@ gchar *fu_plugin_guess_name_from_fn (const gchar *filename); G_END_DECLS - -#endif /* __FU_PLUGIN_PRIVATE_H */ diff -Nru fwupd-1.1.4/src/fu-plugin-vfuncs.h fwupd-1.2.5/src/fu-plugin-vfuncs.h --- fwupd-1.1.4/src/fu-plugin-vfuncs.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-plugin-vfuncs.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,11 +4,11 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_PLUGIN_VFUNCS_H -#define __FU_PLUGIN_VFUNCS_H +#pragma once #include "fu-plugin.h" #include "fu-device.h" +#include "fu-hash.h" G_BEGIN_DECLS @@ -78,5 +78,3 @@ FuDevice *dev); G_END_DECLS - -#endif /* __FU_PLUGIN_VFUNCS_H */ diff -Nru fwupd-1.1.4/src/fu-progressbar.c fwupd-1.2.5/src/fu-progressbar.c --- fwupd-1.1.4/src/fu-progressbar.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-progressbar.c 2019-02-25 09:42:18.000000000 +0000 @@ -29,6 +29,7 @@ gint64 last_animated; /* monotonic */ GTimer *time_elapsed; gdouble last_estimate; + gboolean interactive; }; G_DEFINE_TYPE (FuProgressbar, fu_progressbar, G_TYPE_OBJECT) @@ -96,6 +97,8 @@ static void fu_progressbar_erase_line (FuProgressbar *self) { + if (!self->interactive) + return; for (guint i = 0; i < self->to_erase; i++) g_print ("\b"); self->to_erase = 0; @@ -157,7 +160,7 @@ } title = fu_progressbar_status_to_string (status); g_string_append (str, title); - for (i = str->len; i < self->length_status; i++) + for (i = g_utf8_strlen (str->str, -1); i < self->length_status; i++) g_string_append_c (str, ' '); /* add progressbar */ @@ -186,7 +189,7 @@ /* dump to screen */ g_print ("%s", str->str); - self->to_erase = str->len - 2; + self->to_erase = str->len; /* done */ if (is_idle_newline) { @@ -271,6 +274,14 @@ if (status == FWUPD_STATUS_UNKNOWN) status = self->status; + if (!self->interactive) { + if (self->status != status) { + g_debug ("%s\n", fu_progressbar_status_to_string (status)); + self->status = status; + } + return; + } + /* if the main loop isn't spinning and we've not had a chance to * execute the callback just do the refresh now manually */ if (percentage == 0 && @@ -303,6 +314,13 @@ } void +fu_progressbar_set_interactive (FuProgressbar *self, gboolean interactive) +{ + g_return_if_fail (FU_IS_PROGRESSBAR (self)); + self->interactive = interactive; +} + +void fu_progressbar_set_length_status (FuProgressbar *self, guint len) { g_return_if_fail (FU_IS_PROGRESSBAR (self)); @@ -332,6 +350,7 @@ self->length_status = 25; self->spinner_count_up = TRUE; self->time_elapsed = g_timer_new (); + self->interactive = TRUE; } static void diff -Nru fwupd-1.1.4/src/fu-progressbar.h fwupd-1.2.5/src/fu-progressbar.h --- fwupd-1.1.4/src/fu-progressbar.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-progressbar.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_PROGRESSBAR_H -#define __FU_PROGRESSBAR_H +#pragma once #include @@ -26,8 +25,7 @@ guint len); void fu_progressbar_set_title (FuProgressbar *self, const gchar *title); +void fu_progressbar_set_interactive (FuProgressbar *self, + gboolean interactive); G_END_DECLS - -#endif /* __FU_PROGRESSBAR_H */ - diff -Nru fwupd-1.1.4/src/fu-quirks.c fwupd-1.2.5/src/fu-quirks.c --- fwupd-1.1.4/src/fu-quirks.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-quirks.c 2019-02-25 09:42:18.000000000 +0000 @@ -11,12 +11,12 @@ #include #include #include -#include #include "fu-common.h" #include "fu-mutex.h" #include "fu-quirks.h" +#include "fwupd-common.h" #include "fwupd-error.h" #include "fwupd-remote-private.h" @@ -97,9 +97,9 @@ for (guint i = 0; guid_prefixes[i] != NULL; i++) { if (g_str_has_prefix (group, guid_prefixes[i])) { gsize len = strlen (guid_prefixes[i]); - if (as_utils_guid_is_valid (group + len)) + if (fwupd_guid_is_valid (group + len)) return g_strdup (group + len); - return as_utils_guid_from_string (group + len); + return fwupd_guid_hash_string (group + len); } } diff -Nru fwupd-1.1.4/src/fu-quirks.h fwupd-1.2.5/src/fu-quirks.h --- fwupd-1.1.4/src/fu-quirks.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-quirks.h 2019-02-25 09:42:18.000000000 +0000 @@ -5,13 +5,12 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_QUIRKS_H -#define __FU_QUIRKS_H - -G_BEGIN_DECLS +#pragma once #include +G_BEGIN_DECLS + #define FU_TYPE_QUIRKS (fu_quirks_get_type ()) G_DECLARE_FINAL_TYPE (FuQuirks, fu_quirks, FU, QUIRKS, GObject) @@ -29,219 +28,23 @@ const gchar *guid, GHashTableIter *iter); -/** - * FU_QUIRKS_PLUGIN: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the plugin name, e.g. `csr` - * - * Sets the plugin to use for a specific hardware device. - * - * Since: 1.1.0 - */ #define FU_QUIRKS_PLUGIN "Plugin" - -/** - * FU_QUIRKS_UEFI_VERSION_FORMAT: - * @key: a %FU_HWIDS_KEY_MANUFACTURER, e.g. `Alienware` - * @value: the version format, e.g. `none` - * - * Assigns the version format to use for a specific manufacturer. - * A specific version format is sometimes chosen to match the appearance of - * other systems or specifications. - * - * Default value: `use-triplet` - * - * Since: 1.0.1 - */ #define FU_QUIRKS_UEFI_VERSION_FORMAT "UefiVersionFormat" - -/** - * FU_QUIRKS_DAEMON_VERSION_FORMAT: - * @key: the optionally wildcarded AppStream ID e.g. `com.dell.uefi*.firmware` - * @value: the version format, e.g. `none` - * - * Assigns the version format to use for a specific AppStream component. - * A specific version format is sometimes chosen to match the appearance of - * other systems or specifications. - * - * Default value: `use-triplet` - * - * Since: 1.0.1 - */ #define FU_QUIRKS_DAEMON_VERSION_FORMAT "ComponentIDs" - -/** - * FU_QUIRKS_FLAGS: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the quirk, e.g. `is-bootloader` - * - * Assigns optional quirks to use for a 8Bitdo device. The list of supported - * quirks is thus: - * - * * `none`: No device quirks - * * `is-bootloader`: Device is in bootloader mode - * - * Since: 1.0.3 - */ #define FU_QUIRKS_FLAGS "Flags" - -/** - * FU_QUIRKS_SUMMARY: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the USB device summary, e.g. `An open source display colorimeter` - * - * Sets a name for a specific hardware device. - * - * Since: 1.0.2 - */ #define FU_QUIRKS_SUMMARY "Summary" - -/** - * FU_QUIRKS_ICON: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the USB device icon name, e.g. `media-removable` - * - * Adds an icon name for a specific hardware device. - * - * Since: 1.0.2 - */ #define FU_QUIRKS_ICON "Icon" - -/** - * FU_QUIRKS_NAME: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the USB device name, e.g. `ColorHug` - * - * Sets a name for a specific hardware device. - * - * Since: 1.0.2 - */ #define FU_QUIRKS_NAME "Name" - -/** - * FU_QUIRKS_GUID: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the GUID, e.g. `537f7800-8529-5656-b2fa-b0901fe91696` - * - * Adds an extra GUID for a specific hardware device. If the value provided is - * not already a suitable GUID, it will be converted to one. - * - * Since: 1.0.3 - */ #define FU_QUIRKS_GUID "Guid" - -/** - * FU_QUIRKS_COUNTERPART_GUID: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the GUID, e.g. `537f7800-8529-5656-b2fa-b0901fe91696` - * - * Adds an counterpart GUID for a specific hardware device. If the value - * provided is not already a suitable GUID, it will be converted to one. - * - * A counterpart GUID is typically the GUID of the same device in bootloader - * or runtime mode, if they have a different device PCI or USB ID. Adding this - * type of GUID does not cause a "cascade" by matching using the quirk database. - * - * Since: 1.1.2 - */ #define FU_QUIRKS_COUNTERPART_GUID "CounterpartGuid" - -/** - * FU_QUIRKS_PARENT_GUID: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the GUID, e.g. `537f7800-8529-5656-b2fa-b0901fe91696` - * - * Adds an extra GUID to mark as the parent device. If the value provided is - * not already a suitable GUID, it will be converted to one. - * - * Since: 1.1.2 - */ #define FU_QUIRKS_PARENT_GUID "ParentGuid" - -/** - * FU_QUIRKS_CHILDREN: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the GUID, e.g. `USB\VID_0763&PID_2806&I2C_01` - * - * Adds one or more virtual devices to a physical device, delimited by comma. - * - * To set the object type of the child device use a pipe before the object type, - * for instance: `FuRts54xxDevice|USB\VID_0763&PID_2806&I2C_01` - * If the type of device is not specified the parent device type is used. - * - * If the values provided are not already suitable GUIDs, they will be - * converted. - * - * Since: 1.1.2 - */ #define FU_QUIRKS_CHILDREN "Children" - -/** - * FU_QUIRKS_VERSION: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806&REV_0001` - * @value: the version number, e.g. `1.2` - * - * Sets a version for a specific hardware device. - * - * Since: 1.0.3 - */ #define FU_QUIRKS_VERSION "Version" - -/** - * FU_QUIRKS_VENDOR: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the vendor, e.g. `Hughski Limited` - * - * Sets a vendor name for a specific hardware device. - * - * Since: 1.0.3 - */ #define FU_QUIRKS_VENDOR "Vendor" - -/** - * FU_QUIRKS_VENDOR_ID: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the vendor, e.g. `USB:0x123A` - * - * Sets a vendor ID for a specific hardware device. - * - * Since: 1.1.2 - */ #define FU_QUIRKS_VENDOR_ID "VendorId" - -/** - * FU_QUIRKS_FIRMWARE_SIZE_MIN: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the vendor, e.g. `0x10000` - * - * Sets the minimum allowed firmware size. - * - * Since: 1.1.2 - */ #define FU_QUIRKS_FIRMWARE_SIZE_MIN "FirmwareSizeMin" - -/** - * FU_QUIRKS_FIRMWARE_SIZE_MAX: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the vendor, e.g. `0x10000` - * - * Sets the maximum allowed firmware size. - * - * Since: 1.1.2 - */ #define FU_QUIRKS_FIRMWARE_SIZE_MAX "FirmwareSizeMax" - -/** - * FU_QUIRKS_INSTALL_DURATION: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the estimated time for flashing the device in seconds - * - * Sets the estimated time to flash the device - * - * Since: 1.1.3 - */ #define FU_QUIRKS_INSTALL_DURATION "InstallDuration" +#define FU_QUIRKS_VERSION_FORMAT "VersionFormat" G_END_DECLS - -#endif /* __FU_QUIRKS_H */ diff -Nru fwupd-1.1.4/src/fu-self-test.c fwupd-1.2.5/src/fu-self-test.c --- fwupd-1.1.4/src/fu-self-test.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-self-test.c 2019-02-25 09:42:18.000000000 +0000 @@ -6,7 +6,7 @@ #include "config.h" -#include +#include #include #include #include @@ -15,7 +15,9 @@ #include #include +#include "fu-archive.h" #include "fu-common-cab.h" +#include "fu-common-version.h" #include "fu-chunk.h" #include "fu-config.h" #include "fu-device-list.h" @@ -28,6 +30,7 @@ #include "fu-plugin-private.h" #include "fu-plugin-list.h" #include "fu-progressbar.h" +#include "fu-hash.h" #include "fu-hwids.h" #include "fu-smbios.h" #include "fu-test.h" @@ -40,27 +43,159 @@ #endif static void +fu_self_test_mkroot (void) +{ + if (g_file_test ("/tmp/fwupd-self-test", G_FILE_TEST_EXISTS)) { + g_autoptr(GError) error = NULL; + if (!fu_common_rmtree ("/tmp/fwupd-self-test", &error)) + g_warning ("failed to mkroot: %s", error->message); + } + g_assert_cmpint (g_mkdir_with_parents ("/tmp/fwupd-self-test/var/lib/fwupd", 0755), ==, 0); +} + +static void +fu_archive_invalid_func (void) +{ + g_autofree gchar *filename = NULL; + g_autoptr(FuArchive) archive = NULL; + g_autoptr(GBytes) data = NULL; + g_autoptr(GError) error = NULL; + + filename = fu_test_get_filename (TESTDATADIR, "metadata.xml"); + g_assert_nonnull (filename); + data = fu_common_get_contents_bytes (filename, &error); + g_assert_no_error (error); + g_assert_nonnull (data); + + archive = fu_archive_new (data, FU_ARCHIVE_FLAG_NONE, &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED); + g_assert_null (archive); +} + +static void +fu_engine_generate_md_func (void) +{ + const gchar *tmp; + gboolean ret; + g_autofree gchar *filename = NULL; + g_autoptr(FuDevice) device = fu_device_new (); + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(GBytes) data = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(XbNode) component = NULL; + + /* put cab file somewhere we can parse it */ + filename = fu_test_get_filename (TESTDATADIR, "colorhug/colorhug-als-3.0.2.cab"); + g_assert_nonnull (filename); + data = fu_common_get_contents_bytes (filename, &error); + g_assert_no_error (error); + g_assert_nonnull (data); + ret = fu_common_set_contents_bytes ("/tmp/fwupd-self-test/var/cache/fwupd/foo.cab", + data, &error); + g_assert_no_error (error); + g_assert (ret); + + /* load engine and check the device was found */ + ret = fu_engine_load (engine, &error); + g_assert_no_error (error); + g_assert (ret); + fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012"); + fu_device_set_version (device, "1.2.3"); + component = fu_engine_get_component_by_guids (engine, device); + g_assert_nonnull (component); + + /* check remote ID set */ + tmp = xb_node_query_text (component, "../custom/value[@key='fwupd::RemoteId']", NULL); + g_assert_cmpstr (tmp, ==, "directory"); + + /* verify checksums */ + tmp = xb_node_query_text (component, "releases/release/checksum[@target='container']", NULL); + g_assert_cmpstr (tmp, !=, NULL); + tmp = xb_node_query_text (component, "releases/release/checksum[@target='content']", NULL); + g_assert_cmpstr (tmp, ==, NULL); +} + +static void +fu_archive_cab_func (void) +{ + g_autofree gchar *checksum1 = NULL; + g_autofree gchar *checksum2 = NULL; + g_autofree gchar *filename = NULL; + g_autoptr(FuArchive) archive = NULL; + g_autoptr(GBytes) data = NULL; + g_autoptr(GError) error = NULL; + GBytes *data_tmp; + + filename = fu_test_get_filename (TESTDATADIR, "colorhug/colorhug-als-3.0.2.cab"); + g_assert_nonnull (filename); + data = fu_common_get_contents_bytes (filename, &error); + g_assert_no_error (error); + g_assert_nonnull (data); + + archive = fu_archive_new (data, FU_ARCHIVE_FLAG_NONE, &error); + g_assert_no_error (error); + g_assert_nonnull (archive); + + data_tmp = fu_archive_lookup_by_fn (archive, "firmware.metainfo.xml", &error); + g_assert_no_error (error); + g_assert_nonnull (data_tmp); + checksum1 = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, data_tmp); + g_assert_cmpstr (checksum1, ==, "8611114f51f7151f190de86a5c9259d79ff34216"); + + data_tmp = fu_archive_lookup_by_fn (archive, "firmware.bin", &error); + g_assert_no_error (error); + g_assert_nonnull (data_tmp); + checksum2 = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, data_tmp); + g_assert_cmpstr (checksum2, ==, "7c0ae84b191822bcadbdcbe2f74a011695d783c7"); + + data_tmp = fu_archive_lookup_by_fn (archive, "NOTGOINGTOEXIST.xml", &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert_null (data_tmp); +} + +static void +fu_common_version_guess_format_func (void) +{ + g_assert_cmpint (fu_common_version_guess_format (NULL), ==, FU_VERSION_FORMAT_UNKNOWN); + g_assert_cmpint (fu_common_version_guess_format (""), ==, FU_VERSION_FORMAT_UNKNOWN); + g_assert_cmpint (fu_common_version_guess_format ("1234ac"), ==, FU_VERSION_FORMAT_PLAIN); + g_assert_cmpint (fu_common_version_guess_format ("1.2"), ==, FU_VERSION_FORMAT_PAIR); + g_assert_cmpint (fu_common_version_guess_format ("1.2.3"), ==, FU_VERSION_FORMAT_TRIPLET); + g_assert_cmpint (fu_common_version_guess_format ("1.2.3.4"), ==, FU_VERSION_FORMAT_QUAD); + g_assert_cmpint (fu_common_version_guess_format ("1.2.3.4.5"), ==, FU_VERSION_FORMAT_UNKNOWN); + g_assert_cmpint (fu_common_version_guess_format ("1a.2b.3"), ==, FU_VERSION_FORMAT_UNKNOWN); + g_assert_cmpint (fu_common_version_guess_format ("1"), ==, FU_VERSION_FORMAT_PLAIN); +} + +static void fu_engine_requirements_missing_func (void) { gboolean ret; - g_autoptr(AsApp) app = as_app_new (); - g_autoptr(AsRequire) req = as_require_new (); + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo = NULL; g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); g_autoptr(FuInstallTask) task = NULL; g_autoptr(GError) error = NULL; + const gchar *xml = + "" + " " + " not.going.to.exist" + " " + ""; /* set up a dummy version */ fu_engine_add_runtime_version (engine, "org.test.dummy", "1.2.3"); /* make the component require one thing */ - as_require_set_kind (req, AS_REQUIRE_KIND_ID); - as_require_set_compare (req, AS_REQUIRE_COMPARE_GE); - as_require_set_version (req, "1.2.3"); - as_require_set_value (req, "not.going.to.exist"); - as_app_add_require (app, req); + silo = xb_silo_new_from_xml (xml, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + component = xb_silo_query_first (silo, "component", &error); + g_assert_no_error (error); + g_assert_nonnull (component); /* check this fails */ - task = fu_install_task_new (NULL, app); + task = fu_install_task_new (NULL, component); ret = fu_engine_check_requirements (engine, task, FWUPD_INSTALL_FLAG_NONE, &error); @@ -72,23 +207,31 @@ fu_engine_requirements_unsupported_func (void) { gboolean ret; - g_autoptr(AsApp) app = as_app_new (); - g_autoptr(AsRequire) req = as_require_new (); + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo = NULL; g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); g_autoptr(FuInstallTask) task = NULL; g_autoptr(GError) error = NULL; + const gchar *xml = + "" + " " + " " + " " + ""; /* set up a dummy version */ fu_engine_add_runtime_version (engine, "org.test.dummy", "1.2.3"); /* make the component require one thing that we don't support */ - as_require_set_kind (req, AS_REQUIRE_KIND_LAST); - as_require_set_compare (req, AS_REQUIRE_COMPARE_GE); - as_require_set_version (req, "2.6.0"); - as_app_add_require (app, req); + silo = xb_silo_new_from_xml (xml, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + component = xb_silo_query_first (silo, "component", &error); + g_assert_no_error (error); + g_assert_nonnull (component); /* check this fails */ - task = fu_install_task_new (NULL, app); + task = fu_install_task_new (NULL, component); ret = fu_engine_check_requirements (engine, task, FWUPD_INSTALL_FLAG_NONE, &error); @@ -100,25 +243,32 @@ fu_engine_requirements_func (void) { gboolean ret; - g_autoptr(AsApp) app = as_app_new (); - g_autoptr(AsRequire) req = as_require_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); g_autoptr(FuInstallTask) task = NULL; g_autoptr(GError) error = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo = NULL; + const gchar *xml = + "" + " " + " org.test.dummy" + " " + ""; /* set up some dummy versions */ fu_engine_add_runtime_version (engine, "org.test.dummy", "1.2.3"); fu_engine_add_runtime_version (engine, "com.hughski.colorhug", "7.8.9"); /* make the component require one thing */ - as_require_set_kind (req, AS_REQUIRE_KIND_ID); - as_require_set_compare (req, AS_REQUIRE_COMPARE_GE); - as_require_set_version (req, "1.2.3"); - as_require_set_value (req, "org.test.dummy"); - as_app_add_require (app, req); + silo = xb_silo_new_from_xml (xml, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + component = xb_silo_query_first (silo, "component", &error); + g_assert_no_error (error); + g_assert_nonnull (component); /* check this passes */ - task = fu_install_task_new (NULL, app); + task = fu_install_task_new (NULL, component); ret = fu_engine_check_requirements (engine, task, FWUPD_INSTALL_FLAG_NONE, &error); @@ -130,17 +280,28 @@ fu_engine_requirements_device_func (void) { gboolean ret; - g_autoptr(AsApp) app = as_app_new (); - g_autoptr(AsChecksum) csum = as_checksum_new (); - g_autoptr(AsRequire) req1 = as_require_new (); - g_autoptr(AsRequire) req2 = as_require_new (); - g_autoptr(AsRequire) req3 = as_require_new (); - g_autoptr(AsProvide) prov = as_provide_new (); - g_autoptr(AsRelease) rel = as_release_new (); g_autoptr(FuDevice) device = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); g_autoptr(FuInstallTask) task = NULL; g_autoptr(GError) error = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo = NULL; + const gchar *xml = + "" + " " + " " + " bootloader" + " vendor-id" + " " + " " + " 12345678-1234-1234-1234-123456789012" + " " + " " + " " + " " + " " + " " + ""; /* set up a dummy device */ fu_device_set_version (device, "1.2.3"); @@ -150,35 +311,15 @@ fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012"); /* make the component require three things */ - as_require_set_kind (req1, AS_REQUIRE_KIND_FIRMWARE); - as_require_set_compare (req1, AS_REQUIRE_COMPARE_GE); - as_require_set_version (req1, "1.2.3"); - as_app_add_require (app, req1); - as_require_set_kind (req2, AS_REQUIRE_KIND_FIRMWARE); - as_require_set_compare (req2, AS_REQUIRE_COMPARE_EQ); - as_require_set_version (req2, "4.5.6"); - as_require_set_value (req2, "bootloader"); - as_app_add_require (app, req3); - as_require_set_kind (req3, AS_REQUIRE_KIND_FIRMWARE); - as_require_set_compare (req3, AS_REQUIRE_COMPARE_EQ); - as_require_set_version (req3, "FFFF"); - as_require_set_value (req3, "vendor-id"); - as_app_add_require (app, req3); - - /* add release */ - as_checksum_set_target (csum, AS_CHECKSUM_TARGET_CONTENT); - as_checksum_set_filename (csum, "bios.bin"); - as_release_set_version (rel, "1.2.4"); - as_release_add_checksum (rel, csum); - as_app_add_release (app, rel); - - /* add GUID to match */ - as_provide_set_kind (prov, AS_PROVIDE_KIND_FIRMWARE_FLASHED); - as_provide_set_value (prov, "12345678-1234-1234-1234-123456789012"); - as_app_add_provide (app, prov); + silo = xb_silo_new_from_xml (xml, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + component = xb_silo_query_first (silo, "component", &error); + g_assert_no_error (error); + g_assert_nonnull (component); /* check this passes */ - task = fu_install_task_new (device, app); + task = fu_install_task_new (device, component); ret = fu_engine_check_requirements (engine, task, FWUPD_INSTALL_FLAG_NONE, &error); @@ -190,16 +331,31 @@ fu_engine_requirements_other_device_func (void) { gboolean ret; - g_autoptr(AsApp) app = as_app_new (); - g_autoptr(AsChecksum) csum = as_checksum_new (); - g_autoptr(AsProvide) prov = as_provide_new (); - g_autoptr(AsRelease) rel = as_release_new (); - g_autoptr(AsRequire) req1 = as_require_new (); g_autoptr(FuDevice) device1 = fu_device_new (); g_autoptr(FuDevice) device2 = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); g_autoptr(FuInstallTask) task = NULL; g_autoptr(GError) error = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + const gchar *xml = + "" + " " + " 1ff60ab2-3905-06a1-b476-0371f00c9e9b" + " " + " " + " 12345678-1234-1234-1234-123456789012" + " " + " " + " " + " " + " " + " " + ""; + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); /* set up a dummy device */ fu_device_set_version (device1, "1.2.3"); @@ -211,30 +367,19 @@ fu_device_set_name (device2, "Secondary firmware"); fu_device_set_version (device2, "4.5.6"); fu_device_set_vendor_id (device2, "FFFF"); - fu_device_add_guid (device2, "00000000-0000-0000-0000-000000000000"); + fu_device_add_guid (device2, "1ff60ab2-3905-06a1-b476-0371f00c9e9b"); fu_engine_add_device (engine, device2); - /* make the component require another device version */ - as_require_set_kind (req1, AS_REQUIRE_KIND_FIRMWARE); - as_require_set_compare (req1, AS_REQUIRE_COMPARE_GT); - as_require_set_version (req1, "4.0.0"); - as_require_set_value (req1, "00000000-0000-0000-0000-000000000000"); - as_app_add_require (app, req1); - - /* add release */ - as_checksum_set_target (csum, AS_CHECKSUM_TARGET_CONTENT); - as_checksum_set_filename (csum, "bios.bin"); - as_release_set_version (rel, "1.2.4"); - as_release_add_checksum (rel, csum); - as_app_add_release (app, rel); - - /* add GUID to match */ - as_provide_set_kind (prov, AS_PROVIDE_KIND_FIRMWARE_FLASHED); - as_provide_set_value (prov, "12345678-1234-1234-1234-123456789012"); - as_app_add_provide (app, prov); + /* import firmware metainfo */ + silo = xb_silo_new_from_xml (xml, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + component = xb_silo_query_first (silo, "component", &error); + g_assert_no_error (error); + g_assert_nonnull (component); /* check this passes */ - task = fu_install_task_new (device1, app); + task = fu_install_task_new (device1, component); ret = fu_engine_check_requirements (engine, task, FWUPD_INSTALL_FLAG_NONE, &error); @@ -251,22 +396,29 @@ g_autoptr(FuDevice) device = NULL; g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); g_autoptr(GError) error = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); /* add low prio then high then low */ fu_device_set_id (device1, "id1"); fu_device_set_priority (device1, 0); fu_device_set_plugin (device1, "udev"); - fu_device_add_guid (device1, "GUID1"); + fu_device_add_instance_id (device1, "GUID1"); + fu_device_convert_instance_ids (device1); fu_engine_add_device (engine, device1); fu_device_set_id (device2, "id2"); fu_device_set_priority (device2, 1); fu_device_set_plugin (device2, "redfish"); - fu_device_add_guid (device2, "GUID1"); + fu_device_add_instance_id (device2, "GUID1"); + fu_device_convert_instance_ids (device2); fu_engine_add_device (engine, device2); fu_device_set_id (device3, "id3"); fu_device_set_priority (device3, 0); fu_device_set_plugin (device3, "uefi"); - fu_device_add_guid (device3, "GUID1"); + fu_device_add_instance_id (device3, "GUID1"); + fu_device_convert_instance_ids (device3); fu_engine_add_device (engine, device3); /* get the high prio device */ @@ -294,22 +446,29 @@ g_autoptr(FuDevice) device2 = fu_device_new (); g_autoptr(FuDevice) device3 = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); /* add child */ fu_device_set_id (device1, "child"); - fu_device_add_guid (device1, "child-GUID-1"); + fu_device_add_instance_id (device1, "child-GUID-1"); fu_device_add_parent_guid (device1, "parent-GUID"); + fu_device_convert_instance_ids (device1); fu_engine_add_device (engine, device1); /* parent */ fu_device_set_id (device2, "parent"); - fu_device_add_guid (device2, "parent-GUID"); + fu_device_add_instance_id (device2, "parent-GUID"); fu_device_set_vendor (device2, "oem"); + fu_device_convert_instance_ids (device2); /* add another child */ fu_device_set_id (device3, "child2"); - fu_device_add_guid (device3, "child-GUID-2"); + fu_device_add_instance_id (device3, "child-GUID-2"); fu_device_add_parent_guid (device3, "parent-GUID"); + fu_device_convert_instance_ids (device3); fu_device_add_child (device2, device3); /* add two together */ @@ -338,9 +497,14 @@ g_autoptr(GError) error = NULL; g_autoptr(GError) error_none = NULL; g_autoptr(GError) error_both = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); /* set up dummy plugin */ fu_plugin_set_name (plugin, "test"); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_engine_add_plugin (engine, plugin); /* add two dummy devices */ @@ -394,6 +558,10 @@ g_autoptr(FuDevice) device = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); g_autoptr(GError) error = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + g_autoptr(XbSilo) silo = NULL; /* load engine to get FuConfig set up */ ret = fu_engine_load (engine, &error); @@ -403,9 +571,17 @@ /* add the hardcoded 'fwupd' metadata */ filename = fu_test_get_filename (TESTDATADIR, "metadata.xml"); g_assert (filename != NULL); - ret = fu_engine_load_metadata_from_file (engine, filename, NULL, &error); + file = g_file_new_for_path (filename); + ret = xb_builder_source_load_file (source, file, + XB_BUILDER_SOURCE_FLAG_NONE, + NULL, &error); g_assert_no_error (error); g_assert_true (ret); + xb_builder_import_source (builder, source); + silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_NONE, NULL, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + fu_engine_set_silo (engine, silo); /* add a dummy device */ fu_device_set_id (device, "UEFI-dummy-dev0"); @@ -420,15 +596,16 @@ static void fu_engine_require_hwid_func (void) { - AsApp *app; gboolean ret; g_autofree gchar *filename = NULL; - g_autoptr(AsStore) store = NULL; g_autoptr(FuDevice) device = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); g_autoptr(FuInstallTask) task = NULL; g_autoptr(GBytes) blob_cab = NULL; g_autoptr(GError) error = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + g_autoptr(XbSilo) silo = NULL; #if !defined(HAVE_GCAB_0_8) && defined(__s390x__) /* See https://github.com/hughsie/fwupd/issues/318 for more information */ @@ -436,6 +613,9 @@ return; #endif + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); + /* load engine to get FuConfig set up */ ret = fu_engine_load (engine, &error); g_assert_no_error (error); @@ -447,9 +627,9 @@ blob_cab = fu_common_get_contents_bytes (filename, &error); g_assert_no_error (error); g_assert (blob_cab != NULL); - store = fu_engine_get_store_from_blob (engine, blob_cab, &error); + silo = fu_engine_get_silo_from_blob (engine, blob_cab, &error); g_assert_no_error (error); - g_assert (store != NULL); + g_assert_nonnull (silo); /* add a dummy device */ fu_device_set_id (device, "test_device"); @@ -458,12 +638,13 @@ fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); fu_engine_add_device (engine, device); - /* get app */ - app = as_store_get_app_by_id (store, "com.hughski.test.firmware"); - g_assert_nonnull (app); + /* get component */ + component = xb_silo_query_first (silo, "components/component/id[text()='com.hughski.test.firmware']/..", &error); + g_assert_no_error (error); + g_assert_nonnull (component); /* check requirements */ - task = fu_install_task_new (device, app); + task = fu_install_task_new (device, component); ret = fu_engine_check_requirements (engine, task, FWUPD_INSTALL_FLAG_NONE, &error); @@ -489,6 +670,13 @@ g_autoptr(GPtrArray) releases = NULL; g_autoptr(GPtrArray) releases_up = NULL; g_autoptr(GPtrArray) remotes = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + + /* ensure empty tree */ + fu_self_test_mkroot (); + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); /* write a broken file */ ret = g_file_set_contents ("/tmp/fwupd-self-test/broken.xml.gz", @@ -556,10 +744,6 @@ g_assert_no_error (error); g_assert (ret); - /* expect just one broken remote to fail */ - g_test_expect_message ("FuEngine", G_LOG_LEVEL_WARNING, - "failed to load remote broken: *"); - testdatadir = fu_test_get_filename (TESTDATADIR, "."); g_assert (testdatadir != NULL); g_setenv ("FU_SELF_TEST_REMOTES_DIR", testdatadir, TRUE); @@ -573,7 +757,7 @@ remotes = fu_engine_get_remotes (engine, &error); g_assert_no_error (error); g_assert (remotes != NULL); - g_assert_cmpint (remotes->len, ==, 3); + g_assert_cmpint (remotes->len, ==, 4); /* ensure there are no devices already */ devices_pre = fu_engine_get_devices (engine, &error); @@ -623,27 +807,102 @@ } static void +fu_engine_install_duration_func (void) +{ + FwupdRelease *rel; + gboolean ret; + g_autofree gchar *testdatadir = NULL; + g_autoptr(FuDevice) device = fu_device_new (); + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) devices = NULL; + g_autoptr(GPtrArray) releases = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + + /* ensure empty tree */ + fu_self_test_mkroot (); + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); + + /* write the main file */ + ret = g_file_set_contents ("/tmp/fwupd-self-test/stable.xml", + "" + " " + " test" + " " + " aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" + " " + " " + " " + " https://test.org/foo.cab" + " deadbeefdeadbeefdeadbeefdeadbeef" + " deadbeefdeadbeefdeadbeefdeadbeef" + " " + " " + " " + "", -1, &error); + g_assert_no_error (error); + g_assert (ret); + + testdatadir = fu_test_get_filename (TESTDATADIR, "."); + g_assert (testdatadir != NULL); + g_setenv ("FU_SELF_TEST_REMOTES_DIR", testdatadir, TRUE); + ret = fu_engine_load (engine, &error); + g_assert_no_error (error); + g_assert (ret); + + /* add a device so we can get the install duration */ + fu_device_set_version (device, "1.2.3"); + fu_device_set_id (device, "test_device"); + fu_device_add_guid (device, "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"); + fu_device_set_install_duration (device, 999); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_engine_add_device (engine, device); + devices = fu_engine_get_devices (engine, &error); + g_assert_no_error (error); + g_assert (devices != NULL); + g_assert_cmpint (devices->len, ==, 1); + g_assert (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_SUPPORTED)); + + /* check the release install duration */ + releases = fu_engine_get_releases (engine, fu_device_get_id (device), &error); + g_assert_no_error (error); + g_assert (releases != NULL); + g_assert_cmpint (releases->len, ==, 1); + rel = FWUPD_RELEASE (g_ptr_array_index (releases, 0)); + g_assert_cmpint (fwupd_release_get_install_duration (rel), ==, 120); +} + +static void fu_engine_history_func (void) { - AsApp *app; gboolean ret; + g_autofree gchar *checksum = NULL; g_autofree gchar *device_str_expected = NULL; g_autofree gchar *device_str = NULL; g_autofree gchar *filename = NULL; - g_autofree gchar *checksum = NULL; g_autofree gchar *testdatadir = NULL; - g_autoptr(AsStore) store = NULL; g_autoptr(FuDevice) device2 = NULL; - g_autoptr(FwupdDevice) device3 = NULL; - g_autoptr(FwupdDevice) device4 = NULL; g_autoptr(FuDevice) device = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); g_autoptr(FuHistory) history = NULL; g_autoptr(FuInstallTask) task = NULL; g_autoptr(FuPlugin) plugin = fu_plugin_new (); + g_autoptr(FwupdDevice) device3 = NULL; + g_autoptr(FwupdDevice) device4 = NULL; g_autoptr(GBytes) blob_cab = NULL; g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + g_autoptr(XbSilo) silo = NULL; + + /* ensure empty tree */ + fu_self_test_mkroot (); + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); /* set up dummy plugin */ ret = fu_plugin_open (plugin, PLUGINBUILDDIR "/libfu_plugin_test.so", &error); @@ -665,6 +924,7 @@ fu_device_set_name (device, "Test Device"); fu_device_set_plugin (device, "test"); fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012"); + fu_device_add_checksum (device, "0123456789abcdef0123456789abcdef01234567"); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_set_created (device, 1515338000); fu_engine_add_device (engine, device); @@ -679,21 +939,29 @@ blob_cab = fu_common_get_contents_bytes (filename, &error); g_assert_no_error (error); g_assert (blob_cab != NULL); - store = fu_engine_get_store_from_blob (engine, blob_cab, &error); + silo = fu_engine_get_silo_from_blob (engine, blob_cab, &error); g_assert_no_error (error); - g_assert (store != NULL); + g_assert_nonnull (silo); - /* get app */ - app = as_store_get_app_by_id (store, "com.hughski.test.firmware"); - g_assert_nonnull (app); + /* get component */ + component = xb_silo_query_first (silo, "components/component/id[text()='com.hughski.test.firmware']/..", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + + /* set the counter */ + g_setenv ("FWUPD_PLUGIN_TEST", "another-write-required", TRUE); + fu_device_set_metadata_integer (device, "nr-update", 0); /* install it */ - task = fu_install_task_new (device, app); + task = fu_install_task_new (device, component); ret = fu_engine_install (engine, task, blob_cab, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_no_error (error); g_assert (ret); + /* check the write was done more than once */ + g_assert_cmpint (fu_device_get_metadata_integer (device, "nr-update"), ==, 2); + /* check the history database */ history = fu_history_new (); device2 = fu_history_get_device_by_id (history, fu_device_get_id (device), &error); @@ -719,7 +987,8 @@ " [Release]\n" " Version: 1.2.3\n" " Checksum: SHA1(%s)\n" - " TrustFlags: none\n", + " TrustFlags: none\n" + " VersionFormat: triplet\n", checksum); ret = fu_test_compare_lines (device_str, device_str_expected, &error); g_assert_no_error (error); @@ -747,14 +1016,12 @@ static void fu_engine_history_error_func (void) { - AsApp *app; gboolean ret; + g_autofree gchar *checksum = NULL; g_autofree gchar *device_str_expected = NULL; g_autofree gchar *device_str = NULL; g_autofree gchar *filename = NULL; - g_autofree gchar *checksum = NULL; g_autofree gchar *testdatadir = NULL; - g_autoptr(AsStore) store = NULL; g_autoptr(FuDevice) device2 = NULL; g_autoptr(FuDevice) device = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); @@ -765,6 +1032,12 @@ g_autoptr(GError) error2 = NULL; g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + g_autoptr(XbSilo) silo = NULL; + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); /* set up dummy plugin */ g_setenv ("FWUPD_PLUGIN_TEST", "fail", TRUE); @@ -802,12 +1075,13 @@ blob_cab = fu_common_get_contents_bytes (filename, &error); g_assert_no_error (error); g_assert (blob_cab != NULL); - store = fu_engine_get_store_from_blob (engine, blob_cab, &error); + silo = fu_engine_get_silo_from_blob (engine, blob_cab, &error); g_assert_no_error (error); - g_assert (store != NULL); - app = as_store_get_app_by_id (store, "com.hughski.test.firmware"); - g_assert_nonnull (app); - task = fu_install_task_new (device, app); + g_assert_nonnull (silo); + component = xb_silo_query_first (silo, "components/component/id[text()='com.hughski.test.firmware']/..", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + task = fu_install_task_new (device, component); ret = fu_engine_install (engine, task, blob_cab, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED); @@ -843,7 +1117,8 @@ " [Release]\n" " Version: 1.2.3\n" " Checksum: SHA1(%s)\n" - " TrustFlags: none\n", + " TrustFlags: none\n" + " VersionFormat: triplet\n", checksum); ret = fu_test_compare_lines (device_str, device_str_expected, &error); g_assert_no_error (error); @@ -879,8 +1154,9 @@ /* add one device */ fu_device_set_id (device1, "device1"); - fu_device_add_guid (device1, "foobar"); + fu_device_add_instance_id (device1, "foobar"); fu_device_set_remove_delay (device1, 100); + fu_device_convert_instance_ids (device1); fu_device_list_add (device_list, device1); g_assert_cmpint (added_cnt, ==, 1); g_assert_cmpint (removed_cnt, ==, 0); @@ -1005,15 +1281,17 @@ /* fake devices */ fu_device_set_id (device1, "device1"); - fu_device_add_guid (device1, "foo"); - fu_device_add_guid (device1, "bar"); + fu_device_add_instance_id (device1, "foo"); + fu_device_add_instance_id (device1, "bar"); fu_device_set_plugin (device1, "self-test"); fu_device_set_remove_delay (device1, FU_DEVICE_REMOVE_DELAY_USER_REPLUG); + fu_device_convert_instance_ids (device1); fu_device_set_id (device2, "device2"); - fu_device_add_guid (device2, "baz"); - fu_device_add_guid (device2, "bar"); /* matches */ + fu_device_add_instance_id (device2, "baz"); + fu_device_add_instance_id (device2, "bar"); /* matches */ fu_device_set_plugin (device2, "self-test"); fu_device_set_remove_delay (device2, FU_DEVICE_REMOVE_DELAY_USER_REPLUG); + fu_device_convert_instance_ids (device2); /* not yet added */ ret = fu_device_list_wait_for_replug (device_list, device1, &error); @@ -1069,9 +1347,10 @@ fu_device_set_plugin (device1, "plugin-for-runtime"); fu_device_set_vendor_id (device1, "USB:0x20A0"); fu_device_set_version (device1, "1.2.3"); - fu_device_add_guid (device1, "foobar"); - fu_device_add_guid (device1, "bootloader"); + fu_device_add_instance_id (device1, "foobar"); + fu_device_add_instance_id (device1, "bootloader"); fu_device_set_remove_delay (device1, 100); + fu_device_convert_instance_ids (device1); fu_device_list_add (device_list, device1); g_assert_cmpint (added_cnt, ==, 1); g_assert_cmpint (removed_cnt, ==, 0); @@ -1080,7 +1359,8 @@ /* add another device in bootloader mode */ fu_device_set_id (device2, "device2"); fu_device_set_plugin (device2, "plugin-for-bootloader"); - fu_device_add_guid (device2, "bootloader"); + fu_device_add_instance_id (device2, "bootloader"); + fu_device_convert_instance_ids (device2); /* verify only a changed event was generated */ added_cnt = removed_cnt = changed_cnt = 0; @@ -1139,7 +1419,8 @@ /* add child */ fu_device_set_id (device_child, "child"); - fu_device_add_guid (device_child, "child-GUID-1"); + fu_device_add_instance_id (device_child, "child-GUID-1"); + fu_device_convert_instance_ids (device_child); fu_device_list_add (device_list, device_child); g_assert_cmpint (added_cnt, ==, 1); g_assert_cmpint (removed_cnt, ==, 0); @@ -1147,7 +1428,8 @@ /* add parent */ fu_device_set_id (device_parent, "parent"); - fu_device_add_guid (device_parent, "parent-GUID-1"); + fu_device_add_instance_id (device_parent, "parent-GUID-1"); + fu_device_convert_instance_ids (device_parent); fu_device_add_child (device_parent, device_child); fu_device_list_add (device_list, device_parent); g_assert_cmpint (added_cnt, ==, 2); @@ -1187,10 +1469,12 @@ /* add both */ fu_device_set_id (device1, "device1"); - fu_device_add_guid (device1, "foobar"); + fu_device_add_instance_id (device1, "foobar"); + fu_device_convert_instance_ids (device1); fu_device_list_add (device_list, device1); fu_device_set_id (device2, "device2"); - fu_device_add_guid (device2, "baz"); + fu_device_add_instance_id (device2, "baz"); + fu_device_convert_instance_ids (device2); fu_device_list_add (device_list, device2); g_assert_cmpint (added_cnt, ==, 2); g_assert_cmpint (removed_cnt, ==, 0); @@ -1242,6 +1526,15 @@ } static void +fu_device_version_format_func (void) +{ + g_autoptr(FuDevice) device = fu_device_new (); + fu_device_set_version_format (device, FU_VERSION_FORMAT_TRIPLET); + fu_device_set_version (device, "Ver1.2.3 RELEASE"); + g_assert_cmpstr (fu_device_get_version (device), ==, "1.2.3"); +} + +static void fu_device_open_refcount_func (void) { gboolean ret; @@ -1562,7 +1855,8 @@ fu_device_set_physical_id (device, "usb:00:05"); fu_device_set_quirks (device, quirks); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); - fu_device_add_guid (device, "USB\\VID_0BDA&PID_1100"); + fu_device_add_instance_id (device, "USB\\VID_0BDA&PID_1100"); + fu_device_convert_instance_ids (device); g_assert_cmpstr (fu_device_get_name (device), ==, "Hub"); /* ensure children are created */ @@ -1574,6 +1868,34 @@ } static void +fu_plugin_hash_func (void) +{ + GError *error = NULL; + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuPlugin) plugin = fu_plugin_new (); + gboolean ret = FALSE; + + ret = fu_engine_load (engine, &error); + g_assert_no_error (error); + g_assert (ret); + + /* make sure not tainted */ + ret = fu_engine_get_tainted (engine); + g_assert_false (ret); + + /* create a tainted plugin */ + g_setenv ("FWUPD_PLUGIN_TEST", "build-hash", TRUE); + ret = fu_plugin_open (plugin, PLUGINBUILDDIR "/libfu_plugin_test.so", &error); + g_assert_no_error (error); + + /* make sure it tainted now */ + g_test_expect_message ("FuEngine", G_LOG_LEVEL_WARNING, "* has incorrect built version*"); + fu_engine_add_plugin (engine, plugin); + ret = fu_engine_get_tainted (engine); + g_assert_true (ret); +} + +static void fu_plugin_module_func (void) { GError *error = NULL; @@ -1633,8 +1955,7 @@ g_assert (mapped_file != NULL); blob_cab = g_mapped_file_get_bytes (mapped_file); fwupd_release_set_version (fu_device_get_release_default (device), "1.2.3"); - ret = fu_plugin_runner_update (plugin, device, blob_cab, NULL, - FWUPD_INSTALL_FLAG_OFFLINE, &error); + ret = fu_plugin_runner_schedule_update (plugin, device, blob_cab, &error); g_assert_no_error (error); g_assert (ret); g_assert_cmpint (cnt, ==, 1); @@ -1655,7 +1976,7 @@ pending_cap = g_strdup (fwupd_release_get_filename (release)); /* lets do this online */ - ret = fu_plugin_runner_update (plugin, device, blob_cab, NULL, + ret = fu_plugin_runner_update (plugin, device, blob_cab, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_no_error (error); g_assert (ret); @@ -2279,13 +2600,17 @@ { GError *error = NULL; gboolean ret; - GPtrArray *apps; g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); g_autoptr(FuPlugin) plugin = fu_plugin_new (); - g_autoptr(GPtrArray) devices = NULL; g_autoptr(GBytes) blob = NULL; + g_autoptr(GPtrArray) components = NULL; + g_autoptr(GPtrArray) devices = NULL; g_autoptr(GPtrArray) install_tasks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - g_autoptr(AsStore) store = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + g_autoptr(XbSilo) silo = NULL; + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); /* create CAB file */ blob = _build_cab (GCAB_COMPRESSION_NONE, @@ -2308,6 +2633,9 @@ " \n" " \n" " \n" + " \n" + " plain\n" + " \n" "", "acme.module2.metainfo.xml", "\n" @@ -2318,6 +2646,9 @@ " \n" " \n" " \n" + " \n" + " plain\n" + " \n" "", "firmware.bin", "world", NULL); @@ -2325,11 +2656,13 @@ g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 10240, &error); + silo = fu_common_cab_build_silo (blob, 10240, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + components = xb_silo_query (silo, "components/component", 0, &error); g_assert_no_error (error); - g_assert_nonnull (store); - apps = as_store_get_apps (store); - g_assert_cmpint (apps->len, ==, 3); + g_assert_nonnull (components); + g_assert_cmpint (components->len, ==, 3); /* set up dummy plugin */ g_setenv ("FWUPD_PLUGIN_TEST", "composite", TRUE); @@ -2370,8 +2703,8 @@ } /* produce install tasks */ - for (guint i = 0; i < apps->len; i++) { - AsApp *app = g_ptr_array_index (apps, i); + for (guint i = 0; i < components->len; i++) { + XbNode *component = g_ptr_array_index (components, i); /* do any devices pass the requirements */ for (guint j = 0; j < devices->len; j++) { @@ -2380,14 +2713,14 @@ g_autoptr(GError) error_local = NULL; /* is this component valid for the device */ - task = fu_install_task_new (device, app); + task = fu_install_task_new (device, component); if (!fu_engine_check_requirements (engine, task, 0, &error_local)) { g_debug ("requirement on %s:%s failed: %s", fu_device_get_id (device), - as_app_get_id (app), + xb_node_query_text (component, "id", NULL), error_local->message); continue; } @@ -2432,16 +2765,16 @@ static void fu_common_store_cab_func (void) { - AsApp *app; - AsChecksum *csum; - AsRelease *rel; - AsRequire *req; GBytes *blob_tmp; - g_autoptr(AsStore) store = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbNode) csum = NULL; + g_autoptr(XbNode) rel = NULL; + g_autoptr(XbNode) req = NULL; + g_autoptr(XbSilo) silo = NULL; - /* create store */ + /* create silo */ blob = _build_cab (GCAB_COMPRESSION_NONE, "acme.metainfo.xml", "\n" @@ -2452,9 +2785,8 @@ " \n" " \n" " \n" - " \n" " 5\n" - " 7c211433f02071597741e6ff5a8ea34789abbf43\n" + " 7c211433f02071597741e6ff5a8ea34789abbf43\n" "

We fixed things

\n" "
\n" "
\n" @@ -2469,38 +2801,42 @@ g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 10240, &error); + silo = fu_common_cab_build_silo (blob, 10240, &error); g_assert_no_error (error); - g_assert (store != NULL); + g_assert_nonnull (silo); /* verify */ - app = as_store_get_app_by_id (store, "com.acme.example.firmware"); - g_assert_nonnull (app); - rel = as_app_get_release_default (app); + component = xb_silo_query_first (silo, "components/component/id[text()='com.acme.example.firmware']/..", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + rel = xb_node_query_first (component, "releases/release", &error); + g_assert_no_error (error); g_assert_nonnull (rel); - g_assert_cmpstr (as_release_get_version (rel), ==, "1.2.3"); - csum = as_release_get_checksum_by_target (rel, AS_CHECKSUM_TARGET_CONTENT); - g_assert_cmpstr (as_checksum_get_value (csum), ==, "7c211433f02071597741e6ff5a8ea34789abbf43"); - blob_tmp = as_release_get_blob (rel, "firmware.dfu"); + g_assert_cmpstr (xb_node_get_attr (rel, "version"), ==, "1.2.3"); + csum = xb_node_query_first (rel, "checksum[@target='content']", &error); + g_assert_nonnull (csum); + g_assert_cmpstr (xb_node_get_text (csum), ==, "7c211433f02071597741e6ff5a8ea34789abbf43"); + blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.dfu)"); g_assert_nonnull (blob_tmp); - blob_tmp = as_release_get_blob (rel, "firmware.dfu.asc"); + blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.dfu.asc)"); g_assert_nonnull (blob_tmp); - req = as_app_get_require_by_value (app, AS_REQUIRE_KIND_ID, "org.freedesktop.fwupd"); + req = xb_node_query_first (component, "requires/id", &error); + g_assert_no_error (error); g_assert_nonnull (req); } static void fu_common_store_cab_unsigned_func (void) { - AsApp *app; - AsChecksum *csum; - AsRelease *rel; GBytes *blob_tmp; - g_autoptr(AsStore) store = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbNode) csum = NULL; + g_autoptr(XbNode) rel = NULL; + g_autoptr(XbSilo) silo = NULL; - /* create store */ + /* create silo */ blob = _build_cab (GCAB_COMPRESSION_NONE, "acme.metainfo.xml", "\n" @@ -2515,36 +2851,37 @@ g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 10240, &error); + silo = fu_common_cab_build_silo (blob, 10240, &error); g_assert_no_error (error); - g_assert (store != NULL); + g_assert_nonnull (silo); /* verify */ - app = as_store_get_app_by_id (store, "com.acme.example.firmware"); - g_assert_nonnull (app); - rel = as_app_get_release_default (app); + component = xb_silo_query_first (silo, "components/component/id[text()='com.acme.example.firmware']/..", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + rel = xb_node_query_first (component, "releases/release", &error); + g_assert_no_error (error); g_assert_nonnull (rel); - g_assert_cmpstr (as_release_get_version (rel), ==, "1.2.3"); - csum = as_release_get_checksum_by_target (rel, AS_CHECKSUM_TARGET_CONTENT); - g_assert_cmpstr (as_checksum_get_value (csum), ==, "7c211433f02071597741e6ff5a8ea34789abbf43"); - blob_tmp = as_release_get_blob (rel, "firmware.bin"); + g_assert_cmpstr (xb_node_get_attr (rel, "version"), ==, "1.2.3"); + csum = xb_node_query_first (rel, "checksum[@target='content']", &error); + g_assert_null (csum); + blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.bin)"); g_assert_nonnull (blob_tmp); - blob_tmp = as_release_get_blob (rel, "firmware.bin.asc"); + blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.bin.asc)"); g_assert_null (blob_tmp); } static void fu_common_store_cab_folder_func (void) { - AsApp *app; - AsChecksum *csum; - AsRelease *rel; GBytes *blob_tmp; - g_autoptr(AsStore) store = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbNode) rel = NULL; + g_autoptr(XbSilo) silo = NULL; - /* create store */ + /* create silo */ blob = _build_cab (GCAB_COMPRESSION_NONE, "lvfs\\acme.metainfo.xml", "\n" @@ -2559,26 +2896,26 @@ g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 10240, &error); + silo = fu_common_cab_build_silo (blob, 10240, &error); g_assert_no_error (error); - g_assert (store != NULL); + g_assert_nonnull (silo); /* verify */ - app = as_store_get_app_by_id (store, "com.acme.example.firmware"); - g_assert_nonnull (app); - rel = as_app_get_release_default (app); + component = xb_silo_query_first (silo, "components/component/id[text()='com.acme.example.firmware']/..", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + rel = xb_node_query_first (component, "releases/release", &error); + g_assert_no_error (error); g_assert_nonnull (rel); - g_assert_cmpstr (as_release_get_version (rel), ==, "1.2.3"); - csum = as_release_get_checksum_by_target (rel, AS_CHECKSUM_TARGET_CONTENT); - g_assert_cmpstr (as_checksum_get_value (csum), ==, "7c211433f02071597741e6ff5a8ea34789abbf43"); - blob_tmp = as_release_get_blob (rel, "firmware.bin"); + g_assert_cmpstr (xb_node_get_attr (rel, "version"), ==, "1.2.3"); + blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.bin)"); g_assert_nonnull (blob_tmp); } static void fu_common_store_cab_error_no_metadata_func (void) { - g_autoptr(AsStore) store = NULL; + g_autoptr(XbSilo) silo = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; @@ -2590,15 +2927,15 @@ g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 10240, &error); + silo = fu_common_cab_build_silo (blob, 10240, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert (store == NULL); + g_assert_null (silo); } static void fu_common_store_cab_error_wrong_size_func (void) { - g_autoptr(AsStore) store = NULL; + g_autoptr(XbSilo) silo = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; @@ -2619,15 +2956,15 @@ g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 10240, &error); + silo = fu_common_cab_build_silo (blob, 10240, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert (store == NULL); + g_assert_null (silo); } static void fu_common_store_cab_error_missing_file_func (void) { - g_autoptr(AsStore) store = NULL; + g_autoptr(XbSilo) silo = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; @@ -2647,15 +2984,15 @@ g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 10240, &error); + silo = fu_common_cab_build_silo (blob, 10240, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert (store == NULL); + g_assert_null (silo); } static void fu_common_store_cab_error_size_func (void) { - g_autoptr(AsStore) store = NULL; + g_autoptr(XbSilo) silo = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; @@ -2673,15 +3010,15 @@ g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 123, &error); + silo = fu_common_cab_build_silo (blob, 123, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert (store == NULL); + g_assert_null (silo); } static void fu_common_store_cab_error_wrong_checksum_func (void) { - g_autoptr(AsStore) store = NULL; + g_autoptr(XbSilo) silo = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; @@ -2701,9 +3038,9 @@ g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 10240, &error); + silo = fu_common_cab_build_silo (blob, 10240, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert (store == NULL); + g_assert_null (silo); } static gboolean @@ -2729,7 +3066,7 @@ fu_test_loop_run_with_timeout (100); fu_test_loop_quit (); cnt = fu_device_get_metadata_integer (device, "cnt"); - g_assert_cmpint (cnt, >=, 9); + g_assert_cmpint (cnt, >=, 8); /* disable the poll */ fu_device_set_poll_interval (device, 0); @@ -2838,6 +3175,138 @@ } } +static void +fu_common_version_func (void) +{ + guint i; + struct { + guint32 val; + const gchar *ver; + FuVersionFormat flags; + } version_from_uint32[] = { + { 0x0, "0.0.0.0", FU_VERSION_FORMAT_QUAD }, + { 0xff, "0.0.0.255", FU_VERSION_FORMAT_QUAD }, + { 0xff01, "0.0.255.1", FU_VERSION_FORMAT_QUAD }, + { 0xff0001, "0.255.0.1", FU_VERSION_FORMAT_QUAD }, + { 0xff000100, "255.0.1.0", FU_VERSION_FORMAT_QUAD }, + { 0x0, "0.0.0", FU_VERSION_FORMAT_TRIPLET }, + { 0xff, "0.0.255", FU_VERSION_FORMAT_TRIPLET }, + { 0xff01, "0.0.65281", FU_VERSION_FORMAT_TRIPLET }, + { 0xff0001, "0.255.1", FU_VERSION_FORMAT_TRIPLET }, + { 0xff000100, "255.0.256", FU_VERSION_FORMAT_TRIPLET }, + { 0x0, "0", FU_VERSION_FORMAT_PLAIN }, + { 0xff000100, "4278190336", FU_VERSION_FORMAT_PLAIN }, + { 0x0, "11.0.0.0", FU_VERSION_FORMAT_INTEL_ME }, + { 0xffffffff, "18.31.255.65535", FU_VERSION_FORMAT_INTEL_ME }, + { 0x0b32057a, "11.11.50.1402", FU_VERSION_FORMAT_INTEL_ME }, + { 0xb8320d84, "11.8.50.3460", FU_VERSION_FORMAT_INTEL_ME2 }, + { 0, NULL } + }; + struct { + guint16 val; + const gchar *ver; + FuVersionFormat flags; + } version_from_uint16[] = { + { 0x0, "0.0", FU_VERSION_FORMAT_PAIR }, + { 0xff, "0.255", FU_VERSION_FORMAT_PAIR }, + { 0xff01, "255.1", FU_VERSION_FORMAT_PAIR }, + { 0x0, "0.0", FU_VERSION_FORMAT_BCD }, + { 0x0110, "1.10", FU_VERSION_FORMAT_BCD }, + { 0x9999, "99.99", FU_VERSION_FORMAT_BCD }, + { 0x0, "0", FU_VERSION_FORMAT_PLAIN }, + { 0x1234, "4660", FU_VERSION_FORMAT_PLAIN }, + { 0, NULL } + }; + struct { + const gchar *old; + const gchar *new; + } version_parse[] = { + { "0", "0" }, + { "0x1a", "0.0.26" }, + { "257", "0.0.257" }, + { "1.2.3", "1.2.3" }, + { "0xff0001", "0.255.1" }, + { "16711681", "0.255.1" }, + { "20150915", "20150915" }, + { "dave", "dave" }, + { "0x1x", "0x1x" }, + { NULL, NULL } + }; + + /* check version conversion */ + for (i = 0; version_from_uint32[i].ver != NULL; i++) { + g_autofree gchar *ver = NULL; + ver = fu_common_version_from_uint32 (version_from_uint32[i].val, + version_from_uint32[i].flags); + g_assert_cmpstr (ver, ==, version_from_uint32[i].ver); + } + for (i = 0; version_from_uint16[i].ver != NULL; i++) { + g_autofree gchar *ver = NULL; + ver = fu_common_version_from_uint16 (version_from_uint16[i].val, + version_from_uint16[i].flags); + g_assert_cmpstr (ver, ==, version_from_uint16[i].ver); + } + + /* check version parsing */ + for (i = 0; version_parse[i].old != NULL; i++) { + g_autofree gchar *ver = NULL; + ver = fu_common_version_parse (version_parse[i].old); + g_assert_cmpstr (ver, ==, version_parse[i].new); + } +} + +static void +fu_common_vercmp_func (void) +{ + /* same */ + g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3"), ==, 0); + g_assert_cmpint (fu_common_vercmp ("001.002.003", "001.002.003"), ==, 0); + + /* same, not dotted decimal */ + g_assert_cmpint (fu_common_vercmp ("1.2.3", "0x1020003"), ==, 0); + g_assert_cmpint (fu_common_vercmp ("0x10203", "0x10203"), ==, 0); + + /* upgrade and downgrade */ + g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.4"), <, 0); + g_assert_cmpint (fu_common_vercmp ("001.002.000", "001.002.009"), <, 0); + g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.2"), >, 0); + g_assert_cmpint (fu_common_vercmp ("001.002.009", "001.002.000"), >, 0); + + /* unequal depth */ + g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3.1"), <, 0); + g_assert_cmpint (fu_common_vercmp ("1.2.3.1", "1.2.4"), <, 0); + + /* mixed-alpha-numeric */ + g_assert_cmpint (fu_common_vercmp ("1.2.3a", "1.2.3a"), ==, 0); + g_assert_cmpint (fu_common_vercmp ("1.2.3a", "1.2.3b"), <, 0); + g_assert_cmpint (fu_common_vercmp ("1.2.3b", "1.2.3a"), >, 0); + + /* alpha version append */ + g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3a"), <, 0); + g_assert_cmpint (fu_common_vercmp ("1.2.3a", "1.2.3"), >, 0); + + /* alpha only */ + g_assert_cmpint (fu_common_vercmp ("alpha", "alpha"), ==, 0); + g_assert_cmpint (fu_common_vercmp ("alpha", "beta"), <, 0); + g_assert_cmpint (fu_common_vercmp ("beta", "alpha"), >, 0); + + /* alpha-compare */ + g_assert_cmpint (fu_common_vercmp ("1.2a.3", "1.2a.3"), ==, 0); + g_assert_cmpint (fu_common_vercmp ("1.2a.3", "1.2b.3"), <, 0); + g_assert_cmpint (fu_common_vercmp ("1.2b.3", "1.2a.3"), >, 0); + + /* tilde is all-powerful */ + g_assert_cmpint (fu_common_vercmp ("1.2.3~rc1", "1.2.3~rc1"), ==, 0); + g_assert_cmpint (fu_common_vercmp ("1.2.3~rc1", "1.2.3"), <, 0); + g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3~rc1"), >, 0); + g_assert_cmpint (fu_common_vercmp ("1.2.3~rc2", "1.2.3~rc1"), >, 0); + + /* invalid */ + g_assert_cmpint (fu_common_vercmp ("1", NULL), ==, G_MAXINT); + g_assert_cmpint (fu_common_vercmp (NULL, "1"), ==, G_MAXINT); + g_assert_cmpint (fu_common_vercmp (NULL, NULL), ==, G_MAXINT); +} + int main (int argc, char **argv) { @@ -2852,12 +3321,14 @@ g_setenv ("FWUPD_SYSFSFWDIR", TESTDATADIR_SRC, TRUE); g_setenv ("FWUPD_LOCALSTATEDIR", "/tmp/fwupd-self-test/var", TRUE); - fu_common_rmtree ("/tmp/fwupd-self-test", NULL); - g_assert_cmpint (g_mkdir_with_parents ("/tmp/fwupd-self-test/var/lib/fwupd", 0755), ==, 0); + /* ensure empty tree */ + fu_self_test_mkroot (); /* tests go here */ if (g_test_slow ()) g_test_add_func ("/fwupd/progressbar", fu_progressbar_func); + g_test_add_func ("/fwupd/archive{invalid}", fu_archive_invalid_func); + g_test_add_func ("/fwupd/archive{cab}", fu_archive_cab_func); g_test_add_func ("/fwupd/engine{requirements-other-device}", fu_engine_requirements_other_device_func); g_test_add_func ("/fwupd/device{incorporate}", fu_device_incorporate_func); g_test_add_func ("/fwupd/device{poll}", fu_device_poll_func); @@ -2865,6 +3336,7 @@ g_test_add_func ("/fwupd/device-locker{fail}", fu_device_locker_fail_func); g_test_add_func ("/fwupd/device{metadata}", fu_device_metadata_func); g_test_add_func ("/fwupd/device{open-refcount}", fu_device_open_refcount_func); + g_test_add_func ("/fwupd/device{version-format}", fu_device_version_format_func); g_test_add_func ("/fwupd/device-list", fu_device_list_func); g_test_add_func ("/fwupd/device-list{delay}", fu_device_list_delay_func); g_test_add_func ("/fwupd/device-list{compatible}", fu_device_list_compatible_func); @@ -2883,6 +3355,8 @@ g_test_add_func ("/fwupd/engine{requirements-device}", fu_engine_requirements_device_func); g_test_add_func ("/fwupd/engine{device-auto-parent}", fu_engine_device_parent_func); g_test_add_func ("/fwupd/engine{device-priority}", fu_engine_device_priority_func); + g_test_add_func ("/fwupd/engine{install-duration}", fu_engine_install_duration_func); + g_test_add_func ("/fwupd/engine{generate-md}", fu_engine_generate_md_func); g_test_add_func ("/fwupd/hwids", fu_hwids_func); g_test_add_func ("/fwupd/smbios", fu_smbios_func); g_test_add_func ("/fwupd/smbios3", fu_smbios3_func); @@ -2898,7 +3372,11 @@ g_test_add_func ("/fwupd/plugin{composite}", fu_plugin_composite_func); g_test_add_func ("/fwupd/keyring{gpg}", fu_keyring_gpg_func); g_test_add_func ("/fwupd/keyring{pkcs7}", fu_keyring_pkcs7_func); + g_test_add_func ("/fwupd/plugin{build-hash}", fu_plugin_hash_func); g_test_add_func ("/fwupd/chunk", fu_chunk_func); + g_test_add_func ("/fwupd/common{version-guess-format}", fu_common_version_guess_format_func); + g_test_add_func ("/fwupd/common{version}", fu_common_version_func); + g_test_add_func ("/fwupd/common{vercmp}", fu_common_vercmp_func); g_test_add_func ("/fwupd/common{strstrip}", fu_common_strstrip_func); g_test_add_func ("/fwupd/common{endian}", fu_common_endian_func); g_test_add_func ("/fwupd/common{cab-success}", fu_common_store_cab_func); diff -Nru fwupd-1.1.4/src/fu-smbios.h fwupd-1.2.5/src/fu-smbios.h --- fwupd-1.1.4/src/fu-smbios.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-smbios.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_SMBIOS_H -#define __FU_SMBIOS_H +#pragma once #include @@ -41,5 +40,3 @@ GError **error); G_END_DECLS - -#endif /* __FU_SMBIOS_H */ diff -Nru fwupd-1.1.4/src/fu-test.h fwupd-1.2.5/src/fu-test.h --- fwupd-1.1.4/src/fu-test.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-test.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,11 +4,12 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_TEST_H__ -#define __FU_TEST_H__ +#pragma once #include +G_BEGIN_DECLS + gchar *fu_test_get_filename (const gchar *testdatadirs, const gchar *filename); void fu_test_loop_run_with_timeout (guint timeout_ms); @@ -17,4 +18,4 @@ const gchar *txt2, GError **error); -#endif /* __FU_TEST_H__ */ +G_END_DECLS diff -Nru fwupd-1.1.4/src/fu-tool.c fwupd-1.2.5/src/fu-tool.c --- fwupd-1.1.4/src/fu-tool.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-tool.c 2019-02-25 09:42:18.000000000 +0000 @@ -9,6 +9,7 @@ #include "config.h" #include +#include #include #include #include @@ -16,24 +17,30 @@ #include #include +#include "fu-device-private.h" #include "fu-engine.h" #include "fu-plugin-private.h" #include "fu-progressbar.h" #include "fu-smbios.h" #include "fu-util-common.h" #include "fu-debug.h" +#include "fwupd-common-private.h" #define SYSTEMD_SERVICE "org.freedesktop.systemd1" #define SYSTEMD_OBJECT_PATH "/org/freedesktop/systemd1" #define SYSTEMD_MANAGER_INTERFACE "org.freedesktop.systemd1.Manager" #define SYSTEMD_FWUPD_UNIT "fwupd.service" -/* this is only valid in this file */ -#define FWUPD_ERROR_INVALID_ARGS (FWUPD_ERROR_LAST+1) - /* custom return code */ #define EXIT_NOTHING_TO_DO 2 +typedef enum { + FU_UTIL_OPERATION_UNKNOWN, + FU_UTIL_OPERATION_UPDATE, + FU_UTIL_OPERATION_INSTALL, + FU_UTIL_OPERATION_LAST +} FuUtilOperation; + typedef struct { GCancellable *cancellable; GMainLoop *loop; @@ -41,10 +48,16 @@ GPtrArray *cmd_array; FuEngine *engine; FuProgressbar *progressbar; + gboolean no_reboot_check; + gboolean prepare_blob; + gboolean cleanup_blob; FwupdInstallFlags flags; gboolean show_all_devices; /* only valid in update and downgrade */ + FuUtilOperation current_operation; FwupdDevice *current_device; + gchar *current_message; + FwupdDeviceFlags completion_flags; } FuUtilPrivate; typedef gboolean (*FuUtilPrivateCb) (FuUtilPrivate *util, @@ -76,9 +89,11 @@ g_autoptr(GError) error_local = NULL; /* try to stop any already running daemon */ - connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); - if (connection == NULL) - return FALSE; + connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error_local); + if (connection == NULL) { + g_debug ("Failed to get bus: %s", error_local->message); + return TRUE; + } proxy = g_dbus_proxy_new_sync (connection, G_DBUS_PROXY_FLAGS_NONE, NULL, @@ -120,7 +135,13 @@ } } - return fu_engine_load (priv->engine, error); + if (!fu_engine_load (priv->engine, error)) + return FALSE; + if (fu_engine_get_tainted (priv->engine)) { + g_printerr ("WARNING: This tool has loaded 3rd party code and " + "is no longer supported by the upstream developers!\n"); + } + return TRUE; } static gint @@ -285,6 +306,7 @@ g_object_unref (priv->progressbar); if (priv->context != NULL) g_option_context_free (priv->context); + g_free (priv->current_message); g_free (priv); } @@ -373,6 +395,49 @@ } static gboolean +fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(GPtrArray) devices = NULL; + + /* load engine */ + if (!fu_util_start_engine (priv, error)) + return FALSE; + + /* get devices from daemon */ + devices = fu_engine_get_devices (priv->engine, error); + if (devices == NULL) + return FALSE; + for (guint i = 0; i < devices->len; i++) { + FwupdDevice *dev = g_ptr_array_index (devices, i); + g_autoptr(GPtrArray) rels = NULL; + g_autoptr(GError) error_local = NULL; + + /* not going to have results, so save a D-Bus round-trip */ + if (!fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_SUPPORTED)) + continue; + + /* get the releases for this device and filter for validity */ + rels = fu_engine_get_upgrades (priv->engine, + fwupd_device_get_id (dev), + &error_local); + if (rels == NULL) { + g_printerr ("%s\n", error_local->message); + continue; + } + g_print ("%s", fwupd_device_to_string (dev)); + g_print (" Release information:\n"); + /* print all releases */ + for (guint j = 0; j < rels->len; j++) { + FwupdRelease *rel = g_ptr_array_index (rels, j); + g_print ("%s\n", fwupd_release_to_string (rel)); + } + } + + /* success */ + return TRUE; +} + +static gboolean fu_util_get_details (FuUtilPrivate *priv, gchar **values, GError **error) { g_autoptr(GPtrArray) array = NULL; @@ -531,7 +596,7 @@ } static void -fu_util_install_device_changed_cb (FwupdClient *client, +fu_util_update_device_changed_cb (FwupdClient *client, FwupdDevice *device, FuUtilPrivate *priv) { @@ -543,11 +608,40 @@ return; /* show message in progressbar */ - /* TRANSLATORS: %1 is a device name */ - str = g_strdup_printf (_("Installing %s"), - fwupd_device_get_name (device)); - fu_progressbar_set_title (priv->progressbar, str); + if (priv->current_operation == FU_UTIL_OPERATION_UPDATE) { + /* TRANSLATORS: %1 is a device name */ + str = g_strdup_printf (_("Updating %s…"), + fwupd_device_get_name (device)); + fu_progressbar_set_title (priv->progressbar, str); + } else if (priv->current_operation == FU_UTIL_OPERATION_INSTALL) { + /* TRANSLATORS: %1 is a device name */ + str = g_strdup_printf (_("Installing on %s…"), + fwupd_device_get_name (device)); + fu_progressbar_set_title (priv->progressbar, str); + } else { + g_warning ("no FuUtilOperation set"); + } g_set_object (&priv->current_device, device); + + if (fwupd_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) + priv->completion_flags |= FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN; + else if (fwupd_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT)) + priv->completion_flags |= FWUPD_DEVICE_FLAG_NEEDS_REBOOT; + + if (priv->current_message == NULL) { + const gchar *tmp = fwupd_device_get_update_message (priv->current_device); + if (tmp != NULL) + priv->current_message = g_strdup (tmp); + } +} + +static void +fu_util_display_current_message (FuUtilPrivate *priv) +{ + if (priv->current_message == NULL) + return; + g_print ("%s\n", priv->current_message); + g_clear_pointer (&priv->current_message, g_free); } static gboolean @@ -587,16 +681,47 @@ return FALSE; } + priv->current_operation = FU_UTIL_OPERATION_INSTALL; g_signal_connect (priv->engine, "device-changed", - G_CALLBACK (fu_util_install_device_changed_cb), priv); + G_CALLBACK (fu_util_update_device_changed_cb), priv); /* write bare firmware */ - return fu_engine_install_blob (priv->engine, device, - NULL, /* blob_cab */ - blob_fw, - NULL, /* version */ - priv->flags, - error); + if (priv->prepare_blob) { + g_autoptr(GPtrArray) devices = NULL; + devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + g_ptr_array_add (devices, g_object_ref (device)); + if (!fu_engine_composite_prepare (priv->engine, devices, error)) { + g_prefix_error (error, "failed to prepare composite action: "); + return FALSE; + } + } + if (!fu_engine_install_blob (priv->engine, device, blob_fw, priv->flags, error)) + return FALSE; + if (priv->cleanup_blob) { + g_autoptr(FuDevice) device_new = NULL; + g_autoptr(GError) error_local = NULL; + + /* get the possibly new device from the old ID */ + device_new = fu_engine_get_device (priv->engine, + fu_device_get_id (device), + &error_local); + if (device_new == NULL) { + g_debug ("failed to find new device: %s", + error_local->message); + } else { + g_autoptr(GPtrArray) devices_new = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + g_ptr_array_add (devices_new, g_steal_pointer (&device_new)); + if (!fu_engine_composite_cleanup (priv->engine, devices_new, error)) { + g_prefix_error (error, "failed to cleanup composite action: "); + return FALSE; + } + } + } + + fu_util_display_current_message (priv); + + /* success */ + return fu_util_prompt_complete (priv->completion_flags, TRUE, error); } static gint @@ -651,13 +776,13 @@ static gboolean fu_util_install (FuUtilPrivate *priv, gchar **values, GError **error) { - GPtrArray *apps; g_autofree gchar *filename = NULL; - g_autoptr(AsStore) store = NULL; g_autoptr(GBytes) blob_cab = NULL; + g_autoptr(GPtrArray) components = NULL; g_autoptr(GPtrArray) devices_possible = NULL; g_autoptr(GPtrArray) errors = NULL; g_autoptr(GPtrArray) install_tasks = NULL; + g_autoptr(XbSilo) silo = NULL; /* load engine */ if (!fu_util_start_engine (priv, error)) @@ -689,22 +814,24 @@ if (filename == NULL) return FALSE; - /* parse store */ + /* parse silo */ blob_cab = fu_common_get_contents_bytes (filename, error); if (blob_cab == NULL) { fu_util_maybe_prefix_sandbox_error (filename, error); return FALSE; } - store = fu_engine_get_store_from_blob (priv->engine, blob_cab, error); - if (store == NULL) + silo = fu_engine_get_silo_from_blob (priv->engine, blob_cab, error); + if (silo == NULL) + return FALSE; + components = xb_silo_query (silo, "components/component", 0, error); + if (components == NULL) return FALSE; - apps = as_store_get_apps (store); - /* for each component in the store */ + /* for each component in the silo */ errors = g_ptr_array_new_with_free_func ((GDestroyNotify) g_error_free); install_tasks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - for (guint i = 0; i < apps->len; i++) { - AsApp *app = g_ptr_array_index (apps, i); + for (guint i = 0; i < components->len; i++) { + XbNode *component = g_ptr_array_index (components, i); /* do any devices pass the requirements */ for (guint j = 0; j < devices_possible->len; j++) { @@ -713,18 +840,21 @@ g_autoptr(GError) error_local = NULL; /* is this component valid for the device */ - task = fu_install_task_new (device, app); + task = fu_install_task_new (device, component); if (!fu_engine_check_requirements (priv->engine, task, priv->flags, &error_local)) { g_debug ("requirement on %s:%s failed: %s", fu_device_get_id (device), - as_app_get_id (app), + xb_node_query_text (component, "id", NULL), error_local->message); g_ptr_array_add (errors, g_steal_pointer (&error_local)); continue; } + /* if component should have an update message from CAB */ + fu_device_incorporate_from_component (device, component); + /* success */ g_ptr_array_add (install_tasks, g_steal_pointer (&task)); } @@ -740,15 +870,106 @@ return FALSE; } + priv->current_operation = FU_UTIL_OPERATION_INSTALL; g_signal_connect (priv->engine, "device-changed", - G_CALLBACK (fu_util_install_device_changed_cb), priv); + G_CALLBACK (fu_util_update_device_changed_cb), priv); /* install all the tasks */ if (!fu_engine_install_tasks (priv->engine, install_tasks, blob_cab, priv->flags, error)) return FALSE; + fu_util_display_current_message (priv); + + /* we don't want to ask anything */ + if (priv->no_reboot_check) { + g_debug ("skipping reboot check"); + return TRUE; + } + /* success */ - return TRUE; + return fu_util_prompt_complete (priv->completion_flags, TRUE, error); +} + +static gboolean +fu_util_update (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(GPtrArray) devices = NULL; + + /* load engine */ + if (!fu_util_start_engine (priv, error)) + return FALSE; + + priv->current_operation = FU_UTIL_OPERATION_UPDATE; + g_signal_connect (priv->engine, "device-changed", + G_CALLBACK (fu_util_update_device_changed_cb), priv); + + devices = fu_engine_get_devices (priv->engine, error); + if (devices == NULL) + return FALSE; + for (guint i = 0; i < devices->len; i++) { + FwupdDevice *dev = g_ptr_array_index (devices, i); + FwupdRelease *rel; + const gchar *remote_id; + const gchar *device_id; + const gchar *uri_tmp; + g_autoptr(GPtrArray) rels = NULL; + g_autoptr(GError) error_local = NULL; + + if (!fu_util_is_interesting_device (dev)) + continue; + /* only show stuff that has metadata available */ + if (!fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_SUPPORTED)) + continue; + + device_id = fu_device_get_id (dev); + rels = fu_engine_get_upgrades (priv->engine, device_id, &error_local); + if (rels == NULL) { + g_printerr ("%s\n", error_local->message); + continue; + } + + rel = g_ptr_array_index (rels, 0); + uri_tmp = fwupd_release_get_uri (rel); + remote_id = fwupd_release_get_remote_id (rel); + if (remote_id != NULL) { + FwupdRemote *remote; + g_auto(GStrv) argv = NULL; + + remote = fu_engine_get_remote_by_id (priv->engine, + remote_id, + &error_local); + if (remote == NULL) { + g_printerr ("%s\n", error_local->message); + continue; + } + + argv = g_new0 (gchar *, 2); + /* local remotes have the firmware already */ + if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL) { + const gchar *fn_cache = fwupd_remote_get_filename_cache (remote); + g_autofree gchar *path = g_path_get_dirname (fn_cache); + argv[0] = g_build_filename (path, uri_tmp, NULL); + } else if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DIRECTORY) { + argv[0] = g_strdup (uri_tmp + 7); + /* web remote, fu_util_install will download file */ + } else { + argv[0] = fwupd_remote_build_firmware_uri (remote, uri_tmp, error); + } + if (!fu_util_install (priv, argv, &error_local)) { + g_printerr ("%s\n", error_local->message); + continue; + } + fu_util_display_current_message (priv); + } + } + + /* we don't want to ask anything */ + if (priv->no_reboot_check) { + g_debug ("skipping reboot check"); + return TRUE; + } + + return fu_util_prompt_complete (priv->completion_flags, TRUE, error); } static gboolean @@ -906,6 +1127,94 @@ return TRUE; } +static gboolean +fu_util_firmware_builder (FuUtilPrivate *priv, gchar **values, GError **error) +{ + const gchar *script_fn = "startup.sh"; + const gchar *output_fn = "firmware.bin"; + g_autoptr(GBytes) archive_blob = NULL; + g_autoptr(GBytes) firmware_blob = NULL; + if (g_strv_length (values) < 2) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments"); + return FALSE; + } + archive_blob = fu_common_get_contents_bytes (values[0], error); + if (archive_blob == NULL) + return FALSE; + if (g_strv_length (values) > 2) + script_fn = values[2]; + if (g_strv_length (values) > 3) + output_fn = values[3]; + firmware_blob = fu_common_firmware_builder (archive_blob, script_fn, output_fn, error); + if (firmware_blob == NULL) + return FALSE; + return fu_common_set_contents_bytes (values[1], firmware_blob, error); +} + +static void +fu_util_device_added_cb (FwupdClient *client, + FwupdDevice *device, + gpointer user_data) +{ + g_autofree gchar *tmp = fwupd_device_to_string (device); + /* TRANSLATORS: this is when a device is hotplugged */ + g_print ("%s\n%s", _("Device added:"), tmp); +} + +static void +fu_util_device_removed_cb (FwupdClient *client, + FwupdDevice *device, + gpointer user_data) +{ + g_autofree gchar *tmp = fwupd_device_to_string (device); + /* TRANSLATORS: this is when a device is hotplugged */ + g_print ("%s\n%s", _("Device removed:"), tmp); +} + +static void +fu_util_device_changed_cb (FwupdClient *client, + FwupdDevice *device, + gpointer user_data) +{ + g_autofree gchar *tmp = fwupd_device_to_string (device); + /* TRANSLATORS: this is when a device has been updated */ + g_print ("%s\n%s", _("Device changed:"), tmp); +} + +static void +fu_util_changed_cb (FwupdClient *client, gpointer user_data) +{ + /* TRANSLATORS: this is when the daemon state changes */ + g_print ("%s\n", _("Changed")); +} + +static gboolean +fu_util_monitor (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(FwupdClient) client = fwupd_client_new (); + + /* get all the devices */ + if (!fwupd_client_connect (client, priv->cancellable, error)) + return FALSE; + + /* watch for any hotplugged device */ + g_signal_connect (client, "changed", + G_CALLBACK (fu_util_changed_cb), priv); + g_signal_connect (client, "device-added", + G_CALLBACK (fu_util_device_added_cb), priv); + g_signal_connect (client, "device-removed", + G_CALLBACK (fu_util_device_removed_cb), priv); + g_signal_connect (client, "device-changed", + G_CALLBACK (fu_util_device_changed_cb), priv); + g_signal_connect (priv->cancellable, "cancelled", + G_CALLBACK (fu_util_cancelled_cb), priv); + g_main_loop_run (priv->loop); + return TRUE; +} + int main (int argc, char *argv[]) { @@ -914,6 +1223,7 @@ gboolean force = FALSE; gboolean ret; gboolean version = FALSE; + gboolean interactive = isatty (fileno (stdout)) != 0; g_auto(GStrv) plugin_glob = NULL; g_autoptr(FuUtilPrivate) priv = g_new0 (FuUtilPrivate, 1); g_autoptr(GError) error = NULL; @@ -931,12 +1241,22 @@ { "force", '\0', 0, G_OPTION_ARG_NONE, &force, /* TRANSLATORS: command line option */ _("Override plugin warning"), NULL }, + { "no-reboot-check", '\0', 0, G_OPTION_ARG_NONE, &priv->no_reboot_check, + /* TRANSLATORS: command line option */ + _("Do not check for reboot after update"), NULL }, { "show-all-devices", '\0', 0, G_OPTION_ARG_NONE, &priv->show_all_devices, /* TRANSLATORS: command line option */ _("Show devices that are not updatable"), NULL }, { "plugin-whitelist", '\0', 0, G_OPTION_ARG_STRING_ARRAY, &plugin_glob, /* TRANSLATORS: command line option */ _("Manually whitelist specific plugins"), NULL }, + { "prepare", '\0', 0, G_OPTION_ARG_NONE, &priv->prepare_blob, + /* TRANSLATORS: command line option */ + _("Run the plugin composite prepare routine when using install-blob"), NULL }, + { "cleanup", '\0', 0, G_OPTION_ARG_NONE, &priv->cleanup_blob, + /* TRANSLATORS: command line option */ + _("Run the plugin composite cleanup routine when using install-blob"), NULL }, + { NULL} }; @@ -947,7 +1267,7 @@ textdomain (GETTEXT_PACKAGE); /* ensure root user */ - if (getuid () != 0 || geteuid () != 0) + if (interactive && (getuid () != 0 || geteuid () != 0)) /* TRANSLATORS: we're poking around as a power user */ g_printerr ("%s\n", _("This program may only work correctly as root")); @@ -958,6 +1278,12 @@ /* add commands */ priv->cmd_array = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_util_item_free); fu_util_add (priv->cmd_array, + "build-firmware", + "FILE-IN FILE-OUT [SCRIPT] [OUTPUT]", + /* TRANSLATORS: command description */ + _("Build firmware using a sandbox"), + fu_util_firmware_builder); + fu_util_add (priv->cmd_array, "smbios-dump", "FILE", /* TRANSLATORS: command description */ @@ -976,6 +1302,12 @@ _("Gets details about a firmware file"), fu_util_get_details); fu_util_add (priv->cmd_array, + "get-updates", + NULL, + /* TRANSLATORS: command description */ + _("Gets the list of updates for connected hardware"), + fu_util_get_updates); + fu_util_add (priv->cmd_array, "get-devices", NULL, /* TRANSLATORS: command description */ @@ -1023,6 +1355,18 @@ /* TRANSLATORS: command description */ _("Return all the hardware IDs for the machine"), fu_util_hwids); + fu_util_add (priv->cmd_array, + "monitor", + NULL, + /* TRANSLATORS: command description */ + _("Monitor the daemon for events"), + fu_util_monitor); + fu_util_add (priv->cmd_array, + "update", + NULL, + /* TRANSLATORS: command description */ + _("Update all devices that match local metadata"), + fu_util_update); /* do stuff on ctrl+c */ priv->cancellable = g_cancellable_new (); @@ -1036,6 +1380,12 @@ g_ptr_array_sort (priv->cmd_array, (GCompareFunc) fu_sort_command_name_cb); + /* non-TTY consoles cannot answer questions */ + if (!interactive) { + priv->no_reboot_check = TRUE; + fu_progressbar_set_interactive (priv->progressbar, FALSE); + } + /* get a list of the commands */ priv->context = g_option_context_new (NULL); cmd_descriptions = fu_util_get_descriptions (priv->cmd_array); diff -Nru fwupd-1.1.4/src/fu-udev-device.c fwupd-1.2.5/src/fu-udev-device.c --- fwupd-1.1.4/src/fu-udev-device.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-udev-device.c 2019-02-25 09:42:18.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017-2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -83,6 +83,32 @@ return (guint16) g_ascii_strtoull (buf, NULL, 16); } +static void +fu_udev_device_dump_internal (GUdevDevice *udev_device) +{ +#ifdef HAVE_GUDEV_232 + const gchar * const *keys; + + keys = g_udev_device_get_property_keys (udev_device); + for (guint i = 0; keys[i] != NULL; i++) { + g_debug ("%s={%s}", keys[i], + g_udev_device_get_property (udev_device, keys[i])); + } + keys = g_udev_device_get_sysfs_attr_keys (udev_device); + for (guint i = 0; keys[i] != NULL; i++) { + g_debug ("%s=[%s]", keys[i], + g_udev_device_get_sysfs_attr (udev_device, keys[i])); + } +#endif +} + +void +fu_udev_device_dump (FuUdevDevice *self) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + fu_udev_device_dump_internal (priv->udev_device); +} + static gboolean fu_udev_device_probe (FuDevice *device, GError **error) { @@ -91,6 +117,7 @@ FuUdevDevicePrivate *priv = GET_PRIVATE (self); const gchar *tmp; g_autofree gchar *subsystem = NULL; + g_autoptr(GUdevDevice) udev_parent = NULL; /* set ven:dev:rev */ priv->vendor = fu_udev_device_get_sysfs_attr_as_uint64 (priv->udev_device, "vendor"); @@ -98,17 +125,18 @@ priv->revision = fu_udev_device_get_sysfs_attr_as_uint64 (priv->udev_device, "revision"); /* fallback to the parent */ - if (priv->vendor == 0x0 && priv->model == 0x0 && priv->revision == 0x0) { - g_autoptr(GUdevDevice) parent = g_udev_device_get_parent (priv->udev_device); - priv->vendor = fu_udev_device_get_sysfs_attr_as_uint64 (parent, "vendor"); - priv->model = fu_udev_device_get_sysfs_attr_as_uint64 (parent, "device"); - priv->revision = fu_udev_device_get_sysfs_attr_as_uint64 (parent, "revision"); + udev_parent = g_udev_device_get_parent (priv->udev_device); + if (udev_parent != NULL && + priv->vendor == 0x0 && priv->model == 0x0 && priv->revision == 0x0) { + priv->vendor = fu_udev_device_get_sysfs_attr_as_uint64 (udev_parent, "vendor"); + priv->model = fu_udev_device_get_sysfs_attr_as_uint64 (udev_parent, "device"); + priv->revision = fu_udev_device_get_sysfs_attr_as_uint64 (udev_parent, "revision"); } /* hidraw helpfully encodes the information in a different place */ - if (priv->vendor == 0x0 && priv->model == 0x0 && priv->revision == 0x0 && + if (udev_parent != NULL && + priv->vendor == 0x0 && priv->model == 0x0 && priv->revision == 0x0 && g_strcmp0 (g_udev_device_get_subsystem (priv->udev_device), "hidraw") == 0) { - g_autoptr(GUdevDevice) udev_parent = g_udev_device_get_parent (priv->udev_device); tmp = g_udev_device_get_property (udev_parent, "HID_ID"); if (tmp != NULL && strlen (tmp) == 22) { priv->vendor = fu_udev_device_read_uint16 (tmp + 10); @@ -139,6 +167,8 @@ tmp = g_udev_device_get_property (priv->udev_device, "FWUPD_MODEL"); if (tmp == NULL) tmp = g_udev_device_get_property (priv->udev_device, "ID_MODEL_FROM_DATABASE"); + if (tmp == NULL) + tmp = g_udev_device_get_property (priv->udev_device, "ID_MODEL"); if (tmp != NULL) fu_device_set_name (device, tmp); } @@ -148,10 +178,28 @@ tmp = g_udev_device_get_property (priv->udev_device, "FWUPD_VENDOR"); if (tmp == NULL) tmp = g_udev_device_get_property (priv->udev_device, "ID_VENDOR_FROM_DATABASE"); + if (tmp == NULL) + tmp = g_udev_device_get_property (priv->udev_device, "ID_VENDOR"); if (tmp != NULL) fu_device_set_vendor (device, tmp); } + /* set serial */ + if (fu_device_get_serial (device) == NULL) { + tmp = g_udev_device_get_property (priv->udev_device, "ID_SERIAL_SHORT"); + if (tmp == NULL) + tmp = g_udev_device_get_property (priv->udev_device, "ID_SERIAL"); + if (tmp != NULL) + fu_device_set_serial (device, tmp); + } + + /* set revision */ + if (fu_device_get_version (device) == NULL) { + tmp = g_udev_device_get_property (priv->udev_device, "ID_REVISION"); + if (tmp != NULL) + fu_device_set_version (device, tmp); + } + /* set vendor ID */ subsystem = g_ascii_strup (fu_udev_device_get_subsystem (self), -1); if (subsystem != NULL && priv->vendor != 0x0000) { @@ -166,18 +214,18 @@ devid = g_strdup_printf ("%s\\VEN_%04X&DEV_%04X&REV_%02X", subsystem, priv->vendor, priv->model, priv->revision); - fu_device_add_guid (device, devid); + fu_device_add_instance_id (device, devid); } if (priv->vendor != 0x0000 && priv->model != 0x0000) { g_autofree gchar *devid = NULL; devid = g_strdup_printf ("%s\\VEN_%04X&DEV_%04X", subsystem, priv->vendor, priv->model); - fu_device_add_guid (device, devid); + fu_device_add_instance_id (device, devid); } if (priv->vendor != 0x0000) { g_autofree gchar *devid = NULL; devid = g_strdup_printf ("%s\\VEN_%04X", subsystem, priv->vendor); - fu_device_add_guid (device, devid); + fu_device_add_instance_id (device, devid); } /* subclassed */ @@ -203,6 +251,24 @@ return; } +guint +fu_udev_device_get_slot_depth (FuUdevDevice *self, const gchar *subsystem) +{ + GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (self)); + g_autoptr(GUdevDevice) device_tmp = NULL; + + device_tmp = g_udev_device_get_parent_with_subsystem (udev_device, subsystem, NULL); + if (device_tmp == NULL) + return 0; + for (guint i = 0; i < 0xff; i++) { + g_autoptr(GUdevDevice) parent = g_udev_device_get_parent (device_tmp); + if (parent == NULL) + return i; + g_set_object (&device_tmp, parent); + } + return 0; +} + static void fu_udev_device_incorporate (FuDevice *self, FuDevice *donor) { @@ -320,6 +386,29 @@ return priv->revision; } +static GString * +fu_udev_device_get_parent_subsystems (FuUdevDevice *self) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + GString *str = g_string_new (NULL); + g_autoptr(GUdevDevice) udev_device = g_object_ref (priv->udev_device); + + /* find subsystems of all parent devices */ + while (TRUE) { + g_autoptr(GUdevDevice) parent = g_udev_device_get_parent (udev_device); + if (parent == NULL) + break; + if (g_udev_device_get_subsystem (parent) != NULL) { + g_string_append_printf (str, "%s,", + g_udev_device_get_subsystem (parent)); + } + g_set_object (&udev_device, g_steal_pointer (&parent)); + } + if (str->len > 0) + g_string_truncate (str, str->len - 1); + return str; +} + /** * fu_udev_device_set_physical_id: * @self: A #GUdevDevice @@ -352,11 +441,13 @@ udev_device = g_udev_device_get_parent_with_subsystem (priv->udev_device, subsystem, NULL); if (udev_device == NULL) { + g_autoptr(GString) str = NULL; + str = fu_udev_device_get_parent_subsystems (self); g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, - "failed to find device with subsystem %s", - subsystem); + "failed to find device with subsystem %s, only got %s", + subsystem, str->str); return FALSE; } } @@ -370,7 +461,8 @@ return FALSE; } physical_id = g_strdup_printf ("PCI_SLOT_NAME=%s", tmp); - } else if (g_strcmp0 (subsystem, "usb") == 0) { + } else if (g_strcmp0 (subsystem, "usb") == 0 || + g_strcmp0 (subsystem, "scsi") == 0) { tmp = g_udev_device_get_property (udev_device, "DEVPATH"); if (tmp == NULL) { g_set_error_literal (error, diff -Nru fwupd-1.1.4/src/fu-udev-device.h fwupd-1.2.5/src/fu-udev-device.h --- fwupd-1.1.4/src/fu-udev-device.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-udev-device.h 2019-02-25 09:42:18.000000000 +0000 @@ -1,11 +1,10 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017-2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_UDEV_DEVICE_H -#define __FU_UDEV_DEVICE_H +#pragma once #include #include @@ -32,10 +31,11 @@ guint16 fu_udev_device_get_vendor (FuUdevDevice *self); guint16 fu_udev_device_get_model (FuUdevDevice *self); guint8 fu_udev_device_get_revision (FuUdevDevice *self); +guint fu_udev_device_get_slot_depth (FuUdevDevice *self, + const gchar *subsystem); gboolean fu_udev_device_set_physical_id (FuUdevDevice *self, const gchar *subsystem, GError **error); +void fu_udev_device_dump (FuUdevDevice *self); G_END_DECLS - -#endif /* __FU_UDEV_DEVICE_H */ diff -Nru fwupd-1.1.4/src/fu-udev-device-private.h fwupd-1.2.5/src/fu-udev-device-private.h --- fwupd-1.1.4/src/fu-udev-device-private.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-udev-device-private.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_UDEV_DEVICE_PRIVATE_H -#define __FU_UDEV_DEVICE_PRIVATE_H +#pragma once #include "fu-udev-device.h" @@ -14,5 +13,3 @@ void fu_udev_device_emit_changed (FuUdevDevice *self); G_END_DECLS - -#endif /* __FU_UDEV_DEVICE_PRIVATE_H */ diff -Nru fwupd-1.1.4/src/fu-usb-device.c fwupd-1.2.5/src/fu-usb-device.c --- fwupd-1.1.4/src/fu-usb-device.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-usb-device.c 2019-02-25 09:42:18.000000000 +0000 @@ -8,8 +8,6 @@ #include "config.h" -#include - #include "fu-usb-device-private.h" /** @@ -230,6 +228,7 @@ g_autofree gchar *devid1 = NULL; g_autofree gchar *devid2 = NULL; g_autofree gchar *vendor_id = NULL; + g_autoptr(GPtrArray) intfs = NULL; /* set vendor ID */ vendor_id = g_strdup_printf ("USB:0x%04X", g_usb_device_get_vid (priv->usb_device)); @@ -238,8 +237,8 @@ /* set the version if the release has been set */ release = g_usb_device_get_release (priv->usb_device); if (release != 0x0) { - g_autofree gchar *version = as_utils_version_from_uint16 (release, - AS_VERSION_PARSE_FLAG_USE_BCD); + g_autofree gchar *version = NULL; + version = fu_common_version_from_uint16 (release, FU_VERSION_FORMAT_BCD); fu_device_set_version (device, version); } @@ -248,14 +247,37 @@ g_usb_device_get_vid (priv->usb_device), g_usb_device_get_pid (priv->usb_device), release); - fu_device_add_guid (device, devid2); + fu_device_add_instance_id (device, devid2); devid1 = g_strdup_printf ("USB\\VID_%04X&PID_%04X", g_usb_device_get_vid (priv->usb_device), g_usb_device_get_pid (priv->usb_device)); - fu_device_add_guid (device, devid1); + fu_device_add_instance_id (device, devid1); devid0 = g_strdup_printf ("USB\\VID_%04X", g_usb_device_get_vid (priv->usb_device)); - fu_device_add_guid (device, devid0); + fu_device_add_instance_id (device, devid0); + + /* add the interface GUIDs */ + intfs = g_usb_device_get_interfaces (priv->usb_device, error); + if (intfs == NULL) + return FALSE; + for (guint i = 0; i < intfs->len; i++) { + GUsbInterface *intf = g_ptr_array_index (intfs, i); + g_autofree gchar *intid1 = NULL; + g_autofree gchar *intid2 = NULL; + g_autofree gchar *intid3 = NULL; + intid1 = g_strdup_printf ("USB\\CLASS_%02X&SUBCLASS_%02X&PROT_%02X", + g_usb_interface_get_class (intf), + g_usb_interface_get_subclass (intf), + g_usb_interface_get_protocol (intf)); + fu_device_add_instance_id (device, intid1); + intid2 = g_strdup_printf ("USB\\CLASS_%02X&SUBCLASS_%02X", + g_usb_interface_get_class (intf), + g_usb_interface_get_subclass (intf)); + fu_device_add_instance_id (device, intid2); + intid3 = g_strdup_printf ("USB\\CLASS_%02X", + g_usb_interface_get_class (intf)); + fu_device_add_instance_id (device, intid3); + } /* subclassed */ if (klass->probe != NULL) { diff -Nru fwupd-1.1.4/src/fu-usb-device.h fwupd-1.2.5/src/fu-usb-device.h --- fwupd-1.1.4/src/fu-usb-device.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-usb-device.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_USB_DEVICE_H -#define __FU_USB_DEVICE_H +#pragma once #include #include @@ -48,5 +47,3 @@ gboolean fu_usb_device_is_open (FuUsbDevice *device); G_END_DECLS - -#endif /* __FU_USB_DEVICE_H */ diff -Nru fwupd-1.1.4/src/fu-usb-device-private.h fwupd-1.2.5/src/fu-usb-device-private.h --- fwupd-1.1.4/src/fu-usb-device-private.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-usb-device-private.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,8 +4,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_USB_DEVICE_PRIVATE_H -#define __FU_USB_DEVICE_PRIVATE_H +#pragma once #include "fu-usb-device.h" @@ -14,5 +13,3 @@ const gchar *fu_usb_device_get_platform_id (FuUsbDevice *self); G_END_DECLS - -#endif /* __FU_USB_DEVICE_PRIVATE_H */ diff -Nru fwupd-1.1.4/src/fu-util.c fwupd-1.2.5/src/fu-util.c --- fwupd-1.1.4/src/fu-util.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-util.c 2019-02-25 09:42:18.000000000 +0000 @@ -9,7 +9,7 @@ #include "config.h" #include -#include +#include #include #include #include @@ -29,9 +29,6 @@ #include "fu-util-common.h" #include "fwupd-common-private.h" -/* this is only valid in this file */ -#define FWUPD_ERROR_INVALID_ARGS (FWUPD_ERROR_LAST+1) - /* custom return code */ #define EXIT_NOTHING_TO_DO 2 @@ -60,6 +57,8 @@ /* only valid in update and downgrade */ FuUtilOperation current_operation; FwupdDevice *current_device; + gchar *current_message; + FwupdDeviceFlags completion_flags; } FuUtilPrivate; typedef gboolean (*FuUtilPrivateCb) (FuUtilPrivate *util, @@ -230,6 +229,17 @@ g_warning ("no FuUtilOperation set"); } g_set_object (&priv->current_device, device); + + if (fwupd_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) + priv->completion_flags |= FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN; + else if (fwupd_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT)) + priv->completion_flags |= FWUPD_DEVICE_FLAG_NEEDS_REBOOT; + + if (priv->current_message == NULL) { + const gchar *tmp = fwupd_device_get_update_message (priv->current_device); + if (tmp != NULL) + priv->current_message = g_strdup (tmp); + } } static FwupdDevice * @@ -439,6 +449,60 @@ return fu_util_report_history (priv, NULL, error); } +static gchar * +fu_util_convert_appstream_description (const gchar *xml, GError **error) +{ + g_autoptr(GString) str = g_string_new (NULL); + g_autoptr(XbNode) n = NULL; + g_autoptr(XbSilo) silo = NULL; + + /* parse XML */ + silo = xb_silo_new_from_xml (xml, error); + if (silo == NULL) + return NULL; + + n = xb_silo_get_root (silo); + while (n != NULL) { + g_autoptr(XbNode) n2 = NULL; + + /* support

,

    ,
      and
    1. , ignore all else */ + if (g_strcmp0 (xb_node_get_element (n), "p") == 0) { + g_string_append_printf (str, "%s\n\n", xb_node_get_text (n)); + } else if (g_strcmp0 (xb_node_get_element (n), "ul") == 0) { + g_autoptr(GPtrArray) children = xb_node_get_children (n); + for (guint i = 0; i < children->len; i++) { + XbNode *nc = g_ptr_array_index (children, i); + if (g_strcmp0 (xb_node_get_element (nc), "li") == 0) { + g_string_append_printf (str, " • %s\n", + xb_node_get_text (nc)); + } + } + g_string_append (str, "\n"); + } else if (g_strcmp0 (xb_node_get_element (n), "ol") == 0) { + g_autoptr(GPtrArray) children = xb_node_get_children (n); + for (guint i = 0; i < children->len; i++) { + XbNode *nc = g_ptr_array_index (children, i); + if (g_strcmp0 (xb_node_get_element (nc), "li") == 0) { + g_string_append_printf (str, " %u. %s\n", + i + 1, + xb_node_get_text (nc)); + } + } + g_string_append (str, "\n"); + } + + n2 = xb_node_get_next (n); + g_set_object (&n, n2); + } + + /* remove extra newline */ + if (str->len > 0) + g_string_truncate (str, str->len - 1); + + /* success */ + return g_string_free (g_steal_pointer (&str), FALSE); +} + static gboolean fu_util_modify_remote_warning (FuUtilPrivate *priv, FwupdRemote *remote, GError **error) { @@ -449,7 +513,7 @@ warning_markup = fwupd_remote_get_agreement (remote); if (warning_markup == NULL) return TRUE; - warning_plain = as_markup_convert_simple (warning_markup, error); + warning_plain = fu_util_convert_appstream_description (warning_markup, error); if (warning_plain == NULL) return FALSE; @@ -590,6 +654,15 @@ return g_steal_pointer (&filename); } +static void +fu_util_display_current_message (FuUtilPrivate *priv) +{ + if (priv->current_message == NULL) + return; + g_print ("%s\n", priv->current_message); + g_clear_pointer (&priv->current_message, g_free); +} + static gboolean fu_util_install (FuUtilPrivate *priv, gchar **values, GError **error) { @@ -617,7 +690,20 @@ filename = fu_util_download_if_required (priv, values[0], error); if (filename == NULL) return FALSE; - return fwupd_client_install (priv->client, id, filename, priv->flags, NULL, error); + + if (!fwupd_client_install (priv->client, id, filename, priv->flags, NULL, error)) + return FALSE; + + fu_util_display_current_message (priv); + + /* we don't want to ask anything */ + if (priv->no_reboot_check) { + g_debug ("skipping reboot check"); + return TRUE; + } + + /* show reboot if needed */ + return fu_util_prompt_complete (priv->completion_flags, TRUE, error); } static gboolean @@ -646,51 +732,6 @@ } static gboolean -fu_util_update_reboot (GError **error) -{ - g_autoptr(GDBusConnection) connection = NULL; - g_autoptr(GVariant) val = NULL; - - connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); - if (connection == NULL) - return FALSE; - -#ifdef HAVE_SYSTEMD - /* reboot using logind */ - val = g_dbus_connection_call_sync (connection, - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "Reboot", - g_variant_new ("(b)", TRUE), - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - error); -#elif defined(HAVE_CONSOLEKIT) - /* reboot using ConsoleKit */ - val = g_dbus_connection_call_sync (connection, - "org.freedesktop.ConsoleKit", - "/org/freedesktop/ConsoleKit/Manager", - "org.freedesktop.ConsoleKit.Manager", - "Restart", - NULL, - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - error); -#else - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_ARGS, - "No supported backend compiled in to perform the operation."); -#endif - return val != NULL; -} - -static gboolean fu_util_install_prepared (FuUtilPrivate *priv, gchar **values, GError **error) { gint vercmp; @@ -746,8 +787,8 @@ continue; /* tell the user what's going to happen */ - vercmp = as_utils_vercmp (fwupd_device_get_version (dev), - fwupd_release_get_version (rel)); + vercmp = fu_common_vercmp (fwupd_device_get_version (dev), + fwupd_release_get_version (rel)); if (vercmp == 0) { /* TRANSLATORS: the first replacement is a display name * e.g. "ColorHugALS" and the second is a version number @@ -792,7 +833,7 @@ } /* reboot */ - if (!fu_util_update_reboot (error)) + if (!fu_util_prompt_complete (FWUPD_DEVICE_FLAG_NEEDS_REBOOT, FALSE, error)) return FALSE; g_print ("%s\n", _("Done!")); @@ -1484,7 +1525,7 @@ tmp = fwupd_release_get_description (rel); if (tmp != NULL) { g_autofree gchar *desc = NULL; - desc = as_markup_convert_simple (tmp, NULL); + desc = fu_util_convert_appstream_description (tmp, NULL); /* TRANSLATORS: section header for firmware description */ fu_util_print_data (_("Description"), desc); } @@ -1649,6 +1690,45 @@ return fu_util_download_metadata (priv, error); } +static gchar * +fu_util_time_to_str (guint64 tmp) +{ + g_return_val_if_fail (tmp != 0, FALSE); + + /* seconds */ + if (tmp < 60) { + /* TRANSLATORS: duration in seconds */ + return g_strdup_printf (ngettext ("%u second", "%u seconds", + (gint) tmp), + (guint) tmp); + } + + /* minutes */ + tmp /= 60; + if (tmp < 60) { + /* TRANSLATORS: duration in minutes */ + return g_strdup_printf (ngettext ("%u minute", "%u minutes", + (gint) tmp), + (guint) tmp); + } + + /* hours */ + tmp /= 60; + if (tmp < 60) { + /* TRANSLATORS: duration in minutes */ + return g_strdup_printf (ngettext ("%u hour", "%u hours", + (gint) tmp), + (guint) tmp); + } + + /* days */ + tmp /= 24; + /* TRANSLATORS: duration in days! */ + return g_strdup_printf (ngettext ("%u day", "%u days", + (gint) tmp), + (guint) tmp); +} + static gboolean fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) { @@ -1696,6 +1776,7 @@ /* print all releases */ for (guint j = 0; j < rels->len; j++) { FwupdRelease *rel = g_ptr_array_index (rels, j); + guint64 duration; GPtrArray *checksums; /* TRANSLATORS: Appstream ID for the hardware type */ @@ -1715,6 +1796,15 @@ fu_util_print_data (_("Update Remote ID"), fwupd_release_get_remote_id (rel)); + /* optional approximate duration */ + duration = fwupd_release_get_install_duration (rel); + if (duration > 0) { + g_autofree gchar *str = fu_util_time_to_str (duration); + /* TRANSLATORS: section header for the amount + * of time it takes to install the update */ + fu_util_print_data (_("Update Duration"), str); + } + checksums = fwupd_release_get_checksums (rel); for (guint k = 0; k < checksums->len; k++) { const gchar *checksum = g_ptr_array_index (checksums, k); @@ -1731,9 +1821,7 @@ tmp = fwupd_release_get_description (rel); if (tmp != NULL) { g_autofree gchar *md = NULL; - md = as_markup_convert (tmp, - AS_MARKUP_CONVERT_FORMAT_SIMPLE, - NULL); + md = fu_util_convert_appstream_description (tmp, NULL); if (md != NULL) { /* TRANSLATORS: section header for long firmware desc */ fu_util_print_data (_("Update Description"), md); @@ -1876,101 +1964,6 @@ return TRUE; } -static void -fu_util_cancelled_cb (GCancellable *cancellable, gpointer user_data) -{ - FuUtilPrivate *priv = (FuUtilPrivate *) user_data; - /* TRANSLATORS: this is when a device ctrl+c's a watch */ - g_print ("%s\n", _("Cancelled")); - g_main_loop_quit (priv->loop); -} - -static void -fu_util_device_added_cb (FwupdClient *client, - FwupdDevice *device, - gpointer user_data) -{ - g_autofree gchar *tmp = fwupd_device_to_string (device); - /* TRANSLATORS: this is when a device is hotplugged */ - g_print ("%s\n%s", _("Device added:"), tmp); -} - -static void -fu_util_device_removed_cb (FwupdClient *client, - FwupdDevice *device, - gpointer user_data) -{ - g_autofree gchar *tmp = fwupd_device_to_string (device); - /* TRANSLATORS: this is when a device is hotplugged */ - g_print ("%s\n%s", _("Device removed:"), tmp); -} - -static void -fu_util_device_changed_cb (FwupdClient *client, - FwupdDevice *device, - gpointer user_data) -{ - g_autofree gchar *tmp = fwupd_device_to_string (device); - /* TRANSLATORS: this is when a device has been updated */ - g_print ("%s\n%s", _("Device changed:"), tmp); -} - -static void -fu_util_changed_cb (FwupdClient *client, gpointer user_data) -{ - /* TRANSLATORS: this is when the daemon state changes */ - g_print ("%s\n", _("Changed")); -} - -static gboolean -fu_util_firmware_builder (FuUtilPrivate *priv, gchar **values, GError **error) -{ - const gchar *script_fn = "startup.sh"; - const gchar *output_fn = "firmware.bin"; - g_autoptr(GBytes) archive_blob = NULL; - g_autoptr(GBytes) firmware_blob = NULL; - if (g_strv_length (values) < 2) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_ARGS, - "Invalid arguments"); - return FALSE; - } - archive_blob = fu_common_get_contents_bytes (values[0], error); - if (archive_blob == NULL) - return FALSE; - if (g_strv_length (values) > 2) - script_fn = values[2]; - if (g_strv_length (values) > 3) - output_fn = values[3]; - firmware_blob = fu_common_firmware_builder (archive_blob, script_fn, output_fn, error); - if (firmware_blob == NULL) - return FALSE; - return fu_common_set_contents_bytes (values[1], firmware_blob, error); -} - -static gboolean -fu_util_monitor (FuUtilPrivate *priv, gchar **values, GError **error) -{ - /* get all the devices */ - if (!fwupd_client_connect (priv->client, priv->cancellable, error)) - return FALSE; - - /* watch for any hotplugged device */ - g_signal_connect (priv->client, "changed", - G_CALLBACK (fu_util_changed_cb), priv); - g_signal_connect (priv->client, "device-added", - G_CALLBACK (fu_util_device_added_cb), priv); - g_signal_connect (priv->client, "device-removed", - G_CALLBACK (fu_util_device_removed_cb), priv); - g_signal_connect (priv->client, "device-changed", - G_CALLBACK (fu_util_device_changed_cb), priv); - g_signal_connect (priv->cancellable, "cancelled", - G_CALLBACK (fu_util_cancelled_cb), priv); - g_main_loop_run (priv->loop); - return TRUE; -} - static gboolean fu_util_update_device_with_release (FuUtilPrivate *priv, FwupdDevice *dev, @@ -1996,13 +1989,17 @@ if (remote == NULL) return FALSE; - /* local remotes have the firmware already */ + /* local and directory remotes have the firmware already */ if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL) { const gchar *fn_cache = fwupd_remote_get_filename_cache (remote); g_autofree gchar *path = g_path_get_dirname (fn_cache); - /* install with flags chosen by the user */ fn = g_build_filename (path, uri_tmp, NULL); + } else if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DIRECTORY) { + fn = g_strdup (uri_tmp + 7); + } + /* install with flags chosen by the user */ + if (fn != NULL) { return fwupd_client_install (priv->client, fwupd_device_get_id (dev), fn, priv->flags, NULL, error); @@ -2036,7 +2033,6 @@ static gboolean fu_util_update_all (FuUtilPrivate *priv, GError **error) { - gboolean requires_reboot = FALSE; g_autoptr(GPtrArray) devices = NULL; /* get devices from daemon */ @@ -2067,8 +2063,8 @@ rel = g_ptr_array_index (rels, 0); if (!fu_util_update_device_with_release (priv, dev, rel, error)) return FALSE; - if (fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT)) - requires_reboot = TRUE; + + fu_util_display_current_message (priv); } /* we don't want to ask anything */ @@ -2077,18 +2073,7 @@ return TRUE; } - /* at least one of the updates needed a reboot */ - if (requires_reboot) { - g_print ("\n%s %s [Y|n]: ", - /* TRANSLATORS: explain why we want to upload */ - _("An update requires a reboot to complete."), - /* TRANSLATORS: reboot to apply the update */ - _("Restart now?")); - if (!fu_util_prompt_for_boolean (TRUE)) - return TRUE; - return fu_util_update_reboot (error); - } - return TRUE; + return fu_util_prompt_complete (priv->completion_flags, TRUE, error); } static gboolean @@ -2118,6 +2103,8 @@ if (!fu_util_update_device_with_release (priv, dev, rel, error)) return FALSE; + fu_util_display_current_message (priv); + /* we don't want to ask anything */ if (priv->no_reboot_check) { g_debug ("skipping reboot check"); @@ -2126,14 +2113,9 @@ /* the update needs the user to restart the computer */ if (fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT)) { - g_print ("\n%s %s [Y|n]: ", - /* TRANSLATORS: exactly one update needs this */ - _("The update requires a reboot to complete."), - /* TRANSLATORS: reboot to apply the update */ - _("Restart now?")); - if (!fu_util_prompt_for_boolean (TRUE)) - return TRUE; - return fu_util_update_reboot (error); + if (!fu_util_prompt_complete (FWUPD_DEVICE_FLAG_NEEDS_REBOOT, TRUE, + error)) + return FALSE; } return TRUE; } @@ -2248,6 +2230,7 @@ g_object_unref (priv->current_device); if (priv->soup_session != NULL) g_object_unref (priv->soup_session); + g_free (priv->current_message); g_main_loop_unref (priv->loop); g_object_unref (priv->cancellable); g_object_unref (priv->progressbar); @@ -2450,18 +2433,6 @@ _("Update the stored metadata with current ROM contents"), fu_util_verify_update); fu_util_add (priv->cmd_array, - "monitor", - NULL, - /* TRANSLATORS: command description */ - _("Monitor the daemon for events"), - fu_util_monitor); - fu_util_add (priv->cmd_array, - "build-firmware", - "FILE-IN FILE-OUT [SCRIPT] [OUTPUT]", - /* TRANSLATORS: command description */ - _("Build firmware using a sandbox"), - fu_util_firmware_builder); - fu_util_add (priv->cmd_array, "modify-remote", "REMOTE-ID KEY VALUE", /* TRANSLATORS: command description */ @@ -2495,6 +2466,7 @@ priv->no_unreported_check = TRUE; priv->no_metadata_check = TRUE; priv->no_reboot_check = TRUE; + fu_progressbar_set_interactive (priv->progressbar, FALSE); } /* get a list of the commands */ @@ -2558,6 +2530,17 @@ return EXIT_SUCCESS; } + /* show a warning if the daemon is tainted */ + if (!fwupd_client_connect (priv->client, priv->cancellable, &error)) { + g_printerr ("Failed to connect to daemon: %s\n", + error->message); + return EXIT_FAILURE; + } + if (fwupd_client_get_tainted (priv->client)) { + g_printerr ("WARNING: The daemon has loaded 3rd party code and " + "is no longer supported by the upstream developers!\n"); + } + /* run the specified command */ ret = fu_util_run (priv, argv[1], (gchar**) &argv[2], &error); if (!ret) { diff -Nru fwupd-1.1.4/src/fu-util-common.c fwupd-1.2.5/src/fu-util-common.c --- fwupd-1.1.4/src/fu-util-common.c 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-util-common.c 2019-02-25 09:42:18.000000000 +0000 @@ -6,7 +6,6 @@ #include -#include #include #include #include @@ -163,11 +162,6 @@ g_string_append_printf (string, "compile-time dependency versions\n"); g_string_append_printf (string, - "\tappstream-glib:\t%d.%d.%d\n", - AS_MAJOR_VERSION, - AS_MINOR_VERSION, - AS_MICRO_VERSION); - g_string_append_printf (string, "\tgusb:\t%d.%d.%d\n", G_USB_MAJOR_VERSION, G_USB_MINOR_VERSION, @@ -179,3 +173,124 @@ #endif return g_string_free (string, FALSE); } + +static gboolean +fu_util_update_shutdown (GError **error) +{ + g_autoptr(GDBusConnection) connection = NULL; + g_autoptr(GVariant) val = NULL; + + connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); + if (connection == NULL) + return FALSE; + +#ifdef HAVE_SYSTEMD + /* shutdown using logind */ + val = g_dbus_connection_call_sync (connection, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "PowerOff", + g_variant_new ("(b)", TRUE), + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + error); +#elif defined(HAVE_CONSOLEKIT) + /* shutdown using ConsoleKit */ + val = g_dbus_connection_call_sync (connection, + "org.freedesktop.ConsoleKit", + "/org/freedesktop/ConsoleKit/Manager", + "org.freedesktop.ConsoleKit.Manager", + "Stop", + NULL, + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + error); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "No supported backend compiled in to perform the operation."); +#endif + return val != NULL; +} + +static gboolean +fu_util_update_reboot (GError **error) +{ + g_autoptr(GDBusConnection) connection = NULL; + g_autoptr(GVariant) val = NULL; + + connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); + if (connection == NULL) + return FALSE; + +#ifdef HAVE_SYSTEMD + /* reboot using logind */ + val = g_dbus_connection_call_sync (connection, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "Reboot", + g_variant_new ("(b)", TRUE), + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + error); +#elif defined(HAVE_CONSOLEKIT) + /* reboot using ConsoleKit */ + val = g_dbus_connection_call_sync (connection, + "org.freedesktop.ConsoleKit", + "/org/freedesktop/ConsoleKit/Manager", + "org.freedesktop.ConsoleKit.Manager", + "Restart", + NULL, + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + error); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "No supported backend compiled in to perform the operation."); +#endif + return val != NULL; +} + +gboolean +fu_util_prompt_complete (FwupdDeviceFlags flags, gboolean prompt, GError **error) +{ + if (flags & FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN) { + if (prompt) { + g_print ("\n%s %s [Y|n]: ", + /* TRANSLATORS: explain why we want to shutdown */ + _("An update requires the system to shutdown to complete."), + /* TRANSLATORS: shutdown to apply the update */ + _("Shutdown now?")); + if (!fu_util_prompt_for_boolean (TRUE)) + return TRUE; + } + return fu_util_update_shutdown (error); + } + if (flags & FWUPD_DEVICE_FLAG_NEEDS_REBOOT) { + if (prompt) { + g_print ("\n%s %s [Y|n]: ", + /* TRANSLATORS: explain why we want to reboot */ + _("An update requires a reboot to complete."), + /* TRANSLATORS: reboot to apply the update */ + _("Restart now?")); + if (!fu_util_prompt_for_boolean (TRUE)) + return TRUE; + } + return fu_util_update_reboot (error); + } + + return TRUE; +} diff -Nru fwupd-1.1.4/src/fu-util-common.h fwupd-1.2.5/src/fu-util-common.h --- fwupd-1.1.4/src/fu-util-common.h 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/fu-util-common.h 2019-02-25 09:42:18.000000000 +0000 @@ -4,12 +4,16 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_UTIL_COMMON_H__ -#define __FU_UTIL_COMMON_H__ +#pragma once #include #include +G_BEGIN_DECLS + +/* this is only valid for tools */ +#define FWUPD_ERROR_INVALID_ARGS (FWUPD_ERROR_LAST+1) + void fu_util_print_data (const gchar *title, const gchar *msg); guint fu_util_prompt_for_number (guint maxnum); @@ -21,4 +25,8 @@ gchar *fu_util_get_versions (void); -#endif /* __FU_UTIL_COMMON_H__ */ +gboolean fu_util_prompt_complete (FwupdDeviceFlags flags, + gboolean prompt, + GError **error); + +G_END_DECLS diff -Nru fwupd-1.1.4/src/meson.build fwupd-1.2.5/src/meson.build --- fwupd-1.1.4/src/meson.build 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/meson.build 2019-02-25 09:42:18.000000000 +0000 @@ -25,12 +25,16 @@ libfwupdprivate = static_library( 'fwupdprivate', sources : [ + 'fu-archive.c', 'fu-common.c', + 'fu-common-guid.c', + 'fu-common-version.c', 'fu-chunk.c', 'fu-device.c', 'fu-device-locker.c', 'fu-hwids.c', 'fu-history.c', + 'fu-io-channel.c', 'fu-mutex.c', 'fu-plugin.c', 'fu-progressbar.c', @@ -45,15 +49,18 @@ include_directories('../libfwupd'), ], dependencies : [ - appstream_glib, giounix, gudev, gusb, soup, sqlite, libarchive, + libxmlb, valgrind, ], + link_with : [ + fwupd, + ], c_args : [ '-DFU_OFFLINE_DESTDIR=""', ], @@ -71,7 +78,7 @@ include_directories('../libfwupd'), ], dependencies : [ - appstream_glib, + libxmlb, giounix, gudev, gusb, @@ -99,15 +106,28 @@ c_name : 'fu' ) +fu_hash = custom_target( + 'fu-hash.h', + input : libfwupdprivate, + output : 'fu-hash.h', + command : [python3.path(), + join_paths(meson.current_source_dir(), 'fu-hash.py'), + '@INPUT@', '@OUTPUT@'] +) + fwupdtool = executable( 'fwupdtool', resources_src, + fu_hash, sources : [ 'fu-tool.c', keyring_src, + 'fu-archive.c', 'fu-chunk.c', 'fu-common.c', 'fu-common-cab.c', + 'fu-common-guid.c', + 'fu-common-version.c', 'fu-config.c', 'fu-keyring.c', 'fu-keyring-result.c', @@ -117,7 +137,9 @@ 'fu-device.c', 'fu-device-list.c', 'fu-device-locker.c', + 'fu-idle.c', 'fu-install-task.c', + 'fu-io-channel.c', 'fu-keyring.c', 'fu-keyring-utils.c', 'fu-history.c', @@ -135,7 +157,7 @@ ], dependencies : [ keyring_deps, - appstream_glib, + libxmlb, libgcab, giounix, gmodule, @@ -179,11 +201,15 @@ executable( 'fwupd', resources_src, + fu_hash, sources : [ keyring_src, + 'fu-archive.c', 'fu-chunk.c', 'fu-common.c', 'fu-common-cab.c', + 'fu-common-guid.c', + 'fu-common-version.c', 'fu-config.c', 'fu-keyring.c', 'fu-keyring-result.c', @@ -194,6 +220,8 @@ 'fu-device.c', 'fu-device-list.c', 'fu-device-locker.c', + 'fu-idle.c', + 'fu-io-channel.c', 'fu-install-task.c', 'fu-keyring.c', 'fu-keyring-utils.c', @@ -212,7 +240,7 @@ ], dependencies : [ keyring_deps, - appstream_glib, + libxmlb, libgcab, giounix, gmodule, @@ -231,6 +259,7 @@ install : true, install_dir : join_paths(libexecdir, 'fwupd') ) + endif if get_option('tests') @@ -245,12 +274,16 @@ hwid_test_firmware, noreqs_test_firmware, test_deps, + fu_hash, sources : [ keyring_src, 'fu-self-test.c', + 'fu-archive.c', 'fu-chunk.c', 'fu-common.c', 'fu-common-cab.c', + 'fu-common-guid.c', + 'fu-common-version.c', 'fu-config.c', 'fu-engine.c', 'fu-keyring.c', @@ -260,7 +293,9 @@ 'fu-device-list.c', 'fu-device-locker.c', 'fu-history.c', + 'fu-idle.c', 'fu-install-task.c', + 'fu-io-channel.c', 'fu-keyring.c', 'fu-keyring-result.c', 'fu-mutex.c', @@ -279,7 +314,7 @@ ], dependencies : [ keyring_deps, - appstream_glib, + libxmlb, libgcab, giounix, gmodule, @@ -309,14 +344,21 @@ gir_dep = declare_dependency(sources: gir) gnome.generate_gir(fwupd, sources : [ + 'fu-archive.c', + 'fu-archive.h', 'fu-chunk.c', 'fu-chunk.h', 'fu-common.c', + 'fu-common-guid.c', + 'fu-common-guid.h', + 'fu-common-version.c', + 'fu-common-version.h', 'fu-common.h', 'fu-device.c', 'fu-device.h', 'fu-device-locker.c', 'fu-device-locker.h', + 'fu-io-channel.c', 'fu-plugin.c', 'fu-plugin.h', 'fu-quirks.c', @@ -334,7 +376,7 @@ include_directories('../libfwupd'), ], dependencies : [ - appstream_glib, + libxmlb, gir_dep, giounix, gusb, diff -Nru fwupd-1.1.4/src/org.freedesktop.fwupd.xml fwupd-1.2.5/src/org.freedesktop.fwupd.xml --- fwupd-1.1.4/src/org.freedesktop.fwupd.xml 2018-11-07 14:17:34.000000000 +0000 +++ fwupd-1.2.5/src/org.freedesktop.fwupd.xml 2019-02-25 09:42:18.000000000 +0000 @@ -23,6 +23,17 @@ + + + + + If the daemon has been tainted with a 3rd party plugin. + + + + + + diff -Nru fwupd-1.1.4/src/README.md fwupd-1.2.5/src/README.md --- fwupd-1.1.4/src/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/src/README.md 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,137 @@ +Quirk use +--------- +Quirks are defined by creating an INI style file in the compiled in quirk location (typically `/usr/share/fwupd/quirks.d`). + +The quirk is declared by creating a group based upon the `DeviceInstanceId` or `GUID` +and then mapping out values to keys. + +## All plugins +All fwupd devices support the following quirks: + +### Plugin +Sets the plugin to use for a specific hardware device. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the plugin name, e.g. `csr` +* Minimum fwupd version: **1.1.0** +### UefiVersionFormat +Assigns the version format to use for a specific manufacturer. A specific version +format is sometimes chosen to match the appearance of other systems or +specifications. +* Key: a %FU_HWIDS_KEY_MANUFACTURER, e.g. `Alienware` +* Value: the version format, e.g. `none` +* Supported values: `none`, `use-triplet` +* Minimum fwupd version: **1.0.1** +### ComponentIDs +Assigns the version format to use for a specific AppStream component. A specific +version format is sometimes chosen to match the appearance of other systems or +specifications. +* Key: the optionally wildcarded AppStream ID e.g. `com.dell.uefi*.firmware` +* Value: the version format, e.g. `none` +* Minimum fwupd version: **1.0.1** +### Flags +Assigns optional quirks to use for a 8bitdo device +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the quirk, e.g. `is-bootloader` +* Supported values: + * `none`: no device quirks + * `is-bootloader`: device is in bootloader mode +* Minimum fwupd version: **1.0.3** +### Summary +Sets a summary for a specific hardware device. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* the device summary, e.g. `An open source display colorimeter` +* Minimum fwupd version: **1.0.2** +### Icon +Adds an icon name for a specific hardware device. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the device icon name, e.g. `media-removable` +* Minimum fwupd version: **1.0.2** +### Name +Sets a name for a specific hardware device. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the device name, e.g. `ColorHug` +* Minimum fwupd version: **1.0.2** +### Guid +Adds an extra GUID for a specific hardware device. If the value provided is not +already a suitable GUID, it will be converted to one. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the GUID, e.g. `537f7800-8529-5656-b2fa-b0901fe91696` +* Minimum fwupd version: **1.0.3** +### CounterpartGuid +Adds an counterpart GUID for a specific hardware device. If the value provided +is not already a suitable GUID, it will be converted to one. A counterpart +GUID is typically the GUID of the same device in bootloader or runtime mode, +if they have a different device PCI or USB ID. Adding this type of GUID does +not cause a "cascade" by matching using the quirk database. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the GUID, e.g. `537f7800-8529-5656-b2fa-b0901fe91696` +* Minimum fwupd version: **1.1.2** +### ParentGuid +Adds an extra GUID to mark as the parent device. If the value provided is not +already a suitable GUID, it will be converted to one. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the GUID, e.g. `537f7800-8529-5656-b2fa-b0901fe91696` +* Minimum fwupd version: **1.1.2** +### Children +Adds one or more virtual devices to a physical device. To set the object type +of the child device use a pipe before the object type, for instance: +`FuRts54xxDeviceUSB\VID_0763&PID_2806&I2C_01` If the type of device is not +specified the parent device type is used. If the values provided are not +already suitable GUIDs, they will be converted. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: The virtual device, delimited by a comma +* Minimum fwupd version: **1.1.2** +### Vendor +Sets a vendor name for a specific hardware device. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the vendor, e.g. `Hughski Limited` +* Minimum fwupd version: **1.0.3** +### VendorId +Sets a vendor ID for a specific hardware device. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the vendor, e.g. `USB:0x123A` +* Minimum fwupd version: **1.1.2** +### Version +Sets a version for a specific hardware device. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: Version number, e.g. `1.2` +* Minimum fwupd version: **1.0.3** +### FirmwareSizeMin +Sets the minimum allowed firmware size. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: A number in bytes, e.g. `512` +* Minimum fwupd version: **1.1.2** +### FirmwareSizeMax +Sets the maximum allowed firmware size. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: A number in bytes, e.g. `1024` +* Minimum fwupd version: **1.1.2** +### InstallDuration +Sets the estimated time to flash the device +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: A number in seconds, e.g. `60` +* Minimum fwupd version: **1.1.3** +### VersionFormat +Sets the version format the device should use for conversion. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: The quirk format, e.g. `quad` +* Minimum fwupd version: **1.2.0** + +## Plugin specific +Plugins may add support for additional quirks that are relevant only for +those plugins. View them by looking at the `README.md` in plugin directories. + +## Example +Here is an example as seen in the CSR plugin. + +``` +[DeviceInstanceId=USB\VID_0A12&PID_1337] +Plugin = csr +Name = H05 +Summary = Bluetooth Headphones +Icon = audio-headphones +Vendor = AIAIAI +[DeviceInstanceId=USB\VID_0A12&PID_1337&REV_2520] +Version = 1.2 +``` +Additional samples can be found in other plugins. diff -Nru fwupd-1.1.4/subprojects/.gitignore fwupd-1.2.5/subprojects/.gitignore --- fwupd-1.1.4/subprojects/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/subprojects/.gitignore 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1 @@ +libxmlb diff -Nru fwupd-1.1.4/subprojects/libxmlb.wrap fwupd-1.2.5/subprojects/libxmlb.wrap --- fwupd-1.1.4/subprojects/libxmlb.wrap 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.5/subprojects/libxmlb.wrap 2019-02-25 09:42:18.000000000 +0000 @@ -0,0 +1,4 @@ +[wrap-git] +directory = libxmlb +url = https://github.com/hughsie/libxmlb.git +revision = 0.1.5