pax_global_header00006660000000000000000000000064126774751030014526gustar00rootroot0000000000000052 comment=837cc2405f4c251ca1eaa576e22df052cf1cb1a7 fwupd-0.7.0/000077500000000000000000000000001267747510300126575ustar00rootroot00000000000000fwupd-0.7.0/.tx/000077500000000000000000000000001267747510300133705ustar00rootroot00000000000000fwupd-0.7.0/.tx/config000066400000000000000000000002111267747510300145520ustar00rootroot00000000000000[main] host = https://www.transifex.com [fwupd.master] file_filter = po/.po source_file = po/fwupd.pot source_lang = en type = PO fwupd-0.7.0/AUTHORS000066400000000000000000000000451267747510300137260ustar00rootroot00000000000000Richard Hughes fwupd-0.7.0/COPYING000066400000000000000000000432541267747510300137220ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. fwupd-0.7.0/MAINTAINERS000066400000000000000000000000451267747510300143530ustar00rootroot00000000000000Richard Hughes fwupd-0.7.0/Makefile.am000066400000000000000000000041331267747510300147140ustar00rootroot00000000000000AUTOMAKE_OPTIONS = 1.7 ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} SUBDIRS = \ libfwupd \ libdfu \ po \ data \ docs \ policy \ src snapshot: $(MAKE) dist distdir=$(PACKAGE)-$(VERSION)-`date +"%Y%m%d"` EXTRA_DIST = \ COPYING \ MAINTAINERS \ AUTHORS \ README.md \ NEWS \ autogen.sh \ config.h \ intltool-extract.in \ intltool-merge.in \ intltool-update.in MAINTAINERCLEANFILES = \ $(srcdir)/INSTALL \ $(srcdir)/ABOUT-NLS \ $(srcdir)/aclocal.m4 \ $(srcdir)/autoscan.log \ $(srcdir)/compile \ $(srcdir)/config.guess \ $(srcdir)/config.rpath \ $(srcdir)/config.h.in \ $(srcdir)/config.sub \ $(srcdir)/configure.scan \ $(srcdir)/depcomp \ $(srcdir)/install-sh \ $(srcdir)/ltmain.sh \ $(srcdir)/missing \ $(srcdir)/mkinstalldirs \ $(srcdir)/omf.make \ $(srcdir)/test-driver \ $(srcdir)/xmldocs.make \ $(srcdir)/gtk-doc.make \ $(srcdir)/ChangeLog \ $(srcdir)/po/Makefile.in.in~ \ $(srcdir)/fwupd-*.tar.* \ `find "$(srcdir)" -type f -name Makefile.in -print` DISTCHECK_CONFIGURE_FLAGS = \ --enable-colorhug \ --enable-uefi \ --with-udevrulesdir=$$dc_install_base/$(udevrulesdir) \ --with-systemdunitdir=$$dc_install_base/$(systemdunitdir) GITIGNOREFILES = \ .tx distclean-local: if test $(srdcir) = .; then :; else \ rm -f ChangeLog; \ fi ChangeLog: @echo Creating $@ @if test -d "$(srcdir)/.git"; then \ (GIT_DIR=$(top_srcdir)/.git ./missing --run git log e197d80c8937c622f21f569457d1bbd05746d951.. --stat -M -C --name-status --date=short --no-color) | fmt --split-only > $@.tmp \ && mv -f $@.tmp $@ \ || ($(RM) $@.tmp; \ echo Failed to generate ChangeLog, your ChangeLog may be outdated >&2; \ (test -f $@ || echo git-log is required to generate this file >> $@)); \ else \ test -f $@ || \ (echo A git checkout and git-log is required to generate ChangeLog >&2 && \ echo A git checkout and git-log is required to generate this file >> $@); \ fi .PHONY: ChangeLog -include $(top_srcdir)/git.mk fwupd-0.7.0/NEWS000066400000000000000000000210751267747510300133630ustar00rootroot00000000000000Version 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. fwupd-0.7.0/README.md000066400000000000000000000071371267747510300141460ustar00rootroot00000000000000fwupd ===== This project aims to make updating firmware on Linux automatic, safe and reliable. Additional information is available at the website: http://www.fwupd.org DFU Support ----------- DFU support is supported directly by this project with the embedded libdfu library. ColorHug Support ---------------- For colorhug support you need to install colord 1.2.12 or later. * source: https://github.com/hughsie/colord * rpms: http://people.freedesktop.org/~hughsient/fedora/ * debs (Debian): https://tracker.debian.org/pkg/fwupd * debs (Ubuntu): https://launchpad.net/ubuntu/+source/fwupd If you don't want or need this functionality you can use the `--disable-colorhug` option. UEFI Support ------------ For UEFI capsule support, you need to install fwupdate 0.5 or later. * source: https://github.com/rhinstaller/fwupdate * rpms: https://pjones.fedorapeople.org/fwupdate/ * debs (Debian): https://tracker.debian.org/pkg/fwupdate * debs (Ubuntu): https://launchpad.net/ubuntu/+source/fwupdate If you don't want or need this functionality you can use the `--disable-uefi` option. UEFI Unlock Support ------------------- On some Dell systems it's possible to turn on and off UEFI capsule support from within the BIOS. This functionality can also be adjusted from within the OS by fwupd. This requires using fwupdate 0.6 or later and compiling it with libsmbios support. When fwupd and fwupdate have been compiled with this support you will be able to enable UEFI support on the device by using the `unlock` command. Raspberry Pi support -------------------- A provider is available that can flash the boot firmware on the Raspberry Pi. Adding a new provider --------------------- An extensible architecture allows for providing new Provider types (for reading and writing different firmware) as well as for plugins that can extend existing firmware providers to quirk their behavior. If you have a firmware specification and would like to see support in this project, please file an issue and share the spec. Patches are also welcome. LVFS ---- This project is configured by default to download firmware from the [Linux Vendor Firmware Service (LVFS)] (https://secure-lvfs.rhcloud.com/lvfs/). This service is available to all OEMs and firmware creators who would like to make their firmware available to Linux users. Basic usage flow (command line) ------------------------------ If you have a device with firmware supported by fwupd, this is how you will check for updates and apply them using fwupd's command line tools. `fwupdmgr get-devices` This will display all devices detected by fwupd. `fwupdmgr refresh` This will download the latest metadata from LVFS. `fwupdmgr get-updates` If updates are available for any devices on the system, they'll be displayed. `fwupdmgr update` This will download and apply all updates for your system. * Updates that can be applied live *(Online updates)* will be done immediately. * Updates that require a reboot *(Offline updates)* will be staged for the next reboot. 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. fwupd-0.7.0/RELEASE000066400000000000000000000022121267747510300136570ustar00rootroot00000000000000fwupd Release Notes 1. Write NEWS entries for fwupd in the same format as usual. git shortlog 0.6.3.. | grep -i -v trivial | grep -v Merge > NEWS.new Version 0.7.0 ~~~~~~~~~~~~~ Released: 2016-xx-xx New Features: Bugfixes: Update translations: cd po make fwupd.pot INTLTOOL_EXTRACT="/usr/bin/intltool-extract" XGETTEXT="/usr/bin/xgettext --no-location" srcdir=. /usr/bin/intltool-update --gettext-package fwupd --pot tx push --source tx pull --all --minimum-perc=5 git add *.po cd .. 2. Commit changes to git: # MAKE SURE THESE ARE CORRECT export release_ver="0.7.0" git commit -a -m "Release fwupd ${release_ver}" git tag -s -f -m "Release fwupd ${release_ver}" "${release_ver}" git push --tags git push 3. Generate the tarball: make distcheck 3a. Generate the additon verification metadata sha1sum fwupd-${release_ver}.tar.xz > fwupd-${release_ver}.tar.xz.sha1 gpg -b -a fwupd-${release_ver}.tar.xz 4. Upload tarball: scp fwupd-${release_ver}.tar.* hughsient@people.freedesktop.org:~/public_html/releases 5. Do post release version bump in configure.ac 6. Commit changes: git commit -a -m "trivial: post release version bump" git push fwupd-0.7.0/autogen.sh000077500000000000000000000016101267747510300146560ustar00rootroot00000000000000#!/bin/sh # Copyright (C) 2015 Richard Hughes # # Run this to generate all the initial makefiles, etc. # # Licensed under the GNU General Public License Version 2 # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. test -n "$srcdir" || srcdir=`dirname "$0"` test -n "$srcdir" || srcdir=. olddir=`pwd` cd "$srcdir" AUTORECONF=`which autoreconf` if test -z $AUTORECONF; then echo "*** No autoreconf found, please install it ***" exit 1 fi autopoint --force gtkdocize || exit 1 ACLOCAL="${ACLOCAL-aclocal} $ACLOCAL_FLAGS" AUTOPOINT='intltoolize --automake --copy' autoreconf --force --install --verbose cd "$olddir" test -n "$NOCONFIGURE" || "$srcdir/configure" "$@" fwupd-0.7.0/configure.ac000066400000000000000000000171331267747510300151520ustar00rootroot00000000000000# Copyright (C) 2015 Richard Hughes AC_PREREQ(2.63) m4_define([fwupd_major_version], [0]) m4_define([fwupd_minor_version], [7]) m4_define([fwupd_micro_version], [0]) m4_define([fwupd_version], [fwupd_major_version.fwupd_minor_version.fwupd_micro_version]) AC_INIT([fwupd],[fwupd_version],[https://github.com/hughsie/fwupd]) AC_CONFIG_SRCDIR(src) AM_INIT_AUTOMAKE([1.9 no-dist-gzip dist-xz tar-ustar foreign]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) AC_PROG_LIBTOOL m4_ifdef([GOBJECT_INTROSPECTION_CHECK], [GOBJECT_INTROSPECTION_CHECK([0.9.8])]) AM_CONDITIONAL(HAVE_INTROSPECTION, test "x$found_introspection" = xyes) GLIB_GSETTINGS # use this in fu-version.h FWUPD_MAJOR_VERSION=fwupd_major_version FWUPD_MINOR_VERSION=fwupd_minor_version FWUPD_MICRO_VERSION=fwupd_micro_version AC_SUBST(VERSION) AC_SUBST(FWUPD_MAJOR_VERSION) AC_SUBST(FWUPD_MINOR_VERSION) AC_SUBST(FWUPD_MICRO_VERSION) # libtool versioning - this applies to libfwupd # # See http://sources.redhat.com/autobook/autobook/autobook_91.html#SEC91 for details # # increment; # CURRENT If the API or ABI interface has changed (reset REVISION to 0) # REVISION If the API and ABI remains the same, but bugs are fixed. # AGE Don't use. LT_CURRENT=1 LT_REVISION=1 LT_AGE=0 AC_SUBST(LT_CURRENT) AC_SUBST(LT_REVISION) AC_SUBST(LT_AGE) # enable nice build output on automake1.11 m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) # check for gtk-doc GTK_DOC_CHECK([1.14],[--flavour no-tmpl]) AS_ALL_LINGUAS AC_PROG_CC AC_PROG_INSTALL LT_INIT AM_PROG_CC_C_O IT_PROG_INTLTOOL([0.35.0]) AC_PATH_PROG(XSLTPROC, xsltproc) dnl --------------------------------------------------------------------------- dnl - Extra verbose warning switches dnl --------------------------------------------------------------------------- if test "$GCC" = "yes"; then WARNINGFLAGS_C="$WARNINGFLAGS_C -Wall" WARNINGFLAGS_C="$WARNINGFLAGS_C -Wcast-align -Wno-uninitialized" WARNINGFLAGS_C="$WARNINGFLAGS_C -Wmissing-declarations" WARNINGFLAGS_C="$WARNINGFLAGS_C -Wpointer-arith" WARNINGFLAGS_C="$WARNINGFLAGS_C -Wcast-align" WARNINGFLAGS_C="$WARNINGFLAGS_C -Wwrite-strings" WARNINGFLAGS_C="$WARNINGFLAGS_C -Winit-self" WARNINGFLAGS_C="$WARNINGFLAGS_C -Wreturn-type" WARNINGFLAGS_C="$WARNINGFLAGS_C -Wformat-nonliteral" WARNINGFLAGS_C="$WARNINGFLAGS_C -Wformat-security" WARNINGFLAGS_C="$WARNINGFLAGS_C -Wmissing-include-dirs" WARNINGFLAGS_C="$WARNINGFLAGS_C -Wmissing-format-attribute" WARNINGFLAGS_C="$WARNINGFLAGS_C -Wclobbered" WARNINGFLAGS_C="$WARNINGFLAGS_C -Wempty-body" WARNINGFLAGS_C="$WARNINGFLAGS_C -Wignored-qualifiers" WARNINGFLAGS_C="$WARNINGFLAGS_C -Wsign-compare" WARNINGFLAGS_C="$WARNINGFLAGS_C -Wtype-limits" WARNINGFLAGS_C="$WARNINGFLAGS_C -Wuninitialized" WARNINGFLAGS_C="$WARNINGFLAGS_C -Waggregate-return" WARNINGFLAGS_C="$WARNINGFLAGS_C -Wdeclaration-after-statement" WARNINGFLAGS_C="$WARNINGFLAGS_C -Wshadow" WARNINGFLAGS_C="$WARNINGFLAGS_C -Wno-strict-aliasing" WARNINGFLAGS_C="$WARNINGFLAGS_C -Winline" WARNINGFLAGS_C="$WARNINGFLAGS_C -Wmissing-parameter-type" WARNINGFLAGS_C="$WARNINGFLAGS_C -Woverride-init" else WARNINGFLAGS_C="" fi AC_SUBST(WARNINGFLAGS_C) dnl --------------------------------------------------------------------------- dnl - gettext stuff dnl --------------------------------------------------------------------------- AM_GNU_GETTEXT_VERSION([0.17]) AM_GNU_GETTEXT([external]) GETTEXT_PACKAGE=AC_PACKAGE_NAME AC_SUBST(GETTEXT_PACKAGE) AC_DEFINE(GETTEXT_PACKAGE, "AC_PACKAGE_NAME", [foo]) # check for PIE (position independent executable) support if test x$with_pic != xno; then AX_CHECK_COMPILE_FLAG([-fPIE], [AX_CHECK_LINK_FLAG([-fPIE -pie], [PIE_CFLAGS="-fPIE" PIE_LDFLAGS="-pie"])]) AC_SUBST(PIE_CFLAGS) AC_SUBST(PIE_LDFLAGS) fi # check for full RELRO (relocation read-only) support AX_CHECK_LINK_FLAG([-Wl,-z,relro,-z,now], [RELRO_LDFLAGS="-Wl,-z,relro,-z,now"]) AC_SUBST([RELRO_LDFLAGS]) # use -lm LT_LIB_M AC_SUBST(LIBM) dnl --------------------------------------------------------------------------- dnl - Check library dependencies dnl --------------------------------------------------------------------------- PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.45.8 gobject-2.0 gthread-2.0 gio-2.0 >= 2.25.9 gio-unix-2.0 gmodule-2.0) PKG_CHECK_MODULES(GUDEV, gudev-1.0) PKG_CHECK_MODULES(POLKIT, polkit-gobject-1 >= 0.103) PKG_CHECK_MODULES(GCAB, libgcab-1.0) PKG_CHECK_MODULES(APPSTREAM_GLIB, appstream-glib >= 0.5.10) PKG_CHECK_MODULES(GUSB, gusb >= 0.2.9) PKG_CHECK_MODULES(SQLITE, sqlite3) PKG_CHECK_MODULES(ARCHIVE, libarchive) PKG_CHECK_MODULES(SOUP, libsoup-2.4 >= 2.51.92) AC_PATH_PROG(DOCBOOK2MAN, docbook2man) if test -z $DOCBOOK2MAN ; then AC_MSG_ERROR([docbook2man program not found]) fi AC_PATH_PROG(GCAB, [gcab], [no]) if test -z $GCAB ; then AC_MSG_ERROR([gcab program not found]) fi # ColorHug support AC_ARG_ENABLE(colorhug, AS_HELP_STRING([--enable-colorhug],[Enable ColorHug support]), enable_colorhug=$enableval, enable_colorhug=yes) if test x$enable_colorhug != xno; then PKG_CHECK_MODULES(COLORHUG, colorhug >= 1.2.12) AC_DEFINE(HAVE_COLORHUG,1,[Use ColorHug support]) fi AM_CONDITIONAL(HAVE_COLORHUG, test x$enable_colorhug = xyes) # gpgme support AC_MSG_CHECKING([for gpgme]) if ! test -x "/usr/bin/gpgme-config"; then AC_MSG_ERROR([Cannot locate gpgme]) else AC_MSG_RESULT([yes]) GPGME_CFLAGS="`\"/usr/bin/gpgme-config\" --cflags`" GPGME_LIBS="`\"/usr/bin/gpgme-config\" --libs`" GPGME_CFLAGS+=" `\"/usr/bin/gpg-error-config\" --cflags`" GPGME_LIBS+=" `\"/usr/bin/gpg-error-config\" --libs`" AC_SUBST([GPGME_CFLAGS]) AC_SUBST([GPGME_LIBS]) fi # UEFI support AC_ARG_ENABLE(uefi, AS_HELP_STRING([--enable-uefi],[Enable UEFI support]), enable_uefi=$enableval, enable_uefi=yes) if test x$enable_uefi != xno; then PKG_CHECK_MODULES(UEFI, fwup >= 0.5) AC_DEFINE(HAVE_UEFI,1,[Use UEFI support]) # check for ability to unlock PKG_CHECK_MODULES(UEFI_UNLOCK, fwup >= 0.6, has_uefi_unlock=yes, has_uefi_unlock=no) if test x$has_uefi_unlock = xyes; then AC_DEFINE(HAVE_UEFI_UNLOCK,1,[Use UEFI unlock support]) fi fi AM_CONDITIONAL(HAVE_UEFI, test x$enable_uefi = xyes) # systemd support AC_ARG_WITH([systemdunitdir], AS_HELP_STRING([--with-systemdunitdir=DIR], [Directory for systemd service files]), [], [with_systemdunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)]) AC_SUBST([systemdunitdir], [$with_systemdunitdir]) # udev rules AC_ARG_WITH([udevrulesdir], AS_HELP_STRING([--with-udevrulesdir=DIR], [Directory for udev rules files]), [], [with_udevrulesdir=$($PKG_CONFIG --variable=udevdir udev)/rules.d]) AC_SUBST([udevrulesdir], [$with_udevrulesdir]) dnl --------------------------------------------------------------------------- dnl - Makefiles, etc. dnl --------------------------------------------------------------------------- AC_CONFIG_FILES([ Makefile libdfu/Makefile libdfu/dfu.pc libfwupd/fwupd-version.h libfwupd/fwupd.pc libfwupd/Makefile data/Makefile data/pki/Makefile data/tests/Makefile data/tests/rpiupdate/Makefile data/tests/colorhug/Makefile data/tests/dfu/Makefile docs/Makefile docs/libdfu/Makefile docs/libfwupd/Makefile docs/man/Makefile policy/Makefile po/Makefile.in src/Makefile src/plugins/Makefile ]) AC_OUTPUT dnl ========================================================================== echo " fwupd $VERSION ================= prefix: ${prefix} datadir: ${datadir} compiler: ${CC} cflags: ${CFLAGS} cppflags: ${CPPFLAGS} " fwupd-0.7.0/contrib/000077500000000000000000000000001267747510300143175ustar00rootroot00000000000000fwupd-0.7.0/contrib/fwupd.spec.in000066400000000000000000000073361267747510300167360ustar00rootroot00000000000000%define alphatag #ALPHATAG# Summary: Firmware update daemon Name: fwupd Version: #VERSION# Release: 0.#BUILD#%{?alphatag}%{?dist} License: GPLv2+ URL: https://github.com/hughsie/fwupd Source0: http://people.freedesktop.org/~hughsient/releases/%{name}-%{version}.tar.xz BuildRequires: docbook-utils BuildRequires: gettext BuildRequires: glib2-devel >= 2.45.8 BuildRequires: intltool BuildRequires: libgudev1-devel BuildRequires: colord-devel >= 1.0.0 BuildRequires: polkit-devel >= 0.103 BuildRequires: libgcab1-devel BuildRequires: sqlite-devel BuildRequires: gpgme-devel BuildRequires: systemd BuildRequires: libsoup-devel >= 2.51.92 BuildRequires: libarchive-devel BuildRequires: gobject-introspection-devel BuildRequires: libappstream-glib-devel >= 0.5.10 BuildRequires: gcab BuildRequires: valgrind %ifarch x86_64 %{ix86} aarch64 BuildRequires: fwupdate-devel >= 0.5 %endif Requires(post): systemd Requires(preun): systemd Requires(postun): systemd Obsoletes: fwupd-sign < 0.1.6 %description fwupd is a daemon to allow session software to update device firmware. %package devel Summary: Development package for %{name} Requires: %{name} = %{version}-%{release} %description devel Files for development with %{name}. %package -n libdfu Summary: A library for DFU %description -n libdfu A library for updating USB devices using DFU. %package -n libdfu-devel Summary: Development package for libdfu Requires: libdfu = %{version}-%{release} %description -n libdfu-devel Files for development with libdfu. %prep %setup -q %build %configure \ --disable-static \ %ifnarch x86_64 %{ix86} aarch64 --disable-uefi \ %endif --disable-rpath \ --disable-silent-rules \ --disable-dependency-tracking make %{?_smp_mflags} %install make install DESTDIR=$RPM_BUILD_ROOT find %{buildroot} -name '*.la' -exec rm -f {} ';' %find_lang %{name} %check make check VERBOSE=1 %post /sbin/ldconfig %systemd_post fwupd.service %preun %systemd_preun fwupd.service %postun /sbin/ldconfig %systemd_postun_with_restart fwupd.service %files -f %{name}.lang %doc README.md AUTHORS NEWS %license COPYING %config(noreplace)%{_sysconfdir}/fwupd.conf %dir %{_libexecdir}/fwupd %{_libexecdir}/fwupd/fwupd %{_bindir}/fwupdmgr %{_sysconfdir}/pki/fwupd %{_sysconfdir}/pki/fwupd-metadata %{_sysconfdir}/dbus-1/system.d/org.freedesktop.fwupd.conf %{_datadir}/app-info/xmls/org.freedesktop.fwupd.xml %{_datadir}/dbus-1/interfaces/org.freedesktop.fwupd.xml %{_datadir}/polkit-1/actions/org.freedesktop.fwupd.policy %{_datadir}/polkit-1/rules.d/org.freedesktop.fwupd.rules %{_datadir}/dbus-1/system-services/org.freedesktop.fwupd.service %{_datadir}/man/man1/fwupdmgr.1.gz %{_unitdir}/fwupd-offline-update.service %{_unitdir}/fwupd.service %{_unitdir}/system-update.target.wants/ %dir %{_localstatedir}/lib/fwupd %{_libdir}/libfwupd*.so.* %{_libdir}/girepository-1.0/Fwupd-1.0.typelib %dir %{_localstatedir}/cache/app-info %dir %{_localstatedir}/cache/app-info/icons %dir %{_localstatedir}/cache/app-info/xmls /usr/lib/udev/rules.d/*.rules %dir %{_libdir}/fwupd-plugins-1 %{_libdir}/fwupd-plugins-1/*.so %files devel %{_datadir}/gir-1.0/Fwupd-1.0.gir %{_datadir}/gtk-doc/html/libfwupd %{_includedir}/fwupd-1 %{_libdir}/libfwupd*.so %{_libdir}/pkgconfig/fwupd.pc %files -n libdfu %{_bindir}/dfu-tool %{_datadir}/man/man1/dfu-tool.1.gz %{_libdir}/girepository-1.0/Dfu-1.0.typelib %{_libdir}/libdfu*.so.* %files -n libdfu-devel %{_datadir}/gir-1.0/Dfu-1.0.gir %{_datadir}/gtk-doc/html/libdfu %dir %{_includedir}/libdfu %{_includedir}/dfu.h %{_includedir}/libdfu/*.h %{_libdir}/libdfu*.so %{_libdir}/pkgconfig/dfu.pc %changelog * #LONGDATE# Richard Hughes #VERSION#-0.#BUILD##ALPHATAG# - Update from git fwupd-0.7.0/data/000077500000000000000000000000001267747510300135705ustar00rootroot00000000000000fwupd-0.7.0/data/90-fwupd-devices.rules000066400000000000000000000031401267747510300176350ustar00rootroot00000000000000######################################################################## # Copyright (C) 2015 Richard Hughes # # Licensed under the GNU General Public License Version 2 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # VIA USB 3.0 VL811 Hub SUBSYSTEM=="usb", DRIVER=="hub", ATTRS{idVendor}=="2109", ATTRS{idProduct}=="0810", ENV{FWUPD_GUID}="adbb9034-b577-42c2-a661-1ee4f49ef64c", ENV{FWUPD_VENDOR}="VIA", ENV{FWUPD_MODEL}="USB 3.0 VL811 Hub" # VIA USB 3.0 VL811+ Hub SUBSYSTEM=="usb", DRIVER=="hub", ATTRS{idVendor}=="2109", ATTRS{idProduct}=="0811", ENV{FWUPD_GUID}="54f84d05-c917-4c50-8b35-44feabaaa323", ENV{FWUPD_VENDOR}="VIA", ENV{FWUPD_MODEL}="USB 3.0 VL811+ Hub" # VIA USB 3.0 VL812 Hub SUBSYSTEM=="usb", DRIVER=="hub", ATTRS{idVendor}=="2109", ATTRS{idProduct}=="0812", ENV{FWUPD_GUID}="cd0314ec-b80f-4d1a-a24f-c409183a8b2d", ENV{FWUPD_VENDOR}="VIA", ENV{FWUPD_MODEL}="USB 3.0 VL812 Hub" # VIA USB 3.0 VL812 B2 Hub SUBSYSTEM=="usb", DRIVER=="hub", ATTRS{idVendor}=="2109", ATTRS{idProduct}=="2812", ENV{FWUPD_GUID}="26470009-97a8-4028-867a-bbbac6ee7bf0", ENV{FWUPD_VENDOR}="VIA", ENV{FWUPD_MODEL}="USB 3.0 VL812 B2 Hub" ENV{FWUPD_GUID}=="*?", ENV{ID_MODEL}=="", IMPORT{builtin}="usb_id" ENV{FWUPD_GUID}=="*?", ENV{ID_MODEL_FROM_DATABASE}=="", IMPORT{builtin}="hwdb --subsystem=usb" # PCI cards with ROM SUBSYSTEM=="pci", TEST=="/sys$devpath/rom", ENV{FWUPD_GUID}="$attr{vendor}:$attr{device}" fwupd-0.7.0/data/Makefile.am000066400000000000000000000027231267747510300156300ustar00rootroot00000000000000SUBDIRS = tests pki configdir = $(sysconfdir) dist_config_DATA = fwupd.conf dbusdir = $(sysconfdir)/dbus-1/system.d dist_dbus_DATA = org.freedesktop.fwupd.conf appstreamdir = $(datadir)/app-info/xmls dist_appstream_DATA = org.freedesktop.fwupd.xml dbusservicemaindir = $(datadir)/dbus-1/system-services dbusservicemain_in_files = org.freedesktop.fwupd.service.in dbusservicemain_DATA = $(dbusservicemain_in_files:.service.in=.service) $(dbusservicemain_DATA): $(dbusservicemain_in_files) Makefile @sed -e "s|\@servicedir\@|$(libexecdir)|" $< | \ sed -e "s|\@daemon_user\@|$(daemon_user)|" > $@ %.service: %.service.in Makefile $(AM_V_GEN)sed -e 's|\@servicedir\@|$(libexecdir)|' \ -e 's|\@bindir\@|$(bindir)|' \ -e 's|\@daemon_user\@|$(daemon_user)|' $< > $@.tmp && mv $@.tmp $@ systemdservicedir = $(systemdunitdir) systemdservice_in_files = \ fwupd.service.in \ fwupd-offline-update.service.in systemdservice_DATA = $(systemdservice_in_files:.service.in=.service) install-data-hook: mkdir -p $(DESTDIR)$(systemdunitdir)/system-update.target.wants ln -sf ../fwupd-offline-update.service $(DESTDIR)$(systemdunitdir)/system-update.target.wants/fwupd-offline-update.service udevrules_DATA = \ 90-fwupd-devices.rules EXTRA_DIST = \ $(udevrules_DATA) \ $(dbusservicemain_in_files) \ $(systemdservice_in_files) DISTCLEANFILES = \ $(dbusservicemain_DATA) \ $(systemdservice_DATA) -include $(top_srcdir)/git.mk fwupd-0.7.0/data/fwupd-offline-update.service.in000066400000000000000000000002121267747510300215770ustar00rootroot00000000000000[Unit] Description=Updates device firmware whilst offline OnFailure=reboot.target [Service] ExecStart=@bindir@/fwupdmgr install-prepared fwupd-0.7.0/data/fwupd.conf000066400000000000000000000005031267747510300155620ustar00rootroot00000000000000[fwupd] # The download URI to use for LVFS metadata # # If you want to use testing firmware then change this value to: # https://secure-lvfs.rhcloud.com/downloads/firmware-testing.xml.gz DownloadURI=https://secure-lvfs.rhcloud.com/downloads/firmware.xml.gz # If we should verify option ROM images EnableOptionROM=true fwupd-0.7.0/data/fwupd.service.in000066400000000000000000000003661267747510300167110ustar00rootroot00000000000000[Unit] Description=Firmware update daemon After=dbus.service Before=gdm.service ConditionPathExists=/var/lib/fwupd/pending.db [Service] Type=dbus BusName=org.freedesktop.fwupd ExecStart=@servicedir@/fwupd/fwupd PrivateNetwork=yes PrivateTmp=yes fwupd-0.7.0/data/org.freedesktop.fwupd.conf000066400000000000000000000020231267747510300206610ustar00rootroot00000000000000 fwupd-0.7.0/data/org.freedesktop.fwupd.service.in000066400000000000000000000001611267747510300220020ustar00rootroot00000000000000[D-BUS Service] Name=org.freedesktop.fwupd Exec=@servicedir@/fwupd/fwupd User=root #SystemdService=fwupd.service fwupd-0.7.0/data/org.freedesktop.fwupd.xml000066400000000000000000000103251267747510300205400ustar00rootroot00000000000000 com.steelseries.rival-legacy.firmware be9dac3a-180b-5aee-9e39-da122d4300ff steelseries UEFI-dummy-dev0 2d47f29b-83a2-4f31-a2e8-63474f4d4c2e UEFI Updates Enable UEFI Update Functionality

Applying this update will enable the UEFI firmware reporting interface on your hardware.

You will have to restart your computer after this update is installed to be notified of any pending firmware updates.

com.via.VL811.firmware adbb9034-b577-42c2-a661-1ee4f49ef64c VL811 Firmware Firmware for VIA USB 3.0 hub VIA http://www.via.com.tw/

This stable release fixes the following problems with USB 3.0:

  • Do not wake during transition to S4
  • Do not drop from Apple USB 3.0 Host during S3/S4 and Device PnP
  • Do not drop during S3/S4 when connected to native Intel and AMD Hosts

This stable release fixes the following problems with USB 2.0:

  • Do not drop from Apple USB 3.0 Host during S3/S4 and Device PnP
com.via.VL811+.firmware 54f84d05-c917-4c50-8b35-44feabaaa323 VL811+ Firmware Firmware for VIA USB 3.0 hub VIA http://www.via.com.tw/ com.via.VL812.firmware cd0314ec-b80f-4d1a-a24f-c409183a8b2d VL812 Firmware Firmware for VIA USB 3.0 hub VIA http://www.via.com.tw/ com.via.VL812_B2.firmware 26470009-97a8-4028-867a-bbbac6ee7bf0 VL812 B2 Firmware Firmware for VIA USB 3.0 hub VIA http://www.via.com.tw/
fwupd-0.7.0/data/pki/000077500000000000000000000000001267747510300143535ustar00rootroot00000000000000fwupd-0.7.0/data/pki/GPG-KEY-Hughski-Limited000066400000000000000000000032461267747510300203330ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1 mQENBFUr0UoBCACsdOLuTJ81dICrSvUhyznBsL4WgEa2RUbEjJuaXwrEyPMikHE1 Clda2YI7VbpCgIVq8Zy63CGJ4Xqs2T6pyetaXnbX8J0C+7wg2IfPv7pUyCsP7/JR HRB2GNelCWrsGArN1cOPI0ESH4yHWKF9KCGlpsLfSHmvF7D8vcKlKQUlO4T6lxOP SNjMSXkMsxfDDhl1mzqrwxfU4V6nnPcuMwU7tvg+39PioP4Ny1tKP4SSpBfh7qwz XXRd505dqNLOubxmOPZ5rznVkKmW2cwahO6fr5zVA8/2TDZQ79mdbfvSJVlW06qs C5PYmLnBjyzE5uQ4oxSIuUEiMfqrn3Qs6PhhABEBAAG0Ikh1Z2hza2kgTGltaXRl ZCA8aW5mb0BodWdoc2tpLmNvbT6JATgEEwECACIFAlUr0UoCGwMGCwkIBwMCBhUI AgkKCwQWAgMBAh4BAheAAAoJEK2KUo/sRIge/fUH/Rblgzh5GeB0Zp2U9W+r26iJ t1AD5a/fKxQahz/pwMkevQCCMzI1vpX12P3HtACZOD3Zjh9RXY6Z3033YZjrRApe FkOVfcyUF1nP/z2Ox3jE3+B8v1u0UzH/MqtF/1095mqvR7gllE288KDqu7bvd5l3 z4IETk5qqoeCe9LYc8aob973dbocyS/gou/FLCKxoXVEe8DPRwv8qmXlXOujxdxd FcslpYqtjj4fgUswQ/cY/a1UcAX5zCnVqFbU7oJH2uTNewKuaZ2wgPbnzvwx8JYl VfFdPN7GZ0NMrZDLeJ0SLXer/9+qAKNH4UpQS9axXQL+VKOzsZCXuv31VDCj5Jy5 AQ0EVSvRSgEIAMgVrZP3LmA9bx7B8l+agVh5DNXrMixX9jhZ0Yfn8+UIMMNTZziD ZV3nXxswKPrcsqQ+KP9iUwq3V2oio46bvHiMMoZSGCaTv4yiKOliFOMYr9NAOSTZ 8mOI24dNXI9XqQ7ZA8m4uKmgHZQUIUUlx693uRI2Wmk/Y5XEBoL2+XdA5KalO+36 27YXpdyU3GiMCOtSBLWNfBxXw6oKdNUp+8o/fYrmQnBxuGgmVlcZEmjhrIGXaCH1 iDeWIFqaM/S+DXMF3bgqvqRZq1U2RwT2oxapAuaG/0I5JaKKpb3HqMCXfOUxpFPk zgUYpHatUcePG/94K8N8CRjnJ+l83H5PewcAEQEAAYkBHwQYAQIACQUCVSvRSgIb DAAKCRCtilKP7ESIHrrcCACc6UTZzVGbVq9pXSz2Bw2xQpAEAhnnedPgfXwEJMM0 24bMUNsyJcQZAW1d5KfJYNAihOfse3oDQ/hJAycTK3GAHsPfljEQjWGn27eC8Fxu mHpfNpxbTirChfepCNctZG818Hp2v+K4X/PjyQMQ6J5H9oinnlasVQ6wzdZifnWm 7E5OL0NV/ni9xqq4fC5y5qxNBeYVmHUF4H0E3VOuCbESAOnUDpCo998Dc68eZEmV f3IMukvvnxM9VOZQSnp7J/kkhPB5fim2z2qrlJK9N+tBjAMugxtnAV2fIaZYTiba SnN2hheFd9Y0nMmWbwRqFtwMG1m/tS3JlD52Rpwzk59B =WFoi -----END PGP PUBLIC KEY BLOCK----- fwupd-0.7.0/data/pki/GPG-KEY-Linux-Vendor-Firmware-Service000066400000000000000000000016771267747510300230540ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v2 mQENBFWt/98BCADZ4+lUHSp4OMlzVf4HlJNLJ7Ks5QxGwL/hy2wChoNLuA/j4GNM 9mBZutKynYmphD0Mi4XjXn7JNXyuJa8Qutz98/Iyhsjq4LeiL9ayaKMXT+3pKlTm Gd/Fzo3QEOqTJ5s2RamrfwFIVuvwoj+rNmzj5fUCgoDOZeqVl6gxb7ZPzL8sWTOU iLeGMSzZBGE0ioJ82PZzsHelrrObDP1mMre1jQ6zxLlnYUlLvtJpydAfeBxU+6yL fgPeoFeuCE6JIszyWuyAgpBpYSGgj1bpt9Sxc2+MoZ0BjDzoijZqt4O48gYuEaLf iqYzQybe1JF0McO4C0dmjdKQz2qm0XrQyNhVABEBAAG0LkxpbnV4IFZlbmRvciBG aXJtd2FyZSBTZXJ2aWNlIDxzaWduQGZ3dXBkLm9yZz6JATcEEwEIACEFAlWt/98C GwMFCwkIBwIGFQgJCgsCBBYCAwECHgECF4AACgkQSKbYDkU4usJjjQgAzmTcA8qH s+1kieEZvsUzH4wun2Hlz7R5FRc/7BijgIQAA9TTrJnwbJmEBzEvHv7FKQLiBN3a 0lQIZgahmcUt1qm6VW94VAio+SDCdqTx73wUsgM3t9sAwKxkEdJQQoO8PqYHV3uK rq0t2YjXglIBHRDiJlOTAR3if37OCDKCcHOOODqYrsN7wNleez+ulkDyP7C7ZTbm /A7Xec73t2OQUnejU0uvRvc7VSnQDRFBHA9TPiBhbruMw+ZX+z/wfPd7x2RCqoOE vHh+QofE41Ya2QOkT96fAKfcJ+gvIbmwp3w7h+Hus1h3xDrykCG9cCxuH0HxooVI XL3IlFx/6OUpBA== =6Dz2 -----END PGP PUBLIC KEY BLOCK----- fwupd-0.7.0/data/pki/Makefile.am000066400000000000000000000004321267747510300164060ustar00rootroot00000000000000pkidir = $(sysconfdir)/pki/fwupd dist_pki_DATA = \ GPG-KEY-Hughski-Limited \ GPG-KEY-Linux-Vendor-Firmware-Service pkimetadatadir = $(sysconfdir)/pki/fwupd-metadata dist_pkimetadata_DATA = \ GPG-KEY-Linux-Vendor-Firmware-Service -include $(top_srcdir)/git.mk fwupd-0.7.0/data/tests/000077500000000000000000000000001267747510300147325ustar00rootroot00000000000000fwupd-0.7.0/data/tests/Makefile.am000066400000000000000000000003261267747510300167670ustar00rootroot00000000000000SUBDIRS = \ colorhug \ dfu \ rpiupdate test_files = \ rpiboot/start.elf \ pki/GPG-KEY-Linux-Vendor-Firmware-Service EXTRA_DIST = $(test_files) -include $(top_srcdir)/git.mk fwupd-0.7.0/data/tests/colorhug/000077500000000000000000000000001267747510300165545ustar00rootroot00000000000000fwupd-0.7.0/data/tests/colorhug/Makefile.am000066400000000000000000000011521267747510300206070ustar00rootroot00000000000000test_files = \ colorhug-als-3.0.2.cab colorhug-als-3.0.2.cab: firmware.bin firmware.bin.asc firmware.inf firmware.metainfo.xml $(AM_V_GEN) touch -c -m -d"2000-01-01T00:00:00" $?; \ $(GCAB) --create --nopath $@ \ $(srcdir)/firmware.bin \ $(srcdir)/firmware.bin.asc \ $(srcdir)/firmware.inf \ $(srcdir)/firmware.metainfo.xml BUILT_SOURCES = \ colorhug-als-3.0.2.cab CLEANFILES = \ $(BUILT_SOURCES) EXTRA_DIST = \ $(test_files) \ firmware.bin \ firmware.bin.asc \ firmware.inf \ firmware.metainfo.xml -include $(top_srcdir)/git.mk fwupd-0.7.0/data/tests/colorhug/firmware.bin000066400000000000000000000175001267747510300210650ustar00rootroot000000000000001 (~1 ðpÿ~ 1(üêëìíîï 0„0…'0™12!1 0„0…@0™12!1 0„0…@0™12!1@0„™0…Ø0†0‡0™1,!~ š1±*!Õ 02=Ž!4W(4†‡  9ÇÈGÊHËY(ÊËKJj(0ÇGº9™1H!!!3{(3†‡  9ÇÈGÌHÍ}(ÌÍML‡(0ÇG" Ø)!º 0ñ0òÿ0ó0ô@0õ0ö™1Û!1# !ÇGÔw)0¹(™1T!1¸(#!™1€!1£)™1'!1¸(#!™18!1£)™1p!1!ÇG"¢£)#!™1Ã!1£)0 >†0‡Þ0„…0!ÇÇ Ï(£)Þ0†‡0 >„0…0!ÇÇ ß(£)0 >†0‡Ø0„…0!ÇÇ ï(£)0!Ó0Ò0Ñ0Ð0 >†0‡Ð0„…0!ÇÇ )£)!^ Ô!_ ÕÖד1Ï#1 W!Ó V!Ò U!Ñ T!Ð0 >†0‡Ð0„…0!ÇÇ 5)£)$0!ÇG¹£)#!:N)!ÿ:N) 0!ÇGr)€0ñ?0ò@0ó0ô›1x#1!ÇGÕU£)€0ñ?0ò0ó0ô¡0ÇGõœ1¼$1!ÈHÕ£)ÕÕ £)T:¡(:¥(:µ(:¾(:Ä(:Ô(:ä( :ô(:«(:¯(/: )::) :@):Ÿ(t)!3´)3†‡  9ÇÈGÎH϶)ÎÏONØ)UÇG" !TÇG"¡ññ 0!ÇGò@0ÈHó0›11#1!ÉI³ñ 0!ÇGò@0ÈHó0›11#!ÉI´ B:*@98*!À A:ÿ)!®® *!® B@9:D9:D9Û0[!2 :À Ä,*D9«>†‡Û[àD9©>8*D9j>†‡Û[àD9§>†‡Û[ß_E*û0Û[àF*`ÄN*`ÛD9«>S*`ÛD9j>†‡[A:t*`†‡l*Äf*D9©>i*D9§>†‡„0Û`†‡[0Û[à`†‡˜*0Û`†‡[`†‡0Ó0Ô`Û[Õ0Ö0ל1$‘1* `†‡0 Û[àß©*`†‡Ì*į*D9©>²*D9§>†‡;0Û`†‡[0Ó0Ô`Û[Õ0Ö0ל1$‘1Ô*;0 Û`†‡[ D9˜>ÛÜ0Ü=[Ý\Þþ0Û]†^‡[!²ý*=Ž’0‘Ÿ0—{0’Žú*Žö*!²² 2:+=Ž+’0 çg!²=+û0 çg=™1–!’1=Ž!+ 3+•1Ÿ%’10 çg!²þ0 çg=?+™1¬!’1ï0 çg=V+P+s0 Ó0ÔÕ0Ö0ל1$’1¿0 çg=’\+™1ø!’1=’o+ÿ0 Ó0ÔÕ0Ö0ל1$’1=“0!2w+ =’Ì+ éÅ+ çgïo çç g 9èh!¸÷0 çg= o˜+!8©>›+!8§>†‡9 ç0çgþ9g!¸°+1Ï%’1À+r0 Ó0Ôo0çgÕ0Ö0ל1$’10 çgé0iÌ+=}+ 0 è0ç0æ0å ØXä0ã0â0á0àWcò+Vbò+Uaò+T`,d þ+ , ØXä0à0á=0â=0ã=ä+Wc,Vb,Ua,T` ,0×0Ö0Õ0Ô0ã0â0á0àWc6,Vb6,Ua6,T`b,d Y, U,0å0æ=0ç=0è=hgfeU,ÿ0×ÿ0Öÿ0Õÿ0Ô ØXä0à0á=0â=0ã=(,™1T!“1 ØXäd >„•0>…ØÙÚÛ[ôZóYòXñhøg÷föeõš1C"“1t ßsÞrÝqÜh_Ÿ,g^Ÿ,f]Ÿ,e\ª,ÿ0×ÿ0Öÿ0Õÿ0Ôh×gÖfÕeÔ ÈÉç,!À H!.:ó, Èó,!Àó,!À ÄÏ,D9«>Ò,D9j>†‡ñqòr†‡ó,r†‡ó,0ñqÈó,@9:·,:Ã,:Æ,ó,!ÀH0¾0¿@0ñqÁ›4•4W4•4q4•484f40464444444•4 44)44444À4–4 444444444 4!44444"4444444@4444444@44444ÿ4 44¡4444)4@444&4ÿ44u44•4@44444)4@4‘44À444H44u44g44h44s44k44i44 44L44t44d44.4444C44o44l44o44r44H44u44g44A44L44S4444444444?4'44444444444 44!=“˜0ô™0óõu½-s†t‡0ó0ô=0ñqõu­-0=‘Ÿ0—{0’ö0vâ-vñ0ñ5ÿ>Ì-q5 >†‡0À?0Á?Â?Ã?0ñqö0vÉ-=–=ô-÷0ñq!À¢£¤ç-0ñq!µ0ñq¶°±¯ö0v!.vj>†‡v«>†‡v§>†‡v©>†‡0ñqö0v.(0ñq ê0=˜@0ñ0òq ¢r£0¡„0ñq !ò n†‡A?övóôt!$L.s#R.#ósö0 >†‡vóôó ô ó ô @?s£A?t=¤õvu}.uH>†‡ó †‡s0ós 0ósõe.0 >†‡®.0ó| †‡sH0ó0ô|>†‡sÀ?tÁ? n†‡¦.È0ó|†‡sˆ0ó|†‡s0ó| †‡s@0ó0ô|>†‡sÀ?tÁ?„0ó|†‡s!¢ ì1p% @9:DA:ø./!C:/#0¾•0¿ 0ð.:0!¾•0¿0Á0ÂÀ0ñqÀ/ C!:ß.:ê.:// @‰ 9:@/Æ0!¾0¿0Á0ÂÁ0ñqÀ€0ñq!À Cñq!ÆÅ0!¾0¿0Á0Â0ñqÀ€0ñq!À Bñq!Å A:U/: /:&/ :U/:/:4/U/!À0 Ü™0ÛÝ]q/[†\‡0Û0Ü=0û{Ý]a/ 0ñ0ò0ó0ô 0õ0ö™1Û!—1= Þ0^š/^§>†‡^©>†‡0û{Þ0^ˆ/Ä0ñ0ò0ó0ô0õ0ö™1Û!—1=(0û{ ê 0û{înû{üBû{!ÃÃÅ/0û{²0 Ó0ÔÃ0û{Õ0Ö0ל1$ 0û{!² Òxã/ñRš1u"—1øë/ññ Rš1u" R˜>ùú0ú=yÐzÑP†Q‡xœ1†,œ1‰,œ1»,œ1‰,œ1»,œ1m,œ1v,œ1¤,œ1|,œ1y,œ1Œ,œ1˜,œ1», ‰ 9þþ -)4d€1‰ 3)4ñq ŽŽ444444ÿ4ÿ4K)Q)!9$:I)Q)!¹  ‰ 9ñ0ñ5‰ Z)9qó 0òû0ññ f)ò f)20ób) ‰ 9ñ0ñ5‰ v) òò r 9qòr9ññ qï9qŽr69ññ ñ qû9qŽ!¯t0 Ó0ÔÕ0Ö0ל1$=Žû0û{=ï0û{Ž!¯¯ u0 Ó0ÔÕ0Ö0ל1$òr9ññ ñ ñ q÷9qŽr69ñññ qß9qŒrøøq÷÷0õ0ö;ÿ0vë)ÿ0uw†x‡s0÷0ø=á)=* n†‡€:*j†‡„:*Œ0ñn†‡q=ß0ñq m: *–1<& í!­A*0÷| †‡w@0÷0ø|>†‡wÀ?xÁ?Œ0÷|†‡w­0 Ó0Ò0Ñ0ÐqW*u ÐvÑ=wÒ=xÓ=0õ5ö ÷ ø ‰ X*0ô6ó ò ñ ‰ _*tsrqL* SôRóQòPñö 0òr÷qò0ò5‰ }*vó0ó5ÿ>ƒ*s5rô0ô5ÿ>‹*t5õu÷w†‡ñŸ*wòv«>£*wòvj>†‡rw†‡w>†‡=Žº*ŽŽÿ0™1a!š10™18!š10™1€!š10™1Ã!š1•1Ÿ%š1!×0Wè*0™18!š1_0™1a!š10™18!š1_0™1a!š10!ÖV×0WÏ*d’1é"š11= š1è*!½ ì!°±­ í0âj†‡b0âbê0âj†‡b0âbê0â|†‡b!ÀÁ¢£¤œ1e$š10 Ó0ÔÕ0Ö0ל1$š1ž1«&öq8+vj>:+v«>†‡ôt÷÷E+0rô0õw>†‡tÀ?uÁ?sôw †‡t@0ôw†‡tˆ0ôw†‡tqn+0ôvj>r+0ôv«>†‡tw@0r0q+0?0qõ0rövu+0?0sõ0tövu™+00ò6ñ ‰ š+÷øtx¦+swÂ+#wqõxr=öu‘v’U0–ª0–• 0÷0ø= +#0!°± m:é+0ô| †‡tH0ô0õ|>†‡tÀ?uÁ?È0ô|†‡t!B Gó+!A Fþ+G! F!ÁÁž19&H0ô0õ j>†‡tÀ?uÁ?È0ôj†‡tJ,™1p!œ1 ØX!»0™1Ã!œ10™18!!;™1Ã!0 ØXø0—1Ú'œ1ñ 0 ØXò@0ÙYó0›11# ÚZ!´–1Ñ& T:P,d,S:+,:G,:d,w:d,:&,:,d, @‰ 9:°,!À0 áa!²Ÿ1#'—1V'Ã0!¾0¿@ÁÁ À”1³$‘1ê! DÄ>!¾0¿@ÁÁ À!À BáDÄ>†‡a0Ó0ÔÕ0Ö0ל1$ A„ 0˜15>‚@0r0qÅ,00ò6ñ ‰ Æ,øùtyÒ,sx-#•r’’q‘‘0ñ0ò=xuöv†0‡“x>ö0y=÷twø,sv-x>uöv†0‡”U0–ª0–•0ø0ù=Ì,#0 j†‡00ö0ôtê!2:3- B=–.-0/-0ôt!² m:j-H0ô0õj>†‡tÀ?uÁ?ž19&1!=:U-„0ô j†‡töa-È0ô j†‡tˆ0ô j†‡t!¢¢ í!µ0ñqµ¶0ñq¶ m:-j †‡È0ñj†‡qm:!­0ñ n †‡q@0ñ0òn>†‡qÀ?rÁ?„0ñn†‡q!­­ 0ñ| †‡q@0ñ0ò|>†‡qÀ?rÁ?€0ñ|†‡q oý9..o6?9ã0ã5ÿ>Ø-c5 >ädînãcü0ãcün†‡ ‰ 9 :+.æ0f.n>†‡@?ãA?äc†d‡åf@>†‡en>†‡0A1 0ãcæ0f÷-@0ã0än>†‡cÀ?dÁ?š1ð"š1"ý0 oãc:1%0ñqó0!B0AW.Añqó½O.½½ W.=:W.0ñq½0¾>†‡sñòñ ò ñ ò @?qÁA?r=Âsñ j †‡qH0ñq!¼@Ž.§.>„?…ñ<†‡q0¾0¿=0ñq¼0óóy.>„?…ñ<†‡q0¾0¿=0ñq¼0óó’.=!Àä.¢Á.0öv í!±½.›1Æ#!¶µ0ö| †‡v@0ö0÷|>†‡vÀ?wÁ?Œ0ö|†‡v„0ö j†‡v Àú.íí !°ð.›1Æ#ž1!¶µ ì1p%0öv í0ö| †‡v@0ö0÷|>†‡vÀ?wÁ?„0ö|†‡v!¶µ ì1p% @€:À0ñq!À/‰0!¾•0¿0Á0 Bñòñ5ò 0q„•0r=…?!¾?¿?ò>ñ0q„rr …ósÁ?ò>ñ0q„rr …ósÂ0 B‰/Bñòñ5ò 0q„•0r=…?!¾?¿>„?…ñòqÁrÂ!À!À C:./:8/:h/Œ/fwupd-0.7.0/data/tests/colorhug/firmware.bin.asc000066400000000000000000000007311267747510300216300ustar00rootroot00000000000000-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJVLPMHAAoJEK2KUo/sRIgeAxAH/jPY7c2qrG4UEsZXgUFxMUQe QEufh3cK9cv8kA7SAzpSHy6M0rNanC2vCqcc/fTJI/yBRfBjPPZYEsQgwpB/8m9y wiTPRuQySwCKsH+ZXNh3j6x8Oaf3DTiO7bJI/M3sOb4fdvb0Csp910g67Nt+HtMw I5EUM0uvMquZTUygp9B6BBJv8xRKtCNgqvPhyoDZKxKrPzaFwvb7BY50Q03LymU6 hQUIkjHIvMcTljNocOZNvTBHvEGB2BiBb60QhAXYyNfDrS58pm2JHfw/pgOuQTzT 3Lw9qmedRXbWR95u/piUmyUsY5ey75lD08U/2aE9RLBZ9xR17u1mAgyLGoIMYEk= =ZdoH -----END PGP SIGNATURE----- fwupd-0.7.0/data/tests/colorhug/firmware.inf000066400000000000000000000007661267747510300210770ustar00rootroot00000000000000; Copyright (C) 2015 Hughski Limited [Version] Class=Firmware ClassGuid={f2e7dd72-6468-4e36-b6f1-6488f42c1b52} DriverVer=03/03/2015,3.0.2 [Firmware_CopyFiles] firmware.bin [Firmware_AddReg] HKR,,FirmwareId,,{84f40464-9272-4ef7-9399-cd95f12da696} HKR,,FirmwareVersion,%REG_DWORD%,0x0000000 HKR,,FirmwareFilename,,firmware.bin [Strings] Provider = "Hughski" MfgName = "Hughski Limited" FirmwareDesc = "ColorHugALS Firmware" DiskName = "Firmware for the ColorHugALS Ambient Light Sensor" fwupd-0.7.0/data/tests/colorhug/firmware.metainfo.xml000066400000000000000000000022211267747510300227100ustar00rootroot00000000000000 com.hughski.ColorHugALS.firmware ColorHugALS Firmware Firmware for the ColorHugALS Ambient Light Sensor

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

84f40464-9272-4ef7-9399-cd95f12da696 http://www.hughski.com/ CC0-1.0 GPL-2.0+ richard_at_hughsie.com Hughski Limited

This stable release fixes the following bugs:

  • Fix the return code from GetHardwareVersion
  • Scale the output of TakeReadingRaw by the datasheet values
fwupd-0.7.0/data/tests/dfu/000077500000000000000000000000001267747510300155105ustar00rootroot00000000000000fwupd-0.7.0/data/tests/dfu/Makefile.am000066400000000000000000000003411267747510300175420ustar00rootroot00000000000000EXTRA_DIST = \ example.bin \ example.dfu \ example.xdfu \ firmware.bin \ firmware.hex \ metadata.dfu \ kiibohd.dfu.bin \ dev_VRBRAIN.dfu -include $(top_srcdir)/git.mk fwupd-0.7.0/data/tests/dfu/dev_VRBRAIN.dfu000066400000000000000000002650221267747510300201600ustar00rootroot00000000000000DfuSejTargetST...00DD200085DD40008A9 :1067DC00E1D2000849D200080000000000000000CF :1067EC003DD20008D90300000000803F0000803F2C :1067FC000000803F4BFB00084FFB0008C5FB000866 :10680C0055FB000885FB000800C2010000000800D1 :10681C0041FC00084DFC00087DFC000859FC0008F8 :10682C00åhÑf8? ¹Ô úQ=úúúúúú­µÔµÔµÔµÔµÔµÔµÔµÔµÔµÔµÔµÔµÔµÔµÔµÔµÔµÔµÔµÔµÔµÔµÔµÔÙâµÔµÔ­â¹âÁâµÔÁð%ðµÔµÔµÔµÔ5ùAùMùµÔµÔúµÔµÔµÔÍâµÔµÔ-›µÔµÔµÔµÔµÔµÔµÔµÔµÔµÔµÔµÔµÔµÔµÔµÔµÔMúµÔa›µÔYùµÔµÔµÔµÔµÔµÔµÔµÔµÔµÔ8µML+h"ˆ›\þ+Ñ#àÿ+ Ñ K "p K"Zƒ K"p8½ ðÔý*h#ˆ MÒ\ !û(`3#€8½¿  @  8µBL#xƒBÙ (}Øßèð;61@""EN@', ##p ð¨ý9K`9K"Zƒ9J#p8J`bà8Kx*aÑ5J6I` ""p"pVà1K3J` p"à.K2J` #Kà,K0J` #Fà)K/J`#Aà'K-J`#<à$K,J`#7à"K*J` p3àK)J`##pK"`*àOô€pðú³#KÛzë±#Kx(Ù#!I"ZTÊ%Up+ñê²аëR+FðØà" Dd#Spÿ#“p K`àKJ`##pK"€8½  @   p/ /˜/£/‚/³/•//ª/ê& æ'  /  -éðA K!L[{+±#x+Ù ÿ÷Fÿ#x +2ÐL#h&F+-ÐM+x/F£¹KÓø€ ðñü€E Ø#+pK"hˆÓ\±K"ƒ½èðAÿ÷õ¾;x“±Kh ðÛü„B Ø K"p K2hˆÓ\+êÐK"Zƒæç½èð’'     @pµF¶ûòôFF± Fÿ÷öÿûdK]ø;p½¿H1µx *FñùÐ *÷Ð-*ÑF¿î à+*¿F·î Ÿí7zFFø¡ñ0IJ , Øî øîåzòîjçî&z°îgzìç.)ÑòîzðîgjFø09Ȳ ( Øî¸îåj†î'jgî¦z7îzíçxðßE*4ÑZx-*Ñ3"à+*¿33";!ø08IJ ,Ø $ûõç±õš4¿ FOôšsF÷îz)Ùßíj9gî¦z÷çð+±òîjgî¦z;øç"±Çî'zà÷îzgî'z î' ½¿ ¼¾LµDø!±Kh ð…ý÷罿À& Hÿ÷ï¿¿m1µHÿ÷èÿ$KHáX 4Rhð øÀ,õѽ1h0³1pµ ðóû)Kˆ)KOôzq°ûññx'Hðòÿð„ø%Kh%Kh%KSø!%KF²ûóò$Hðâÿ$ã²"JRø#I±"úó+BÐHðÔÿ4ðç ðIø˜±LK"xHSø"ðÆÿ#x+ÑKH}+ ¿n!o!ðºÿHÿ÷ÿKˆðý!FFOô™cH½èp@ðª¿x' . »1( \ B@Bù1äA"2Ä (1&2À& 02å4D 428µ hF Fð5û!FF(h½è8@ð7»µ Hÿ÷Jÿ! ðtÿHÿ÷Cÿ ðqû ½è@ ð“»¿f2p2µFðû($Ñ#Iâ\ hDIxð)¿ :âT3+ñÑ%f]H1Fðíú(±5`1Fðçú±Hÿ÷ÿà-íÑ Fð‰þHÿ÷ÿ#JD©’ø‚! D IY\ø 3+òÑ# Hø 0©ðÿ°p½¿” 4M2Ÿ2L! ¶1µðû0 ¿HH½è@ÿ÷Ù¾¿´2Ú2-éðAFð®úFðŠùFŒ¹)Hÿ÷Çþ)KSø$A±#£@3BÐ&Hðæþ4òç$H!à(F$I"Fð›úX¹"H#Lÿ÷®þTø)ïÐHðÑþ÷ç+x-+¿5ñÿ4OðOð&KSø&p'¹H½èðAÿ÷’¾(F9F"Fðuú˜¹ °@¸ñÐð5ùHàðOÿHÿ÷~þ9F H½èðAð¢¾6Úçø2¸/"2å4˜? 3´/ 3:3D3¶1µFHÿ÷[þJ#pJ`Jpð~ù F½è@ÿ÷ÿ¾¿M3% X $ µHÿ÷@þ ðÿHÿ÷:þ ðhú ½è@ ðŠºe3r2øµFð úF8¹KHZyK:Sø"(à8FI"Fðú`¹HLÿ÷þTø±Hð:þøçHà%KSø%`&¹H½èø@ÿ÷¾8F1F"Fðæù5(îÑK H]q1F½èø@ð¾¿L! €3 0˜?”30"2å4§3¿3µF Fð¸ùðÿÑ K H“øÀ½è@ðø½ FðSù(ØKLƒøÀ Fðïýã罿L! Ñ3õ6pµFð“ù¹ H0à FIðãù$&F%Fx±,±,Ñð,ùFàð(ùFI 4ðÐùîç -ÙH !½èp@ð»½,ÜKH3ù )F½èp@𰽦õzs³õzÙ H½èp@𦽠H)F2Fð¡ýK#ø`p½¿ç3¿6!4^( G4_448µFð?ùÀ²h¹FKHëD!F³øF 4ð}ý,óÑ8½(FðÕø(F Ü !(FðùðÌøKëD¤øF8½H!½è8@ðb½H š4¦4“#+(¿ "µ FÚ- ø XBÿ÷ˆü#p F½0µ-틇°°î@Š! "F¨ðÑøµîÀŠßí+zñîúÌ¿8î'Š8îgŠßí(z(î'ŠiF½îÈŠ "îZ…êåp ëåpÿ÷Çÿ-¬¿ #-#hFø 0ðÏø(Ñ0#ø 0ø0ø0 à(Ñ0#ø 0ø0à(¿0#ø 0iF¨ðšø¨ð±ø8Ų*F© FðÕø#cU FIðŠø© F)Dð…ø F°½ì‹0½¿o:zD}27µyF F+7Øßèð ƒhx0àƒh“ù,àƒhˆ)àƒh³ù%àƒhh"àƒhhF“í ÿ÷rÿFHð¸ü³ÔízhF¸îç ÿ÷fÿFHð¬ü”í hF¸îÀ ÿ÷[ÿFHð¡ü à!Hðœü%±Háh"ið–ü°0½-2,2Ð4Ì4-éøC-í‹Fð:øONF ±(Ñ+x*+ÑLHÿ÷Pü$1YJHðuü09Fÿ÷“ÿHHÿ÷Dü4@ö3œBïÑ}à(F=!ð ø(_ÐD Fð¼ÿF Fÿ÷¨û'°î@Š$|CVø€@FðøAFF(Fð ø(<Ñ1KD”ízøîÇz´îçŠñîú/Û”ízøîÇz´îçŠñîú&Ø"y*¿îšî:*Øßèð ¢hp à¢h€à¢h‚íŠà£hƒíŠAFHðü½ì‹ F!½èøCÿ÷0¿Hà7Ž/±ÑH½ì‹½èøCÿ÷Ø»F7Y)F8FðîÿX± H9Fð÷ûH! Dÿ÷ÿHðïû4@ö3œBèѽì‹½èøƒBÓ4²5å4è4ó45pµ-í‹^H^L„°ÿ÷¦û]HðÍû]Hÿ÷<þby\K\H:&FSø"ðÁûÔízõî@zñîú_Ð4%íеî@ŠñîúRÐ5QHTíš”íšÔíŠ)Fð¦ûµîÀŠñîúÕKHðžû°îH hFÿ÷OþFGHð•ûõîÀšñîúÕBHðû°îi hFÿ÷>þF?Hð„ûµîÀšñîúÕ:Hð|û°îI hFÿ÷-þF6HðsûõîÀŠñîúÕ1Hðkû°îh hFÿ÷þF/Hðbû -ñ¥Ñ,HiðZûðìý*LFTø±)HðPûøç F'KSø$A±#£@+BÐ$HðCû4òçsª“ø‚1D JŠ\ø,1)óÑ$Hø@iFð.ûMHaYð)û(!ÿ÷GþHÿ÷øú4@ö3œBîѰ½ì‹p½¿m1L! 55õ6 0e5p5¿6-2¶1x5´/Š5¸/˜54M¥5B®5å4𵉰Fð þŲ-rÑH€Lÿ÷ºúTízõî@zñîú,Ð5)F{HðØúí ¨ÿ÷‰ýFwHðÏúí ¨ÿ÷€ýFsHðÆú”í ¨ÿ÷wýFnHð½ú”í ¨ÿ÷nýFkHð´ú -ñËÑßíhzhK°îgzðîgj"ªBñ ÚíZSíZíj2vî…jwî¥z7îzíç]HÍíjÍízízÿ÷cú$«#DízßíWzWKXH°îÇz´îçzñîúØ¿F4ÿ÷Oú ,êÑRHtà FQI"ð.þ8¹PKD0"À(aøÑ{à FLI"ð þF F» !ðþ(nÐF0Fð þ,FFDKSø$P ¹CHMà0F)Fú²ðþ8¹ Fð'þ?H)FðAúLà4éçðšýF .FHÜ F !ðÜýFP±E(Fÿ÷|ù/Kë‡í $àF(F !ðÊýFH±E(Fÿ÷jù&Këƒí 4(F !ðºýFH±E(Fÿ÷ZùKëƒí 4(F !ðªý¹Hÿ÷Ôùà0ÿ÷HùK,ë†í ñÑHÿ÷ÿàH !ðëù °ð½¿À5d! ë5ñ5¶1`! õ5 ×#<¼5¸5å46L! 6 0§36"6õ6\6-éðGgKx†°˜FB¹#eHˆø0ÿ÷‡ùdHÿ÷„ùcM(h ðÿ©F(ð·€(h`L ðÿ (FÐ?(OÑOð %h[OVF-±[H9h*FðPý¹ºF¹>FWK 7ŸBñÓÎ±ÖøàÚøÀ+Føpø¸BÐ#` àZMI0¹-+Ø 'ÏT"`ˆTàÏTFêç#h ±VEÐGHÿ÷>ùVE ØVø ÿ÷8ùÙø ! ðÁþóç9Hÿ÷/ù%#hB¦Ò:KÙøY] ð³þ5ôç#h+¹(6Ñ4Hÿ÷¼úUà (Ñ4Hç )Ð )DÑ2H-Mÿ÷ù"h*I•#«T“.K“¨" #ðŽüF8±hðÜü0³h(D˜Gà&Hÿ÷õøH!0"ð­ü##`˜ø0+ôb¯"à (ÌÐ)Ñ^ç/+?ö\¯¡ñ Ò²^*?öV¯¹ )?ôR¯Z"`J(hÑT ð]þIç)èÑ; J#`!ÑTH>ç°½èð‡$ „6¼6À& X h0% (1Á6Æ6å4iÑ6ò6KxH*ÑZˆ²õ™oÑy¾*Ñ“øÄ$ï*Oð Ñø+P@J“BùÑÐñ8¿ pG pGpG¿ÈpµFDøa±N0FðJü(öІH0Dc€ø‚1ïçp½4ML! µÿ÷Áÿ¹ ðŸü K IFOô™bðüøÀ$*„¿"€øÀ$øÀOô‚rûõÚqHðþû½¿L! H -éðG.Hø PÄ#ûñ9iCöÄYC@öÄaC‘ûòñ'J"ø3+íÑ%Jø!0²ø@a²øB¡ø"àÃñd ëƒ \B_ú‰ùOêL ÎñdÆë ¤²"¡²²/Ü)¿F%àMFûñûñûõ‘ûõõED !}C•ûñõeD-²Oôzqû õ•ûñõ I5DUR2 4*¤²ØÑxðyü½èðGð»»¿H 8( L! ' µÿ÷mÿ½è@ÿ÷‘¿øµ/KH"pOô™bZ€¾"qï"ƒøÄ$"FƒøÅ$FQ±“øÀ&IOô‚rû0õÚpðiû"F±\2²õ™oƒêøÑJ%‚øÅ4 ðÆøó ðÙøX ! ðù(ÑL3ñwCõr Fh ð1ù(Ð5 ð¼ø-ãÑàK4œBêÑ ð³ø-Ðÿ÷Ûþ¹ ð¹ûÿ÷¡ÿ7± !"½èø@ð1¹ø½L! H È8µF F ðÐû(F!Fÿ÷ÿ½è8@ ðÅ»KhB ¿  pG¿\ KhC`pG¿\ Kh"ê`pG\ KhpG¿\ K›hB ¿  pG¿L! KšhC˜`pG¿L! -éóGFÿ÷þ±,ð½àJàMhQhàLkFÃOô™b!(FðÑú!Oô‚r FðËúH#+pOô€ #kqÿ÷ÔÿOô€pÿ÷ÐÿOô`ÿ÷Ìÿ ÿ÷ÉÿOôs¥øb1ú#¥ød1*#¥ø`1Oôús¥øh1 #…øf1n#…ø}1+#…ø~1!#…ø1##…ø€1@òLC¥ø1@òls&'"Oð OôÈp!@òÜ^¥ø’1@ò~C…øS!…øT!…øU‘¥øx…øŠ¥øŽá…øÀd¥øja¥øla¥øna¥øVa¥øXa¥øZa…ø]a…ø^a…ø\q…øa…ø‹a…ø®q…ø¯a…ø°a…ø”a…ø•q¥ø@1@ò:s¥øB1…øŸOôzsOôá1¥øD1¥øN@ò~S Åø¤OôQ¥øF1…øv@òêS Åø¨@öÄ¥øH1©@ò´S@öÿq`u uU Oð(¥øJ1¥øš2#!àpOð - ¥øL1¥øP1ár!s`s…ø–q…øžq…ø¬a…ø­a®s…ø—a…øÂt…øÃt&p„ø€„ø€æu#q„øÀOð „øÀ„ø„øÀOð OðP Oðd „ø#0„ø$0„ø!0# v„ø„øÀOð OðZ „ø  u„ø10A cK„øÀOðx „øÀ„ø „ø%¤ø&à„ø. ¦s&væsfv„ø„ø €„ø  §w„ø"`f…¦…&…„ø/€„ø0€ccRK£cRKãcRK#dRH„øDp#„øE0ÿ÷mýOôHs¤øz0È#„øÏ0Oô–c¤øÐ0@òÙ3¤øÒ0„øv`„øw`„øx€„øyp„ø|`„øÎ#FOôr¤ø~ Oôúb¤ø€ ø „ø„ 6@òÜQ.¤ø‚ñ êÑ"ƒøÔ ƒøÕ ƒøÖ ƒøÜ d"£øÞ Oô–r£øà ("£øâ Oð|RÃøä Ãøè "£øð £øò £øô @òlrÈ £øö @òR£øØ£øú  $Oð~RƒøÚƒøÛ@£øî£øø£øü`Ãø!R#…øÁ4#ê3!À+aùÑ$(õÚp IOô‚rõ‚tð"ù´õCòÑ F°½èðGÿ÷ú½°½èð‡¿,ML! H š™?ö(|?= w? @=MKšh"ê˜`pGL! K"š`pGL! K˜hpG¿L! 8µL% påa ðUù%b`b8½H& î øîÇzŸí Ÿí zõîÀzñîúØ¿ñîgz‡î€ µ î ð ùKƒí ½€–K5úŽ< µî*[-í‹øîçŠî:Kœ¸îçŠÓíz(î'Š(î ¨î¨ ð±ûßíz› î' ðîH ýîÀz±îh Ãízðüùßí zŸí zàîz½ì‹ýîçzî:+¼¿õ C 3#`½¿ ,}Ž?  F  ³Eî ¸îçzÒíz'î'zÑízçîzµÁíz’ízñîGjýîçzýîæj½îÇz Fî*î îð¸ûî øîÇzÄízýîçzî ½0µ"FIÌ\ Fœ±.,Ñ3x±D$,TÉ\ $bC¡ñ0 ,œ¿0:R+Ø3ççF0½ 0½¿¤ 8µ Mëz£± Kx+Ù K Lh[hc` `ÿ÷<ÿKˆK€Kˆ£`#+s8½ê& æ' È' „' Ø(  ' µ"FHL!RHRHDR `a` ` LD3 `a` ` LD+ `a` `ñãѽ À ' 0' Œ H :Kßí;zXy:JÙ{î ¸îGz˜y‡î'zòîj‚ízî¸îGz3IÑ`‡î'z‚ízî ¸îGz/J|Ñ`‡î&z‚ízî ¸îGz˜~‡î'zî ‚íz¸îFjŸí&zØy†îj‚íjî ¸îFj!JX|Ñ`†î&j‚íjî ¸îFjØ~†î'j‚íjî ¸îFj†îj‚íjJ|Ú±yJ˜{~î¸îFjÆî&jÂíjî øîfjÆî§zÂízî:øîgz‡î‡z‚ízpGH ÈBì úD0 zD & ê& 0& ÷µF ÿ÷_þOô€pÿ÷[ü(>Ð Mnpð±ÿ$¨`l`M•øž1£B ¿''ÿ÷]ÿK”ë!FrhH;F ð™üK˜` ÿ÷:þ•ù 1+È¿…ø A•ù !SK ÐIëBëBh’ˆÃø Ú à JhÃø˜QhÃø ‰°ð½H& L! O@À&  ìNâN-éðAKx++ÑM #kƒKOô€BZƒL h ðÑøP± &.ƒ h'h ðÏøF8F ð¶ønƒ hO ðÁø(éÐ L8h×ø€Oô€F&ƒ ð»øF@F ð¢øfƒÚçOðÿ0½èðH& @ @À& sµLh#` hc`MhNÿ÷ËýK“•è”è –ÿ÷âý`hihJ3h`AîI h‘íz)hJøîçzAgî‡z`ýîçzÂíz J` K³øÞ K€°p½¿ È' p D& &  ¼ | H ´ DòPc˜BÝ õ @ 8pGK˜B¼¿õ @ 0pG¿°¹ÿÿ&KðµhFñx+F^xð2ðÿn±ºBóÑ ð½±ëƒ[Û²ø+0:DÛ² *òÜ"B Ù±ë‚RÒ²øk0>2DÒ²òç.,ÑL ! &qC&x¯xÕ0941D8óÑà!HBCd û!$H±ûôñûð½” @B€–˜-éðO–L-í‹£h‹°Ó¹”N3x;+òç†ßèðýýý׺K˜h ðàÿK“øž1+Fð4Ó+Рh ðÎÿ(ìÑÞç$- ÐØ -𚀠-ð—€èà*- Ð,-Ðãà~J#p~Jp~Jpìà{Oßøè:x{K˜ø`!™TzJî¹xpG)ÑYxP)Ñ™xG)ÑÙxG)ÑyA)Ñ!p˜xnIR(ÑÈxM(Ñ yC)¿!px*Ð*9ÐNà²*KØßèð  (J.aHÿ÷1ÿbK`?àxS+<Ñ_KhRB`7àZHÿ÷#ÿ[KX`1àxW+.ÑXKZhRBZ`)àxVK0*”¿""Úr!à ÿ÷ýPKrà ÿ÷ýMKXà.Ð.Ñ ÿ÷ ýHKØ à ÿ÷ýAòCOôzrXC°ûòóAJ“6#*-ˆø`;paÑ?J!pcà=N3x+KÐ7I x@+Ù£ñ7Ò²àððKx@+Œ¿7;0;Û²D,JxÛ²™B2Ñ,Kx- Ð-,Ñ*K,J™‰€Ú‰+K€$àßøœ€˜ø 0 ¹#à"J'Kh`QhY`%Kz%Op S‰;€ÿ÷ñù(ìјø0+èÐ K:ˆ›hÒd#ZCK`ßç#"2pà Jx+ØYp JÕTKx#¹ JxM@pà#ð~áÀ& H& L! „ ¸ ü ¤ (  ê& ˆ 4' L È' æ' ' „' ”& ”Kx")òTßèð %3Pitb(Ñ"àpµ-@ðEx2p@á"pˆKpˆK à†I"p…K xx*DÒ² pDp‚Kp,áI"p~K xx*DÒ² pDp|K€áxI"pwK xx*DÒ² pDpuKˆë%­²µõØ€à"€kKpoJ#€áiHjJxx)Dɲp1DpiI ˆÇ*œ¿hH…T2’² €cI ˆ‘B@ðë€"¥ç"p\KxƒBðâ€XJ#pÞàpXKxƒB@ðØ€VKx+JÐØ+Ð+5ÐÍà+UÐ0+@ðÉ€RKyRK*ˆ¿"pxNJ#màLKNJYhQ`™h`iLMLNOôzs’ûóó+€JKxórJK" pÿ÷óø(iÑ3|+fÐEK*ˆ›hÒd#ZCCK`]à:JSyðÐyØCBCA:Jp+PÑ7JÓrMà2KÚzðКzÑJBJA2I p ¹0IÊr“ø/ 3Kp:à(K2NZi2€ši1MBòs’ûóó+€/K" pÿ÷±ø@»#K|+³3ˆd+"Ù*ˆ #²ûóò'K‘²€ ²³)Ý¢õ´r€à‹Bñ Ú!Hø\T Hø\THø\THxT3êçI x»³Kx¢³"p p#0à ý þ ‰ ¼ è È ç' È' ' ê& ˜ ÿ „' ”& æ' 4' L  Ø( Ø& ª' Ð' '( #+?ôq­šM«hë`ð¿û¨` ÿ÷Iø—Kx* ¿""p”KÚz*?ô\­“Jx*öW­Zx¹|¹s{¹ ±ÿ÷ûŒKMxOð2’ûþþëŽÎëƒøà‡Kx“‡KëŽ#†J†I˜XßøP‚…NXPûøñ™Qëƒ ƒNßø@’ûSø p^ø `Nø ¿Bò|ûüü&8DCø ûöðûxHP˜úŒü(ë %øÏFѬñ ¼õy˜¿Ëø3+ÅÑnOnMßøˆ¡ðKû;hŸílzÀî øîEz·îŠÇî‡zÅízð;ûÕíz8`ôîÈzñîúX¿ðîHzªÅíz_K’ª’–è Ëÿ÷õùš[I˜d#’ûóò €YJûóó€šø 0/F ¹ €€UIVK x*=ÐÕíz0hhÈî'z‚phOðî*¸îÇzZh'î'z€½îÇzKJîºî ÒíjHJ¸îÇz²ùà²ù'î&z ú‹ðgî'zûøðýîçz€²îÊúŒþžûøþßøÁ€úŽþ¬øà¬ø¢øà" p0hqhY``šø0#¹KÛy+?ôp¬ßøÔ€ßøÔßøÔ°ÍøÍø°˜è ÿ÷…ùØørh(KŠî*$JØø’íz2høîçzŠgî‡z`ýîçzšø Ãízßø0 ±"Šø šù *?Ð*ðЀ:äH& l ê& æ' Ä ( < ` È'   €igÿœ ¸ @ zD„' ‚' ' ) ˆ  € ¼ €–˜t D  D& p |N%Sø{Jßø ¢Òíz5ø ßø’—í ßø‚î ¸îÅzîgî'zýîçzî €oJ€²¨R²î ¸îçzÙíz“gî'zDýîçz1FJFîºÿ÷2ùeIßífZ‘øÚ›—ízSø ÖízÙíjî¸îFjqhr`&î%jQˆîjú‹ûXD%øOôúbî6îjøîÅZ‡îjSI…î‡z7îgzæîzÆízÆízfî§z“ýîçzî ðÐü5ø II12’²b*5ø ˜¿ D€²%ø@ö¸2²ð½üBJ(ø !û"5Vø`-›ôq¯ÿ÷l»™íš5Kî ³ùà€7KûòòE¨¿Fˆúˆøúˆð²ˆBÝ•ízßí0zgî'zýîçzîŠDúˆø£ø€+KÛøPhÃë XFÿ÷¶ú(Aò“ÝBàCB“BÌ¿##ßí"Š"N+KÐîÅ ¸îÉš î( ðÐù î KI½îÀ @ö¸2î €²€²ðWüHö C(D˜BÝ õ @ 8à(¼¿õ @ 00`#࿌ ì ´ H ÛÉ@0øÿÿHôÿÿH ´ ÈB| Ó79& º D 0' 0 5`3h¯NÃõ S(3î:øîÇz%g°îh ð÷øí °îh ðwùí ¥JßøÐ²ª^úˆñ ¨î*îëESíjžI¸îÇzøîçzOôzrÖî‡zýîçzî €²%ø ²ðéû€²%ø ²”K—í Óíz“î ¸îÅz1Fgî'zFýîçzîÊúŒüÍøÀþ÷óÿ5ù ßøX²ßí‡Z›øÚ›—ízÓíjshÖízÝøÀr`î¸îFjÓ&î%jî:ˆîj„DzK{I@ö¸2øîÅZ6îj‡îj…î‡z7îgzæîzÆízÆízfî§zýîçzî `D€²èR²“ðû›XSkK "û35Vø+`-[Fôt¯“øÜ 2±dJhd"‘ûòñcJ€³øØ0Ùø šBÝ`Kh`KhÀÿ÷žùBòs(¸¿@B˜B÷ª#Šø0YKˆUK€ÿ÷ºWK“øžq˜F±/ ЈàrxSK hëYh ðáù|à hßøP‘ ðàù(xÐ3xLM+;Ð+DÐ+pÑðGøkjÃc+FiÙëi++Ü þ÷àüAM¹ói hëYh ð»ùsx hë©h ðŸùóiwb3óaNà@ þ÷Èü(çИøŒ1+ãÑóië[h³õ–OÜÙ0K"ÚaØç 6àjx+KÙøëYh ðù +à+i+ Ð+%Ð;»*j%K/aSø2iaëÂ[h«aàëiªi“B ÚjiÙøÑ\ ðYùëi3ëaà*jI2*bQø2 #ëa¹#+aà þ÷|þ#s`Sà¿H D üÿÿ & ÛÉ@0' HôÿÿŒ & ˜( p |  L! OH& HM´ H À& rhK2r`J’ø¡!J±Zx2Ò²!²ûññëRZpð˜ÿJ°`#pJ3aÓr àðÿ³h@öÄÀBÙ þ÷ü þ÷%þ °½ì‹½èðH& L! æ' ê& 8µ)M-í‹Õ튰îh F ð;ÿ°î@аîh ð»ÿ•íšðî@аîI ð-ÿðî@š°îI ð­ÿÔízÔíjgî¨ °î@z`î‡ (îæ fî‡j”ízçî) §îˆ æîˆ ð1øßízŸízK î' €î “íz0î ²îz€î ð8ÿ½ì‹ƒ²D¿õ´s›²²8½ü áDÛI@Ô 8µ(Lßí(z”øE0'Mî:¸îÀ î' ðÛþ+ˆî:øîçz'î€ ðÿ-ˆŸízKîZøîçz€Çî'zK ŸízÇî‡zŸízÃíz´øz0î:øîçzKÇî'zŸízgî‡z”ízÃízßízKgî'z¶îzÇî'zÃízþ÷Qû±½è8@ð¸8½¿H 5úŽ<@ èA$ ˆ& @FaD¬& L=DÛI@°& í ízÐíz î 8µ§î F F§î§ ð7ùµî@ ñîúÐÔízÇî€zÅízÔízÇî€zÅízÔíz‡î€ …í 8½8µ-í ‹‘íŠíªÐíªíš°îH F F ðFþðî@š°îH ðÆþ•íаî@º°îH ð8þðî@аîH ð¸þ•íʰî@аîL ð*þðî@º°îL ðªþkîZ+î©z°îeZ§îHZ¥îÈz î)jkî+z*î‡z(îÀ ðîFjçîˆjªîzæîzk©î'zkîhzjî¦jjî§zêî+jêîzhéîjéî(z½ì ‹Äíj„ízÄíz8½€êàs£ëàs‹BÛ(Ý@pGÐDpG pGðµî -í‹VKßíVzŸíVzVMøîfЇ°hî§ŠÓízñîgzÍízÓízPK³ù0ñîgzÍízî:MKøîçz³ù gîÇzFÍízî*³ù ³ù0øîçz¨Íízî*øîçziFÍízî:øîçzÍízÿ÷Bÿ•øD0Ýíz+Ñ9KZx9Kr¹h@!’ûññQî¸îÇz7î'z½îÇzƒízh@#’ûóóî:¸îæzà-Kˆî:¸îÇzwîÇz*JÍízÒíz(K)L“íŠí 'hxî§zÈî§ŠÝízwîÈz¨î§ŠƒíŠ ð‘ý•ø0ÿ÷dÿí 8D `gh ð†ý•ø0ÿ÷Yÿ°îH 8D``§h ð{ý•ø/ÿ÷NÿKhD`Kh8D2 ``°½ì‹ð½¿ü ½7†55úŽÐ”í Ôíz”íŠÜ  aD ÈB¤  ½7†5|& ô ”& ˆ&  $tI$úÿÿ  Ì ò  & þÿÿÔþÿÿ  à #KhÈë z"I"N #ûðûóðOô–rð²ü3h(` }IJû00`ð¨ü¤—íz0`îJ8î‡zøîçz+hgî‡zŸízgî‡zBòýîçzûööDî oð•–".`ðˆü0(`à#+`ÇíŠ à ½ì‹½èøä ÔþÿÿØ àüæÿ ;-éðA ˆ°ðbøðù(ûЧK¨L¨N" `ý÷$þý÷rý ð,ù ð˜ÿ”ø10`3±ð÷*Ñø0à#ø0„ø1¨ ð'ý ý÷öý±ð[ø ð'ý ð1þOô€ ý÷ëý¨± ð\ù‘KOôBZƒ'MkiƒôCka ?ðGùðÿóÑOôCkƒð4ü ý÷¹ýð“ÿ ý÷ªý¹ ð>ù#J@òÞQ™R3$+øÑ~KJ` puý÷·ý¸±”øŠ1+Øßèð vHð¤þ àtHð”ýàrHðÿàpHðJýOô`ý÷šý±nHðýOô€pý÷’ý±”øŸþ÷)ùOô ý÷‰ý±ðRüeK "Zƒ_JOô€Aƒ'˜FØø0[Mƒð Èø0 ðàøkiƒô€Cka ?ðØøðÿêÑVK "ƒOô€Ckƒð|ûÿ÷¢ùðÜÿOô€pý÷Xý¹#à ý÷Rý(øÐóh3¿# ø 0ý÷Gý¹ ý÷Cýà ðø  ý÷:ýø Oô€ ý÷4ýø ý÷/ý ¹cy]kBkAà#ø 0cyYJBJA³ñCBCAø0´øN1­ø0´øP1­ø0Oô€@Oôzsø ­ø0ý÷ ý ± K³øJ1­ø0½ø0³õúˆ¿#Oô€0ˆ¿­ø0ý÷÷üøOô0ý÷ñü´øŽ1­ø0Kø³øÒ0­ø0¨ ð›øð#øK`cy+ÑKOôÈr€KOôzr€KÈ"€K"Zsðùüç¿( L! À& @ð' P MH@@H 4 œ p | ê& K "ZƒOô€B£ø$OôB£ø$þç@-éðOŒK³ù ³ù0‡°*¸¿RB+¸¿[B$šB¸¿F’%F F'F”¢F&Fßø²›ø0¹›ø0+?Ð.=Ð|K{I³øh!{KH_[_ßøü‘QBë@ð¶úwK™ø 5ùÀë Ìë³ù*0ë ™øÍøÀû ðd#oðQCûóðë‚ð™újKÝøÀiI‚FàX“`DBòrðú›àP™ø0XC›ø0#±aKy ¹.<Ñ_Kßø`±ßøŒ;ùp]Ië 뇙ø0ûóðYKê^€Tø “DOôzRðbú›Høë^+¸¿[B³õ Ü. Ñ»ù0+¸¿[Bd+Ý#Hø0Xø }#’ûóø™ø 0ûøOê¨@Ky²±.Ð›ÝøÝø °Ãõúr ûð{Cû 3Oôúqû “ûñó’ûñòàÛx ±.ÑBF;FàšSF1IßøÔ°hZ0I5ù Àq\%ø ú€ùßøÀ°‘Ìë ßø¼ÀTø ‘Tø ‰D™‰DÍøßø¨Tø Dø ø Ýø°™Dø  û ñOð ‘ûùñR™ßø€ÀûðoðOûññD6D.%ø ññô ¯K¼ø €Z€š€JÒˆÚ€°½èðd' L!  ´ L ðØÿÿê& H €ÁÿÿÄ $( D' t F d @ ( |' -é÷O$%F'F/FNßø@Ñ–ø$0¸ù 3SC[#àAK8ù³øh!@QBðù>Kë^Às³ù* D;JÓxk¹–ø#08ùy3KC:±²|PCë #à3zCC2Jßøä°5ùßøà »ø/I>DÉë òzTø 0–øÀû ðÀû0 û üDø OêìOôÍøÀðOù#KDø áXDø»ø0ÝøÀOöÿr ²ûóóÁë YCßø„KTø Tø Dø  ‰ ë`K>Nˆ#hD=J#`x3Û²p"³ûò÷û7ðÿGÑßøüÙø0Oð“ûøûËë 8FÉø°ðŸüXDÉøûøð€²ð—ÿšø10€c³ßøÌÙø0“ûøúÊë  Éø ð†üPDÉøûøð€²ð ÿK"h`KPCOôzrûòüÓéë AëìqÃéJ# ðÁþK'``J3ˆˆšB6Ó 9à¿ð' H L! þÿÿ( d' ' ê& Ø( ÛI@ì' 4C  D x' m è' ( @~' î' 8( $( à' ˆ 8 *JˆšBÓ û÷“úû÷?û'Kˆ¹&Kˆ+¹ à ü÷Çü(öÐ#KZi‚ð Za à«x±K "Zƒkx±K "ƒð]üKIh hš*Ûh{JX¹pJPiõô#€ð õsPa `à#“pðqûKx[¹Oô`ü÷²ü0±°½ì‹½èðOð5¼°½ì‹½èð¿z' œ p @,   ê& $ KDø‚ð¬¿L! -éðA ü÷‡üßø¤€#O(7Ñ"LFFØø0貘G òî"@òÜS’²šBˆ¿KIˆ¿³øŽ hK@+Ú;cð3ë… K#ø ˆcˆD ˆDàˆD² 5“ûðó-»SññÎÑ2 `½èð$à²Øø0˜G'ø4,öѽèðð' À L! < €P (0µ3JÐ(_Ð(¿1K2K[à2KŸí2zYxÝz1L2HîøîgzîZÇî‡z]}.IøîfjÄízßí,zÆî§jÀíjîZøîfjxÆî§jÁíjîZøîfj{Æî‡jÄíjîZøîfj}Æî§jÀíjîZøîfjÝxÆî§jÁíjîZøîfj†î‡z„íz\{Û}îJ¸îGz‡î'z€ízî:¸îGz KÇî'zÁízà K`0½¿( m=í?H ÈB( X' l' zDÕEMA-éðO-í‹ ƒ°ü÷ªû¦MÀ±•øŠ1+Øßèð ð‘ü àð¶û àð'ýàð2û0¿ à šIšJ hh,ŠFÚ(ðnƒõœC 3`ÿ÷òþOô€@ü÷zû ±‘Kx ¹ÿ÷>üOôpü÷pûO(;ÐNL–øÎ0´ù냑BÝßø,‚˜ø º±µøŽ!:€z€º€¶øÐ ú€–øÏ D냙BÝÿ÷ü#ˆø0}Kˆ2€–øÎ0´ù 냚B ÝxN–ø€¸ñÑÿ÷ü†ø€#ˆ3#€"µøµø’AF¹^›BÄ¿cðÛ²2¡B¸¿Cð@*ñÑiLßøÈ"xšBјø ù*Ø2à"ˆø Oô€@#pü÷ û[NX±µøŽµøL!·ù0ˆƒBÝ D“B ÛOô€@ü÷÷ú(¹·ù µø1šBÛOð àRJ#`S`“`PJ`S`¶øF0#±EKx+@ðë„Oð ¶øF0s±@Kx[¹DK[xC±•ø•1±ÿ÷—ûà¹ñùјø0+@ðÁ€;JSx“Fñ¶øF0#¹#x_+Ñÿ÷‚û•ø”1+ð°€¶øF0+@ð«€#x}+@ð§€ÿ÷rû£à"xW*Ñ/KOôzrOô€p€ü÷œú±ü÷Yý ü÷vú±)K "€ ü÷oúð¹&K€à “ü÷‡ú›¨±JxZ*Ñ!Jx±p"K àKx‚ðpK ±"à"p#x]+ð‚„[+ð„^+ð€„¶øF0k»"xo**Ñÿ÷}û;àL! , @ ’' ð' H p  ê& 8 t L p | Ø( n \ ]  Œ •ø”!±¹#x~+ÍÐ#x—+щKOôÈr€à§+¿#‹ø0#x»+ѳ3à·+ѳ;³… à¾+Ñs3à½+ Ñs;s… Fü÷pù#ˆø0 ü÷úH³uJuKxq±uIIxY±·ùµøˆBÝx¹pHp2$€[|S±nKx*¹nJx¹jJ2!€"àjKx2±eJRx¹pgK"pgH#"0ø¡òT´õÇŒ¿$$œ@ ²"C@òT¡BÌ¿$$ñÿ>úô"C@ò¤d¡BÔ¿!!\¡@3 C +’²ÛÑ#ëCLI°øFB ¿  XT3+ˆFñÑKxFLK¹KK³ù KK“øÎ0냚B Ý ü÷où@±ãxC¹EJ`S`ø¹ ú÷þOô€ ú÷ þ±#HðZý¹ ú÷ þ ú÷õý ±K”øTh˜G ú÷ìý ±K”øSh˜GK ú÷áýKȱ!²d"‘ûòðû²î*øîÇjî øîÇzŸízæî‡z²îzgî‡zÃízà"` ½¿L! ˆ( œ( ¬( È( H Ô ‰ˆˆ<î øîçjßí zŸí z Kfî§j“ø}1Æî‡jî:¸îÇzfî‡züîçzî €²pG¿33S@ðEL! @öäCXCK@öÿr°ûòð³øz!€OôzrPC³øx!ûòðpG¿L! 8µ %$ ðÂüD ðûø=öÑÄóOÿ÷¸ÿ I‘ø~A#"FBÓ3+"DùÑJ‘ø€p›²JXC€‘ø!SCJ€8½¿L! . z' î' 0µ J Hhø1KƒB¿#H`hH@ø!@IPø# h,D$ `0½t H è ¬  pµKMh*hš*!ÛN+`3hL{±ci˜G£h˜G+h"hHID+`£i˜G#3` p½ãh˜G#i˜Gÿ÷»ÿ+hbh D0`+`p½ p½, l x ¬( è ¨ ºK-é÷O[h¹HºI˜G(ðg¸KßøÔ’ˆßø£›F*ð€´L&5F F»ø ²O²õzÑ !#û»Q a9ù»Y D»Q#iî3+øîåz#aÑ#ÄízÄíz£`à”íjî:wîÆj¸îåz†î‡z6îz7îÇjÔíz„ízæî†z„ízÄízÄíz#*)ø0*ø09Ñ#i+ Ý;î:Ôíz¸îÀ ‡î€ àŸíŒ ð–ú‹K“øf1»±î:øîÇz´îç ñîúÝOôzs«ø0#Èø0Èø$0Èø80»`{`;` à»YOôzr3“ûòó !"*ø0ý÷qý5-ññô|¯»ø0;«ø0#9ø:ø Š)ø 3+õÑlOjL8ˆdM(@Ð#FiN5ùÀßøœá°õÈ¿!±P±XaD±P!ë éR3+]N¬øjñæÑ( ÑÞø0ñÈOôÈs’ûóò¦øj!Þø È2’ûóò¦øl!Þø 2’ûóóQJˆ›¦øn1PKY…™…Fú÷…û;ˆ;;€ ú÷ü(iÐJO:ˆ2*ÑIK´øj€´ølY€´øn™€BIDKH‰€Y€à*2Ð#F@H5ùÀ2*¿&FPFXfDFP&ë îR3+0H©øjañéÑ*Ñ5Kp5Kp5K!p/Kˆ øjYˆ øl›ˆ,I øn1'KˆIˆX…™…::€,Jxã±&I#hp2"ûòð¤øjHh‰hûòð‘ûòòI¤øl ˆR¤øn! JFS…“…ú÷û*ˆ´øj1Ó+€jˆ´øl1Ók€ªˆ´øn1Ó«€˜°½èðœ( t& Œ& p „  L! œ   @ H : Ü À È ± n  \ ì 8µJLK’øUhOô€E%ƒ˜GKeƒ"p8½L! @È( Ú pµ:K:Lh"hš*jÛõÃ3 3#`6K7H[h˜G6K7Iš{F’±"h `#4ND"¦øp!F.J2NšZšS1NšS3+ðÑ…s/Kxƒ±(K*Jˆ²øp(€]ˆ²ør²øt!(X€˜ˆ‚š€ h+1Ð"h!H"IÓ#J“BØ"KZi‚ð Za#JÅ^šZ²¥BÄ¿MZSÍ^¥B¼¿LS3+ïÑàJ#`Å^Ì^J,D%D+D”ûõô+¢øpAòÑ Fú÷Mú p½ p½¿, € È( ˜& ê& Œ L! Ô â Ú ÃÉ@µBø@ÑBKOð û0Oðúô°ø†0¿C#ê ø†@½H 8µM+hF!Fhðnÿ+hyT@q8½¿D µFÀ²ÿ÷ëÿÄó ÿ÷çÿÄó@ÿ÷ãÿ ½è@ÿ÷Þ¿µFÀ²ÿ÷ÙÿÄó ½è@ÿ÷Ó¿KhZyQYqD˜ypGD µÿ÷óÿFÿ÷ðÿë €²½µÿ÷óÿFÿ÷ðÿë@½8µF$ Fÿ÷®ÿM ÿ÷«ÿ, L ¿> ! ÿ÷¤ÿ#h"(Fqÿ÷žÿ#h“øF½è8@ÿ÷—¿¿D F ÿ÷Ü¿F ÿ÷Ø¿Khyÿ÷‡¿¿D pµFF Fÿ÷êÿ$ã²BÐ0]ÿ÷wÿ4÷çp½µDø±ÿ÷mÿùç½-éøC'$%KxBÚKJë\ !û#Óø€@F ðýF ¹&FàDàNEÚøÿ÷Jÿ6÷ç5àç$±ø²ÿ÷®ÿ$Ùç½èøƒð ñ dWøµGNGM3hGL+`Oô`##`ú÷Øù ±óhëd#h3#`AMÿ!"(F ðÅü# +pú÷§ù$±#lp«p$ ú÷žùh±#OôPf+Uú÷¶ù ±3K"4šUà4F ú÷ŒùH±*#+U!£Qp"êT4à ú÷~ù(ðÑ ú÷™ù±#+U4Oô€pú÷‘ù(±c "*U "êT4O{yðï*Ð+Ñ #+U4 # f+Uú÷yù±K"šU¦—ø°0Oð¿ t«Uú÷iù± K"U´{y+Ñ*#+U!£Qp"êT4Kpø½¿À& ì ñ L! ð -é÷O%ÀKhB€òp‡¾K¿NL"û33`½Kx ±°½èðOù÷Ú¾ºO;x ±ðÁü3hµLhðþ(ðR‡#hhðþ#h“øI º¹°ñ$bBbAƒøI *çÑ­K[x+ãÑ#(Ñù÷µþÞç©K“øÁ4ƒBÙÑ Õç*ÑM(¿""ð&¿*Ñ<(¿""ð¿* Ñ@(Oðò‡ƒøG ZqƒøHq"ð¿*ÑyƒøFP@q"ð¿*«Ñ“øH“øG ‘ByÙA@qQƒøGD˜qœçB@ðøF0u+ðþ„òi+ð@„ò®€E+ðȆØB+ðˆ† Ø@+ð¨†A+@ðφ ÿ÷jþ$ð­¾C+ðR†D+@ðÆ ÿ÷^þpJ#pð¾¾f+ðb‚Ød+ð9‚e+@𱆠ÿ÷LþjK³ùÿ÷ýýð=ýFðDú D²ÿ÷ôý ú÷[ø€F ú÷WøF ú÷Sø€@êD ú÷MøDꤲDêÀ„² ú÷DøDê²ÿ÷ÕýRJyÓx¤DêCSxC“yDêÃSyDêCSzDêƒLKÙyDêÁzDê$YzDêA$ÑyDê$z’zDêÁ$Dê4Z{DêB4š{Dê‚4|DêDyDêZ|DêBDš|Dê‚DÚ|DêÂD}DêTZ}DêBTš}Û}Dê‚TDêÃT3K xFËág+ð‚h+@ð1†/H‹ão+ð„$Øl+ðƃØj+ð‘ƒk+@ð!† ÿ÷¼ý&K³ùÿ÷mý%K³ùÿ÷hý#KxððѼm+ð¹ƒn+ð¿ƒð¾r+ðK„Øp+ð„q+@ðü…ßøL€˜ø@ðþÿ÷‘ý$ð¼s+ð|„t+@ðê…ÿ÷°ýðé½ì D $ è ê& L! D ’' ð F( ‚' ' l Î+ðÝ„>ØÈ+wÐ'Øx+ðÔ Øv+ðV„w+@ð¹…ÑL xÿ÷SýOð¡Fñã +ð…¤+@ð«…ßøxƒ˜ø€0À²ÿ÷@ý˜øÿ÷Ðü$ð½Ë+JÐØÉ+XÐÊ+@ð“…¿Lñ ràÌ+ð€Í+ð”„ð‡½Ô+ð‚ØÑ+ðF„ØÏ+ðš€Ð+ðz„ðw½Ò+ðã€Ó+@ðq…ÿ÷Ùü®K€Jàð+ðÅ„ ØÖ+ðË€ï+@ðb…ÿ÷Êü§L …ÿ÷Æü`…8àú+ðv„þ+@ðT… ÿ÷ïü$ð¢¼$<à$ÿ÷³üKS4,øÑ ÿ÷ßüþ÷µþð@½ÿ÷›ü—K—LØrÿ÷–ü–Kpÿ÷¦ü `ÿ÷£ü``ÿ÷–ü’K€ÿ÷’ü‘K€‘KxBðp ÿ÷¼üð½ÿ÷zü4`pÿ÷vüàrÿ÷süDE`uóÑíç|KxœBéÒ…Kø€ÿ÷püzKëH4£øFïçÿ÷]üvLàwÿ÷Yü„ø ÿ÷Uü„ø#ÿ÷Qü„ø$ÿ÷Mü„ø%ÿ÷Iü„ø!ÿ÷Eü„ø"Àçÿ÷Jüoô¯aCoLeOÆ+˜¿¤øŽÿ÷?ü¤ø@ÿ÷;ü¤øBÿ÷7ü¤øDÿ÷3ü§øÐÿ÷%ü„øžÿ÷!ü„øŸÿ÷ü„ø ÿ÷ü„ø|ÿ÷ü„ø—ÿ÷üÿ÷üë€@8…ÿ÷ ü„ø}ÿ÷ü„øÿ÷ü„ø~ÿ÷ýû„ø€xç$ÿ÷üMKS4,øÑoçBK[x+ôk¯ÿ÷êûEK(ƒøÀOðˆ¿"Fˆ¿ƒøÀ$ù÷ÄýYç ÿ÷üç ÿ÷§û;KXyÿ÷£û ÿ÷ û9Hðh¼‹B Ò4Jøà"úþ꿚@C3ðçÿ÷œû-K“øÀã ÿ÷ñû-K-Lˆ³õ€o&ÙOð4ù#ûóðñÿ÷–û¸ñóÑ%L´ùÿ÷Žû´ùÿ÷Šû´ù Lÿ÷…û´ùÿ÷û´ùÿ÷}û´ùøã´ùÿ÷vû´ùÿ÷rû´ùÿ÷nûÙçHsá¿ð G ˜( H ð' ê& È' æ' ' 4' l ñ L! ^( À@ ¤& Ä ˜& 0 ç' 8 ÿ÷‡ûºLOð´ù~ÿ÷6û´ù€ÿ÷2û´ù‚ÿ÷.û³K”ø„[y+ÐØ+Ð+ÐQà+!Ð+2ÐLà_úˆó+3Ð+FÑ0à_úˆó+AÑ´ø†0ðà_úˆó+Ð+6Ñ´ø†0šH¿@ðð*à_úˆó+Ñ´ø†0ðà+"Ñ´ø†0ðÐ@ðà_úˆó+Ð+Ñ´ø†0ðà+Ð+ Ñ´ø†0ð¿@ðð¿@ðñÿ÷ªú¸ññ ŒÑtã ÿ÷ ûßøô±Oðÿ÷Óú«ø~ÿ÷Ïú«ø€ÿ÷Ëú«ø‚ÿ÷½ú ð‹ø„0sK“ø¹ñFtÐ!عñhйñ@ðž€'_úˆú;F—PF!FJFÿ÷Xú;F—PF'!F"ÿ÷Pú—PF!FJF;Fÿ÷Iú—|à¹ñmйñ|Ñ_úˆùOð SFÍø HF!F"ÿ÷5ú'SFÍø HF!F"ÿ÷,úSFHF!F"—ÿ÷%úSFHFOð !F"—ÿ÷úHF!F"SFÍø ÿ÷úHF!F"SFÍø ÿ÷ úHF!F"SFÍø ÿ÷úÍø HF!F"SF6à#“_úˆð!F"KF.à'_úˆù;F—HF!F"ÿ÷ëù;F—HF!F"'ÿ÷ãùHF!F"#—ÿ÷Üù—HF!F"#à'_úˆú;F—PF!F"ÿ÷Ìù#“PF!F";Fÿ÷Äùñ¸ñ ñ ô9¯¥â!ÿ÷Nú¡â ÿ÷:ú$K_4ÿ÷êù,øÑ•â ÿ÷.úKLØzÿ÷½ùKxÿ÷¹ù hÿ÷Æù`hÿ÷Ãù K³ùÿ÷Ðù K³ùÿ÷Ëù Kà¿H L! ð' ê& È' æ' ' 4' L ÆL ÿ÷üù´ùÿ÷®ù´ùÿ÷ªùÁK³ù$â ÿ÷íù¿Khÿ÷ù¾Kóç ÿ÷äù¼K!ˆÿ"ðhúÀ²ÿ÷où¹KOöÿrh!ð^ú²ÿ÷‡ùµK³ùÿ÷‚ù³K“ø|!³K2±h +¸¿[BXCàh(¸¿@B!OöÿrðAú²éáªL ÿ÷±ùàÿ÷Bù”ø ÿ÷>ù”ø#ÿ÷:ù”ø$ÿ÷6ù”ø%ÿ÷2ù”ø!ÿ÷.ù”ø"»à ›Lÿ÷“ùñ 4`xÿ÷!ùàzÿ÷ù`}ÿ÷ùDEóÑèá/ ÿ÷ù’Hÿ÷žùáá˜ø0œB€ðÝŽKâ\ŠKëB4³ùFÿ÷$ùïçŠKˆJ#Døz˜BÑÿ÷÷ø 4´õñÑñ™ø0˜E€ð½$èçxLßøè ÿ÷Pù´ùŽÿ÷ù´ù@ÿ÷þø´ùBÿ÷úø´ùDÿ÷öø¸ùÐÿ÷òø”øžÿ÷Ìø”øŸÿ÷Èø”ø ÿ÷Äø”ø|ÿ÷Àø”ø—ÿ÷¼ø ÿ÷¹ø¸ù( #ûóðÿ÷Ôø”ø}ÿ÷®ø”øÿ÷ªø”ø~ÿ÷¦ø”ø€3à ÿ÷ ù$à²4ÿ÷›ø ,ùÑháÿ÷ÄøF ÿ÷þø¹ñÑRKà¹ñÑPKÓø€\hà$ FHFÿ÷€ø@Fÿ÷ø Fÿ÷ŠøIKhÿ÷†ø ÿ÷•ø ÿ÷’ø ÿ÷mø<áÿ÷˜ø€Fÿ÷©ø‚Fÿ÷¦øFÿ÷£øFÿ÷–øÿ÷”øÿ÷ˆø¸ñÑ6KÃøÃø 6K"ƒø€s,?ô÷«1K`ÿ÷ó»¸ñôï«,KÃø Ãø ±*K`(H+K"pù÷ÿÿ÷Þ»&K[x+ôÙ« ù÷çúÿ÷Ô»!K[x+ôÏ« KOôÈr€ÿ÷É»KZx*ôÄ«"šsÿ÷À»K\x,@ðÜ€ F!ù÷ ú Fÿ÷µ»¿´ Ø( ”&  x' ' ä' L! è' H G `Vñ dW„' 8'  & ê& < œ ^K_4þ÷ûÿ,øÑ¦à[L ÿ÷>ø´ù,þ÷ðÿ´ù*kà ÿ÷4øUKhþ÷ÔÿTKhþ÷ÐÿSKh‡à˜ø0œB€ð‰€PK]þ÷´ÿOK]þ÷°ÿNK]þ÷¬ÿMK]þ÷¨ÿ4èç ÿ÷øþ÷ÏÿIL`qù÷=üþ÷Ýÿù÷Oúþ÷Åÿ„øŠþ÷Ëÿ¤øVþ÷Çÿ¤øXþ÷Ãÿ¤øZþ÷¿ÿ¤øxþ÷»ÿ¤øzPà8L þ÷èÿ`yþ÷yÿù÷üþ÷…ÿ”øŠþ÷qÿ´ùVþ÷ÿ´ùXþ÷‹ÿ´ùZþ÷‡ÿ´ùxþ÷ƒÿ´ùzþ÷ÿ,à þ÷Åÿ$$K#D4“ø‚þ÷Qÿ,öÑàþ÷zÿK#D4,ƒø‚öÑà þ÷­ÿ$K]4þ÷;ÿ ,øÑ þ÷Fÿ þ÷Cÿà þ÷Ÿÿþ÷¡ÿ3h"ƒøI ÿ÷¦¸5ÿ÷‹¸°½èð¿D' H è÷ÿì÷ÿð÷ÿØ& ª' Ð' '( L! VˆBÛB¨¿FpGFpG´îà ñîúÔ´îÁ ñîúÈ¿°îA pG°î` pGµAK³øV!-í‹¹ÓøX)tвî*Ÿí;zßí;z³ùX!³ùZ19IøîèŠî*h¸îÈŠÈî§Š p(îŠ î:ˆî'Šøîꪰîh *î‡zÇî'ªð™ü°î@š°îh ðýðî@š°îH ðüðî@аîH ð ý°î@аîj ðü°î@ª°îj ðý î ziîŠzðîGZçîˆZK*î jiî€jÃíZðîFZæîÈZçîzæîHj*î(ª(îÀ iîèšhƒíªƒí ƒíŠÃíZÃíšÃíjÃízÃíн싽¿L! ÛI@4CH ¤ 8µ°ù0"L-í‹î:°ù0”í Ôíz î:¸îÉšøî芰ù0)î î:§î¨ F¸îÈŠÔíz§îˆ ðUü”í Ôíz(€)î §î¨ Ôíz§îˆ ðFü”í Ôízh€)î §î¨ Ôíz§îˆ ð7ü½ì‹¨€8½¿¤ :*0Øßèð"&ˆ €CˆàCˆ €ˆ[BK€ƒˆàˆ[B €CˆöçCˆ[B €ˆòçˆ[B €Cˆ àCˆ €ˆàˆ €CˆàCˆ[B €ˆ[BK€ƒˆ[B‹€Kx¹Fÿ÷|¿pG¿H µK!‘Óø¤!#ðÙøKØ`°]øûL! À& pGpG*K+Jhhµ`)JhY`Qh’hÚ`'J™`haQh’hša%JYahÙaQh’hZb"Jbˆ…QˆY…‘ˆÒˆÚ…J™…ˆ†QˆY†’ˆš†JˆÙ†Qˆ’ˆZ‡J‡x"ŠBÚLëB4ø@„‡2õçJˆ£ød Jˆ£ølQˆ’ˆ£øp J£ønhšfJR‰£ø^ ½¿\ , ¼' ' L' d' Ä ¤&  F( 2 ˜& Ü 0 Ið8º¿+ µF,ÙdðÀ²ÿ÷ñÿä öçಽè@ÿ÷ê¿Cƒêàpÿ÷ë¿pµNLMG ÿ÷Ýÿ0xÿ÷àÿ#h(hÀÿ÷ëÿchhhÀÿ÷æÿ Kˆÿ÷Òÿ Kˆÿ÷Îÿ Kˆÿ÷Êÿ3x#t+h£`khã`p½¿æ' Ø È' ' 4' L 8µFF#Fø ±Iðáù÷çX8½¿+ FIð×¹+ ´µ« Sø+I“ý÷)þ°]øë°pG¿e‡-éøOÂë F › šBMÂë kh3F‰FÑ+h‹BvÒ=Hÿ÷Ãÿ+hFTø#ÿ÷½ÿ<9Hÿ÷¹ÿkh3k`7K"Dpà$à5KxœBTÚ š’±û ó!Ó\™@0KhB Ñkh3k`Õø€ š&OEçÛ5à'Kx!±, ÿ÷@ÿ4à!p+hû òë#¹°Xÿ÷ƒÿDàçCDØx (Ù '°û÷ð00À²ÿ÷&ÿJhë4Êx²û÷ðû#ñ0À²ÿ÷ÿÅç00À²ÿ÷ÿ4¿çÑ ÿ÷ ÿ:h2:`Oðÿ2z`(hHE,¿  ½èø ½èøÌ ¨XŒYì I ð -éðO‹M+x;‹°+ò¢„ßèð-Pg{õO„Nð9úshd3˜B@ò‘„$KJxœB Ú3h}OÐ\0±ÿ÷Êþ;h34;`ïç1hwKR\*@ðz„`Oðÿ2Z`#ðr¼##“sK“ñ ’rH£ñ !3ÿ÷"ÿF(@ða„Oô€pø÷¤þfK0±Oðÿ2`Z`#ðS¼`#ðO¼#dJ“#““cH!ñÿ÷ÿ(@ðA„XKOðÿ2`Z`#ð8¼[J\H#$““”!ñÿ÷êþ(@ð*„MK,p`ð%¼JL#h¹c`##`HKxchD@+¨¿@#+c`@ó„BKh +ò „ßèð^^  $)2:BKVDHÿ÷®þch;OàBHBICJÿ÷¦þch);GàAKAH“øÂ“øÃ$ÿ÷›þch;<à=K>HÙà9K=H³ø@à7K;H³øBÿ÷‰þch;*à8K9HÙhÿ÷þch;"à6K7Hˆÿ÷yþch ;à*K4H“ø}ÿ÷pþch;à&K0H“ø“ø~!ÿ÷eþch;à,K-Hˆÿ÷]þch ;c`#h3#`ªãð2ùFE ÿ÷êý ÿ÷çý Fÿ÷êý"J#`"J`"J`ðù!K`#ã¿ô Ì I h\å\X€^(\8\^±XÍXVäXL! íXH YY Yœ( 2Y@ EYRYbYÈ }YÔ h ü ø ÇKh)@ð´€ÆMÿ÷ýI ,hÿ÷ŠýÃKhÿ÷Œý hÿ÷‰ý`hÿ÷–ý hÿ÷“ýàhÿ÷ý iÿ÷ý`iÿ÷Šý iÿ÷‡ý &·O";h²@BÐë†Sø ÿ÷zý6.ðÑ´ù(°Nÿ÷rý´ù*ÿ÷ný´ù,ÿ÷jý¶ø@1´ù.Àÿ÷Sý;hÙÕ¦Kˆ´ød0ÀÀó ÿ÷Gý;hZÔ;hÕ nÿ÷Ný à´ùlÿ÷Iý´ùnÿ÷Eý´ùpÿ÷Aýëç´ù0ÿ÷<ý´ù2ÿ÷8ý´ù4ÿ÷4ý´ù6ÿ÷0ý´ù8ÿ÷,ý´ù:ÿ÷(ý¶ø@1´ù<Àÿ÷ý&‡KxžB ÚëF6³ù<´ù<0Àÿ÷ýðç;hœÕ+h³ù^ òÜPÿ÷ý+h{J|Ik`«`››KC3!“ûññëA[t!û"*`…âoHøÂ4øÃ$9D±ûòðûšB€ð#‚eNÿ÷ZüP Öøwhÿ÷Æü²h3hhhDshh ëCÿ÷Ñü$ ë;Ph[h4Àÿ÷Çü ,ôÑ# ëú ii¬ŠQ3 +ôÑ"F¡Xñ ?( Øñ(Ø1)Ù+¿#à#2 *ëÑ+˜Ð+Лð›ðCê›ðCà«©Oð àð@ð@ÿ÷pü›ð›BêÀ² àð?@ð€ÿ÷büøÿ÷^üøÿ÷Zü %càSø)ñ€ÿ(OêŠ Ùõ@°õ€?ÒJð àõ²ñ€4¿Jð Jð ‹BäÑjð?À²ÿ÷8ü% ð+`] Ð+Ð+Ñÿ÷,ü`YÀó àÿ÷&ü`YÀó ÿ÷!ü`YÀó@ àÿ÷ü`YÀó ÿ÷ü`YÀó@ÿ÷ü`Y5ÿ÷ ü -Oêª ÐѬç¿h \ Ô ð L! È  5ÂrO»K!h©@B Ы ë;DRø Sø<Àÿ÷ùû5-ëÑ# ë²ù(ú²ù( ŠDø 3+òѪ¨OðRøOêˆ_úƒøi±ñ-ØHðà€1ÿ)”¿HðHð‚BèÑ@Fÿ÷´û%ªF«Fð)Ð)Ð)6Ñ»ñÑbY_ú‚ú‹F-à`Yð@ê ÿ÷™ûOð #à»ñ Ð`YÀó@ê à`Y»ñÑÀó ÿ÷…û`]ÿ÷‚ûàÀó0@ê ÿ÷{û`YÀóÿ÷vûbY_ú‚ú5-O꘻ѻñÑPFÿ÷gûuKhô€Uйød·ød0Ë“%PÕë…# ë°ùlàø°ùlÀëAø3+ñÑ5 Õ ªë…»nÙøh ÓAø<5à%±-јÿ÷Jû$àkë… Rø@À² ±@ð;öÕÿ÷#ûOð Tø+±ÿ÷2û ñ «EöÛâçñ2h2ùrh2ù²h2ù0" D“ûòóÀ4ÿ÷û,êÑ$2hñ[D4²ùrhD²ù²hD"³ù0 D“ûòóÀÿ÷û,æÑ$6KxœBÚ2hñ[D4²ùrhD²ù²hD"³ù0 D“ûòóÀÿ÷âúãç'I hšÕ¹ù^·ù^0Àÿ÷Öúsh2h³`"K"Ir`Ò’JC2!’ûññëARt!û33`Oô€pø÷ªú(NÐðèýKIh‚ŠBFÙLM`"h+hšB ÑbhkhšBÑJh+&ÑKh["ÑH ÿ÷ˆú hÿ÷›ú`hÿ÷˜ú#h+`chk`#à¿ð  5ÂrOø ?B„' Ø h ü JKx*|‘BÑJ™hhˆBÑRhÛhšBÐÿ÷sú Kh2` Kh2 *Ñ"` Kh2`à#+p °½èðæ' Ø È' Ô h ü ðµ`N3x+…°@ð¹€^M•øÂ ±•øÃ ±ˆBÓ#…øÂ4à FF2±“ûòôû4F"F÷çûóð…øÂ‘ûóó…øÃ4«‰OHOIëÃAöi“BÄ¿@òâB“ûòóKJ̿۲#p"ð1ú± 0à$ ,ØhFDIàc,ØhFCI à´õzÒhFAIàBòsœB”¿?I?IhF"Fý÷[ù>HiF"ð6úP±;HiF "ð0úÐñ8¿ 8¹à6K4œBÐÑÌç0pNà!"3H3Oðºü3K3J`ñtè2š`Y`1Kˆ1K$€<`ã²;+&Øßèð!*)Kx B´¿  àhyCXBXAà$K#Dz0¿ à à ø÷mùà ø÷‰ù ±;h"¢@C;`4,ÌÑL##`ð×ü#``3p°ð½ô L! à( ‹YI ŽYžY­Y»YÈY+ Ÿ†Ø ð \ 2 È  H Ì Kx*µ Ù$Hpðpû"F I½è@ðo¹½ô + ‹YµOô ø÷/ùK±"p½p½ô ¹ðù¸ pG¹ðˆ¹ pG ¹FFFðй pG+± ¹FFF𻹠pG¹FFðº pGHpGüBFHðˆ»<@Kµ`Fÿ ÿ÷óÿÿ(Ð#h+÷ѰñÿXBXA½¿ˆ K"ƒÿ ÿ÷à¿@ K"µÿ Zƒÿ÷×ÿOôúpÿ÷ÙÿF¹ÿ÷éÿà$ F½¿@8µF FÕ7 !ÿ÷÷ÿ(6Øð ,ÑDð@ÿ÷µÿ(ÿ÷²ÿÅó@ÿ÷®ÿÅó ÿ÷ªÿè²ÿ÷§ÿd±, ¿‡  àÿ÷¹ÿÿ÷¿ÿ(áÑÿ à• ÿ÷–ÿ ,Ñÿ ÿ÷‘ÿ $ÿ ÿ÷ÿÕ<ðÿöÑ8½8½JÈ#pµF F`Fÿ ÿ÷zÿÿ(Ñ2h*÷Ñàþ( Ñ)Fÿ"£²Hðûÿ ÿ÷iÿÿ ÿ÷fÿ p½ p½ˆ <@µFOôrHðûúÿ ÿ÷Tÿÿ ÿ÷Qÿÿ ÿ÷NÿðCXBXA½<@µ FðÑú#“#ø0#ø0#ø0H#iFø0ð'ù°]øû@÷µÿ÷áÿðúðYûBK"ƒ %ÿ =ÿ÷ÿðÿøÑ(F)Fÿ÷Lÿ(FÐ$\à9NOôzs OôÕq3`ÿ÷>ÿ(3Ñÿ ÿ÷ÿ¯xU5-÷Ñø0+æÑø0ª+âÑ3h¹3h+ÝÐà© Oð€Aÿ÷!ÿ(òÑóç: !ÿ÷ÿ(ÎÑFÿ ÿ÷Üþ8U4,øÑø0ð@ ¿$ $à)F© ÿ÷ÿ(š¿$©%%F3h[¹3h+°Ñ Oôqÿ÷õþ(¿$à(F!ÿ÷íþ(ëÑìç Kpÿ÷Èþ K±xðþà"pxðûpx°ð½¿@ˆ l J KxðûpxpG¿J 8µKxFÚF,ÔKxX¿I, Ñ ÿ÷³þع(FOôqÿ÷ñþÐñ8¿$à ÿ÷¥þh¹(FOôqÿ÷ãþ±<õuõÑ !ÿ÷–þÿ÷vþ ¿ 8½ 8½J l pµ,KFxFÐFLÔxYKÔ(KxX¿v,Ñ 1Fÿ÷tþ±$5àOôúpÿ÷;þ(÷Ðþ ÿ÷0þ(Fÿ÷ÏþÐñ8¿$$àðЗ !Fÿ÷Yþ 1Fÿ÷UþÀ¹Oôúpÿ÷þP±ü ÿ÷þ(Fÿ÷³þ±<õuïÑOôúpÿ÷þ(ÊÐý ÿ÷þÿ÷þ ¿ p½ p½ p½¿J l µrKx FÙñÜ€(òÔ€ßèðÒ@•ÿ÷þÆà !ÿ÷þF±$ÄàhF!ÿ÷Rþ(÷Ðø0øø › +ø 0Ñð? 1ë"‹›]à‰ë’øø ðë"øðëÐðëC2;!àMN3xððÿë± !ÿ÷Õý(¾Ñÿ ÿ÷˜ýhF!ÿ÷þ(µÐ0$ÿ <ÿ÷ýðÿøÑø 0" úó à ÿ÷¸ýF( ÑhF!ÿ÷õý(šÐ1xø ø 0ððÿa±ø ð?Û ëB‰ 39‹@+`Jàð[ ëÁÂó„3û3+`F=à#KxðF?ôp¯ iFÿ÷Tÿ(ôi¯ø0› Ñø 0Zõ`¯•è3xX¿IOð X¿dÿ÷hý(ôQ¯!F! ÿ÷aýF(ôI¯& ÿ÷Zý(ôC¯Gò0Pÿ÷!ýÐñ8¿$à$ÿ÷-ý Fà °p½J l µOô€pðù!LH±#Oô€p#pðùK"`.à ðù ± ðù#$à ðù ± ð ù#à ðüø ± ðù#à ðóø ± ðùø# àOôpðéø(±Oôpðîø##pLò:0!ðÑø x½¿m t ÿ÷²¿KhK@3±KHI"`ðî½pG¿d@ p  d@! ÿ÷濵#“BÐÌ\ÄT3ùç½DBÐøúçpGhµF³±FFø (Ù:(øÑà ½Fø ”BÑ08²*Ø3 `½Oðÿ0½µ€±hs±xb±Ùˆ‚ˆ‘BÑXxÿ÷Füð ¿  ½ ½Ê~‹~(Cê#ÑH} }Bê"CêCFpGøµÅjñ0F9F@x*F#ÿ÷2ü ¹#j qê£išBÓ ø½æx.úÙ£i`xD9F*F#ÿ÷ü>óç ø½y ±ÿ÷Ù¿FpGøµFÿ÷öÿF-RÑ#x+GÑfy.DÑñ08F)FOôrÿ÷zÿU#A"„ø.2ª#„ø/2„ø3 R#„ø""i„ø00„ø10a#„ø20„ø2Âó#„ø"„ø2 „ø"âh„ø2Âó#„ø"„ø2 „ø"âi„ø2r!2„ø„øâb`x9F3Fÿ÷Ãûeq!`x Fÿ÷Æû0¿ ø½Ãj™BpµF FÐÿ÷—ÿFx¹*Fpxñ0#ÿ÷ û(¿Oðÿ5¿$õbà$ Fp½#µqOðÿ3ÃbFÿ÷Úÿ€»”ø.2”ø/"Cê"K²šB(Ñ”øh ”øi0Bêb”øf0C”øg0Bê"K"ðBšBДø„”ø… @ê`”ø‚ C”øƒ @ê ð@À¿ ½ ½ ½¿UªÿÿFAT-éÿA#`FFFÿ÷ÑþÀò_¶KSø'@,ð[4`#xk±`xÿ÷3ûÆÔ-ðRð ¿ Rá#ø²#p`pÿ÷ûÁñE±BñC F!ÿ÷ˆÿ($Ñõùs"xI±™yØy AêayCXyAê!Mø2*ñìÑ&]øP-± F)Fÿ÷hÿ¹ à 6.òÑà%(ð± á”ø< ”ø;0Cê#³õôÑ”øG”øF0Sê Ñ”øV”øW0@ê`”øT0C”øU0@ê ”ø@` as+æpØØ”ø=¡p)ÓÐK BÐÑ”øA0”øB Cê""ÇÑ”øDp”øC0Sê# Ñ”øR0”øSpCêc”øPp;C”øQpCê#”ø?€”ø>pWê(«ÐûüëgD»B¤ÓÛ³ûñó+ŸÐ@öõq‹BÙOöõv³BŒ¿&&à&3ë/D.caåa!b§bÑ*‡Ñ”ø^ ”ø_Bêb”ø\ C”ø]Bê"bb›à*?ôt¯.OêC¿ÒaD¿ðab ¿FëRòÿ°ëS/ÿô`¯Oðÿ3#aã`.Oð€cqXÑ”øa ”ø`0Cê#+PÑ Fiÿ÷Šþ(JÑ”ø.2”ø/"`qCê".K²šB?Ñ”ø2 ”ø30Bêb”ø00C”ø10Bê"&KšB.Ñ”ø"”ø2Bêb”ø2C”ø2Bê"KšBÑ”ø2”ø"Cêc”ø"C”ø"Cê##a”ø2”ø"Cêc”ø"C”ø"Cê#ã`J&pˆ3›²€ã€ à à à(Fà à à °½èð¿| UªÿÿRRaArrAax Ci9;™B=¿‚xƒjû0 pG)øµF F^ÙCi™B[Òx+)Ð+:Ð+TÑëQjëV!ÿ÷úý±Oðÿ0ø½w!jÆó&D FëW!–ø0`ÿ÷êý(îÑÇóFà&5Fci5BÓ.Ø ø½% F)Fÿ÷¸þ0±AåÐ(!еBëÑðç F)FoðpBÿ÷Oÿ¨¹W¹#iå`ZÐ;#acyCðcqà F9F*Fÿ÷=ÿ(íÐà(Fø½(ÁÐ ø½-éøCƈ6³²FF¹ ½èøƒi+ùÐðYÑÁh3ah¹‰žBîÒPà‚x:êKÑÿ÷nþ(FØ ½èøƒBÑ ½èøƒ hCiB4Ó/ÕÐáhÿ÷zÿF(=Ð(éÐCìÐ hÿ÷ÿûF(æÑ h9F00Oôrÿ÷ŠûÔø)FHFÿ÷5þÉø,#hšx—B Ò"q hÿ÷äû(ÌÑ#hÚj2Úb7îçÚj×ßbå` h)Fÿ÷þ a#hæ€OêHñ0CDca ½èøƒ ½èøƒ-éðA x/+FFÐ\+Ñ6%¥`3x+IØ F)Fÿ÷hþea½èð\+@Чi !8F "%ÿ÷:û(F!*F0ëø< +6Ø +Œ¿##-tÐ8xå(¿ 8p)¿’Ò²ð)ð ¿Cð*¿Cðûr F!ÿ÷2þ`³¢iÒz(JÑRoÔaiËzÛLÕ#hxÿ÷;û `3x/+°Fñ¶Ñøç/+ÆÐ\+ÄÐ.+RÐB;ÒÕ€;+Nó\Bðßø¨Àøo–³žBúÑ,à h!iÿ÷ªû(ÌÑbix³±ÑzððÿY¹¥iÑ\3èø ˆBÑ +öÑ ·ç F!ÿ÷ðþ±ç °ç($Ñð¿ ½èð ½èð ½èð£ñA.ØBðà£ña.Ø ;BðÛ²{U5hç)èÑ’ FÒ² !aç½èð¿^Ÿ^µ!Fÿ÷°ýp¹ h!iÿ÷UûH¹cixå+Ð;± F!ÿ÷¬þïç(¿ ½8µFÿ÷ãÿF¹ h!iÿ÷<ûF`¹`i)F "ÿ÷iú "`i¡iÿ÷[ú#h"q(F8½)pµF F$ÙCi™B!ÒciBÒ F)Fÿ÷ ýF¹ p½(ÐAÐ F)F"ÿ÷¤ýh¹#iZÐ3#acyCðcq5Fßç p½ p½µ¨‘@øFÿ÷1úÛ HPø#F ± p˜±!pBø#P±,ѨiF"ÿ÷@ûà à °½| -éðC°F‘F(ð€#`©¨ðÿ÷'û(@ð‹€«¨™ “ÿ÷˜þ œ¹,¿ ððBÐH±(Ѩÿ÷gÿGð œ0±oàãzðjÑsdÔ>8Õþ÷gþÀó#& sãsÝø€ær #t&wfw¦wæw`t˜ø!Fÿ÷÷ù#¦væv&ufuˆø0FÀ±@F1FØø,ÿ÷Oÿ(?ј>Æ`IFÿ÷rúH±7à(5ÑãzØ/Ô±ÕÚ-ÔÝø€;OðØø,0ëaH¿Gð ,b¯qîq˜ø!Fÿ÷Âù(a£âCêc"Cb®`Cê#ë`¸ø0®aÅø€«€0Fà à à à °½èðƒ-éøO™F#Éø0FFFÿ÷ƒù(@ð¯€ày(@ð«€£y™@ñ¦€£hÝB(¿%½±£hÃó*wÑ hø  ñÿ: êS*ðÿ ѹ!iY¹àaiÿ÷ýF(¹£hâh“B}Ùã`{à)ÐJUÐ#iaa¹!a£y[ Õ!F¢iQø$;Xx#þ÷¢ý(DÑ£y#ð@£qÔø°aiXFÿ÷Âû¹ 8à_êU(ë "Лø0›øë šBˆ¿Êë9F2FCFþ÷ý»£i™AE Òñ$ëA!Oôrÿ÷äø£y#ð@£qOêH&&à£i³BТhãhšB Ò›øñ$2F#þ÷Tý± àq½èø¦a hÀóÀõvµB8¿.F D$09F2Fÿ÷ºø£yCð@£q£h3D£`Ùø03D7DÉø0­dç£yCð £q ½èø ½èøCh+7µFÛ]D<-s Ý*F«hñ ÿ÷0ÿ›]¿oð£he`3£`°0½pµFÿ÷¯ø(MÑ£yð ðÿ*FÐ[ Õ!F¢iQø$;Xx#þ÷üü(8Ñ£y#ð@£q háiÿ÷9ùF€»%jëzCð ërãh+w£‰ kw㉫wã{ëw#i«vÃó" +u êvkuþ÷çüÀó#¨uëu +vhv®tît£y#ð £q#h"q h½èp@ÿ÷­¸ p½p½µFÿ÷§ÿ ¹ Fÿ÷Vø¹ `½µ•°F#‘¨F““ÿ÷yÿš*ÚOðÿ0 à˜©kFÿ÷¯þ(õÑ›ššBñј°]øûµKxFò¹ ðâÿðˆø(ûÐ Kh KOôzq²ûññ9Y` Ið ø#!™`!`K²ûóòK`##p½¿„ \ ààíàÀÏj8- µF F!ðù(ùÐ F!ð ù(ùÐ F€!ðù(ùÑ ‰À²½øµFFF$£²»BÒ1](Fÿ÷Üÿ4öçø½-éðAFFF˜F$£²CEÒ(F9Fÿ÷Ëÿ0U4õç½èðpµˆ°%#!F& ø 0ø Pø Pø`ð¸ÿ©OôàSAø=*Hðþ(H !"ð`þ&H !"ð[þ"#H !ðVþOô@!ð´ÿ¨ð‚øOô‚s­øP­øP­ø P­øP­ø0¹­ø@à,Ñ­øP­ø@ à,Ñ­ø@­øPà,Ñ#­ø`­ø0Oôs! H­ø0ðaøHðø©Hð/øH!ðVø°p½¿@<@ ÿ÷¿Kh2`pG¿Œ µ J IhŒhh“BøÑJhhOôzrPC°ûñðû½Œ àà KhpG¿Œ 8µFÿ÷ÜÿFÿ÷Ùÿ@ BúÓ8½µF,±Oôzpÿ÷îÿ<øç½€µ N@òÛ #xCsƒ‡siLƒð sa8F%ÿ÷äÿ%ƒ ÿ÷àÿeƒðç¿@@±KJ`KJÚ`pGüÿ ï¾­Þíàú ð» ðüºJK‘hð )Ð)ÐJàJàPhQhô€Ph¿JJð?²ûñò IIhÁóAÀóˆ1BCI²ûñò`JI’hÂó‰\hÊ@`pG¿8@\ $ôzK OKOôpµÃøˆ MKhBð`"š`h!ð„q!ô€1`HIY`h†°!ô€!`Ú`’’hBô€2`@Khô2’š2’š¹š²õ oñÑhô3¿#“›+ Ð4Kšh"ôš`4JÃø„ hBð€b`0à.KlBð€Rd.JhAô€A`šhš`šhBôBš`šhBô Rš`(JZ`hBð€r`h J‰ûÕ$K@òa`“h#ð“`“hCð“`K›hð +ùÑÁçhüÕLOðc£`ÿ÷Gÿ¨ðæý›J³ûòóJ`KhOôzs²ûóòK:Z`ð"„ø# "š`"`ð†þOô `ð|û°½íà8@0$0Pp@T@<@@B \ ààµÐøä5Fi˜G#„ø1 ½µ#€ø1Ðøä5Ûh˜G ½µÐøà5Ûi±˜G ½µÐøà5j˜G ½µÐøà5[j˜G ½!µ FF@"ð)þ€!@" F#ð#þ#„ø1Ôøä5 x[h˜G ½µiFFð'ùøð+ ÐÓ+Ñ FiFð’úà FiFðKù à FiFðpúà Fð€ðbþ °½pµF)<Ñø1+AÑÐø4!Ðø 1šBÙÁxÒ)Àø4!ÑÐø$ DÀø$1 FÔø$’²ð§ø)àÐø8QµûóöûV^¹B ÓÐø<1BÒ2Fð–øÄøHê .ÀøÀ؆h‘øÀ&@†`†h úüLê†`Fh&êE`yFh@­²5CE`Åh,@Ä`ÍyÄhúò"CÂ`3+ÅѽèðOöÿs`#qCqƒqÃqpGƒpGAƒpGðÉëµ›j!™@$êbjš@Cb½µK˜BÑOô!ð_ùOôàK˜BÑOô€!ðTùOô€ à K˜B ÑOô!ðIùOô!½è@ðB¹½¿T@X@\@ðµ…°F†ˆ2OhF Fð½ø˜*h0K&ð?6°û÷÷6 ú‡üLꦀ!ˆ!ð  šB!€ ØS°ûóó›² ñ +úŒü˜¿#¤ø À"àéˆKöÿs™BÑëB°ûòó›²à#SC°ûóó›²Cô€CÃó  ¹CðOô–rWCOôzr—ûò÷7¿²CôC'„£ƒ#ˆi‰ªˆ›²Cð#€#ˆ#ôc#ð C C›²#€*‰«‰C›²#°ð½@B †Aòˆ3`#ƒ€KöÿrCOô€C€ƒpGˆ±›²Cðà#ð €pGˆ±›²Cô€sà#ô€s €pGˆ±›²Côsà#ôs €pG±Aðàðþ‚pGˆ±›²Cô€cà#ô€c €pGƒˆ›² ±Cà#ê€pGK"pppG¿8@Kšhð *µÐ*ÐKàKàYhZhô€Yh¿KKð?³ûòóJRhÂóBÁóˆ2KCR³ûòó I`‹h JÃóÔ\hã@C`ŒhÄó‚$]#úô„`‰hÁóB1R\Ó@Ã`½8@$ôz Kk ±Cà"êcpG¿8@KZk ±Cà"êXcpG¿8@Kl ±Cà"êdpG¿8@KZl ±Cà"êXdpG¿8@Kj ±Cà"êbpG¿8@KZj ±Cà"êXbpG¿8@C +JÑhà+ ¿oSoð#úððpG¿8@µ#“1 ÿ÷æÿ›3“›³õ oÐ(óÐ1 ÿ÷Úÿ0¿ °]øûKZoBð€rZgpG8@KÚk ±Cà"êØcpG¿,@K[kB ¿  pG¿,@K˜cpG¿,@µK˜B ÑOô€P!ÿ÷›ÿOô€P!½è@ÿ÷”¿K˜BÑOô€@!ÿ÷€ÿOô€@ à K˜B ÑOô@!ÿ÷uÿOô@!½è@ÿ÷n¿½¿0@8@<@ ˆˆµLˆ#CŒˆ#C̈#C ‰#CL‰#CŒ‰#C̉ôAR#CC›²€ƒ‹#ôc ƒƒ Š‚½#€C€ƒ€Ã€CƒÃ#‚pGˆ±›²Cð@à#ð@ €pG€‰€²pGpGˆ±›²CôSà#ôS €pG‰B ¿  pG0µŒ$ð$$ „‹Œ­²%ðó¤²*C$ð BêDð²!Cƒ„0½0µŒ$ð$$ „‹Œ%ô@u¤²-- $ð DðEê"Bê3D꛲Œ²ƒ„0½JˆB›²Ðõ€bBаñ€O Тõ€2BÐõ€bBÐõ€bBÑJˆ#ðpCJBÐõ€bBÐ#ô@s ‰›²C€KhÃb ˆ…K˜BÐõ€c˜BÑ‹z†#ƒ‚pG¿@@Oðÿ3C`#€C€ƒrpGˆ±›²Cðà#ð €pGŒ#ð „pµŒ„ˆ‹ ˆNˆ"ðs *C‰#ð5C­² +CM¨B¤²Ðõ€e¨BÑ͉NŠ#ð+Cˆ#ð+C Š5C$ô@t­²,C„€ƒŠhBc„p½@Œ#ð „Œ‚ˆ0µ‹ ˆ$ôæD$$ #ð Dê$‰ CêMˆCêM¨B’²¤²›²Ðõ€e¨BÑ͉#ð€›²CêOö¿u@‹ˆEê Š"ô@bBê…MŠBê…›²’²‚€Šhƒ‚c„0½¿@Œ#ô€s „Œ‚ˆ0µ„‹ ˆ$ðs$$ #ôs,C‰ Cê#MˆCê#M¨B’²›²Ðõ€e¨BÑ͉#ôc›²Cê#Oöÿ5@‹ˆEê# Š"ô@RBêMŠB꛲’²‚€Šh„ƒÂc„0½¿@Œ#ô€S „Œ0µ„ˆ‚‹ ˆ"ôæB #ôSBê"‰ Cê3MˆCê3 M¨B¤²’²›²Ðõ€e¨BÑ Š$ô€DDê…¤²„€‚ƒŠhd„0½¿@#€C€ƒ€ƒ`ƒÃ‚C‚pG‹#ð CƒpG‹#ôc Cê!‹²ƒpGƒ‹#ð CƒpGƒ‹#ôc Cê!‹²ƒƒpG#"€C€‚€Ã€pG@kpG€kpGÀkpGlpG‹#ð  ƒ‹›²CƒpG‹#ô@c ƒ‹›²Cê!‹²ƒpGƒ‹#ð  ƒƒƒ‹›²CƒpGƒ‹#ô@c ƒƒƒ‹›²Cê!‹²ƒƒpGøµ FˆªˆIˆ+‰F>¹ÿ÷ þ F鈽èø@ÿ÷À¿.Ñÿ÷þ F鈽èø@ÿ÷Á¿.µøÀŒÑ'ô€w?? „†‹Œ¶²­²&ðó%ô eFêEê!›²‰²CAô€q‚ƒ½èø@„aFÿ÷¬¿'ô€W?? „†‹Œ&ô@v%ôU6mm 6 Fê&Eê1Fê3‰²›²Aô€Qƒƒ„½èø@aFÿ÷—¿°øD0)±oêCCoêSC›²àÃó øD0pGƒ‰›² ±Cà#êpGŠ‚‰ê’²ÐB ¿  pGÉC‰²‚pGŠÊˆ›²0µ#ô@S FC‚ ‰«ˆ‚‰ Ci‰’² C"ô°R"ð ›²CƒƒŠª‰›²#ô@sC…°ƒ‚FhFÿ÷üKœBÐõ€cœBÑ›à›¢‰²**hOð´¿R’YC±ûòñd#±ûóò û ‰²(ÚÉ21±ûóóðà 21±ûóóðC’²"°0½@ƒ‰±›²CôSà#ôS ƒpGÁó€pGÁóBµ$ð£BúñÑ 0à+ ¿00h ±Cà#ê`½ˆB ¿  pG #‹@ÛC›²€pG7µ#L“F ð˜û+h<i’К*ôÚšBð’šaJi‘:Ð™ÉøÔ ðû °0½A 0µÄxl¹ë‚3ÐøÐP›"FšBÐQø"(`2øç 0½µ2ÐøÐ@’#“BOêƒÐ hAø#3öçD½"ðµ#‚p)Oð@Ãp‚€ Ñ#p#CpOô sÀ#rÁrOð C àA¹ #p#CpOô cÀ#KÁrõbExaÃ`FF$¬Bñ ñÒõgõ0aeWa41Fðçxõ€bBaëDõˆbÀøÌ õ eõ bFªBñÐÁøŒ 2÷çë4õ€Rõ€TF¢BñÐÁøÌ õ€Röçõ`cÀø 1 ð½¿@8µz+FOðPø /$Ñ“kazeóC ±Cô€“cÓh#ô€#ðPCðoóÃoóÇoóQCoóÓCÓ`ÿ÷+ÿãx+>Ñ#cóDãhEð `6àÓhCð@Ó`ÿ÷ÿ#zbz+¿Oô4Oô< ±Cô€âh “cð´úâh!zÓh)¿Cô€3Ó`#z+Ñk#có›eoó×U-#Eð€UcóEcÈ ðšúãhEôcÈ ð“úãx+Ñãhh"bóDEð ` 8½ÃhšhBðš` pGÃhšh"ðš` pGµ#“›Cð “›aóŠ“Âh›aKi‘;Й‰øÔ ðUú °]øû¿A µ#“›Cð“Âh›aKi‘;Ð™ÉøÔ ð9ú °]øû¿A ÂhµÓh)oó]soóžsÑCðSà ¹Cð€CÓ`2 ð)ú ½ÃhXið€ðpGÃhZi˜i@pGihaó`pGÂhOðÿ1#“aQaÂhQ`QaI‘aÁx™B¿#Côp‘iCô`SCð C“a pG€8µÐø 1"`iFheóÌ"`Ãz+FÑ!ÿ÷Ëÿãh€!Oô€aóYbšbÀ"bóaóEOô rÃøQbóoóEÃøQÃø Q! Fÿ÷Qÿ Fÿ÷nÿ"i#Oðÿ1aSa‘a!iÓabx“BÒëƒ3’ih(¬¿ Oð@` aÿ `ìç#bx“BÒëƒ3Rmh(¬¿ Oð@` aÿ `ìç iCô€s aãx+ÑK@"bóYC c Fÿ÷sÿ 8½¿i›hÃóA+Ð+Ð+Ð pG pG pGiiµœh hÄóA(¿ `ó oó  `ZhBô€rZ` ½0µMx x-OðëƒÑúó¤icóà%úódmcóB#h Ôheó ÍxɈeó“Caó™SCð€SCôC#`iÙi CÚa 0½0µMx x$-"FëƒÑúó‰icóà%úóImcóBioóÏ4 `Ùi!êÚa 0½øµNx F xSi.ëEÑi)h,icó¹fóÜD à–hŸ?·ûööfóÜDÖx.¿fó^t,aÄxx,Ñë…i­ila àÔx,Ð3±i'fkúõ5CecÔx,Ñi¤häT¿AðQAð€Qxë„AðA¤i!`Ñx)6ÑÑhx›²ÿ÷@ý0àNm•h1h4i+¹eó#cóÜD à+D;³ûõócóÜDÃó ]Ceó4aÃx+Ñxëƒ\micaÓx+ÑSy±AðQàAð€QxëƒAðACm` ø½÷µ‘øÀJi¼ñ=Ñ„i#h&i–õ²ÆóGB¹bólóÄøPøpàŽh²BŠ¿fóbóNa">FbóÄøPø`š"aÂx*Ñ xë‚•i ijaCðC#`Ãx+?ÑKi+<Ði xXk!úòCZc3à xëƒ\m#h%i•ï²ÅóFhJ¹"eóbóÄøpø` à:FeóMaø 5F"bóÄøPš"aÂx*Ñ xë‚Tm iba xë‚CðCBm` °ð½Kx+ xëƒ Ñ‚ih+¸¿Cð€CCô`àCmhBô` pGKx+ xÉx냡ñ ¿‚iBmh)oóUS˜¿Cð€S` pGišiØi@ pGëiKm›hPi@pGi˜iÛi@€²pG‚°#“À#ø0"OðbóÄø0#ø0CmšaÂx*Ñõ¹`XahOð€"`°pGƒzc±i›hÛÕÐø 1Ðø !oóAoó`pGµFÿ÷Aü#"„ø1„ø!#FaxŠBñ(Ò!ƒøñ@ !ƒøð £øö ƒøóÃøøÃøüÃø2çç#F"axŠBñ(Ò!@ ƒøH#£øN#ƒøIƒøKÃøPÃøTÃø\2èç Fÿ÷çü Fÿ÷kü F!ÿ÷#ý Fÿ÷dý F½è@ÿ÷ѼpµÍ²ð€ðOð(¿ûûõŒqõ\qä²í pMpŠ`Ëp±Ì€+¿# qÿ÷Ûý p½Ë²ð€ðµOð(¿ûûõŒqõ\qÛ pKpÿ÷ïý ½8µð(%eCõ\uAKa#Ê`‹aKpDUÃx+¿ a¹ÿ÷yþàÿ÷ôý 8½øµð(&fCõŒv'Op„UÊ` a"ŠaKa¹ÿ÷aþàÿ÷Üý ø½Ë²ð€ðµOð(¿ûûõŒqõ\qÛ $Œp pKpÿ÷Àþ ½Ë²ð€ðµOð(¿ûûõŒqõ\q$Û Œp pKpÿ÷½þ F½i#aó h C`pG-é÷OFÿ÷„ü¹ â Fÿ÷…üF(÷ÐÀóÀ@(TÐ Fÿ÷³þ&F€F¡FOð ¸ñHÐð=Ð_úŠû FYFÿ÷¨þFè Õsm%`âxªBÑiÙøx3Âó›Éøˆ3¨Kh FhYF˜Gãx+ ѺñÑ”ø1+Ñ Fÿ÷’þ©Õsm%`jÕsm%`+Õ˜Kh F›h˜Gsm%` ñ OêX6 ñ( ³ç }@ñ¯€ Fÿ÷iþ F‚F&FOð ºñð¢€ðð–€#i_ú‰ûi]kë‹%ú õ’ií’hí² C@èÕZk%ú ñ"êZcØø0`yKh F[hYF˜Gãx«B ѹñÑ”ø1+Ñ Fÿ÷4þiÕØø0%`*ÕØø0%`ëÕØø0%`¨ÕØø0 %`iÕØø0@%`ªÕØø0%`+AÕÖø01Öø,!ÒÖø 1šB8¿Fñ Øø0›iOêœ ›²cE)ÙÖø0QÖø,1B#Ò³Öø !Öø$]•B(¿Fñ Oêœ «² FZFÍøÀÿ÷0úÖø$1+DÆø$1Öø01DÆø0QØø0ÝøÀ›iÒçØø0€%` ñ OêZ ñ(6Yç ½Õãh"Za/Ú£zC±Ôø 1Ôø !oóAoó`#iZh"ðZ`+Kh F›i˜GãhOðBZa 9Õ%Kh F[i˜G#išhãhOôaYa£zƒ±ÒÕÔø 1hBð`hBð`KiBða ;ÕKh FÛh˜Gãh"Za þ7Õãhši"ðšaj(%ðûEÆóCC+õ\uÐ+Ñ Fõ¹a"ÿ÷¾ù«iÆó 3D«aà¿` íàÆó V±2F Féhÿ÷«ùëh3Dë`«iD®aãhšiBðša ý6Õ#iZh%"ðZ` F)Fÿ÷Œú#F*FaxŠBñÒXiÿ!`m2`óç#i&Oðÿ2fóšafóE"ÝaZa/"ahoó ` Fÿ÷ ýãhOô€RZa Kh Fi˜G0F¹Õ Fÿ÷`ûãh FÝhÿ÷Kû(Ñ#£pOôs£€ #à#£p@#£€#có%ãhOôRÝ` Zaú Õ Kh FÛi˜GãhOô€Za » ÕKh Fj˜GãhOôZa °½èð` µL hÿ(ÐKJ›hIh˜Gÿ##` ½¿  $ ° ñ- C# €HpG¤ øµKh*ñÐ`4àN"`3x+.ÐL#h³õoK¿"`!hh‘BÑ#3p àKOŒ¿ÁõbÁë`hÐøì5³ø90BвÙDí!`=`à)D!`!«²9` L!1p"D!ÿ÷:ý ø½¬ ¨ ¸ ´ ¼ ù- 8µ(# Mû K±øˆiF(F˜GÔøì5 F!*F³ø@0ÿ÷ýü 8½¿±- $ pµ xð`F F'Ð -!Ñ͈Jx½± Õ K!I›hF*F˜G0FIâˆý÷eÿàKI`K*F`ý÷vÿ%(àKF›h)F*F˜G!àý÷Åÿ%àKx +Ð +Ð+ÑKˆ !+Ñʈ:*(¿:"0F Ià I"ý÷9ÿà‹x¹K`àý÷¥ÿ(Fp½¿$ ñ-   ° ¶ ¤ µ!Fÿ÷}ü F!ÿ÷yü‚! Fÿ÷uüK[h˜G ½$ 8µÐøì5F³ø9 !#ÿ÷CüÔøì5 F³ø@ !#ÿ÷:ü‚! F"#ÿ÷4ü K"%q]qKh˜GÔøì5J³ø@0 F!ÿ÷\ü(F8½` $ ±- pµKx*ÑM)h ¹pàÐøì5 L³ø90&h™B²²ÙD&`Éà‹²1D!`!L)`"D!ÿ÷Mü p½¿¨ ¼ ¸ ù- þçµ# J I˜ˆBÒ IYX™P3õç H IOðˆB¸¿@ø+ÿöú¯ý÷Äü½è@ö÷¸º ü Üf 87 pGKˆ€²pGÀ -éðA ˆ°9L:NFþ÷Qû! F Fþ÷ú F!"þ÷üù" F!þ÷÷ù%à#' F©“$Oô€Xøpø pø Pø Pþ÷—ù0F©Íø€ø@ø pø Pø @þ÷‰ù0FAFþ÷Îù0F©”þ÷€ù!F0F¦õ`Fþ÷Ãù0Fþ÷§û@F!Fþ÷/ûOô‚s­ø0Oôs­ø0(#­ø00F#©­ø0­ø P­øP­øp­ø@­øPþ÷¹û0F)Fþ÷ñû0F!Fþ÷Üû F°½èð¿@@8µ'MF!(Fþ÷Ìû+ˆ,›²,Ð Ø,Ð,!Ð,6Ñ#ð8›²2à@,%ÐØ ,-Ñ#ð8›²Cð 'à€, дõ€"Ñ#ð8›²Cð8à#ð8›²Cðà#ð8›²Cðà#ð8›²Cð à#ð8›²Cð(à#ð8›²Cð0H!€½è8@þ÷ƒ»0@Kˆ2’²€Oðÿ0pGÈ 8µF@òé4H!þ÷Œû ¹<¤²,öÑà H)Fþ÷tû@òé4H!þ÷|û0¹<¤²,öÑÿ÷×ÿàHþ÷`ûÀ²8½¿0@Kˆ€²pGÈ K"€pGÈ -éðC °Fþ÷Gú !þ÷Cú !þ÷?úUO !þ÷:ú !þ÷6ú"8F !þ÷æø¨$þ÷Õø%&Oô€h8F©Íø€ø@ø Pø `ø @þ÷ƒø©CHÍø€ø@ø Pø `ø @þ÷uø§ø€ßøô€@F§õ@gþ÷œú(F!Fþ÷ú8F !"þ÷°ø8F!"þ÷«ø"8F!þ÷¦øOôS8F©“Oô€IøPøPø`ø@þ÷Hø8F©ÍøøPøPø@ø`þ÷:øOôC©8F“ø Pø!Pø"`ø#@þ÷+ø@Fþ÷XúHF!Fþ÷ÔùOô‚s­ø&0Oôs­ø.0(#­ø00@F# ©­ø40­ø$`­ø(`­ø*P­ø,@­ø2`þ÷jú@F1Fþ÷¢ú@F!Fþ÷ú°½èðƒ¿@ @8@8µ'MF!(Fþ÷|ú+ˆ,›²,Ð Ø,Ð,!Ð,6Ñ#ð8›²2à@,%ÐØ ,-Ñ#ð8›²Cð 'à€, дõ€"Ñ#ð8›²Cð8à#ð8›²Cðà#ð8›²Cðà#ð8›²Cð à#ð8›²Cð(à#ð8›²Cð0H!€½è8@þ÷3º8@Kˆ2’²€Oðÿ0pGÊ 8µF@òõH!þ÷<ú ¹<¤²,öÑà H)Fþ÷$ú@òõH!þ÷,ú0¹<¤²,öÑÿ÷×ÿàHþ÷úÀ²8½¿8@-éðAF FF~³±•ø€5àOðÿ@òõH!þ÷ ú ¹?¿²/öÑàHAFþ÷ñù@òõ H!þ÷ùù@¹?¿²/öÑÿ÷¤ÿÀ²½èðHþ÷ÛùÀ² ± p4>Îç ½èð¿8@Kˆ€²pGÊ K"€pGÊ KSø 0hŠ¡õzqKCOôzp“ûðó`pG” KSø 0h`pG” KSø Bhˆ#ð µ€ƒh$€h`ˆ›²Cð€½” (K ØJˆŠBÒ"úðxCpx+ ÑK"pKˆ²(Ý9€pG€pG¿Å  p JHˆµ€É€‰²@öŒ#™B LÙ#à¡òï"’²@òÚSšBØ x(ØK#øÿ÷¾ÿ#x3#p½Š Æ d Ì -éðOOêßø\±TO[ø @‹°& ë ˆFFC! F“’þ÷ÄùBF F™ð\ûÙø0Ùø“"#© ñOð è ø0ø øøý÷zþ¨˜ø€þ÷¡ú›­ø0›“Oô€s­ø$08Kšx­ø p!+ë­ø­ø ¿Oð Oð ¸ñ +Øßèð*********" F©þ÷„ù FIFþ÷|úà F©þ÷³ù FIFþ÷{úà F©þ÷îù FIFþ÷|úà F©þ÷'ú FIFþ÷{ú ë ›{± F!þ÷û F!þ÷Lùñ$l`«`¸ñ Øßèð  ñ4àñ8àñ<àñ@»Q›ì`(F+‚ °½èðÜ Ä Ì_µKxƒBÙKh˜G½¿ˆ  KxƒBÙKSø 0h`pG h K3øpGÌ µF¨ FFþ÷'ú#­ø0 F#©­øP­ø`­ø 0­ø 0þ÷Wú°p½øµFHM"ûñ“øÀF4¼ñÑ"™€Úp+(Y{"à˜ˆÙ€ ‰²¡òï ƒ€²@òÚRBؘx K#øÿ÷–þ ûv+6"(Y{òp½èø@ÿ÷¯¿¿Ü Ì_Ì -é÷Oßøl€KOê ë&û6£h“#F‹F²t`hø0Oð #'iFø0ø øpý÷ZýYø!{RFÿ÷€ÿ F:FOöÿqðJú F)FZFðóù0F°½èð¿Ü Ì_tK‚|-éðApsKÂ|pF! ý÷ïþ !ý÷ßþOô€0!ý÷æþkH !"ý÷rýiH !"ý÷mýfH !"ý÷hýdH!"ý÷cýaH!"ý÷^ý_H!"ý÷Yý]H!"ý÷Tý[H !"ý÷Oý! FXHý÷JýWH!"ý÷EýTH!"ý÷@ýSH!"ý÷;ýPH!"ý÷6ý"MH!ý÷1ýcy"Š+KK€£ybx¿OðOð+¿##±3DJRø#p%z]yÿ*ðððIxÑ?K?J`"‰²õú`Ù=Jaàby± (¿€#"y±ê¿€#ÞÕ"6Iÿ÷/ÿ6K"pEà™Õ3N3I2xÿ÷$ÿ3x33p:àZ&Õ#‰³õúØâ|* ¿!!à!¢|*±ÁëAë‚’à&Jæ|JC±Oôzc²ûóò#Kxñƒøà’²£‰ÿ÷ÉýKàÕKxrpc‰J’ûóò!㉒²ÿ÷¸ýKCø&5-Ñ—ç¢| ±J`½èð¿Ä Œ @@@@ `_ eÚEÚíÚÈ %Ý@Bˆ ”  h uÚµhh˜G½8µF Fø±(Fÿ÷òÿøç8½µh[h˜G½µh›h˜G½µhÛh˜G½µhi˜G½µ"Ô² KSø$0ƒBñ÷Ñ"Ó²H0øˆBñ÷ÑëƒàÀ²½¬`À`pµF&4K]­¹ F!þ÷ñø([Ñ F!þ÷öø)F Fÿ÷Ðÿ,K%û5 Fþ÷5øFà-Ñ F)Fþ÷Ùø(CÑ F)Fþ÷Þø)F Fÿ÷¸ÿ K%û5 Fþ÷ø.à-Ñ F)Fþ÷Áø(+Ñ F)Fþ÷Æø)F Fÿ÷ ÿK%û5 Fþ÷ øà -Ñ F!þ÷©ø(Ñ F!þ÷®ø)F Fÿ÷ˆÿK%û5 Fý÷óÿ«h² ±({˜G6.—Ñp½À`Ì pµ FFFÿ÷nÿ(ØK"û0†`qsp½Ì )Øßèð   !à!à!à!"þ÷[¸pG8µF FF!{h*Fÿ÷Ïÿ h!{½è8@ÿ÷Û¿µ#ø¨ø0ø0ø0ý÷Jú°]øûµF¨FFý÷SþJKUCh>´ñ€O–²ûõòÐIŒBÑR:#­ø ø0à:­ø # F©­ø 0­ø0ý÷óý°p½¿@B\ @µFhÿ÷Éÿ h!ý÷(þ`{½è@ÿ÷¯¿Hÿ÷¿¿@Oð€@ÿ÷þ¾Hÿ÷û¾¿@Hÿ÷õ¾¿@Hÿ÷﾿@@µFkF!" ð:þø ø0øCê#²î:Køîçz“ízgî‡z“ízýîçz¨î*­ø ø Bê"²î*øîçzøgî‡z“ízýîçzî*­ø ø Bê"²î*øîçz!Fgî‡zýîçzî:­ø 0Kxú÷Îø°½ ¬ -éÿA±^KpOô€S$©­ø0[Hø@#ø0ðoü2 ü÷åü!F" ðÉý!`" ðÄýd ü÷Øü¨ÿ÷†ÿ %'F&F!" ð¶ý2 ü÷Êü¨ÿ÷xÿ½ù ½ù ½ù 0D‘B¸¿ FDšB¸¿Fõ€_D Ý>KZi=‚ô€BZaÛÑOðàOð !"ðý %!" ð‡ý2 ü÷›ü¨ÿ÷Iÿ½ù ½ù ½ù 0¤‘B¸¿ FöšB¸¿Fõ€_ÁëÝ&KZi=‚ô€BZaÚÑàOðîJßí!z!M¸îæzîz‡î‡z!p" °îÇz…íz¸îæzÇî‡zîjðîçzÅízøîÇzŸízÇî'zðîçzÅízð<ý! " ð7ý !"ð2ýd ü÷Fü¸ñÑOð~S+`k`«`°½èð¬ @ @@oF À^F7µ«$FøM !"ðýP±ø0H+ÑK+`Kk` à F°0½¿ãåâ±KppG® KOô€R€±KppG@ ­ pµF†°>H FOô€aý÷Ìùº ÿ÷äùøÿ ÿ÷ßùOô€aø 5Hý÷»ù ü÷Ùûø 0ÛÔ [àOô€a.Hý÷¯ù» ÿ÷Çù!"¨ÿ÷êùOô€aF'Hý÷Ÿù,èÑø0ø øCê"²#’ûóò­ø ø Bê"²’ûóòø­ø ø Bê"²’ûóó­ø0KhFx1Fù÷nÿø ø 0Cê#­ø0ø ø 0Cê#­ø0ø ø 0Cê#­ø0KhF)Fxù÷Pÿ F°p½¿@® ­ pµFF Fÿ÷Îù,ÐØ,Ð ,Ð\¹à¼,дõ€Ðb,Ñ$ à$à$à$à$à$à$Oô€a\Hý÷'ùk ÿ÷?ù€ ÿ÷<ùOô€aVHý÷ù– ü÷CûOô€aRHý÷ùh ÿ÷,ù ÿ÷)ùOô€aMHý÷ù– ü÷0ûOô€aIHý÷ùk ÿ÷ù ÿ÷ùOô€aCHý÷ôø ü÷ûOô€a?Hý÷îøl ÿ÷ù ÿ÷ùOô€a:Hý÷áø ü÷ÿúOô€a6Hý÷Ûøj ÿ÷óø ÿ÷ðøOô€a0Hý÷Îø ü÷ìúOô€a,Hý÷Èø ÿ÷àø ÿ÷ÝøOô€a'Hý÷»ø ü÷ÙúOô€a#Hý÷µø ÿ÷Íø ÿ÷ÊøOô€aHý÷¨ø ü÷ÆúOô€aHý÷¢ø ÿ÷ºø Fÿ÷·øOô€aHý÷•ø ü÷³úOô€aHý÷ø ÿ÷§ø ÿ÷¤øOô€a Hý÷‚ø ü÷ ú ÿ÷=øK3`#s`K+`Kk`Kë` p½¿@måaå…åD’1-éðOQKˆQKŒFhQKˆûEâ BêEb´OðOêåGëJK‰°ÍéEˆIKˆûEÖ" Bêbë Oê%#OðGë BKÓø€¸õúoÍé«QÚ¨õúb‚û#&¢ûEûUkOê4Íé#¢7LIC EOêáqBê…rOê¥#ÚòÜT„ûEOð ¤û g ûyÍégÍø Ýé«ÝégOð ë Kë ¤û g ûwOê6Íé«’CëLÁëÝé«Ýég!`ÝéE¶gëºë kë Íé«ÍégKŸhÝø ¢ûEû Ub BêÅ"kÝéEcëÔ DêCD±`¼ñÐKhÌø0 °½èðþ5 6 6 6 6 6 $úÿÿ6 8µ M L!(Fü÷ªÿ þ÷rþ þ÷oþ p þ÷kþ`p þ÷gþ! p(F½è8@ü÷“¿@6 µL! Fü÷‹ÿX þ÷Sþ F!½è@ü÷€¿¿@µL! Fü÷yÿH þ÷Aþ F!½è@ü÷n¿¿@ K Jˆh¢ë"K`Kˆ‚û#Ð @êC Kõú``pG 6 6 6 ü5 6 8µML!(Fü÷Hÿ þ÷þ þ÷ þ p þ÷ þ`p þ÷þ! p(Fü÷3ÿ½è8@ÿ÷Ä¿@6 8µFþ÷"þ!`H`Mü÷$ÿ þ÷ìý ü÷Hù!ZHü÷ÿ– ü÷Aù!WHü÷ÿ¢ þ÷Ûý þ÷Øýhp þ÷Ôý!(pOHQMü÷ÿ ü÷ù!KHü÷üþ¤ þ÷Äý þ÷Áýhp þ÷½ý!(pDHFMü÷êþ ü÷ù!@Hü÷åþ¦ þ÷­ý þ÷ªýhp þ÷¦ý!(p8H-W@°¦¾9ÑÀ«ª*>h!¢3ÚÉ?h!¢³ÚI@î*"ðA±ñÿO8µðî@zÜîJ$ð@°ñÿOܲñ~_FЕðEêÔuh¹-;Пí? -¿°îg 8½î*7î' 8½³±ñÿO2аñÿOÐAÉ<)!Ü*IÛî*‡î‡ ðúð;ù-8Ð--Ð-@Пí-zßí-z0î 0îg 8½ßí*zŸí* ,¨¿°îg 8½Ÿí& äçŸí# 8½½è8@ð¹°ñÿO"Ð-óÐ-+ÐßízŸí -¿°îg 8½Ÿízßíz0î 7îÀ 8½î:ñCî:8½<1³ÚŸí ¸ç8½-Ð- ÐßízŸí -¿°îg 8½Ÿí 8½Ÿí 8½Ÿí 8½¿ÛIÀ.½»3ÛI@ÛÉ?ÛÉ¿€ÛI?ÛI¿äËÀäË@-éðGîZ5ðG-í‹îJîjÐ&ðH¸ñÿOîšݽì‹PH½èðGðº·ñÿOݸñ~_òÑ·î ½ì‹½èð‡.QÛOð ·ñÿOCзñ~_\дñ€Ohдñ|_îjÐðcù¸ñ Ð)ð@C³ñ~_ÐOêÙs;ZêfзñšOsÝ6JEóÌ,ÀòÏŸí4 Ìç¹ñß۽싽èðGðË»,¼¿÷îz‡î€ ¹ñºÚ¨ñ~XZê;Ñ0î@ €î °ç¸ñ~_«ÐÝ,ÚÛîZ§ç·ñ—OÚ·ñ~_ ÛûÃñ–Gúòúó»Bð‡Oð Ÿç,ÛîjçOð ”ç,ºÚîZ±îB …çîj&î €çîj·î €î% yçºñôv¯±î@ rçîj2îB €î k翬a÷ÿ?€K¸õ€òV_íz`î'zoðîŠìJOêèVÈó>EDHð~Q@ó?çJE@ó” 6¡õFßøüƒŸíãjŸíã:ßíã:ŸíãJŸíãZßíãJßøäÃâOßíâ Ÿíâßíâ*’Dî˜ízwî‡j·î*‚î&*IAðQõ€!DwîÇZîeî‚j1îÇzî 7îÇ &î¦z ô`§î: ð ëî ãî::D±îgj£î‡Jæî!Z¤îZæîZåîJeî‚:vî§Z'îzeî£Z°îZçî$Z°îEz§î§zÒíJ‘í:7î%zîjî ô` ðî*7îEZ¸îÂJ¦î'ZuîÅZeî¦jãî‡j°îf*§î‡*î ô` ðî*¦î*î*vîÂjfî jçîjvîƒj°îfz§î¢z7î$z7îzî*"ôb"ðî*5îÄz7îdz§îâzvîÇz$ôd$ðîZîJî*vîGjfî'z"îzæî‚z ñÿ:Zê ·îŠwî‡j¿îjî:¿°îFŠ+#ðB@󪀲ñ†O{Üoвñ|_~Ü"F#ôc#ðî:Ÿí}jŸí}*ßí}:ßí}*Ÿí}Jßí}JŸí}Zßí}Z6îÇz&î†jwîÇz°î:§î‚j·î ðîFzæî£z'î§z°îg*§î"J¦îã*äîJvîBj¤î‡Z°îgjåîZçî¦j¥îÇj°îFz7îCz'î†j†îzwîfjvîçz0îg î:D³õÀò–€î:(î æðÂñ æ FÆæ!¯æXJETÝ,÷1®ŸíV î ûåŸíUjvîÇj7î†j´îæjñîúÝßíNz(î' î' éåÒOô~:AúòDÂóÇQHM¡ñEúôÂó"êî*7îezÁñ–@ôA+7î‡j¸¿@BÂî:^çU2l>£‹>«ªª>·mÛ>š™?¸aO8v? Ã68v?Œ¾¿5r1?r1?L»13êݵU³Š8a 6»«ª*>€?ÊòIq<ª83ÿÿC`B¢ ;ª¸?p¥ì6ª¸?ÈaÀapµî:“J#ðD”B†°îjFfÝJ”BÜ+ßíŽzŽJ$ð@óÛ€”BpîgzfПí‹zwîÇj wîæzÅíj7îÇz…íz°p½„J”BfÝ´ñÿOIÚâ†:¤ëÂTîJýîÇzßí~jøîçz7îgzÍíz'î&zýîÇzøîçz7îgzÍíz'î&zµî@zñîúíz@ð±€õî@zñîú ¿##nI è¨)Fð·ù.Ú•ízÕíz±îGzñîgz@B…ízÅízà"…í B` °p½pî@z ÅízÅízõçßí[jŸí[zwîæz wîÇjwîæzÅíj7îÇz…ízãçð$þßíSjßíJZßíKz¶îz î&z½îÇzøîÇjî ±îfj(¦î% fî§zÜHKA$ðÿSø!0šBÐ0îgz…íz0îG .pîgzÅízµÚ±îGzñîgz…ízÅíz@B«ç0îgzäî*ÂóÇSã+áÝŸí1zŸí1Zðî@ZæîZpîezæîzÖî…z5îçzî*ÂóÇSä,,Ü…íz°îe Çç”Bpî'zПízwî‡jOðÿ0wîæzÅíj7î‡z…ízrç#SçßíjŸízwî¦zOðÿ0wî‡jwîæzÅíj7î‡z…íz]çŸízŸíZ°îe ¦î uîÀzæîzÖî…zŒç¿ØI?ãË@€É?ÐÉ?CD57€IC€CPbD57£….„ù"?Ða£….21$î:#ðB²ñÿOp´0Òj³+=Û²õOêãQ,Ó¡ñÃóÑCôH¿[%V[,F!Oð€r ˜BÜ„D9OêCOêRóѱðDmñ|UëÆUîZp¼pG î p¼pGô Ñ[ñúÕÂñDÆç0î@ €î èç"D¾ç¿î:#ðC³ñH_,ÚýîÀzî:+`Ð`îzßí1JŸí1Zßí1ZŸí1jßí1jŸí1z§î¤Zåî'Z¥î§jæî'j¦î§z'î'z îÀ öîj§î‡ ·îz—î¦ 7î@ pG`îzßíJŸíZßíZŸíjßíjŸízJ§î¤Z“Båî'Z¥î§jæî'j¦î§z'î'zÕÝJ“BÜñCî:÷îZuîæZ`îÀ ¶îjçî‡ ×î†jvîà 5îà pGöîZõîjíç·î pG¿N×G­öt1|ò“´ Ð7a ¶º«ª*=™™™>H?-éðO-í‹×°¥Ld‘ñÿ9Tø%€FÓH¿Û#êãs“žÛCëÂFë“ÉëÔežD0©ëƒ"+ª¿¦Xßí”zîjñ¨¿øîÇzƒBáìzñíѸñOêˆ Û¨C®ë…^DB¨¹ñÀò®ßí…zQF"F#ñìj2íz3«Bæî‡zöÑàìz°BñçÑ ñ DFÍø€ßízŠŸíxŠÝø€ãD¦V«3D,í ݬñBª2D1D«`î(z°î@zýîçzríjøîçz§îÈz7î¦ ½îÇzî Cø‹BéÑ@FÍøÀð•ü°î@š´î )î ðüòîz îgš¸ñÝøÀýîÉšøîéz9îgš@ó¡€aÈñ\ø!0CúòúðLø!0îÈñDCúð î›+-Ýî*,ñ î*@ó@cF ë!Sø+Âñÿ¹Âõ€p±Cø !»BòѸñ ݸñð¸ñÑb\ø"0ð?Lø"0›+iеî@šñîúxÑ™g¹B ÜfD#Vø-^ECêùÑ+@ð±šS\ø# *@ð§ ëƒOðSø-ñ*ùЦDfvE.ܘŸ Deœ ë©ë€ëƒe›wDBªë†ë‡Pøîøîçz¹ñäìzßíz ÛQF"F#ñìj2íz3«Bæî‡zöѸBæìzâÑtFç@ð¡€c\ø#0“lçhe€C€;·î 0îIš)Ð@FÍøÀðÁû9î@šÝøÀµî@šñîú†Ð›ÍøÀ°îI XBÝø€ð®û_ízÝøÀ´îç ñîúÀòTízš îzg½îÇz2¸îÇz’§îg ½îÇz½îÀ î:Lø$0îJLø'@˜ÍøÀ·î ðƒû/ÝøÀ6Û}ªB®í*z ë2DsízøîçzcEgî€z î bízóÑB¨ë‡ ¸ñÀòé€Ißíz"F#àƒBÜñìj²ìz3˜Eæî‡zôÚV©ë€0…B¤ñCí(zàÑdœ,Øßè𳇇*b\ø"0ðLø"0ÿæöîz´îçšñîú Ú"’øæßíwzàìz°BñôE®[æî*!2,‘ î*?÷À®!Îæ/@ó¹€¹V«z.® Dë‚Sí(z/¨FSíj6î§zvîÇjvî§jðîGzcíjƒBízïÑ/@ó›€V¨DQí(zF0©Síj6î§zvîÇjvî§jðîGzcíj‹BízïÑßíPzF3íz™Bwî‡zùÑœ,}ÐÝí.jí/zžñîgzñîfj±îGzÆízÆíj†ízîðW°½ì‹½èð/tÛ.ª{ßí;zëƒ3íz“Bwî‡zùÑ𢳱îgzÝí.j›/ƒízvîçzÝ/«ë‡³ìz»Bwî‡zùÑœ ±ñîgzÅízÊç/EÛ{.ªßí%zëƒ3íz“Bwî‡zùÑž±ñîgz™Áíz´çßíz$ç°îgzÉçOð_æš\ø'0Ýø€:’+ôÝ® ë‡Sø?:)ùÐ’Òæœßí z,Ñ.š/›Åíz*`k`Šç½îÀ 'FîZLø$P½æßízÂçßíz“çteî:#ðC³ñH_ÚýîÀzî:#³`îzŸíZŸíjßíjŸízßíZ§î…j'î€Zæî'j¦î§zçî'Zp±eîÅZ¶îzàî‡ZŸí zÕî§ åî 0î` pGŸí z§î¥z§î pG¿ÓÉ./4/ײï86 P¹‰ˆ<«ª*>«ª*¾ pGŸí pG¿øðµSì+Ãó P òÿ1)ƒ°œFîzOêÓv1Ü)OÛ=HAêC'Ð@êC ÐOô€,)#êLúñ@ê ¿'OðG2KëÆI?J›D6î‡z‘íZ—î'ZD-“í uîgz0îg $Û8½0î 8½ßí5jpî&j·îzôîÇjñîú©Ý8½ðcø/KœBÜ£õМB*Üðîz¿îz î'z#pî'zÇî'z•ç±î@ 8½6î‡z°îg §îg 8½!KœB Ü÷îz·îz î'z#pîgzÇî‡z|çÿîzÇî€z#vç·îzpîGz0îz#Çî‡zlç¿ÛÉ?ÛÉ¿ÿÿß>×i…8Žã½«ªª>ÍÌL¾°eÀeÊòIqÿÿ—?ÿÿ@î*"ðCî:pG¿î:#ð@°ñÿO¬¿  pGî:#ð@Á 9)´Ü)F"ÛHABÐßízpî'zõîÀzñîú Ý+!Û$êî ]øKpG°ñÿOÒî:]øKpG0î ]øKpGßízpî'zõîÀzñîúìÝ+ÛŸí éçOôCúñ D×ç(¿î ¿î:ÜçÿÿÊòIqî:3ð@Ñ pG õ³ñþOÒ pGKBšBØ pG°ñÿCXBXApG¿þÿŸí pG¿Àµî:3ðA-í‹î*бñÿOÒ±õÓÉ Dþ)0Ü)Ý"ðÿBBêÁRî*½ì‹½½ì‹0î ½ßízJ î'zBî:"ÛÃóÇQî*9ÝçñÚLòP2B ÜŸíŠî:°îH ð*ø î ÖçŸíŠî:°îH ðø î ËçŸí 'î Æç1"ðÿBBêÁRßízî*'î' ºç¿L°<ÿÿ`B¢ ÊòIq3î!ðBîðCCî:pG! "ðй-éðN‚F‹FFF¹ ½èðŽ+úÐ&¦B÷Ò¥mû¹PFIF›˜G(ÛÐn%F,FîçHF½èðŽKhpG¿ø µ#“BÐÌ\ÄT3ùç½DF“BÐøúçpGµF"F4x+úÑÌ\ÔT3,úѽɲFø;±‹BùÑFpG)ûÐFpGFø+*ûÑ8pGKðµh#“BÐÅ\tdxð,Ì\ë¿ 5xð/¿ 4-Ñ3,çÑà%(Fð½” µF2±øKøK:,÷ÑD“BÐ!øùç½0µx ±Fà x+¿ 0½"F4x8±#È\(±Õ\…BõÑ3øç0½F0½K-éðAh¬mFFü¹P ðãø¨e„`«m`D`aÜ`«mœa\a«mÜbœb«m\cc«mÜcœc«m\dd«mÜdœd«mw«m\b0F9Fªm#½èðAð¸ø ðµ¹h(³FFø[øk>±µBúÑ ± Fóç`pð½M¹`(Fð½øk®BÐ.ùÑF#FFø[óç±!!pà+F`ð½ð½„F?H-éðOÐø€F4Fø[ë@xððÿ±&Fòç--Ñ´ux'à+-¿ux´3ð Ñ0-Ñ xðßX(QÑex#4à+¿ #/ ¿oðJOðJºûóù&ûª0Fë ›ø°ðÐ0= àð лñ¿OðW Oð7 ËëBÚ¶ñÿ? ÐHEØÑUEÜûP&àOðÿ6ø[×çs Ñ/Oð" ¿oð@Oð@Ìø0*¹½èð±@BB±±a`½èð+¿#°ç½èð” 0µFJF Fh)F"F½è0@ÿ÷r¿ø KFhð¸¿ø pµÍ%ð5 -8¿ %-F?ÛB=Ó!KhF!F¡± h[Ô +Ù `ÌÍPàŒBÑbh`àKhc` Fà FIhéçL#h¹0Fð'ø `)F0Fð"øCFÐÄ$ð„B Ñ%`ñ # ðà ÐZBâPp½0Fað ø0îÑ #3` p½¿L H 8µL#FF#`ðøCÑ#h±+`8½47 Jhc±DiFˆBØ`FpGK "`Oðÿ0pGK`ïç¿P 47 87 ðA࿃ðC0µOêAOêC”ê¿ê¿Tê Uê êd\êe\ðâ€OêTTÔëUU¸¿mB Ý,D€êê‚êƒê€êê6-ˆ¿0½ðOOê1Oô€Lê1Ð@BaëAðOOê3Lê3ÐRBcëC”ê𧀤ñÕñ  Ûúü"úò€Añúò€CúóYAà¥ñ ñ *úü(¿Lð CúóÀQëãqðEÕOðÜñ ~ënë±õ€Ó±õ ÓI_ê0Oê< ñOêDRõ€€ðš€¼ñO¿_êP PñAëQAê0½_êL @AAëô€¤ñéÑ‘ð¿F ±úó¿ 3£ñ ³ñ  Ú 2Ýñ Âñ ú ð!úñ àñØ¿Âñ úñ ú üÜ¿Aê @䢿ëQ)C0½oê<Ú 4ÜñÄñ  úðúó@ê!úóEê0½Äñ Äñ  úðúó@ê)F0½!úð)F0½”ðƒô€¿ô€4=Nçêd\¿êe\)Дê¿êÐTê ¿FF0½‘ê¿! 0½_êT\Ñ@IA(¿AðA0½õ€<¿õ€0½ðEEðþAAôpOð0½êd\¿FFêe\¿ FFPê4¿Rê5‘êAô!0½¿ð¿!pG0µOô€dñ2OðOðPç¿ð¿!pG0µOô€dñ2ðEH¿@BOð>ç¿BOêâOê1Oêp¿ðC“ðOð`QpG’ð¿“ðOpG0µOô`tðE!ðA ç¿Pê¿pG0µOð àPê¿pG0µðEÕ@BaëAOô€dñ2_ê‘\?ôÜ®Oð_êÜ ¿2_êÜ ¿2ëÜÂñ úü úðúþ@ê!úñDÁæ¿pµOðÿ LôàlêT¿êU”ê •ê ðÞø,Dê!êLQ#êLSPê5¿Rê5Aô€Cô€8РûÎOðáûåðBàûåOðáûVœð¿Nð¤ñÿ¶õdõ@tÒ_êNmAFëBêÆ!AêUQOêÅ @ê^POêÎ.´ñý ˆ¿¼õàoؾñO¿_êPPñAëQp½ðFFê@êê´ë\¿Ôë AêQp½Aô€Oð<ó«€ñ6Þ¿ ðAp½Äñ <5Ú 4ÜñÄñ úó úðúò@êðB!ðAëÓp!úöBë^êC¿ êÓpp½Äñ Äñ úó úðúò@êðAëÓpAñ^êC¿ êÓpp½Äñ úòNê úóúòCê!úððA!úò êëÓp^êC¿ êÓpp½”ðÑðF@Aëô€¿<÷ÐAê•ð¿pGðFRCëô€¿=÷ÐCêpG”ê  êU¿•ê  ÐPêA¿RêCÑÑêðAOðp½PêA¿FFRêCДê ÑPê6Ñ•ê ÑRê6¿FF ÑêðAAðþAAôpOðp½AðþAAôxp½pµOðÿ LôàlêT¿êU”ê •ê ð§ø¤ëêRê5Oê1ðˆ€Oê3Oð€UEêCêcOê"EêEêeOê&ðAB¿–BDñýõ@tÒ[Oê2¶eë[Oê2Oô€Oô,¶ëuë"¿¶uF@ê [Oê2¶ëuë"¿¶uF@ê\[Oê2¶ëuë"¿¶uF@êœ[Oê2¶ëuë"¿¶uF@êÜUêÐOêEêuOêOêÃCêRsOêÂ_êÀÑô€ ÑAêOðOðL¶çô€¿C ´ñý ˆ¿¼õào?ö¯®µë ¿¶ë _êP PñAëQp½ðNNê1ë\¿Ôë AêQp½Aô€Oð<æEêæ êU”ê ¿•ê ?ô;¯”ê  ÑPê4ô4¯•ê ô%¯FF,ç•ê ÑRê5?ôý®FF"çPêA¿RêCôÅ®PêAô ¯RêCôë®çOðÿ<à¿Oð à¿Oð MøÍOêA êl\OêC ¿êl\аPêA ¿RêC ‘ê¿ê pGñ‘êX¿™B¿B,¿Øoêãp@ðpGOêA êl\ÑPê<ÑOêC êl\ÖÑRê<ÓÐ]ø pG¿„FFbFŒFFcF࿵ÿ÷·ÿ(H¿ñ½Møíÿ÷ôÿ ¿ ]øû¿Møíÿ÷êÿ4¿ ]øû¿Møíÿ÷àÿ”¿ ]øû¿Møíÿ÷Îÿ”¿ ]øû¿Møíÿ÷Äÿ4¿ ]øû¿OêA²ñàC$¿³õÜñþ\ ÙðLOêÀLêPp²ñO@냿 ðpGð€O!Ññ8r¼¿ð@pGAô€OêRRÂñÂñ ú ó úð¿@ðOêÁ#OêÓ#ú ü@ê #úóOêCÌçêbSÑPê3¿Oðþ@@ô@pGð@@ðþ@@ôpG¿s¹j¹)¿(¼¿ OðAÄ¿oðAOðÿ0ð<¸‚°ìF-éPðøÝøà° ¼pG¿-épCžFF€F‰Fð)øûóû3¤ûED¸ëiëÆéE½èpƒ-épCžF€F‰FFð]ùûõûS ûED¸ëiëÆéE½èpƒpG¿)-éðÀòŸ€$+Àò–€FFF+>ÑŠBWÙ²ú‚óK±Ãñ ú÷ úò@Cúö) ·ûñò3 û|¨²Cê Gûó»B Ùñÿ<€ð»B@òþ€:/Dÿ·ûñó¶²ûqFêAûðˆBÙIñÿ7€ð퀈B@òê€;CêB#à‹B Ù#FFF±@BaëA½èðpG³úƒø¸ñ@ð„€‹BÓ‚BòÞ€#"èç¹#³ûòõµú…ò*9Ñ( ú…ü#·ûðñ2 ûwBêG ûòºBÙñÿ8ÒºBòÁ€AF¿·ûðò¶²ûpFê@ ûü„EÙ@ñÿ7Ò„Eò«€:FBêB±çäCRBcëCdç@BaëAOðÿ4[ç•@Âñ 'úñ( &úó—@±ûðøC; ûú…üCêA ûó‹BúöÙIñÿ2yÒ‹BwÙ¨ñ)Dɱûðó¿²ûGêG ûòºBÙñÿ1`ÒºB^Ù;/D¿CêCçÈñ úü%úóCê OêI!úóú÷ úò³ûùñC û3: úŒûBêC ûúšEúðÙë ñÿ25ÒšE3Ù9cDÊë³ûùò û3¿²GêG ûù¹EÙë ñÿ3Ò¹EÙ:gDBêE¥ûÉëBOð ÓÐ*F çbFç;Fçúö†BõÒj#çFåç F çFËçFˆçCFBF ç:Sç9/D<ç¿-éðFFF+CÑŠBSÙ²ú‚÷W±Çñ  úöúóúôCúõ! ¶ûñò+ ûg ²CêFûó³B Ù6ñÿ7€ðö€³B@òó€:&Dö¶ûñó­²ûaEêAûðˆBÙ ñÿ6€ð B@ò߀;CêB#FF½èðpG‹BJسúƒö.MÑ‹BÓ‚BòÖ€#"FF½èðpG¹$´ûòô´ú„ò*|Ñ & §²#±ûöð* ûBêAûòŠBÙ ñÿ<ÒŠBòÀ`F‰±ûöò­²ûEêEû÷¯BÙ,ñÿ1€ð–€§B@ò“€:BêBFF½èðpG#FFF½èðpGÆñ "úô³@COêH!úóú÷ úõ³ûøü/Cû3= ú„úEêC û ù™EúûÙ ñÿ2mÓ”FÉë³ûøõû3¿²GêG ûø¸EÙ?ñÿ3aÓFEê L¬û #ÈëŸBOðIÓEÐbF+Fcç”@Âñ !úü& úóúõ¼ûöøCê û̧²Cê LûócEúõ Ùë ñÿ2:ÒcE8Ù¨ñ¤DÃë ¼ûöó‰²ûÌAê AûòŠBÙ ñÿ0"ÒŠB Ù;!D‰CêCIç:F ç3Fç Fkç°@B¶Ò ñÿ2#ç3F2Fç™EÙ¬ñ #DŒç¸E›Ù='D™çFÞçFÇç8!D:ç¿ÿ#–ÿ (( ( (( Fÿ ÿÿÿ#ÿÿÿFÈÿ’@–@›@¬@µ@À@Ë@Ö@†@ß@€@è@ò@ý@AAAA&A*A3A7A=ACAFAMAPAUAaAdAjAqA{A…AŽAœA¨A¯AµAÂAÍAÚA}>>Y ¨>­>•Á>Ê>™ç>ì>Å ?õ6a ?(?yŠ?Å?£?± ¾?Æ?e Õ?Ú?…6ê?] @ @u@õ6=õ6F@N@V@^@e@m@0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZVRBrain CLI version 2.31 Jul 20 2015 / 13:01:43Available commands: %s %s System Uptime: %d seconds, Voltage: %d * 0.1V (%dS battery) Hardware: %s @ %dMHz, detected sensors: %s ACCHW: %s.%cCycle Time: %d, I2C Errors: %d, config size: %d Saving... Rebooting...Must be any order of AETR1234 Current assignment: Error: Enable and plug in GPS first Enabling GPS passthrough... Enabled features: Available features: Invalid feature name... Disabled Enabled Leaving CLI mode... Resetting to defaults... Current mixer: %s Available mixers: Invalid mixer type... Mixer set to %s Current profile: %d Usage: motor index [value] - show [or set] motor value No such motor, use a number [0, %d] Motor %d is set at %d Invalid motor value, 1000..2000 Setting motor %d to %d aux %u %u Invalid Feature index: must be < %u %d %dCurrent settings: %s set to ERR: Value assignment out of range ERR: Unknown variable name Current Config: Copy everything below here... mixer %s cmix %dcmix %d 0 0 0 0 feature -%s feature %s map %s set %s = NG OK Custom mixer: Motor Thr Roll Pitch Yaw #%d: %s Sanity check: resetloadLoaded %s mix... Wrong number of arguments, needs idx thr roll pitch yaw Motor number must be between 1 and %d Entering CLI Mode, type 'exit' to return, or 'help' # ERR: Unknown command, try 'help' looptimeemf_avoidancemidrcminthrottlemaxthrottlemincommandmincheckmaxcheckdeadband3d_lowdeadband3d_highneutral3ddeadband3d_throttlemotor_pwm_rateservo_pwm_ratepwm_filterretarded_armdisarm_kill_switchfw_althold_dirreboot_charactersoftserial_baudratesoftserial_1_invertedsoftserial_2_invertedgps_typegps_baudrategps_ubx_sbasgps_autobaudserialrx_typespektrum_sat_bindspektrum_sat_on_flexporttelemetry_providertelemetry_porttelemetry_switchvbatscalecurrentscalecurrentoffsetmultiwiicurrentoutputvbatmaxcellvoltagevbatmincellvoltagevbatwarningcellvoltagepower_adc_channelalign_gyroalign_accalign_magalign_board_rollalign_board_pitchalign_board_yawyaw_control_directionacc_hardwaremag_hardwaremax_angle_inclinationmoron_thresholdgyro_lpfgyro_cmpf_factorgyro_cmpfm_factorpid_controlleryawdeadbandalt_hold_throttle_neutralalt_hold_fast_changethrottle_correction_valuethrottle_correction_anglerc_raterc_expothr_midthr_exporoll_pitch_rateyaw_ratetpa_ratetpa_breakpointfailsafe_delayfailsafe_off_delayfailsafe_throttlefailsafe_detect_thresholdauto_disarm_boardrssi_aux_channelrssi_adc_channelrssi_adc_maxrssi_adc_offsetyaw_directiontri_unarmed_servofw_roll_throwfw_pitch_throwfw_vector_trustgimbal_flagsacc_lpf_factoraccxy_deadbandaccz_deadbandacc_unarmedcalsmall_angleacc_trim_pitchacc_trim_rollbaro_tab_sizebaro_noise_lpfbaro_cf_velbaro_cf_altaccz_lpf_cutoffmag_declinationgps_pos_pgps_pos_igps_pos_dgps_posr_pgps_posr_igps_posr_dgps_nav_pgps_nav_igps_nav_dgps_wp_radiusnav_controls_headingnav_speed_minnav_speed_maxnav_slew_ratep_pitchi_pitchp_rolli_rollp_yawi_yawp_alti_altd_altp_leveli_leveld_levelp_veli_veld_velfw_gps_maxcorrfw_gps_rudderfw_gps_maxclimbfw_gps_maxdivefw_climb_throttlefw_cruise_throttlefw_idle_throttlefw_scaler_throttlefw_roll_compfw_rth_altblackbox_rate_numblackbox_rate_denomauxfeature_name auxflag or blank for listcmixdesign custom mixerdefaultsreset to defaults and rebootdumpprint configurable settings in a pastable formexitfeaturelist or -val or valgpspassthroughpassthrough gps to serialhelpmapmapping of rc channel ordermixer name or listmotorget/set motor output valueprofileindex (0 to 2)savesave and rebootname=value or blank or * for listshow system statusversionNaze 32Naze32 rev.5Naze32 SPADXL345MPU6050MMA845xBMA280MPU6500NoneGYROACCBAROSONARGPSGPS+MAGPPMVBATINFLIGHT_ACC_CALSERIALRXMOTOR_STOPSERVO_TILTSOFTSERIALLED_RINGFAILSAFETELEMETRYPOWERMETERVARIO3DFW_FAILSAFE_RTHSYNCPWMFASTPWMI2CBLACKBOXTRIQUADPQUADXBIGIMBALY6HEX6FLYING_WINGY4HEX6XOCTOX8OCTOFLATPOCTOFLATXAIRPLANEHELI_120_CCPMHELI_90_DEGVTAIL4HEX6HPPM_TO_SERVODUALCOPTERSINGLECOPTERCUSTOMr@w@{@Ž@€@†@Š@õ6'@/@<@ö6X! (#ÿ6Z!  7Ú" °¤7Œ" Ð7Ž" Ð+7" Ð67Ü" Ð?7Þ" ÐH7’" ÐW7”" Ðg7–" Ðq7˜" Ð…7š" 2}”7œ" 2ò£7ž" ®7à" »7á" Î7â" ÿÿÿÿÝ7 & 0~ò7ð" °Âî7ô" °K8ø" 8ù" .8ê" 78ë" D8ì" ÿÿÿÿQ8í" ^8Ö" l8×" ~8Ø" —8ú" ª8û" ¹8ü" Ê8É" ÈÔ8Ä" 'á8Æ" rï8È" 9Ê" 29Ë" 2+9Ì" 2B9Í" T9Ÿ" _9 " i9¡" s9¢" Lÿÿÿh„9¤" Lÿÿÿh–9¦" Lÿÿÿh¦9¨" ÿÿÿÿ¼9©" É9ª" Ö9´" d„ì9²" €ü9¬" :®" dè:°" dè(:H <¾ 7:¿ dC:À ú]:Á r:Ä –Œ: „¦:g ú®:h d¶:i d¾:j dÇ:k d×:l dà:m dé:n èÐø:! È;! È;! èÐ,;! dÐF;Â" <X;ã" i;ä" z;æ" ÿ‡;è" ÿ—;! ÿÿÿÿ¥;! ·;,! Å;0! Ô;4! ä;! ÿñ;v ú<x d<w d<Œ ,< ´8<t Ôþÿÿ,G<r Ôþÿÿ,U<y 0c<| r<€ ~<„ Š<ˆ š<p °¹ÿÿPFª<M È´<W Ⱦ<a ÈÈ<N ÈÓ<X ÈÞ<b Èé<O Èó<Y Èý<c È= ! Ð=$! *=&! Ð8=(! ÐF=#! dT=J È\=T ÈŽ9^ Èd=I Èk=S È}9] Èr=K Èx=U È 9_ È~=L È„=V ÈŠ=` È=P Ș=Z È =d Ȩ=R È®=\ È´=f Ⱥ=6! Óÿÿÿ-É=8! Óÿÿÿ-×=:! Óÿÿÿ-ç=! èÐ>@! èÐ>B! èÐ,>D! ?>H! L>b ÈW>&  i>&  ddddddAERT1234AETR1234`M‡ µbðÿµbðýµbðûµbðúµbðüµbðþµbGµbIµbOµbgµb0<£µbÈÞj$PUBX,41,1,0003,0001,115200,0*1E $PMTK251,115200*1F $PUBX,41,1,0003,0001,57600,0*2D $PMTK251,57600*2C $PUBX,41,1,0003,0001,38400,0*26 $PMTK251,38400*27 $PUBX,41,1,0003,0001,19200,0*23 $PMTK251,19200*22 $PUBX,41,1,0003,0001,9600,0*16 0Ý1åQŠAà5èÂçM NáNAN–UNwNK‹N­N€%ÁNõ6dddddddddddddddd€?÷5?÷5¿€?€?÷5¿÷5¿€?€?÷5¿÷5?€?€?÷5?÷5?€?€?€¿€¿€?€¿€¿€?€?€¿€?€?€¿€?г]¿?€?€?г]¿¿€¿€?г]??€?€?г]?¿€¿€?€¿€?€?€?€¿€?€?¿€?€?¿€¿€?€?€¿?€?€??€?€?€??€¿€¿€?€¿¿€¿€?¿€?€¿€?€??€¿€?¿€??€?€¿€?€¿€?€¿€¿€?€?€?€?€?€?€?€¿€¿€?¨ªª?€?€¿°ª*¿€?€?°ª*¿€?€?€?€¿dddd€?€¿€?€?TQôSQ„QðTPôP°T4TüR”OtP˜SœR´QPU€?€¿€?€¿€?€¿€¿€?€?€?€?€?€?€?€¿€¿€?€?€?€¿€?€¿€?€¿€¿€?€?€?€?€?€?€?€¿€¿€?€¿€?€?€?€¿€¿€¿€?€?€?€¿€?€?€¿€?dddddddd€?€?€?€?€¿€¿€?€?€¿€?€?€¿€dddddddd€?€?€¿€?€¿€?€?€?€?€?€¿€¿€?¿Ð³]?€?€?¿Ð³]¿€?€??г]?€¿€??г]¿€¿€?€¿€¿€?€?€?dddddddd€?€?€¿€?€¿€¿€?€?€?€?€?€¿€?¨ªª?€?€?€¿°ª*¿€¿€?€?°ª*¿€¿€?¨ªª?€¿€?€¿°ª*¿€?€?€?°ª*¿€?€?€?€?€?€¿€¿€?€?€¿€?€?€¿€ddU”TØS|S¤Q\OROLL;PITCH;YAW;ALT;Pos;PosR;NavR;LEVEL;MAG;VEL;Jul 20 2015ARM;ANGLE;HORIZON;BARO;VARIO;MAG;HEADFREE;HEADADJ;CAMSTAB;CAMTRIG;GPS HOME;GPS HOLD;PASSTHRU;BEEPER;LEDMAX;LEDLOW;LLIGHTS;CALIB;GOVERNOR;OSD SW;TELEMETRY;SERVO1;SERVO2;SERVO3;œV¡V¨V±V·V¾VÃVÍVÖV ßV èV òV üV W WWW'W.W8W@WKWSW[Wÿè[ï[ø[\\\H Field H Firmware type:Baseflight H Firmware date:%s %s 13:01:53H P interval:%d/%d H rcRate:%d H minthrottle:%d H maxthrottle:%d H gyro.scale:0x%x H acc_1G:%u H vbatscale:%u H vbatcellvoltage:%u,0,%u H vbatref:%u 0:0:LOG0000%d.TXT0:LOG000%d.TXT0:LOG00%d.TXT0:LOG0%d.TXT0:LOG%d.TXTGPS_home[0]GPS_home[1]GPS_numSatGPS_coord[0]GPS_coord[1]GPS_altitudeGPS_speedGPS_ground_courseloopIterationaxisP[0]axisP[1]axisP[2]axisI[0]axisI[1]axisI[2]axisD[0]axisD[1]axisD[2]rcCommand[0]rcCommand[1]rcCommand[2]rcCommand[3]vbatLatestmagADC[0]magADC[1]magADC[2]BaroAltgyroData[0]gyroData[1]gyroData[2]accSmooth[0]accSmooth[1]accSmooth[2]motor[0]motor[1]motor[2]motor[3]motor[4]motor[5]motor[6]motor[7]servo[5]H nameH signedH predictorH encodingG nameG signedG predictorG encodingI nameI signedI predictorI encodingP predictorP encodingš[¡[ª[¶[ìY÷YZZZ(ZH Product:Blackbox flight data recorder by Nicholas Sherlock H Blackbox version:1 H Data version:2 H I interval:32 :Z ú6HZQZZZcZlZuZ~Z ‡ZZ™Z¦Z³ZÀZÍZ  ØZ âZ ìZ öZ þZ [["[/[<[I[R[[[d[m[v[[ˆ[‘[ ÔYàYÁ[È[Ñ[Ý["*+,:;<=>?[]|"*+,.:;<=>?[]|€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™­›Œ®Ÿ !¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ÷ØÙÚÛÜÝÞŸHIŠ‹Œ„@…@†@‡@‚ƒÿŽ_¬_p_?_ !"#$%&'ˆ‰Š‹Œ@Mÿ !"#$%&'HIJKLM‚ÿHIJKLM‚D€E€F€G€ABCÿ@@@@@@ @@@ @@@@@@@ @@.@@ .@@@@@@ @@ @@@@ @@@@@@ @  @@ @€Ûó©óÁóuøµóø‘ùmù{ùeùiùgùSTM32 Virtual ComPort in HS modeSTM32 Virtual ComPort in FS ModeSTMicroelectronics00000000050B00000000050CVCP ConfigVCP InterfaceKËacosfpowfsqrtfÀ?ÜÏÑ5€?À?É?I@Ë–@É@Sû@ËAí/AIA1bAS{A:ŠAË–A\£Aí¯A~¼AÉA ÕA1âAÂîASûAòB: BƒBËBB\#B¥)Bí/B66B~è‚5õ.»D„éœp&´_~A9‘Ö9ƒS9ôœ„_‹½ù(;ø—ÿÞ˜ï/‹Z mm6~Ï'Ë ·OF?fž_ê-u'ºÇëåñ{=9÷ŠR’êkû_±]V0Fü{k«ðϼ šô6©ã‘a^æe™…_ h@ÿØ€Ms'1VÊs¨É`â{ÀŒk É?ð9Ú7¢3„.P+Â'Ð"ÄÆD0C0Ãi7¬1h!"3´3h!¢38cí>ÚI?^˜{?ÚÉ? ((((( ˆAAAAAABBBBBB Ôf€Ãÿ µb1å€?ÿÿÿÿ€?m=ÜÜÜÜÜÜÜÜ  z d C±«°a°°3°ó¯ݯ°%° ÿ CÀ2 $$$$‚ÿ  @@ùÓÑÓÓ Ò]ÔáÒIÒ=ÒÙ€?€?€?KûOûÅûUû…ûÂAüMü}üYü™ü½üÙü @ƒ@Wõü÷üùüÿüýûüýüÐe}a˜ ƒUFD÷Ÿ"Ofwupd-0.7.0/data/tests/dfu/example.bin000066400000000000000000000000141267747510300176300ustar00rootroot00000000000000hello world fwupd-0.7.0/data/tests/dfu/example.dfu000066400000000000000000000000341267747510300176400ustar00rootroot00000000000000hello world ÿÿÿÿÿÿUFDfêd-fwupd-0.7.0/data/tests/dfu/example.xdfu000066400000000000000000000000341267747510300200300ustar00rootroot00000000000000i»y_fÛs5­ ÿÿÿÿÿÿUFD¤Mþ3fwupd-0.7.0/data/tests/dfu/firmware.bin000066400000000000000000000002101267747510300200070ustar00rootroot00000000000000=ï ðúÏðûÏðéÏðêÏðáÏðâÏðÙÏðÚÏðóÏ ðôÏ ðöÏ ð÷Ï ðøÏ ðõÏðÀõÿ Àøÿ À÷ÿ Àöÿ Àôÿ ÀóÿÀÚÿÀÙÿÀâÿÀáÿÀêÿÀéÿÀûÿÀúÿ?ï ðBï ð=ï ðfwupd-0.7.0/data/tests/dfu/firmware.hex000066400000000000000000000006001267747510300200260ustar00rootroot00000000000000:044000003DEF20F080 :10400800FACF01F0FBCF02F0E9CF03F0EACF04F0DA :10401800E1CF05F0E2CF06F0D9CF07F0DACF08F00C :10402800F3CF09F0F4CF0AF0F6CF0BF0F7CF0CF08E :10403800F8CF0DF0F5CF0EF00EC0F5FF0DC0F8FF6C :104048000CC0F7FF0BC0F6FF0AC0F4FF09C0F3FF6E :1040580008C0DAFF07C0D9FF06C0E2FF05C0E1FFCC :1040680004C0EAFF03C0E9FF02C0FBFF01C0FAFF7A :1040780011003FEF20F0000142EF20F03DEF20F06B :00000001FF fwupd-0.7.0/data/tests/dfu/kiibohd.dfu.bin000066400000000000000000001073041267747510300203750ustar00rootroot00000000000000 ùAMÁùùùù99ù9é99999999999É99999999999999999999999-L9999999999µ!KLò R€Mö(€"#ø,KJ`JZ`KxÕxBðp#JI˜ˆBÒIYX™P3õçKJ“BÒ"Cø+øçK€"ø+J“BùÑK "pKOô‚"`KKö2`"Cø,b¶ðøþç @8€@‚? Ð@éÿœïÿ¨˜œïÿ¤ äà.äà@@€@ààµðýðÿûðCøðiøðëýr¶ðvø(ûÑb¶ðUþðÿûòçKh2`pG¿œïÿµ Hðÿ L#hXÕðý#hYÕðø#hÕð øKhÛëÕðøèç¿Pl4€@µÿ÷ÝÿHðñ¾¿nbµHðêþK!hð£ÿHðâþJK`½ub,íàu“ú íൠHðÐþ K!hð‰ÿHðÈþK!hðÿH½è@𾾌b(íà­b4íàu“µ Hð°þ K!hðiÿHð¨þK!hðaÿH½è@ðž¾¹b(íàÏb8íàu“µHðþK!hðIÿH½è@ð†¾Ûb(íàu“DF“BÐøúçpGµ#“BÐÌ\ÄT3ùç½pGr¶ K Ih Kh hb¶IÕKöN1ŠBˆ¿3Âõ;B0!2²ûñòOôzpû pGààíàœïÿ8µFÿ÷ÜÿFÿ÷Ùÿ@°õzÓ<Ðõzuÿ÷Îÿòç8½ˆCˆ“B$¿ÀˆÓ˜²pG8µ FFHð,þ!(Fð±þaˆ"ˆK“BЊBáˆÙXB Ñ Hðþ(F!ðŸþH½è8@ð¾‹B¨¿#c€cˆ¢hÕT8½¿d/du“8µ#M(Fÿ÷Âÿ눛²˜B,FÓHðõý(ˆ!€²ðyþHðíýhˆ!€²ðqþHðåý(y!ðjþHðÞýÿ 8½+yC¹ÿ#+qÿ÷ÔÿKqÿ÷Ðÿ(q¢h#ˆ›²Ð\#ˆ›²3›²#€"ˆãˆ’²›²šBÓK"€#y;Û²#q8½œéÿidziu“éÿ-éðAr¶ßø9M˜ø`+x8Lðö²#yOÐ[±öGÕ4Hð›ý€#+p##€c€#qTà0O;y ³ðÕ/HðŒý€#+p#ˆø0ñÕ+Hð‚ý;à*Hð~ý8y!ðþ'Hðwý:y*¿à"è"Kp/à#;ýÑK€"pp#;ýÑHÿ÷(ÿ㈛²˜BÒK"px’üÔKð"pÿ÷RÿKpà+K ذ"*px Iÿ÷ÿ#;ýÑ€"ÐçxIÿ÷ ÿ K"pb¶½èð¿`@œéÿ¡déÿÌd÷d0eu“`@`@-éøC3L㈛²‹B€F F‘FXÓ Fÿ÷ÜþkƒBRÚ"ˆcˆ’²›²šB¿""#F«B)ÒI±)Ñaˆ h‰²;ET›²!àaˆ h‰²;ø›²!à`ˆøp¦h€²7TgˆàˆN¿²€²7‡B¨¿ ñ¬¿p€w€›²Óç*ÑJ#pKxð Fд"pàxŸüÔ°# p Kð"pÿ÷ÄþKp ½èøƒ ½èøƒ ½èøƒ¿œéÿ`@`@`@-éðA˜FK°°ˆFFF¨!¶"­ø0ÿ÷"þè#ø0ø `,FëœBÚø@¨!"ÿ÷nÿ¹ ÿ÷@þõçñ‰¨É²"ÿ÷aÿ¹ ÿ÷3þòç4ä²àç0°½èð cµHðtü !$"´#½è@ÿ÷º¿u“7µè#ø0ý#F Fø0ø ¨!"ÿ÷6ÿ¹ ÿ÷þõç(F!F"ÿ÷,ÿ¹ ÿ÷þýõç°0½µHðDüH’!"½è@ÿ÷Ó¿¿u“7fµè#ý$ø0ø@ø ø0øøhF!"ÿ÷ÿ¹ ÿ÷Òýõç¨!"ÿ÷öþ¹ ÿ÷Èýõç°½µ#H#IðÅù#KhBð@`!JOôs`S` K…"p"Zq€"Zp "qKOôb` !" #ÿ÷>ÿKhBô€2`KOô¢r`Kh Bô€2`!´#Fÿ÷*ÿH!"ÿ÷mÿH’!"ÿ÷hÿ ! "½è@ÿ÷“¿¿pcËg4€@ @`@áàTð@@ @Dð@·g7fµ Hð°û # !"ÿ÷øþ ! "ÿ÷mÿH!"½è@ÿ÷4¿u“·g0µ "…° FF! ÿ÷Yÿè#ø 0ý#ø 0ø@¨!"ÿ÷`þ¹ ÿ÷2ýõçè#$ø0ø @¬BÐø @¨!"ÿ÷Lþ¹ ÿ÷ýõçé#ø0!¨ Fÿ÷?þ¹ ÿ÷ýõçH4ðZûä²Þç ! "ÿ÷ÿ°0½¿^eµiFªðø˜x±ð"üIJHð@û !Fÿ÷¢ÿ°½u“0µ…°$Hð1ûHð.û˜iFªðmø˜xë±|+ ÑHð!û¨!F"ÿ÷øý%,Fêçðõû«eDí²ø ˜ð ø Hð û-íÙà%FHðû¨)F"ÿ÷Ûý°0½¿u“xe”ezi0µ…°$HðíúHðêú˜iFªð)ø˜xë±|+ ÑHðÝú¨!F"ÿ÷´ý%,Fêçð±û«eDí²ø ˜ðÜÿ HðÇú-íÙà%FHðÀú¨)F"ÿ÷—ý°0½¿u“xe”eziµ©ªðîÿ˜x+@Ðý#è$ø0ø@ð|û©øª˜ðÛÿ˜xs³ø@ðnû#øø0hF!"ÿ÷bý@¹ ÿ÷4üõçø03ø0˜©ªð»ÿ˜xs±ðPûø¨!"ÿ÷Gý(çÑ ÿ÷üôç°½ pGxµ+6Øßèð "-JCˆDBx™xŠàJCˆDBx™x Dšp"àCˆIBx DøçKñÜxAx3a“B™pøÑàKñÜxAx3!D“B™pøÑà#JAxD3+‘pøÑHè#p$#Cp’!"½è@ÿ÷°½UøÿTøÿµ©ªðTÿ˜x ³ðéú©ø ª˜ðHÿ˜x«±ðÝú©ø ª˜ð<ÿ˜x±ðÑú€²àF­ø¨ÿ÷‹ÿ°]øûÿ)sµ FFFÑÿ(ÑH°½èp@ðÚ¹ ¹(-ÐJhJxɲð(#ÝpJx"x*Øßèð bˆ*Ù:b€&à& Jy0èÀ²!*Fðdÿ.¹ F°½èp@ÿ÷I¿°p½¿—eœïÿ ïÿËéÿsµLiFªðÚþ#˜#€x±ðmú €°½ªïÿµiFªðÉþ›xT+ Ðt+л¹ Kxñÿ2¿"à Kx*¿""HpðmùHðjùKxð˜ù°]øû¿¨ïÿu“jh7µÂ²­øÀó ë‚"’ñ€B(Lõ’")IØßèð"-$Jà$JRø#$úðCBø#8àTø#%úðCDø#Oô¢s`Kx+)ÑhCð $àJRø#0"úðB ¿  àTø#%úð!êDø#Oôˆs` Kx(±¨B ÑhCðàhCð`à` °0½ð@ð@ð@Êéÿð@pµ-I-Hð§þ-Hðìø !ðqù$*Kø ëD!Xx4Bê ÿ÷ÿ ,ñÑ$HðÖø#HðÓø !ðXù$ Kø ëD!Xx4Bê ÿ÷fÿ,ñÑHð½øHðºø!H ð?ùHð³ø! FM&HVC#¬2qCqH*«UOðÿ5cp¥påpñƒqëÑ J€ J€p½Çjàjh¨éÿu“­hºéÿÊhúÿ¦ïÿ¤ïÿ( ØßèðHàHàHàHàHðq¸¿çhñhþh iiK-é÷Oˆ‚B8¿€FŒK ¹ˆŒJ€€àˆ2€‰Kh%_úƒûßø4’OêE ë ø0Px!Cê ÿ÷åþï²Oð"KzCÔ¹ay!q!aq|IøëHIx’@ê !“ÿ÷Ìþ!ˆ´øÀš›Oöÿ~H±qE¿1Oê\ ¿™R¤øÀ àôE¿ ñ OêQ¿¤øÀÑRcy+EÑ¢y#yÂë Ò²+Øßèð  ˆaˆˆBÙ# à*Ù#à ˆaˆˆBÙ*Øcq(à#cqà#ûçVHðäÿ„ø°8FayðzýRKx»±ay"yŠBÐ+Ñ)Ñ8FðYøà+ Ñ8F!ðRø`yÿ÷DÿGHðÃÿñ 7¸ñÿ²ô}¯CJø0RD!Px5Cê ÿ÷Tþ -ô^¯=Kˆ*^Ð:;H€ð¤ÿ:Hð¡ÿ-K!ˆð%ø5Hð™ÿ6Hð–ÿ)K!ˆðø0HðŽÿ1Hð‹ÿ!0Fðø+Hð„ÿ-Hðÿ$£Ñ&Hð{ÿ*Hðxÿ! ²ðýÿ'Hðqÿ'HðnÿI%û4(yÿ÷äþhyÿ÷áþ!Hð`ÿ!(ˆðåÿHðYÿhˆ!ðÞÿHðRÿH,ÏÑH°½èðOðJ¿°½èð¿¦ïÿ¢ïÿ¤ïÿœïÿúÿºéÿ%i¨ïÿzi¨éÿªïÿu“Yi|iŸiÂijvjjµHðÿ ½ÇkµHðÿHðÿKxÒñ8¿"p½¿u“ækÁïÿ ˆpµFOöÿr“BF FÑ1K €x+;Ð/Hðïþ(F!ðtÿ-Hðèþ ˆ!ðmÿ*Hðáþ)à;Ò( €Ð'HðÙþ>¹&K'Hh2`&Kpà%K&Hh2`%K"pðÆþ(F!ðKÿHð¿þ p½¹KàKh2`#ˆ+¹#¹JàJp Kxƒ±Hð¨þ!(Fð-ÿ Hð¡þ ˆ!ð&ÿHðšþ ˆÐñ8¿ p½Áïÿlziu“5l´ïÿYlÈïÿ¼ïÿal°ïÿÄïÿ¸ïÿjl0µMÍ‹°¬ÄÍÄ+hH#`ðkþ Hðhþ$­ Hðcþà²ð’þHð]þUø$4ðjû ,ïÑ °0½ku““l§p8µ9H9M:LðFþ9HðCþ9Hð@þ8K9Jx9K( ¿FFð6þ6Hð3þ6K!xð·þ4Hð+þ4K!xð¯þ2Hð#þ2K!xð§þ0Hðþ0K!hðÔþ.Hðþ.K!hðÌþ,Hð þ(y!ðþ*Hðþ x!ð‰þ'Hðýý'K!xðþHðõý$K!hð®þHðíý!K!hð¦þHðåý(x!ðjþHðÞý x!½è8@ða¾u“6ýÿýÿÏlôlÊïÿÉlÂlmËéÿmÀïÿm°ïÿ4m¼ïÿ@m¸ïÿBmJmRmÈïÿ´ïÿÄïÿ7µªiFðçúHMLðžýJ#p›xS+ ÐØD+Ð àd+Ðs+Ðà#p Hð‰ý#+pÿ#à Hð‚ý#+p##p°0½u“ÊïÿËéÿÉïÿhm“m-éðA€FFF(Mƒ#ûS›x;D€+ Ý%Hð`ý Fðý#HðZý þ÷ ÿêç&ó²»B5ÒKxk±!øðÓýHðGý FðvýHðAýƒ"ûSYxHXpøD6Èp™x1™p“ù)¼¿!Ypûóêé\RxŠB¿2êTƒ#cCêV*¼¿"êTÆç½èð üÿ¿mòmÁïÿnu“µ* FøÑJHðýJKx#ˆOöþq*IÐZ‹B"€ø Ð1‹BÑCKà#ZCBK"€"prà?K@MxAɲ)pBUiÙ:N"p3xS±:HðÛü0x!ð`ý8HðÔüYà7Kx»±6HðÍü!(xðRý4HðÆü!hxðKý0Hð¿ü¨x!ðDý*Hð¸ü&Hð÷ù:àX‹B €ÐOöÿr“B&ÑKøp$KÝx±þç™x")ÚpÐþçp#øø 0ø ø¨ à¨!ø =KC#€K!p Fÿ÷ÿ à! F ñÿ÷ÿ"ˆ¹K!™pÚp ˆÐñ8¿ °p½nÊïÿ5ýÿEþÿBþÿ9nu“Áïÿ€nziýÿ€)ÙHà*Øÿ÷ä¾HðQ¼¿”nØn ˆ÷µFY£õC‰²û;F9€8M+Øßèð hp`à¨p^àèp\à(qZàhq8€WàkyY/KDHp;ˆ+OÑ+K[xÿ+Ð+JxšBѪx)KèxSø20)y(J˜Gkxÿ+Ð#JxšB8Ðñÿ6Oð¿&+p!LN±ãx±þç¢xæp*¿£p Ðþçcx±þç"bp"x*¿#pÐþçKˆ¨!2F­ø0ÿ÷ÿ H!2Fÿ÷ˆÿ2F Hiyÿ÷ƒÿ"#±¢pãpà"pcp8ˆÐñ8¿ °ð½ýÿýÿËéÿsýÿýÿ(k÷µ!LâxcxF*ýÑ+ýÑ#ãpcp&x£x+ýÑ.ýÑ%#"¨1Fø0ø ¥p%pøPøpÿ÷/þ¨1F*Fÿ÷*þÒ#ø0½BÐ! F ñÿ÷þ5 ñ!"ÿ÷þí²îç"#¢pãp"pcp°ð½ýÿsµ Låx±þç¦x".âpÐþç K¥pˆ›x­ø¨!ø0ÿ÷õý¦påp°p½¿ýÿ*ksµLex±þç&x#.cpÐþç"ø ø0ø#¨1F*F%pø0ÿ÷Ñý&pep°p½¿ýÿµ HFð5û,ÑHð0ûKx± ÿ÷Îÿàÿ÷«ÿ ½¿ o+oÊïÿsµLåx±þç¦x".âpÐþç#ø0ø#¨1F¥pø ø0ÿ÷”ý¦påp°p½ýÿ8µFF Hðøú¹ HðôúK Fpÿ÷ÑÿKx±`À²ÿ÷Œÿ 8½ao„oËéÿÈïÿ8µFFHðØú-ÑHðÓúKx{± HðÍú F!ðRû HðÆú Kx¢BÒpà Fÿ÷Ÿÿ 8½¿¾o+oÊïÿÜou“Àïÿ-é÷CLæx‰FF±þç§x%/åpÐþç#øø hF*F!ø0¦pøPøpÿ÷ý#ûñHFɲ*Fÿ÷+þ§pæp°½èðƒýÿµiFªð¿ÿHðxú˜ðSû(Øßèð  ÿ÷©þàÿ÷ìþà ÿ÷ÿà ÿ÷Bÿ àKh›ˆ© "­ø 0ÿ÷¦ÿ°]øû¿u“-k-éóGø0,Kø xø(pÝø,€øF ø$ –Bøø@ø`øpšF;ÐÙLex±þç”ø`p¹ñÐþçhF!*F%pÿ÷«ü@F9F*Fÿ÷ºý„øepšø0³BÙLåx%±àÿ.Ñøçþç”ø&¹ñæpÐþçhF!2F¥pÿ÷‰ü@F9F2Fÿ÷˜ý„øåp°½èð‡ËéÿýÿsµLbxãxF*ýÑ+ýÑ#cpãp"x£x*ýÑ+ýÑ%#%p¥pø0µBÐ! F ñÿ÷Zü5 ñ!"ÿ÷Süí²îç"#¢pãp"pcp°p½¿ýÿµiFªðõþ Hð®ùHð«ù˜ð†úÀ²(¿ ÿ÷¸ÿ°]øû¿u“üoµ! L H"þ÷û!Oôƒr Hþ÷ û!" Fþ÷ûK!€"£ø€ !p¡p£ø!½ýÿ6ýÿ üÿ>ýÿµHðrùHðoùÿ÷ÓÿKÿ"p½¿u“$pËéÿøµNNNIF$NH4pðÿMKp ±LKpLKMLhMMMOBô€b`hBôb`@ò"ÃøÐ/OôrÃøÔ/FKÏ2`OôQrZ`DKEJˆ pxQpCJCIxpˆBI pxAKBHpxZrAJ#põ€R€!p>Kpõ€Sp=KhBð`ZhBðZ`9J##pp€„7J`7Jp"*pEøî<5M/`õ€W/b«€«„ë€ë„ª`ªbë`ëb0K+a‚3+c/K€„Y€Y„YY…,Ioð ` b+KhAð`‚##p(I„#p # põ€Q p%I,# põ€Q p#KOô€1`Oô€!`2p½èø@ÿ÷*¿±ïÿŸq4kÊïÿËéÿ4€@@@ @Ð@Ìéÿ @²ïÿ  @°@°@@ @ @<€@@€@@@>ýÿ@@ €@  @ @áà-éøCF±(ÑWKàWK³ø€úˆøàOðàTHðrø#ø$0RK‚"û2F²ø€‰²ˆEð’€²ø€‰²É±‚"bCDJN°ø€‰²MÁñ€­² D ø€PŸ\3xÿ²s±8F!ðÓøAHðGøà€!ˆE¢ø€àÑ½èøƒ=Mø$0©F+ÃØßèð I3x±8Hð0ø·ñ_B_Aà3x±4Hð&ø/ ¿''ø$pDà3x±/Hðø/Ñ#ø$09à/Oê„ Ø"ø$ ëOöÿqWpQ€à"ø$ ëkx+Ñ©"F ÿ÷¿üà3xÛ±Hðóÿhx!ðxøà3x±Hðéÿ ë„KJx8FSø"01"F˜G± K"ø$ 3x+?ôg¯HðÓÿbç½èøƒ6@@tp>ýÿÁïÿzi6ýÿUp\pbphpnpÐéÿu“pµcKxFB¹bKx*±aJx¹xÿ÷Dþ_K`Jhh™BÐÃó @òÿqˆBÑ `ÿ÷Ôû#xC¹XKxÿ+ÑWKx ±ÿ÷üVKx+ð™€TL£x#¹”ø…0+AÑCàQN3x+öÑPKxPKðpx­¿%»±MHðmÿ!(FðòÿKHðfÿ!0xðëÿGHð_ÿ x!ðäÿEHðXÿ>Kxíí²-ÎТx:K*ÊÐxHDpÈx=I:pšp“ù *¼¿"p=çç8N3x;± ÿ÷±þ ½èp@ÿ÷¬¾3Kx,Kðpx­¿%ñ/Hð%ÿ!(Fðªÿ'Hðÿ!0xð£ÿ#Hðÿ”ø…!ð›ÿ Hðÿ!Kxíí²-ÎДø…K)ÉГøƒBDƒøƒ ø†`Hñÿ1H¿"pñÿ5ƒø…H¿ƒøƒ àçp½ÊïÿDñÿÉïÿœïÿ¬ïÿËéÿ°ïÿ±ïÿ üÿ @ @ÁïÿŸp@mu“ @°@°@«p°@µKxÿ÷]ýþ÷Éýþ÷©úK"€½¿DñÿÌïÿµKˆB€þ÷Eþÿ÷õþþ÷Dü ½¿ÌïÿpGK"€pGÌïÿµHð–þHð“þ !ðÿ$ Hð‹þ ²!ðÿ Hð„þ Kÿ Sø40F"4˜G ,ëѽ¿u“Rtwt§psµiFªð­û˜ðDÿKÀ²(¿ €°]øû¿|ðÿ-é÷C%F¨F©F'˜iFªð‘û˜x+YÐu¹K+ Ñ0ð!ÿ+K_ú€ùëÉFFyDÿ²Càðÿñö²¾Bø:Ñ"Hð-þ"Hð*þHFðYþ Hð$þ! xð©þHðþ!`xð¢þHðþ x!ð›þHðþ#JH™XB ÑHðþHðþHðþà3h+íÑRø90 xax¢˜G7F5¾Bí²Ò°Fœç°½èðƒsu“{t§pØt=GtÞtµ L H#xÓñ8¿##pðÑýHðÎý x½è@ðû½¿<ñÿu“%usµ$%F˜iFªðýú˜x ³,ÐL+Ñ0ðþŲàð‰þƲ Hð§ý Hð¤ý(FðÓý Hðžý0F!Fð#þK^U4ä²,ÕѰp½u“JuluO µ L H#xÓñ8¿##pðýHð|ý x½è@𩽿.ñÿu“suµ L H#xÓñ8¿##pðeýHðbý x½è@ð½¿0ñÿu“˜u-éøC+HßøÐßøÐ€*O*N+M+LðIý+HðFýHFðCý! ðÈý@Fð<ý%HðKú%Hð6ý8Fð3ý0x!ð¸ý(Fð,ý! ð±ý Fð%ý!V ðªýHFðý Fð£ý@FðýHð&ú8Fðýpx!ð–ý(Fð ý! ðý Fðý !½èøCð†½¿u“vO v0lÂußuõu4vwt§p8µDHDMðáüDHðÞü(xð-ýBHðØü$+x£B Ù?K"û3!˜xðUý4øà®EÑšBÑßøÌáZ.øPoKOðøàëE#kp“²à2Ò²âç1ɲÙç3€4ä²Áç$'FcKˆ¢B@òЀbMøÿ÷=þ(YÐ(ð¡€(MÑ]H5øàßøxëθøy#‹BßøhÁÒ<øÀ”E:Ð3Û²ôçK,ø Pø>¨ø0x!;±Oðû1ɲC\öçD–ø€øœFAEÐßøìàë œøHE ÑBHœøÀøàOð û€øÀ€øà1ɲ3äç#ZC9K!™T5ø {%ø ß²Ià3H5øPßøÌÀëżøy#‹BßøÀàÒ>øà–E6Ð3Û²ôçK.ø Pø5¬ø0x!3±%û1ɲC\÷çD–øÀøŒFaEÐMëžø@E ÑHžøà]]Oð û€øà…p1ɲ3çç#ZCK!™T4ä²LçÊïÿ/ñÿËéÿHþÿBñÿ1ñÿ0ñÿ§ |ðÿ¿y:ñÿ© €ðÿ˜„Jÿÿ~ðÿÎïÿ%€/F0KˆªBBÙ/K/Jø0ßøÌ€Oð ûùëƒ ø@Rø#0] ë4‘“ä²Oð ›ÛøšEÐë!K ]šSø1ÀPx‘x“ñàGÛø ›]ë ñ y3D_úŠúä²Þç ø@ ]“¹ ø05í²¸ç0x€ÿ÷pøJx#3pb± J Ip pàK3øz#øײæç°½èð¿~ðÿÎïÿ”}s.ñÿ>ñÿBñÿJÿÿµHIðŸüJ#pJpJ€JpJ€I"XZT! D®+ApöÑF H"TJpŠp3@ò“Bôѽ¤Í{.ñÿ0ñÿ|ðÿ/ñÿFþÿ© JÿÿV(-éøOFgØ5Lßø‘ëÀ ë@ 2Hð¥þ2Hð¢þ(Fðñþ.HðœþTø50x$f³4ä²#ûF´BØøpÒë !›øðÿ$Hð„þ8]!ð ÿ4 Hð|þä²›ø!ðÿþ´BáÒHðqþÝç>]±HðkþÑçHðgþøðµþHð`þ˜øð®þHðYþšø0+ÐÓ+нèøHàHàH½èøOðG¾½èø¿˜„u“ßyzn z zz/z¼zÅzGz© V(-é÷OFò—€LMMKOð ûùKDë€JH“ðþIHðþ FðcþEHðþUø$0x&Õ¹CHðþ>Iø ðSþ@Hðþý›!Xxð‚þ=Hðöý›˜x!°½èðOðw¾4F&Øø ßøð°ø!ðlþ3Hðàýø !;ø2ðbþ.HðÖýø0ÿ [ø30F"˜G)HðËý ë#ßø¬°:x ëÂyšBÙú!Px“ðCþ:x› ëÂ3y“BÚH“ð®ý›Û²âçHð¨ý;x ëÃ6yö²3D®Bä²ÒHðšý®B«ÑØø0]fö²-‡ÐHðŽý‚ç°½èð”}Jÿÿu“Oz zzz@mzvzxz¯Œn zsµ˜iFªð«ú˜x‹±R+ÐT+óÑ0ð;þÀ²ÿ÷¦þìç0ð4þÀ²ÿ÷)ÿåç°]øûKxKpKxKppG¿CñÿBñÿEñÿ>ñÿµHð8ýHð5ýKx½è@ða½¿u“L‹MëÿµHð$ýHð!ýKx½è@ðM½¿u“r‹=ñÿ7µ K"pF+xL+ ت˜iFðIúšx±#x3#pïç°0½CñÿµLiFªð8ú#˜#px±ðËý p°½AñÿµiFªð'ú˜ð¾ýKp°]øû¿Eñÿÿ)0µÑÿ(ÑHàKx#¹ H½è0@ðɼðý+ K Ñ L%xEð@%p¹(Ñ€0½ˆ€0½¿‹Mëÿ®‹ ?ñÿÿ)Ñÿ(ÑHð¥¼pG÷‹ÿ)0µÑÿ(ÑHàKx#¹ H½è0@ð“¼ðý+ K Ñ L%xEð %p¹(Ñp0½xp0½¿ ŒMëÿ%ŒX ?ñÿÿ)Ñÿ(ÑHðo¼ðYº¿lŒ"I#ST2*ùÑJ€JpJppGY  >ñÿX ÿ)µÑÿ(ÑH½è@ðJ¼L#x+±)Ñÿ÷Ùÿ##p½ŒMëÿÿ)8µ FÑÿ(ÑH½è8@ð1¼M+x+Ð,Ñÿ÷¿ÿ,p8½¿˜ŒMëÿÿ)pµÑÿ(ÑdH­àdL#x%Fðÿ±. Ðàðý+Ñ^K$pQ¹(Ñp½1¹(ð­€CXBXAà +xxðÿ±-!Ðp½ðàà+ ÑQK"„ðàúôxCpp½MJx+ÙLHtàh,ØYpJJÔTp½JHðØû F!dàðàà+Ñ„ð@KäCä²¥@x±Cà"êp9KxBðpp½#Û²-+Ø<ä².,Ø8K9J]]à"F/I xDð à¤ñ3Ò²h* Ø2I2K›\Š\(I xDð p1àñcÛ²+Ø,JÒ\!KxAðp##àñPÒ²-*Ø&I'K›\Š\I xDðáçD¹Kx½èp@Bðpÿ÷ ¿Hðrû F)Fð÷ûH½èp@ði»% ILúò(±à\CâT x+Dàà\ êâT x3 pp½¿±ŒMëÿ?ñÿ>ñÿBñÿÍŒY úŒŠcŽ’Žr3‰/Š6u“µð¹üHIðãø½è@ÿ÷½¾¿`Šì‰µKxFJ¹Kx+ØJ!ÑT3Û²÷çKx±ðæüùç Jp"xðÿ±(нKpàF½è@þ÷\¼MëÿBñÿY ?ñÿ>ñÿð¾ðh¾!C\ ±1ûçð•¾JK`pGú íàðµ K LxBðëÅ‚ðp` Hpx. ¿ˆ'È'†ðGêApDø5ð½ÔñÿàÿlòÿC+µØr¶ JRø#±AhBø#Jˆ2ø@a"øb¶½ ½¿´ñÿ’ 8( Ør¶KSø 0 ±0[hûçb¶pG pGòÿµr¶#JDø,Õ™JRø1@,¹ëC0X`K àAðRø1@d¹ëÁ0X` KBø10 Kx:pb¶½3 +ÙÑb¶K"p½è@𷽿zàÿˆ@È@bòÿC+0µ2ØJ@@ðDr¶Lâ\* Øßèð0"à0"àHJPø#@¹@ø#àRø#A`Bø#à"à"âTðñ ˆC` ¿ˆ#È#CêC`b¶0½àÿlñÿòÿ8òÿKJš\ø+J“BøÑJK`pGà@ó‚ü¿à@ú íà-éðG®Kxä²`Õ­Kx«±¬Jxðÿ)±;Û²p ¹ÿ÷Õÿ¨Jxðÿ)±;Û²p ¹ðôýŸK"pððÿ+ðƒžKŸLxÒ² Oê’@ðZ‚ëÇZhTø70Ãóƒ; +òL‚ßèðððJJJJJJ(JJJ hŽMRh+`j`J›²Dø7 ŒOJ!&³õ o9`!a¡apð¥+سõð:Ø‚+ð)Ø€+@ð‘‚L!pap•á³õ€Àð‰Hhá@ò2“B سõ@€ð/¢õ°r“B@ðzªˆxKaá@ò2“Bð$pá@ö!“BðCسõoðÀ€Ø£õÐc+òajˆ©ˆkK"á³õo@ðY]Kªx`NpxfKÒ²põ€xàBò!“Bðv Ø¢õ°R“Bð:õ€r“B@ð>ªx\K8áBò¡“Bð:€2“B@ð2ªxWK,á3jÕpj8ð~ü6FEõÑ&°Fßød‘Vø (±Ðø ðpüPFøçIøJKßøL‘ðPVø (±Ðø ðaüPFøçEKIøðPDK#øCKø :*Øßèð"à"ø ñ¸ññÈÑ9K"p&™F8J8K2D3Dø,›ðpOê†%Ððü8±ëF0X`0KDø80à™ø0Dø83‰ø0ðþûHð8±ëÃ0P`JDø3 àDø3™ø03‰ø0Hð6Hð! .Dø3Dø8ÀÑ­àK Lx1F#pªà¿€ @kòÿÕñÿnòÿ @àÿXòÿÈ@Hñÿlòÿcòÿ¼DñÿMëÿ|òÿLñÿ8òÿ’ lñÿbòÿz0Ȉ@´ñÿòÿ«ˆ+hØLšK!pap›\šiÕ&pgૈð*YÜiˆ)VÑš”KDx"ðMà’H/ૈð*HÜiˆ)EÑšŒKDxBð<à3ø l–BÐ 3SøL£ñ ,ôÑ2à3ø lŽBóÑ * ¿!x‰2à+y+RÙ~Hð!ø¨ˆ1Fð¦ø|Hðøà3ø °õ_Ð 3SøL,õÑà3ø BõÑ3øàjˆqK pqKpàpàiK"p(à!mLà Fà!B8¿F@.4¿5F@% F)Fÿ÷ ýv,DÑ@-Ñ5Fà@.4¿5F@% F)Fÿ÷ûüv,DÑ@-Ñ[K<`€"ZKXàZM+ˆBò!‹BÑ#Ð\SIXT3+ùÑ x†+ÑSK"p à@ö!‹BÑkˆ›Õ(y ±( ÑRxLKîçxJKpFÿ÷Çü à>Hð¡ÿ¨ˆ!ð&øùF(êÐ àx2±"‹Hp½èðAð÷½û÷†ÿÏç…M+xšÕ…K†NxK±…Hðéý0x!ðnþƒHðâý2x##r#€br !Fÿ÷…û+x#ð àà[ÕwKzNxK±zHðÌý0ˆ!ðQþtHðÅý2ˆ#br #r#€¢r !Fÿ÷fû+x#ð@Áà3xðÿ±.EнèðdKjOxc³iHð§ý!8xð,þgHð ý0F!eNð$þcHð˜ý0x!ðþpx!ðþ°x!ðþðx!ðþ0y!ð þpy!ð þWHð}ý;xTI#r&"frñ û÷ûþ##€ !Fÿ÷û.p½èðBKxF±KHðcý+x+lÐ3xCO+6Ð8x!ðáýAHðUý&ßø!ø6ðÕý.õÑ:HðGý&ë!˜y6ðÈý.öÑ4Hð:ý3K!}ð¾ý0Hð2ý&ë!X}6ð³ý.öÑ+Hð%ý;x(Icr FOð&„ø€" ø kû÷Ÿþ"ˆ$I F2 ø+"û÷–þ"ˆ!I F2 ø+BFû÷þ"ˆI FBD ø+"û÷„þ#ˆ3#€0F!Fÿ÷¡ú#+p½èð¿kòÿT‘Mëÿmòÿ?ñÿ‘AñÿX °‘¹‘ ¾‘>ñÿÈ‘ziY u“æ‘_ m n r¶ Jh±úó+Ùb¶ pGOð@Ø@!ê`b¶IH"SCÈ"ÊPB`pG¿ïÿ áÿ KH"óûòó+Ø Jx"± Jx ±ÿ÷ ºr¶JOðA!úóhC`b¶pG áÿbòÿkòÿïÿµL#hk± hBˆSDzˆ“BÓÿ÷Ðÿ K"` àKx¹Oðÿ0½ ÿ÷­ù `(åÑõçC€ F½xòÿkòÿK؈Kh±ˆ[ˆÓDpG’ xòÿ-éøC-N#F F3p,OÐ+M+h©F+»Gò X)Kxðÿ ¹2pà ÿ÷—ù(Ø#3pÿ÷mÿÉø€¹Kp¸ñKÐx*±"pOðÿ0½èøƒû÷±ýÛç)hJHˆ#pÀñ@”B8¿"Fñ DŒDH€¤“BÐø\ ø3øçDKˆ?+Ù@# € ÿ÷«ù#+`K"p­ç4p F½èøƒ¿oòÿpòÿkòÿtòÿnòÿ8µKxðÿ«¹ L!h1±Kˆ €ÿ÷ˆù%`8½ÿ÷ÿF ± ½è8@ÿ÷}¹K"p8½¿oòÿpòÿnòÿHðû¿Í’µHð¼ûHð¹ûH½è@ð´»u“tÞtHð«»¿Ö’-éðA$!Kx£B<Ù HðžûKSø$ð™ûHð–û';²Nš­Vø$0YY!³HJKðmûVø$0XYð„ûÀñ _ú€ø¸ñÐHñÿ8ðvû_úˆøôçVø$0D7hhðlû Hðiûÿ²Ñç4ä²¾ç½èðƒòÿÙ’÷ÿã’Ôöÿê’v’ziu“Kx€ðp𻿂òÿÿ÷\¸µ!Hð>û Hð;û Hð8ûHð5ûHð2ûHð/ûHð,ûHð)ûHð&ûHð#ûHð ûHðûHðûHðûHðûK!hðÍûK!hðÈûK!hðÃûK!h½è@ð¼»u“ñ’4“U“x“¼“ð“.”b”˜”¶”Þ”•%•y•T€@X€@\€@`€@µ L H#x3±ðÑúHðÎú#àðÊúHðÇú##p½€òÿu“’•Á•0µF0#x +úÐF0xðßùÑø[ ``0½-éðA"Kxˆ°+=Ð!M$(F©ªìTÿ÷ßÿ¨FKx£BÙ&3²Mš¿Uø$0ÙYq±˜ðRû0ÑUø$0˜D»h˜Gà6ö²çç4ä²ßçL FðvúKÍø€“ K”“ K H“ KI“JKðKú°½èð(÷ÿlöÿƒòÿÔöÿu“Œnÿ•–ï•’ò•vù•µ Jx +ÙH½è@ð>ºLDø#YpJBø#½¿ƒòÿ/–÷ÿÔöÿKHµ$pKpKpKpðú Hðú K H Ipÿ÷ÎÿðÞù Kp Kp½¿(÷ÿt–Ñöÿòÿüöÿz–ƒòÿX—Z˜‚òÿ€òÿ-é÷O(M+x+IÐ'O$8FiFªüTÿ÷.ÿ F&F#Kx£B#ÙOð ú‰óßøˆ°šOêÂë [ø$0Sø ±˜ðšú8¹[ø$0ñSø `_úˆø ñ _ú‰ùàç4ä²×ç¸ñÑ#H+pð¸ù Hðµù0Fþ÷Äþø;3±+xZ*pø,úTõç°½èð¿(÷ÿlöÿƒòÿt–z–ÔöÿRˆBñÚ “ûòó3û@ûòóûDpG J K8±x Id"û2 x#àxd!JC˜TpG‹BÚH\ÐT3øçpGüöÿ„òÿ(÷ÿlöÿ Kpµd$ Mû4& H.pð[ù HðXù Fþ÷gþ3FÚ²Yã\±HƒT F÷ç*pp½„òÿ(÷ÿt–z–löÿøµtM,xþ÷Iþ ±þ÷Hþ+xpNc+À²ÙoHð0ùnHð-ù#3p>àZ2pkJÐTççkKx ³+x£BÙiHðùhHðù#F*xšB ÙbJ^Ð\!ð˜ùö²bHð ù3FðçaH&à0Ø*&Ñ+Ñ#+p+xTO£B@ò£€UI ] *FîÑD "+ø,!Ñ#MH+pðëøSHðèøRH½èø@ðã¸;PH+pðÞøÜç *zÑÿ÷áþ;x;;pø½*)Ð*ÌÐ *nÑ×çÿ÷"þ=Hÿ÷CÿEKEJxx¡BÒ4 ”ûðöû@p1ɲ )Ðpà!p!px;Jpd"SC:J!ÑT¸ç¥BMÚ [x[+IÑK]A+"Ñ2O/K—ù xšBÑ#F Uÿ÷ ÿ—ù! "8ÿ÷ôþ'KFx!8 "ÿ÷ìþ„B¿#Kp—ùÿ÷ÿs]B+ ÑM•ù! "0ÿ÷ÙþKFx!0 "ÿ÷Ñþ„B¿,p•ù½èø@ÿ÷ú¾"04ÊTä²þ÷kýWçø½¿(÷ÿu“ˆ–löÿ€òÿß–å–ziê–t–z–î–üöÿÑöÿòÿ„òÿKhBô"`KOô¢r`pGð@L@±KàKhBô"`pG¿ð@ð@´µ«Sø “x3±þ÷"ý›’höçCx+õуx+òѰ]øë°pGþ÷½FF3x)úÑ€²pGµFÿ÷óÿ"CšBÚ¡\à\ TáT2;öç½0µF" %³ûõðû303T‹Tðÿä²Ð"Fñç UF½è0@ÿ÷Ù¿µ©ÿ÷åÿ¨þ÷Ùü°]øû0µF" %³ûõôû303P‹T£²€² ±Fòç T½è0@Fÿ÷¹¿µiFÿ÷æÿhFþ÷¹ü°]øûpµ$ð -Œ¿7&0&c5D ›² UÐFñç* Ð* Ð*Ñx"ÊTã4¤²0"›² Uà“BÒX0$ÌTƒ²øç"ÊTF½èp@ÿ÷‚¿µ FiFÿ÷ÎÿhFþ÷ü°]øûpµ$ð -Œ¿7&0&5D ñ UÐFñç* Ð*Ð* Ñx"ÊTã D0"¢pà“BÒ0 ÈT3ùç"ÊTF½èp@ÿ÷M¿µ FiFÿ÷ÑÿhFþ÷Lü°]øûµFø+"±øK”BFöÐø ø,B¿xOöÿp²½pµF %& Fø;“±++ F ÐØ + Ðà-+Ðx+ÐFàOðÿ6à%Fèç -Ð-"ÑF!à!‚BFÙøL0<û3 $:aCóçø-9*Ø0:û3 „BõØàF*Ø7:õçf*õØW:ñçûðp½NMI! Hard Fault! SCB_HFSR: Memory Manager Fault! SCB_CFSR: SCB_MMAR: Bus Fault! SCB_CFSR: SCB_BFAR: Usage Fault! SCB_CFSR: ÿRESET TO LOADERÿèýWrite to given register page starting at address. i.e. 0x2 0x24 0xF0 0x12Test out the led pages.ÁeúfAÉesg¹ÑefýÙeÜcâeúcÁëeVc™óe cÉüeÉf9Read the given register page.Disable software shutdown.DEBUG - DATA: WARNING - I2C_BufferPush failed, buffer full: ERROR - No buffer to pop an entry from... ERROR - I2C NAK detected... ERROR - Arbitration lost... ERROR - Slave Address I2C NAK detected... DEBUG - Attempting to read byte - DEBUG - NEXT INFO - Sending: | LED_control_capability(mode,amount,index)i2cRecvi2cSendledCtrlledRPageledStartledTestledWPageledZeroBasic LED control. Args: []è$ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿZero out LED register pages (non-configuration).Send I2C sequence of bytes and expect a reply of 1 byte on the last sequence. Use |'s to split sequences with a stop.Send I2C sequence of bytes. Use |'s to split sequences with a stop.èÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿISSI LED Module CommandsEnables matrix debug mode, prints out each scan code. If argument T is given, prints out each scan code state transition.INFO - Matrix Debug Mode: INFO - Columns: INFO - Rows: INFO - Max Keys: OPHRIERROR - Matrix scan bug!! Report me! INFO - Max scans: INFO - Previous scans: INFO - Scan Number: : 0x: 0xmatrixDebugmatrixStatePrints out the current scan table N times. O - Off, P - Press, H - Hold, R - Release, I - InvalidMatrix Module Commandsjäg!j-jñ·pÂpÌpÚpãpìpöpqq q4r)++q”ký!6q r½,Aqmq9#Lq»qÙ$Wqùq=-bq³k‘#Toggle UARTConnect debug mode.UARTConnect status.DEBUG - Animation INFO - Connect Debug Mode ToggleDEBUG - PENDING SET -> WARNING - Cable Fault! Slave Master DEBUG - CABLECHECK RECEIVE - INFO - List of UARTConnect commandsMasterSlaveINFO - UARTConnect Status Device Type: Device Id: Max Id: Master <= Status: Faults: / Rx: Tx: Slave <= Status: INFO - Setting device as slave.INFO - Setting device as master.WARNING - Too much data to send on UART, waiting... +ERROR - Invalid ScanCode direction... WARNING - Not enough interconnect layout nodes configured: DEBUG - ERROR - Too big of a command to fit into the buffer...ERROR - Invalid UART to send from... DEBUG - IdRequest ERROR - Invalid IdRequest direction... DEBUG - IdEnumeration ERROR - Invalid IdEnumeration direction... DEBUG - IdReport INFO - Id Reported: INFO - Sending Sync Idles...INFO - Resetting UARTConnect state... Wait SYN SOH ### CMD ERROR - Invalid UARTStatus...TxFIFO 0 - TxFIFO 1 - CableCheckIdRequestIdEnumerationIdReportScanCodeAnimationRemoteCapabilityRemoteOutputRemoteInputconnectCmdconnectDbgconnectIdlconnectLstconnectMstconnectRstconnectStsLists available UARTConnect commands and index idUARTConnect Module CommandsSets the device as master. Use argument of s to set as slave.Resets both Rx and Tx connect buffers and state variables.Sends a command via UART Connect, first arg is which uart, next arg is the command, rest are the arguments.Sends N number of Idle commands, 2 is the default value, and should be sufficient in most cases. +/  ,YÕ8ý8%9­8…8yF=GG±GÑFåFåG  N â áN?   # @ 1 vR "Send key-release event to macro module. Duplicates have undefined behaviour. S10 Scancode 0x0AEG K8 INFO - Capabilities List INFO - KWARNING - flashModeEnabled not set, cancelling firmware reload... INFO - Set flashModeEnabled to 1 in your kll configuration.INFO - Layer Debug Mode: INFO - Setting Layer L to - INFO - Macro Debug Mode: INFO - Macro Processing Mode: INFO - Layer ListD: KType + stdFuncMap (default) Layer State: First -> Last Indices: 1: INFO - Pending Key Events: : INFO - Pending Trigger Macros: INFO - Pending Result Macros: INFO - Trigger Macros Range: T0 -> TINFO - Result Macros Range: R0 -> RINFO - Trigger : Result Macro Pairs T : RDEBUG - Layer 0Macro_layerState(layerIndex,layerState)Macro_layerShift(layerIndex)Macro_layerLatch(layerIndex)Macro_layerLock(layerIndex)Macro_layerRotate(previous)ERROR - Scan Code has no defined Trigger Macro: ERROR - Invalid key state - ERROR - Invalid type - WARNING - ScanCode is out of range/not defined - WARNING - ScanCode is out of range/not defined: ERROR - LED State Type - Not implemented... ERROR - Analog State Type - Not implemented... ERROR - Invalid State Type. This is a bug. DEBUG - Macro Step INFO - Trigger Macro Index: |; Position: Result Macro Index: Trigger Macro State: WaitingINFO - Result Macro Index: (, Final Trigger State (State/Type): capListcapSelectkeyHoldkeyPresskeyReleaselayerDebuglayerListlayerStatemacroDebugmacroListmacroProcmacroShowmacroStep DPause/Resume macro processing.  ç ! Send key-press events to the macro module. Duplicates have undefined behaviour. S10 Scancode 0x0AMacro Module Commands RCK Layer debug mode. Shows layer stack and any changes. /  : à%L O ! Show the macro corresponding to the given index. T16 Indexed Trigger Macro 0x10, R12 Indexed Result Macro 0x0C QSHL>$& (F> € ‰Ç€s·€žsØ‚7|ö{<a|`„Àƒh„½‚@t¹s€Nt {_ˆ4ìˆÕ€´sÆ‚T|}‡yˆøˆ|‰¿€/|Ásˆsšs¢sŒä‚L{Dƒè{é|;|̓]|\„ì!LˆEuˆ3|€s8ôˆ€‰ŒsɃ¦scˆ¸s„sL‚à‚ðˆÜ‚у{„d„N}Wƒð~8ˆH{@ƒèüˆX‰Ã€ s»€ æP U9 % 7H 0 Q  8:I "36*,/#&MP BD:=1 & JUìéÿßuVHëÿ4v * =D;Modify specified indexed layer state . L2 Indexed Layer 0x02 0 Off, 1 Shift, 2 Latch, 4 Lock States ) 6 ã 3 HM< EGJ')List available layers. 7  B C? E(0Ÿz|ƒõ2§z‡u3±zP‚Á;¹z_{ï;ÂzÅs<Ízú{q4Øz-}5âz0€¥4íz „5øz‡ˆ]6{${I5 {e|ME{߃M3 'Send key-hold events to the macro module. Duplicates have undefined behaviour. S10 Scancode 0x0A G  $1I  P ä åBS*A579.0%   T+ ORTFPrints an indexed list of all non USB keycode capabilities.<  I  45=Do N macro processing steps. Defaults to 1.Disables/Enables sending USB keycodes to the Output Module and prints U/K codes.  F > L6  .€I}DDt<ˆ@pˆ• D} q„ W} s ô~C{è‚P{Hƒì{‰&€)‰X|Á‚¸‡%PˆI}ˆò‚Z{Rƒ Ë€!s"ü€#s$\%ªs&š'$‰(‰)(*ñ{+ă,D|-Õƒ.í|/l„0R}1/2Zˆ3S4‚ˆ5´6Ôˆ7ð8‰9!€:‡;•s<l=¯s>Ÿ?¼s@Ê‚AItBí‚CU{DMƒEÚƒFü|Gv„H\}Ix‡Jù~K½‡L*MUˆNNOõP ‰Q+€R.‰SЀT?|UV  V2' AV(+-!$.Triggers the specified capabilities. First two args are state and stateType. K11 Keyboard Capability 0x0B ?" 5@Q  M4# 9 A2List the defined trigger and result macros.KN@C38; , -   ;4 ) O  < J-Keyboard Protocol Mode: 0 - Boot, 1 - OS/NKRO ModePrepare a space separated list of USB codes (decimal). Waits until sendKeys.USB Module CommandsÐc‰±EÜ Ž5Fè#ŽÙEñ´ŠEú–‰FŽëŠYFSend the prepared list of USB codes and modifier byte.Set the modfier byte: 1 LCtrl, 2 LShft, 4 LAlt, 8 LGUI, 16 RCtrl, 32 RShft, 64 RAlt, 128 RGUIINFO - Keyboard Protocol: INFO - LED State: Output_consCtrlSend(consCode)WARNING - Consumer Control is not implemented for Boot Mode Output_noneSend()Output_sysCtrlSend(sysCode)WARNING - System Control is not implemented for Boot Mode Output_flashMode()Output_kbdProtocolBoot()Output_kbdProtocolNKRO()Output_usbCodeSend(usbCode)WARNING - USB Key limit reached WARNING - USB Code above 104/0x68 in Boot Mode: WARNING - USB Code not within 4-49 (0x4-0x31), 51-155 (0x33-0x9B), 157-164 (0x9D-0xA4), 176-221 (0xB0-0xDD) or 224-231 (0xE0-0xE7) NKRO Mode: kbdProtocoloutputDebugreadLEDssendKeyssetKeyssetModToggle Output Debug mode.Read LED byte: 1 NumLck, 2 CapsLck, 4 ScrlLck, 16 Kana, etc. Bîÿ°ìÿÈGñÿ Fñÿ"öîÿ?!Âìÿ "Nëÿ}!Ûìÿ "xíÿv!6íÿ "ËëÿU!Oíÿ "îíÿ5!híÿ 6ïÿ îÿ ¢îÿ :ïÿ $îÿ ’ìÿ Tîÿ  ìÿ lìÿ  Xìÿ  zìÿWARNING - CLEAR_FEATURE - Device/Interface WARNING - SET_FEATURE - Device/Interface WARNING - Unknown interface - ERROR - USB not configured... WARNING - USB Transmit Timeout... SysCtrl[] ConsCtrl[DEBUG - Boot USB: DEBUG - NKRO USB: You're looking at it :PSends a software restart, should be similar to powering on the device.Clear the screen.Signals microcontroller to reflash/reload.Version information about this firmware. c   Revision: 7b7a55899f392ebb7f615fd1801aaaa3dcc3f738 Branch: master Tree Status: Clean Repo Origin: https://github.com/kiibohd/controller.git Commit Date: 2015-10-18 17:54:41 -0700 Commit Author: Jacob Alexander Build Date: 2015-11-12 14:20:55 +0000 Build OS: Linux-4.1.5-x86_64-linode61 Architecture: arm Chip: mk20dx128vlf5 CPU: cortex-m4 Device: Keyboard Modules: Scan(KType) Macro(PartialMap) Output(pjrcUSB) Debug(full) Unique Id: INFO - Hex debug mode disabled... INFO - Hex debug mode enabled... RROR"" is not a valid command...type helpERROR - Max number of dictionaries defined already...  : ERROR - Serial line buffer is full, dropping character and resetting...   clearcliDebughelpledreloadresetrestartversionResets the terminal back to initial settings.ò–g’Xø–k˜yZ—’ÙX—Ä—Y —y’©X—'—ÍX— ’¡Y—¤’¥YEnables/Disables indicator LED. Try a couple times just in case the LED is in an odd state. Warning: May adversely affect some modules...General CommandsEnables/Disables hex output of the most recent cli input.)÷ÿ,çøÿ   ÿ)"µ)-*m* &í!‘'ô|} }}}$},}4}<}d}l}t}|}„}Œ}dlt|„Œ”œ¤¬ÀÈ8tÐØàÜ€ä€ì€ô€ LT\dL|t„ø‚ƒƒƒƒ ƒ(ƒ0ƒ8ƒ\ƒdƒlƒtƒÐ‚¸ƒ€„ˆ„„DˆP‡X‡`‡h‡p‡hˆˆ‡‡˜‡ ‡¨‡°‡´ˆ¼ˆÄˆÌˆ0t܈äˆä{} ¡…u•)‘u•‘u•%à)çu•.%)1u•u•i%3)›u•u•%)¤u•.%°)Ýu•À ¡%u•  ) %5F;u•e 9B ¡&ÿu • 0 1 2 5À&ÿu • 6 6À6Virtual Serial Port - DataJoystick MouseMedia KeysNKRO Keyboard È ú  !"?  !"}‚@  $$$$ƒ@  @…@  !"v†  !"U‡  !"5ˆ ¡ ¡ ¡ )%u•u• 0 1%u•¡ H%5Eu•¤± 8%5EuÀ¡ H´±5Eu± 8%uÀÀÀÀ €¡…u•&·)·À ¡…u•& *ÀBoot Keyboard@M°:Virtual Serial Port - StatusKiibohdRKeyboard - KType PartialMap pjrcUSB full ¡u•à)ç%u•u•)‘u•‘u•%)À RClean master - 2015-10-18 17:54:41 -0700ÿÿÿÿáÿÿ°UFD0U5fwupd-0.7.0/data/tests/dfu/metadata.dfu000066400000000000000000000000431267747510300177650ustar00rootroot00000000000000amaliaMDkeyvalueÿÿÿÿÿÿUFDXÄÞfwupd-0.7.0/data/tests/get-nonfree.sh000077500000000000000000000007251267747510300175060ustar00rootroot00000000000000rm *.rom wget http://www.techpowerup.com/vgabios/375/Asus.9800PRO.256.unknown.031114.rom wget http://www.techpowerup.com/vgabios/133037/Asus.HD7970.3072.121018.rom wget http://www.techpowerup.com/vgabios/148214/Asus.R9290X.4096.131014.rom wget http://www.techpowerup.com/vgabios/74257/Asus.GTX480.1536.100406_1.rom wget http://www.techpowerup.com/vgabios/162406/Asus.GTX980.4096.140905.rom wget http://www.techpowerup.com/vgabios/157835/Asus.TitanBlack.6144.140212.rom fwupd-0.7.0/data/tests/pki/000077500000000000000000000000001267747510300155155ustar00rootroot00000000000000fwupd-0.7.0/data/tests/pki/GPG-KEY-Linux-Vendor-Firmware-Service000077700000000000000000000000001267747510300340752../../pki/GPG-KEY-Linux-Vendor-Firmware-Serviceustar00rootroot00000000000000fwupd-0.7.0/data/tests/rpiboot/000077500000000000000000000000001267747510300164105ustar00rootroot00000000000000fwupd-0.7.0/data/tests/rpiboot/start.elf000066400000000000000000000004761267747510300202440ustar00rootroot00000000000000junkVC_BUILD_ID_USER: dc4VC_BUILD_ID_TIME: 14:58:37VC_BUILD_ID_BRANCH: masterVC_BUILD_ID_TIME: Aug 3 2015VC_BUILD_ID_HOSTNAME: dc4-XPS13-9333VC_BUILD_ID_PLATFORM: raspberrypi_linuxVC_BUILD_ID_VERSION: 4b51d81eb0068a875b336f4cc2c468cbdd06d0c5 (clean)junkfwupd-0.7.0/data/tests/rpiupdate/000077500000000000000000000000001267747510300167275ustar00rootroot00000000000000fwupd-0.7.0/data/tests/rpiupdate/Makefile.am000066400000000000000000000013711267747510300207650ustar00rootroot00000000000000test_files = \ firmware.bin \ rpi-firmware-20150805.cab firmware.bin: $(srcdir)/*.elf $(srcdir)/overlays/* $(srcdir)/README $(AM_V_GEN) tar -cf $@ \ $(srcdir)/README \ $(srcdir)/*.elf \ $(srcdir)/overlays/*.dtb rpi-firmware-20150805.cab: firmware.bin firmware.inf firmware.metainfo.xml $(AM_V_GEN) touch -c -m -d"2000-01-01T00:00:00" $?; \ $(GCAB) --create --nopath $@ \ $(builddir)/firmware.bin \ $(srcdir)/firmware.metainfo.xml \ $(srcdir)/firmware.inf BUILT_SOURCES = \ firmware.bin \ rpi-firmware-20150805.cab CLEANFILES = \ $(BUILT_SOURCES) EXTRA_DIST = \ $(test_files) \ firmware.inf \ firmware.metainfo.xml \ overlays/test.dtb \ start.elf -include $(top_srcdir)/git.mk fwupd-0.7.0/data/tests/rpiupdate/README000066400000000000000000000000001267747510300175750ustar00rootroot00000000000000fwupd-0.7.0/data/tests/rpiupdate/firmware.inf000066400000000000000000000007241267747510300212440ustar00rootroot00000000000000; Copyright (C) 2015 Richard Hughes [Version] Class=Firmware ClassGuid={f2e7dd72-6468-4e36-b6f1-6488f42c1b52} [Firmware_CopyFiles] firmware.bin [Firmware_AddReg] HKR,,FirmwareId,,{c77029fe-ffb2-3706-dc67-67af4a132afd} HKR,,FirmwareVersion,%REG_DWORD%,0x0000000 HKR,,FirmwareFilename,,firmware.bin [Strings] Provider = "Raspberry Pi Foundation" MfgName = "Raspberry Pi" FirmwareDesc = "Raspberry Pi Firmware" DiskName = "Firmware for the Raspberry Pi" fwupd-0.7.0/data/tests/rpiupdate/firmware.metainfo.xml000066400000000000000000000014711267747510300230710ustar00rootroot00000000000000 c77029fe-ffb2-3706-dc67-67af4a132afd Raspberry Pi Device Update Firmware for the Raspberry Pi

Updating the firmware on your Raspberry Pi device improves performance and fixes reported bugs.

https://www.raspberrypi.org/ CC0-1.0 proprietary Raspberry Pi Foundation

This release fixes device startup when running in FIXME mode.

fwupd-0.7.0/data/tests/rpiupdate/overlays/000077500000000000000000000000001267747510300205735ustar00rootroot00000000000000fwupd-0.7.0/data/tests/rpiupdate/overlays/test.dtb000066400000000000000000000000001267747510300222330ustar00rootroot00000000000000fwupd-0.7.0/data/tests/rpiupdate/start.elf000066400000000000000000000004761267747510300205630ustar00rootroot00000000000000junkVC_BUILD_ID_USER: dc4VC_BUILD_ID_TIME: 00:00:00VC_BUILD_ID_BRANCH: masterVC_BUILD_ID_TIME: Aug 5 2015VC_BUILD_ID_HOSTNAME: dc4-XPS13-9333VC_BUILD_ID_PLATFORM: raspberrypi_linuxVC_BUILD_ID_VERSION: 4b51d81eb0068a875b336f4cc2c468cbdd06d0c5 (clean)junkfwupd-0.7.0/docs/000077500000000000000000000000001267747510300136075ustar00rootroot00000000000000fwupd-0.7.0/docs/Makefile.am000066400000000000000000000002011267747510300156340ustar00rootroot00000000000000SUBDIRS = \ libdfu \ libfwupd \ man EXTRA_DIST = \ dfu-metadata-store.md -include $(top_srcdir)/git.mk fwupd-0.7.0/docs/architecture-plan.svg000066400000000000000000001046451267747510300177540ustar00rootroot00000000000000 image/svg+xml fwupd ESRT VendorProvders Udev systemd pending.db session system fwupdmgr downloadcache Internet Gudev + rules sqlite $home gnome-software UpdateMetadata() GetDevices() sysfs metadata firmware AppStream XML fwupd-0.7.0/docs/dfu-metadata-store.md000066400000000000000000000152451267747510300176260ustar00rootroot00000000000000 DFU File Format - Metadata Store Proposal ========================================= Introduction ------------ The DFU specification version 1.1 defines some target-specific data that can optionally be included in the DFU file to ease firmware deployment. These include items such as the runtime vendor, product and device release, but nothing else and with no provision for extra metadata. The DFU file specification does not specify any additional data structures allowing vendors to include additional metadata, although does provide the chance to include future additional data fields in the header in a backwards and forwards compatible way by increasing the `header_len` value. All software reading and writing DFU-format files should already be reading the footer length from the file, rather than assuming a fixed footer length of 0x10 bytes. This ensures that only the raw device firmware is sent to the device and not any additional data fields added in future versions of the DFU specification. There are valid reasons why we would want to add additional metadata into the distributed DFU file. Reasons are listed as follows: * Legal compliance, to tag a file with copyright and licensing information * Business-specific metadata, for instance the SHA-1 git commit for the source * Cryptographic information such as a SHA-256 hash or a detached GPG signature Although the original authors of the specification allowed for future additions to the specification, they only allowed us to extend the footer by 239 bytes as the `header_len` value is specified as just one byte, and 16 bytes are already specified by the specification. This would explain why some vendors are using vendor-specific file prefix data segments, for instance the DfuSe prefix specification from ST. This specification is not aiming to expand or standardize the various incompatible vendor-specific prefix specifications, but tries to squeeze the additional metadata into the existing DFU footer space which is compatible with all existing DFU-compliant software. Specification ------------- An additional structure would be present after the binary firmware data, and notionally contained within the DFU footer itself, although specified as a seporate object. The representation in memory and on disk would be as follows: uint16 signature='MD' uint8 number_of_keys uint8 key(n)_length ... key(n) (no NUL) uint8 value(n)_length ... value(n) (no NUL) If there are no metadata keys being set, it is expected that the metadata table signature is not be written to the file, and that the footer should be again 0x10 bytes in length. The signature of `MD` should also be checked before attempting to parse the metadata store structure to ensure other vendor-specific extensions are not already in use. The key and value fields should be parsed as UTF-8, although in the pursuit of space minimisation ASCII values are preferred where possible. Example ------- The following table shows an example firmware file with the payload 'DATA' set with vendor 0x1234, product 0xABCD and no metadata table. neg. offset description byte ---------------------------- 13 firmware'D' 0x44 12 firmware'A' 0x41 11 firmware'T' 0x54 10 firmware'A' 0x44 0f bcdDevice 0xFF 0e bcdDevice 0xFF 0d idProduct 0xCD 0c idProduct 0xAB 0b idVendor 0x34 0a idVendor 0x12 09 bcdDFU 0x00 08 bcdDFU 0x01 07 ucDfuSig'U' 0x55 06 ucDfuSig'F' 0x46 05 ucDfuSig'D' 0x44 04 bLength 0x10 03 dwCRC 0x52 02 dwCRC 0xB4 01 dwCRC 0xE5 00 dwCRC 0xCE The following table shows a second firmware file with the same payload but with the addition of a metadata table with a single metadata pair of `test=val`: neg. offset description byte ---------------------------- 1f firmware'D' 0x44 1e firmware'A' 0x41 1d firmware'T' 0x54 1c firmware'A' 0x44 1b ucMdSig'M' 0x4D 1a ucMdSig'D' 0x44 19 bMdLength 0x01 18 bKeyLen 0x04 17 KeyData't' 0x74 16 KeyData'e' 0x65 15 KeyData's' 0x73 14 KeyData't' 0x74 13 bValueLen 0x03 12 ValueData'v' 0x76 11 ValueData'a' 0x61 10 ValueData'l' 0x6c 0f bcdDevice 0xFF 0e bcdDevice 0xFF 0d idProduct 0xCD 0c idProduct 0xAB 0b idVendor 0x34 0a idVendor 0x12 09 bcdDFU 0x00 08 bcdDFU 0x01 07 ucDfuSig'U' 0x55 06 ucDfuSig'F' 0x46 05 ucDfuSig'D' 0x44 04 bLength 0x1C 03 dwCRC 0x1B 02 dwCRC 0x25 01 dwCRC 0x6D 00 dwCRC 0xF5 Conclusions ----------- The metadata store proposal allows us to store a small amount of metadata inside the DFU file footer. If the original specification had included just one more byte for the footer length (for instance a `uint16`, rather than a `uint8`) type then I would have proposed a key type allowing integers, IEEE floating point, and strings, and also made the number of keys and the length of keys much larger. Working with what we've been given, we can support a useful easy-to-parse extension that allows us to solve some of the real-world problems vendors are facing when trying to distribute firmware files for devices that support in-the-field device firmware upgrading. Several deliberate compomises have been made to this proposal due to the restricted space available: * The metadata table signature is just two bytes * The number of keys is limited to just 59 pairs * Keys are limited to just 233 chars maximum * Values are limited to just 233 chars maximum * Types are limited to just strings (which can includes empty strings) * Strings are written without a `NUL` trailing byte * The metadata table uses variable offsets rather than fixed sizes The key-value length in particular leads to some other best practices: * A value for the 'License' key should be in SPDX format, NOT the full licence * A value for the 'Copyright' key should just be the company name The author is not already aware of any vendors using this additional data area, but would be willing to work with any vendors who have implemented a similar proprietary extension already or are planning to do so. fwupd-0.7.0/docs/libdfu/000077500000000000000000000000001267747510300150545ustar00rootroot00000000000000fwupd-0.7.0/docs/libdfu/Makefile.am000066400000000000000000000063111267747510300171110ustar00rootroot00000000000000# This is a blank Makefile.am for using gtk-doc. # Copy this to your project's API docs directory and modify the variables to # suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples # of using the various options. # The name of the module, e.g. 'glib'. DOC_MODULE=libdfu # Uncomment for versioned docs and specify the version of the module, e.g. '2'. #DOC_MODULE_VERSION=2 # The top-level XML file. DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml # Directories containing the source code. # gtk-doc will search all .c and .h files beneath these paths # for inline comments documenting functions and macros. # e.g. DOC_SOURCE_DIR=$(top_srcdir)/gtk $(top_srcdir)/gdk DOC_SOURCE_DIR=$(top_srcdir)/libdfu # Extra options to pass to gtkdoc-scangobj. Normally not needed. SCANGOBJ_OPTIONS= # Extra options to supply to gtkdoc-scan. # e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" SCAN_OPTIONS= # Extra options to supply to gtkdoc-mkdb # e.g. MKDB_OPTIONS=--xml-mode --output-format=xml MKDB_OPTIONS=--xml-mode --output-format=xml # Extra options to supply to gtkdoc-mkhtml MKHTML_OPTIONS= # Extra options to supply to gtkdoc-fixref. Normally not needed. # e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html FIXXREF_OPTIONS= # Used for dependencies. The docs will be rebuilt if any of these change. # e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h # e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c HFILE_GLOB=$(top_srcdir)/libdfu/*.h CFILE_GLOB=$(top_srcdir)/libdfu/*.c # Extra header to include when scanning, which are not under DOC_SOURCE_DIR # e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h EXTRA_HFILES= # Header files or dirs to ignore when scanning. Use base file/dir names # e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code IGNORE_HFILES= \ dfu-device-private.h \ dfu-element-private.h \ dfu-image-private.h \ dfu-sector-private.h \ dfu-target-private.h # Images to copy into HTML directory. # e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png HTML_IMAGES= # Extra files that are included by $(DOC_MAIN_SGML_FILE). # e.g. content_files=running.xml building.xml changes-2.0.xml content_files= # Files where gtk-doc abbrevations (#GtkWidget) are expanded # e.g. expand_content_files=running.xml expand_content_files= # CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. # Only needed if you are using gtkdoc-scangobj to dynamically query widget # signals and properties. # e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) # e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) GTKDOC_CFLAGS= GTKDOC_LIBS=$(top_builddir)/libdfu/libdfu.la # This includes the standard gtk-doc make rules, copied by gtkdocize. include $(top_srcdir)/gtk-doc.make # Comment this out if you want 'make check' to test you doc status # and run some sanity checks #if ENABLE_GTK_DOC #TESTS_ENVIRONMENT = \ # DOC_MODULE=$(DOC_MODULE) DOC_MAIN_SGML_FILE=$(DOC_MAIN_SGML_FILE) \ # SRCDIR=$(abs_srcdir) BUILDDIR=$(abs_builddir) #TESTS = $(GTKDOC_CHECK) #endif CLEANFILES= \ libdfu.args \ libdfu.hierarchy \ libdfu.interfaces \ libdfu.prerequisites \ libdfu.signals \ libdfu-*.txt \ *.stamp -include $(top_srcdir)/git.mk fwupd-0.7.0/docs/libdfu/clean.sh000077500000000000000000000001011267747510300164650ustar00rootroot00000000000000rm -f *.txt rm -rf html/ rm -rf xml/ rm -rf tmpl/ rm -f *.stamp fwupd-0.7.0/docs/libdfu/libdfu-docs.xml000066400000000000000000000073651267747510300200040ustar00rootroot00000000000000 ]> libdfu Reference Manual for libdfu [VERSION]. About libdfu libdfu is a library for updating firmware on DFU-capable devices. DFU is a standardised protocol used on many millions of devices to safely update device firmware by the user. Is is designed to be easy to implement in device bootloaders and also easy to support in native host drivers. Flashing firmware using DFU is supported in Windows, Linux and OS-X. Updating firmware on a device is typically done using fwupd or by a session application like GNOME Software. You can also use dfu-util which may support mode device types than dfu-tool supplied by fwupd. libdfu provides a medium-level API which is available for all languages that support GObject Introspection. It supports cancellation using GCancellable and erro reporting using GError. To download a device using the API it is as simple as getting a GUsbDevice and then doing something like this: dfu_firmware = dfu_firmware_new (); if (!dfu_firmware_parse_data (dfu_firmware, blob_fw, DFU_FIRMWARE_PARSE_FLAG_NONE, error)) return FALSE; dfu_device = dfu_device_new (dev); if (!dfu_device_download (dfu_device, dfu_firmware, DFU_TARGET_TRANSFER_FLAG_DETACH | DFU_TARGET_TRANSFER_FLAG_VERIFY | DFU_TARGET_TRANSFER_FLAG_BOOT_RUNTIME, cancelleable, _progress_cb, userdata, error)) return FALSE; You can read more about DFU in the official specification. Object Hierarchy libdfu Functionality exported by libdfu. API Index Index of deprecated API fwupd-0.7.0/docs/libdfu/libdfu.types000066400000000000000000000002171267747510300174070ustar00rootroot00000000000000dfu_context_get_type dfu_device_get_type dfu_element_get_type dfu_firmware_get_type dfu_image_get_type dfu_target_get_type dfu_sector_get_type fwupd-0.7.0/docs/libfwupd/000077500000000000000000000000001267747510300154235ustar00rootroot00000000000000fwupd-0.7.0/docs/libfwupd/Makefile.am000066400000000000000000000061621267747510300174640ustar00rootroot00000000000000# This is a blank Makefile.am for using gtk-doc. # Copy this to your project's API docs directory and modify the variables to # suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples # of using the various options. # The name of the module, e.g. 'glib'. DOC_MODULE=libfwupd # Uncomment for versioned docs and specify the version of the module, e.g. '2'. #DOC_MODULE_VERSION=2 # The top-level XML file. DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml # Directories containing the source code. # gtk-doc will search all .c and .h files beneath these paths # for inline comments documenting functions and macros. # e.g. DOC_SOURCE_DIR=$(top_srcdir)/gtk $(top_srcdir)/gdk DOC_SOURCE_DIR=$(top_srcdir)/libfwupd # Extra options to pass to gtkdoc-scangobj. Normally not needed. SCANGOBJ_OPTIONS= # Extra options to supply to gtkdoc-scan. # e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" SCAN_OPTIONS= # Extra options to supply to gtkdoc-mkdb # e.g. MKDB_OPTIONS=--xml-mode --output-format=xml MKDB_OPTIONS=--xml-mode --output-format=xml # Extra options to supply to gtkdoc-mkhtml MKHTML_OPTIONS= # Extra options to supply to gtkdoc-fixref. Normally not needed. # e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html FIXXREF_OPTIONS= # Used for dependencies. The docs will be rebuilt if any of these change. # e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h # e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c HFILE_GLOB=$(top_srcdir)/libfwupd/*.h CFILE_GLOB=$(top_srcdir)/libfwupd/*.c # Extra header to include when scanning, which are not under DOC_SOURCE_DIR # e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h EXTRA_HFILES= # Header files or dirs to ignore when scanning. Use base file/dir names # e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code IGNORE_HFILES= \ fwupd-enums-private.h # Images to copy into HTML directory. # e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png HTML_IMAGES= # Extra files that are included by $(DOC_MAIN_SGML_FILE). # e.g. content_files=running.xml building.xml changes-2.0.xml content_files= # Files where gtk-doc abbrevations (#GtkWidget) are expanded # e.g. expand_content_files=running.xml expand_content_files= # CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. # Only needed if you are using gtkdoc-scangobj to dynamically query widget # signals and properties. # e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) # e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) GTKDOC_CFLAGS= GTKDOC_LIBS=$(top_builddir)/libfwupd/libfwupd.la # This includes the standard gtk-doc make rules, copied by gtkdocize. include $(top_srcdir)/gtk-doc.make # Comment this out if you want 'make check' to test you doc status # and run some sanity checks #if ENABLE_GTK_DOC #TESTS_ENVIRONMENT = \ # DOC_MODULE=$(DOC_MODULE) DOC_MAIN_SGML_FILE=$(DOC_MAIN_SGML_FILE) \ # SRCDIR=$(abs_srcdir) BUILDDIR=$(abs_builddir) #TESTS = $(GTKDOC_CHECK) #endif CLEANFILES= \ libfwupd.args \ libfwupd.hierarchy \ libfwupd.interfaces \ libfwupd.prerequisites \ libfwupd.signals \ libfwupd-*.txt \ *.stamp -include $(top_srcdir)/git.mk fwupd-0.7.0/docs/libfwupd/clean.sh000077700000000000000000000000001267747510300221322../libdfu/clean.shustar00rootroot00000000000000fwupd-0.7.0/docs/libfwupd/libfwupd-docs.xml000066400000000000000000000031661267747510300207150ustar00rootroot00000000000000 ]> libfwupd Reference Manual for libfwupd [VERSION]. About libfwupd libfwupd is a library for querying the fwupd daemon. Object Hierarchy libfwupd Functionality exported by libfwupd. API Index Index of deprecated API fwupd-0.7.0/docs/libfwupd/libfwupd.types000066400000000000000000000000541267747510300203240ustar00rootroot00000000000000fwupd_client_get_type fwupd_result_get_type fwupd-0.7.0/docs/man/000077500000000000000000000000001267747510300143625ustar00rootroot00000000000000fwupd-0.7.0/docs/man/Makefile.am000066400000000000000000000007711267747510300164230ustar00rootroot00000000000000man_MANS_DIST = \ dfu-tool.1 \ fwupdmgr.1 EXTRA_DIST = \ dfu-tool.sgml \ fwupdmgr.sgml \ $(man_MANS_DIST) man_MANS = \ $(man_MANS_DIST) fwupdmgr.1: fwupdmgr.sgml $(AM_V_GEN) \ docbook2man $? > /dev/null dfu-tool.1: dfu-tool.sgml $(AM_V_GEN) \ docbook2man $? > /dev/null MAINTAINERCLEANFILES = \ manpage.links \ manpage.log \ manpage.refs \ $(man_MANS) clean-local : rm -f *~ rm -f *.1 rm -f manpage.* -include $(top_srcdir)/git.mk fwupd-0.7.0/docs/man/dfu-tool.sgml000066400000000000000000000414711267747510300170060ustar00rootroot00000000000000 26 February,2015"> GNU"> GPL"> ]>
richard@hughsie.com;
Richard Hughes 2015 Richard Hughes &date;
dfu-tool 1 &package; Device Firmware Upgrade Tool &package; DESCRIPTION This manual page documents briefly the &package; command. &package; allows a user to write various kinds of firmware onto devices supporting the USB Device Firmware Upgrade protocol. This tool can be used to switch the device from the normal runtime mode to `DFU mode' which allows the user to read and write firmware. Either the whole device can be written in one operation, or individual `targets' can be specified with the alternative name or number. &package; uses the libdfu shared library to perform actions. All synchronous actions can be safely cancelled and on failure will return errors with both a type and a full textual description. libdfu supports DFU 1.0, DFU 1.1 and the ST DfuSe vendor extension, and handles many device `quirks' necessary for the real-world implementations of DFU. Additionally &package; can be used to convert firmware from various different formats, or to modify details about the elements, images and metadata contained inside the firmware file. For example, you can easily convert DFU 1.1 firmware into the vendor-specific DfuSe format, convert a Intel HEX file into a raw file padded to a specific size, or add new copyright and licensing information to an existing file. Fields such as the vendor and product IDs can be changed, and the firmware elements can be encrypted and decrypted using various different methods. Merging two DfuSe files together is also possible, although specifying different alt-setting numbers before merging is a good idea to avoid confusion. Although &package; tries to provide a large number of easy-to-use commands, it may only be possible to do certain operations using the libdfu library directly. This is easier than it sounds, as the library is built with GObject Introspection support making it usable in many languages such as C, Javascript and Python. Furthermore, using the library is a good idea if you want to perform multiple operations on large firmware files, for instance, converting from an Intel HEX file, padding to a certain size, setting vendor and adding licensing information and then saving to a remote location. OPTIONS This program follows the usual &gnu; command line syntax, with long options starting with two dashes (-). A summary of options is included below. Show summary of all the commands available for use. Show the version of &package; installed. Show extra debugging information. If multiple DFU-capable devices are attached you can specify the specific vendor and product ID of the DFU device you want to query. Manually override the size of each USB transfer, which you may want for unreliable hardware or when the device lies about the maximum packet size it accepts. Force the operation, disregarding warnings or sanity checks like file CRC and checksums. This is useful if you really know what you are doing, or in the specialised case of fuzz-testing libdfu. DEVICE COMMANDS These commands are used to interface with DFU-capable devices. This command lists currently attached DFU capable devices. Some devices do not support the official DFU runtime mode and thus do not support auto-discovery using this command. For those devices, putting the device into DFU mode manually (e.g. by holding a button down when rebooting the device) will make it show up here. This command detaches the currently attached DFU capable device into a special programming mode. Whilst the device is in this special DFU mode it can not be used as a normal device. For example, a printer will not accept documents when in DFU mode. This command attaches a DFU capable device back to runtime so it can be used as a normal device. Some devices do not support attaching, and need to be manually disconnected and connected before changing modes. This command watches DFU devices being hotplugged and can be used to verify libdfu matches up the runtime and DFU modes when attaching and detaching. Use to make this command quit. This command uploads all the firmware from device into a file. If the device has multiple partitions exported as different alternative sections then they will all be read into a multi-image DfuSe-format file. If you just want the contents of one partition, is the command you want. This command uploads firmware from one partition into a file. You can specify the partition by either the ALT-ID or ALT-NAME if set. e.g. &package; read-alt backup.dfu SRAM This command downloads firmware from a file into all possible partitions of a device. If you only want to write one partition, is the command you want. This command downloads firmware from the file into one partition. You can specify the partition by either the ALT-ID or ALT-NAME if set. e.g. &package; write-alt sram.dfu SRAM __SRAM FIRMWARE COMMANDS These commands are used to read and modify existing firmware files. This command dumps all know details about a firmware file. The complete memory map is shown, along with any metadata or vendor information about the firmware file. This command converts the firmware from one format to another, optionally padding to a certain size. Possible values for the destination include: raw, ihex, dfu and dfuse. The and values can be the same if the source file is to be overwritten. Although padding increases the file size with no apparent advantages it can be used to support devices that do not store the runtime image size and where validation of the written firmware is required. e.g. &package; convert dfu firmware.hex firmware.dfu 8000 This command encrypts firmware data. Only the image contents are actually modified, the DFU footer and DfuSe header are left unaltered. Possible values for the destination include: xtea and nop. If the is not of the required length it is used as an input to a hash function which can produce a key of the required size. e.g. &package; encrypt firmware.dfu firmware.xdfu xtea deadbeef This command decrypts firmware data. Only the image contents are actually modified, the DFU footer and DfuSe header are left unaltered. Possible values for the destination include: xtea and nop. If the is not of the required length it is used as an input to a hash function which can produce a key of the required size. e.g. &package; decrypt firmware.xdfu firmware.dfu xtea deadbeef This command merges multiple firmware files into one file. Although you can merge files with the same ALT-ID or ALT-NAME this probably isn't what you want to do. e.g. &package; merge combined.dfu lib.dfu app.dfu This command modifies the alternative number on firmware file. e.g. &package; set-alt-setting firmware.dfu 1 This command modifies the alternative name on firmware file. e.g. &package; set-alt-setting-name firmware.dfu SRAM This command adds or modifies existing metadata on a firmware file. NOTE: There is only very limited metadata storage space in DFU files, so keys and values should be kept as short as possible. In particular, the License value should be specified in SPDX format. e.g. &package; set-metadata firmware.dfu Licence GPL-2.0+ This command sets vendor ID on a firmware file that will be used to match specific devices. Values of ffff will match any device vendor. e.g. &package; set-vendor firmware.dfu 273f This command sets the product ID on a firmware file that will be used to match specific devices. Values of ffff will match any device product. e.g. &package; set-product firmware.dfu 1004 This command sets the release version on firmware file that will be used to match specific devices. Values of ffff will match any device release. e.g. &package; set-release firmware.dfu ffff AUTHOR This manual page was written by Richard Hughes richard@hughsie.com.
fwupd-0.7.0/docs/man/fwupdmgr.sgml000066400000000000000000000122251267747510300171030ustar00rootroot00000000000000 26 February,2015"> GNU"> GPL"> ]>
richard@hughsie.com;
Richard Hughes 2015 Richard Hughes &date;
fwupdmgr 1 &package; fwupd client tool &package; DESCRIPTION This manual page documents briefly the &package; command. &package; allows an administrator to update firmware. OPTIONS This program follows the usual &gnu; command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. Show summary of options. Show extra debugging information. Allow re-installing existing firmware versions. Allow downgrading firmware versions. Perform the installation offline where possible. COMMANDS This program takes commands with a variable number of arguments. Gets details about a firmware file. Get the list of hardware that supports firmware updates. Gets the list of updates for connected hardware. Updates all firmware to latest versions available. Install a firmware file on this hardware. Install prepared updates now. Clears the results from the last update. Refresh metadata from remote server. Gets the results from the last update. AUTHOR This manual page was written by Richard Hughes richard@hughsie.com.
fwupd-0.7.0/git.mk000066400000000000000000000132731267747510300140010ustar00rootroot00000000000000# git.mk # # Copyright 2009, Red Hat, Inc. # Written by Behdad Esfahbod # # Copying and distribution of this file, with or without modification, # are permitted in any medium without royalty provided the copyright # notice and this notice are preserved. # # The canonical source for this file is pango/git.mk, or whereever the # header of pango/git.mk suggests in the future. # # To use in your project, import this file in your git repo's toplevel, # then do "make -f git.mk". This modifies all Makefile.am files in # your project to include git.mk. # # This enables automatic .gitignore generation. If you need to ignore # more files, add them to the GITIGNOREFILES variable in your Makefile.am. # But think twice before doing that. If a file has to be in .gitignore, # chances are very high that it's a generated file and should be in one # of MOSTLYCLEANFILES, CLEANFILES, DISTCLEANFILES, or MAINTAINERCLEANFILES. # # The only case that you need to manually add a file to GITIGNOREFILES is # when remove files in one of mostlyclean-local, clean-local, distclean-local, # or maintainer-clean-local. # # Note that for files like editor backup, etc, there are better places to # ignore them. See "man gitignore". # # If "make maintainer-clean" removes the files but they are not recognized # by this script (that is, if "git status" shows untracked files still), send # me the output of "git status" as well as your Makefile.am and Makefile for # the directories involved. # # For a list of toplevel files that should be in MAINTAINERCLEANFILES, see # pango/Makefile.am. # # Don't EXTRA_DIST this file. It is supposed to only live in git clones, # not tarballs. It serves no useful purpose in tarballs and clutters the # build dir. # # This file knows how to handle autoconf, automake, libtool, gtk-doc, # gnome-doc-utils, mallard, intltool, gsettings. # # # KNOWN ISSUES: # # - Recursive configure doesn't work as $(top_srcdir)/git.mk inside the # submodule doesn't find us. If you have configure.{in,ac} files in # subdirs, add a proxy git.mk file in those dirs that simply does: # "include $(top_srcdir)/../git.mk". Add more ..'s to your taste. # And add those files to git. See vte/gnome-pty-helper/git.mk for # example. # # ChangeLog # # - 2010-12-06 Add support for Mallard docs # - 2010-12-06 Start this change log git-all: git-mk-install git-mk-install: @echo Installing git makefile @any_failed=; find $(top_srcdir) -name Makefile.am | while read x; do \ if grep 'include .*/git.mk' $$x >/dev/null; then \ echo $$x already includes git.mk; \ else \ failed=; \ echo "Updating $$x"; \ { cat $$x; \ echo ''; \ echo '-include $$(top_srcdir)/git.mk'; \ } > $$x.tmp || failed=1; \ if test x$$failed = x; then \ mv $$x.tmp $$x || failed=1; \ fi; \ if test x$$failed = x; then : else \ echo Failed updating $$x; >&2 \ any_failed=1; \ fi; \ fi; done; test -z "$$any_failed" .PHONY: git-all git-mk-install ### .gitignore generation $(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk $(AM_V_GEN) \ { \ if test "x$(DOC_MODULE)" = x -o "x$(DOC_MAIN_SGML_FILE)" = x; then :; else \ for x in \ $(DOC_MODULE)-decl-list.txt \ $(DOC_MODULE)-decl.txt \ tmpl/$(DOC_MODULE)-unused.sgml \ "tmpl/*.bak" \ xml html \ ; do echo /$$x; done; \ fi; \ if test "x$(DOC_MODULE)$(DOC_ID)" = x -o "x$(DOC_LINGUAS)" = x; then :; else \ for x in \ $(_DOC_C_DOCS) \ $(_DOC_LC_DOCS) \ $(_DOC_OMF_ALL) \ $(_DOC_DSK_ALL) \ $(_DOC_HTML_ALL) \ $(_DOC_MOFILES) \ $(_DOC_POFILES) \ $(DOC_H_FILE) \ "*/.xml2po.mo" \ "*/*.omf.out" \ ; do echo /$$x; done; \ fi; \ if test "x$(gsettings_SCHEMAS)" = x; then :; else \ for x in \ $(gsettings_SCHEMAS:.xml=.valid) \ $(gsettings__enum_file) \ ; do echo /$$x; done; \ fi; \ if test -f $(srcdir)/po/Makefile.in.in; then \ for x in \ po/Makefile.in.in \ po/Makefile.in \ po/Makefile \ po/POTFILES \ po/stamp-it \ po/.intltool-merge-cache \ "po/*.gmo" \ "po/*.mo" \ po/$(GETTEXT_PACKAGE).pot \ intltool-extract.in \ intltool-merge.in \ intltool-update.in \ ; do echo /$$x; done; \ fi; \ if test -f $(srcdir)/configure; then \ for x in \ autom4te.cache \ configure \ config.h \ stamp-h1 \ libtool \ config.lt \ ; do echo /$$x; done; \ fi; \ for x in \ .gitignore \ $(GITIGNOREFILES) \ $(CLEANFILES) \ $(PROGRAMS) \ $(check_PROGRAMS) \ $(EXTRA_PROGRAMS) \ $(LTLIBRARIES) \ so_locations \ .libs _libs \ $(MOSTLYCLEANFILES) \ "*.$(OBJEXT)" \ "*.lo" \ $(DISTCLEANFILES) \ $(am__CONFIG_DISTCLEAN_FILES) \ $(CONFIG_CLEAN_FILES) \ TAGS ID GTAGS GRTAGS GSYMS GPATH tags \ "*.tab.c" \ $(MAINTAINERCLEANFILES) \ $(BUILT_SOURCES) \ $(DEPDIR) \ Makefile \ Makefile.in \ "*.orig" \ "*.rej" \ "*.bak" \ "*~" \ ".*.sw[nop]" \ ".dirstamp" \ ; do echo /$$x; done; \ } | \ sed "s@^/`echo "$(srcdir)" | sed 's/\(.\)/[\1]/g'`/@/@" | \ sed 's@/[.]/@/@g' | \ LC_ALL=C sort | uniq > $@.tmp && \ mv $@.tmp $@; all: $(srcdir)/.gitignore gitignore-recurse-maybe gitignore-recurse-maybe: @if test "x$(SUBDIRS)" = "x$(DIST_SUBDIRS)"; then :; else \ $(MAKE) $(AM_MAKEFLAGS) gitignore-recurse; \ fi; gitignore-recurse: @for subdir in $(DIST_SUBDIRS); do \ case " $(SUBDIRS) " in \ *" $$subdir "*) :;; \ *) test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) .gitignore gitignore-recurse || echo "Skipping $$subdir");; \ esac; \ done gitignore: $(srcdir)/.gitignore gitignore-recurse maintainer-clean: gitignore-clean gitignore-clean: -rm -f $(srcdir)/.gitignore .PHONY: gitignore-clean gitignore gitignore-recurse gitignore-recurse-maybe fwupd-0.7.0/libdfu/000077500000000000000000000000001267747510300141245ustar00rootroot00000000000000fwupd-0.7.0/libdfu/Makefile.am000066400000000000000000000065031267747510300161640ustar00rootroot00000000000000if HAVE_INTROSPECTION -include $(INTROSPECTION_MAKEFILE) INTROSPECTION_GIRS = INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir) INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir) endif AM_CPPFLAGS = \ $(APPSTREAM_GLIB_CFLAGS) \ $(GLIB_CFLAGS) \ $(GUSB_CFLAGS) \ $(PIE_CFLAGS) \ -I$(top_srcdir)/libdfu \ -I$(top_srcdir) \ -I$(top_builddir) \ -DG_USB_API_IS_SUBJECT_TO_CHANGE \ -DG_LOG_DOMAIN=\"libdfu\" \ -DTESTDATADIR=\""$(top_srcdir)/data/tests/dfu"\" \ -DLOCALEDIR=\""$(localedir)"\" lib_LTLIBRARIES = \ libdfu.la libdfu_includedir = $(includedir) libdfu_include_HEADERS = \ dfu.h libdfubase_includedir = $(libdfu_includedir)/libdfu libdfubase_include_HEADERS = \ dfu-common.h \ dfu-context.h \ dfu-device.h \ dfu-element.h \ dfu-error.h \ dfu-firmware.h \ dfu-image.h \ dfu-sector.h \ dfu-target.h libdfu_la_SOURCES = \ dfu.h \ dfu-common.c \ dfu-common.h \ dfu-context.c \ dfu-context.h \ dfu-device.c \ dfu-device.h \ dfu-device-private.h \ dfu-element.c \ dfu-element.h \ dfu-element-private.h \ dfu-error.c \ dfu-error.h \ dfu-firmware.c \ dfu-firmware.h \ dfu-image.c \ dfu-image.h \ dfu-image-private.h \ dfu-sector.c \ dfu-sector.h \ dfu-sector-private.h \ dfu-target.c \ dfu-target.h \ dfu-target-private.h libdfu_la_LIBADD = \ $(GUSB_LIBS) \ $(GLIB_LIBS) \ $(LIBM) libdfu_la_LDFLAGS = \ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \ -export-dynamic \ -no-undefined \ -export-symbols-regex '^dfu_.*' libdfu_la_CFLAGS = \ $(PIE_CFLAGS) \ $(WARNINGFLAGS_C) pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = dfu.pc EXTRA_DIST = \ dfu.pc.in bin_PROGRAMS = \ dfu-tool dfu_tool_SOURCES = \ dfu-tool.c dfu_tool_LDADD = \ $(lib_LTLIBRARIES) \ $(APPSTREAM_GLIB_LIBS) \ $(GLIB_LIBS) \ $(GUSB_LIBS) \ $(LIBM) dfu_tool_CFLAGS = -DEGG_TEST $(AM_CFLAGS) $(WARNINGFLAGS_C) TESTS_ENVIRONMENT = \ libtool --mode=execute valgrind \ --quiet \ --leak-check=full \ --show-possibly-lost=no check_PROGRAMS = \ dfu-self-test dfu_self_test_SOURCES = \ dfu-self-test.c dfu_self_test_LDADD = \ $(lib_LTLIBRARIES) \ $(GLIB_LIBS) \ $(GUSB_LIBS) dfu_self_test_CFLAGS = -DEGG_TEST $(AM_CFLAGS) $(WARNINGFLAGS_C) TESTS = dfu-self-test CLEANFILES = *.log *.trs $(BUILT_SOURCES) MAINTAINERCLEANFILES = *.dfu *.bin if HAVE_INTROSPECTION introspection_sources = \ $(libdfu_la_SOURCES) Dfu-1.0.gir: libdfu.la Dfu_1_0_gir_INCLUDES = GObject-2.0 Gio-2.0 GUsb-1.0 Dfu_1_0_gir_CFLAGS = $(AM_CPPFLAGS) Dfu_1_0_gir_SCANNERFLAGS = --identifier-prefix=Dfu \ --symbol-prefix=dfu \ --warn-all \ --add-include-path=$(srcdir) \ --c-include="dfu.h" Dfu_1_0_gir_EXPORT_PACKAGES = dfu Dfu_1_0_gir_LIBS = libdfu.la Dfu_1_0_gir_FILES = $(introspection_sources) INTROSPECTION_GIRS += Dfu-1.0.gir girdir = $(datadir)/gir-1.0 gir_DATA = $(INTROSPECTION_GIRS) typelibdir = $(libdir)/girepository-1.0 typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib) CLEANFILES += $(gir_DATA) $(typelib_DATA) *.log *.trs *.test endif clean-local: rm -f *~ -include $(top_srcdir)/git.mk fwupd-0.7.0/libdfu/dfu-common.c000066400000000000000000000077201267747510300163420ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * SECTION:dfu-common * @short_description: Common functions for DFU * * These helper objects allow converting from enum values to strings. */ #include "config.h" #include "dfu-common.h" /** * dfu_state_to_string: * @state: a #DfuState, e.g. %DFU_STATE_DFU_MANIFEST * * Converts an enumerated value to a string. * * Return value: a string * * Since: 0.5.4 **/ const gchar * dfu_state_to_string (DfuState state) { if (state == DFU_STATE_APP_IDLE) return "appIDLE"; if (state == DFU_STATE_APP_DETACH) return "appDETACH"; if (state == DFU_STATE_DFU_IDLE) return "dfuIDLE"; if (state == DFU_STATE_DFU_DNLOAD_SYNC) return "dfuDNLOAD-SYNC"; if (state == DFU_STATE_DFU_DNBUSY) return "dfuDNBUSY"; if (state == DFU_STATE_DFU_DNLOAD_IDLE) return "dfuDNLOAD-IDLE"; if (state == DFU_STATE_DFU_MANIFEST_SYNC) return "dfuMANIFEST-SYNC"; if (state == DFU_STATE_DFU_MANIFEST) return "dfuMANIFEST"; if (state == DFU_STATE_DFU_MANIFEST_WAIT_RESET) return "dfuMANIFEST-WAIT-RESET"; if (state == DFU_STATE_DFU_UPLOAD_IDLE) return "dfuUPLOAD-IDLE"; if (state == DFU_STATE_DFU_ERROR) return "dfuERROR"; return NULL; } /** * dfu_status_to_string: * @status: a #DfuStatus, e.g. %DFU_STATUS_ERR_ERASE * * Converts an enumerated value to a string. * * Return value: a string * * Since: 0.5.4 **/ const gchar * dfu_status_to_string (DfuStatus status) { if (status == DFU_STATUS_OK) return "OK"; if (status == DFU_STATUS_ERR_TARGET) return "errTARGET"; if (status == DFU_STATUS_ERR_FILE) return "errFILE"; if (status == DFU_STATUS_ERR_WRITE) return "errwrite"; if (status == DFU_STATUS_ERR_ERASE) return "errERASE"; if (status == DFU_STATUS_ERR_CHECK_ERASED) return "errCHECK_ERASED"; if (status == DFU_STATUS_ERR_PROG) return "errPROG"; if (status == DFU_STATUS_ERR_VERIFY) return "errVERIFY"; if (status == DFU_STATUS_ERR_ADDRESS) return "errADDRESS"; if (status == DFU_STATUS_ERR_NOTDONE) return "errNOTDONE"; if (status == DFU_STATUS_ERR_FIRMWARE) return "errFIRMWARE"; if (status == DFU_STATUS_ERR_VENDOR) return "errVENDOR"; if (status == DFU_STATUS_ERR_USBR) return "errUSBR"; if (status == DFU_STATUS_ERR_POR) return "errPOR"; if (status == DFU_STATUS_ERR_UNKNOWN) return "errUNKNOWN"; if (status == DFU_STATUS_ERR_STALLDPKT) return "errSTALLDPKT"; return NULL; } /** * dfu_mode_to_string: * @mode: a #DfuMode, e.g. %DFU_MODE_RUNTIME * * Converts an enumerated value to a string. * * Return value: a string * * Since: 0.5.4 **/ const gchar * dfu_mode_to_string (DfuMode mode) { if (mode == DFU_MODE_RUNTIME) return "runtime"; if (mode == DFU_MODE_DFU) return "DFU"; return NULL; } /** * dfu_cipher_kind_to_string: * @cipher_kind: a #DfuCipherKind, e.g. %DFU_CIPHER_KIND_XTEA * * Converts an enumerated value to a string. * * Return value: a string * * Since: 0.5.4 **/ const gchar * dfu_cipher_kind_to_string (DfuCipherKind cipher_kind) { if (cipher_kind == DFU_CIPHER_KIND_NONE) return "none"; if (cipher_kind == DFU_CIPHER_KIND_XTEA) return "xtea"; return NULL; } fwupd-0.7.0/libdfu/dfu-common.h000066400000000000000000000124161267747510300163450ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __DFU_COMMON_H #define __DFU_COMMON_H #include #include G_BEGIN_DECLS /** * DfuRequest: * @DFU_REQUEST_DETACH: Detach * @DFU_REQUEST_DNLOAD: Download host-to-device * @DFU_REQUEST_UPLOAD: Upload device-to-host * @DFU_REQUEST_GETSTATUS: Get the device status * @DFU_REQUEST_CLRSTATUS: Clear the device status * @DFU_REQUEST_GETSTATE: Get the last set state * @DFU_REQUEST_ABORT: Abort the current transfer * * The DFU request kinds. **/ typedef enum { DFU_REQUEST_DETACH = 0x00, DFU_REQUEST_DNLOAD = 0x01, DFU_REQUEST_UPLOAD = 0x02, DFU_REQUEST_GETSTATUS = 0x03, DFU_REQUEST_CLRSTATUS = 0x04, DFU_REQUEST_GETSTATE = 0x05, DFU_REQUEST_ABORT = 0x06, /*< private >*/ DFU_REQUEST_LAST } DfuRequest; /** * DfuStatus: * @DFU_STATUS_OK: No error condition is present * @DFU_STATUS_ERR_TARGET: File is not targeted for use by this device * @DFU_STATUS_ERR_FILE: File is for this device but fails a verification test * @DFU_STATUS_ERR_WRITE: Device is unable to write memory * @DFU_STATUS_ERR_ERASE: Memory erase function failed * @DFU_STATUS_ERR_CHECK_ERASED: Memory erase check failed * @DFU_STATUS_ERR_PROG: Program memory function failed * @DFU_STATUS_ERR_VERIFY: Programmed memory failed verification * @DFU_STATUS_ERR_ADDRESS: Cannot program memory due to received address that isout of range * @DFU_STATUS_ERR_NOTDONE: Received DFU_DNLOAD with wLength = 0 but data is incomplete * @DFU_STATUS_ERR_FIRMWARE: Device firmware is corrupt * @DFU_STATUS_ERR_VENDOR: iString indicates a vendor-specific error * @DFU_STATUS_ERR_USBR: Device detected unexpected USB reset signaling * @DFU_STATUS_ERR_POR: Device detected unexpected power on reset * @DFU_STATUS_ERR_UNKNOWN: Something unexpected went wrong * @DFU_STATUS_ERR_STALLDPKT: Device stalled an unexpected request * * The status enumerated kind. **/ typedef enum { DFU_STATUS_OK = 0x00, DFU_STATUS_ERR_TARGET = 0x01, DFU_STATUS_ERR_FILE = 0x02, DFU_STATUS_ERR_WRITE = 0x03, DFU_STATUS_ERR_ERASE = 0x04, DFU_STATUS_ERR_CHECK_ERASED = 0x05, DFU_STATUS_ERR_PROG = 0x06, DFU_STATUS_ERR_VERIFY = 0x07, DFU_STATUS_ERR_ADDRESS = 0x08, DFU_STATUS_ERR_NOTDONE = 0x09, DFU_STATUS_ERR_FIRMWARE = 0x0a, DFU_STATUS_ERR_VENDOR = 0x0b, DFU_STATUS_ERR_USBR = 0x0c, DFU_STATUS_ERR_POR = 0x0d, DFU_STATUS_ERR_UNKNOWN = 0x0e, DFU_STATUS_ERR_STALLDPKT = 0x0f, /*< private >*/ DFU_STATUS_LAST } DfuStatus; /** * DfuState: * @DFU_STATE_APP_IDLE: State 0 * @DFU_STATE_APP_DETACH: State 1 * @DFU_STATE_DFU_IDLE: State 2 * @DFU_STATE_DFU_DNLOAD_SYNC: State 3 * @DFU_STATE_DFU_DNBUSY: State 4 * @DFU_STATE_DFU_DNLOAD_IDLE: State 5 * @DFU_STATE_DFU_MANIFEST_SYNC: State 6 * @DFU_STATE_DFU_MANIFEST: State 7 * @DFU_STATE_DFU_MANIFEST_WAIT_RESET: State 8 * @DFU_STATE_DFU_UPLOAD_IDLE: State 9 * @DFU_STATE_DFU_ERROR: State 10 * * The state enumerated kind. **/ typedef enum { DFU_STATE_APP_IDLE = 0x00, DFU_STATE_APP_DETACH = 0x01, DFU_STATE_DFU_IDLE = 0x02, DFU_STATE_DFU_DNLOAD_SYNC = 0x03, DFU_STATE_DFU_DNBUSY = 0x04, DFU_STATE_DFU_DNLOAD_IDLE = 0x05, DFU_STATE_DFU_MANIFEST_SYNC = 0x06, DFU_STATE_DFU_MANIFEST = 0x07, DFU_STATE_DFU_MANIFEST_WAIT_RESET = 0x08, DFU_STATE_DFU_UPLOAD_IDLE = 0x09, DFU_STATE_DFU_ERROR = 0x0a, /*< private >*/ DFU_STATE_LAST } DfuState; /** * DfuMode: * @DFU_MODE_UNKNOWN: Unknown mode * @DFU_MODE_RUNTIME: Runtime mode * @DFU_MODE_DFU: Bootloader mode * * The mode enumerated kind. **/ typedef enum { DFU_MODE_UNKNOWN, DFU_MODE_RUNTIME, DFU_MODE_DFU, /*< private >*/ DFU_MODE_LAST } DfuMode; /** * DfuCipherKind: * @DFU_CIPHER_KIND_NONE: No cipher detected * @DFU_CIPHER_KIND_XTEA: XTEA cipher detected * * The type of cipher used for transfering the firmware. **/ typedef enum { DFU_CIPHER_KIND_NONE, DFU_CIPHER_KIND_XTEA, /*< private >*/ DFU_CIPHER_KIND_LAST } DfuCipherKind; #define DFU_METADATA_KEY_LICENSE "License" #define DFU_METADATA_KEY_COPYRIGHT "Copyright" #define DFU_METADATA_KEY_CIPHER_KIND "CipherKind" const gchar *dfu_state_to_string (DfuState state); const gchar *dfu_status_to_string (DfuStatus status); const gchar *dfu_mode_to_string (DfuMode mode); const gchar *dfu_cipher_kind_to_string (DfuCipherKind cipher_kind); G_END_DECLS #endif /* __DFU_COMMON_H */ fwupd-0.7.0/libdfu/dfu-context.c000066400000000000000000000372471267747510300165450ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * SECTION:dfu-context * @short_description: A system context for managing DFU-capable devices * * This object allows discovering and monitoring hotpluggable DFU devices. * * When using #DfuContext the device is given some time to re-enumerate after a * detach or reset. This allows client programs to continue using the #DfuDevice * without dealing with the device hotplug and the #GUsbDevice changing. * Using this object may be easier than using GUsbContext directly. * * Please be aware that after device detach or reset the number of #DfuTarget * objects may be different and so need to be re-requested. * * See also: #DfuDevice, #DfuTarget */ #include "config.h" #include #include "dfu-device-private.h" #include "dfu-error.h" #include "dfu-context.h" static void dfu_context_finalize (GObject *object); /** * DfuContextPrivate: * * Private #DfuContext data **/ typedef struct { GUsbContext *usb_ctx; GPtrArray *devices; /* of DfuContextItem */ guint timeout; /* in ms */ } DfuContextPrivate; typedef struct { DfuContext *context; /* not refcounted */ DfuDevice *device; /* not refcounted */ guint timeout_id; guint state_change_id; } DfuContextItem; enum { SIGNAL_DEVICE_ADDED, SIGNAL_DEVICE_REMOVED, SIGNAL_DEVICE_CHANGED, SIGNAL_LAST }; static guint signals [SIGNAL_LAST] = { 0 }; G_DEFINE_TYPE_WITH_PRIVATE (DfuContext, dfu_context, G_TYPE_OBJECT) #define GET_PRIVATE(o) (dfu_context_get_instance_private (o)) /** * dfu_context_device_free: **/ static void dfu_context_device_free (DfuContextItem *item) { if (item->timeout_id > 0) g_source_remove (item->timeout_id); if (item->timeout_id > 0) { g_signal_handler_disconnect (item->device, item->state_change_id); } g_object_unref (item->device); g_free (item); } /** * dfu_context_class_init: **/ static void dfu_context_class_init (DfuContextClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); /** * DfuContext::device-added: * @context: the #DfuContext instance that emitted the signal * @device: the #DfuDevice * * The ::device-added signal is emitted when a new DFU device is connected. * * Since: 0.5.4 **/ signals [SIGNAL_DEVICE_ADDED] = g_signal_new ("device-added", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (DfuContextClass, device_added), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, DFU_TYPE_DEVICE); /** * DfuContext::device-removed: * @context: the #DfuContext instance that emitted the signal * @device: the #DfuDevice * * The ::device-removed signal is emitted when a DFU device is removed. * * Since: 0.5.4 **/ signals [SIGNAL_DEVICE_REMOVED] = g_signal_new ("device-removed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (DfuContextClass, device_removed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, DFU_TYPE_DEVICE); /** * DfuContext::device-changed: * @context: the #DfuContext instance that emitted the signal * @device: the #DfuDevice * * The ::device-changed signal is emitted when a DFU device is changed, * typically when it has detached or been reset. * * Since: 0.5.4 **/ signals [SIGNAL_DEVICE_CHANGED] = g_signal_new ("device-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (DfuContextClass, device_changed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, DFU_TYPE_DEVICE); object_class->finalize = dfu_context_finalize; } /** * dfu_context_get_device_id: **/ static gchar * dfu_context_get_device_id (DfuDevice *device) { GUsbDevice *dev; dev = dfu_device_get_usb_dev (device); if (dev == NULL) return g_strdup (dfu_device_get_platform_id (device)); return g_strdup_printf ("%04x:%04x [%s]", g_usb_device_get_vid (dev), g_usb_device_get_pid (dev), g_usb_device_get_platform_id (dev)); } /** * dfu_context_find_item_by_platform_id: **/ static DfuContextItem * dfu_context_find_item_by_platform_id (DfuContext *context, const gchar *platform_id) { DfuContextPrivate *priv = GET_PRIVATE (context); DfuContextItem *item; guint i; /* do we have this device */ for (i = 0; i < priv->devices->len; i++) { item = g_ptr_array_index (priv->devices, i); if (g_strcmp0 (dfu_device_get_platform_id (item->device), platform_id) == 0) return item; } return NULL; } /** * dfu_context_remove_item: **/ static void dfu_context_remove_item (DfuContextItem *item) { DfuContextPrivate *priv = GET_PRIVATE (item->context); g_autofree gchar *device_id = NULL; /* log something */ device_id = dfu_context_get_device_id (item->device); g_debug ("%s was removed", device_id); g_signal_emit (item->context, signals[SIGNAL_DEVICE_REMOVED], 0, item->device); g_ptr_array_remove (priv->devices, item); } /** * dfu_context_device_timeout_cb: **/ static gboolean dfu_context_device_timeout_cb (gpointer user_data) { DfuContextItem *item = (DfuContextItem *) user_data; g_autofree gchar *device_id = NULL; /* bad firmware? */ device_id = dfu_context_get_device_id (item->device); g_debug ("%s did not come back as a DFU capable device", device_id); dfu_context_remove_item (item); return FALSE; } /** * dfu_context_device_state_cb: **/ static void dfu_context_device_state_cb (DfuDevice *device, DfuState state, DfuContext *context) { g_autofree gchar *device_id = NULL; device_id = dfu_context_get_device_id (device); g_debug ("%s state now: %s", device_id, dfu_state_to_string (state)); g_signal_emit (context, signals[SIGNAL_DEVICE_CHANGED], 0, device); } /** * dfu_context_device_added_cb: **/ static void dfu_context_device_added_cb (GUsbContext *usb_context, GUsbDevice *usb_device, DfuContext *context) { DfuContextPrivate *priv = GET_PRIVATE (context); DfuDevice *device; DfuContextItem *item; const gchar *platform_id; g_autofree gchar *device_id = NULL; g_autoptr(GError) error = NULL; /* are we waiting for this device to come back? */ platform_id = g_usb_device_get_platform_id (usb_device); item = dfu_context_find_item_by_platform_id (context, platform_id); if (item != NULL) { device_id = dfu_context_get_device_id (item->device); if (item->timeout_id > 0) { g_debug ("cancelling the remove timeout"); g_source_remove (item->timeout_id); item->timeout_id = 0; } /* try and be helpful; we may be a daemon like fwupd watching a * DFU device after dfu-tool or dfu-util has detached the * device on th command line */ if (!dfu_device_set_new_usb_dev (item->device, usb_device, NULL, &error)) g_warning ("Failed to set new device: %s", error->message); /* inform the UI */ g_signal_emit (context, signals[SIGNAL_DEVICE_CHANGED], 0, item->device); g_debug ("device %s came back", device_id); return; } /* is this a DFU-capable device */ device = dfu_device_new (usb_device); if (device == NULL) { g_debug ("device was not DFU capable"); return; } /* add */ item = g_new0 (DfuContextItem, 1); item->context = context; item->device = device; item->state_change_id = g_signal_connect (item->device, "state-changed", G_CALLBACK (dfu_context_device_state_cb), context); g_ptr_array_add (priv->devices, item); g_signal_emit (context, signals[SIGNAL_DEVICE_ADDED], 0, device); device_id = dfu_context_get_device_id (item->device); g_debug ("device %s was added", device_id); } /** * dfu_context_device_removed_cb: **/ static void dfu_context_device_removed_cb (GUsbContext *usb_context, GUsbDevice *usb_device, DfuContext *context) { DfuContextPrivate *priv = GET_PRIVATE (context); DfuContextItem *item; const gchar *platform_id; /* find the item */ platform_id = g_usb_device_get_platform_id (usb_device); item = dfu_context_find_item_by_platform_id (context, platform_id); if (item == NULL) return; /* mark the backing USB device as invalid */ dfu_device_set_new_usb_dev (item->device, NULL, NULL, NULL); /* this item has just detached */ if (item->timeout_id > 0) g_source_remove (item->timeout_id); item->timeout_id = g_timeout_add (priv->timeout, dfu_context_device_timeout_cb, item); } /** * dfu_context_init: **/ static void dfu_context_init (DfuContext *context) { DfuContextPrivate *priv = GET_PRIVATE (context); priv->timeout = 5000; priv->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) dfu_context_device_free); priv->usb_ctx = g_usb_context_new (NULL); g_signal_connect (priv->usb_ctx, "device-added", G_CALLBACK (dfu_context_device_added_cb), context); g_signal_connect (priv->usb_ctx, "device-removed", G_CALLBACK (dfu_context_device_removed_cb), context); } /** * dfu_context_finalize: **/ static void dfu_context_finalize (GObject *object) { DfuContext *context = DFU_CONTEXT (object); DfuContextPrivate *priv = GET_PRIVATE (context); g_ptr_array_unref (priv->devices); g_object_unref (priv->usb_ctx); G_OBJECT_CLASS (dfu_context_parent_class)->finalize (object); } /** * dfu_context_new: * * Creates a new DFU context object. * * Return value: a new #DfuContext * * Since: 0.5.4 **/ DfuContext * dfu_context_new (void) { DfuContext *context; context = g_object_new (DFU_TYPE_CONTEXT, NULL); return context; } /** * dfu_context_get_timeout: * @context: a #DfuContext * * Gets the wait-for-replug timeout. * * Return value: value in milliseconds * * Since: 0.5.4 **/ guint dfu_context_get_timeout (DfuContext *context) { DfuContextPrivate *priv = GET_PRIVATE (context); g_return_val_if_fail (DFU_IS_CONTEXT (context), 0); return priv->timeout; } /** * dfu_context_set_timeout: * @context: a #DfuContext * @timeout: a timeout in milliseconds * * Sets the wait-for-replug timeout. * This is the longest we will wait for a device to re-enumerate after * disconnecting. Using longer values will result in any UI not updating in a * good time, but using too short values will result in devices being removed * and re-added as different #DfuDevice's. * * Since: 0.5.4 **/ void dfu_context_set_timeout (DfuContext *context, guint timeout) { DfuContextPrivate *priv = GET_PRIVATE (context); g_return_if_fail (DFU_IS_CONTEXT (context)); priv->timeout = timeout; } /** * dfu_context_enumerate: * @context: a #DfuContext * @error: a #GError, or %NULL * * Opens a DFU-capable context. * * Return value: %TRUE for success * * Since: 0.5.4 **/ gboolean dfu_context_enumerate (DfuContext *context, GError **error) { DfuContextPrivate *priv = GET_PRIVATE (context); g_return_val_if_fail (DFU_IS_CONTEXT (context), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_usb_context_enumerate (priv->usb_ctx); return TRUE; } /** * dfu_context_get_devices: * @context: a #DfuContext * * Gets all the DFU-capable devices on the system. * * Return value: (element-type DfuDevice) (transfer container): array of devices * * Since: 0.5.4 **/ GPtrArray * dfu_context_get_devices (DfuContext *context) { DfuContextPrivate *priv = GET_PRIVATE (context); DfuContextItem *item; GPtrArray *devices; guint i; g_return_val_if_fail (DFU_IS_CONTEXT (context), NULL); devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); for (i = 0; i < priv->devices->len; i++) { item = g_ptr_array_index (priv->devices, i); g_ptr_array_add (devices, g_object_ref (item->device)); } return devices; } /** * dfu_context_get_device_by_vid_pid: * @context: a #DfuContext * @vid: a vendor ID * @pid: a product ID * @error: a #GError, or %NULL * * Finds a device in the context with a specific vendor:product ID. * An error is returned if more than one device matches. * * Return value: (transfer full): a #DfuDevice for success, or %NULL for an error * * Since: 0.5.4 **/ DfuDevice * dfu_context_get_device_by_vid_pid (DfuContext *context, guint16 vid, guint16 pid, GError **error) { DfuContextPrivate *priv = GET_PRIVATE (context); DfuContextItem *item; DfuDevice *device = NULL; GUsbDevice *dev; guint i; g_return_val_if_fail (DFU_IS_CONTEXT (context), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* search all devices */ for (i = 0; i < priv->devices->len; i++) { /* match */ item = g_ptr_array_index (priv->devices, i); dev = dfu_device_get_usb_dev (item->device); if (g_usb_device_get_vid (dev) == vid && g_usb_device_get_pid (dev) == pid) { if (device != NULL) { g_set_error (error, DFU_ERROR, DFU_ERROR_INVALID_DEVICE, "multiple device matches for %04x:%04x", vid, pid); return NULL; } device = item->device; continue; } } if (device == NULL) { g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_FOUND, "no device matches for %04x:%04x", vid, pid); return NULL; } return g_object_ref (device); } /** * dfu_context_get_device_by_platform_id: * @context: a #DfuContext * @platform_id: a platform ID * @error: a #GError, or %NULL * * Finds a device in the context with a specific platform ID. * * Return value: (transfer full): a #DfuDevice for success, or %NULL for an error * * Since: 0.5.4 **/ DfuDevice * dfu_context_get_device_by_platform_id (DfuContext *context, const gchar *platform_id, GError **error) { DfuContextPrivate *priv = GET_PRIVATE (context); DfuContextItem *item; guint i; g_return_val_if_fail (DFU_IS_CONTEXT (context), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* search all devices */ for (i = 0; i < priv->devices->len; i++) { item = g_ptr_array_index (priv->devices, i); if (g_strcmp0 (dfu_device_get_platform_id (item->device), platform_id) == 0) { return g_object_ref (item->device); } } g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_FOUND, "no device matches for %s", platform_id); return NULL; } /** * dfu_context_get_device_default: * @context: a #DfuContext * @error: a #GError, or %NULL * * Gets the default device in the context. * An error is returned if more than one device exists. * * Return value: (transfer full): a #DfuDevice for success, or %NULL for an error * * Since: 0.5.4 **/ DfuDevice * dfu_context_get_device_default (DfuContext *context, GError **error) { DfuContextPrivate *priv = GET_PRIVATE (context); DfuContextItem *item; g_return_val_if_fail (DFU_IS_CONTEXT (context), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* none */ if (priv->devices->len == 0) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_NOT_FOUND, "no attached DFU device"); return NULL; } /* multiple */ if (priv->devices->len > 1) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INVALID_DEVICE, "more than one attached DFU device"); return NULL; } item = g_ptr_array_index (priv->devices, 0); return g_object_ref (item->device); } fwupd-0.7.0/libdfu/dfu-context.h000066400000000000000000000051111267747510300165330ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __DFU_CONTEXT_H #define __DFU_CONTEXT_H #include #include #include "dfu-device.h" G_BEGIN_DECLS #define DFU_TYPE_CONTEXT (dfu_context_get_type ()) G_DECLARE_DERIVABLE_TYPE (DfuContext, dfu_context, DFU, CONTEXT, GObject) struct _DfuContextClass { GObjectClass parent_class; void (*device_added) (DfuContext *context, DfuDevice *device); void (*device_removed) (DfuContext *context, DfuDevice *device); void (*device_changed) (DfuContext *context, DfuDevice *device); /*< private >*/ /* Padding for future expansion */ void (*_dfu_context_reserved1) (void); void (*_dfu_context_reserved2) (void); void (*_dfu_context_reserved3) (void); void (*_dfu_context_reserved4) (void); void (*_dfu_context_reserved5) (void); void (*_dfu_context_reserved6) (void); void (*_dfu_context_reserved7) (void); void (*_dfu_context_reserved8) (void); void (*_dfu_context_reserved9) (void); }; DfuContext *dfu_context_new (void); gboolean dfu_context_enumerate (DfuContext *context, GError **error); GPtrArray *dfu_context_get_devices (DfuContext *context); guint dfu_context_get_timeout (DfuContext *context); void dfu_context_set_timeout (DfuContext *context, guint timeout); DfuDevice *dfu_context_get_device_by_vid_pid (DfuContext *context, guint16 vid, guint16 pid, GError **error); DfuDevice *dfu_context_get_device_by_platform_id (DfuContext *context, const gchar *platform_id, GError **error); DfuDevice *dfu_context_get_device_default (DfuContext *context, GError **error); G_END_DECLS #endif /* __DFU_CONTEXT_H */ fwupd-0.7.0/libdfu/dfu-device-private.h000066400000000000000000000032711267747510300177630ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __DFU_DEVICE_PRIVATE_H #define __DFU_DEVICE_PRIVATE_H #include #include #include #include "dfu-device.h" G_BEGIN_DECLS #define DFU_DEVICE_REPLUG_TIMEOUT 5000 /* ms */ GUsbDevice *dfu_device_get_usb_dev (DfuDevice *device); gboolean dfu_device_has_dfuse_support (DfuDevice *device); void dfu_device_error_fixup (DfuDevice *device, GCancellable *cancellable, GError **error); guint dfu_device_get_download_timeout (DfuDevice *device); gchar *dfu_device_get_quirks_as_string (DfuDevice *device); gboolean dfu_device_set_new_usb_dev (DfuDevice *device, GUsbDevice *dev, GCancellable *cancellable, GError **error); G_END_DECLS #endif /* __DFU_DEVICE_PRIVATE_H */ fwupd-0.7.0/libdfu/dfu-device.c000066400000000000000000001467441267747510300163230ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * SECTION:dfu-device * @short_description: Object representing a DFU-capable device * * This object allows two things: * * - Downloading from the host to the device, optionally with * verification using a DFU or DfuSe firmware file. * * - Uploading from the device to the host to a DFU or DfuSe firmware * file. The file format is chosen automatically, with DfuSe being * chosen if the device contains more than one target. * * See also: #DfuTarget, #DfuFirmware */ #include "config.h" #include #include "dfu-common.h" #include "dfu-device-private.h" #include "dfu-error.h" #include "dfu-target-private.h" static void dfu_device_finalize (GObject *object); /** * DfuDevicePrivate: * * Private #DfuDevice data **/ typedef struct { DfuDeviceAttributes attributes; DfuDeviceQuirks quirks; DfuMode mode; DfuState state; DfuStatus status; GPtrArray *targets; GUsbDevice *dev; gboolean open_new_dev; /* if set new GUsbDevice */ gboolean dfuse_supported; gboolean done_upload_or_download; gchar *display_name; gchar *platform_id; guint16 runtime_pid; guint16 runtime_vid; guint16 runtime_release; guint16 transfer_size; guint8 iface_number; guint dnload_timeout; guint timeout_ms; } DfuDevicePrivate; enum { SIGNAL_STATUS_CHANGED, SIGNAL_STATE_CHANGED, SIGNAL_PERCENTAGE_CHANGED, SIGNAL_LAST }; static guint signals [SIGNAL_LAST] = { 0 }; G_DEFINE_TYPE_WITH_PRIVATE (DfuDevice, dfu_device, G_TYPE_OBJECT) #define GET_PRIVATE(o) (dfu_device_get_instance_private (o)) /** * dfu_device_class_init: **/ static void dfu_device_class_init (DfuDeviceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); /** * DfuDevice::status-changed: * @device: the #DfuDevice instance that emitted the signal * @status: the new #DfuStatus * * The ::status-changed signal is emitted when the status changes. * * Since: 0.5.4 **/ signals [SIGNAL_STATUS_CHANGED] = g_signal_new ("status-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (DfuDeviceClass, status_changed), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); /** * DfuDevice::state-changed: * @device: the #DfuDevice instance that emitted the signal * @state: the new #DfuState * * The ::state-changed signal is emitted when the state changes. * * Since: 0.5.4 **/ signals [SIGNAL_STATE_CHANGED] = g_signal_new ("state-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (DfuDeviceClass, state_changed), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); /** * DfuDevice::percentage-changed: * @device: the #DfuDevice instance that emitted the signal * @percentage: the new percentage * * The ::percentage-changed signal is emitted when the percentage changes. * * Since: 0.5.4 **/ signals [SIGNAL_PERCENTAGE_CHANGED] = g_signal_new ("percentage-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (DfuDeviceClass, percentage_changed), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); object_class->finalize = dfu_device_finalize; } /** * dfu_device_init: **/ static void dfu_device_init (DfuDevice *device) { DfuDevicePrivate *priv = GET_PRIVATE (device); priv->iface_number = 0xff; priv->runtime_pid = 0xffff; priv->runtime_vid = 0xffff; priv->runtime_release = 0xffff; priv->state = DFU_STATE_APP_IDLE; priv->status = DFU_STATUS_OK; priv->targets = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); priv->timeout_ms = 500; priv->transfer_size = 64; } /** * dfu_device_get_transfer_size: * @device: a #GUsbDevice * * Gets the transfer size in bytes. * * Return value: packet size, or 0 for unknown * * Since: 0.5.4 **/ guint16 dfu_device_get_transfer_size (DfuDevice *device) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_return_val_if_fail (DFU_IS_DEVICE (device), 0xffff); return priv->transfer_size; } /** * dfu_device_get_download_timeout: * @device: a #GUsbDevice * * Gets the download timeout in ms. * * Return value: delay, or 0 for unknown * * Since: 0.5.4 **/ guint dfu_device_get_download_timeout (DfuDevice *device) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_return_val_if_fail (DFU_IS_DEVICE (device), 0); return priv->dnload_timeout; } /** * dfu_device_set_transfer_size: * @device: a #GUsbDevice * @transfer_size: maximum packet size * * Sets the transfer size in bytes. * * Since: 0.5.4 **/ void dfu_device_set_transfer_size (DfuDevice *device, guint16 transfer_size) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_return_if_fail (DFU_IS_DEVICE (device)); priv->transfer_size = transfer_size; } /** * dfu_device_finalize: **/ static void dfu_device_finalize (GObject *object) { DfuDevice *device = DFU_DEVICE (object); DfuDevicePrivate *priv = GET_PRIVATE (device); /* don't rely on this */ if (priv->dev != NULL) g_usb_device_close (priv->dev, NULL); g_free (priv->display_name); g_free (priv->platform_id); g_ptr_array_unref (priv->targets); G_OBJECT_CLASS (dfu_device_parent_class)->finalize (object); } typedef struct __attribute__((packed)) { guint8 bLength; guint8 bDescriptorType; guint8 bmAttributes; guint16 wDetachTimeOut; guint16 wTransferSize; guint16 bcdDFUVersion; } DfuFuncDescriptor; /** * dfu_device_parse_iface_data: **/ static void dfu_device_parse_iface_data (DfuDevice *device, GBytes *iface_data) { DfuDevicePrivate *priv = GET_PRIVATE (device); const DfuFuncDescriptor *desc; gsize iface_data_length; guint16 dfu_version; /* parse the functional descriptor */ desc = g_bytes_get_data (iface_data, &iface_data_length); if (iface_data_length != 0x09) { g_warning ("interface found, but not interface data"); return; } /* check sanity */ if (desc->bLength != 0x09) { g_warning ("DFU interface data has incorrect length: 0x%02x", desc->bLength); } /* check transfer size */ priv->transfer_size = desc->wTransferSize; if (priv->transfer_size == 0x0000) { g_warning ("DFU transfer size invalid, using default: 0x%04x", desc->wTransferSize); priv->transfer_size = 64; } /* check DFU version */ dfu_version = GUINT16_FROM_LE (desc->bcdDFUVersion); if (priv->quirks & DFU_DEVICE_QUIRK_IGNORE_INVALID_VERSION) { g_debug ("ignoring quirked DFU version"); } else { if (dfu_version == 0x0100 || dfu_version == 0x0110) { g_debug ("basic DFU, no DfuSe support"); priv->dfuse_supported = FALSE; } else if (dfu_version == 0x011a) { g_debug ("DfuSe support"); priv->dfuse_supported = TRUE; } else { g_warning ("DFU version is invalid: 0x%04x", dfu_version); } } /* ST-specific */ if (priv->dfuse_supported && desc->bmAttributes & DFU_DEVICE_ATTRIBUTE_CAN_ACCELERATE) priv->transfer_size = 0x1000; /* get attributes about the DFU operation */ priv->attributes = desc->bmAttributes; } /** * dfu_device_update_from_iface: **/ static gboolean dfu_device_update_from_iface (DfuDevice *device, GUsbInterface *iface) { DfuMode target_mode = DFU_MODE_UNKNOWN; DfuDevicePrivate *priv = GET_PRIVATE (device); /* runtime */ if (g_usb_interface_get_protocol (iface) == 0x01) target_mode = DFU_MODE_RUNTIME; /* DFU */ if (g_usb_interface_get_protocol (iface) == 0x02) target_mode = DFU_MODE_DFU; /* the DSO Nano has uses 0 instead of 2 when in DFU target_mode */ if (dfu_device_has_quirk (device, DFU_DEVICE_QUIRK_USE_PROTOCOL_ZERO) && g_usb_interface_get_protocol (iface) == 0x00) target_mode = DFU_MODE_DFU; /* nothing found */ if (target_mode == DFU_MODE_UNKNOWN) return FALSE; /* in DFU mode, the interface is supposed to be 0 */ if (target_mode == DFU_MODE_DFU && g_usb_interface_get_number (iface) != 0) g_warning ("iface has to be 0 in DFU mode, got 0x%02i", g_usb_interface_get_number (iface)); /* some devices set the wrong mode */ if (dfu_device_has_quirk (device, DFU_DEVICE_QUIRK_FORCE_DFU_MODE)) target_mode = DFU_MODE_DFU; /* save for reset */ if (target_mode == DFU_MODE_RUNTIME || (priv->quirks & DFU_DEVICE_QUIRK_NO_PID_CHANGE)) { priv->runtime_vid = g_usb_device_get_vid (priv->dev); priv->runtime_pid = g_usb_device_get_pid (priv->dev); priv->runtime_release = g_usb_device_get_release (priv->dev); } priv->mode = target_mode; return TRUE; } /** * dfu_device_add_targets: **/ static gboolean dfu_device_add_targets (DfuDevice *device) { DfuDevicePrivate *priv = GET_PRIVATE (device); guint i; GUsbInterface *iface; g_autoptr(GPtrArray) ifaces = NULL; /* add all DFU-capable targets */ ifaces = g_usb_device_get_interfaces (priv->dev, NULL); if (ifaces == NULL) return FALSE; g_ptr_array_set_size (priv->targets, 0); for (i = 0; i < ifaces->len; i++) { GBytes *iface_data = NULL; DfuTarget *target; iface = g_ptr_array_index (ifaces, i); if (g_usb_interface_get_class (iface) != G_USB_DEVICE_CLASS_APPLICATION_SPECIFIC) continue; if (g_usb_interface_get_subclass (iface) != 0x01) continue; target = dfu_target_new (device, iface); if (target == NULL) continue; /* add target */ priv->iface_number = g_usb_interface_get_number (iface); g_ptr_array_add (priv->targets, target); dfu_device_update_from_iface (device, iface); /* parse any interface data */ iface_data = g_usb_interface_get_extra (iface); if (g_bytes_get_size (iface_data) > 0) dfu_device_parse_iface_data (device, iface_data); } /* the device has no DFU runtime, so cheat */ if (priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) { if (priv->targets->len == 0) { g_debug ("no DFU runtime, so faking device"); priv->iface_number = 0xff; } return TRUE; } return priv->targets->len > 0; } /** * dfu_device_has_quirk: (skip) * @device: A #DfuDevice * @quirk: A #DfuDeviceQuirks * * Returns if a device has a specific quirk * * Return value: %TRUE if the device has this quirk * * Since: 0.5.4 **/ gboolean dfu_device_has_quirk (DfuDevice *device, DfuDeviceQuirks quirk) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_return_val_if_fail (DFU_IS_DEVICE (device), 0x0); return (priv->quirks & quirk) > 0; } /** * dfu_device_can_upload: * @device: a #GUsbDevice * * Gets if the device can upload. * * Return value: %TRUE if the device can upload from device to host * * Since: 0.5.4 **/ gboolean dfu_device_can_upload (DfuDevice *device) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE); return (priv->attributes & DFU_DEVICE_ATTRIBUTE_CAN_UPLOAD) > 0; } /** * dfu_device_can_download: * @device: a #GUsbDevice * * Gets if the device can download. * * Return value: %TRUE if the device can download from host to device * * Since: 0.5.4 **/ gboolean dfu_device_can_download (DfuDevice *device) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE); return (priv->attributes & DFU_DEVICE_ATTRIBUTE_CAN_DOWNLOAD) > 0; } /** * dfu_device_set_timeout: * @device: a #DfuDevice * @timeout_ms: the timeout in ms * * Sets the USB timeout to use when contacting the USB device. * * Since: 0.5.4 **/ void dfu_device_set_timeout (DfuDevice *device, guint timeout_ms) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_return_if_fail (DFU_IS_DEVICE (device)); priv->timeout_ms = timeout_ms; } /** * dfu_device_get_mode: * @device: a #GUsbDevice * * Gets the device mode. * * Return value: enumerated mode, e.g. %DFU_MODE_RUNTIME * * Since: 0.5.4 **/ DfuMode dfu_device_get_mode (DfuDevice *device) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_return_val_if_fail (DFU_IS_DEVICE (device), DFU_MODE_UNKNOWN); return priv->mode; } /** * dfu_device_get_timeout: * @device: a #GUsbDevice * * Gets the device timeout. * * Return value: enumerated timeout in ms * * Since: 0.5.4 **/ guint dfu_device_get_timeout (DfuDevice *device) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_return_val_if_fail (DFU_IS_DEVICE (device), 0); return priv->timeout_ms; } /** * dfu_device_get_state: * @device: a #GUsbDevice * * Gets the device state. * * Return value: enumerated state, e.g. %DFU_STATE_DFU_UPLOAD_IDLE * * Since: 0.5.4 **/ DfuState dfu_device_get_state (DfuDevice *device) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_return_val_if_fail (DFU_IS_DEVICE (device), 0); return priv->state; } /** * dfu_device_get_status: * @device: a #GUsbDevice * * Gets the device status. * * Return value: enumerated status, e.g. %DFU_STATUS_ERR_ADDRESS * * Since: 0.5.4 **/ DfuStatus dfu_device_get_status (DfuDevice *device) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_return_val_if_fail (DFU_IS_DEVICE (device), 0); return priv->status; } /** * dfu_device_has_attribute: (skip) * @device: A #DfuDevice * @attribute: A #DfuDeviceAttributes, e.g. %DFU_DEVICE_ATTRIBUTE_CAN_DOWNLOAD * * Returns if an attribute set for the device. * * Return value: %TRUE if the attribute is set * * Since: 0.5.4 **/ gboolean dfu_device_has_attribute (DfuDevice *device, DfuDeviceAttributes attribute) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_return_val_if_fail (DFU_IS_DEVICE (device), 0x0); return (priv->attributes & attribute) > 0; } /** * dfu_device_has_dfuse_support: * @device: A #DfuDevice * * Returns is DfuSe is supported on a device. * * Return value: %TRUE for DfuSe * * Since: 0.5.4 **/ gboolean dfu_device_has_dfuse_support (DfuDevice *device) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE); return priv->dfuse_supported; } /** * dfu_device_set_quirks: **/ static void dfu_device_set_quirks (DfuDevice *device) { DfuDevicePrivate *priv = GET_PRIVATE (device); guint16 vid, pid, release; vid = g_usb_device_get_vid (priv->dev); pid = g_usb_device_get_pid (priv->dev); release = g_usb_device_get_release (priv->dev); /* 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 */ if (vid == 0x0a5c && pid == 0x6412) priv->quirks |= DFU_DEVICE_QUIRK_IGNORE_RUNTIME; /* Openmoko Freerunner / GTA02 */ if ((vid == 0x1d50 || vid == 0x1457) && pid >= 0x5117 && pid <= 0x5126) priv->quirks |= DFU_DEVICE_QUIRK_IGNORE_POLLTIMEOUT | DFU_DEVICE_QUIRK_NO_PID_CHANGE | DFU_DEVICE_QUIRK_NO_DFU_RUNTIME | DFU_DEVICE_QUIRK_NO_GET_STATUS_UPLOAD; /* OpenPCD Reader */ if (vid == 0x16c0 && pid == 0x076b) priv->quirks |= DFU_DEVICE_QUIRK_IGNORE_POLLTIMEOUT; /* Siemens AG, PXM 40 & PXM 50 */ if (vid == 0x0908 && (pid == 0x02c4 || pid == 0x02c5) && release == 0x0) priv->quirks |= DFU_DEVICE_QUIRK_IGNORE_POLLTIMEOUT; /* Midiman M-Audio Transit */ if (vid == 0x0763 && pid == 0x2806) priv->quirks |= DFU_DEVICE_QUIRK_IGNORE_POLLTIMEOUT; /* the LPC DFU bootloader uses the wrong mode */ if (vid == 0x1fc9 && pid == 0x000c) priv->quirks |= DFU_DEVICE_QUIRK_FORCE_DFU_MODE; /* the Leaflabs Maple3 is known broken */ if (vid == 0x1eaf && pid == 0x0003 && release == 0x0200) priv->quirks |= DFU_DEVICE_QUIRK_IGNORE_INVALID_VERSION; /* m-stack DFU implementation */ if (vid == 0x273f && pid == 0x1003) priv->quirks |= DFU_DEVICE_QUIRK_ATTACH_UPLOAD_DOWNLOAD; /* the DSO Nano has uses 0 instead of 2 when in DFU mode */ // quirks |= DFU_DEVICE_QUIRK_USE_PROTOCOL_ZERO; } /** * dfu_device_new: * @dev: A #GUsbDevice * * Creates a new DFU device object. * * Return value: a new #DfuDevice, or %NULL if @dev was not DFU-capable * * Since: 0.5.4 **/ DfuDevice * dfu_device_new (GUsbDevice *dev) { DfuDevicePrivate *priv; DfuDevice *device; device = g_object_new (DFU_TYPE_DEVICE, NULL); priv = GET_PRIVATE (device); priv->dev = g_object_ref (dev); priv->platform_id = g_strdup (g_usb_device_get_platform_id (dev)); /* set any quirks on the device before adding targets */ dfu_device_set_quirks (device); /* add each alternate interface, although typically there will * be only one */ if (!dfu_device_add_targets (device)) { g_object_unref (device); return NULL; } return device; } /** * dfu_device_get_targets: * @device: a #DfuDevice * * Gets all the targets for this device. * * Return value: (transfer none) (element-type DfuTarget): #DfuTarget, or %NULL * * Since: 0.5.4 **/ GPtrArray * dfu_device_get_targets (DfuDevice *device) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_return_val_if_fail (DFU_IS_DEVICE (device), NULL); return priv->targets; } /** * dfu_device_get_target_by_alt_setting: * @device: a #DfuDevice * @alt_setting: the setting used to find * @error: a #GError, or %NULL * * Gets a target with a specific alternative setting. * * Return value: (transfer full): a #DfuTarget, or %NULL * * Since: 0.5.4 **/ DfuTarget * dfu_device_get_target_by_alt_setting (DfuDevice *device, guint8 alt_setting, GError **error) { DfuDevicePrivate *priv = GET_PRIVATE (device); DfuTarget *target; guint i; g_return_val_if_fail (DFU_IS_DEVICE (device), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* find by ID */ for (i = 0; i < priv->targets->len; i++) { target = g_ptr_array_index (priv->targets, i); if (dfu_target_get_alt_setting (target) == alt_setting) return g_object_ref (target); } /* failed */ g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_FOUND, "No target with alt-setting %i", alt_setting); return NULL; } /** * dfu_device_get_target_by_alt_name: * @device: a #DfuDevice * @alt_name: the name used to find * @error: a #GError, or %NULL * * Gets a target with a specific alternative name. * * Return value: (transfer full): a #DfuTarget, or %NULL * * Since: 0.5.4 **/ DfuTarget * dfu_device_get_target_by_alt_name (DfuDevice *device, const gchar *alt_name, GError **error) { DfuDevicePrivate *priv = GET_PRIVATE (device); DfuTarget *target; guint i; g_return_val_if_fail (DFU_IS_DEVICE (device), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* find by ID */ for (i = 0; i < priv->targets->len; i++) { target = g_ptr_array_index (priv->targets, i); if (g_strcmp0 (dfu_target_get_alt_name (target, NULL), alt_name) == 0) return g_object_ref (target); } /* failed */ g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_FOUND, "No target with alt-name %s", alt_name); return NULL; } /** * dfu_device_get_platform_id: * @device: a #DfuDevice * * Gets the platform ID which normally corresponds to the port in some way. * * Return value: string or %NULL * * Since: 0.5.4 **/ const gchar * dfu_device_get_platform_id (DfuDevice *device) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_return_val_if_fail (DFU_IS_DEVICE (device), NULL); return priv->platform_id; } /** * dfu_device_get_runtime_vid: * @device: a #DfuDevice * * Gets the runtime vendor ID. * * Return value: vendor ID, or 0xffff for unknown * * Since: 0.5.4 **/ guint16 dfu_device_get_runtime_vid (DfuDevice *device) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_return_val_if_fail (DFU_IS_DEVICE (device), 0xffff); return priv->runtime_vid; } /** * dfu_device_get_runtime_pid: * @device: a #DfuDevice * * Gets the runtime product ID. * * Return value: product ID, or 0xffff for unknown * * Since: 0.5.4 **/ guint16 dfu_device_get_runtime_pid (DfuDevice *device) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_return_val_if_fail (DFU_IS_DEVICE (device), 0xffff); return priv->runtime_pid; } /** * dfu_device_get_runtime_release: * @device: a #DfuDevice * * Gets the runtime release number in BCD format. * * Return value: release number, or 0xffff for unknown * * Since: 0.5.4 **/ guint16 dfu_device_get_runtime_release (DfuDevice *device) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_return_val_if_fail (DFU_IS_DEVICE (device), 0xffff); return priv->runtime_release; } /** * dfu_device_get_usb_dev: (skip) * @device: a #DfuDevice * * Gets the internal USB device for the #DfuDevice. * * NOTE: This may change at runtime if the device is replugged or * reset. * * Returns: (transfer none): the internal USB device **/ GUsbDevice * dfu_device_get_usb_dev (DfuDevice *device) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_return_val_if_fail (DFU_IS_DEVICE (device), NULL); return priv->dev; } /** * dfu_device_get_display_name: * @device: a #DfuDevice * * Gets the display name to use for the device. * * Return value: string or %NULL for unset * * Since: 0.5.4 **/ const gchar * dfu_device_get_display_name (DfuDevice *device) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_return_val_if_fail (DFU_IS_DEVICE (device), NULL); return priv->display_name; } /** * dfu_device_set_state: **/ static void dfu_device_set_state (DfuDevice *device, DfuState state) { DfuDevicePrivate *priv = GET_PRIVATE (device); if (priv->state == state) return; priv->state = state; g_signal_emit (device, signals[SIGNAL_STATE_CHANGED], 0, state); } /** * dfu_device_set_status: **/ static void dfu_device_set_status (DfuDevice *device, DfuStatus status) { DfuDevicePrivate *priv = GET_PRIVATE (device); if (priv->status == status) return; priv->status = status; g_signal_emit (device, signals[SIGNAL_STATUS_CHANGED], 0, status); } /** * dfu_device_refresh: * @device: a #DfuDevice * @cancellable: a #GCancellable, or %NULL * @error: a #GError, or %NULL * * Refreshes the cached properties on the DFU device. * * Return value: %TRUE for success * * Since: 0.5.4 **/ gboolean dfu_device_refresh (DfuDevice *device, GCancellable *cancellable, GError **error) { DfuDevicePrivate *priv = GET_PRIVATE (device); gsize actual_length = 0; guint8 buf[6]; g_autoptr(GError) error_local = NULL; g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* no backing USB device */ if (priv->dev == NULL) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "failed to refresh: no GUsbDevice for %s", priv->platform_id); return FALSE; } /* the device has no DFU runtime, so cheat */ if (priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "not supported as no DFU runtime"); return FALSE; } if (!g_usb_device_control_transfer (priv->dev, G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, G_USB_DEVICE_REQUEST_TYPE_CLASS, G_USB_DEVICE_RECIPIENT_INTERFACE, DFU_REQUEST_GETSTATUS, 0, priv->iface_number, buf, sizeof(buf), &actual_length, priv->timeout_ms, cancellable, &error_local)) { g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "cannot get device state: %s", error_local->message); return FALSE; } if (actual_length != 6) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "cannot get device status, invalid size: %04x", (guint) actual_length); } /* status or state changed */ dfu_device_set_status (device, buf[0]); dfu_device_set_state (device, buf[4]); if (dfu_device_has_quirk (device, DFU_DEVICE_QUIRK_IGNORE_POLLTIMEOUT)) { priv->dnload_timeout = 5; } else { priv->dnload_timeout = buf[1] + (((guint32) buf[2]) << 8) + (((guint32) buf[3]) << 16); } g_debug ("refreshed status=%s and state=%s", dfu_status_to_string (priv->status), dfu_state_to_string (priv->state)); return TRUE; } /** * dfu_device_detach: * @device: a #DfuDevice * @cancellable: a #GCancellable, or %NULL * @error: a #GError, or %NULL * * Detaches the device putting it into DFU-mode. * * Return value: %TRUE for success * * Since: 0.5.4 **/ gboolean dfu_device_detach (DfuDevice *device, GCancellable *cancellable, GError **error) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_autoptr(GError) error_local = NULL; g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* already in DFU mode */ switch (priv->state) { case DFU_STATE_APP_IDLE: case DFU_STATE_APP_DETACH: break; default: g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "Already in DFU mode"); return FALSE; } /* no backing USB device */ if (priv->dev == NULL) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "failed to detach: no GUsbDevice for %s", priv->platform_id); return FALSE; } /* the device has no DFU runtime, so cheat */ if (priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "not supported as no DFU runtime"); return FALSE; } /* inform UI there's going to be a detach:attach */ dfu_device_set_state (device, DFU_STATE_APP_DETACH); if (!g_usb_device_control_transfer (priv->dev, G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, G_USB_DEVICE_REQUEST_TYPE_CLASS, G_USB_DEVICE_RECIPIENT_INTERFACE, DFU_REQUEST_DETACH, 0, priv->iface_number, NULL, 0, NULL, priv->timeout_ms, cancellable, &error_local)) { /* refresh the error code */ dfu_device_error_fixup (device, cancellable, &error_local); g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "cannot detach device: %s", error_local->message); return FALSE; } /* do a host reset */ if ((priv->attributes & DFU_DEVICE_ATTRIBUTE_WILL_DETACH) == 0) { g_debug ("doing device reset as host will not self-reset"); if (!dfu_device_reset (device, error)) return FALSE; } return TRUE; } /** * dfu_device_abort: * @device: a #DfuDevice * @cancellable: a #GCancellable, or %NULL * @error: a #GError, or %NULL * * Aborts any upload or download in progress. * * Return value: %TRUE for success * * Since: 0.5.4 **/ gboolean dfu_device_abort (DfuDevice *device, GCancellable *cancellable, GError **error) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_autoptr(GError) error_local = NULL; g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* no backing USB device */ if (priv->dev == NULL) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "failed to abort: no GUsbDevice for %s", priv->platform_id); return FALSE; } /* the device has no DFU runtime, so cheat */ if (priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "not supported as no DFU runtime"); return FALSE; } if (!g_usb_device_control_transfer (priv->dev, G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, G_USB_DEVICE_REQUEST_TYPE_CLASS, G_USB_DEVICE_RECIPIENT_INTERFACE, DFU_REQUEST_ABORT, 0, priv->iface_number, NULL, 0, NULL, priv->timeout_ms, cancellable, &error_local)) { /* refresh the error code */ dfu_device_error_fixup (device, cancellable, &error_local); g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "cannot abort device: %s", error_local->message); return FALSE; } return TRUE; } /** * dfu_device_clear_status: * @device: a #DfuDevice * @cancellable: a #GCancellable, or %NULL * @error: a #GError, or %NULL * * Clears any error status on the DFU device. * * Return value: %TRUE for success * * Since: 0.5.4 **/ gboolean dfu_device_clear_status (DfuDevice *device, GCancellable *cancellable, GError **error) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_autoptr(GError) error_local = NULL; g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* no backing USB device */ if (priv->dev == NULL) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "failed to clear status: no GUsbDevice for %s", priv->platform_id); return FALSE; } /* the device has no DFU runtime, so cheat */ if (priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "not supported as no DFU runtime"); return FALSE; } if (!g_usb_device_control_transfer (priv->dev, G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, G_USB_DEVICE_REQUEST_TYPE_CLASS, G_USB_DEVICE_RECIPIENT_INTERFACE, DFU_REQUEST_CLRSTATUS, 0, priv->iface_number, NULL, 0, NULL, priv->timeout_ms, cancellable, &error_local)) { /* refresh the error code */ dfu_device_error_fixup (device, cancellable, &error_local); g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "cannot clear status on the device: %s", error_local->message); return FALSE; } return TRUE; } /** * dfu_device_get_interface: * @device: a #DfuDevice * * Gets the interface number. * * Since: 0.5.4 **/ guint8 dfu_device_get_interface (DfuDevice *device) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_return_val_if_fail (DFU_IS_DEVICE (device), 0xff); return priv->iface_number; } /** * dfu_device_open: * @device: a #DfuDevice * @flags: #DfuDeviceOpenFlags, e.g. %DFU_DEVICE_OPEN_FLAG_NONE * @cancellable: a #GCancellable, or %NULL * @error: a #GError, or %NULL * * Opens a DFU-capable device. * * Return value: %TRUE for success * * Since: 0.5.4 **/ gboolean dfu_device_open (DfuDevice *device, DfuDeviceOpenFlags flags, GCancellable *cancellable, GError **error) { DfuDevicePrivate *priv = GET_PRIVATE (device); guint idx; g_autoptr(GError) error_local = NULL; g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* no backing USB device */ if (priv->dev == NULL) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "failed to open: no GUsbDevice for %s", priv->platform_id); return FALSE; } /* open */ if (!g_usb_device_open (priv->dev, &error_local)) { if (g_error_matches (error_local, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_ALREADY_OPEN)) { g_debug ("device already open, ignoring"); return TRUE; } if (g_error_matches (error_local, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_PERMISSION_DENIED)) { g_set_error (error, DFU_ERROR, DFU_ERROR_PERMISSION_DENIED, "%s", error_local->message); return FALSE; } g_set_error (error, DFU_ERROR, DFU_ERROR_INVALID_DEVICE, "cannot open device %s: %s", g_usb_device_get_platform_id (priv->dev), error_local->message); return FALSE; } /* claim the correct interface if set */ if (priv->iface_number != 0xff) { if (!g_usb_device_claim_interface (priv->dev, (gint) priv->iface_number, 0, &error_local)) { g_set_error (error, DFU_ERROR, DFU_ERROR_INVALID_DEVICE, "cannot claim interface %i: %s", priv->iface_number, error_local->message); return FALSE; } } /* get product name if it exists */ idx = g_usb_device_get_product_index (priv->dev); if (idx != 0x00) priv->display_name = g_usb_device_get_string_descriptor (priv->dev, idx, NULL); /* the device has no DFU runtime, so cheat */ if (priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) { priv->state = DFU_STATE_APP_IDLE; priv->status = DFU_STATUS_OK; flags |= DFU_DEVICE_OPEN_FLAG_NO_AUTO_REFRESH; } /* automatically abort any uploads or downloads */ if ((flags & DFU_DEVICE_OPEN_FLAG_NO_AUTO_REFRESH) == 0) { if (!dfu_device_refresh (device, cancellable, error)) return FALSE; switch (priv->state) { case DFU_STATE_DFU_UPLOAD_IDLE: case DFU_STATE_DFU_DNLOAD_IDLE: case DFU_STATE_DFU_DNLOAD_SYNC: g_debug ("aborting transfer %s", dfu_status_to_string (priv->status)); if (!dfu_device_abort (device, cancellable, error)) return FALSE; break; case DFU_STATE_DFU_ERROR: g_debug ("clearing error %s", dfu_status_to_string (priv->status)); if (!dfu_device_clear_status (device, cancellable, error)) return FALSE; break; default: break; } } priv->open_new_dev = TRUE; return TRUE; } /** * dfu_device_close: * @device: a #DfuDevice * @error: a #GError, or %NULL * * Closes a DFU device. * * Return value: %TRUE for success * * Since: 0.5.4 **/ gboolean dfu_device_close (DfuDevice *device, GError **error) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_autoptr(GError) error_local = NULL; /* no backing USB device */ if (priv->dev == NULL) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "failed to close: no GUsbDevice for %s", priv->platform_id); return FALSE; } /* close if open */ if (!g_usb_device_close (priv->dev, &error_local)) { if (g_error_matches (error_local, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_NOT_OPEN)) { g_debug ("device not open, so ignoring error for close"); return TRUE; } g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, error_local->message); return FALSE; } priv->open_new_dev = FALSE; return TRUE; } /** * dfu_device_set_new_usb_dev: **/ gboolean dfu_device_set_new_usb_dev (DfuDevice *device, GUsbDevice *dev, GCancellable *cancellable, GError **error) { DfuDevicePrivate *priv = GET_PRIVATE (device); /* same */ if (priv->dev == dev) { g_warning ("setting GUsbDevice with same dev?!"); return TRUE; } /* device removed */ if (dev == NULL) { g_debug ("invalidating backing GUsbDevice"); g_clear_object (&priv->dev); g_ptr_array_set_size (priv->targets, 0); return TRUE; } /* close */ if (priv->dev != NULL) { gboolean tmp = priv->open_new_dev; if (!dfu_device_close (device, error)) return FALSE; priv->open_new_dev = tmp; } /* set the new USB device */ g_set_object (&priv->dev, dev); /* should be the same */ if (g_strcmp0 (priv->platform_id, g_usb_device_get_platform_id (dev)) != 0) { g_warning ("platform ID changed when setting new GUsbDevice?!"); g_free (priv->platform_id); priv->platform_id = g_strdup (g_usb_device_get_platform_id (dev)); } /* update all the targets */ if (!dfu_device_add_targets (device)) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "replugged device is not DFU-capable"); return FALSE; } /* reclaim */ if (priv->open_new_dev) { g_debug ("automatically reopening device"); if (!dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE, cancellable, error)) return FALSE; } return TRUE; } typedef struct { DfuDevice *device; GError **error; GMainLoop *loop; GUsbDevice *dev; guint cnt; guint timeout; } DfuDeviceReplugHelper; /** * dfu_device_replug_helper_free: **/ static void dfu_device_replug_helper_free (DfuDeviceReplugHelper *helper) { if (helper->dev != NULL) g_object_unref (helper->dev); g_object_unref (helper->device); g_main_loop_unref (helper->loop); g_free (helper); } /** * dfu_device_replug_helper_cb: **/ static gboolean dfu_device_replug_helper_cb (gpointer user_data) { DfuDeviceReplugHelper *helper = (DfuDeviceReplugHelper *) user_data; DfuDevicePrivate *priv = GET_PRIVATE (helper->device); /* did the backing GUsbDevice change */ if (helper->dev != priv->dev) { g_debug ("device changed GUsbDevice %p->%p", helper->dev, priv->dev); g_set_object (&helper->dev, priv->dev); /* success */ if (helper->dev != NULL) { g_main_loop_quit (helper->loop); return FALSE; } } /* set a limit */ if (helper->cnt++ * 100 > helper->timeout) { g_debug ("gave up waiting for device replug"); if (helper->dev == NULL) { g_set_error_literal (helper->error, DFU_ERROR, DFU_ERROR_INVALID_DEVICE, "target went away but did not come back"); } else { g_set_error_literal (helper->error, DFU_ERROR, DFU_ERROR_INVALID_DEVICE, "target did not disconnect"); } g_main_loop_quit (helper->loop); return FALSE; } /* continue waiting */ g_debug ("waiting for device replug for %ims -- state is %s", helper->cnt * 100, dfu_state_to_string (priv->state)); return TRUE; } /** * dfu_device_wait_for_replug: * @device: a #DfuDevice * @timeout: the maximum amount of time to wait * @cancellable: a #GCancellable, or %NULL * @error: a #GError, or %NULL * * Waits for a DFU device to disconnect and reconnect. * This does rely on a #DfuContext being set up before this is called. * * Return value: %TRUE for success * * Since: 0.5.4 **/ gboolean dfu_device_wait_for_replug (DfuDevice *device, guint timeout, GCancellable *cancellable, GError **error) { DfuDevicePrivate *priv = GET_PRIVATE (device); DfuDeviceReplugHelper *helper; GError *error_tmp = NULL; const guint replug_poll = 100; /* ms */ helper = g_new0 (DfuDeviceReplugHelper, 1); helper->loop = g_main_loop_new (NULL, FALSE); helper->device = g_object_ref (device); helper->dev = g_object_ref (priv->dev); helper->error = &error_tmp; helper->timeout = timeout; g_timeout_add_full (G_PRIORITY_DEFAULT, replug_poll, dfu_device_replug_helper_cb, helper, (GDestroyNotify) dfu_device_replug_helper_free); g_main_loop_run (helper->loop); if (error_tmp != NULL) { g_propagate_error (error, error_tmp); return FALSE; } return TRUE; } /** * dfu_device_reset: * @device: a #DfuDevice * @error: a #GError, or %NULL * * Resets the USB device. * * Return value: %TRUE for success * * Since: 0.5.4 **/ gboolean dfu_device_reset (DfuDevice *device, GError **error) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_autoptr(GError) error_local = NULL; g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* no backing USB device */ if (priv->dev == NULL) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "failed to reset: no GUsbDevice for %s", priv->platform_id); return FALSE; } if (!g_usb_device_reset (priv->dev, &error_local)) { g_set_error (error, DFU_ERROR, DFU_ERROR_INVALID_DEVICE, "cannot reset USB device: %s [%i]", error_local->message, error_local->code); return FALSE; } return TRUE; } /** * dfu_device_attach: * @device: a #DfuDevice * @error: a #GError, or %NULL * * Move device from DFU mode to runtime. * * Return value: %TRUE for success * * Since: 0.5.4 **/ gboolean dfu_device_attach (DfuDevice *device, GError **error) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_autoptr(GError) error_local = NULL; g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* already in runtime mode */ switch (priv->state) { case DFU_STATE_APP_IDLE: case DFU_STATE_APP_DETACH: g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "Already in application runtime mode"); return FALSE; default: break; } /* inform UI there's going to be a re-attach */ dfu_device_set_state (device, DFU_STATE_DFU_MANIFEST_WAIT_RESET); /* handle m-stack DFU bootloaders */ if (!priv->done_upload_or_download && (priv->quirks & DFU_DEVICE_QUIRK_ATTACH_UPLOAD_DOWNLOAD) > 0) { g_autoptr(GBytes) chunk = NULL; g_autoptr(DfuTarget) target = NULL; g_debug ("doing dummy upload to work around m-stack quirk"); target = dfu_device_get_target_by_alt_setting (device, 0, error); if (target == NULL) return FALSE; chunk = dfu_target_upload_chunk (target, 0, NULL, error); if (chunk == NULL) return FALSE; } /* there's a a special command for ST devices */ if (priv->dfuse_supported) { //FIXME return TRUE; } /* normal DFU mode just needs a bus reset */ return dfu_device_reset (device, error); } /** * dfu_device_percentage_cb: **/ static void dfu_device_percentage_cb (DfuTarget *target, guint percentage, DfuDevice *device) { /* FIXME: divide by number of targets? */ g_signal_emit (device, signals[SIGNAL_PERCENTAGE_CHANGED], 0, percentage); } /** * dfu_device_upload: * @device: a #DfuDevice * @flags: flags to use, e.g. %DFU_TARGET_TRANSFER_FLAG_VERIFY * @cancellable: a #GCancellable, or %NULL * @error: a #GError, or %NULL * * Uploads firmware from the target to the host. * * Return value: (transfer full): the uploaded firmware, or %NULL for error * * Since: 0.5.4 **/ DfuFirmware * dfu_device_upload (DfuDevice *device, DfuTargetTransferFlags flags, GCancellable *cancellable, GError **error) { DfuDevicePrivate *priv = GET_PRIVATE (device); guint i; g_autoptr(DfuFirmware) firmware = NULL; /* no backing USB device */ if (priv->dev == NULL) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "failed to upload: no GUsbDevice for %s", priv->platform_id); return NULL; } /* create ahead of time */ firmware = dfu_firmware_new (); dfu_firmware_set_vid (firmware, priv->runtime_vid); dfu_firmware_set_pid (firmware, priv->runtime_pid); dfu_firmware_set_release (firmware, 0xffff); /* APP -> DFU */ if (priv->mode == DFU_MODE_RUNTIME) { if ((flags & DFU_TARGET_TRANSFER_FLAG_DETACH) == 0) { g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "device is not in DFU mode"); return NULL; } g_debug ("detaching"); /* detach and USB reset */ if (!dfu_device_detach (device, NULL, error)) return NULL; if (!dfu_device_wait_for_replug (device, DFU_DEVICE_REPLUG_TIMEOUT, cancellable, error)) return NULL; } /* upload from each target */ for (i = 0; i < priv->targets->len; i++) { DfuTarget *target; guint id; g_autoptr(DfuImage) image = NULL; /* upload to target and proxy signals */ target = g_ptr_array_index (priv->targets, i); id = g_signal_connect (target, "percentage-changed", G_CALLBACK (dfu_device_percentage_cb), device); image = dfu_target_upload (target, DFU_TARGET_TRANSFER_FLAG_NONE, cancellable, error); g_signal_handler_disconnect (target, id); if (image == NULL) return NULL; dfu_firmware_add_image (firmware, image); } /* do not do the dummy upload for quirked devices */ priv->done_upload_or_download = TRUE; /* choose the most appropriate type */ if (priv->targets->len > 1) { g_debug ("switching to DefuSe automatically"); dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_DFUSE); } else { dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_DFU_1_0); } /* do host reset */ if ((flags & DFU_TARGET_TRANSFER_FLAG_ATTACH) > 0 || (flags & DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME) > 0) { if (!dfu_device_attach (device, error)) return NULL; } /* boot to runtime */ if (flags & DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME) { g_debug ("booting to runtime"); if (!dfu_device_wait_for_replug (device, DFU_DEVICE_REPLUG_TIMEOUT, cancellable, error)) return NULL; } /* success */ return g_object_ref (firmware); } /** * dfu_device_download: * @device: a #DfuDevice * @firmware: a #DfuFirmware * @flags: flags to use, e.g. %DFU_TARGET_TRANSFER_FLAG_VERIFY * @cancellable: a #GCancellable, or %NULL * @error: a #GError, or %NULL * * Downloads firmware from the host to the target, optionally verifying * the transfer. * * Return value: %TRUE for success * * Since: 0.5.4 **/ gboolean dfu_device_download (DfuDevice *device, DfuFirmware *firmware, DfuTargetTransferFlags flags, GCancellable *cancellable, GError **error) { DfuDevicePrivate *priv = GET_PRIVATE (device); GPtrArray *images; gboolean ret; guint i; g_autoptr(GPtrArray) targets = NULL; /* no backing USB device */ if (priv->dev == NULL) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "failed to download: no GUsbDevice for %s", priv->platform_id); return FALSE; } /* do we allow wildcard VID:PID matches */ if ((flags & DFU_TARGET_TRANSFER_FLAG_WILDCARD_VID) == 0) { if (dfu_firmware_get_vid (firmware) == 0xffff) { g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "firmware vendor ID not specified"); return FALSE; } } if ((flags & DFU_TARGET_TRANSFER_FLAG_WILDCARD_PID) == 0) { if (dfu_firmware_get_pid (firmware) == 0xffff) { g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "firmware product ID not specified"); return FALSE; } } /* check vendor matches */ if (dfu_firmware_get_vid (firmware) != 0xffff && priv->runtime_pid != 0xffff && dfu_firmware_get_vid (firmware) != priv->runtime_vid) { g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "vendor ID incorrect, expected 0x%04x got 0x%04x\n", dfu_firmware_get_vid (firmware), priv->runtime_vid); return FALSE; } /* check product matches */ if (dfu_firmware_get_pid (firmware) != 0xffff && priv->runtime_pid != 0xffff && dfu_firmware_get_pid (firmware) != priv->runtime_pid) { g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "product ID incorrect, expected 0x%04x got 0x%04x", dfu_firmware_get_pid (firmware), priv->runtime_pid); return FALSE; } /* APP -> DFU */ if (priv->mode == DFU_MODE_RUNTIME) { if ((flags & DFU_TARGET_TRANSFER_FLAG_DETACH) == 0) { g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "device is not in DFU mode"); return FALSE; } /* detach and USB reset */ g_debug ("detaching"); if (!dfu_device_detach (device, NULL, error)) return FALSE; if (!dfu_device_wait_for_replug (device, DFU_DEVICE_REPLUG_TIMEOUT, NULL, error)) return FALSE; } /* download each target */ images = dfu_firmware_get_images (firmware); if (images->len == 0) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INVALID_FILE, "no images in firmware file"); return FALSE; } for (i = 0; i < images->len; i++) { DfuCipherKind cipher_fw; DfuCipherKind cipher_target; DfuImage *image; DfuTargetTransferFlags flags_local = DFU_TARGET_TRANSFER_FLAG_NONE; const gchar *alt_name; guint id; g_autoptr(DfuTarget) target_tmp = NULL; image = g_ptr_array_index (images, i); target_tmp = dfu_device_get_target_by_alt_setting (device, dfu_image_get_alt_setting (image), error); if (target_tmp == NULL) return FALSE; /* we don't actually need to print this, but it makes sure the * target is setup prior to doing the cipher checks */ alt_name = dfu_target_get_alt_name (target_tmp, error); if (alt_name == NULL) return FALSE; g_debug ("downloading to target: %s", alt_name); /* check we're flashing a compatible firmware */ cipher_target = dfu_target_get_cipher_kind (target_tmp); cipher_fw = dfu_firmware_get_cipher_kind (firmware); if ((flags & DFU_TARGET_TRANSFER_FLAG_ANY_CIPHER) == 0) { if (cipher_fw != DFU_CIPHER_KIND_NONE && cipher_target == DFU_CIPHER_KIND_NONE) { g_set_error (error, DFU_ERROR, DFU_ERROR_INVALID_FILE, "Device is only accepting " "unsigned firmware, not %s", dfu_cipher_kind_to_string (cipher_fw)); return FALSE; } if (cipher_fw == DFU_CIPHER_KIND_NONE && cipher_target != DFU_CIPHER_KIND_NONE) { g_set_error (error, DFU_ERROR, DFU_ERROR_INVALID_FILE, "Device is only accepting " "firmware with %s cipher kind", dfu_cipher_kind_to_string (cipher_target)); return FALSE; } } /* download onto target */ if (flags & DFU_TARGET_TRANSFER_FLAG_VERIFY) flags_local = DFU_TARGET_TRANSFER_FLAG_VERIFY; id = g_signal_connect (target_tmp, "percentage-changed", G_CALLBACK (dfu_device_percentage_cb), device); ret = dfu_target_download (target_tmp, image, flags_local, cancellable, error); g_signal_handler_disconnect (target_tmp, id); if (!ret) return FALSE; } /* do not do the dummy upload for quirked devices */ priv->done_upload_or_download = TRUE; /* attempt to switch back to runtime */ if ((flags & DFU_TARGET_TRANSFER_FLAG_ATTACH) > 0 || (flags & DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME) > 0) { if (!dfu_device_attach (device, error)) return FALSE; } /* boot to runtime */ if (flags & DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME) { g_debug ("booting to runtime to set auto-boot"); if (!dfu_device_wait_for_replug (device, DFU_DEVICE_REPLUG_TIMEOUT, cancellable, error)) return FALSE; } return TRUE; } /** * dfu_device_error_fixup: **/ void dfu_device_error_fixup (DfuDevice *device, GCancellable *cancellable, GError **error) { DfuDevicePrivate *priv = GET_PRIVATE (device); /* sad panda */ if (error == NULL) return; /* not the right error to query */ if (!g_error_matches (*error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_NOT_SUPPORTED)) return; /* get the status */ if (!dfu_device_refresh (device, cancellable, NULL)) return; /* not in an error state */ if (priv->state != DFU_STATE_DFU_ERROR) return; /* prefix the error */ switch (priv->status) { case DFU_STATUS_OK: /* ignore */ break; case DFU_STATUS_ERR_VENDOR: g_prefix_error (error, "read protection is active: "); break; default: g_prefix_error (error, "[%s,%s]: ", dfu_state_to_string (priv->state), dfu_status_to_string (priv->status)); break; } } /** * dfu_device_get_quirks_as_string: (skip) * @device: a #DfuDevice * * Gets a string describing the quirks set for a device. * * Return value: string, or %NULL for no quirks * * Since: 0.5.4 **/ gchar * dfu_device_get_quirks_as_string (DfuDevice *device) { DfuDevicePrivate *priv = GET_PRIVATE (device); GString *str; /* just append to a string */ str = g_string_new (""); if (priv->quirks & DFU_DEVICE_QUIRK_IGNORE_POLLTIMEOUT) g_string_append_printf (str, "ignore-polltimeout|"); if (priv->quirks & DFU_DEVICE_QUIRK_FORCE_DFU_MODE) g_string_append_printf (str, "force-dfu-mode|"); if (priv->quirks & DFU_DEVICE_QUIRK_IGNORE_INVALID_VERSION) g_string_append_printf (str, "ignore-invalid-version|"); if (priv->quirks & DFU_DEVICE_QUIRK_USE_PROTOCOL_ZERO) g_string_append_printf (str, "use-protocol-zero|"); if (priv->quirks & DFU_DEVICE_QUIRK_NO_PID_CHANGE) g_string_append_printf (str, "no-pid-change|"); if (priv->quirks & DFU_DEVICE_QUIRK_NO_GET_STATUS_UPLOAD) g_string_append_printf (str, "no-get-status-upload|"); if (priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) g_string_append_printf (str, "no-dfu-runtime|"); if (priv->quirks & DFU_DEVICE_QUIRK_ATTACH_UPLOAD_DOWNLOAD) g_string_append_printf (str, "attach-upload-download|"); if (priv->quirks & DFU_DEVICE_QUIRK_IGNORE_RUNTIME) g_string_append_printf (str, "ignore-runtime|"); /* a well behaved device */ if (str->len == 0) { g_string_free (str, TRUE); return NULL; } /* remove trailing pipe */ g_string_truncate (str, str->len - 1); return g_string_free (str, FALSE); } fwupd-0.7.0/libdfu/dfu-device.h000066400000000000000000000161571267747510300163220ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __DFU_DEVICE_H #define __DFU_DEVICE_H #include #include #include #include "dfu-common.h" #include "dfu-target.h" #include "dfu-firmware.h" G_BEGIN_DECLS #define DFU_TYPE_DEVICE (dfu_device_get_type ()) G_DECLARE_DERIVABLE_TYPE (DfuDevice, dfu_device, DFU, DEVICE, GObject) /** * DfuDeviceOpenFlags: * @DFU_DEVICE_OPEN_FLAG_NONE: No flags set * @DFU_DEVICE_OPEN_FLAG_NO_AUTO_REFRESH: Do not do the initial GET_STATUS * * The optional flags used for opening the target. **/ typedef enum { DFU_DEVICE_OPEN_FLAG_NONE = 0, DFU_DEVICE_OPEN_FLAG_NO_AUTO_REFRESH = (1 << 0), /*< private >*/ DFU_DEVICE_OPEN_FLAG_LAST } DfuDeviceOpenFlags; /** * DfuDeviceQuirks: * @DFU_DEVICE_QUIRK_NONE: No device quirks * @DFU_DEVICE_QUIRK_IGNORE_POLLTIMEOUT: Ignore the device download timeout * @DFU_DEVICE_QUIRK_FORCE_DFU_MODE: Force DFU mode * @DFU_DEVICE_QUIRK_IGNORE_INVALID_VERSION: Ignore invalid version numbers * @DFU_DEVICE_QUIRK_USE_PROTOCOL_ZERO: Fix up the protocol number * @DFU_DEVICE_QUIRK_NO_PID_CHANGE: Accept the same VID:PID when changing modes * @DFU_DEVICE_QUIRK_NO_GET_STATUS_UPLOAD: Do not do GetStatus when uploading * @DFU_DEVICE_QUIRK_NO_DFU_RUNTIME: No DFU runtime interface is provided * @DFU_DEVICE_QUIRK_ATTACH_UPLOAD_DOWNLOAD: An upload or download is required for attach * @DFU_DEVICE_QUIRK_IGNORE_RUNTIME: Device has broken DFU runtime support * * The workarounds for different devices. **/ typedef enum { DFU_DEVICE_QUIRK_NONE = 0, DFU_DEVICE_QUIRK_IGNORE_POLLTIMEOUT = (1 << 0), DFU_DEVICE_QUIRK_FORCE_DFU_MODE = (1 << 1), DFU_DEVICE_QUIRK_IGNORE_INVALID_VERSION = (1 << 2), DFU_DEVICE_QUIRK_USE_PROTOCOL_ZERO = (1 << 3), DFU_DEVICE_QUIRK_NO_PID_CHANGE = (1 << 4), DFU_DEVICE_QUIRK_NO_GET_STATUS_UPLOAD = (1 << 5), DFU_DEVICE_QUIRK_NO_DFU_RUNTIME = (1 << 6), DFU_DEVICE_QUIRK_ATTACH_UPLOAD_DOWNLOAD = (1 << 7), DFU_DEVICE_QUIRK_IGNORE_RUNTIME = (1 << 8), /*< private >*/ DFU_DEVICE_QUIRK_LAST } DfuDeviceQuirks; /** * DfuDeviceAttributes: * @DFU_DEVICE_ATTRIBUTE_NONE: No attributes set * @DFU_DEVICE_ATTRIBUTE_CAN_DOWNLOAD: Can download from host->device * @DFU_DEVICE_ATTRIBUTE_CAN_UPLOAD: Can upload from device->host * @DFU_DEVICE_ATTRIBUTE_MANIFEST_TOL: Can answer GetStatus in manifest * @DFU_DEVICE_ATTRIBUTE_WILL_DETACH: Will self-detach * @DFU_DEVICE_ATTRIBUTE_CAN_ACCELERATE: Use a larger transfer size for speed * * The device DFU attributes. **/ typedef enum { DFU_DEVICE_ATTRIBUTE_NONE = 0, DFU_DEVICE_ATTRIBUTE_CAN_DOWNLOAD = (1 << 0), DFU_DEVICE_ATTRIBUTE_CAN_UPLOAD = (1 << 1), DFU_DEVICE_ATTRIBUTE_MANIFEST_TOL = (1 << 2), DFU_DEVICE_ATTRIBUTE_WILL_DETACH = (1 << 3), DFU_DEVICE_ATTRIBUTE_CAN_ACCELERATE = (1 << 7), /*< private >*/ DFU_DEVICE_ATTRIBUTE_LAST } DfuDeviceAttributes; struct _DfuDeviceClass { GObjectClass parent_class; void (*status_changed) (DfuDevice *device, DfuStatus status); void (*state_changed) (DfuDevice *device, DfuState state); void (*percentage_changed) (DfuDevice *device, guint percentage); /*< private >*/ /* Padding for future expansion */ void (*_dfu_device_reserved1) (void); void (*_dfu_device_reserved2) (void); void (*_dfu_device_reserved3) (void); void (*_dfu_device_reserved4) (void); void (*_dfu_device_reserved5) (void); void (*_dfu_device_reserved6) (void); void (*_dfu_device_reserved7) (void); void (*_dfu_device_reserved8) (void); void (*_dfu_device_reserved9) (void); }; DfuDevice *dfu_device_new (GUsbDevice *dev); gboolean dfu_device_open (DfuDevice *device, DfuDeviceOpenFlags flags, GCancellable *cancellable, GError **error); gboolean dfu_device_close (DfuDevice *device, GError **error); const gchar *dfu_device_get_platform_id (DfuDevice *device); GPtrArray *dfu_device_get_targets (DfuDevice *device); DfuTarget *dfu_device_get_target_by_alt_setting (DfuDevice *device, guint8 alt_setting, GError **error); DfuTarget *dfu_device_get_target_by_alt_name (DfuDevice *device, const gchar *alt_name, GError **error); const gchar *dfu_device_get_display_name (DfuDevice *device); guint16 dfu_device_get_runtime_vid (DfuDevice *device); guint16 dfu_device_get_runtime_pid (DfuDevice *device); guint16 dfu_device_get_runtime_release (DfuDevice *device); gboolean dfu_device_reset (DfuDevice *device, GError **error); gboolean dfu_device_attach (DfuDevice *device, GError **error); gboolean dfu_device_wait_for_replug (DfuDevice *device, guint timeout, GCancellable *cancellable, GError **error); DfuFirmware *dfu_device_upload (DfuDevice *device, DfuTargetTransferFlags flags, GCancellable *cancellable, GError **error); gboolean dfu_device_download (DfuDevice *device, DfuFirmware *firmware, DfuTargetTransferFlags flags, GCancellable *cancellable, GError **error); gboolean dfu_device_refresh (DfuDevice *device, GCancellable *cancellable, GError **error); gboolean dfu_device_detach (DfuDevice *device, GCancellable *cancellable, GError **error); gboolean dfu_device_abort (DfuDevice *device, GCancellable *cancellable, GError **error); gboolean dfu_device_clear_status (DfuDevice *device, GCancellable *cancellable, GError **error); guint8 dfu_device_get_interface (DfuDevice *device); DfuMode dfu_device_get_mode (DfuDevice *device); DfuState dfu_device_get_state (DfuDevice *device); DfuStatus dfu_device_get_status (DfuDevice *device); guint16 dfu_device_get_transfer_size (DfuDevice *device); guint dfu_device_get_timeout (DfuDevice *device); gboolean dfu_device_can_upload (DfuDevice *device); gboolean dfu_device_can_download (DfuDevice *device); gboolean dfu_device_has_attribute (DfuDevice *device, DfuDeviceAttributes attribute); gboolean dfu_device_has_quirk (DfuDevice *device, DfuDeviceQuirks quirk); void dfu_device_set_transfer_size (DfuDevice *device, guint16 transfer_size); void dfu_device_set_timeout (DfuDevice *device, guint timeout_ms); G_END_DECLS #endif /* __DFU_DEVICE_H */ fwupd-0.7.0/libdfu/dfu-element-private.h000066400000000000000000000024211267747510300201510ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __DFU_ELEMENT_PRIVATE_H #define __DFU_ELEMENT_PRIVATE_H #include "dfu-element.h" G_BEGIN_DECLS DfuElement *dfu_element_from_dfuse (const guint8 *data, guint32 length, guint32 *consumed, GError **error); GBytes *dfu_element_to_dfuse (DfuElement *element); G_END_DECLS #endif /* __DFU_ELEMENT_PRIVATE_H */ fwupd-0.7.0/libdfu/dfu-element.c000066400000000000000000000200541267747510300164760ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * SECTION:dfu-element * @short_description: Object representing a binary element * * This object represents an binary blob of data at a specific address. * * This allows relocatable data segments to be stored in different * locations on the device itself. * * See also: #DfuImage, #DfuFirmware */ #include "config.h" #include #include #include "dfu-common.h" #include "dfu-element-private.h" #include "dfu-error.h" static void dfu_element_finalize (GObject *object); /** * DfuElementPrivate: * * Private #DfuElement data **/ typedef struct { GBytes *contents; guint32 target_size; guint32 address; } DfuElementPrivate; G_DEFINE_TYPE_WITH_PRIVATE (DfuElement, dfu_element, G_TYPE_OBJECT) #define GET_PRIVATE(o) (dfu_element_get_instance_private (o)) /** * dfu_element_class_init: **/ static void dfu_element_class_init (DfuElementClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = dfu_element_finalize; } /** * dfu_element_init: **/ static void dfu_element_init (DfuElement *element) { } /** * dfu_element_finalize: **/ static void dfu_element_finalize (GObject *object) { DfuElement *element = DFU_ELEMENT (object); DfuElementPrivate *priv = GET_PRIVATE (element); if (priv->contents != NULL) g_bytes_unref (priv->contents); G_OBJECT_CLASS (dfu_element_parent_class)->finalize (object); } /** * dfu_element_new: * * Creates a new DFU element object. * * Return value: a new #DfuElement * * Since: 0.5.4 **/ DfuElement * dfu_element_new (void) { DfuElement *element; element = g_object_new (DFU_TYPE_ELEMENT, NULL); return element; } /** * dfu_element_get_contents: * @element: a #DfuElement * * Gets the element data. * * Return value: (transfer none): element data * * Since: 0.5.4 **/ GBytes * dfu_element_get_contents (DfuElement *element) { DfuElementPrivate *priv = GET_PRIVATE (element); g_return_val_if_fail (DFU_IS_ELEMENT (element), NULL); return priv->contents; } /** * dfu_element_get_address: * @element: a #DfuElement * * Gets the alternate setting. * * Return value: integer, or 0x00 for unset * * Since: 0.5.4 **/ guint32 dfu_element_get_address (DfuElement *element) { DfuElementPrivate *priv = GET_PRIVATE (element); g_return_val_if_fail (DFU_IS_ELEMENT (element), 0x00); return priv->address; } /** * dfu_element_set_contents: * @element: a #DfuElement * @contents: element data * * Sets the element data. * * Since: 0.5.4 **/ void dfu_element_set_contents (DfuElement *element, GBytes *contents) { DfuElementPrivate *priv = GET_PRIVATE (element); g_return_if_fail (DFU_IS_ELEMENT (element)); g_return_if_fail (contents != NULL); if (priv->contents == contents) return; if (priv->contents != NULL) g_bytes_unref (priv->contents); priv->contents = g_bytes_ref (contents); } /** * dfu_element_set_address: * @element: a #DfuElement * @address: vendor ID, or 0xffff for unset * * Sets the vendor ID. * * Since: 0.5.4 **/ void dfu_element_set_address (DfuElement *element, guint32 address) { DfuElementPrivate *priv = GET_PRIVATE (element); g_return_if_fail (DFU_IS_ELEMENT (element)); priv->address = address; } /** * dfu_element_to_string: * @element: a #DfuElement * * Returns a string representaiton of the object. * * Return value: NULL terminated string, or %NULL for invalid * * Since: 0.5.4 **/ gchar * dfu_element_to_string (DfuElement *element) { DfuElementPrivate *priv = GET_PRIVATE (element); GString *str; g_return_val_if_fail (DFU_IS_ELEMENT (element), NULL); str = g_string_new (""); g_string_append_printf (str, "address: 0x%02x\n", priv->address); if (priv->target_size > 0) { g_string_append_printf (str, "target: 0x%04x\n", priv->target_size); } if (priv->contents != NULL) { g_string_append_printf (str, "contents: 0x%04x\n", (guint32) g_bytes_get_size (priv->contents)); } g_string_truncate (str, str->len - 1); return g_string_free (str, FALSE); } /** * dfu_element_set_target_size: * @element: a #DfuElement * @target_size: size in bytes * * Sets a target size for the element. If the prepared element is smaller * than this then it will be padded with NUL bytes up to the required size. * * Since: 0.5.4 **/ void dfu_element_set_target_size (DfuElement *element, guint32 target_size) { DfuElementPrivate *priv = GET_PRIVATE (element); const guint8 *data; gsize length; guint8 *buf; g_autoptr(GBytes) contents_padded = NULL; g_return_if_fail (DFU_IS_ELEMENT (element)); /* save for dump */ priv->target_size = target_size; /* no need to pad */ if (priv->contents == NULL) return; if (g_bytes_get_size (priv->contents) >= target_size) return; /* reallocate and pad */ data = g_bytes_get_data (priv->contents, &length); buf = g_malloc0 (target_size); g_assert (buf != NULL); memcpy (buf, data, length); /* replace */ g_bytes_unref (priv->contents); priv->contents = g_bytes_new_take (buf, target_size); } /* DfuSe element header */ typedef struct __attribute__((packed)) { guint32 address; guint32 size; } DfuSeElementPrefix; /** * dfu_element_from_dfuse: (skip) * @data: data buffer * @length: length of @data we can access * @consumed: (out): the number of bytes we consued * @error: a #GError, or %NULL * * Unpacks an element from DfuSe data. * * Returns: a #DfuElement, or %NULL for error **/ DfuElement * dfu_element_from_dfuse (const guint8 *data, guint32 length, guint32 *consumed, GError **error) { DfuElement *element = NULL; DfuElementPrivate *priv; DfuSeElementPrefix *el = (DfuSeElementPrefix *) data; guint32 size; g_assert_cmpint(sizeof(DfuSeElementPrefix), ==, 8); /* check input buffer size */ if (length < sizeof(DfuSeElementPrefix)) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "invalid element data size %u", (guint32) length); return NULL; } /* check size */ size = GUINT32_FROM_LE (el->size); if (size + sizeof(DfuSeElementPrefix) > length) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "invalid element size %u, only %u bytes left", size, (guint32) (length - sizeof(DfuSeElementPrefix))); return NULL; } /* create new element */ element = dfu_element_new (); priv = GET_PRIVATE (element); priv->address = GUINT32_FROM_LE (el->address); priv->contents = g_bytes_new (data + sizeof(DfuSeElementPrefix), size); /* return size */ if (consumed != NULL) *consumed = sizeof(DfuSeElementPrefix) + size; return element; } /** * dfu_element_to_dfuse: (skip) * @element: a #DfuElement * * Packs a DfuSe element. * * Returns: (transfer full): the packed data **/ GBytes * dfu_element_to_dfuse (DfuElement *element) { DfuElementPrivate *priv = GET_PRIVATE (element); DfuSeElementPrefix *el; const guint8 *data; gsize length; guint8 *buf; data = g_bytes_get_data (priv->contents, &length); buf = g_malloc0 (length + sizeof (DfuSeElementPrefix)); el = (DfuSeElementPrefix *) buf; el->address = GUINT32_TO_LE (priv->address); el->size = GUINT32_TO_LE (length); memcpy (buf + sizeof (DfuSeElementPrefix), data, length); return g_bytes_new_take (buf, length + sizeof (DfuSeElementPrefix)); } fwupd-0.7.0/libdfu/dfu-element.h000066400000000000000000000041621267747510300165050ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __DFU_ELEMENT_H #define __DFU_ELEMENT_H #include #include G_BEGIN_DECLS #define DFU_TYPE_ELEMENT (dfu_element_get_type ()) G_DECLARE_DERIVABLE_TYPE (DfuElement, dfu_element, DFU, ELEMENT, GObject) struct _DfuElementClass { GObjectClass parent_class; /*< private >*/ /* Padding for future expansion */ void (*_dfu_element_reserved1) (void); void (*_dfu_element_reserved2) (void); void (*_dfu_element_reserved3) (void); void (*_dfu_element_reserved4) (void); void (*_dfu_element_reserved5) (void); void (*_dfu_element_reserved6) (void); void (*_dfu_element_reserved7) (void); void (*_dfu_element_reserved8) (void); void (*_dfu_element_reserved9) (void); }; DfuElement *dfu_element_new (void); GBytes *dfu_element_get_contents (DfuElement *element); guint32 dfu_element_get_address (DfuElement *element); void dfu_element_set_contents (DfuElement *element, GBytes *contents); void dfu_element_set_address (DfuElement *element, guint32 address); void dfu_element_set_target_size (DfuElement *element, guint32 target_size); gchar *dfu_element_to_string (DfuElement *element); G_END_DECLS #endif /* __DFU_ELEMENT_H */ fwupd-0.7.0/libdfu/dfu-error.c000066400000000000000000000025521267747510300162010ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * SECTION:dfu-error * @short_description: Error defines for libdfu * * This documents the error domain and codes used by libdfu. */ #include "config.h" #include #include "dfu-error.h" /** * dfu_error_quark: * * Return value: An error quark. * * Since: 0.5.4 **/ GQuark dfu_error_quark (void) { static GQuark quark = 0; if (!quark) quark = g_quark_from_static_string ("DfuError"); return quark; } fwupd-0.7.0/libdfu/dfu-error.h000066400000000000000000000035701267747510300162070ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __DFU_ERROR_H #define __DFU_ERROR_H #include #define DFU_ERROR dfu_error_quark() /** * DfuError: * @DFU_ERROR_INTERNAL: Internal error * @DFU_ERROR_VERIFY_FAILED: Failed to verify write * @DFU_ERROR_INVALID_FILE: Invalid file format * @DFU_ERROR_INVALID_DEVICE: Invalid device type * @DFU_ERROR_NOT_FOUND: Resource not found * @DFU_ERROR_NOT_SUPPORTED: Action was not supported * @DFU_ERROR_PERMISSION_DENIED: Failed due to access permissions * * The error code. **/ typedef enum { DFU_ERROR_INTERNAL, /* Since: 0.5.4 */ DFU_ERROR_VERIFY_FAILED, /* Since: 0.5.4 */ DFU_ERROR_INVALID_FILE, /* Since: 0.5.4 */ DFU_ERROR_INVALID_DEVICE, /* Since: 0.5.4 */ DFU_ERROR_NOT_FOUND, /* Since: 0.5.4 */ DFU_ERROR_NOT_SUPPORTED, /* Since: 0.5.4 */ DFU_ERROR_PERMISSION_DENIED, /* Since: 0.5.4 */ /*< private >*/ DFU_ERROR_LAST } DfuError; GQuark dfu_error_quark (void); #endif /* __DFU_ERROR_H */ fwupd-0.7.0/libdfu/dfu-firmware.c000066400000000000000000001172211267747510300166640ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * SECTION:dfu-firmware * @short_description: Object representing a DFU or DfuSe firmware file * * This object allows reading and writing firmware files either in * raw, DFU or DfuSe formats. * * A #DfuFirmware can be made up of several #DfuImages, although * typically there is only one. * * See also: #DfuImage */ #include "config.h" #include #include #include "dfu-common.h" #include "dfu-error.h" #include "dfu-firmware.h" #include "dfu-image-private.h" static void dfu_firmware_finalize (GObject *object); /** * DfuFirmwarePrivate: * * Private #DfuFirmware data **/ typedef struct { GHashTable *metadata; GPtrArray *images; guint16 vid; guint16 pid; guint16 release; guint32 crc; DfuCipherKind cipher_kind; DfuFirmwareFormat format; } DfuFirmwarePrivate; G_DEFINE_TYPE_WITH_PRIVATE (DfuFirmware, dfu_firmware, G_TYPE_OBJECT) #define GET_PRIVATE(o) (dfu_firmware_get_instance_private (o)) /** * dfu_firmware_class_init: **/ static void dfu_firmware_class_init (DfuFirmwareClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = dfu_firmware_finalize; } /** * dfu_firmware_init: **/ static void dfu_firmware_init (DfuFirmware *firmware) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); priv->vid = 0xffff; priv->pid = 0xffff; priv->release = 0xffff; priv->images = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); priv->metadata = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); } /** * dfu_firmware_finalize: **/ static void dfu_firmware_finalize (GObject *object) { DfuFirmware *firmware = DFU_FIRMWARE (object); DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); g_ptr_array_unref (priv->images); g_hash_table_destroy (priv->metadata); G_OBJECT_CLASS (dfu_firmware_parent_class)->finalize (object); } /** * dfu_firmware_new: * * Creates a new DFU firmware object. * * Return value: a new #DfuFirmware * * Since: 0.5.4 **/ DfuFirmware * dfu_firmware_new (void) { DfuFirmware *firmware; firmware = g_object_new (DFU_TYPE_FIRMWARE, NULL); return firmware; } /** * dfu_firmware_get_image: * @firmware: a #DfuFirmware * @alt_setting: an alternative setting, typically 0x00 * * Gets an image from the firmware file. * * Return value: (transfer none): a #DfuImage, or %NULL for not found * * Since: 0.5.4 **/ DfuImage * dfu_firmware_get_image (DfuFirmware *firmware, guint8 alt_setting) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); DfuImage *im; guint i; g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), NULL); /* find correct image */ for (i = 0; i < priv->images->len; i++) { im = g_ptr_array_index (priv->images, i); if (dfu_image_get_alt_setting (im) == alt_setting) return im; } return NULL; } /** * dfu_firmware_get_image_by_name: * @firmware: a #DfuFirmware * @name: an alternative setting name * * Gets an image from the firmware file. * * Return value: (transfer none): a #DfuImage, or %NULL for not found * * Since: 0.5.4 **/ DfuImage * dfu_firmware_get_image_by_name (DfuFirmware *firmware, const gchar *name) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); DfuImage *im; guint i; g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), NULL); /* find correct image */ for (i = 0; i < priv->images->len; i++) { im = g_ptr_array_index (priv->images, i); if (g_strcmp0 (dfu_image_get_name (im), name) == 0) return im; } return NULL; } /** * dfu_firmware_get_image_default: * @firmware: a #DfuFirmware * * Gets the default image from the firmware file. * * Return value: (transfer none): a #DfuImage, or %NULL for not found * * Since: 0.5.4 **/ DfuImage * dfu_firmware_get_image_default (DfuFirmware *firmware) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), NULL); if (priv->images->len == 0) return NULL; return g_ptr_array_index (priv->images, 0); } /** * dfu_firmware_get_images: * @firmware: a #DfuFirmware * * Gets all the images contained in this firmware file. * * Return value: (transfer none) (element-type DfuImage): list of images * * Since: 0.5.4 **/ GPtrArray * dfu_firmware_get_images (DfuFirmware *firmware) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), NULL); return priv->images; } /** * dfu_firmware_get_size: * @firmware: a #DfuFirmware * * Gets the size of all the images in the firmware. * * This only returns actual data that would be sent to the device and * does not include any padding. * * Return value: a integer value, or 0 if there are no images. * * Since: 0.5.4 **/ guint32 dfu_firmware_get_size (DfuFirmware *firmware) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); guint32 length = 0; guint i; g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), 0); for (i = 0; i < priv->images->len; i++) { DfuImage *image = g_ptr_array_index (priv->images, i); length += dfu_image_get_size (image); } return length; } /** * dfu_firmware_add_image: * @firmware: a #DfuFirmware * @image: a #DfuImage * * Adds an image to the list of images. * * Since: 0.5.4 **/ void dfu_firmware_add_image (DfuFirmware *firmware, DfuImage *image) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); g_return_if_fail (DFU_IS_FIRMWARE (firmware)); g_return_if_fail (DFU_IS_IMAGE (image)); g_ptr_array_add (priv->images, g_object_ref (image)); } /** * dfu_firmware_get_vid: * @firmware: a #DfuFirmware * * Gets the vendor ID. * * Return value: a vendor ID, or 0xffff for unset * * Since: 0.5.4 **/ guint16 dfu_firmware_get_vid (DfuFirmware *firmware) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), 0xffff); return priv->vid; } /** * dfu_firmware_get_pid: * @firmware: a #DfuFirmware * * Gets the product ID. * * Return value: a product ID, or 0xffff for unset * * Since: 0.5.4 **/ guint16 dfu_firmware_get_pid (DfuFirmware *firmware) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), 0xffff); return priv->pid; } /** * dfu_firmware_get_release: * @firmware: a #DfuFirmware * * Gets the device ID. * * Return value: a device ID, or 0xffff for unset * * Since: 0.5.4 **/ guint16 dfu_firmware_get_release (DfuFirmware *firmware) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), 0xffff); return priv->release; } /** * dfu_firmware_get_format: * @firmware: a #DfuFirmware * * Gets the DFU version. * * Return value: a version, or 0x0 for unset * * Since: 0.5.4 **/ guint16 dfu_firmware_get_format (DfuFirmware *firmware) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), 0xffff); return priv->format; } /** * dfu_firmware_set_vid: * @firmware: a #DfuFirmware * @vid: vendor ID, or 0xffff for unset * * Sets the vendor ID. * * Since: 0.5.4 **/ void dfu_firmware_set_vid (DfuFirmware *firmware, guint16 vid) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); g_return_if_fail (DFU_IS_FIRMWARE (firmware)); priv->vid = vid; } /** * dfu_firmware_set_pid: * @firmware: a #DfuFirmware * @pid: product ID, or 0xffff for unset * * Sets the product ID. * * Since: 0.5.4 **/ void dfu_firmware_set_pid (DfuFirmware *firmware, guint16 pid) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); g_return_if_fail (DFU_IS_FIRMWARE (firmware)); priv->pid = pid; } /** * dfu_firmware_set_release: * @firmware: a #DfuFirmware * @release: device ID, or 0xffff for unset * * Sets the device ID. * * Since: 0.5.4 **/ void dfu_firmware_set_release (DfuFirmware *firmware, guint16 release) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); g_return_if_fail (DFU_IS_FIRMWARE (firmware)); priv->release = release; } /** * dfu_firmware_set_format: * @firmware: a #DfuFirmware * @format: a #DfuFirmwareFormat, e.g. %DFU_FIRMWARE_FORMAT_DFUSE * * Sets the DFU version in BCD format. * * Since: 0.5.4 **/ void dfu_firmware_set_format (DfuFirmware *firmware, DfuFirmwareFormat format) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); g_return_if_fail (DFU_IS_FIRMWARE (firmware)); priv->format = format; } typedef struct __attribute__((packed)) { guint16 release; guint16 pid; guint16 vid; guint16 ver; guint8 sig[3]; guint8 len; guint32 crc; } DfuFirmwareFooter; static guint32 _crctbl[] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; /** * dfu_firmware_generate_crc32: **/ static guint32 dfu_firmware_generate_crc32 (const guint8 *data, gsize length) { guint i; guint32 accum = 0xffffffff; for (i = 0; i < length; i++) accum = _crctbl[(accum^data[i]) & 0xff] ^ (accum >> 8); return accum; } /** * dfu_firmware_ihex_parse_uint8: **/ static guint8 dfu_firmware_ihex_parse_uint8 (const gchar *data, guint pos) { gchar buffer[3]; memcpy (buffer, data + pos, 2); buffer[2] = '\0'; return g_ascii_strtoull (buffer, NULL, 16); } /** * dfu_firmware_ihex_parse_uint16: **/ static guint16 dfu_firmware_ihex_parse_uint16 (const gchar *data, guint pos) { gchar buffer[5]; memcpy (buffer, data + pos, 4); buffer[4] = '\0'; return g_ascii_strtoull (buffer, NULL, 16); } #define DFU_INHX32_RECORD_TYPE_DATA 0 #define DFU_INHX32_RECORD_TYPE_EOF 1 #define DFU_INHX32_RECORD_TYPE_EXTENDED 4 /** * dfu_firmware_add_ihex: **/ static gboolean dfu_firmware_add_ihex (DfuFirmware *firmware, GBytes *bytes, DfuFirmwareParseFlags flags, GError **error) { const gchar *in_buffer; gsize len_in; guint16 addr_high = 0; guint16 addr_low = 0; guint32 addr32 = 0; guint32 addr32_last = 0; guint8 checksum; guint8 data_tmp; guint8 len_tmp; guint8 type; guint end; guint i; guint j; guint offset = 0; g_autoptr(DfuElement) element = NULL; g_autoptr(DfuImage) image = NULL; g_autoptr(GBytes) contents = NULL; g_autoptr(GString) string = NULL; g_return_val_if_fail (bytes != NULL, FALSE); /* create element */ image = dfu_image_new (); dfu_image_set_name (image, "ihex"); element = dfu_element_new (); /* parse records */ in_buffer = g_bytes_get_data (bytes, &len_in); string = g_string_new (""); while (offset < len_in) { /* check starting token */ if (in_buffer[offset] != ':') { g_set_error (error, DFU_ERROR, DFU_ERROR_INVALID_FILE, "invalid starting token, got %c at %x", in_buffer[offset], offset); return FALSE; } /* check there's enough data for the smallest possible record */ if (offset + 12 > (guint) len_in) { g_set_error (error, DFU_ERROR, DFU_ERROR_INVALID_FILE, "record incomplete at %i, length %i", offset, (guint) len_in); return FALSE; } /* length, 16-bit address, type */ len_tmp = dfu_firmware_ihex_parse_uint8 (in_buffer, offset+1); addr_low = dfu_firmware_ihex_parse_uint16 (in_buffer, offset+3); type = dfu_firmware_ihex_parse_uint8 (in_buffer, offset+7); /* position of checksum */ end = offset + 9 + len_tmp * 2; if (end > (guint) len_in) { g_set_error (error, DFU_ERROR, DFU_ERROR_INVALID_FILE, "checksum > file length: %u", end); return FALSE; } /* verify checksum */ if ((flags & DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST) == 0) { checksum = 0; for (i = offset + 1; i < end + 2; i += 2) { data_tmp = dfu_firmware_ihex_parse_uint8 (in_buffer, i); checksum += data_tmp; } if (checksum != 0) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INVALID_FILE, "invalid record checksum"); return FALSE; } } /* process different record types */ switch (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 %04x", addr_low); dfu_element_set_address (element, addr_low); } addr32 = addr_high + addr_low; } /* parse bytes from line */ for (i = offset + 9; i < end; i += 2) { /* any holes in the hex record */ len_tmp = addr32 - addr32_last; if (addr32_last > 0x0 && len_tmp > 1) { for (j = 1; j < len_tmp; j++) { g_debug ("filling address 0x%04x", addr32_last + j); /* although 0xff might be clearer, * we can't write 0xffff to pic14 */ g_string_append_c (string, 0x00); } } /* write into buf */ data_tmp = dfu_firmware_ihex_parse_uint8 (in_buffer, i); g_string_append_c (string, data_tmp); g_debug ("writing address 0x%04x", addr32); addr32_last = addr32++; } break; case DFU_INHX32_RECORD_TYPE_EOF: break; case DFU_INHX32_RECORD_TYPE_EXTENDED: addr_high = dfu_firmware_ihex_parse_uint16 (in_buffer, offset+9); g_error ("set base address %x", addr_high); addr_high <<= 16; addr32 = addr_high + addr_low; break; default: g_set_error (error, DFU_ERROR, DFU_ERROR_INVALID_FILE, "invalid ihex record type %i", 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; } } /* add single image */ contents = g_bytes_new (string->str, string->len); dfu_element_set_contents (element, contents); dfu_image_add_element (image, element); dfu_firmware_add_image (firmware, image); dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_INTEL_HEX); return TRUE; } /** * dfu_firmware_write_data_ihex_element: **/ static gboolean dfu_firmware_write_data_ihex_element (DfuElement *element, GString *str, GError **error) { GBytes *contents; const guint8 *data; const guint chunk_size = 16; gsize len; guint chunk_len; guint i; guint j; /* get number of chunks */ contents = dfu_element_get_contents (element); data = g_bytes_get_data (contents, &len); for (i = 0; i < len; i += chunk_size) { guint8 checksum = 0; /* length, 16-bit address, type */ chunk_len = MIN (len - i, 16); g_string_append_printf (str, ":%02X%04X%02X", chunk_len, dfu_element_get_address (element) + i, DFU_INHX32_RECORD_TYPE_DATA); for (j = 0; j < chunk_len; j++) g_string_append_printf (str, "%02X", data[i+j]); /* add checksum */ for (j = 0; j < (chunk_len * 2) + 8; j++) checksum += str->str[str->len - (j + 1)]; g_string_append_printf (str, "%02X\n", checksum); } return TRUE; } /** * dfu_firmware_write_data_ihex: **/ static GBytes * dfu_firmware_write_data_ihex (DfuFirmware *firmware, GError **error) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); DfuElement *element; DfuImage *image; GPtrArray *elements; guint i; guint j; g_autoptr(GString) str = NULL; /* write all the element data */ str = g_string_new (""); for (i = 0; i < priv->images->len; i++) { image = g_ptr_array_index (priv->images, i); elements = dfu_image_get_elements (image); for (j = 0; j < elements->len; j++) { element = g_ptr_array_index (elements, j); if (!dfu_firmware_write_data_ihex_element (element, str, error)) return NULL; } } /* add EOF */ g_string_append_printf (str, ":000000%02XFF\n", DFU_INHX32_RECORD_TYPE_EOF); return g_bytes_new (str->str, str->len); } /** * dfu_firmware_add_binary: **/ static gboolean dfu_firmware_add_binary (DfuFirmware *firmware, GBytes *bytes, GError **error) { g_autoptr(DfuElement) element = NULL; g_autoptr(DfuImage) image = NULL; image = dfu_image_new (); element = dfu_element_new (); dfu_element_set_contents (element, bytes); dfu_image_add_element (image, element); dfu_firmware_add_image (firmware, image); return TRUE; } /* DfuSe header */ typedef struct __attribute__((packed)) { guint8 sig[5]; guint8 ver; guint32 image_size; guint8 targets; } DfuSePrefix; /** * dfu_firmware_add_dfuse: **/ static gboolean dfu_firmware_add_dfuse (DfuFirmware *firmware, GBytes *bytes, GError **error) { DfuSePrefix *prefix; gsize len; guint32 offset = sizeof(DfuSePrefix); guint8 *data; guint i; /* check the prefix (BE) */ data = (guint8 *) g_bytes_get_data (bytes, &len); prefix = (DfuSePrefix *) data; if (memcmp (prefix->sig, "DfuSe", 5) != 0) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "invalid DfuSe prefix"); return FALSE; } /* check the version */ if (prefix->ver != 0x01) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "invalid DfuSe version, got %02x", prefix->ver); return FALSE; } /* check image size */ if (GUINT32_FROM_LE (prefix->image_size) != len) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "invalid DfuSe image size, " "got %" G_GUINT32_FORMAT ", " "expected %" G_GSIZE_FORMAT, GUINT32_FROM_LE (prefix->image_size), len); return FALSE; } /* parse the image targets */ len -= sizeof(DfuSePrefix); for (i = 0; i < prefix->targets; i++) { guint consumed; g_autoptr(DfuImage) image = NULL; image = dfu_image_from_dfuse (data + offset, len, &consumed, error); if (image == NULL) return FALSE; dfu_firmware_add_image (firmware, image); offset += consumed; len -= consumed; } return TRUE; } /** * dfu_firmware_write_data_dfuse: **/ static GBytes * dfu_firmware_write_data_dfuse (DfuFirmware *firmware, GError **error) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); DfuSePrefix *prefix; guint i; guint32 image_size_total = 0; guint32 offset = sizeof (DfuSePrefix); guint8 *buf; g_autoptr(GPtrArray) dfuse_images = NULL; /* get all the image data */ dfuse_images = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref); for (i = 0; i < priv->images->len; i++) { DfuImage *im = g_ptr_array_index (priv->images, i); GBytes *contents; contents = dfu_image_to_dfuse (im); image_size_total += g_bytes_get_size (contents); g_ptr_array_add (dfuse_images, contents); } g_debug ("image_size_total: %i", image_size_total); buf = g_malloc0 (sizeof (DfuSePrefix) + image_size_total); /* DfuSe header */ prefix = (DfuSePrefix *) buf; memcpy (prefix->sig, "DfuSe", 5); prefix->ver = 0x01; prefix->image_size = offset + image_size_total; prefix->targets = priv->images->len; /* copy images */ for (i = 0; i < dfuse_images->len; i++) { GBytes *contents = g_ptr_array_index (dfuse_images, i); gsize length; const guint8 *data; data = g_bytes_get_data (contents, &length); memcpy (buf + offset, data, length); offset += length; } /* return blob */ return g_bytes_new_take (buf, sizeof (DfuSePrefix) + image_size_total); } /** * dfu_firmware_parse_metadata: * * The representation in memory is as follows: * * uint16 signature='MD' * uint8 number_of_keys * uint8 number_of_keys * uint8 key(n)_length * ... key(n) (no NUL) * uint8 value(n)_length * ... value(n) (no NUL) * **/ static gboolean dfu_firmware_parse_metadata (DfuFirmware *firmware, const guint8 *data, guint data_length, guint32 footer_size, GError **error) { guint i; guint idx = data_length - footer_size + 2; guint kvlen; guint number_keys; /* not big enough */ if (footer_size <= 0x10) return TRUE; /* signature invalid */ if (memcmp (&data[data_length - footer_size], "MD", 2) != 0) return TRUE; /* parse key=value store */ number_keys = data[idx++]; for (i = 0; i < number_keys; i++) { g_autofree gchar *key = NULL; g_autofree gchar *value = NULL; /* parse key */ kvlen = data[idx++]; if (kvlen > 233) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "metadata table corrupt, key=%i", kvlen); return FALSE; } if (idx + kvlen + 0x10 > data_length) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "metadata table corrupt"); return FALSE; } key = g_strndup ((const gchar *) data + idx, kvlen); idx += kvlen; /* parse value */ kvlen = data[idx++]; if (kvlen > 233) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "metadata table corrupt, value=%i", kvlen); return FALSE; } if (idx + kvlen + 0x10 > data_length) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "metadata table corrupt"); return FALSE; } value = g_strndup ((const gchar *) data + idx, kvlen); idx += kvlen; dfu_firmware_set_metadata (firmware, key, value); } return TRUE; } /** * dfu_firmware_parse_data: * @firmware: a #DfuFirmware * @bytes: raw firmware data * @flags: optional flags, e.g. %DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST * @error: a #GError, or %NULL * * Parses firmware data which may have an optional DFU suffix. * * Return value: %TRUE for success * * Since: 0.5.4 **/ gboolean dfu_firmware_parse_data (DfuFirmware *firmware, GBytes *bytes, DfuFirmwareParseFlags flags, GError **error) { DfuFirmwareFooter *ftr; DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); const gchar *cipher_str; gsize len; guint32 crc_new; guint32 size; guint8 *data; g_autoptr(GBytes) contents = NULL; g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), FALSE); g_return_val_if_fail (bytes != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* sanity check */ g_assert_cmpint(sizeof(DfuSePrefix), ==, 11); /* set defaults */ priv->vid = 0xffff; priv->pid = 0xffff; priv->release = 0xffff; /* this is ihex */ data = (guint8 *) g_bytes_get_data (bytes, &len); if (data[0] == ':') return dfu_firmware_add_ihex (firmware, bytes, flags, error); /* too small to be a DFU file */ if (len < 16) { priv->format = DFU_FIRMWARE_FORMAT_RAW; return dfu_firmware_add_binary (firmware, bytes, error); } /* check for DFU signature */ ftr = (DfuFirmwareFooter *) &data[len-sizeof(DfuFirmwareFooter)]; if (memcmp (ftr->sig, "UFD", 3) != 0) { priv->format = DFU_FIRMWARE_FORMAT_RAW; return dfu_firmware_add_binary (firmware, bytes, error); } /* check version */ priv->format = GUINT16_FROM_LE (ftr->ver); if ((flags & DFU_FIRMWARE_PARSE_FLAG_NO_VERSION_TEST) == 0) { if (priv->format != DFU_FIRMWARE_FORMAT_DFU_1_0 && priv->format != DFU_FIRMWARE_FORMAT_DFUSE) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "version check failed, got %04x", priv->format); return FALSE; } } /* verify the checksum */ priv->crc = GUINT32_FROM_LE (ftr->crc); if ((flags & DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST) == 0) { crc_new = dfu_firmware_generate_crc32 (data, len - 4); if (priv->crc != crc_new) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "CRC failed, expected %04x, got %04x", crc_new, GUINT32_FROM_LE (ftr->crc)); return FALSE; } } /* set from footer */ dfu_firmware_set_vid (firmware, GUINT16_FROM_LE (ftr->vid)); dfu_firmware_set_pid (firmware, GUINT16_FROM_LE (ftr->pid)); dfu_firmware_set_release (firmware, GUINT16_FROM_LE (ftr->release)); /* check reported length */ size = GUINT16_FROM_LE (ftr->len); if (size > len) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "reported firmware size %04x larger than file %04x", (guint) size, (guint) len); return FALSE; } /* parse the optional metadata segment */ if ((flags & DFU_FIRMWARE_PARSE_FLAG_NO_METADATA) == 0) { if (!dfu_firmware_parse_metadata (firmware, data, len, size, error)) return FALSE; } /* set this automatically */ cipher_str = dfu_firmware_get_metadata (firmware, DFU_METADATA_KEY_CIPHER_KIND); if (cipher_str != NULL) { if (g_strcmp0 (cipher_str, "XTEA") == 0) priv->cipher_kind = DFU_CIPHER_KIND_XTEA; else g_warning ("Unknown CipherKind: %s", cipher_str); } /* parse DfuSe prefix */ contents = g_bytes_new_from_bytes (bytes, 0, len - size); if (priv->format == DFU_FIRMWARE_FORMAT_DFUSE) return dfu_firmware_add_dfuse (firmware, contents, error); /* just copy old-plain DFU file */ return dfu_firmware_add_binary (firmware, contents, error); } /** * dfu_firmware_parse_file: * @firmware: a #DfuFirmware * @file: a #GFile to load and parse * @flags: optional flags, e.g. %DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST * @cancellable: a #GCancellable, or %NULL * @error: a #GError, or %NULL * * Parses a DFU firmware, which may contain an optional footer. * * Return value: %TRUE for success * * Since: 0.5.4 **/ gboolean dfu_firmware_parse_file (DfuFirmware *firmware, GFile *file, DfuFirmwareParseFlags flags, GCancellable *cancellable, GError **error) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); gchar *contents = NULL; gsize length = 0; g_autofree gchar *basename = NULL; g_autoptr(GBytes) bytes = NULL; g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), FALSE); g_return_val_if_fail (G_IS_FILE (file), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* guess cipher kind based on file extension */ basename = g_file_get_basename (file); if (g_str_has_suffix (basename, ".xdfu")) priv->cipher_kind = DFU_CIPHER_KIND_XTEA; if (!g_file_load_contents (file, cancellable, &contents, &length, NULL, error)) return FALSE; bytes = g_bytes_new_take (contents, length); return dfu_firmware_parse_data (firmware, bytes, flags, error); } /** * dfu_firmware_get_metadata: * @firmware: a #DfuFirmware * @key: metadata string key * * Gets metadata from the store with a specific key. * * Return value: the metadata value, or %NULL for unset * * Since: 0.5.4 **/ const gchar * dfu_firmware_get_metadata (DfuFirmware *firmware, const gchar *key) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); return g_hash_table_lookup (priv->metadata, key); } /** * dfu_firmware_set_metadata: * @firmware: a #DfuFirmware * @key: metadata string key * @value: metadata string value * * Sets a metadata value with a specific key. * * Since: 0.5.4 **/ void dfu_firmware_set_metadata (DfuFirmware *firmware, const gchar *key, const gchar *value) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); g_debug ("adding metadata %s=%s", key, value); g_hash_table_insert (priv->metadata, g_strdup (key), g_strdup (value)); } /** * dfu_firmware_remove_metadata: * @firmware: a #DfuFirmware * @key: metadata string key * * Removes a metadata item from the store * * Since: 0.5.4 **/ void dfu_firmware_remove_metadata (DfuFirmware *firmware, const gchar *key) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); g_debug ("removing metadata %s", key); g_hash_table_remove (priv->metadata, key); } /** * dfu_firmware_build_metadata_table: **/ static GBytes * dfu_firmware_build_metadata_table (DfuFirmware *firmware, GError **error) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); GList *l; guint8 mdbuf[239]; guint idx = 0; guint number_keys; g_autoptr(GList) keys = NULL; /* no metadata */ if (g_hash_table_size (priv->metadata) == 0) return g_bytes_new (NULL, 0); /* check the number of keys */ keys = g_hash_table_get_keys (priv->metadata); number_keys = g_list_length (keys); if (number_keys > 59) { g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "too many metadata keys (%i)", number_keys); return NULL; } /* write the signature */ mdbuf[idx++] = 'M'; mdbuf[idx++] = 'D'; mdbuf[idx++] = number_keys; for (l = keys; l != NULL; l = l->next) { const gchar *key; const gchar *value; guint key_len; guint value_len; /* check key and value length */ key = l->data; key_len = strlen (key); if (key_len > 233) { g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "metdata key too long: %s", key); return NULL; } value = g_hash_table_lookup (priv->metadata, key); value_len = strlen (value); if (value_len > 233) { g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "value too long: %s", value); return NULL; } /* do we still have space? */ if (idx + key_len + value_len + 2 > sizeof(mdbuf)) { g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "not enough space in metadata table, " "already used %i bytes", idx); return NULL; } /* write the key */ mdbuf[idx++] = key_len; memcpy(mdbuf + idx, key, key_len); idx += key_len; /* write the value */ mdbuf[idx++] = value_len; memcpy(mdbuf + idx, value, value_len); idx += value_len; } g_debug ("metadata table was %i/%i bytes", idx, (guint) sizeof(mdbuf)); return g_bytes_new (mdbuf, idx); } /** * dfu_firmware_add_footer: **/ static GBytes * dfu_firmware_add_footer (DfuFirmware *firmware, GBytes *contents, GError **error) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); DfuFirmwareFooter *ftr; const guint8 *data_bin; const guint8 *data_md; gsize length_bin = 0; gsize length_md = 0; guint8 *buf; g_autoptr(GBytes) metadata_table = NULL; /* get any file metadata */ metadata_table = dfu_firmware_build_metadata_table (firmware, error); if (metadata_table == NULL) return NULL; data_md = g_bytes_get_data (metadata_table, &length_md); /* add the raw firmware data */ data_bin = g_bytes_get_data (contents, &length_bin); buf = g_malloc0 (length_bin + length_md + 0x10); memcpy (buf + 0, data_bin, length_bin); /* add the metadata table */ memcpy (buf + length_bin, data_md, length_md); /* set up LE footer */ ftr = (DfuFirmwareFooter *) (buf + length_bin + length_md); ftr->release = GUINT16_TO_LE (priv->release); ftr->pid = GUINT16_TO_LE (priv->pid); ftr->vid = GUINT16_TO_LE (priv->vid); ftr->ver = GUINT16_TO_LE (priv->format); ftr->len = GUINT16_TO_LE (0x10 + length_md); memcpy(ftr->sig, "UFD", 3); ftr->crc = dfu_firmware_generate_crc32 (buf, length_bin + length_md + 12); /* return all data */ return g_bytes_new_take (buf, length_bin + length_md + 0x10); } /** * dfu_firmware_write_data: * @firmware: a #DfuFirmware * @error: a #GError, or %NULL * * Writes DFU data to a data blob with a DFU-specific footer. * * Return value: (transfer none): firmware data * * Since: 0.5.4 **/ GBytes * dfu_firmware_write_data (DfuFirmware *firmware, GError **error) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); DfuImage *image; g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* at least one image */ if (priv->images == 0) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "no image data to write"); return NULL; } /* DFU only supports one image */ if (priv->images->len > 1 && priv->format != DFU_FIRMWARE_FORMAT_DFUSE) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "only DfuSe format supports multiple images (%i)", priv->images->len); return NULL; } /* raw */ if (priv->format == DFU_FIRMWARE_FORMAT_RAW) { GBytes *contents; DfuElement *element; image = dfu_firmware_get_image_default (firmware); g_assert (image != NULL); element = dfu_image_get_element (image, 0); if (element == NULL) { g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_FOUND, "no firmware element data to write"); return NULL; } contents = dfu_element_get_contents (element); return g_bytes_ref (contents); } /* plain-old DFU */ if (priv->format == DFU_FIRMWARE_FORMAT_DFU_1_0) { GBytes *contents; DfuElement *element; image = dfu_firmware_get_image_default (firmware); g_assert (image != NULL); element = dfu_image_get_element (image, 0); if (element == NULL) { g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_FOUND, "no firmware element data to write"); return NULL; } contents = dfu_element_get_contents (element); g_assert (contents != NULL); return dfu_firmware_add_footer (firmware, contents, error); } /* DfuSe */ if (priv->format == DFU_FIRMWARE_FORMAT_DFUSE) { g_autoptr(GBytes) contents = NULL; contents = dfu_firmware_write_data_dfuse (firmware, error); if (contents == NULL) return NULL; return dfu_firmware_add_footer (firmware, contents, error); } /* Intel HEX */ if (priv->format == DFU_FIRMWARE_FORMAT_INTEL_HEX) return dfu_firmware_write_data_ihex (firmware, error); /* invalid */ g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "invalid format for write (0x%04x)", priv->format); return NULL; } /** * dfu_firmware_write_file: * @firmware: a #DfuFirmware * @file: a #GFile * @cancellable: a #GCancellable, or %NULL * @error: a #GError, or %NULL * * Writes a DFU firmware with the optional footer. * * Return value: %TRUE for success * * Since: 0.5.4 **/ gboolean dfu_firmware_write_file (DfuFirmware *firmware, GFile *file, GCancellable *cancellable, GError **error) { const guint8 *data; gsize length = 0; g_autoptr(GBytes) bytes = NULL; g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), FALSE); g_return_val_if_fail (G_IS_FILE (file), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* get blob */ bytes = dfu_firmware_write_data (firmware, error); if (bytes == NULL) return FALSE; /* save to firmware */ data = g_bytes_get_data (bytes, &length); return g_file_replace_contents (file, (const gchar *) data, length, NULL, FALSE, G_FILE_CREATE_NONE, NULL, cancellable, error); } /** * dfu_firmware_to_string: * @firmware: a #DfuFirmware * * Returns a string representaiton of the object. * * Return value: NULL terminated string, or %NULL for invalid * * Since: 0.5.4 **/ gchar * dfu_firmware_to_string (DfuFirmware *firmware) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); DfuImage *image; GList *l; GString *str; guint i; g_autoptr(GList) keys = NULL; g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), NULL); 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); g_string_append_printf (str, "release: 0x%04x\n", priv->release); g_string_append_printf (str, "crc: 0x%08x\n", priv->crc); g_string_append_printf (str, "format: %s [0x%04x]\n", dfu_firmware_format_to_string (priv->format), priv->format); g_string_append_printf (str, "cipher: %s\n", dfu_cipher_kind_to_string (priv->cipher_kind)); /* print metadata */ keys = g_hash_table_get_keys (priv->metadata); for (l = keys; l != NULL; l = l->next) { const gchar *key; const gchar *value; key = l->data; value = g_hash_table_lookup (priv->metadata, key); g_string_append_printf (str, "metadata: %s=%s\n", key, value); } /* print images */ for (i = 0; i < priv->images->len; i++) { g_autofree gchar *tmp = NULL; image = g_ptr_array_index (priv->images, i); tmp = dfu_image_to_string (image); g_string_append_printf (str, "= IMAGE %i =\n", i); g_string_append_printf (str, "%s\n", tmp); } g_string_truncate (str, str->len - 1); return g_string_free (str, FALSE); } /** * dfu_firmware_format_to_string: * @format: a #DfuFirmwareFormat, e.g. %DFU_FIRMWARE_FORMAT_DFU_1_0 * * Returns a string representaiton of the format. * * Return value: NULL terminated string, or %NULL for invalid * * Since: 0.5.4 **/ const gchar * dfu_firmware_format_to_string (DfuFirmwareFormat format) { if (format == DFU_FIRMWARE_FORMAT_RAW) return "RAW"; if (format == DFU_FIRMWARE_FORMAT_DFU_1_0) return "DFU"; if (format == DFU_FIRMWARE_FORMAT_DFUSE) return "DfuSe"; if (format == DFU_FIRMWARE_FORMAT_INTEL_HEX) return "IHEX"; return NULL; } /** * dfu_firmware_get_cipher_kind: * @firmware: a #DfuFirmware * * Returns the kind of cipher used by the firmware file. * * NOTE: this value is based on a heuristic, and may not be accurate. * The value %DFU_CIPHER_KIND_NONE will be returned when the cipher * is not recognised. * * Return value: NULL terminated string, or %NULL for invalid * * Since: 0.5.4 **/ DfuCipherKind dfu_firmware_get_cipher_kind (DfuFirmware *firmware) { DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), 0); return priv->cipher_kind; } fwupd-0.7.0/libdfu/dfu-firmware.h000066400000000000000000000116761267747510300167000ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __DFU_FIRMWARE_H #define __DFU_FIRMWARE_H #include #include #include "dfu-common.h" #include "dfu-image.h" G_BEGIN_DECLS #define DFU_TYPE_FIRMWARE (dfu_firmware_get_type ()) G_DECLARE_DERIVABLE_TYPE (DfuFirmware, dfu_firmware, DFU, FIRMWARE, GObject) struct _DfuFirmwareClass { GObjectClass parent_class; /*< private >*/ /* Padding for future expansion */ void (*_dfu_firmware_reserved1) (void); void (*_dfu_firmware_reserved2) (void); void (*_dfu_firmware_reserved3) (void); void (*_dfu_firmware_reserved4) (void); void (*_dfu_firmware_reserved5) (void); void (*_dfu_firmware_reserved6) (void); void (*_dfu_firmware_reserved7) (void); void (*_dfu_firmware_reserved8) (void); void (*_dfu_firmware_reserved9) (void); }; /** * DfuFirmwareParseFlags: * @DFU_FIRMWARE_PARSE_FLAG_NONE: No flags set * @DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST: Do not verify the CRC * @DFU_FIRMWARE_PARSE_FLAG_NO_VERSION_TEST: Do not verify the DFU version * @DFU_FIRMWARE_PARSE_FLAG_NO_METADATA: Do not read the metadata table * * The optional flags used for parsing. **/ typedef enum { DFU_FIRMWARE_PARSE_FLAG_NONE = 0, DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST = (1 << 0), DFU_FIRMWARE_PARSE_FLAG_NO_VERSION_TEST = (1 << 1), DFU_FIRMWARE_PARSE_FLAG_NO_METADATA = (1 << 2), /*< private >*/ DFU_FIRMWARE_PARSE_FLAG_LAST } DfuFirmwareParseFlags; /** * DfuFirmwareFormat: * @DFU_FIRMWARE_FORMAT_UNKNOWN: Format unknown * @DFU_FIRMWARE_FORMAT_RAW: Raw format * @DFU_FIRMWARE_FORMAT_DFU_1_0: DFU 1.0 * @DFU_FIRMWARE_FORMAT_DFUSE: DfuSe extension * @DFU_FIRMWARE_FORMAT_INTEL_HEX: Intel HEX * * The known versions of the DFU standard in BCD format. **/ typedef enum { DFU_FIRMWARE_FORMAT_UNKNOWN = 0, DFU_FIRMWARE_FORMAT_RAW = 0x0001, DFU_FIRMWARE_FORMAT_DFU_1_0 = 0x0100, DFU_FIRMWARE_FORMAT_DFUSE = 0x011a, DFU_FIRMWARE_FORMAT_INTEL_HEX = 0x0002, /*< private >*/ DFU_FIRMWARE_FORMAT_LAST } DfuFirmwareFormat; DfuFirmware *dfu_firmware_new (void); const gchar *dfu_firmware_format_to_string (DfuFirmwareFormat format); DfuImage *dfu_firmware_get_image (DfuFirmware *firmware, guint8 alt_setting); DfuImage *dfu_firmware_get_image_by_name (DfuFirmware *firmware, const gchar *name); DfuImage *dfu_firmware_get_image_default (DfuFirmware *firmware); GPtrArray *dfu_firmware_get_images (DfuFirmware *firmware); guint16 dfu_firmware_get_vid (DfuFirmware *firmware); guint16 dfu_firmware_get_pid (DfuFirmware *firmware); guint16 dfu_firmware_get_release (DfuFirmware *firmware); guint16 dfu_firmware_get_format (DfuFirmware *firmware); guint32 dfu_firmware_get_size (DfuFirmware *firmware); DfuCipherKind dfu_firmware_get_cipher_kind (DfuFirmware *firmware); void dfu_firmware_add_image (DfuFirmware *firmware, DfuImage *image); void dfu_firmware_set_vid (DfuFirmware *firmware, guint16 vid); void dfu_firmware_set_pid (DfuFirmware *firmware, guint16 pid); void dfu_firmware_set_release (DfuFirmware *firmware, guint16 release); void dfu_firmware_set_format (DfuFirmware *firmware, DfuFirmwareFormat format); gboolean dfu_firmware_parse_data (DfuFirmware *firmware, GBytes *bytes, DfuFirmwareParseFlags flags, GError **error); gboolean dfu_firmware_parse_file (DfuFirmware *firmware, GFile *file, DfuFirmwareParseFlags flags, GCancellable *cancellable, GError **error); GBytes *dfu_firmware_write_data (DfuFirmware *firmware, GError **error); gboolean dfu_firmware_write_file (DfuFirmware *firmware, GFile *file, GCancellable *cancellable, GError **error); gchar *dfu_firmware_to_string (DfuFirmware *firmware); const gchar *dfu_firmware_get_metadata (DfuFirmware *firmware, const gchar *key); void dfu_firmware_set_metadata (DfuFirmware *firmware, const gchar *key, const gchar *value); void dfu_firmware_remove_metadata (DfuFirmware *firmware, const gchar *key); G_END_DECLS #endif /* __DFU_FIRMWARE_H */ fwupd-0.7.0/libdfu/dfu-image-private.h000066400000000000000000000023771267747510300176140ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __DFU_IMAGE_PRIVATE_H #define __DFU_IMAGE_PRIVATE_H #include "dfu-image.h" G_BEGIN_DECLS DfuImage *dfu_image_from_dfuse (const guint8 *data, guint32 length, guint32 *consumed, GError **error); GBytes *dfu_image_to_dfuse (DfuImage *image); G_END_DECLS #endif /* __DFU_IMAGE_PRIVATE_H */ fwupd-0.7.0/libdfu/dfu-image.c000066400000000000000000000243571267747510300161410ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * SECTION:dfu-image * @short_description: Object representing a a firmware image * * A #DfuImage is typically made up of several #DfuElements, although * typically there will only be one. * * See also: #DfuElement */ #include "config.h" #include #include #include "dfu-common.h" #include "dfu-element-private.h" #include "dfu-error.h" #include "dfu-image-private.h" static void dfu_image_finalize (GObject *object); /** * DfuImagePrivate: * * Private #DfuImage data **/ typedef struct { GPtrArray *elements; gchar name[255]; guint8 alt_setting; } DfuImagePrivate; G_DEFINE_TYPE_WITH_PRIVATE (DfuImage, dfu_image, G_TYPE_OBJECT) #define GET_PRIVATE(o) (dfu_image_get_instance_private (o)) /** * dfu_image_class_init: **/ static void dfu_image_class_init (DfuImageClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = dfu_image_finalize; } /** * dfu_image_init: **/ static void dfu_image_init (DfuImage *image) { DfuImagePrivate *priv = GET_PRIVATE (image); priv->elements = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); memset (priv->name, 0x00, 255); } /** * dfu_image_finalize: **/ static void dfu_image_finalize (GObject *object) { DfuImage *image = DFU_IMAGE (object); DfuImagePrivate *priv = GET_PRIVATE (image); g_ptr_array_unref (priv->elements); G_OBJECT_CLASS (dfu_image_parent_class)->finalize (object); } /** * dfu_image_new: * * Creates a new DFU image object. * * Return value: a new #DfuImage * * Since: 0.5.4 **/ DfuImage * dfu_image_new (void) { DfuImage *image; image = g_object_new (DFU_TYPE_IMAGE, NULL); return image; } /** * dfu_image_get_elements: * @image: a #DfuImage * * Gets the element data. * * Return value: (transfer none) (element-type DfuElement): element data * * Since: 0.5.4 **/ GPtrArray * dfu_image_get_elements (DfuImage *image) { DfuImagePrivate *priv = GET_PRIVATE (image); g_return_val_if_fail (DFU_IS_IMAGE (image), NULL); return priv->elements; } /** * dfu_image_get_element: * @image: a #DfuImage * @idx: an array index * * Gets the element. * * Return value: (transfer none): element data, or %NULL for invalid * * Since: 0.5.4 **/ DfuElement * dfu_image_get_element (DfuImage *image, guint8 idx) { DfuImagePrivate *priv = GET_PRIVATE (image); g_return_val_if_fail (DFU_IS_IMAGE (image), NULL); if (idx >= priv->elements->len) return NULL; return g_ptr_array_index (priv->elements, idx); } /** * dfu_image_get_alt_setting: * @image: a #DfuImage * * Gets the alternate setting. * * Return value: integer, or 0x00 for unset * * Since: 0.5.4 **/ guint8 dfu_image_get_alt_setting (DfuImage *image) { DfuImagePrivate *priv = GET_PRIVATE (image); g_return_val_if_fail (DFU_IS_IMAGE (image), 0xff); return priv->alt_setting; } /** * dfu_image_get_name: * @image: a #DfuImage * * Gets the target name. * * Return value: a string, or %NULL for unset * * Since: 0.5.4 **/ const gchar * dfu_image_get_name (DfuImage *image) { DfuImagePrivate *priv = GET_PRIVATE (image); g_return_val_if_fail (DFU_IS_IMAGE (image), NULL); return priv->name; } /** * dfu_image_get_size: * @image: a #DfuImage * * Gets the size of all the elements in the image. * * This only returns actual data that would be sent to the device and * does not include any padding. * * Return value: a integer value, or 0 if there are no elements. * * Since: 0.5.4 **/ guint32 dfu_image_get_size (DfuImage *image) { DfuImagePrivate *priv = GET_PRIVATE (image); guint32 length = 0; guint i; g_return_val_if_fail (DFU_IS_IMAGE (image), 0); for (i = 0; i < priv->elements->len; i++) { DfuElement *element = g_ptr_array_index (priv->elements, i); length += g_bytes_get_size (dfu_element_get_contents (element)); } return length; } /** * dfu_image_add_element: * @image: a #DfuImage * @element: a #DfuElement * * Adds an element to the image. * * Since: 0.5.4 **/ void dfu_image_add_element (DfuImage *image, DfuElement *element) { DfuImagePrivate *priv = GET_PRIVATE (image); g_return_if_fail (DFU_IS_IMAGE (image)); g_return_if_fail (DFU_IS_ELEMENT (element)); g_ptr_array_add (priv->elements, g_object_ref (element)); } /** * dfu_image_set_alt_setting: * @image: a #DfuImage * @alt_setting: vendor ID, or 0xffff for unset * * Sets the vendor ID. * * Since: 0.5.4 **/ void dfu_image_set_alt_setting (DfuImage *image, guint8 alt_setting) { DfuImagePrivate *priv = GET_PRIVATE (image); g_return_if_fail (DFU_IS_IMAGE (image)); priv->alt_setting = alt_setting; } /** * dfu_image_set_name: * @image: a #DfuImage * @name: a target string, or %NULL * * Sets the target name. * * Since: 0.5.4 **/ void dfu_image_set_name (DfuImage *image, const gchar *name) { guint16 sz; DfuImagePrivate *priv = GET_PRIVATE (image); g_return_if_fail (DFU_IS_IMAGE (image)); /* this is a hard limit in DfuSe */ memset (priv->name, 0x00, 0xff); if (name != NULL) { sz = MIN (strlen (name), 0xff - 1); memcpy (priv->name, name, sz); } } /** * dfu_image_to_string: * @image: a #DfuImage * * Returns a string representaiton of the object. * * Return value: NULL terminated string, or %NULL for invalid * * Since: 0.5.4 **/ gchar * dfu_image_to_string (DfuImage *image) { DfuImagePrivate *priv = GET_PRIVATE (image); GString *str; guint i; g_return_val_if_fail (DFU_IS_IMAGE (image), NULL); str = g_string_new (""); g_string_append_printf (str, "alt_setting: 0x%02x\n", priv->alt_setting); if (priv->name[0] != '\0') g_string_append_printf (str, "name: %s\n", priv->name); g_string_append_printf (str, "elements: 0x%02x\n", priv->elements->len); /* add elements */ for (i = 0; i < priv->elements->len; i++) { DfuElement *element = g_ptr_array_index (priv->elements, i); g_autofree gchar *tmp = NULL; tmp = dfu_element_to_string (element); g_string_append_printf (str, "== ELEMENT %i ==\n", i); g_string_append_printf (str, "%s\n", tmp); } g_string_truncate (str, str->len - 1); return g_string_free (str, FALSE); } /* DfuSe image header */ typedef struct __attribute__((packed)) { guint8 sig[6]; guint8 alt_setting; guint32 target_named; gchar target_name[255]; guint32 target_size; guint32 elements; } DfuSeImagePrefix; /** * dfu_image_from_dfuse: (skip) * @data: data buffer * @length: length of @data we can access * @consumed: (out): the number of bytes we consued * @error: a #GError, or %NULL * * Unpacks an image from DfuSe data. * * Returns: a #DfuImage, or %NULL for error **/ DfuImage * dfu_image_from_dfuse (const guint8 *data, guint32 length, guint32 *consumed, GError **error) { DfuImagePrivate *priv; DfuSeImagePrefix *im; guint32 offset = sizeof(DfuSeImagePrefix); guint j; g_autoptr(DfuImage) image = NULL; g_assert_cmpint(sizeof(DfuSeImagePrefix), ==, 274); /* check input buffer size */ if (length < sizeof(DfuSeImagePrefix)) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "invalid image data size %u", (guint32) length); return NULL; } /* verify image signature */ im = (DfuSeImagePrefix *) data; if (memcmp (im->sig, "Target", 6) != 0) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INVALID_FILE, "invalid DfuSe target signature"); return NULL; } /* create new image */ image = dfu_image_new (); priv = GET_PRIVATE (image); priv->alt_setting = im->alt_setting; if (im->target_named == 0x01) memcpy (priv->name, im->target_name, 255); /* parse elements */ length -= offset; for (j = 0; j < im->elements; j++) { guint32 consumed_local; g_autoptr(DfuElement) element = NULL; element = dfu_element_from_dfuse (data + offset, length, &consumed_local, error); if (element == NULL) return NULL; dfu_image_add_element (image, element); offset += consumed_local; length -= consumed_local; } /* return size */ if (consumed != NULL) *consumed = offset; return g_object_ref (image); } /** * dfu_image_to_dfuse: (skip) * @image: a #DfuImage * * Packs a DfuSe image * * Returns: (transfer full): the packed data **/ GBytes * dfu_image_to_dfuse (DfuImage *image) { DfuImagePrivate *priv = GET_PRIVATE (image); DfuElement *element; DfuSeImagePrefix *im; GBytes *bytes; guint32 length_total = 0; guint32 offset = sizeof (DfuSeImagePrefix); guint8 *buf; guint i; g_autoptr(GPtrArray) element_array = NULL; /* get total size */ element_array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref); for (i = 0; i < priv->elements->len; i++) { element = g_ptr_array_index (priv->elements, i); bytes = dfu_element_to_dfuse (element); g_ptr_array_add (element_array, bytes); length_total += g_bytes_get_size (bytes); } /* add prefix */ buf = g_malloc0 (length_total + sizeof (DfuSeImagePrefix)); im = (DfuSeImagePrefix *) buf; memcpy (im->sig, "Target", 6); im->alt_setting = priv->alt_setting; if (priv->name != NULL) { im->target_named = 0x01; memcpy (im->target_name, priv->name, 255); } im->target_size = length_total; im->elements = priv->elements->len; /* copy data */ for (i = 0; i < element_array->len; i++) { const guint8 *data; gsize length; bytes = g_ptr_array_index (element_array, i); data = g_bytes_get_data (bytes, &length); memcpy (buf + offset, data, length); offset += length; } return g_bytes_new_take (buf, length_total + sizeof (DfuSeImagePrefix)); } fwupd-0.7.0/libdfu/dfu-image.h000066400000000000000000000043701267747510300161370ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __DFU_IMAGE_H #define __DFU_IMAGE_H #include #include #include "dfu-element.h" G_BEGIN_DECLS #define DFU_TYPE_IMAGE (dfu_image_get_type ()) G_DECLARE_DERIVABLE_TYPE (DfuImage, dfu_image, DFU, IMAGE, GObject) struct _DfuImageClass { GObjectClass parent_class; /*< private >*/ /* Padding for future expansion */ void (*_dfu_image_reserved1) (void); void (*_dfu_image_reserved2) (void); void (*_dfu_image_reserved3) (void); void (*_dfu_image_reserved4) (void); void (*_dfu_image_reserved5) (void); void (*_dfu_image_reserved6) (void); void (*_dfu_image_reserved7) (void); void (*_dfu_image_reserved8) (void); void (*_dfu_image_reserved9) (void); }; DfuImage *dfu_image_new (void); GPtrArray *dfu_image_get_elements (DfuImage *image); DfuElement *dfu_image_get_element (DfuImage *image, guint8 idx); guint8 dfu_image_get_alt_setting (DfuImage *image); const gchar *dfu_image_get_name (DfuImage *image); guint32 dfu_image_get_size (DfuImage *image); void dfu_image_add_element (DfuImage *image, DfuElement *element); void dfu_image_set_alt_setting (DfuImage *image, guint8 alt_setting); void dfu_image_set_name (DfuImage *image, const gchar *name); gchar *dfu_image_to_string (DfuImage *image); G_END_DECLS #endif /* __DFU_IMAGE_H */ fwupd-0.7.0/libdfu/dfu-sector-private.h000066400000000000000000000023661267747510300200270ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __DFU_SECTOR_PRIVATE_H #define __DFU_SECTOR_PRIVATE_H #include "dfu-sector.h" G_BEGIN_DECLS DfuSector *dfu_sector_new (guint32 address, guint32 size, guint32 size_left, guint16 zone, guint16 number, DfuSectorCap cap); G_END_DECLS #endif /* __DFU_SECTOR_PRIVATE_H */ fwupd-0.7.0/libdfu/dfu-sector.c000066400000000000000000000124461267747510300163520ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * SECTION:dfu-sector * @short_description: Object representing a sector on a chip * * This object represents an sector of memory at a specific address on the * device itself. * * This allows relocatable data segments to be stored in different * locations on the device itself. * * You can think of these objects as flash segments on devices, where a * complete block can be erased and then written to. * * See also: #DfuElement */ #include "config.h" #include #include #include "dfu-common.h" #include "dfu-sector-private.h" /** * DfuSectorPrivate: * * Private #DfuSector data **/ typedef struct { guint32 address; guint32 size; guint32 size_left; guint16 zone; guint16 number; DfuSectorCap cap; } DfuSectorPrivate; G_DEFINE_TYPE_WITH_PRIVATE (DfuSector, dfu_sector, G_TYPE_OBJECT) #define GET_PRIVATE(o) (dfu_sector_get_instance_private (o)) /** * dfu_sector_class_init: **/ static void dfu_sector_class_init (DfuSectorClass *klass) { } /** * dfu_sector_init: **/ static void dfu_sector_init (DfuSector *sector) { } /** * dfu_sector_new: (skip) * address: the address for the sector * size: the size of this sector * size_left: the size of the rest of the sector * zone: the zone of memory the setor belongs * number: the sector number in the zone * cap: the #DfuSectorCap * * Creates a new DFU sector object. * * Return value: a new #DfuSector * * Since: 0.5.4 **/ DfuSector * dfu_sector_new (guint32 address, guint32 size, guint32 size_left, guint16 zone, guint16 number, DfuSectorCap cap) { DfuSectorPrivate *priv; DfuSector *sector; sector = g_object_new (DFU_TYPE_SECTOR, NULL); priv = GET_PRIVATE (sector); priv->address = address; priv->size = size; priv->size_left = size_left; priv->zone = zone; priv->number = number; priv->cap = cap; return sector; } /** * dfu_sector_get_address: * @sector: a #DfuSector * * Gets the alternate setting. * * Return value: integer, or 0x00 for unset * * Since: 0.5.4 **/ guint32 dfu_sector_get_address (DfuSector *sector) { DfuSectorPrivate *priv = GET_PRIVATE (sector); g_return_val_if_fail (DFU_IS_SECTOR (sector), 0x00); return priv->address; } /** * dfu_sector_get_size: * @sector: a #DfuSector * * Gets the alternate setting. * * Return value: integer, or 0x00 for unset * * Since: 0.5.4 **/ guint32 dfu_sector_get_size (DfuSector *sector) { DfuSectorPrivate *priv = GET_PRIVATE (sector); g_return_val_if_fail (DFU_IS_SECTOR (sector), 0x00); return priv->size; } /** * dfu_sector_get_size_left: * @sector: a #DfuSector * * Gets the alternate setting. * * Return value: integer, or 0x00 for unset * * Since: 0.5.4 **/ guint32 dfu_sector_get_size_left (DfuSector *sector) { DfuSectorPrivate *priv = GET_PRIVATE (sector); g_return_val_if_fail (DFU_IS_SECTOR (sector), 0x00); return priv->size_left; } /** * dfu_sector_get_id: * @sector: a #DfuSector * * Gets the sector ID which is a combination of the zone and sector number. * You can use this number to check if the segment is the 'same' as the last * written or read sector. * * Return value: integer ID, or 0x00 for unset * * Since: 0.5.4 **/ guint32 dfu_sector_get_id (DfuSector *sector) { DfuSectorPrivate *priv = GET_PRIVATE (sector); g_return_val_if_fail (DFU_IS_SECTOR (sector), 0x00); return (((guint32) priv->zone) << 16) | priv->number; } /** * dfu_sector_has_cap: * @sector: a #DfuSector * @cap: a #DfuSectorCap, e.g. %DFU_SECTOR_CAP_ERASEABLE * * Finds out if the sector has the required capability. * * Return value: %TRUE if the sector has the capabilily * * Since: 0.5.4 **/ gboolean dfu_sector_has_cap (DfuSector *sector, DfuSectorCap cap) { DfuSectorPrivate *priv = GET_PRIVATE (sector); g_return_val_if_fail (DFU_IS_SECTOR (sector), FALSE); return priv->cap & cap; } /** * dfu_sector_to_string: * @sector: a #DfuSector * * Returns a string representaiton of the object. * * Return value: NULL terminated string, or %NULL for invalid * * Since: 0.5.4 **/ gchar * dfu_sector_to_string (DfuSector *sector) { DfuSectorPrivate *priv = GET_PRIVATE (sector); GString *str; g_return_val_if_fail (DFU_IS_SECTOR (sector), NULL); str = g_string_new (""); g_string_append_printf (str, "Zone:%i, Sec#:%i, Addr:0x%08x, " "Size:0x%04x, Caps:0x%01x", priv->zone, priv->number, priv->address, priv->size, priv->cap); return g_string_free (str, FALSE); } fwupd-0.7.0/libdfu/dfu-sector.h000066400000000000000000000047231267747510300163560ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __DFU_SECTOR_H #define __DFU_SECTOR_H #include #include G_BEGIN_DECLS #define DFU_TYPE_SECTOR (dfu_sector_get_type ()) G_DECLARE_DERIVABLE_TYPE (DfuSector, dfu_sector, DFU, SECTOR, GObject) struct _DfuSectorClass { GObjectClass parent_class; /*< private >*/ /* Padding for future expansion */ void (*_dfu_sector_reserved1) (void); void (*_dfu_sector_reserved2) (void); void (*_dfu_sector_reserved3) (void); void (*_dfu_sector_reserved4) (void); void (*_dfu_sector_reserved5) (void); void (*_dfu_sector_reserved6) (void); void (*_dfu_sector_reserved7) (void); void (*_dfu_sector_reserved8) (void); void (*_dfu_sector_reserved9) (void); }; /** * DfuSectorCap: * @DFU_SECTOR_CAP_NONE: No operations possible * @DFU_SECTOR_CAP_READABLE: Sector can be read * @DFU_SECTOR_CAP_WRITEABLE: Sector can be written * @DFU_SECTOR_CAP_ERASEABLE: Sector can be erased * * The flags indicating what the sector can do. **/ typedef enum { DFU_SECTOR_CAP_NONE = 0, DFU_SECTOR_CAP_READABLE = 1 << 0, DFU_SECTOR_CAP_WRITEABLE = 1 << 1, DFU_SECTOR_CAP_ERASEABLE = 1 << 2, /*< private >*/ DFU_SECTOR_CAP_LAST } DfuSectorCap; guint32 dfu_sector_get_id (DfuSector *sector); guint32 dfu_sector_get_address (DfuSector *sector); guint32 dfu_sector_get_size (DfuSector *sector); guint32 dfu_sector_get_size_left (DfuSector *sector); gboolean dfu_sector_has_cap (DfuSector *sector, DfuSectorCap cap); gchar *dfu_sector_to_string (DfuSector *sector); G_END_DECLS #endif /* __DFU_SECTOR_H */ fwupd-0.7.0/libdfu/dfu-self-test.c000066400000000000000000000546111267747510300167610ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include "dfu-common.h" #include "dfu-context.h" #include "dfu-device.h" #include "dfu-error.h" #include "dfu-firmware.h" #include "dfu-sector-private.h" #include "dfu-target-private.h" /** * dfu_test_get_filename: **/ static gchar * dfu_test_get_filename (const gchar *filename) { gchar *tmp; char full_tmp[PATH_MAX]; g_autofree gchar *path = NULL; path = g_build_filename (TESTDATADIR, filename, NULL); tmp = realpath (path, full_tmp); if (tmp == NULL) return NULL; return g_strdup (full_tmp); } /** * _g_bytes_compare_verbose: **/ static gchar * _g_bytes_compare_verbose (GBytes *bytes1, GBytes *bytes2) { const guint8 *data1; const guint8 *data2; gsize length1; gsize length2; guint i; data1 = g_bytes_get_data (bytes1, &length1); data2 = g_bytes_get_data (bytes2, &length2); /* not the same length */ if (length1 != length2) { return g_strdup_printf ("got %" G_GSIZE_FORMAT " bytes, " "expected %" G_GSIZE_FORMAT, length1, length2); } /* return 00 01 02 03 */ for (i = 0; i < length1; i++) { if (data1[i] != data2[i]) { return g_strdup_printf ("got 0x%02x, expected 0x%02x @ 0x%04x", data1[i], data2[i], i); } } return NULL; } static void dfu_firmware_xdfu_func (void) { gboolean ret; g_autofree gchar *fn = NULL; g_autoptr(DfuFirmware) firmware = NULL; g_autoptr(GError) error = NULL; g_autoptr(GFile) file = NULL; fn = dfu_test_get_filename ("example.xdfu"); g_assert (fn != NULL); firmware = dfu_firmware_new (); file = g_file_new_for_path (fn); ret = dfu_firmware_parse_file (firmware, file, DFU_FIRMWARE_PARSE_FLAG_NONE, NULL, &error); g_assert_no_error (error); g_assert (ret); g_assert_cmpint (dfu_firmware_get_cipher_kind (firmware), ==, DFU_CIPHER_KIND_XTEA); } static void dfu_enums_func (void) { guint i; for (i = 0; i < DFU_STATE_LAST; i++) g_assert_cmpstr (dfu_state_to_string (i), !=, NULL); for (i = 0; i < DFU_STATUS_LAST; i++) g_assert_cmpstr (dfu_status_to_string (i), !=, NULL); } static GBytes * dfu_self_test_get_bytes_for_file (GFile *file, GError **error) { gchar *contents = NULL; gsize length = 0; if (!g_file_load_contents (file, NULL, &contents, &length, NULL, error)) return NULL; return g_bytes_new_take (contents, length); } static void dfu_firmware_raw_func (void) { DfuElement *element; DfuImage *image_tmp; GBytes *no_suffix_contents; gchar buf[256]; guint i; gboolean ret; g_autoptr(DfuFirmware) firmware = NULL; g_autoptr(GBytes) fw = NULL; g_autoptr(GBytes) roundtrip_orig = NULL; g_autoptr(GBytes) roundtrip = NULL; g_autoptr(GError) error = NULL; /* set up some dummy data */ for (i = 0; i < 256; i++) buf[i] = i; fw = g_bytes_new_static (buf, 256); /* load a non DFU firmware */ firmware = dfu_firmware_new (); ret = dfu_firmware_parse_data (firmware, fw, DFU_FIRMWARE_PARSE_FLAG_NONE, &error); g_assert_no_error (error); g_assert (ret); g_assert_cmpint (dfu_firmware_get_vid (firmware), ==, 0xffff); g_assert_cmpint (dfu_firmware_get_pid (firmware), ==, 0xffff); g_assert_cmpint (dfu_firmware_get_release (firmware), ==, 0xffff); g_assert_cmpint (dfu_firmware_get_format (firmware), ==, DFU_FIRMWARE_FORMAT_RAW); g_assert_cmpint (dfu_firmware_get_cipher_kind (firmware), ==, DFU_CIPHER_KIND_NONE); image_tmp = dfu_firmware_get_image (firmware, 0xfe); g_assert (image_tmp == NULL); image_tmp = dfu_firmware_get_image (firmware, 0); g_assert (image_tmp != NULL); g_assert_cmpint (dfu_image_get_size (image_tmp), ==, 256); element = dfu_image_get_element (image_tmp, 0); g_assert (element != NULL); no_suffix_contents = dfu_element_get_contents (element); g_assert (no_suffix_contents != NULL); g_assert_cmpint (g_bytes_compare (no_suffix_contents, fw), ==, 0); /* can we roundtrip without adding data */ roundtrip = dfu_firmware_write_data (firmware, &error); g_assert_no_error (error); g_assert (roundtrip != NULL); g_assert_cmpstr (_g_bytes_compare_verbose (roundtrip, fw), ==, NULL); } static void dfu_firmware_dfu_func (void) { gchar buf[256]; guint i; gboolean ret; g_autofree gchar *filename = NULL; g_autoptr(DfuFirmware) firmware = NULL; g_autoptr(DfuImage) image = NULL; g_autoptr(DfuElement) element = NULL; g_autoptr(GBytes) data = NULL; g_autoptr(GBytes) fw = NULL; g_autoptr(GBytes) roundtrip_orig = NULL; g_autoptr(GBytes) roundtrip = NULL; g_autoptr(GError) error = NULL; g_autoptr(GFile) file = NULL; /* set up some dummy data */ for (i = 0; i < 256; i++) buf[i] = i; fw = g_bytes_new_static (buf, 256); /* write DFU format */ firmware = dfu_firmware_new (); dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_DFU_1_0); dfu_firmware_set_vid (firmware, 0x1234); dfu_firmware_set_pid (firmware, 0x5678); dfu_firmware_set_release (firmware, 0xfedc); image = dfu_image_new (); element = dfu_element_new (); dfu_element_set_contents (element, fw); dfu_image_add_element (image, element); dfu_firmware_add_image (firmware, image); g_assert_cmpint (dfu_firmware_get_size (firmware), ==, 256); data = dfu_firmware_write_data (firmware, &error); g_assert_no_error (error); g_assert (data != NULL); /* can we load it again? */ g_ptr_array_set_size (dfu_firmware_get_images (firmware), 0); ret = dfu_firmware_parse_data (firmware, data, DFU_FIRMWARE_PARSE_FLAG_NONE, &error); g_assert_no_error (error); g_assert (ret); g_assert_cmpint (dfu_firmware_get_vid (firmware), ==, 0x1234); g_assert_cmpint (dfu_firmware_get_pid (firmware), ==, 0x5678); g_assert_cmpint (dfu_firmware_get_release (firmware), ==, 0xfedc); g_assert_cmpint (dfu_firmware_get_format (firmware), ==, DFU_FIRMWARE_FORMAT_DFU_1_0); g_assert_cmpint (dfu_firmware_get_size (firmware), ==, 256); /* load a real firmware */ filename = dfu_test_get_filename ("kiibohd.dfu.bin"); g_assert (filename != NULL); file = g_file_new_for_path (filename); g_ptr_array_set_size (dfu_firmware_get_images (firmware), 0); ret = dfu_firmware_parse_file (firmware, file, DFU_FIRMWARE_PARSE_FLAG_NONE, NULL, &error); g_assert_no_error (error); g_assert (ret); g_assert_cmpint (dfu_firmware_get_vid (firmware), ==, 0x1c11); g_assert_cmpint (dfu_firmware_get_pid (firmware), ==, 0xb007); g_assert_cmpint (dfu_firmware_get_release (firmware), ==, 0xffff); g_assert_cmpint (dfu_firmware_get_format (firmware), ==, DFU_FIRMWARE_FORMAT_DFU_1_0); g_assert_cmpint (dfu_firmware_get_size (firmware), ==, 0x8eB4); g_assert_cmpint (dfu_firmware_get_cipher_kind (firmware), ==, DFU_CIPHER_KIND_NONE); /* can we roundtrip without loosing data */ roundtrip_orig = dfu_self_test_get_bytes_for_file (file, &error); g_assert_no_error (error); g_assert (roundtrip_orig != NULL); roundtrip = dfu_firmware_write_data (firmware, &error); g_assert_no_error (error); g_assert (roundtrip != NULL); g_assert_cmpstr (_g_bytes_compare_verbose (roundtrip, roundtrip_orig), ==, NULL); } static void dfu_firmware_dfuse_func (void) { gboolean ret; g_autofree gchar *filename = NULL; g_autoptr(DfuFirmware) firmware = NULL; g_autoptr(GBytes) roundtrip_orig = NULL; g_autoptr(GBytes) roundtrip = NULL; g_autoptr(GError) error = NULL; g_autoptr(GFile) file = NULL; /* load a DeFUse firmware */ filename = dfu_test_get_filename ("dev_VRBRAIN.dfu"); g_assert (filename != NULL); file = g_file_new_for_path (filename); firmware = dfu_firmware_new (); ret = dfu_firmware_parse_file (firmware, file, DFU_FIRMWARE_PARSE_FLAG_NONE, NULL, &error); g_assert_no_error (error); g_assert (ret); g_assert_cmpint (dfu_firmware_get_vid (firmware), ==, 0x0483); g_assert_cmpint (dfu_firmware_get_pid (firmware), ==, 0x0000); g_assert_cmpint (dfu_firmware_get_release (firmware), ==, 0x0000); g_assert_cmpint (dfu_firmware_get_format (firmware), ==, DFU_FIRMWARE_FORMAT_DFUSE); g_assert_cmpint (dfu_firmware_get_size (firmware), ==, 0x168d5); g_assert_cmpint (dfu_firmware_get_cipher_kind (firmware), ==, DFU_CIPHER_KIND_NONE); /* can we roundtrip without loosing data */ roundtrip_orig = dfu_self_test_get_bytes_for_file (file, &error); g_assert_no_error (error); g_assert (roundtrip_orig != NULL); roundtrip = dfu_firmware_write_data (firmware, &error); g_assert_no_error (error); g_assert (roundtrip != NULL); // g_file_set_contents ("/tmp/1.bin", // g_bytes_get_data (roundtrip, NULL), // g_bytes_get_size (roundtrip), NULL); g_assert_cmpstr (_g_bytes_compare_verbose (roundtrip, roundtrip_orig), ==, NULL); } static void dfu_firmware_metadata_func (void) { gboolean ret; g_autofree gchar *filename = NULL; g_autoptr(DfuFirmware) firmware = NULL; g_autoptr(GBytes) roundtrip_orig = NULL; g_autoptr(GBytes) roundtrip = NULL; g_autoptr(GError) error = NULL; g_autoptr(GFile) file = NULL; /* load a DFU firmware with a metadata table */ filename = dfu_test_get_filename ("metadata.dfu"); g_assert (filename != NULL); file = g_file_new_for_path (filename); firmware = dfu_firmware_new (); ret = dfu_firmware_parse_file (firmware, file, DFU_FIRMWARE_PARSE_FLAG_NONE, NULL, &error); g_assert_no_error (error); g_assert (ret); g_assert_cmpint (dfu_firmware_get_size (firmware), ==, 6); g_assert_cmpstr (dfu_firmware_get_metadata (firmware, "key"), ==, "value"); g_assert_cmpstr (dfu_firmware_get_metadata (firmware, "???"), ==, NULL); /* can we roundtrip without loosing data */ roundtrip_orig = dfu_self_test_get_bytes_for_file (file, &error); g_assert_no_error (error); g_assert (roundtrip_orig != NULL); roundtrip = dfu_firmware_write_data (firmware, &error); g_assert_no_error (error); g_assert (roundtrip != NULL); g_assert_cmpstr (_g_bytes_compare_verbose (roundtrip, roundtrip_orig), ==, NULL); } static void dfu_firmware_intel_hex_func (void) { const guint8 *data; gboolean ret; gsize len; g_autofree gchar *filename_hex = NULL; g_autofree gchar *filename_ref = NULL; g_autofree gchar *str = NULL; g_autoptr(DfuFirmware) firmware = NULL; g_autoptr(GBytes) data_bin2 = NULL; g_autoptr(GBytes) data_bin = NULL; g_autoptr(GBytes) data_hex = NULL; g_autoptr(GBytes) data_ref = NULL; g_autoptr(GError) error = NULL; g_autoptr(GFile) file_bin = NULL; g_autoptr(GFile) file_hex = NULL; /* load a Intel hex32 file */ filename_hex = dfu_test_get_filename ("firmware.hex"); g_assert (filename_hex != NULL); file_hex = g_file_new_for_path (filename_hex); firmware = dfu_firmware_new (); ret = dfu_firmware_parse_file (firmware, file_hex, DFU_FIRMWARE_PARSE_FLAG_NONE, NULL, &error); g_assert_no_error (error); g_assert (ret); g_assert_cmpint (dfu_firmware_get_size (firmware), ==, 136); dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_RAW); data_bin = dfu_firmware_write_data (firmware, &error); g_assert_no_error (error); g_assert (data_bin != NULL); /* did we match the reference file? */ filename_ref = dfu_test_get_filename ("firmware.bin"); g_assert (filename_ref != NULL); file_bin = g_file_new_for_path (filename_ref); data_ref = dfu_self_test_get_bytes_for_file (file_bin, &error); g_assert_no_error (error); g_assert (data_ref != NULL); g_assert_cmpstr (_g_bytes_compare_verbose (data_bin, data_ref), ==, NULL); /* export a ihex file (which will be slightly different due to * non-continous regions being expanded */ dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_INTEL_HEX); data_hex = dfu_firmware_write_data (firmware, &error); g_assert_no_error (error); g_assert (data_hex != NULL); data = g_bytes_get_data (data_hex, &len); str = g_strndup ((const gchar *) data, len); g_assert_cmpstr (str, ==, ":104000003DEF20F000000000FACF01F0FBCF02F0AF\n" ":10401000E9CF03F0EACF04F0E1CF05F0E2CF06F005\n" ":10402000D9CF07F0DACF08F0F3CF09F0F4CF0AF021\n" ":10403000F6CF0BF0F7CF0CF0F8CF0DF0F5CF0EF044\n" ":104040000EC0F5FF0DC0F8FF0CC0F7FF0BC0F6FF45\n" ":104050000AC0F4FF09C0F3FF08C0DAFF07C0D9FF24\n" ":1040600006C0E2FF05C0E1FF04C0EAFF03C0E9FF0A\n" ":1040700002C0FBFF01C0FAFF11003FEF20F00001BB\n" ":0840800042EF20F03DEF20F037\n" ":00000001FF\n"); /* do we match the binary file again */ dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_RAW); data_bin2 = dfu_firmware_write_data (firmware, &error); g_assert_no_error (error); g_assert (data_bin2 != NULL); g_assert_cmpstr (_g_bytes_compare_verbose (data_bin, data_bin2), ==, NULL); } static void dfu_device_func (void) { GPtrArray *targets; gboolean ret; g_autoptr(DfuDevice) device = NULL; g_autoptr(DfuTarget) target1 = NULL; g_autoptr(DfuTarget) target2 = NULL; g_autoptr(GError) error = NULL; g_autoptr(GUsbContext) usb_ctx = NULL; g_autoptr(GUsbDevice) usb_device = NULL; /* find any DFU in appIDLE mode */ usb_ctx = g_usb_context_new (&error); g_assert_no_error (error); g_assert (usb_ctx != NULL); g_usb_context_enumerate (usb_ctx); usb_device = g_usb_context_find_by_vid_pid (usb_ctx, 0x273f, 0x1005, &error); if (usb_device == NULL) return; g_assert_no_error (error); g_assert (usb_device != NULL); /* check it's DFU-capable */ device = dfu_device_new (usb_device); g_assert (device != NULL); /* get targets */ targets = dfu_device_get_targets (device); g_assert_cmpint (targets->len, ==, 2); /* get by ID */ target1 = dfu_device_get_target_by_alt_setting (device, 1, &error); g_assert_no_error (error); g_assert (target1 != NULL); /* ensure open */ ret = dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE, NULL, &error); g_assert_no_error (error); g_assert (ret); /* get by name */ target2 = dfu_device_get_target_by_alt_name (device, "sram", &error); g_assert_no_error (error); g_assert (target2 != NULL); /* close */ ret = dfu_device_close (device, &error); g_assert_no_error (error); g_assert (ret); } static void dfu_colorhug_plus_func (void) { GPtrArray *elements; gboolean ret; gboolean seen_app_idle = FALSE; g_autoptr(DfuContext) context = NULL; g_autoptr(DfuDevice) device = NULL; g_autoptr(DfuDevice) device2 = NULL; g_autoptr(DfuTarget) target = NULL; g_autoptr(DfuImage) image = NULL; g_autoptr(GError) error = NULL; /* create context */ context = dfu_context_new (); ret = dfu_context_enumerate (context, &error); g_assert_no_error (error); g_assert (ret); /* push appIDLE into dfuIDLE */ device2 = dfu_context_get_device_by_vid_pid (context, 0x273f, 0x1002, NULL); if (device2 != NULL) { ret = dfu_device_open (device2, DFU_DEVICE_OPEN_FLAG_NONE, NULL, &error); g_assert_no_error (error); g_assert (ret); ret = dfu_device_detach (device2, NULL, &error); g_assert_no_error (error); g_assert (ret); /* wait for it to come back as 273f:1005 */ ret = dfu_device_wait_for_replug (device2, 5000, NULL, &error); g_assert_no_error (error); g_assert (ret); /* close it */ ret = dfu_device_close (device2, &error); g_assert_no_error (error); g_assert (ret); } /* find any DFU in dfuIDLE mode */ device = dfu_context_get_device_by_vid_pid (context, 0x273f, 0x1003, NULL); if (device == NULL) return; /* we don't know this unless we went from appIDLE -> dfuIDLE */ if (device2 == NULL) { g_assert_cmpint (dfu_device_get_runtime_vid (device), ==, 0xffff); g_assert_cmpint (dfu_device_get_runtime_pid (device), ==, 0xffff); } /* open it */ ret = dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE, NULL, &error); g_assert_no_error (error); g_assert (ret); /* is in dfuIDLE mode */ g_assert_cmpstr (dfu_state_to_string (dfu_device_get_state (device)), ==, "dfuIDLE"); /* lets try and flash something inappropriate */ if (seen_app_idle) { g_autoptr(DfuFirmware) firmware = NULL; g_autoptr(GFile) file = NULL; g_autofree gchar *filename = NULL; filename = dfu_test_get_filename ("kiibohd.dfu.bin"); g_assert (filename != NULL); file = g_file_new_for_path (filename); firmware = dfu_firmware_new (); ret = dfu_firmware_parse_file (firmware, file, DFU_FIRMWARE_PARSE_FLAG_NONE, NULL, &error); g_assert_no_error (error); g_assert (ret); ret = dfu_device_download (device, firmware, DFU_TARGET_TRANSFER_FLAG_DETACH | DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME, NULL, &error); g_assert_error (error, DFU_ERROR, DFU_ERROR_INTERNAL); g_assert (ret); g_clear_error (&error); } /* get a dump of the existing firmware */ target = dfu_device_get_target_by_alt_setting (device, 0, &error); g_assert_no_error (error); g_assert (target != NULL); image = dfu_target_upload (target, DFU_TARGET_TRANSFER_FLAG_NONE, NULL, &error); g_assert_no_error (error); g_assert (DFU_IS_IMAGE (image)); elements = dfu_image_get_elements (image); g_assert (elements != NULL); g_assert_cmpint (elements->len, ==, 1); /* download a new firmware */ ret = dfu_target_download (target, image, DFU_TARGET_TRANSFER_FLAG_VERIFY | DFU_TARGET_TRANSFER_FLAG_ATTACH, NULL, &error); g_assert_no_error (error); g_assert (ret); /* wait for it to come back as 273f:1004 */ ret = dfu_device_wait_for_replug (device, 5000, NULL, &error); g_assert_no_error (error); g_assert (ret); /* we should know now */ g_assert_cmpint (dfu_device_get_runtime_vid (device), ==, 0x273f); g_assert_cmpint (dfu_device_get_runtime_pid (device), ==, 0x1002); } /** * dfu_target_sectors_to_string: **/ static gchar * dfu_target_sectors_to_string (DfuTarget *target) { DfuSector *sector; GPtrArray *sectors; GString *str; guint i; str = g_string_new (""); sectors = dfu_target_get_sectors (target); for (i = 0; i < sectors->len; i++) { g_autofree gchar *tmp = NULL; sector = g_ptr_array_index (sectors, i); tmp = dfu_sector_to_string (sector); g_string_append_printf (str, "%s\n", tmp); } if (str->len > 0) g_string_truncate (str, str->len - 1); return g_string_free (str, FALSE); } static void dfu_target_dfuse_func (void) { gboolean ret; gchar *tmp; g_autoptr(DfuTarget) target = NULL; g_autoptr(GError) error = NULL; /* NULL */ target = g_object_new (DFU_TYPE_TARGET, NULL); ret = dfu_target_parse_sectors (target, NULL, &error); g_assert_no_error (error); g_assert (ret); tmp = dfu_target_sectors_to_string (target); g_assert_cmpstr (tmp, ==, ""); g_free (tmp); /* no addresses */ ret = dfu_target_parse_sectors (target, "@Flash3", &error); g_assert_no_error (error); g_assert (ret); tmp = dfu_target_sectors_to_string (target); g_assert_cmpstr (tmp, ==, ""); g_free (tmp); /* one sector, no space */ ret = dfu_target_parse_sectors (target, "@Internal Flash /0x08000000/2*001Ka", &error); g_assert_no_error (error); g_assert (ret); tmp = dfu_target_sectors_to_string (target); g_assert_cmpstr (tmp, ==, "Zone:0, Sec#:0, Addr:0x08000000, Size:0x0400, Caps:0x1\n" "Zone:0, Sec#:0, Addr:0x08000400, Size:0x0400, Caps:0x1"); g_free (tmp); /* multiple sectors */ ret = dfu_target_parse_sectors (target, "@Flash1 /0x08000000/2*001 Ka,4*001 Kg", &error); g_assert_no_error (error); g_assert (ret); tmp = dfu_target_sectors_to_string (target); g_assert_cmpstr (tmp, ==, "Zone:0, Sec#:0, Addr:0x08000000, Size:0x0400, Caps:0x1\n" "Zone:0, Sec#:0, Addr:0x08000400, Size:0x0400, Caps:0x1\n" "Zone:0, Sec#:1, Addr:0x08000000, Size:0x0400, Caps:0x7\n" "Zone:0, Sec#:1, Addr:0x08000400, Size:0x0400, Caps:0x7\n" "Zone:0, Sec#:1, Addr:0x08000800, Size:0x0400, Caps:0x7\n" "Zone:0, Sec#:1, Addr:0x08000c00, Size:0x0400, Caps:0x7"); g_free (tmp); /* non-contiguous */ ret = dfu_target_parse_sectors (target, "@Flash2 /0xF000/4*100Ba/0xE000/3*8Kg/0x80000/2*24Kg", &error); g_assert_no_error (error); g_assert (ret); tmp = dfu_target_sectors_to_string (target); g_assert_cmpstr (tmp, ==, "Zone:0, Sec#:0, Addr:0x0000f000, Size:0x0064, Caps:0x1\n" "Zone:0, Sec#:0, Addr:0x0000f064, Size:0x0064, Caps:0x1\n" "Zone:0, Sec#:0, Addr:0x0000f0c8, Size:0x0064, Caps:0x1\n" "Zone:0, Sec#:0, Addr:0x0000f12c, Size:0x0064, Caps:0x1\n" "Zone:1, Sec#:0, Addr:0x0000e000, Size:0x2000, Caps:0x7\n" "Zone:1, Sec#:0, Addr:0x00010000, Size:0x2000, Caps:0x7\n" "Zone:1, Sec#:0, Addr:0x00012000, Size:0x2000, Caps:0x7\n" "Zone:2, Sec#:0, Addr:0x00080000, Size:0x6000, Caps:0x7\n" "Zone:2, Sec#:0, Addr:0x00086000, Size:0x6000, Caps:0x7"); g_free (tmp); /* invalid */ ret = dfu_target_parse_sectors (target, "Flash", NULL); g_assert (ret); ret = dfu_target_parse_sectors (target, "@Internal Flash /0x08000000", NULL); g_assert (!ret); ret = dfu_target_parse_sectors (target, "@Internal Flash /0x08000000/12*001a", NULL); g_assert (!ret); /* indicate a cipher being used */ g_assert_cmpint (dfu_target_get_cipher_kind (target), ==, DFU_CIPHER_KIND_NONE); ret = dfu_target_parse_sectors (target, "@Flash|XTEA", &error); g_assert_no_error (error); g_assert (ret); g_assert_cmpint (dfu_target_get_cipher_kind (target), ==, DFU_CIPHER_KIND_XTEA); } 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 ("/libdfu/enums", dfu_enums_func); g_test_add_func ("/libdfu/target(DfuSe}", dfu_target_dfuse_func); g_test_add_func ("/libdfu/firmware{raw}", dfu_firmware_raw_func); g_test_add_func ("/libdfu/firmware{dfu}", dfu_firmware_dfu_func); g_test_add_func ("/libdfu/firmware{dfuse}", dfu_firmware_dfuse_func); g_test_add_func ("/libdfu/firmware{xdfu}", dfu_firmware_xdfu_func); g_test_add_func ("/libdfu/firmware{metadata}", dfu_firmware_metadata_func); g_test_add_func ("/libdfu/firmware{intel-hex}", dfu_firmware_intel_hex_func); g_test_add_func ("/libdfu/device", dfu_device_func); g_test_add_func ("/libdfu/colorhug+", dfu_colorhug_plus_func); return g_test_run (); } fwupd-0.7.0/libdfu/dfu-target-private.h000066400000000000000000000027661267747510300200220ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __DFU_TARGET_PRIVATE_H #define __DFU_TARGET_PRIVATE_H #include #include "dfu-device.h" #include "dfu-target.h" G_BEGIN_DECLS DfuTarget *dfu_target_new (DfuDevice *device, GUsbInterface *iface); GBytes *dfu_target_upload_chunk (DfuTarget *target, guint8 index, GCancellable *cancellable, GError **error); /* export this just for the self tests */ gboolean dfu_target_parse_sectors (DfuTarget *target, const gchar *alt_name, GError **error); G_END_DECLS #endif /* __DFU_TARGET_PRIVATE_H */ fwupd-0.7.0/libdfu/dfu-target.c000066400000000000000000001166561267747510300163510ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * SECTION:dfu-target * @short_description: Object representing a DFU-capable target * * This object allows uploading and downloading an image onto a * specific DFU-capable target. * * You only need to use this in preference to #DfuDevice if you only * want to update one target on the device. Most users will want to * update all the targets on the device at the same time. * * See also: #DfuDevice, #DfuImage */ #include "config.h" #include #include #include "dfu-common.h" #include "dfu-device-private.h" #include "dfu-error.h" #include "dfu-sector-private.h" #include "dfu-target-private.h" static void dfu_target_finalize (GObject *object); typedef enum { DFU_CMD_DFUSE_GET_COMMAND = 0x00, DFU_CMD_DFUSE_SET_ADDRESS_POINTER = 0x21, DFU_CMD_DFUSE_ERASE = 0x41, DFU_CMD_DFUSE_READ_UNPROTECT = 0x92, DFU_CMD_DFUSE_LAST } DfuCmdDfuse; /** * DfuTargetPrivate: * * Private #DfuTarget data **/ typedef struct { DfuDevice *device; /* not refcounted */ DfuCipherKind cipher_kind; gboolean done_setup; guint8 alt_setting; guint8 alt_idx; gchar *alt_name; GPtrArray *sectors; /* of DfuSector */ GHashTable *sectors_erased; /* of DfuSector:1 */ } DfuTargetPrivate; enum { SIGNAL_PERCENTAGE_CHANGED, SIGNAL_LAST }; static guint signals [SIGNAL_LAST] = { 0 }; G_DEFINE_TYPE_WITH_PRIVATE (DfuTarget, dfu_target, G_TYPE_OBJECT) #define GET_PRIVATE(o) (dfu_target_get_instance_private (o)) /** * dfu_target_class_init: **/ static void dfu_target_class_init (DfuTargetClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); /** * DfuTarget::percentage-changed: * @device: the #DfuTarget instance that emitted the signal * @percentage: the new percentage * * The ::percentage-changed signal is emitted when the percentage changes. * * Since: 0.5.4 **/ signals [SIGNAL_PERCENTAGE_CHANGED] = g_signal_new ("percentage-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (DfuTargetClass, percentage_changed), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); object_class->finalize = dfu_target_finalize; } /** * dfu_target_init: **/ static void dfu_target_init (DfuTarget *target) { DfuTargetPrivate *priv = GET_PRIVATE (target); priv->sectors = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); priv->sectors_erased = g_hash_table_new (g_direct_hash, g_direct_equal); } /** * dfu_target_finalize: **/ static void dfu_target_finalize (GObject *object) { DfuTarget *target = DFU_TARGET (object); DfuTargetPrivate *priv = GET_PRIVATE (target); g_free (priv->alt_name); g_ptr_array_unref (priv->sectors); g_hash_table_unref (priv->sectors_erased); /* we no longer care */ if (priv->device != NULL) { g_object_remove_weak_pointer (G_OBJECT (priv->device), (gpointer *) &priv->device); } G_OBJECT_CLASS (dfu_target_parent_class)->finalize (object); } /** * dfu_target_sectors_to_string: **/ static gchar * dfu_target_sectors_to_string (DfuTarget *target) { DfuTargetPrivate *priv = GET_PRIVATE (target); DfuSector *sector; GString *str; guint i; str = g_string_new (""); for (i = 0; i < priv->sectors->len; i++) { g_autofree gchar *tmp = NULL; sector = g_ptr_array_index (priv->sectors, i); tmp = dfu_sector_to_string (sector); g_string_append_printf (str, "%s\n", tmp); } if (str->len > 0) g_string_truncate (str, str->len - 1); return g_string_free (str, FALSE); } /** * dfu_target_get_sector_for_addr: * * Returns: the sector that should be used for a specific address, or %NULL **/ static DfuSector * dfu_target_get_sector_for_addr (DfuTarget *target, guint32 addr) { DfuTargetPrivate *priv = GET_PRIVATE (target); DfuSector *sector; guint i; for (i = 0; i < priv->sectors->len; i++) { sector = g_ptr_array_index (priv->sectors, i); if (addr < dfu_sector_get_address (sector)) continue; if (addr > dfu_sector_get_address (sector) + dfu_sector_get_size (sector)) continue; return sector; } return NULL; } /** * dfu_target_parse_sector: * * Parse the DfuSe sector format according to UM0424 **/ static gboolean dfu_target_parse_sector (DfuTarget *target, const gchar *dfuse_sector_id, guint32 addr, guint zone, guint number, GError **error) { DfuTargetPrivate *priv = GET_PRIVATE (target); DfuSectorCap cap = DFU_SECTOR_CAP_NONE; gchar *tmp; guint32 addr_offset = 0; guint64 nr_sectors; guint64 sector_size; guint i; /* parse # of sectors */ nr_sectors = g_ascii_strtoull (dfuse_sector_id, &tmp, 10); if (nr_sectors > 999) { g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "Invalid number of sectors: %s", dfuse_sector_id); return FALSE; } /* check this is the delimiter */ if (tmp[0] != '*') { g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "Invalid sector ID: %s", dfuse_sector_id); return FALSE; } /* parse sector size */ sector_size = g_ascii_strtoull (tmp + 1, &tmp, 10); if (sector_size > 999) { g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "Invalid sector size: %s", dfuse_sector_id); return FALSE; } /* optional spaces */ while (tmp[0] == ' ') tmp++; /* get multiplier */ switch (tmp[0]) { case 'B': /* byte */ break; case 'K': /* Kilo */ sector_size *= 0x400; break; case 'M': /* Mega */ sector_size *= 0x100000 ; break; default: g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "Invalid sector multiplier: %s", tmp); return FALSE; } /* get sector type */ switch (tmp[1]) { case 'a': cap = DFU_SECTOR_CAP_READABLE; break; case 'b': cap = DFU_SECTOR_CAP_ERASEABLE; break; case 'c': cap = DFU_SECTOR_CAP_READABLE | DFU_SECTOR_CAP_ERASEABLE; break; case 'd': cap = DFU_SECTOR_CAP_WRITEABLE; break; case 'e': cap = DFU_SECTOR_CAP_READABLE | DFU_SECTOR_CAP_WRITEABLE; break; case 'f': cap = DFU_SECTOR_CAP_ERASEABLE | DFU_SECTOR_CAP_WRITEABLE; break; case 'g': cap = DFU_SECTOR_CAP_READABLE | DFU_SECTOR_CAP_ERASEABLE | DFU_SECTOR_CAP_WRITEABLE; break; default: g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "Invalid sector type: %s", tmp); return FALSE; } /* add all the sectors */ for (i = 0; i < nr_sectors; i++) { DfuSector *sector; sector = dfu_sector_new (addr + addr_offset, sector_size, (nr_sectors * sector_size)- addr_offset, zone, number, cap); g_ptr_array_add (priv->sectors, sector); addr_offset += dfu_sector_get_size (sector); } return TRUE; } /** * dfu_target_parse_sectors: (skip) * * Parse the DfuSe format according to UM0424 **/ gboolean dfu_target_parse_sectors (DfuTarget *target, const gchar *alt_name, GError **error) { DfuTargetPrivate *priv = GET_PRIVATE (target); guint64 addr; guint i; guint j; g_autofree gchar *str_debug = NULL; g_auto(GStrv) zones = NULL; /* not set */ if (alt_name == NULL) return TRUE; /* do we have any hint for the cipher */ if (g_strstr_len (alt_name, -1, "|XTEA") != NULL) priv->cipher_kind = DFU_CIPHER_KIND_XTEA; /* From the Neo Freerunner */ if (g_str_has_prefix (alt_name, "RAM 0x")) { DfuSector *sector; addr = g_ascii_strtoull (alt_name + 6, NULL, 16); if (addr == 0 && addr > G_MAXUINT32) return FALSE; g_debug ("RAM descripton, so parsing"); sector = dfu_sector_new (addr, /* addr */ 0x0, /* size */ 0x0, /* size_left */ 0x0, /* zone */ 0x0, /* number */ DFU_SECTOR_CAP_READABLE | DFU_SECTOR_CAP_WRITEABLE); g_ptr_array_add (priv->sectors, sector); } /* not a DfuSe alternative name */ if (alt_name[0] != '@') return TRUE; /* clear any existing zones */ g_ptr_array_set_size (priv->sectors, 0); /* parse zones */ zones = g_strsplit (alt_name, "/", -1); g_debug ("DfuSe nice alt-name: %s", g_strchomp (zones[0] + 1)); for (i = 1; zones[i] != NULL; i += 2) { g_auto(GStrv) sectors = NULL; /* parse address */ if (!g_str_has_prefix (zones[i], "0x")) return FALSE; addr = g_ascii_strtoull (zones[i] + 2, NULL, 16); if (addr > G_MAXUINT32) return FALSE; /* no sectors?! */ if (zones[i+1] == NULL) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "No sector section"); return FALSE; } /* parse sectors */ sectors = g_strsplit (zones[i+1], ",", -1); for (j = 0; sectors[j] != NULL; j++) { if (!dfu_target_parse_sector (target, sectors[j], addr, (i - 1) / 2, j, error)) return FALSE; } } /* success */ str_debug = dfu_target_sectors_to_string (target); g_debug ("%s", str_debug); return TRUE; } /** * dfu_target_new: (skip) * @device: a #DfuDevice * @iface: a #GUsbInterface * * Creates a new DFU target, which represents an alt-setting on a * DFU-capable device. * * Return value: a #DfuTarget, or %NULL if @iface was not DFU-capable * * Since: 0.5.4 **/ DfuTarget * dfu_target_new (DfuDevice *device, GUsbInterface *iface) { DfuTargetPrivate *priv; DfuTarget *target; target = g_object_new (DFU_TYPE_TARGET, NULL); priv = GET_PRIVATE (target); priv->device = device; priv->alt_idx = g_usb_interface_get_index (iface); priv->alt_setting = g_usb_interface_get_alternate (iface); /* if we try to ref the target and destroy the device */ g_object_add_weak_pointer (G_OBJECT (priv->device), (gpointer *) &priv->device); return target; } /** * dfu_target_get_sectors: * @target: a #GUsbDevice * * Gets the sectors exported by the device. * * Return value: (transfer none) (element-type DfuSector): sectors * * Since: 0.5.4 **/ GPtrArray * dfu_target_get_sectors (DfuTarget *target) { DfuTargetPrivate *priv = GET_PRIVATE (target); g_return_val_if_fail (DFU_IS_TARGET (target), NULL); return priv->sectors; } /** * dfu_target_status_to_error_msg: * @status: a #DfuStatus, e.g. %DFU_STATUS_ERR_ERASE * * Converts an enumerated value to an error description. * * Return value: a string * * Since: 0.5.4 **/ static const gchar * dfu_target_status_to_error_msg (DfuStatus status) { if (status == DFU_STATUS_OK) return "No error condition is present"; if (status == DFU_STATUS_ERR_TARGET) return "Firmware is not for designed this device"; if (status == DFU_STATUS_ERR_FILE) return "Firmware is for this device but fails verification"; if (status == DFU_STATUS_ERR_WRITE) return "Device is unable to write memory"; if (status == DFU_STATUS_ERR_ERASE) return "Memory erase function failed"; if (status == DFU_STATUS_ERR_CHECK_ERASED) return "Memory erase check failed"; if (status == DFU_STATUS_ERR_PROG) return "Program memory function failed"; if (status == DFU_STATUS_ERR_VERIFY) return "Programmed memory failed verification"; if (status == DFU_STATUS_ERR_ADDRESS) return "Cannot program memory due to address out of range"; if (status == DFU_STATUS_ERR_NOTDONE) return "Received zero-length download but data is incomplete"; if (status == DFU_STATUS_ERR_FIRMWARE) return "Device firmware is corrupt"; if (status == DFU_STATUS_ERR_VENDOR) return "Vendor-specific error"; if (status == DFU_STATUS_ERR_USBR) return "Device detected unexpected USB reset signaling"; if (status == DFU_STATUS_ERR_POR) return "Device detected unexpected power on reset"; if (status == DFU_STATUS_ERR_UNKNOWN) return "Something unexpected went wrong"; if (status == DFU_STATUS_ERR_STALLDPKT) return "Device stalled an unexpected request"; return NULL; } /** * dfu_target_check_status: **/ static gboolean dfu_target_check_status (DfuTarget *target, GCancellable *cancellable, GError **error) { DfuTargetPrivate *priv = GET_PRIVATE (target); DfuStatus status; /* get the status */ if (!dfu_device_refresh (priv->device, cancellable, error)) return FALSE; /* not in an error state */ if (dfu_device_get_state (priv->device) != DFU_STATE_DFU_ERROR) return TRUE; /* DfuSe-specific long errors */ status = dfu_device_get_status (priv->device); if (dfu_device_has_dfuse_support (priv->device)) { if (status == DFU_STATUS_ERR_VENDOR) { g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "Read protection is active"); return FALSE; } if (status == DFU_STATUS_ERR_TARGET) { g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "Address is wrong or unsupported"); return FALSE; } } /* use a proper error description */ g_set_error_literal (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, dfu_target_status_to_error_msg (status)); return FALSE; } /** * dfu_target_use_alt_setting: * @target: a #DfuTarget * @error: a #GError, or %NULL * * Opens a DFU-capable target. * * Return value: %TRUE for success * * Since: 0.5.4 **/ static gboolean dfu_target_use_alt_setting (DfuTarget *target, GError **error) { DfuTargetPrivate *priv = GET_PRIVATE (target); GUsbDevice *dev; g_autoptr(GError) error_local = NULL; g_return_val_if_fail (DFU_IS_TARGET (target), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* use the correct setting */ dev = dfu_device_get_usb_dev (priv->device); if (dfu_device_get_mode (priv->device) == DFU_MODE_DFU) { if (!g_usb_device_set_interface_alt (dev, (gint) dfu_device_get_interface (priv->device), (gint) priv->alt_setting, &error_local)) { g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "cannot set alternate setting 0x%02x on interface %i: %s", priv->alt_setting, dfu_device_get_interface (priv->device), error_local->message); return FALSE; } } return TRUE; } /** * dfu_target_setup: * @target: a #DfuTarget * @error: a #GError, or %NULL * * Opens a DFU-capable target. * * Return value: %TRUE for success * * Since: 0.5.4 **/ static gboolean dfu_target_setup (DfuTarget *target, GError **error) { DfuTargetPrivate *priv = GET_PRIVATE (target); g_autoptr(GError) error_local = NULL; g_return_val_if_fail (DFU_IS_TARGET (target), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* already done */ if (priv->done_setup) return TRUE; /* get string */ if (priv->alt_idx != 0x00) { GUsbDevice *dev; dev = dfu_device_get_usb_dev (priv->device); priv->alt_name = g_usb_device_get_string_descriptor (dev, priv->alt_idx, NULL); } /* parse the DfuSe format according to UM0424 */ if (!dfu_target_parse_sectors (target, priv->alt_name, error)) return FALSE; /* add a dummy entry */ if (priv->sectors->len == 0) { DfuSector *sector; sector = dfu_sector_new (0x0, /* addr */ 0x0, /* size */ 0x0, /* size_left */ 0x0, /* zone */ 0x0, /* number */ DFU_SECTOR_CAP_READABLE | DFU_SECTOR_CAP_WRITEABLE); g_debug ("no UM0424 sector descripton in %s", priv->alt_name); g_ptr_array_add (priv->sectors, sector); } priv->done_setup = TRUE; return TRUE; } /** * dfu_target_download_chunk: **/ static gboolean dfu_target_download_chunk (DfuTarget *target, guint8 index, GBytes *bytes, GCancellable *cancellable, GError **error) { DfuTargetPrivate *priv = GET_PRIVATE (target); g_autoptr(GError) error_local = NULL; gsize actual_length; if (!g_usb_device_control_transfer (dfu_device_get_usb_dev (priv->device), G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, G_USB_DEVICE_REQUEST_TYPE_CLASS, G_USB_DEVICE_RECIPIENT_INTERFACE, DFU_REQUEST_DNLOAD, index, dfu_device_get_interface (priv->device), (guint8 *) g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), &actual_length, dfu_device_get_timeout (priv->device), cancellable, &error_local)) { /* refresh the error code */ dfu_device_error_fixup (priv->device, cancellable, &error_local); g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "cannot download data: %s", error_local->message); return FALSE; } /* for ST devices, the action only occurs when we do GetStatus */ if (!dfu_target_check_status (target, cancellable, error)) return FALSE; g_assert (actual_length == g_bytes_get_size (bytes)); return TRUE; } /** * dfu_target_set_address: * @target: a #DfuTarget * @address: memory address * @cancellable: a #GCancellable, or %NULL * @error: a #GError, or %NULL * * Sets the address used for the next download or upload request. * * IMPORTANT: This only works on DfuSe-capable devices from ST. * * Return value: %TRUE for success * * Since: 0.5.4 **/ static gboolean dfu_target_set_address (DfuTarget *target, guint32 address, GCancellable *cancellable, GError **error) { DfuTargetPrivate *priv = GET_PRIVATE (target); GBytes *data_in; guint8 buf[5]; /* invalid */ if (!dfu_device_has_dfuse_support (priv->device)) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "only supported for DfuSe targets"); return FALSE; } /* format buffer */ buf[0] = DFU_CMD_DFUSE_SET_ADDRESS_POINTER; memcpy (buf + 1, &address, 4); data_in = g_bytes_new_static (buf, sizeof(buf)); if (!dfu_target_download_chunk (target, 0, data_in, cancellable, error)) return FALSE; /* for ST devices, the action only occurs when we do GetStatus */ if (!dfu_target_check_status (target, cancellable, error)) return FALSE; return TRUE; } /** * dfu_target_erase_address: * @target: a #DfuTarget * @address: memory address * @cancellable: a #GCancellable, or %NULL * @error: a #GError, or %NULL * * Erases a memory sector at a given address. * * IMPORTANT: This only works on DfuSe-capable devices from ST. * * Return value: %TRUE for success * * Since: 0.5.4 **/ static gboolean dfu_target_erase_address (DfuTarget *target, guint32 address, GCancellable *cancellable, GError **error) { DfuTargetPrivate *priv = GET_PRIVATE (target); GBytes *data_in; guint8 buf[5]; /* invalid */ if (!dfu_device_has_dfuse_support (priv->device)) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "only supported for DfuSe targets"); return FALSE; } /* format buffer */ buf[0] = DFU_CMD_DFUSE_ERASE; memcpy (buf + 1, &address, 4); data_in = g_bytes_new_static (buf, sizeof(buf)); if (!dfu_target_download_chunk (target, 0, data_in, cancellable, error)) return FALSE; /* for ST devices, the action only occurs when we do GetStatus */ if (!dfu_target_check_status (target, cancellable, error)) return FALSE; /* 2nd check required to get error code */ return dfu_target_check_status (target, cancellable, error); } #if 0 /** * dfu_target_mass_erase: * @target: a #DfuTarget * @cancellable: a #GCancellable, or %NULL * @error: a #GError, or %NULL * * Mass erases the device clearing all SRAM and EEPROM memory. * * This may not be supported on all devices, a better way of doing this action * is to enable read protection and then doing dfu_target_read_unprotect(). * * IMPORTANT: This only works on DfuSe-capable devices from ST. * * Return value: %TRUE for success * * Since: 0.5.4 **/ static gboolean dfu_target_mass_erase (DfuTarget *target, GCancellable *cancellable, GError **error) { DfuTargetPrivate *priv = GET_PRIVATE (target); GBytes *data_in; guint8 buf[1]; /* invalid */ if (!dfu_device_has_dfuse_support (priv->device)) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "only supported for DfuSe targets"); return FALSE; } /* format buffer */ buf[0] = DFU_CMD_DFUSE_ERASE; data_in = g_bytes_new_static (buf, sizeof(buf)); if (!dfu_target_download_chunk (target, 0, data_in, cancellable, error)) return FALSE; /* for ST devices, the action only occurs when we do GetStatus */ if (!dfu_target_check_status (target, cancellable, error)) return FALSE; /* 2nd check required to get error code */ return dfu_target_check_status (target, cancellable, error); } /** * dfu_target_read_unprotect: * @target: a #DfuTarget * @cancellable: a #GCancellable, or %NULL * @error: a #GError, or %NULL * * Turns of read protection on the device, clearing all SRAM and EEPROM memory. * * IMPORTANT: This only works on DfuSe-capable devices from ST. * * Return value: %TRUE for success * * Since: 0.5.4 **/ static gboolean dfu_target_read_unprotect (DfuTarget *target, GCancellable *cancellable, GError **error) { DfuTargetPrivate *priv = GET_PRIVATE (target); GBytes *data_in; guint8 buf[5]; /* invalid */ if (!dfu_device_has_dfuse_support (priv->device)) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "only supported for DfuSe targets"); return FALSE; } /* format buffer */ buf[0] = DFU_CMD_DFUSE_READ_UNPROTECT; memcpy (buf + 1, &address, 4); data_in = g_bytes_new_static (buf, sizeof(buf)); if (!dfu_target_download_chunk (target, 0, data_in, cancellable, error)) return FALSE; /* for ST devices, the action only occurs when we do GetStatus */ return dfu_target_check_status (target, cancellable, error); } #endif /** * dfu_target_upload_chunk: (skip) **/ GBytes * dfu_target_upload_chunk (DfuTarget *target, guint8 index, GCancellable *cancellable, GError **error) { DfuTargetPrivate *priv = GET_PRIVATE (target); g_autoptr(GError) error_local = NULL; guint8 *buf; gsize actual_length; guint16 transfer_size = dfu_device_get_transfer_size (priv->device); buf = g_new0 (guint8, transfer_size); if (!g_usb_device_control_transfer (dfu_device_get_usb_dev (priv->device), G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, G_USB_DEVICE_REQUEST_TYPE_CLASS, G_USB_DEVICE_RECIPIENT_INTERFACE, DFU_REQUEST_UPLOAD, index, dfu_device_get_interface (priv->device), buf, (gsize) transfer_size, &actual_length, dfu_device_get_timeout (priv->device), cancellable, &error_local)) { /* refresh the error code */ dfu_device_error_fixup (priv->device, cancellable, &error_local); g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "cannot upload data: %s", error_local->message); return NULL; } /* for ST devices, the action only occurs when we do GetStatus */ if (!dfu_device_has_quirk (priv->device, DFU_DEVICE_QUIRK_NO_GET_STATUS_UPLOAD)) { if (!dfu_target_check_status (target, cancellable, error)) return NULL; } return g_bytes_new_take (buf, actual_length); } /** * dfu_target_upload_element: **/ static DfuElement * dfu_target_upload_element (DfuTarget *target, guint32 address, gsize expected_size, GCancellable *cancellable, GError **error) { DfuTargetPrivate *priv = GET_PRIVATE (target); DfuSector *sector; DfuElement *element = NULL; GBytes *chunk_tmp; gsize chunk_size; gsize offset = 0; gsize total_size = 0; guint16 transfer_size = dfu_device_get_transfer_size (priv->device); guint8 *buffer; guint32 last_sector_id = G_MAXUINT; guint dfuse_sector_offset = 0; guint i; guint old_percentage = G_MAXUINT; g_autoptr(GBytes) contents = NULL; g_autoptr(GPtrArray) chunks = NULL; /* ST uses wBlockNum=0 for DfuSe commands and wBlockNum=1 is reserved */ if (dfu_device_has_dfuse_support (priv->device)) { offset += address; dfuse_sector_offset = 2; } /* get all the chunks from the hardware */ chunks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref); for (i = 0; i < 0xffff; i++) { /* for DfuSe devices we need to handle the address manually */ if (dfu_device_has_dfuse_support (priv->device)) { /* check the sector with this element address is suitable */ sector = dfu_target_get_sector_for_addr (target, offset); if (sector == NULL) { g_set_error (error, DFU_ERROR, DFU_ERROR_INVALID_DEVICE, "no memory sector at 0x%04x", (guint) offset); return NULL; } if (!dfu_sector_has_cap (sector, DFU_SECTOR_CAP_READABLE)) { g_set_error (error, DFU_ERROR, DFU_ERROR_INVALID_DEVICE, "memory sector at 0x%04x is not readble", (guint) offset); return NULL; } /* manually set the sector address */ if (dfu_sector_get_id (sector) != last_sector_id) { g_debug ("setting DfuSe address to 0x%04x", (guint) offset); if (!dfu_target_set_address (target, offset, cancellable, error)) return NULL; last_sector_id = dfu_sector_get_id (sector); } } /* read chunk of data */ chunk_tmp = dfu_target_upload_chunk (target, i + dfuse_sector_offset, cancellable, error); if (chunk_tmp == NULL) return NULL; /* keep a sum of all the chunks */ chunk_size = g_bytes_get_size (chunk_tmp); total_size += chunk_size; offset += chunk_size; /* add to array */ g_debug ("got #%04x chunk of size %" G_GSIZE_FORMAT, i, chunk_size); g_ptr_array_add (chunks, chunk_tmp); /* update UI */ if (chunk_size > 0) { guint percentage = (total_size * 100) / expected_size; if (percentage != old_percentage) { g_signal_emit (target, signals[SIGNAL_PERCENTAGE_CHANGED], 0, percentage); } } /* detect short write as EOF */ if (chunk_size < transfer_size) break; } /* check final size */ if (expected_size > 0) { if (total_size != expected_size) { g_set_error (error, DFU_ERROR, DFU_ERROR_INVALID_FILE, "invalid size, got %" G_GSIZE_FORMAT ", " "expected %" G_GSIZE_FORMAT , total_size, expected_size); return NULL; } } /* stitch them all together */ offset = 0; buffer = g_malloc0 (total_size); for (i = 0; i < chunks->len; i++) { const guint8 *chunk_data; chunk_tmp = g_ptr_array_index (chunks, i); chunk_data = g_bytes_get_data (chunk_tmp, &chunk_size); memcpy (buffer + offset, chunk_data, chunk_size); offset += chunk_size; } /* create new image */ contents = g_bytes_new_take (buffer, total_size); element = dfu_element_new (); dfu_element_set_contents (element, contents); return element; } /** * dfu_target_upload: * @target: a #DfuTarget * @flags: flags to use, e.g. %DFU_TARGET_TRANSFER_FLAG_VERIFY * @cancellable: a #GCancellable, or %NULL * @error: a #GError, or %NULL * * Uploads firmware from the target to the host. * * Return value: (transfer full): the uploaded image, or %NULL for error * * Since: 0.5.4 **/ DfuImage * dfu_target_upload (DfuTarget *target, DfuTargetTransferFlags flags, GCancellable *cancellable, GError **error) { DfuTargetPrivate *priv = GET_PRIVATE (target); DfuSector *sector; guint i; guint32 last_sector_id = G_MAXUINT; g_autoptr(DfuImage) image = NULL; g_return_val_if_fail (DFU_IS_TARGET (target), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* ensure populated */ if (!dfu_target_setup (target, error)) return NULL; /* can the target do this? */ if (!dfu_device_can_upload (priv->device)) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "target cannot do uploading"); return NULL; } /* use correct alt */ if (!dfu_target_use_alt_setting (target, error)) return NULL; /* no open?! */ if (priv->sectors->len == 0) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "no sectors defined for target"); return NULL; } /* create a new image */ image = dfu_image_new (); dfu_image_set_name (image, priv->alt_name); dfu_image_set_alt_setting (image, priv->alt_setting); /* get all the sectors for the device */ for (i = 0; i < priv->sectors->len; i++) { g_autoptr(DfuElement) element = NULL; /* only upload to the start of any zone:sector */ sector = g_ptr_array_index (priv->sectors, i); if (dfu_sector_get_id (sector) == last_sector_id) continue; /* get the first element from the hardware */ g_debug ("starting upload from 0x%08x (0x%04x)", dfu_sector_get_address (sector), dfu_sector_get_size_left (sector)); element = dfu_target_upload_element (target, dfu_sector_get_address (sector), dfu_sector_get_size_left (sector), cancellable, error); if (element == NULL) return NULL; /* this element was uploaded okay */ dfu_image_add_element (image, element); /* ignore sectors until one of these changes */ last_sector_id = dfu_sector_get_id (sector); } /* do host reset */ if ((flags & DFU_TARGET_TRANSFER_FLAG_ATTACH) > 0 || (flags & DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME) > 0) { if (!dfu_device_attach (priv->device, error)) return NULL; } /* boot to runtime */ if (flags & DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME) { g_debug ("booting to runtime"); if (!dfu_device_wait_for_replug (priv->device, DFU_DEVICE_REPLUG_TIMEOUT, cancellable, error)) return NULL; } /* success */ return g_object_ref (image); } /** * _g_bytes_compare_verbose: **/ static gchar * _g_bytes_compare_verbose (GBytes *bytes1, GBytes *bytes2) { const guint8 *data1; const guint8 *data2; gsize length1; gsize length2; guint i; data1 = g_bytes_get_data (bytes1, &length1); data2 = g_bytes_get_data (bytes2, &length2); /* not the same length */ if (length1 != length2) { return g_strdup_printf ("got %" G_GSIZE_FORMAT " bytes, " "expected %" G_GSIZE_FORMAT, length1, length2); } /* return 00 01 02 03 */ for (i = 0; i < length1; i++) { if (data1[i] != data2[i]) { return g_strdup_printf ("got 0x%02x, expected 0x%02x @ 0x%04x", data1[i], data2[i], i); } } return NULL; } /** * dfu_target_download_element: **/ static gboolean dfu_target_download_element (DfuTarget *target, DfuElement *element, DfuTargetTransferFlags flags, GCancellable *cancellable, GError **error) { DfuTargetPrivate *priv = GET_PRIVATE (target); DfuSector *sector; GBytes *bytes; guint i; guint nr_chunks; guint dfuse_sector_offset = 0; guint last_sector_id = G_MAXUINT; guint old_percentage = G_MAXUINT; guint16 transfer_size = dfu_device_get_transfer_size (priv->device); g_autoptr(GError) error_local = NULL; /* ST uses wBlockNum=0 for DfuSe commands and wBlockNum=1 is reserved */ if (dfu_device_has_dfuse_support (priv->device)) dfuse_sector_offset = 2; /* round up as we have to transfer incomplete blocks */ bytes = dfu_element_get_contents (element); nr_chunks = ceil ((gdouble) g_bytes_get_size (bytes) / (gdouble) transfer_size); if (nr_chunks == 0) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INVALID_FILE, "zero-length firmware"); return FALSE; } for (i = 0; i < nr_chunks + 1; i++) { gsize length; gsize offset; guint percentage; g_autoptr(GBytes) bytes_tmp = NULL; /* caclulate the offset into the element data */ offset = i * transfer_size; /* for DfuSe devices we need to handle the erase and setting * the address manually */ if (dfu_device_has_dfuse_support (priv->device)) { /* check the sector with this element address is suitable */ sector = dfu_target_get_sector_for_addr (target, offset); if (sector == NULL) { g_set_error (error, DFU_ERROR, DFU_ERROR_INVALID_DEVICE, "no memory sector at 0x%04x", (guint) offset); return FALSE; } if (!dfu_sector_has_cap (sector, DFU_SECTOR_CAP_WRITEABLE)) { g_set_error (error, DFU_ERROR, DFU_ERROR_INVALID_DEVICE, "memory sector at 0x%04x is not writable", (guint) offset); return FALSE; } /* if it's erasable and not yet blanked */ if (!dfu_sector_has_cap (sector, DFU_SECTOR_CAP_ERASEABLE) && g_hash_table_lookup (priv->sectors_erased, sector) == NULL) { g_debug ("erasing DfuSe address at 0x%04x", (guint) offset); if (!dfu_target_erase_address (target, offset, cancellable, error)) return FALSE; g_hash_table_insert (priv->sectors_erased, sector, GINT_TO_POINTER (1)); } /* manually set the sector address */ if (dfu_sector_get_id (sector) != last_sector_id) { g_debug ("setting DfuSe address to 0x%04x", (guint) offset); if (!dfu_target_set_address (target, offset, cancellable, error)) return FALSE; last_sector_id = dfu_sector_get_id (sector); } } /* we have to write one final zero-sized chunk for EOF */ if (i < nr_chunks) { length = g_bytes_get_size (bytes) - offset; if (length > transfer_size) length = transfer_size; bytes_tmp = g_bytes_new_from_bytes (bytes, offset, length); } else { bytes_tmp = g_bytes_new (NULL, 0); } g_debug ("writing #%04x chunk of size %" G_GSIZE_FORMAT, i, g_bytes_get_size (bytes_tmp)); if (!dfu_target_download_chunk (target, i + dfuse_sector_offset, bytes_tmp, cancellable, error)) return FALSE; /* update UI */ percentage = (offset * 100) / g_bytes_get_size (bytes); if (percentage != old_percentage) { g_signal_emit (target, signals[SIGNAL_PERCENTAGE_CHANGED], 0, percentage); } /* give the target a chance to update */ g_usleep (dfu_device_get_download_timeout (priv->device) * 1000); /* getting the status moves the state machine to DNLOAD-IDLE */ if (!dfu_device_refresh (priv->device, cancellable, error)) return FALSE; } /* verify */ if (flags & DFU_TARGET_TRANSFER_FLAG_VERIFY) { GBytes *bytes_tmp; g_autoptr(DfuElement) element_tmp = NULL; element_tmp = dfu_target_upload_element (target, dfu_element_get_address (element), g_bytes_get_size (bytes), cancellable, error); if (element_tmp == NULL) return FALSE; bytes_tmp = dfu_element_get_contents (element_tmp); if (g_bytes_compare (bytes_tmp, bytes) != 0) { g_autofree gchar *bytes_cmp_str = NULL; bytes_cmp_str = _g_bytes_compare_verbose (bytes_tmp, bytes); g_set_error (error, DFU_ERROR, DFU_ERROR_VERIFY_FAILED, "verify failed: %s", bytes_cmp_str); return FALSE; } } return TRUE; } /** * dfu_target_download: * @target: a #DfuTarget * @image: a #DfuImage * @flags: flags to use, e.g. %DFU_TARGET_TRANSFER_FLAG_VERIFY * @cancellable: a #GCancellable, or %NULL * @error: a #GError, or %NULL * * Downloads firmware from the host to the target, optionally verifying * the transfer. * * Return value: %TRUE for success * * Since: 0.5.4 **/ gboolean dfu_target_download (DfuTarget *target, DfuImage *image, DfuTargetTransferFlags flags, GCancellable *cancellable, GError **error) { DfuTargetPrivate *priv = GET_PRIVATE (target); DfuElement *element; GPtrArray *elements; gboolean ret; guint i; g_return_val_if_fail (DFU_IS_TARGET (target), FALSE); g_return_val_if_fail (DFU_IS_IMAGE (image), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* ensure populated */ if (!dfu_target_setup (target, error)) return FALSE; /* can the target do this? */ if (!dfu_device_can_download (priv->device)) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "target cannot do downloading"); return FALSE; } /* use correct alt */ if (!dfu_target_use_alt_setting (target, error)) return FALSE; /* mark these as all erased */ if (dfu_device_has_dfuse_support (priv->device)) g_hash_table_remove_all (priv->sectors_erased); /* download all elements in the image to the device */ elements = dfu_image_get_elements (image); if (elements->len == 0) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INVALID_FILE, "no image elements"); return FALSE; } for (i = 0; i < elements->len; i++) { element = dfu_image_get_element (image, i); g_debug ("downloading element at 0x%04x", dfu_element_get_address (element)); ret = dfu_target_download_element (target, element, flags, cancellable, error); if (!ret) return FALSE; } /* attempt to switch back to runtime */ if ((flags & DFU_TARGET_TRANSFER_FLAG_ATTACH) > 0 || (flags & DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME) > 0) { if (!dfu_device_attach (priv->device, error)) return FALSE; } /* boot to runtime */ if (flags & DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME) { g_debug ("booting to runtime to set auto-boot"); if (!dfu_device_wait_for_replug (priv->device, DFU_DEVICE_REPLUG_TIMEOUT, cancellable, error)) return FALSE; } /* success */ return TRUE; } #if 0 /** * dfu_target_get_commands: **/ static gboolean dfu_target_get_commands (DfuTarget *target, GCancellable *cancellable, GError **error) { GBytes *data_in; GBytes *data_out; guint8 buf[1]; /* invalid */ if (!dfu_device_has_dfuse_support (priv->device)) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "only supported for DfuSe targets"); return FALSE; } /* format buffer */ buf[0] = DFU_CMD_DFUSE_GET_COMMAND; data_in = g_bytes_new_static (buf, sizeof(buf)); if (!dfu_target_download_chunk (target, 0, data_in, cancellable, error)) return FALSE; /* return results */ data_out = dfu_target_upload_chunk (target, 0, cancellable, error); if (data_out == NULL) return FALSE; // N bytes, // each byte is the command code // FIXME: parse? return TRUE; } #endif /** * dfu_target_get_alt_setting: * @target: a #DfuTarget * * Gets the alternate setting to use for this interface. * * Return value: the alternative setting, typically zero * * Since: 0.5.4 **/ guint8 dfu_target_get_alt_setting (DfuTarget *target) { DfuTargetPrivate *priv = GET_PRIVATE (target); g_return_val_if_fail (DFU_IS_TARGET (target), 0xff); return priv->alt_setting; } /** * dfu_target_get_alt_name: * @target: a #DfuTarget * @error: a #GError, or %NULL * * Gets the alternate setting name to use for this interface. * * Return value: the alternative setting name, typically %NULL * * Since: 0.5.4 **/ const gchar * dfu_target_get_alt_name (DfuTarget *target, GError **error) { DfuTargetPrivate *priv = GET_PRIVATE (target); g_return_val_if_fail (DFU_IS_TARGET (target), NULL); /* ensure populated */ if (!dfu_target_setup (target, error)) return NULL; /* nothing */ if (priv->alt_name == NULL) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_NOT_FOUND, "no alt-name"); return NULL; } return priv->alt_name; } /** * dfu_target_get_cipher_kind: * @target: a #DfuTarget * * Gets the cipher used for data sent to this interface. * * Return value: the cipher, typically %DFU_CIPHER_KIND_NONE * * Since: 0.5.4 **/ DfuCipherKind dfu_target_get_cipher_kind (DfuTarget *target) { DfuTargetPrivate *priv = GET_PRIVATE (target); g_return_val_if_fail (DFU_IS_TARGET (target), 0); return priv->cipher_kind; } fwupd-0.7.0/libdfu/dfu-target.h000066400000000000000000000070351267747510300163440ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __DFU_TARGET_H #define __DFU_TARGET_H #include #include #include #include "dfu-common.h" #include "dfu-image.h" G_BEGIN_DECLS #define DFU_TYPE_TARGET (dfu_target_get_type ()) G_DECLARE_DERIVABLE_TYPE (DfuTarget, dfu_target, DFU, TARGET, GUsbDevice) struct _DfuTargetClass { GUsbDeviceClass parent_class; void (*percentage_changed) (DfuTarget *target, guint percentage); /*< private >*/ /* Padding for future expansion */ void (*_dfu_target_reserved1) (void); void (*_dfu_target_reserved2) (void); void (*_dfu_target_reserved3) (void); void (*_dfu_target_reserved4) (void); void (*_dfu_target_reserved5) (void); void (*_dfu_target_reserved6) (void); void (*_dfu_target_reserved7) (void); void (*_dfu_target_reserved8) (void); void (*_dfu_target_reserved9) (void); }; /** * DfuTargetTransferFlags: * @DFU_TARGET_TRANSFER_FLAG_NONE: No flags set * @DFU_TARGET_TRANSFER_FLAG_VERIFY: Verify the download once complete * @DFU_TARGET_TRANSFER_FLAG_DETACH: If required, detach from runtime mode * @DFU_TARGET_TRANSFER_FLAG_ATTACH: Attach the device back to runtime after completion * @DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME: Wait for runtime to load after completion * @DFU_TARGET_TRANSFER_FLAG_WILDCARD_VID: Allow downloading images with wildcard VIDs * @DFU_TARGET_TRANSFER_FLAG_WILDCARD_PID: Allow downloading images with wildcard PIDs * @DFU_TARGET_TRANSFER_FLAG_ANY_CIPHER: Allow any cipher kinds to be downloaded * * The optional flags used for transfering firmware. **/ typedef enum { DFU_TARGET_TRANSFER_FLAG_NONE = 0, DFU_TARGET_TRANSFER_FLAG_VERIFY = (1 << 0), DFU_TARGET_TRANSFER_FLAG_DETACH = (1 << 1), DFU_TARGET_TRANSFER_FLAG_ATTACH = (1 << 2), DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME = (1 << 3), DFU_TARGET_TRANSFER_FLAG_WILDCARD_VID = (1 << 4), DFU_TARGET_TRANSFER_FLAG_WILDCARD_PID = (1 << 5), DFU_TARGET_TRANSFER_FLAG_ANY_CIPHER = (1 << 6), /*< private >*/ DFU_TARGET_TRANSFER_FLAG_LAST } DfuTargetTransferFlags; GPtrArray *dfu_target_get_sectors (DfuTarget *target); guint8 dfu_target_get_alt_setting (DfuTarget *target); const gchar *dfu_target_get_alt_name (DfuTarget *target, GError **error); DfuImage *dfu_target_upload (DfuTarget *target, DfuTargetTransferFlags flags, GCancellable *cancellable, GError **error); gboolean dfu_target_download (DfuTarget *target, DfuImage *image, DfuTargetTransferFlags flags, GCancellable *cancellable, GError **error); DfuCipherKind dfu_target_get_cipher_kind (DfuTarget *target); G_END_DECLS #endif /* __DFU_TARGET_H */ fwupd-0.7.0/libdfu/dfu-tool.c000066400000000000000000001576211267747510300160350ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include #include #include "dfu-device-private.h" typedef struct { GCancellable *cancellable; GPtrArray *cmd_array; gboolean force; gchar *device_vid_pid; guint16 transfer_size; } DfuToolPrivate; /** * dfu_tool_print_indent: **/ static void dfu_tool_print_indent (const gchar *title, const gchar *message, guint indent) { guint i; for (i = 0; i < indent; i++) g_print (" "); g_print ("%s:", title); for (i = strlen (title) + indent; i < 15; i++) g_print (" "); g_print ("%s\n", message); } /** * dfu_tool_private_free: **/ static void dfu_tool_private_free (DfuToolPrivate *priv) { if (priv == NULL) return; g_free (priv->device_vid_pid); g_object_unref (priv->cancellable); if (priv->cmd_array != NULL) g_ptr_array_unref (priv->cmd_array); g_free (priv); } G_DEFINE_AUTOPTR_CLEANUP_FUNC(DfuToolPrivate, dfu_tool_private_free) typedef gboolean (*FuUtilPrivateCb) (DfuToolPrivate *util, gchar **values, GError **error); typedef struct { gchar *name; gchar *arguments; gchar *description; FuUtilPrivateCb callback; } FuUtilItem; /** * dfu_tool_item_free: **/ static void dfu_tool_item_free (FuUtilItem *item) { g_free (item->name); g_free (item->arguments); g_free (item->description); g_free (item); } /** * dfu_tool_sort_command_name_cb: **/ static gint dfu_tool_sort_command_name_cb (FuUtilItem **item1, FuUtilItem **item2) { return g_strcmp0 ((*item1)->name, (*item2)->name); } /** * dfu_tool_add: **/ static void dfu_tool_add (GPtrArray *array, const gchar *name, const gchar *arguments, const gchar *description, FuUtilPrivateCb callback) { guint i; FuUtilItem *item; g_auto(GStrv) names = NULL; g_return_if_fail (name != NULL); g_return_if_fail (description != NULL); g_return_if_fail (callback != NULL); /* add each one */ names = g_strsplit (name, ",", -1); for (i = 0; names[i] != NULL; i++) { item = g_new0 (FuUtilItem, 1); item->name = g_strdup (names[i]); if (i == 0) { item->description = g_strdup (description); } else { /* TRANSLATORS: this is a command alias, e.g. 'get-devices' */ item->description = g_strdup_printf (_("Alias to %s"), names[0]); } item->arguments = g_strdup (arguments); item->callback = callback; g_ptr_array_add (array, item); } } /** * dfu_tool_get_descriptions: **/ static gchar * dfu_tool_get_descriptions (GPtrArray *array) { guint i; guint j; guint len; const guint max_len = 31; FuUtilItem *item; GString *string; /* print each command */ string = g_string_new (""); for (i = 0; i < array->len; i++) { item = g_ptr_array_index (array, i); g_string_append (string, " "); g_string_append (string, item->name); len = strlen (item->name) + 2; if (item->arguments != NULL) { g_string_append (string, " "); g_string_append (string, item->arguments); len += strlen (item->arguments) + 1; } if (len < max_len) { for (j = len; j < max_len + 1; j++) g_string_append_c (string, ' '); g_string_append (string, item->description); g_string_append_c (string, '\n'); } else { g_string_append_c (string, '\n'); for (j = 0; j < max_len + 1; j++) g_string_append_c (string, ' '); g_string_append (string, item->description); g_string_append_c (string, '\n'); } } /* remove trailing newline */ if (string->len > 0) g_string_set_size (string, string->len - 1); return g_string_free (string, FALSE); } /** * dfu_tool_run: **/ static gboolean dfu_tool_run (DfuToolPrivate *priv, const gchar *command, gchar **values, GError **error) { guint i; FuUtilItem *item; /* find command */ for (i = 0; i < priv->cmd_array->len; i++) { item = g_ptr_array_index (priv->cmd_array, i); if (g_strcmp0 (item->name, command) == 0) return item->callback (priv, values, error); } /* not found */ g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, /* TRANSLATORS: error message */ _("Command not found")); return FALSE; } /** * dfu_tool_get_defalt_device: **/ static DfuDevice * dfu_tool_get_defalt_device (DfuToolPrivate *priv, GError **error) { DfuDevice *device; g_autoptr(DfuContext) dfu_context = NULL; /* get all the DFU devices */ dfu_context = dfu_context_new (); dfu_context_enumerate (dfu_context, NULL); /* we specified it manually */ if (priv->device_vid_pid != NULL) { gchar *tmp; guint64 pid; guint64 vid; /* parse */ vid = g_ascii_strtoull (priv->device_vid_pid, &tmp, 16); if (vid == 0 || vid > G_MAXUINT16) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Invalid format of VID:PID"); return NULL; } if (tmp[0] != ':') { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Invalid format of VID:PID"); return NULL; } pid = g_ascii_strtoull (tmp + 1, NULL, 16); if (vid == 0 || vid > G_MAXUINT16) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Invalid format of VID:PID"); return NULL; } /* find device */ device = dfu_context_get_device_by_vid_pid (dfu_context, vid, pid, error); if (device == NULL) return NULL; } else { /* auto-detect first device */ device = dfu_context_get_device_default (dfu_context, error); if (device == NULL) return NULL; } /* this has to be added to the device so we can deal with detach */ g_object_set_data_full (G_OBJECT (device), "DfuContext", g_object_ref (dfu_context), (GDestroyNotify) g_object_unref); return device; } /** * dfu_tool_set_vendor: **/ static gboolean dfu_tool_set_vendor (DfuToolPrivate *priv, gchar **values, GError **error) { guint64 tmp; g_autoptr(DfuFirmware) firmware = NULL; g_autoptr(GFile) file = NULL; /* check args */ if (g_strv_length (values) < 2) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Invalid arguments, expected FILE VID" " -- e.g. `firmware.dfu 273f"); return FALSE; } /* open */ file = g_file_new_for_path (values[0]); firmware = dfu_firmware_new (); if (!dfu_firmware_parse_file (firmware, file, DFU_FIRMWARE_PARSE_FLAG_NONE, priv->cancellable, error)) { return FALSE; } /* parse VID */ tmp = g_ascii_strtoull (values[1], NULL, 16); if (tmp == 0 || tmp > 0xffff) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Failed to parse VID '%s'", values[1]); return FALSE; } dfu_firmware_set_vid (firmware, tmp); /* write out new file */ return dfu_firmware_write_file (firmware, file, priv->cancellable, error); } /** * dfu_tool_set_product: **/ static gboolean dfu_tool_set_product (DfuToolPrivate *priv, gchar **values, GError **error) { guint64 tmp; g_autoptr(DfuFirmware) firmware = NULL; g_autoptr(GFile) file = NULL; /* check args */ if (g_strv_length (values) < 2) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Invalid arguments, expected FILE PID" " -- e.g. `firmware.dfu 1004"); return FALSE; } /* open */ file = g_file_new_for_path (values[0]); firmware = dfu_firmware_new (); if (!dfu_firmware_parse_file (firmware, file, DFU_FIRMWARE_PARSE_FLAG_NONE, priv->cancellable, error)) { return FALSE; } /* parse VID */ tmp = g_ascii_strtoull (values[1], NULL, 16); if (tmp == 0 || tmp > 0xffff) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Failed to parse PID '%s'", values[1]); return FALSE; } dfu_firmware_set_pid (firmware, tmp); /* write out new file */ return dfu_firmware_write_file (firmware, file, priv->cancellable, error); } /** * dfu_tool_set_release: **/ static gboolean dfu_tool_set_release (DfuToolPrivate *priv, gchar **values, GError **error) { guint64 tmp; g_autoptr(DfuFirmware) firmware = NULL; g_autoptr(GFile) file = NULL; /* check args */ if (g_strv_length (values) < 2) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Invalid arguments, expected FILE RELEASE" " -- e.g. `firmware.dfu ffff"); return FALSE; } /* open */ file = g_file_new_for_path (values[0]); firmware = dfu_firmware_new (); if (!dfu_firmware_parse_file (firmware, file, DFU_FIRMWARE_PARSE_FLAG_NONE, priv->cancellable, error)) { return FALSE; } /* parse VID */ tmp = g_ascii_strtoull (values[1], NULL, 16); if (tmp == 0 || tmp > 0xffff) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Failed to parse release '%s'", values[1]); return FALSE; } dfu_firmware_set_release (firmware, tmp); /* write out new file */ return dfu_firmware_write_file (firmware, file, priv->cancellable, error); } /** * dfu_tool_set_metadata: **/ static gboolean dfu_tool_set_metadata (DfuToolPrivate *priv, gchar **values, GError **error) { g_autoptr(DfuFirmware) firmware = NULL; g_autoptr(GFile) file = NULL; /* check args */ if (g_strv_length (values) < 3) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Invalid arguments, expected FILE KEY VALUE" " -- e.g. `firmware.dfu Licence GPL-2.0+"); return FALSE; } /* open */ file = g_file_new_for_path (values[0]); firmware = dfu_firmware_new (); if (!dfu_firmware_parse_file (firmware, file, DFU_FIRMWARE_PARSE_FLAG_NONE, priv->cancellable, error)) { return FALSE; } /* doesn't make sense for non-DFU */ if (dfu_firmware_get_format (firmware) == DFU_FIRMWARE_FORMAT_RAW) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Only possible on DFU/DfuSe images, try convert"); return FALSE; } /* set metadata */ dfu_firmware_set_metadata (firmware, values[1], values[2]); /* write out new file */ return dfu_firmware_write_file (firmware, file, priv->cancellable, error); } /** * dfu_tool_set_alt_setting: **/ static gboolean dfu_tool_set_alt_setting (DfuToolPrivate *priv, gchar **values, GError **error) { DfuImage *image; guint64 tmp; g_autoptr(DfuFirmware) firmware = NULL; g_autoptr(GFile) file = NULL; /* check args */ if (g_strv_length (values) < 2) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Invalid arguments, expected FILE ALT-ID" " -- e.g. `firmware.dfu 1"); return FALSE; } /* open */ file = g_file_new_for_path (values[0]); firmware = dfu_firmware_new (); if (!dfu_firmware_parse_file (firmware, file, DFU_FIRMWARE_PARSE_FLAG_NONE, priv->cancellable, error)) { return FALSE; } /* doesn't make sense for non-DfuSe */ if (dfu_firmware_get_format (firmware) != DFU_FIRMWARE_FORMAT_DFUSE) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Only possible on DfuSe images, try convert"); return FALSE; } /* parse VID */ tmp = g_ascii_strtoull (values[1], NULL, 10); if (tmp == 0 || tmp > 0xff) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Failed to parse alternative setting '%s'", values[1]); return FALSE; } image = dfu_firmware_get_image_default (firmware); if (image == NULL) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "found no image '%s'", values[1]); return FALSE; } dfu_image_set_alt_setting (image, tmp); /* write out new file */ return dfu_firmware_write_file (firmware, file, priv->cancellable, error); } /** * dfu_tool_set_alt_setting_name: **/ static gboolean dfu_tool_set_alt_setting_name (DfuToolPrivate *priv, gchar **values, GError **error) { DfuImage *image; g_autoptr(DfuFirmware) firmware = NULL; g_autoptr(GFile) file = NULL; /* check args */ if (g_strv_length (values) < 2) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Invalid arguments, expected FILE ALT-NAME" " -- e.g. `firmware.dfu ST"); return FALSE; } /* open */ file = g_file_new_for_path (values[0]); firmware = dfu_firmware_new (); if (!dfu_firmware_parse_file (firmware, file, DFU_FIRMWARE_PARSE_FLAG_NONE, priv->cancellable, error)) { return FALSE; } /* doesn't make sense for non-DfuSe */ if (dfu_firmware_get_format (firmware) != DFU_FIRMWARE_FORMAT_DFUSE) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Only possible on DfuSe images, try convert"); return FALSE; } /* parse VID */ image = dfu_firmware_get_image_default (firmware); if (image == NULL) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "found no image '%s'", values[1]); return FALSE; } dfu_image_set_name (image, values[1]); /* write out new file */ return dfu_firmware_write_file (firmware, file, priv->cancellable, error); } /** * dfu_tool_merge: **/ static gboolean dfu_tool_merge (DfuToolPrivate *priv, gchar **values, GError **error) { guint16 pid = 0xffff; guint16 rel = 0xffff; guint16 vid = 0xffff; guint i; g_autofree gchar *str_debug = NULL; g_autoptr(DfuFirmware) firmware = NULL; g_autoptr(GFile) file = NULL; /* check args */ if (g_strv_length (values) < 3) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Invalid arguments, expected " "FILE-OUT FILE1 FILE2 [FILE3...]" " -- e.g. `combined.dfu lib.dfu app.dfu`"); return FALSE; } /* parse source files */ firmware = dfu_firmware_new (); dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_DFUSE); for (i = 1; values[i] != NULL; i++) { GPtrArray *images; guint j; g_autoptr(GFile) file_tmp = NULL; g_autoptr(DfuFirmware) firmware_tmp = NULL; /* open up source */ file_tmp = g_file_new_for_path (values[i]); firmware_tmp = dfu_firmware_new (); if (!dfu_firmware_parse_file (firmware_tmp, file_tmp, DFU_FIRMWARE_PARSE_FLAG_NONE, priv->cancellable, error)) { return FALSE; } /* check same vid:pid:rel */ if (vid != 0xffff && dfu_firmware_get_vid (firmware_tmp) != vid) { g_set_error (error, DFU_ERROR, DFU_ERROR_INVALID_FILE, "Vendor ID was already set as " "0x%04x, %s is 0x%04x", vid, values[i], dfu_firmware_get_vid (firmware_tmp)); return FALSE; } if (pid != 0xffff && dfu_firmware_get_pid (firmware_tmp) != pid) { g_set_error (error, DFU_ERROR, DFU_ERROR_INVALID_FILE, "Product ID was already set as " "0x%04x, %s is 0x%04x", pid, values[i], dfu_firmware_get_pid (firmware_tmp)); return FALSE; } if (rel != 0xffff && dfu_firmware_get_release (firmware_tmp) != rel) { g_set_error (error, DFU_ERROR, DFU_ERROR_INVALID_FILE, "Release was already set as " "0x%04x, %s is 0x%04x", rel, values[i], dfu_firmware_get_release (firmware_tmp)); return FALSE; } /* add all images to destination */ images = dfu_firmware_get_images (firmware_tmp); for (j = 0; j < images->len; j++) { DfuImage *image; guint alt_id; /* verify the alt-setting does not already exist */ image = g_ptr_array_index (images, j); alt_id = dfu_image_get_alt_setting (image); g_print ("Adding alternative setting ID of 0x%02x\n", alt_id); if (dfu_firmware_get_image (firmware, alt_id) != NULL) { if (!priv->force) { g_set_error (error, DFU_ERROR, DFU_ERROR_INVALID_FILE, "The alternative setting ID " "of 0x%02x has already been added", alt_id); return FALSE; } g_print ("WARNING: The alternative setting " "ID of 0x%02x has already been added\n", alt_id); } /* add to destination */ dfu_firmware_add_image (firmware, image); } /* save last IDs */ vid = dfu_firmware_get_vid (firmware_tmp); pid = dfu_firmware_get_pid (firmware_tmp); rel = dfu_firmware_get_release (firmware_tmp); } /* print the new object */ str_debug = dfu_firmware_to_string (firmware); g_print ("New merged file:\n%s\n", str_debug); /* write out new file */ file = g_file_new_for_path (values[0]); return dfu_firmware_write_file (firmware, file, priv->cancellable, error); } /** * dfu_tool_convert: **/ static gboolean dfu_tool_convert (DfuToolPrivate *priv, gchar **values, GError **error) { guint64 tmp; guint argc = g_strv_length (values); g_autofree gchar *str_debug = NULL; g_autoptr(DfuFirmware) firmware = NULL; g_autoptr(GFile) file_in = NULL; g_autoptr(GFile) file_out = NULL; /* check args */ if (argc < 3 || argc > 4) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Invalid arguments, expected " "FORMAT FILE-IN FILE-OUT [SIZE]" " -- e.g. `dfu firmware.hex firmware.dfu 8000`"); return FALSE; } /* parse file */ file_in = g_file_new_for_path (values[1]); file_out = g_file_new_for_path (values[2]); firmware = dfu_firmware_new (); if (!dfu_firmware_parse_file (firmware, file_in, DFU_FIRMWARE_PARSE_FLAG_NONE, priv->cancellable, error)) { return FALSE; } /* set output format */ if (g_strcmp0 (values[0], "raw") == 0) { dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_RAW); } else if (g_strcmp0 (values[0], "dfu") == 0) { dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_DFU_1_0); } else if (g_strcmp0 (values[0], "dfuse") == 0) { dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_DFUSE); } else if (g_strcmp0 (values[0], "ihex") == 0) { dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_INTEL_HEX); } else { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "unknown format '%s', expected [raw|dfu|dfuse|ihex]", values[0]); return FALSE; } /* set target size */ if (argc > 3) { DfuImage *image; DfuElement *element; gchar *endptr; tmp = g_ascii_strtoull (values[3], &endptr, 16); if (tmp > 0xffff || endptr[0] != '\0') { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Failed to parse target size '%s'", values[3]); return FALSE; } /* doesn't make sense for DfuSe */ if (dfu_firmware_get_format (firmware) == DFU_FIRMWARE_FORMAT_DFUSE) { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Cannot pad DfuSe image, try DFU"); return FALSE; } /* this has to exist */ if (tmp > 0) { image = dfu_firmware_get_image_default (firmware); g_assert (image != NULL); element = dfu_image_get_element (image, 0); dfu_element_set_target_size (element, tmp); } } /* print the new object */ str_debug = dfu_firmware_to_string (firmware); g_debug ("DFU: %s", str_debug); /* write out new file */ return dfu_firmware_write_file (firmware, file_out, priv->cancellable, error); } /** * dfu_tool_attach: **/ static gboolean dfu_tool_attach (DfuToolPrivate *priv, gchar **values, GError **error) { g_autoptr(DfuDevice) device = NULL; device = dfu_tool_get_defalt_device (priv, error); if (device == NULL) return FALSE; if (!dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE, priv->cancellable, error)) return FALSE; if (!dfu_device_attach (device, error)) return FALSE; return TRUE; } typedef struct { guint marks_total; guint marks_shown; DfuState last_state; } DfuToolProgressHelper; /** * fu_tool_state_changed_cb: **/ static void fu_tool_state_changed_cb (DfuDevice *device, DfuState state, DfuToolProgressHelper *helper) { const gchar *title = NULL; guint i; /* changed state */ if (state == helper->last_state) return; /* state was left hanging... */ if (helper->marks_shown == 0) { switch (helper->last_state) { case DFU_STATE_APP_DETACH: case DFU_STATE_DFU_DNLOAD_IDLE: case DFU_STATE_DFU_MANIFEST_WAIT_RESET: case DFU_STATE_DFU_UPLOAD_IDLE: /* TRANSLATORS: when an action has completed */ g_print ("%s\n", _("OK")); break; default: g_debug ("ignore last state transition %s", dfu_state_to_string (helper->last_state)); break; } } switch (state) { case DFU_STATE_APP_DETACH: /* TRANSLATORS: when moving from runtime to DFU mode */ title = _("Detaching"); break; case DFU_STATE_DFU_MANIFEST_WAIT_RESET: /* TRANSLATORS: when moving from DFU to runtime mode */ title = _("Attaching"); break; case DFU_STATE_DFU_DNLOAD_IDLE: /* TRANSLATORS: when copying from host to device */ title = _("Downloading"); break; case DFU_STATE_DFU_UPLOAD_IDLE: /* TRANSLATORS: when copying from device to host */ title = _("Uploading"); break; default: g_debug ("ignoring %s", dfu_state_to_string (state)); break; } /* show title and then pad */ if (title != NULL) { g_print ("%s ", title); for (i = strlen (title); i < 15; i++) g_print (" "); g_print (": "); } /* reset the progress bar */ switch (state) { case DFU_STATE_APP_DETACH: case DFU_STATE_DFU_DNLOAD_IDLE: case DFU_STATE_DFU_MANIFEST_WAIT_RESET: case DFU_STATE_DFU_UPLOAD_IDLE: g_debug ("resetting progress bar"); helper->marks_shown = 0; break; default: break; } /* ignore if the same */ helper->last_state = state; } /** * fu_tool_percentage_changed_cb: **/ static void fu_tool_percentage_changed_cb (DfuDevice *device, guint percentage, DfuToolProgressHelper *helper) { guint marks_now; guint i; /* add any sections */ marks_now = percentage * helper->marks_total / 100; for (i = helper->marks_shown; i < marks_now; i++) g_print ("#"); helper->marks_shown = marks_now; /* this state done */ if (percentage == 100) g_print ("\n"); } /** * dfu_tool_read_alt: **/ static gboolean dfu_tool_read_alt (DfuToolPrivate *priv, gchar **values, GError **error) { DfuTargetTransferFlags flags = DFU_TARGET_TRANSFER_FLAG_NONE; DfuToolProgressHelper helper; g_autofree gchar *str_debug = NULL; g_autoptr(DfuDevice) device = NULL; g_autoptr(DfuFirmware) firmware = NULL; g_autoptr(DfuImage) image = NULL; g_autoptr(DfuTarget) target = NULL; g_autoptr(GFile) file = NULL; /* check args */ if (g_strv_length (values) < 2) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Invalid arguments, expected " "FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID"); return FALSE; } /* open correct device */ device = dfu_tool_get_defalt_device (priv, error); if (device == NULL) return FALSE; if (priv->transfer_size > 0) dfu_device_set_transfer_size (device, priv->transfer_size); if (!dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE, priv->cancellable, error)) return FALSE; /* set up progress */ helper.last_state = DFU_STATE_DFU_ERROR; helper.marks_total = 30; helper.marks_shown = 0; g_signal_connect (device, "state-changed", G_CALLBACK (fu_tool_state_changed_cb), &helper); g_signal_connect (device, "percentage-changed", G_CALLBACK (fu_tool_percentage_changed_cb), &helper); /* APP -> DFU */ if (dfu_device_get_mode (device) == DFU_MODE_RUNTIME) { g_debug ("detaching"); if (!dfu_device_detach (device, priv->cancellable, error)) return FALSE; if (!dfu_device_wait_for_replug (device, DFU_DEVICE_REPLUG_TIMEOUT, priv->cancellable, error)) return FALSE; /* put back in same state */ flags |= DFU_TARGET_TRANSFER_FLAG_ATTACH; flags |= DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME; } /* transfer */ target = dfu_device_get_target_by_alt_name (device, values[1], NULL); if (target == NULL) { gchar *endptr; guint64 tmp = g_ascii_strtoull (values[1], &endptr, 10); if (tmp > 0xff || endptr[0] != '\0') { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Failed to parse alt-setting '%s'", values[1]); return FALSE; } target = dfu_device_get_target_by_alt_setting (device, tmp, error); if (target == NULL) return FALSE; } /* do transfer */ image = dfu_target_upload (target, flags, priv->cancellable, error); if (image == NULL) return FALSE; /* create new firmware object */ firmware = dfu_firmware_new (); dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_DFU_1_0); dfu_firmware_set_vid (firmware, dfu_device_get_runtime_vid (device)); dfu_firmware_set_pid (firmware, dfu_device_get_runtime_pid (device)); dfu_firmware_add_image (firmware, image); /* save file */ file = g_file_new_for_path (values[0]); if (!dfu_firmware_write_file (firmware, file, priv->cancellable, error)) return FALSE; /* print the new object */ str_debug = dfu_firmware_to_string (firmware); g_debug ("DFU: %s", str_debug); /* success */ g_print ("%u bytes successfully uploaded from device\n", dfu_image_get_size (image)); return TRUE; } /** * dfu_tool_read: **/ static gboolean dfu_tool_read (DfuToolPrivate *priv, gchar **values, GError **error) { DfuTargetTransferFlags flags = DFU_TARGET_TRANSFER_FLAG_NONE; DfuToolProgressHelper helper; g_autofree gchar *str_debug = NULL; g_autoptr(DfuDevice) device = NULL; g_autoptr(DfuFirmware) firmware = NULL; g_autoptr(DfuImage) image = NULL; g_autoptr(GFile) file = NULL; /* check args */ if (g_strv_length (values) < 1) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Invalid arguments, expected FILENAME"); return FALSE; } /* open correct device */ device = dfu_tool_get_defalt_device (priv, error); if (device == NULL) return FALSE; if (!dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE, priv->cancellable, error)) return FALSE; /* optional reset */ if (dfu_device_get_mode (device) == DFU_MODE_RUNTIME) { flags |= DFU_TARGET_TRANSFER_FLAG_DETACH; flags |= DFU_TARGET_TRANSFER_FLAG_ATTACH; flags |= DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME; } /* transfer */ helper.last_state = DFU_STATE_DFU_ERROR; helper.marks_total = 30; helper.marks_shown = 0; g_signal_connect (device, "state-changed", G_CALLBACK (fu_tool_state_changed_cb), &helper); g_signal_connect (device, "percentage-changed", G_CALLBACK (fu_tool_percentage_changed_cb), &helper); firmware = dfu_device_upload (device, flags, priv->cancellable, error); if (firmware == NULL) return FALSE; /* save file */ file = g_file_new_for_path (values[0]); if (!dfu_firmware_write_file (firmware, file, priv->cancellable, error)) return FALSE; /* print the new object */ str_debug = dfu_firmware_to_string (firmware); g_debug ("DFU: %s", str_debug); /* success */ g_print ("%u bytes successfully uploaded from device\n", dfu_firmware_get_size (firmware)); return TRUE; } /** * dfu_tool_get_device_string: **/ static gchar * dfu_tool_get_device_string (DfuToolPrivate *priv, DfuDevice *device) { gchar *dstr; GUsbDevice *dev; g_autoptr(GError) error = NULL; /* open, and get status */ dev = dfu_device_get_usb_dev (device); if (dev == NULL) { return g_strdup_printf ("%04x:%04x [%s]", dfu_device_get_runtime_vid (device), dfu_device_get_runtime_pid (device), "removed"); } if (!dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE, priv->cancellable, &error)) { return g_strdup_printf ("%04x:%04x [%s]", g_usb_device_get_vid (dev), g_usb_device_get_pid (dev), error->message); } dstr = g_strdup_printf ("%04x:%04x [%s:%s]", g_usb_device_get_vid (dev), g_usb_device_get_pid (dev), dfu_state_to_string (dfu_device_get_state (device)), dfu_status_to_string (dfu_device_get_status (device))); dfu_device_close (device, NULL); return dstr; } /** * dfu_tool_device_added_cb: **/ static void dfu_tool_device_added_cb (DfuContext *context, DfuDevice *device, gpointer user_data) { DfuToolPrivate *priv = (DfuToolPrivate *) user_data; g_autofree gchar *tmp; tmp = dfu_tool_get_device_string (priv, device); /* TRANSLATORS: this is when a device is hotplugged */ dfu_tool_print_indent (_("Added"), tmp, 0); } /** * dfu_tool_device_removed_cb: **/ static void dfu_tool_device_removed_cb (DfuContext *context, DfuDevice *device, gpointer user_data) { DfuToolPrivate *priv = (DfuToolPrivate *) user_data; g_autofree gchar *tmp; tmp = dfu_tool_get_device_string (priv, device); /* TRANSLATORS: this is when a device is hotplugged */ dfu_tool_print_indent (_("Removed"), tmp, 0); } /** * dfu_tool_device_changed_cb: **/ static void dfu_tool_device_changed_cb (DfuContext *context, DfuDevice *device, gpointer user_data) { DfuToolPrivate *priv = (DfuToolPrivate *) user_data; g_autofree gchar *tmp; tmp = dfu_tool_get_device_string (priv, device); /* TRANSLATORS: this is when a device is hotplugged */ dfu_tool_print_indent (_("Changed"), tmp, 0); } /** * dfu_tool_watch_cancelled_cb: **/ static void dfu_tool_watch_cancelled_cb (GCancellable *cancellable, gpointer user_data) { GMainLoop *loop = (GMainLoop *) user_data; /* TRANSLATORS: this is when a device ctrl+c's a watch */ g_print ("%s\n", _("Cancelled")); g_main_loop_quit (loop); } /** * dfu_tool_parse_xtea_key: **/ static gboolean dfu_tool_parse_xtea_key (const gchar *key, guint32 *keys, GError **error) { guint i; guint key_len; g_autofree gchar *key_pad = NULL; /* too long */ key_len = strlen (key); if (key_len > 32) { g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "Key string too long at %i chars, max 16", key_len); return FALSE; } /* parse 4x32b values or generate a hash */ if (key_len == 32) { for (i = 0; i < 4; i++) { gchar buf[] = "xxxxxxxx"; gchar *endptr; guint64 tmp; /* copy to 4-char buf (with NUL) */ memcpy (buf, key + i*8, 8); tmp = g_ascii_strtoull (buf, &endptr, 16); if (endptr && endptr[0] != '\0') { g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "Failed to parse key '%s'", key); return FALSE; } keys[3-i] = tmp; } } else { gsize buf_len = 16; g_autoptr(GChecksum) csum = NULL; csum = g_checksum_new (G_CHECKSUM_MD5); g_checksum_update (csum, (const guchar *) key, key_len); g_checksum_get_digest (csum, (guint8 *) keys, &buf_len); g_assert (buf_len == 16); } /* success */ g_debug ("using XTEA key %04x%04x%04x%04x", keys[3], keys[2], keys[1], keys[0]); return TRUE; } /** * dfu_tool_get_firmware_contents_default: **/ static guint8 * dfu_tool_get_firmware_contents_default (DfuFirmware *firmware, gsize *length, GError **error) { DfuElement *element; DfuImage *image; GBytes *contents; image = dfu_firmware_get_image_default (firmware); if (image == NULL) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "No default image"); return NULL; } element = dfu_image_get_element (image, 0); if (element == NULL) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "No default element"); return NULL; } contents = dfu_element_get_contents (element); if (contents == NULL) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "No image contents"); return NULL; } return (guint8 *) g_bytes_get_data (contents, length); } #define XTEA_DELTA 0x9e3779b9 #define XTEA_NUM_ROUNDS 32 /** * dfu_tool_encrypt_xtea: **/ static void dfu_tool_encrypt_xtea (const guint32 key[4], guint8 *data, guint16 length) { guint32 sum; guint32 *tmp = (guint32 *) data; guint32 v0; guint32 v1; guint8 i; guint j; for (j = 0; j < length / 4; j += 2) { sum = 0; v0 = tmp[j]; v1 = tmp[j+1]; for (i = 0; i < XTEA_NUM_ROUNDS; i++) { v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]); sum += XTEA_DELTA; v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]); } tmp[j] = v0; tmp[j+1] = v1; } } /** * dfu_tool_decrypt_xtea: **/ static void dfu_tool_decrypt_xtea (const guint32 key[4], guint8 *data, guint16 length) { guint32 sum; guint32 *tmp = (guint32 *) data; guint32 v0; guint32 v1; guint8 i; guint j; for (j = 0; j < length / 4; j += 2) { v0 = tmp[j]; v1 = tmp[j+1]; sum = XTEA_DELTA * XTEA_NUM_ROUNDS; for (i = 0; i < XTEA_NUM_ROUNDS; i++) { v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]); sum -= XTEA_DELTA; v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]); } tmp[j] = v0; tmp[j+1] = v1; } } /** * dfu_tool_encrypt: **/ static gboolean dfu_tool_encrypt (DfuToolPrivate *priv, gchar **values, GError **error) { gsize len; guint8 *data; g_autoptr(DfuFirmware) firmware = NULL; g_autoptr(GFile) file_in = NULL; g_autoptr(GFile) file_out = NULL; /* check args */ if (g_strv_length (values) < 4) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Invalid arguments, expected " "FILENAME-IN FILENAME-OUT TYPE KEY" " -- e.g. firmware.dfu firmware.xdfu xtea deadbeef"); return FALSE; } /* check extensions */ if (!priv->force) { if (!g_str_has_suffix (values[0], ".dfu")) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "Invalid filename, expected *.dfu"); return FALSE; } if (!g_str_has_suffix (values[1], ".xdfu")) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "Invalid filename, expected *.xdfu"); return FALSE; } } /* open */ file_in = g_file_new_for_path (values[0]); firmware = dfu_firmware_new (); if (!dfu_firmware_parse_file (firmware, file_in, DFU_FIRMWARE_PARSE_FLAG_NONE, priv->cancellable, error)) { return FALSE; } /* get data */ data = dfu_tool_get_firmware_contents_default (firmware, &len, error); if (data == NULL) return FALSE; /* check type */ if (g_strcmp0 (values[2], "xtea") == 0) { guint32 key[4]; if (!dfu_tool_parse_xtea_key (values[3], key, error)) return FALSE; dfu_tool_encrypt_xtea (key, data, len); dfu_firmware_set_metadata (firmware, DFU_METADATA_KEY_CIPHER_KIND, "XTEA"); } else { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "unknown type '%s', expected [xtea]", values[2]); return FALSE; } /* write out new file */ file_out = g_file_new_for_path (values[1]); g_debug ("wrote %s", values[1]); return dfu_firmware_write_file (firmware, file_out, priv->cancellable, error); } /** * dfu_tool_decrypt: **/ static gboolean dfu_tool_decrypt (DfuToolPrivate *priv, gchar **values, GError **error) { gsize len; guint8 *data; g_autoptr(DfuFirmware) firmware = NULL; g_autoptr(GFile) file_in = NULL; g_autoptr(GFile) file_out = NULL; /* check args */ if (g_strv_length (values) < 4) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Invalid arguments, expected " "FILENAME-IN FILENAME-OUT TYPE KEY" " -- e.g. firmware.xdfu firmware.dfu xtea deadbeef"); return FALSE; } /* check extensions */ if (!priv->force) { if (!g_str_has_suffix (values[0], ".xdfu")) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "Invalid filename, expected *.xdfu"); return FALSE; } if (!g_str_has_suffix (values[1], ".dfu")) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "Invalid filename, expected *.dfu"); return FALSE; } } /* open */ file_in = g_file_new_for_path (values[0]); firmware = dfu_firmware_new (); if (!dfu_firmware_parse_file (firmware, file_in, DFU_FIRMWARE_PARSE_FLAG_NONE, priv->cancellable, error)) { return FALSE; } /* get data */ data = dfu_tool_get_firmware_contents_default (firmware, &len, error); if (data == NULL) return FALSE; /* check type */ if (g_strcmp0 (values[2], "xtea") == 0) { guint32 key[4]; if (!dfu_tool_parse_xtea_key (values[3], key, error)) return FALSE; dfu_tool_decrypt_xtea (key, data, len); dfu_firmware_remove_metadata (firmware, DFU_METADATA_KEY_CIPHER_KIND); } else { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "unknown type '%s', expected [xtea]", values[2]); return FALSE; } /* write out new file */ file_out = g_file_new_for_path (values[1]); g_debug ("wrote %s", values[1]); return dfu_firmware_write_file (firmware, file_out, priv->cancellable, error); } /** * dfu_tool_watch: **/ static gboolean dfu_tool_watch (DfuToolPrivate *priv, gchar **values, GError **error) { guint i; DfuDevice *device; g_autoptr(DfuContext) dfu_context = NULL; g_autoptr(GMainLoop) loop = NULL; g_autoptr(GPtrArray) devices = NULL; /* get all the DFU devices */ dfu_context = dfu_context_new (); dfu_context_enumerate (dfu_context, NULL); /* print what's already attached */ devices = dfu_context_get_devices (dfu_context); for (i = 0; i < devices->len; i++) { device = g_ptr_array_index (devices, i); dfu_tool_device_added_cb (dfu_context, device, priv); } /* watch for any hotplugged device */ loop = g_main_loop_new (NULL, FALSE); g_signal_connect (dfu_context, "device-added", G_CALLBACK (dfu_tool_device_added_cb), priv); g_signal_connect (dfu_context, "device-removed", G_CALLBACK (dfu_tool_device_removed_cb), priv); g_signal_connect (dfu_context, "device-changed", G_CALLBACK (dfu_tool_device_changed_cb), priv); g_signal_connect (priv->cancellable, "cancelled", G_CALLBACK (dfu_tool_watch_cancelled_cb), loop); g_main_loop_run (loop); return TRUE; } /** * dfu_tool_dump: **/ static gboolean dfu_tool_dump (DfuToolPrivate *priv, gchar **values, GError **error) { DfuFirmwareParseFlags flags = DFU_FIRMWARE_PARSE_FLAG_NONE; guint i; /* check args */ if (g_strv_length (values) < 1) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Invalid arguments, expected FILENAME"); return FALSE; } /* dump corrupt files */ if (priv->force) { flags |= DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST; flags |= DFU_FIRMWARE_PARSE_FLAG_NO_VERSION_TEST; } /* open files */ for (i = 0; values[i] != NULL; i++) { g_autoptr(DfuFirmware) firmware = NULL; g_autoptr(GFile) file = NULL; g_autoptr(GError) error_local = NULL; /* dump to screen */ g_print ("Loading %s:\n", values[i]); firmware = dfu_firmware_new (); file = g_file_new_for_path (values[i]); if (!dfu_firmware_parse_file (firmware, file, flags, priv->cancellable, &error_local)) { g_print ("Failed to load firmware: %s\n", error_local->message); continue; } g_print ("%s\n", dfu_firmware_to_string (firmware)); } return TRUE; } /** * dfu_tool_write_alt: **/ static gboolean dfu_tool_write_alt (DfuToolPrivate *priv, gchar **values, GError **error) { DfuImage *image; DfuTargetTransferFlags flags = DFU_TARGET_TRANSFER_FLAG_VERIFY; DfuToolProgressHelper helper; g_autofree gchar *str_debug = NULL; g_autoptr(DfuDevice) device = NULL; g_autoptr(DfuFirmware) firmware = NULL; g_autoptr(DfuTarget) target = NULL; g_autoptr(GFile) file = NULL; /* check args */ if (g_strv_length (values) < 2) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Invalid arguments, expected " "FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID " "[IMAGE-ALT-NAME|IMAGE-ALT-ID]"); return FALSE; } /* open file */ firmware = dfu_firmware_new (); file = g_file_new_for_path (values[0]); if (!dfu_firmware_parse_file (firmware, file, DFU_FIRMWARE_PARSE_FLAG_NONE, priv->cancellable, error)) return FALSE; /* open correct device */ device = dfu_tool_get_defalt_device (priv, error); if (device == NULL) return FALSE; if (priv->transfer_size > 0) dfu_device_set_transfer_size (device, priv->transfer_size); if (!dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE, priv->cancellable, error)) return FALSE; /* set up progress */ helper.last_state = DFU_STATE_DFU_ERROR; helper.marks_total = 30; helper.marks_shown = 0; g_signal_connect (device, "state-changed", G_CALLBACK (fu_tool_state_changed_cb), &helper); g_signal_connect (device, "percentage-changed", G_CALLBACK (fu_tool_percentage_changed_cb), &helper); /* APP -> DFU */ if (dfu_device_get_mode (device) == DFU_MODE_RUNTIME) { g_debug ("detaching"); if (!dfu_device_detach (device, priv->cancellable, error)) return FALSE; if (!dfu_device_wait_for_replug (device, 5000, priv->cancellable, error)) return FALSE; /* put back in same state */ flags |= DFU_TARGET_TRANSFER_FLAG_ATTACH; flags |= DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME; } /* print the new object */ str_debug = dfu_firmware_to_string (firmware); g_debug ("DFU: %s", str_debug); /* get correct target on device */ target = dfu_device_get_target_by_alt_name (device, values[1], NULL); if (target == NULL) { gchar *endptr; guint64 tmp = g_ascii_strtoull (values[1], &endptr, 10); if (tmp > 0xff || endptr[0] != '\0') { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Failed to parse alt-setting '%s'", values[1]); return FALSE; } target = dfu_device_get_target_by_alt_setting (device, tmp, error); if (target == NULL) return FALSE; } /* allow overriding the firmware alt-setting */ if (g_strv_length (values) > 2) { image = dfu_firmware_get_image_by_name (firmware, values[2]); if (image == NULL) { gchar *endptr; guint64 tmp = g_ascii_strtoull (values[2], &endptr, 10); if (tmp > 0xff || endptr[0] != '\0') { g_set_error (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Failed to parse image alt-setting '%s'", values[2]); return FALSE; } image = dfu_firmware_get_image (firmware, tmp); if (image == NULL) { g_set_error (error, DFU_ERROR, DFU_ERROR_INVALID_FILE, "could not locate image in firmware for %02x", (guint) tmp); return FALSE; } } } else { g_print ("WARNING: Using default firmware image\n"); image = dfu_firmware_get_image_default (firmware); if (image == NULL) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INVALID_FILE, "no default image"); return FALSE; } } /* allow forcing firmware kinds */ if (priv->force) { flags |= DFU_TARGET_TRANSFER_FLAG_ANY_CIPHER; } /* transfer */ if (!dfu_target_download (target, image, flags, priv->cancellable, error)) return FALSE; /* success */ g_print ("%u bytes successfully downloaded to device\n", dfu_image_get_size (image)); return TRUE; } /** * dfu_tool_write: **/ static gboolean dfu_tool_write (DfuToolPrivate *priv, gchar **values, GError **error) { DfuTargetTransferFlags flags = DFU_TARGET_TRANSFER_FLAG_VERIFY; DfuToolProgressHelper helper; g_autofree gchar *str_debug = NULL; g_autoptr(DfuDevice) device = NULL; g_autoptr(DfuFirmware) firmware = NULL; g_autoptr(GFile) file = NULL; /* check args */ if (g_strv_length (values) < 1) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INTERNAL, "Invalid arguments, expected FILENAME"); return FALSE; } /* open file */ firmware = dfu_firmware_new (); file = g_file_new_for_path (values[0]); if (!dfu_firmware_parse_file (firmware, file, DFU_FIRMWARE_PARSE_FLAG_NONE, priv->cancellable, error)) return FALSE; /* open correct device */ device = dfu_tool_get_defalt_device (priv, error); if (device == NULL) return FALSE; if (!dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE, priv->cancellable, error)) return FALSE; /* print the new object */ str_debug = dfu_firmware_to_string (firmware); g_debug ("DFU: %s", str_debug); /* put in correct mode */ if (dfu_device_get_mode (device) == DFU_MODE_RUNTIME) { flags |= DFU_TARGET_TRANSFER_FLAG_DETACH; flags |= DFU_TARGET_TRANSFER_FLAG_ATTACH; flags |= DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME; } /* allow wildcards */ if (priv->force) { flags |= DFU_TARGET_TRANSFER_FLAG_WILDCARD_VID; flags |= DFU_TARGET_TRANSFER_FLAG_WILDCARD_PID; flags |= DFU_TARGET_TRANSFER_FLAG_ANY_CIPHER; } /* transfer */ helper.last_state = DFU_STATE_DFU_ERROR; helper.marks_total = 30; helper.marks_shown = 0; g_signal_connect (device, "state-changed", G_CALLBACK (fu_tool_state_changed_cb), &helper); g_signal_connect (device, "percentage-changed", G_CALLBACK (fu_tool_percentage_changed_cb), &helper); if (!dfu_device_download (device, firmware, flags, priv->cancellable, error)) return FALSE; /* success */ g_print ("%u bytes successfully downloaded to device\n", dfu_firmware_get_size (firmware)); return TRUE; } /** * dfu_tool_list_target: **/ static void dfu_tool_list_target (DfuTarget *target) { DfuCipherKind cipher_kind; GPtrArray *sectors; const gchar *tmp; guint i; g_autofree gchar *alt_id = NULL; g_autoptr(GError) error_local = NULL; /* TRANSLATORS: the identifier name please */ alt_id = g_strdup_printf ("%i", dfu_target_get_alt_setting (target)); dfu_tool_print_indent (_("ID"), alt_id, 1); /* this is optional */ tmp = dfu_target_get_alt_name (target, NULL); if (tmp != NULL) { /* TRANSLATORS: interface name, e.g. "Flash" */ dfu_tool_print_indent (_("Name"), tmp, 2); } cipher_kind = dfu_target_get_cipher_kind (target); /* TRANSLATORS: this is the encryption method used when writing */ dfu_tool_print_indent (_("Cipher"), dfu_cipher_kind_to_string (cipher_kind), 2); /* print sector information */ sectors = dfu_target_get_sectors (target); for (i = 0; i < sectors->len; i++) { DfuSector *sector; g_autofree gchar *msg = NULL; g_autofree gchar *title = NULL; sector = g_ptr_array_index (sectors, i); msg = dfu_sector_to_string (sector); /* TRANSLATORS: these are areas of memory on the chip */ title = g_strdup_printf ("%s 0x%02x", _("Region"), i); dfu_tool_print_indent (title, msg, 2); } } /** * dfu_tool_list: **/ static gboolean dfu_tool_list (DfuToolPrivate *priv, gchar **values, GError **error) { guint i; g_autoptr(DfuContext) dfu_context = NULL; g_autoptr(GPtrArray) devices = NULL; /* get all the connected USB devices */ dfu_context = dfu_context_new (); dfu_context_enumerate (dfu_context, NULL); devices = dfu_context_get_devices (dfu_context); for (i = 0; i < devices->len; i++) { DfuDevice *device = NULL; DfuTarget *target; GUsbDevice *dev; GPtrArray *dfu_targets; const gchar *tmp; guint j; g_autofree gchar *quirks = NULL; g_autofree gchar *version = NULL; g_autoptr(GError) error_local = NULL; /* device specific */ device = g_ptr_array_index (devices, i); dev = dfu_device_get_usb_dev (device); version = as_utils_version_from_uint16 (g_usb_device_get_release (dev), AS_VERSION_PARSE_FLAG_NONE); g_print ("%s %04x:%04x [v%s]:\n", /* TRANSLATORS: detected a DFU device */ _("Found"), g_usb_device_get_vid (dev), g_usb_device_get_pid (dev), version); /* open */ if (!dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE, priv->cancellable, &error_local)) { if (g_error_matches (error_local, DFU_ERROR, DFU_ERROR_PERMISSION_DENIED)) { /* TRANSLATORS: probably not run as root... */ dfu_tool_print_indent (_("Status"), _("Unknown: permission denied"), 2); } else { /* TRANSLATORS: device has failed to report status */ dfu_tool_print_indent (_("Status"), error_local->message, 2); } continue; } tmp = dfu_mode_to_string (dfu_device_get_mode (device)); /* TRANSLATORS: device mode, e.g. runtime or DFU */ dfu_tool_print_indent (_("Mode"), tmp, 1); tmp = dfu_status_to_string (dfu_device_get_status (device)); /* TRANSLATORS: device status, e.g. "OK" */ dfu_tool_print_indent (_("Status"), tmp, 1); tmp = dfu_state_to_string (dfu_device_get_state (device)); /* TRANSLATORS: device state, i.e. appIDLE */ dfu_tool_print_indent (_("State"), tmp, 1); /* quirks are NULL if none are set */ quirks = dfu_device_get_quirks_as_string (device); if (quirks != NULL) { /* TRANSLATORS: device quirks, i.e. things that * it does that we have to work around */ dfu_tool_print_indent (_("Quirks"), quirks, 1); } /* list targets */ dfu_targets = dfu_device_get_targets (device); for (j = 0; j < dfu_targets->len; j++) { target = g_ptr_array_index (dfu_targets, j); dfu_tool_list_target (target); } } return TRUE; } /** * dfu_tool_detach: **/ static gboolean dfu_tool_detach (DfuToolPrivate *priv, gchar **values, GError **error) { g_autoptr(DfuDevice) device = NULL; /* open correct device */ device = dfu_tool_get_defalt_device (priv, error); if (device == NULL) return FALSE; if (priv->transfer_size > 0) dfu_device_set_transfer_size (device, priv->transfer_size); /* detatch */ if (!dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE, priv->cancellable, error)) return FALSE; if (!dfu_device_detach (device, priv->cancellable, error)) return FALSE; return TRUE; } /** * dfu_tool_sigint_cb: **/ static gboolean dfu_tool_sigint_cb (gpointer user_data) { DfuToolPrivate *priv = (DfuToolPrivate *) user_data; g_debug ("Handling SIGINT"); g_cancellable_cancel (priv->cancellable); return FALSE; } /** * main: **/ int main (int argc, char *argv[]) { gboolean ret; gboolean verbose = FALSE; gboolean version = FALSE; g_autofree gchar *cmd_descriptions = NULL; g_autoptr(DfuToolPrivate) priv = g_new0 (DfuToolPrivate, 1); g_autoptr(GError) error = NULL; g_autoptr(GOptionContext) context = NULL; const GOptionEntry options[] = { { "version", '\0', 0, G_OPTION_ARG_NONE, &version, "Print the version number", NULL }, { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Print verbose debug statements", NULL }, { "device", 'd', 0, G_OPTION_ARG_STRING, &priv->device_vid_pid, "Specify Vendor/Product ID(s) of DFU device", "VID:PID" }, { "transfer-size", 't', 0, G_OPTION_ARG_STRING, &priv->transfer_size, "Specify the number of bytes per USB transfer", "BYTES" }, { "force", '\0', 0, G_OPTION_ARG_NONE, &priv->force, "Force the action ignoring all warnings", NULL }, { NULL} }; setlocale (LC_ALL, ""); bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); /* add commands */ priv->cmd_array = g_ptr_array_new_with_free_func ((GDestroyNotify) dfu_tool_item_free); dfu_tool_add (priv->cmd_array, "convert", NULL, /* TRANSLATORS: command description */ _("Convert firmware to DFU format"), dfu_tool_convert); dfu_tool_add (priv->cmd_array, "merge", NULL, /* TRANSLATORS: command description */ _("Merge multiple firmware files into one"), dfu_tool_merge); dfu_tool_add (priv->cmd_array, "set-vendor", NULL, /* TRANSLATORS: command description */ _("Set vendor ID on firmware file"), dfu_tool_set_vendor); dfu_tool_add (priv->cmd_array, "set-product", NULL, /* TRANSLATORS: command description */ _("Set product ID on firmware file"), dfu_tool_set_product); dfu_tool_add (priv->cmd_array, "set-release", NULL, /* TRANSLATORS: command description */ _("Set release version on firmware file"), dfu_tool_set_release); dfu_tool_add (priv->cmd_array, "set-alt-setting", NULL, /* TRANSLATORS: command description */ _("Set alternative number on firmware file"), dfu_tool_set_alt_setting); dfu_tool_add (priv->cmd_array, "set-alt-setting-name", NULL, /* TRANSLATORS: command description */ _("Set alternative name on firmware file"), dfu_tool_set_alt_setting_name); dfu_tool_add (priv->cmd_array, "attach", NULL, /* TRANSLATORS: command description */ _("Attach DFU capable device back to runtime"), dfu_tool_attach); dfu_tool_add (priv->cmd_array, "read", NULL, /* TRANSLATORS: command description */ _("Read firmware from device into a file"), dfu_tool_read); dfu_tool_add (priv->cmd_array, "read-alt", NULL, /* TRANSLATORS: command description */ _("Read firmware from one partition into a file"), dfu_tool_read_alt); dfu_tool_add (priv->cmd_array, "write", NULL, /* TRANSLATORS: command description */ _("Write firmware from file into device"), dfu_tool_write); dfu_tool_add (priv->cmd_array, "write-alt", NULL, /* TRANSLATORS: command description */ _("Write firmware from file into one partition"), dfu_tool_write_alt); dfu_tool_add (priv->cmd_array, "list", NULL, /* TRANSLATORS: command description */ _("List currently attached DFU capable devices"), dfu_tool_list); dfu_tool_add (priv->cmd_array, "detach", NULL, /* TRANSLATORS: command description */ _("Detach currently attached DFU capable device"), dfu_tool_detach); dfu_tool_add (priv->cmd_array, "dump", NULL, /* TRANSLATORS: command description */ _("Dump details about a firmware file"), dfu_tool_dump); dfu_tool_add (priv->cmd_array, "watch", NULL, /* TRANSLATORS: command description */ _("Watch DFU devices being hotplugged"), dfu_tool_watch); dfu_tool_add (priv->cmd_array, "encrypt", NULL, /* TRANSLATORS: command description */ _("Encrypt firmware data"), dfu_tool_encrypt); dfu_tool_add (priv->cmd_array, "decrypt", NULL, /* TRANSLATORS: command description */ _("Decrypt firmware data"), dfu_tool_decrypt); dfu_tool_add (priv->cmd_array, "set-metadata", NULL, /* TRANSLATORS: command description */ _("Sets metadata on a firmware file"), dfu_tool_set_metadata); /* do stuff on ctrl+c */ priv->cancellable = g_cancellable_new (); g_unix_signal_add_full (G_PRIORITY_DEFAULT, SIGINT, dfu_tool_sigint_cb, priv, NULL); /* sort by command name */ g_ptr_array_sort (priv->cmd_array, (GCompareFunc) dfu_tool_sort_command_name_cb); /* get a list of the commands */ context = g_option_context_new (NULL); cmd_descriptions = dfu_tool_get_descriptions (priv->cmd_array); g_option_context_set_summary (context, cmd_descriptions); /* TRANSLATORS: DFU stands for device firmware update */ g_set_application_name (_("DFU Utility")); g_option_context_add_main_entries (context, options, NULL); ret = g_option_context_parse (context, &argc, &argv, &error); if (!ret) { /* TRANSLATORS: the user didn't read the man page */ g_print ("%s: %s\n", _("Failed to parse arguments"), error->message); return EXIT_FAILURE; } /* set verbose? */ if (verbose) g_setenv ("G_MESSAGES_DEBUG", "all", FALSE); /* version */ if (version) { g_print ("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION); return EXIT_SUCCESS; } /* run the specified command */ ret = dfu_tool_run (priv, argv[1], (gchar**) &argv[2], &error); if (!ret) { if (g_error_matches (error, DFU_ERROR, DFU_ERROR_INTERNAL)) { g_autofree gchar *tmp = NULL; tmp = g_option_context_get_help (context, TRUE, NULL); g_print ("%s\n\n%s", error->message, tmp); } else { g_print ("%s\n", error->message); } return EXIT_FAILURE; } /* success/ */ return EXIT_SUCCESS; } fwupd-0.7.0/libdfu/dfu.h000066400000000000000000000026441267747510300150610ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * SECTION:dfu * @short_description: Helper objects for interacting with DFU devices. */ #ifndef __DFU_H__ #define __DFU_H__ #define __DFU_H_INSIDE__ #include #include #include #include #include #include #include #include #include #undef __DFU_H_INSIDE__ #endif /* __DFU_H__ */ fwupd-0.7.0/libdfu/dfu.pc.in000066400000000000000000000004261267747510300156350ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: dfu Description: libdfu is a library for reading and writing USB device firmware Version: @VERSION@ Requires: glib-2.0, gobject-2.0, gio-2.0 Libs: -L${libdir} -ldfu Cflags: -I${includedir} fwupd-0.7.0/libdfu/examples/000077500000000000000000000000001267747510300157425ustar00rootroot00000000000000fwupd-0.7.0/libdfu/examples/upload.py000077500000000000000000000012341267747510300176030ustar00rootroot00000000000000#!/usr/bin/python # Copyright (C) 2015 Richard Hughes # Licensed under the GNU General Public License Version 2 import gi gi.require_version('Dfu', '1.0') from gi.repository import Dfu from gi.repository import Gio cancellable = Gio.Cancellable.new() ctx = Dfu.Context.new() ctx.enumerate() for dev in ctx.get_devices(): # print details about the device dev.open(Dfu.DeviceOpenFlags.NONE, cancellable) print "getting firmware from %s:%s" % (dev.get_state(), dev.get_status()) # transfer firmware from device to host and show summary fw = dev.upload(Dfu.TargetTransferFlags.DETACH, cancellable) print fw.to_string() fwupd-0.7.0/libdfu/fuzzing.md000066400000000000000000000001641267747510300161430ustar00rootroot00000000000000CC=afl-gcc ./configure --disable-shared AFL_HARDEN=1 make afl-fuzz -m 300 -i fuzzing -o findings ./dfu-tool dump @@ fwupd-0.7.0/libdfu/fuzzing/000077500000000000000000000000001267747510300156205ustar00rootroot00000000000000fwupd-0.7.0/libdfu/fuzzing/example.dfu000066400000000000000000000000341267747510300177500ustar00rootroot00000000000000hello world ÿÿÿÿÿÿUFDfêd-fwupd-0.7.0/libdfu/fuzzing/example.dfuse000066400000000000000000000005011267747510300202770ustar00rootroot00000000000000DfuSe1TargetST hello world ÿÿÿÿÿÿUFDæw„~fwupd-0.7.0/libdfu/fuzzing/firmware.hex000066400000000000000000000006001267747510300201360ustar00rootroot00000000000000:044000003DEF20F080 :10400800FACF01F0FBCF02F0E9CF03F0EACF04F0DA :10401800E1CF05F0E2CF06F0D9CF07F0DACF08F00C :10402800F3CF09F0F4CF0AF0F6CF0BF0F7CF0CF08E :10403800F8CF0DF0F5CF0EF00EC0F5FF0DC0F8FF6C :104048000CC0F7FF0BC0F6FF0AC0F4FF09C0F3FF6E :1040580008C0DAFF07C0D9FF06C0E2FF05C0E1FFCC :1040680004C0EAFF03C0E9FF02C0FBFF01C0FAFF7A :1040780011003FEF20F0000142EF20F03DEF20F06B :00000001FF fwupd-0.7.0/libdfu/fuzzing/metadata-multiple.dfu000066400000000000000000000001151267747510300217260ustar00rootroot00000000000000amaliaMDkeyvalue CopyrightRichard HughesLicenseGPL-2.0+ÿÿÿÿÿÿUFDGZ+Ø@fwupd-0.7.0/libdfu/fuzzing/metadata.dfu000066400000000000000000000000431267747510300200750ustar00rootroot00000000000000amaliaMDkeyvalueÿÿÿÿÿÿUFDXÄÞfwupd-0.7.0/libfwupd/000077500000000000000000000000001267747510300144735ustar00rootroot00000000000000fwupd-0.7.0/libfwupd/Makefile.am000066400000000000000000000051021267747510300165250ustar00rootroot00000000000000if HAVE_INTROSPECTION -include $(INTROSPECTION_MAKEFILE) INTROSPECTION_GIRS = INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir) INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir) endif AM_CPPFLAGS = \ $(GLIB_CFLAGS) \ $(PIE_CFLAGS) \ -I$(top_srcdir) \ -I$(top_srcdir)/libfwupd \ -DFWUPD_COMPILATION \ -DG_LOG_DOMAIN=\"libfwupd\" \ -DLIBEXECDIR=\""$(libexecdir)"\" \ -DPACKAGE_DATA_DIR=\""$(datadir)"\" lib_LTLIBRARIES = \ libfwupd.la libfwupd_includedir = $(includedir)/fwupd-1 libfwupd_include_HEADERS = \ fwupd.h libfwupdbase_includedir = $(libfwupd_includedir)/libfwupd libfwupdbase_include_HEADERS = \ fwupd-client.h \ fwupd-enums.h \ fwupd-error.h \ fwupd-result.h \ fwupd-version.h libfwupd_la_SOURCES = \ fwupd-client.c \ fwupd-enums.c \ fwupd-enums-private.h \ fwupd-error.c \ fwupd-result.c libfwupd_la_LIBADD = \ $(GLIB_LIBS) libfwupd_la_LDFLAGS = \ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \ -export-dynamic \ -no-undefined \ -export-symbols-regex '^fwupd_.*' libfwupd_la_CFLAGS = \ $(PIE_CFLAGS) \ $(WARNINGFLAGS_C) pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = fwupd.pc EXTRA_DIST = \ fwupd-version.h.in \ fwupd.pc.in if HAVE_INTROSPECTION introspection_sources = \ $(libfwupd_la_SOURCES) \ $(libfwupdbase_include_HEADERS) Fwupd-1.0.gir: libfwupd.la Fwupd_1_0_gir_INCLUDES = GObject-2.0 Gio-2.0 Fwupd_1_0_gir_CFLAGS = $(AM_CPPFLAGS) -DCD_DISABLE_DEPRECATED Fwupd_1_0_gir_SCANNERFLAGS = --identifier-prefix=Fwupd \ --symbol-prefix=fwupd \ --warn-all \ --add-include-path=$(srcdir) \ --c-include="fwupd.h" Fwupd_1_0_gir_EXPORT_PACKAGES = fwupd Fwupd_1_0_gir_LIBS = libfwupd.la Fwupd_1_0_gir_FILES = $(introspection_sources) INTROSPECTION_GIRS += Fwupd-1.0.gir girdir = $(datadir)/gir-1.0 gir_DATA = $(INTROSPECTION_GIRS) typelibdir = $(libdir)/girepository-1.0 typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib) CLEANFILES = $(gir_DATA) $(typelib_DATA) endif TESTS_ENVIRONMENT = \ libtool --mode=execute valgrind \ --quiet \ --leak-check=full \ --show-possibly-lost=no check_PROGRAMS = \ fwupd-self-test fwupd_self_test_SOURCES = \ fwupd-client.c \ fwupd-enums.c \ fwupd-error.c \ fwupd-result.c \ fwupd-self-test.c fwupd_self_test_LDADD = \ $(LIBM) \ $(ARCHIVE_LIBS) \ $(GLIB_LIBS) fwupd_self_test_CFLAGS = \ $(WARNINGFLAGS_C) TESTS = fwupd-self-test clean-local: rm -f *~ -include $(top_srcdir)/git.mk fwupd-0.7.0/libfwupd/fwupd-client.c000066400000000000000000000622331267747510300172460ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2016 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "config.h" #include #include #include #include #include #include #include #include "fwupd-client.h" #include "fwupd-enums.h" #include "fwupd-error.h" #include "fwupd-result.h" static void fwupd_client_finalize (GObject *object); /** * FwupdClientPrivate: * * Private #FwupdClient data **/ typedef struct { FwupdStatus status; GDBusConnection *conn; GDBusProxy *proxy; } FwupdClientPrivate; enum { SIGNAL_CHANGED, SIGNAL_STATUS_CHANGED, SIGNAL_LAST }; enum { PROP_0, PROP_STATUS, PROP_LAST }; static guint signals [SIGNAL_LAST] = { 0 }; G_DEFINE_TYPE_WITH_PRIVATE (FwupdClient, fwupd_client, G_TYPE_OBJECT) #define GET_PRIVATE(o) (fwupd_client_get_instance_private (o)) typedef struct { gboolean ret; GError *error; GMainLoop *loop; GVariant *val; GDBusMessage *message; } FwupdClientHelper; /** * fwupd_client_helper_free: **/ static void fwupd_client_helper_free (FwupdClientHelper *helper) { if (helper->message != NULL) g_object_unref (helper->message); if (helper->val != NULL) g_variant_unref (helper->val); if (helper->error != NULL) g_error_free (helper->error); g_main_loop_unref (helper->loop); g_free (helper); } /** * fwupd_client_helper_new: **/ static FwupdClientHelper * fwupd_client_helper_new (void) { FwupdClientHelper *helper; helper = g_new0 (FwupdClientHelper, 1); helper->loop = g_main_loop_new (NULL, FALSE); return helper; } G_DEFINE_AUTOPTR_CLEANUP_FUNC(FwupdClientHelper, fwupd_client_helper_free) /** * fwupd_client_properties_changed_cb: **/ static void fwupd_client_properties_changed_cb (GDBusProxy *proxy, GVariant *changed_properties, GStrv invalidated_properties, FwupdClient *client) { g_autoptr(GVariant) val = NULL; FwupdClientPrivate *priv = GET_PRIVATE (client); /* print to the console */ val = g_dbus_proxy_get_cached_property (proxy, "Status"); if (val == NULL) return; priv->status = g_variant_get_uint32 (val); g_debug ("Emitting ::status-changed() [%s]", fwupd_status_to_string (priv->status)); g_signal_emit (client, signals[SIGNAL_STATUS_CHANGED], 0, priv->status); } /** * fwupd_client_signal_cb: */ static void fwupd_client_signal_cb (GDBusProxy *proxy, const gchar *sender_name, const gchar *signal_name, GVariant *parameters, FwupdClient *client) { g_debug ("Emitting ::changed()"); g_signal_emit (client, signals[SIGNAL_CHANGED], 0); } /** * fwupd_client_startup: **/ static gboolean fwupd_client_startup (FwupdClient *client, GCancellable *cancellable, GError **error) { FwupdClientPrivate *priv = GET_PRIVATE (client); g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* nothing to do */ if (priv->proxy != NULL) return TRUE; /* connect to the daemon */ priv->conn = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); if (priv->conn == NULL) return FALSE; priv->proxy = g_dbus_proxy_new_sync (priv->conn, G_DBUS_PROXY_FLAGS_NONE, NULL, FWUPD_DBUS_SERVICE, FWUPD_DBUS_PATH, FWUPD_DBUS_INTERFACE, NULL, error); if (priv->proxy == NULL) return FALSE; g_signal_connect (priv->proxy, "g-properties-changed", G_CALLBACK (fwupd_client_properties_changed_cb), client); g_signal_connect (priv->proxy, "g-signal", G_CALLBACK (fwupd_client_signal_cb), client); return TRUE; } /** * fwupd_client_parse_results_from_data: **/ static GPtrArray * fwupd_client_parse_results_from_data (GVariant *devices) { FwupdResult *res; GPtrArray *results = NULL; gsize sz; guint i; g_autoptr(GVariant) untuple = NULL; results = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); untuple = g_variant_get_child_value (devices, 0); sz = g_variant_n_children (untuple); for (i = 0; i < sz; i++) { g_autoptr(GVariant) data = NULL; data = g_variant_get_child_value (untuple, i); res = fwupd_result_new_from_data (data); g_ptr_array_add (results, res); } return results; } /** * fwupd_client_fixup_dbus_error: **/ static void fwupd_client_fixup_dbus_error (GError *error) { g_autofree gchar *name = NULL; g_return_if_fail (error != NULL); /* is a remote error? */ if (!g_dbus_error_is_remote_error (error)) return; /* parse the remote error */ name = g_dbus_error_get_remote_error (error); error->domain = FWUPD_ERROR; error->code = fwupd_error_from_string (name); g_dbus_error_strip_remote_error (error); } /** * fwupd_client_get_devices: * @client: A #FwupdClient * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL * * Gets all the devices registered with the daemon. * * Returns: (element-type FwupdResult) (transfer container): results * * Since: 0.7.0 **/ GPtrArray * fwupd_client_get_devices (FwupdClient *client, GCancellable *cancellable, GError **error) { FwupdClientPrivate *priv = GET_PRIVATE (client); g_autoptr(GVariant) val = NULL; g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* connect */ if (!fwupd_client_startup (client, cancellable, error)) return NULL; /* call into daemon */ val = g_dbus_proxy_call_sync (priv->proxy, "GetDevices", NULL, G_DBUS_CALL_FLAGS_NONE, -1, cancellable, error); if (val == NULL) { if (error != NULL) fwupd_client_fixup_dbus_error (*error); return NULL; } return fwupd_client_parse_results_from_data (val); } /** * fwupd_client_get_updates: * @client: A #FwupdClient * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL * * Gets all the devices with known updates. * * Returns: (element-type FwupdResult) (transfer container): results * * Since: 0.7.0 **/ GPtrArray * fwupd_client_get_updates (FwupdClient *client, GCancellable *cancellable, GError **error) { FwupdClientPrivate *priv = GET_PRIVATE (client); g_autoptr(GVariant) val = NULL; g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* connect */ if (!fwupd_client_startup (client, cancellable, error)) return NULL; /* call into daemon */ val = g_dbus_proxy_call_sync (priv->proxy, "GetUpdates", NULL, G_DBUS_CALL_FLAGS_NONE, -1, cancellable, error); if (val == NULL) { if (error != NULL) fwupd_client_fixup_dbus_error (*error); return NULL; } return fwupd_client_parse_results_from_data (val); } /** * fwupd_client_proxy_call_cb: **/ static void fwupd_client_proxy_call_cb (GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *) user_data; helper->val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &helper->error); if (helper->val != NULL) helper->ret = TRUE; if (helper->error != NULL) fwupd_client_fixup_dbus_error (helper->error); g_main_loop_quit (helper->loop); } /** * fwupd_client_verify: * @client: A #FwupdClient * @device_id: the device ID * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL * * Verify a specific device. * * Returns: %TRUE for verification success * * Since: 0.7.0 **/ gboolean fwupd_client_verify (FwupdClient *client, const gchar *device_id, GCancellable *cancellable, GError **error) { FwupdClientPrivate *priv = GET_PRIVATE (client); g_autoptr(FwupdClientHelper) helper = NULL; g_autoptr(GVariant) val = NULL; g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); g_return_val_if_fail (device_id != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* connect */ if (!fwupd_client_startup (client, cancellable, error)) return FALSE; /* call into daemon */ helper = fwupd_client_helper_new (); g_dbus_proxy_call (priv->proxy, "Verify", g_variant_new ("(s)", device_id), G_DBUS_CALL_FLAGS_NONE, -1, cancellable, fwupd_client_proxy_call_cb, helper); g_main_loop_run (helper->loop); if (!helper->ret) { g_propagate_error (error, helper->error); helper->error = NULL; return FALSE; } return TRUE; } /** * fwupd_client_unlock: * @client: A #FwupdClient * @device_id: the device ID * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL * * Unlocks a specific device so firmware can be read or wrote. * * Returns: %TRUE for success * * Since: 0.7.0 **/ gboolean fwupd_client_unlock (FwupdClient *client, const gchar *device_id, GCancellable *cancellable, GError **error) { FwupdClientPrivate *priv = GET_PRIVATE (client); g_autoptr(FwupdClientHelper) helper = NULL; g_autoptr(GVariant) val = NULL; g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); g_return_val_if_fail (device_id != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* connect */ if (!fwupd_client_startup (client, cancellable, error)) return FALSE; /* call into daemon */ helper = fwupd_client_helper_new (); g_dbus_proxy_call (priv->proxy, "Unlock", g_variant_new ("(s)", device_id), G_DBUS_CALL_FLAGS_NONE, -1, cancellable, fwupd_client_proxy_call_cb, helper); g_main_loop_run (helper->loop); if (!helper->ret) { g_propagate_error (error, helper->error); helper->error = NULL; return FALSE; } return TRUE; } /** * fwupd_client_clear_results: * @client: A #FwupdClient * @device_id: the device ID * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL * * Clears the results for a specific device. * * Returns: %TRUE for success * * Since: 0.7.0 **/ gboolean fwupd_client_clear_results (FwupdClient *client, const gchar *device_id, GCancellable *cancellable, GError **error) { FwupdClientPrivate *priv = GET_PRIVATE (client); g_autoptr(FwupdClientHelper) helper = NULL; g_autoptr(GVariant) val = NULL; g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); g_return_val_if_fail (device_id != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* connect */ if (!fwupd_client_startup (client, cancellable, error)) return FALSE; /* call into daemon */ helper = fwupd_client_helper_new (); g_dbus_proxy_call (priv->proxy, "ClearResults", g_variant_new ("(s)", device_id), G_DBUS_CALL_FLAGS_NONE, -1, cancellable, fwupd_client_proxy_call_cb, helper); g_main_loop_run (helper->loop); if (!helper->ret) { g_propagate_error (error, helper->error); helper->error = NULL; return FALSE; } return TRUE; } /** * fwupd_client_get_results: * @client: A #FwupdClient * @device_id: the device ID * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL * * Gets the results of a previous firmware update for a specific device. * * Returns: (transfer full): a #FwupdResult, or %NULL for failure * * Since: 0.7.0 **/ FwupdResult * fwupd_client_get_results (FwupdClient *client, const gchar *device_id, GCancellable *cancellable, GError **error) { FwupdClientPrivate *priv = GET_PRIVATE (client); g_autoptr(FwupdClientHelper) helper = NULL; g_autoptr(GVariant) val = NULL; g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); g_return_val_if_fail (device_id != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* connect */ if (!fwupd_client_startup (client, cancellable, error)) return NULL; /* call into daemon */ helper = fwupd_client_helper_new (); g_dbus_proxy_call (priv->proxy, "GetResults", g_variant_new ("(s)", device_id), G_DBUS_CALL_FLAGS_NONE, -1, cancellable, fwupd_client_proxy_call_cb, helper); g_main_loop_run (helper->loop); if (!helper->ret) { g_propagate_error (error, helper->error); helper->error = NULL; return NULL; } return fwupd_result_new_from_data (helper->val); } /** * fwupd_client_send_message_cb: **/ static void fwupd_client_send_message_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *) user_data; GDBusConnection *con = G_DBUS_CONNECTION (source_object); helper->message = g_dbus_connection_send_message_with_reply_finish (con, res, &helper->error); if (helper->message && !g_dbus_message_to_gerror (helper->message, &helper->error)) { helper->ret = TRUE; helper->val = g_dbus_message_get_body (helper->message); if (helper->val != NULL) g_variant_ref (helper->val); } if (helper->error != NULL) fwupd_client_fixup_dbus_error (helper->error); g_main_loop_quit (helper->loop); } /** * fwupd_client_install: * @client: A #FwupdClient * @device_id: the device ID * @filename: the filename to install * @install_flags: the #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL * * Install a file onto a specific device. * * Returns: %TRUE for success * * Since: 0.7.0 **/ gboolean fwupd_client_install (FwupdClient *client, const gchar *device_id, const gchar *filename, FwupdInstallFlags install_flags, GCancellable *cancellable, GError **error) { FwupdClientPrivate *priv = GET_PRIVATE (client); GVariant *body; GVariantBuilder builder; gint retval; gint fd; g_autoptr(FwupdClientHelper) helper = NULL; g_autoptr(GDBusMessage) request = NULL; g_autoptr(GUnixFDList) fd_list = NULL; g_autoptr(GVariant) val = NULL; g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); g_return_val_if_fail (device_id != NULL, FALSE); g_return_val_if_fail (filename != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* connect */ if (!fwupd_client_startup (client, cancellable, error)) return FALSE; /* set options */ g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); g_variant_builder_add (&builder, "{sv}", "reason", g_variant_new_string ("user-action")); g_variant_builder_add (&builder, "{sv}", "filename", g_variant_new_string (filename)); if (install_flags & FWUPD_INSTALL_FLAG_OFFLINE) { g_variant_builder_add (&builder, "{sv}", "offline", g_variant_new_boolean (TRUE)); } if (install_flags & FWUPD_INSTALL_FLAG_ALLOW_OLDER) { g_variant_builder_add (&builder, "{sv}", "allow-older", g_variant_new_boolean (TRUE)); } if (install_flags & FWUPD_INSTALL_FLAG_ALLOW_REINSTALL) { g_variant_builder_add (&builder, "{sv}", "allow-reinstall", g_variant_new_boolean (TRUE)); } /* open file */ fd = open (filename, O_RDONLY); if (fd < 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "failed to open %s", filename); return FALSE; } /* set out of band file descriptor */ fd_list = g_unix_fd_list_new (); retval = g_unix_fd_list_append (fd_list, fd, NULL); g_assert (retval != -1); request = g_dbus_message_new_method_call (FWUPD_DBUS_SERVICE, FWUPD_DBUS_PATH, FWUPD_DBUS_INTERFACE, "Install"); g_dbus_message_set_unix_fd_list (request, fd_list); /* g_unix_fd_list_append did a dup() already */ close (fd); /* call into daemon */ helper = fwupd_client_helper_new (); body = g_variant_new ("(sha{sv})", device_id, fd > -1 ? 0 : -1, &builder); g_dbus_message_set_body (request, body); g_dbus_connection_send_message_with_reply (priv->conn, request, G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, cancellable, fwupd_client_send_message_cb, helper); g_main_loop_run (helper->loop); if (!helper->ret) { g_propagate_error (error, helper->error); helper->error = NULL; return FALSE; } return TRUE; } /** * fwupd_client_get_details: * @client: A #FwupdClient * @filename: the firmware filename, e.g. "firmware.cab" * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL * * Gets details about a specific firmware file. * * Returns: (transfer full): a #FwupdResult, or %NULL for failure * * Since: 0.7.0 **/ FwupdResult * fwupd_client_get_details (FwupdClient *client, const gchar *filename, GCancellable *cancellable, GError **error) { FwupdClientPrivate *priv = GET_PRIVATE (client); GVariant *body; gint fd; gint retval; g_autoptr(FwupdClientHelper) helper = NULL; g_autoptr(GDBusMessage) request = NULL; g_autoptr(GUnixFDList) fd_list = NULL; g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); g_return_val_if_fail (filename != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* connect */ if (!fwupd_client_startup (client, cancellable, error)) return NULL; /* open file */ fd = open (filename, O_RDONLY); if (fd < 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "failed to open %s", filename); return NULL; } /* set out of band file descriptor */ fd_list = g_unix_fd_list_new (); retval = g_unix_fd_list_append (fd_list, fd, NULL); g_assert (retval != -1); request = g_dbus_message_new_method_call (FWUPD_DBUS_SERVICE, FWUPD_DBUS_PATH, FWUPD_DBUS_INTERFACE, "GetDetails"); g_dbus_message_set_unix_fd_list (request, fd_list); /* g_unix_fd_list_append did a dup() already */ close (fd); /* call into daemon */ helper = fwupd_client_helper_new (); body = g_variant_new ("(h)", fd > -1 ? 0 : -1); g_dbus_message_set_body (request, body); g_dbus_connection_send_message_with_reply (priv->conn, request, G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, cancellable, fwupd_client_send_message_cb, helper); g_main_loop_run (helper->loop); if (!helper->ret) { g_propagate_error (error, helper->error); helper->error = NULL; return NULL; } /* print results */ return fwupd_result_new_from_data (helper->val); } /** * fwupd_client_update_metadata: * @client: A #FwupdClient * @metadata_fn: the XML metadata filename * @signature_fn: the GPG signature file * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL * * Updates the metadata. This allows a session process to download the metadata * and metadata signing file to be passed into the daemon to be checked and * parsed. * * Returns: %TRUE for success * * Since: 0.7.0 **/ gboolean fwupd_client_update_metadata (FwupdClient *client, const gchar *metadata_fn, const gchar *signature_fn, GCancellable *cancellable, GError **error) { FwupdClientPrivate *priv = GET_PRIVATE (client); GVariant *body; gint fd; gint fd_sig; g_autoptr(FwupdClientHelper) helper = NULL; g_autoptr(GDBusMessage) request = NULL; g_autoptr(GUnixFDList) fd_list = NULL; g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); g_return_val_if_fail (metadata_fn != NULL, FALSE); g_return_val_if_fail (signature_fn != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* connect */ if (!fwupd_client_startup (client, cancellable, error)) return FALSE; /* open file */ fd = open (metadata_fn, O_RDONLY); if (fd < 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "failed to open %s", metadata_fn); return FALSE; } fd_sig = open (signature_fn, O_RDONLY); if (fd_sig < 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "failed to open %s", signature_fn); return FALSE; } /* set out of band file descriptor */ fd_list = g_unix_fd_list_new (); g_unix_fd_list_append (fd_list, fd, NULL); g_unix_fd_list_append (fd_list, fd_sig, NULL); request = g_dbus_message_new_method_call (FWUPD_DBUS_SERVICE, FWUPD_DBUS_PATH, FWUPD_DBUS_INTERFACE, "UpdateMetadata"); g_dbus_message_set_unix_fd_list (request, fd_list); /* g_unix_fd_list_append did a dup() already */ close (fd); close (fd_sig); /* call into daemon */ body = g_variant_new ("(hh)", fd, fd_sig); g_dbus_message_set_body (request, body); helper = fwupd_client_helper_new (); g_dbus_connection_send_message_with_reply (priv->conn, request, G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, cancellable, fwupd_client_send_message_cb, helper); g_main_loop_run (helper->loop); if (!helper->ret) { g_propagate_error (error, helper->error); helper->error = NULL; return FALSE; } return TRUE; } /** * fwupd_client_get_property: **/ static void fwupd_client_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { FwupdClient *client = FWUPD_CLIENT (object); FwupdClientPrivate *priv = GET_PRIVATE (client); switch (prop_id) { case PROP_STATUS: g_value_set_uint (value, priv->status); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } /** * fwupd_client_set_property: **/ static void fwupd_client_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { FwupdClient *client = FWUPD_CLIENT (object); FwupdClientPrivate *priv = GET_PRIVATE (client); switch (prop_id) { case PROP_STATUS: priv->status = g_value_get_uint (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } /** * fwupd_client_class_init: **/ static void fwupd_client_class_init (FwupdClientClass *klass) { GParamSpec *pspec; GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = fwupd_client_finalize; object_class->get_property = fwupd_client_get_property; object_class->set_property = fwupd_client_set_property; /** * FwupdClient::changed: * @client: the #FwupdClient instance that emitted the signal * * The ::changed signal is emitted when the daemon internal has * changed, for instance when a device has been added or removed. * * Since: 0.7.0 **/ signals [SIGNAL_CHANGED] = g_signal_new ("changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (FwupdClientClass, changed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * FwupdClient::state-changed: * @client: the #FwupdClient instance that emitted the signal * @status: the #FwupdStatus * * The ::state-changed signal is emitted when the daemon status has * changed, e.g. going from %FWUPD_STATUS_IDLE to %FWUPD_STATUS_DEVICE_WRITE. * * Since: 0.7.0 **/ signals [SIGNAL_STATUS_CHANGED] = g_signal_new ("status-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (FwupdClientClass, status_changed), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); /** * FwupdClient:status: * * The last-reported status of the daemon. * * Since: 0.7.0 */ pspec = g_param_spec_uint ("status", NULL, NULL, 0, FWUPD_STATUS_LAST, FWUPD_STATUS_UNKNOWN, G_PARAM_READWRITE); g_object_class_install_property (object_class, PROP_STATUS, pspec); } /** * fwupd_client_init: **/ static void fwupd_client_init (FwupdClient *client) { } /** * fwupd_client_finalize: **/ static void fwupd_client_finalize (GObject *object) { FwupdClient *client = FWUPD_CLIENT (object); FwupdClientPrivate *priv = GET_PRIVATE (client); if (priv->conn != NULL) g_object_unref (priv->conn); if (priv->proxy != NULL) g_object_unref (priv->proxy); G_OBJECT_CLASS (fwupd_client_parent_class)->finalize (object); } /** * fwupd_client_new: * * Creates a new client. * * Returns: a new #FwupdClient * * Since: 0.7.0 **/ FwupdClient * fwupd_client_new (void) { FwupdClient *client; client = g_object_new (FWUPD_TYPE_CLIENT, NULL); return FWUPD_CLIENT (client); } fwupd-0.7.0/libfwupd/fwupd-client.h000066400000000000000000000061521267747510300172510ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2016 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __FWUPD_CLIENT_H #define __FWUPD_CLIENT_H #include #include #include "fwupd-enums.h" #include "fwupd-result.h" G_BEGIN_DECLS #define FWUPD_TYPE_CLIENT (fwupd_client_get_type ()) G_DECLARE_DERIVABLE_TYPE (FwupdClient, fwupd_client, FWUPD, CLIENT, GObject) struct _FwupdClientClass { GObjectClass parent_class; void (*changed) (FwupdClient *client); void (*status_changed) (FwupdClient *client, FwupdStatus status); /*< private >*/ void (*_fwupd_reserved1) (void); void (*_fwupd_reserved2) (void); void (*_fwupd_reserved3) (void); void (*_fwupd_reserved4) (void); void (*_fwupd_reserved5) (void); void (*_fwupd_reserved6) (void); void (*_fwupd_reserved7) (void); }; FwupdClient *fwupd_client_new (void); GPtrArray *fwupd_client_get_devices (FwupdClient *client, GCancellable *cancellable, GError **error); GPtrArray *fwupd_client_get_updates (FwupdClient *client, GCancellable *cancellable, GError **error); gboolean fwupd_client_verify (FwupdClient *client, const gchar *device_id, GCancellable *cancellable, GError **error); gboolean fwupd_client_unlock (FwupdClient *client, const gchar *device_id, GCancellable *cancellable, GError **error); gboolean fwupd_client_clear_results (FwupdClient *client, const gchar *device_id, GCancellable *cancellable, GError **error); FwupdResult *fwupd_client_get_results (FwupdClient *client, const gchar *device_id, GCancellable *cancellable, GError **error); FwupdResult *fwupd_client_get_details (FwupdClient *client, const gchar *filename, GCancellable *cancellable, GError **error); gboolean fwupd_client_install (FwupdClient *client, const gchar *device_id, const gchar *filename, FwupdInstallFlags install_flags, GCancellable *cancellable, GError **error); gboolean fwupd_client_update_metadata (FwupdClient *client, const gchar *metadata_fn, const gchar *signature_fn, GCancellable *cancellable, GError **error); G_END_DECLS #endif /* __FWUPD_CLIENT_H */ fwupd-0.7.0/libfwupd/fwupd-enums-private.h000066400000000000000000000054471267747510300206000ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2016 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __FWUPD_ENUMS_PRIVATE_H #define __FWUPD_ENUMS_PRIVATE_H /* FIXME: change the keys to the new names when we bump major version */ #define FWUPD_RESULT_KEY_DEVICE_CREATED "Created" /* t */ #define FWUPD_RESULT_KEY_DEVICE_DESCRIPTION "Description" /* s */ #define FWUPD_RESULT_KEY_DEVICE_FLAGS "Flags" /* t */ #define FWUPD_RESULT_KEY_DEVICE_CHECKSUM "FirmwareHash" /* s */ #define FWUPD_RESULT_KEY_DEVICE_CHECKSUM_KIND "DeviceChecksumKind" /* u */ #define FWUPD_RESULT_KEY_DEVICE_MODIFIED "Modified" /* t */ #define FWUPD_RESULT_KEY_DEVICE_NAME "DisplayName" /* s */ #define FWUPD_RESULT_KEY_DEVICE_PROVIDER "Provider" /* s */ #define FWUPD_RESULT_KEY_DEVICE_VERSION "Version" /* s */ #define FWUPD_RESULT_KEY_DEVICE_VERSION_LOWEST "VersionLowest" /* s */ #define FWUPD_RESULT_KEY_DEVICE_VENDOR "DeviceVendor" /* s */ #define FWUPD_RESULT_KEY_GUID "Guid" /* s */ #define FWUPD_RESULT_KEY_UPDATE_DESCRIPTION "UpdateDescription" /* s */ #define FWUPD_RESULT_KEY_UPDATE_ERROR "PendingError" /* s */ #define FWUPD_RESULT_KEY_UPDATE_FILENAME "FilenameCab" /* s */ #define FWUPD_RESULT_KEY_UPDATE_CHECKSUM "UpdateHash" /* s */ #define FWUPD_RESULT_KEY_UPDATE_CHECKSUM_KIND "UpdateChecksumKind" /* u */ #define FWUPD_RESULT_KEY_UPDATE_ID "AppstreamId" /* s */ #define FWUPD_RESULT_KEY_UPDATE_LICENSE "License" /* s */ #define FWUPD_RESULT_KEY_UPDATE_NAME "Name" /* s */ #define FWUPD_RESULT_KEY_UPDATE_SIZE "Size" /* t */ #define FWUPD_RESULT_KEY_UPDATE_STATE "PendingState" /* s */ #define FWUPD_RESULT_KEY_UPDATE_SUMMARY "Summary" /* s */ #define FWUPD_RESULT_KEY_UPDATE_TRUST_FLAGS "Trusted" /* t */ #define FWUPD_RESULT_KEY_UPDATE_URI "UpdateUri" /* s */ #define FWUPD_RESULT_KEY_UPDATE_HOMEPAGE "UrlHomepage" /* s */ #define FWUPD_RESULT_KEY_UPDATE_VENDOR "Vendor" /* s */ #define FWUPD_RESULT_KEY_UPDATE_VERSION "UpdateVersion" /* s */ #endif /* __FWUPD_ENUMS_PRIVATE_H */ fwupd-0.7.0/libfwupd/fwupd-enums.c000066400000000000000000000144401267747510300171140ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "config.h" #include "fwupd-enums.h" /** * fwupd_status_to_string: * @status: A #FwupdStatus, e.g. %FWUPD_STATUS_DECOMPRESSING * * Converts a #FwupdStatus to a string. * * Return value: identifier string * * Since: 0.1.1 **/ const gchar * fwupd_status_to_string (FwupdStatus status) { if (status == FWUPD_STATUS_UNKNOWN) return "unknown"; if (status == FWUPD_STATUS_IDLE) return "idle"; if (status == FWUPD_STATUS_DECOMPRESSING) return "decompressing"; if (status == FWUPD_STATUS_LOADING) return "loading"; if (status == FWUPD_STATUS_DEVICE_RESTART) return "device-restart"; if (status == FWUPD_STATUS_DEVICE_WRITE) return "device-write"; if (status == FWUPD_STATUS_DEVICE_VERIFY) return "device-verify"; if (status == FWUPD_STATUS_SCHEDULING) return "scheduling"; return NULL; } /** * fwupd_status_from_string: * @status: A string, e.g. "decompressing" * * Converts a string to a #FwupdStatus. * * Return value: enumerated value * * Since: 0.1.1 **/ FwupdStatus fwupd_status_from_string (const gchar *status) { if (g_strcmp0 (status, "unknown") == 0) return FWUPD_STATUS_UNKNOWN; if (g_strcmp0 (status, "idle") == 0) return FWUPD_STATUS_IDLE; if (g_strcmp0 (status, "decompressing") == 0) return FWUPD_STATUS_DECOMPRESSING; if (g_strcmp0 (status, "loading") == 0) return FWUPD_STATUS_LOADING; if (g_strcmp0 (status, "device-restart") == 0) return FWUPD_STATUS_DEVICE_RESTART; if (g_strcmp0 (status, "device-write") == 0) return FWUPD_STATUS_DEVICE_WRITE; if (g_strcmp0 (status, "device-verify") == 0) return FWUPD_STATUS_DEVICE_VERIFY; if (g_strcmp0 (status, "scheduling") == 0) return FWUPD_STATUS_SCHEDULING; return FWUPD_STATUS_LAST; } /** * fwupd_device_flag_to_string: * @device_flag: A #FwupdDeviceFlags, e.g. %FU_DEVICE_FLAG_REQUIRE_AC * * Converts a #FwupdDeviceFlags to a string. * * Return value: identifier string * * Since: 0.7.0 **/ const gchar * fwupd_device_flag_to_string (FwupdDeviceFlags device_flag) { if (device_flag == FU_DEVICE_FLAG_NONE) return "none"; if (device_flag == FU_DEVICE_FLAG_INTERNAL) return "internal"; if (device_flag == FU_DEVICE_FLAG_ALLOW_ONLINE) return "allow-online"; if (device_flag == FU_DEVICE_FLAG_ALLOW_OFFLINE) return "allow-offline"; if (device_flag == FU_DEVICE_FLAG_REQUIRE_AC) return "require-ac"; if (device_flag == FU_DEVICE_FLAG_LOCKED) return "locked"; return NULL; } /** * fwupd_device_flag_from_string: * @device_flag: A string, e.g. "require-ac" * * Converts a string to a #FwupdDeviceFlags. * * Return value: enumerated value * * Since: 0.7.0 **/ FwupdDeviceFlags fwupd_device_flag_from_string (const gchar *device_flag) { if (g_strcmp0 (device_flag, "none") == 0) return FU_DEVICE_FLAG_NONE; if (g_strcmp0 (device_flag, "internal") == 0) return FU_DEVICE_FLAG_INTERNAL; if (g_strcmp0 (device_flag, "allow-online") == 0) return FU_DEVICE_FLAG_ALLOW_ONLINE; if (g_strcmp0 (device_flag, "allow-offline") == 0) return FU_DEVICE_FLAG_ALLOW_OFFLINE; if (g_strcmp0 (device_flag, "require-ac") == 0) return FU_DEVICE_FLAG_REQUIRE_AC; if (g_strcmp0 (device_flag, "locked") == 0) return FU_DEVICE_FLAG_LOCKED; return FU_DEVICE_FLAG_LAST; } /** * fwupd_update_state_to_string: * @update_state: A #FwupdUpdateState, e.g. %FWUPD_UPDATE_STATE_PENDING * * Converts a #FwupdUpdateState to a string. * * Return value: identifier string * * Since: 0.7.0 **/ const gchar * fwupd_update_state_to_string (FwupdUpdateState update_state) { if (update_state == FWUPD_UPDATE_STATE_UNKNOWN) return "unknown"; if (update_state == FWUPD_UPDATE_STATE_PENDING) return "pending"; if (update_state == FWUPD_UPDATE_STATE_SUCCESS) return "success"; if (update_state == FWUPD_UPDATE_STATE_FAILED) return "failed"; return NULL; } /** * fwupd_update_state_from_string: * @update_state: A string, e.g. "pending" * * Converts a string to a #FwupdUpdateState. * * Return value: enumerated value * * Since: 0.7.0 **/ FwupdUpdateState fwupd_update_state_from_string (const gchar *update_state) { if (g_strcmp0 (update_state, "unknown") == 0) return FWUPD_UPDATE_STATE_UNKNOWN; if (g_strcmp0 (update_state, "pending") == 0) return FWUPD_UPDATE_STATE_PENDING; if (g_strcmp0 (update_state, "success") == 0) return FWUPD_UPDATE_STATE_SUCCESS; if (g_strcmp0 (update_state, "failed") == 0) return FWUPD_UPDATE_STATE_FAILED; return FWUPD_UPDATE_STATE_UNKNOWN; } /** * fwupd_trust_flag_to_string: * @trust_flag: A #FwupdTrustFlags, e.g. %FWUPD_TRUST_FLAG_PAYLOAD * * Converts a #FwupdTrustFlags to a string. * * Return value: identifier string * * Since: 0.7.0 **/ const gchar * fwupd_trust_flag_to_string (FwupdTrustFlags trust_flag) { if (trust_flag == FWUPD_TRUST_FLAG_NONE) return "none"; if (trust_flag == FWUPD_TRUST_FLAG_PAYLOAD) return "payload"; if (trust_flag == FWUPD_TRUST_FLAG_METADATA) return "metadata"; return NULL; } /** * fwupd_trust_flag_from_string: * @trust_flag: A string, e.g. "payload" * * Converts a string to a #FwupdTrustFlags. * * Return value: enumerated value * * Since: 0.7.0 **/ FwupdTrustFlags fwupd_trust_flag_from_string (const gchar *trust_flag) { if (g_strcmp0 (trust_flag, "none") == 0) return FWUPD_TRUST_FLAG_NONE; if (g_strcmp0 (trust_flag, "payload") == 0) return FWUPD_TRUST_FLAG_PAYLOAD; if (g_strcmp0 (trust_flag, "metadata") == 0) return FWUPD_TRUST_FLAG_METADATA; return FWUPD_TRUST_FLAG_LAST; } fwupd-0.7.0/libfwupd/fwupd-enums.h000066400000000000000000000121131267747510300171140ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __FWUPD_ENUMS_H #define __FWUPD_ENUMS_H #include #define FWUPD_DBUS_PATH "/" #define FWUPD_DBUS_SERVICE "org.freedesktop.fwupd" #define FWUPD_DBUS_INTERFACE "org.freedesktop.fwupd" #define FWUPD_DEVICE_ID_ANY "*" /** * FwupdStatus: * @FWUPD_STATUS_UNKNOWN: Unknown state * @FWUPD_STATUS_IDLE: Idle * @FWUPD_STATUS_LOADING: Loading a resource * @FWUPD_STATUS_DECOMPRESSING: Decompressing firmware * @FWUPD_STATUS_DEVICE_RESTART: Restarting the device * @FWUPD_STATUS_DEVICE_WRITE: Writing to a device * @FWUPD_STATUS_DEVICE_VERIFY: Verifying (reading) a device * @FWUPD_STATUS_SCHEDULING: Scheduling an offline update * * The flags to show daemon status. **/ typedef enum { FWUPD_STATUS_UNKNOWN, /* Since: 0.1.1 */ FWUPD_STATUS_IDLE, /* Since: 0.1.1 */ FWUPD_STATUS_LOADING, /* Since: 0.1.1 */ FWUPD_STATUS_DECOMPRESSING, /* Since: 0.1.1 */ FWUPD_STATUS_DEVICE_RESTART, /* Since: 0.1.1 */ FWUPD_STATUS_DEVICE_WRITE, /* Since: 0.1.1 */ FWUPD_STATUS_DEVICE_VERIFY, /* Since: 0.1.1 */ FWUPD_STATUS_SCHEDULING, /* Since: 0.1.1 */ /*< private >*/ FWUPD_STATUS_LAST } FwupdStatus; /** * FwupdTrustFlags: * @FWUPD_TRUST_FLAG_NONE: No trust * @FWUPD_TRUST_FLAG_PAYLOAD: The firmware is trusted * @FWUPD_TRUST_FLAG_METADATA: The metadata is trusted * * The flags to show the level of trust. **/ typedef enum { FWUPD_TRUST_FLAG_NONE = 0, /* Since: 0.1.2 */ FWUPD_TRUST_FLAG_PAYLOAD = 1 << 0, /* Since: 0.1.2 */ FWUPD_TRUST_FLAG_METADATA = 1 << 1, /* Since: 0.1.2 */ /*< private >*/ FWUPD_TRUST_FLAG_LAST } FwupdTrustFlags; /** * FwupdDeviceFlags: * @FU_DEVICE_FLAG_NONE: No flags set * @FU_DEVICE_FLAG_INTERNAL: Device cannot be removed easily * @FU_DEVICE_FLAG_ALLOW_ONLINE: Permits 'live' updating * @FU_DEVICE_FLAG_ALLOW_OFFLINE: Permits 'offline' updating * @FU_DEVICE_FLAG_REQUIRE_AC: Requires AC power * @FU_DEVICE_FLAG_LOCKED: Is locked and can be unlocked * * FIXME: rename FU_DEVICE_ -> FWUPD_DEVICE_ when we break API * * The device flags. **/ typedef enum { FU_DEVICE_FLAG_NONE = 0, /* Since: 0.1.3 */ FU_DEVICE_FLAG_INTERNAL = 1 << 0, /* Since: 0.1.3 */ FU_DEVICE_FLAG_ALLOW_ONLINE = 1 << 1, /* Since: 0.1.3 */ FU_DEVICE_FLAG_ALLOW_OFFLINE = 1 << 2, /* Since: 0.1.3 */ FU_DEVICE_FLAG_REQUIRE_AC = 1 << 3, /* Since: 0.6.3 */ FU_DEVICE_FLAG_LOCKED = 1 << 4, /* Since: 0.6.3 */ /*< private >*/ FU_DEVICE_FLAG_LAST } FwupdDeviceFlags; /** * FwupdInstallFlags: * @FWUPD_INSTALL_FLAG_NONE: No flags set * @FWUPD_INSTALL_FLAG_OFFLINE: Perform this offline * @FWUPD_INSTALL_FLAG_ALLOW_REINSTALL: Allow reinstalling the same version * @FWUPD_INSTALL_FLAG_ALLOW_OLDER: Allow downgrading firmware * * Flags to set when performing the firwmare update or install. **/ typedef enum { FWUPD_INSTALL_FLAG_NONE = 0, /* Since: 0.7.0 */ FWUPD_INSTALL_FLAG_OFFLINE = 1, /* Since: 0.7.0 */ FWUPD_INSTALL_FLAG_ALLOW_REINSTALL = 2, /* Since: 0.7.0 */ FWUPD_INSTALL_FLAG_ALLOW_OLDER = 4, /* Since: 0.7.0 */ /*< private >*/ FWUPD_INSTALL_FLAG_LAST } FwupdInstallFlags; /** * FwupdUpdateState: * @FWUPD_UPDATE_STATE_UNKNOWN: Unknown * @FWUPD_UPDATE_STATE_PENDING: Update is pending * @FWUPD_UPDATE_STATE_SUCCESS: Update was successfull * @FWUPD_UPDATE_STATE_FAILED: Update failed * * The update state. **/ typedef enum { FWUPD_UPDATE_STATE_UNKNOWN, /* Since: 0.7.0 */ FWUPD_UPDATE_STATE_PENDING, /* Since: 0.7.0 */ FWUPD_UPDATE_STATE_SUCCESS, /* Since: 0.7.0 */ FWUPD_UPDATE_STATE_FAILED, /* Since: 0.7.0 */ /*< private >*/ FWUPD_UPDATE_STATE_LAST } FwupdUpdateState; const gchar *fwupd_status_to_string (FwupdStatus status); FwupdStatus fwupd_status_from_string (const gchar *status); const gchar *fwupd_device_flag_to_string (FwupdDeviceFlags device_flag); FwupdDeviceFlags fwupd_device_flag_from_string (const gchar *device_flag); const gchar *fwupd_update_state_to_string (FwupdUpdateState update_state); FwupdUpdateState fwupd_update_state_from_string (const gchar *update_state); const gchar *fwupd_trust_flag_to_string (FwupdTrustFlags trust_flag); FwupdTrustFlags fwupd_trust_flag_from_string (const gchar *trust_flag); #endif /* __FWUPD_ENUMS_H */ fwupd-0.7.0/libfwupd/fwupd-error.c000066400000000000000000000101211267747510300171060ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015-2016 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "config.h" #include #include "fwupd-enums.h" #include "fwupd-error.h" /** * fwupd_error_to_string: * @error: A #FwupdError, e.g. %FWUPD_ERROR_VERSION_NEWER * * Converts a #FwupdError to a string. * * Return value: identifier string * * Since: 0.7.0 **/ const gchar * fwupd_error_to_string (FwupdError error) { if (error == FWUPD_ERROR_INTERNAL) return FWUPD_DBUS_INTERFACE ".Internal"; if (error == FWUPD_ERROR_VERSION_NEWER) return FWUPD_DBUS_INTERFACE ".VersionNewer"; if (error == FWUPD_ERROR_VERSION_SAME) return FWUPD_DBUS_INTERFACE ".VersionSame"; if (error == FWUPD_ERROR_ALREADY_PENDING) return FWUPD_DBUS_INTERFACE ".AlreadyPending"; if (error == FWUPD_ERROR_AUTH_FAILED) return FWUPD_DBUS_INTERFACE ".AuthFailed"; if (error == FWUPD_ERROR_READ) return FWUPD_DBUS_INTERFACE ".Read"; if (error == FWUPD_ERROR_WRITE) return FWUPD_DBUS_INTERFACE ".Write"; if (error == FWUPD_ERROR_INVALID_FILE) return FWUPD_DBUS_INTERFACE ".InvalidFile"; if (error == FWUPD_ERROR_NOT_FOUND) return FWUPD_DBUS_INTERFACE ".NotFound"; if (error == FWUPD_ERROR_NOTHING_TO_DO) return FWUPD_DBUS_INTERFACE ".NothingToDo"; if (error == FWUPD_ERROR_NOT_SUPPORTED) return FWUPD_DBUS_INTERFACE ".NotSupported"; if (error == FWUPD_ERROR_SIGNATURE_INVALID) return FWUPD_DBUS_INTERFACE ".SignatureInvalid"; return NULL; } /** * fwupd_error_from_string: * @error: A string, e.g. "org.freedesktop.fwupd.VersionNewer" * * Converts a string to a #FwupdError. * * Return value: enumerated value * * Since: 0.7.0 **/ FwupdError fwupd_error_from_string (const gchar *error) { if (g_strcmp0 (error, FWUPD_DBUS_INTERFACE ".Internal") == 0) return FWUPD_ERROR_INTERNAL; if (g_strcmp0 (error, FWUPD_DBUS_INTERFACE ".VersionNewer") == 0) return FWUPD_ERROR_VERSION_NEWER; if (g_strcmp0 (error, FWUPD_DBUS_INTERFACE ".VersionSame") == 0) return FWUPD_ERROR_VERSION_SAME; if (g_strcmp0 (error, FWUPD_DBUS_INTERFACE ".AlreadyPending") == 0) return FWUPD_ERROR_ALREADY_PENDING; if (g_strcmp0 (error, FWUPD_DBUS_INTERFACE ".AuthFailed") == 0) return FWUPD_ERROR_AUTH_FAILED; if (g_strcmp0 (error, FWUPD_DBUS_INTERFACE ".Read") == 0) return FWUPD_ERROR_READ; if (g_strcmp0 (error, FWUPD_DBUS_INTERFACE ".Write") == 0) return FWUPD_ERROR_WRITE; if (g_strcmp0 (error, FWUPD_DBUS_INTERFACE ".InvalidFile") == 0) return FWUPD_ERROR_INVALID_FILE; if (g_strcmp0 (error, FWUPD_DBUS_INTERFACE ".NotFound") == 0) return FWUPD_ERROR_NOT_FOUND; if (g_strcmp0 (error, FWUPD_DBUS_INTERFACE ".NothingToDo") == 0) return FWUPD_ERROR_NOTHING_TO_DO; if (g_strcmp0 (error, FWUPD_DBUS_INTERFACE ".NotSupported") == 0) return FWUPD_ERROR_NOT_SUPPORTED; if (g_strcmp0 (error, FWUPD_DBUS_INTERFACE ".SignatureInvalid") == 0) return FWUPD_ERROR_SIGNATURE_INVALID; return FWUPD_ERROR_LAST; } /** * fwupd_error_quark: * * Return value: An error quark. * * Since: 0.1.1 **/ GQuark fwupd_error_quark (void) { static GQuark quark = 0; if (!quark) { guint i; quark = g_quark_from_static_string ("FwupdError"); for (i = 0; i < FWUPD_ERROR_LAST; i++) { g_dbus_error_register_error (quark, i, fwupd_error_to_string (i)); } } return quark; } fwupd-0.7.0/libfwupd/fwupd-error.h000066400000000000000000000050511267747510300171210ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015-2016 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __FWUPD_ERROR_H #define __FWUPD_ERROR_H #include #define FWUPD_ERROR fwupd_error_quark() /** * FwupdError: * @FWUPD_ERROR_INTERNAL: Internal error * @FWUPD_ERROR_VERSION_NEWER: Installed newer firmware version * @FWUPD_ERROR_VERSION_SAME: Installed same firmware version * @FWUPD_ERROR_ALREADY_PENDING: Already set be be installed offline * @FWUPD_ERROR_AUTH_FAILED: Failed to get authentication * @FWUPD_ERROR_READ: Failed to read from device * @FWUPD_ERROR_WRITE: Failed to write to the device * @FWUPD_ERROR_INVALID_FILE: Invalid file format * @FWUPD_ERROR_NOT_FOUND: No matching device exists * @FWUPD_ERROR_NOTHING_TO_DO: Nothing to do * @FWUPD_ERROR_NOT_SUPPORTED: Action was not possible * @FWUPD_ERROR_SIGNATURE_INVALID: Signature was invalid * * The error code. **/ typedef enum { FWUPD_ERROR_INTERNAL, /* Since: 0.1.1 */ FWUPD_ERROR_VERSION_NEWER, /* Since: 0.1.1 */ FWUPD_ERROR_VERSION_SAME, /* Since: 0.1.1 */ FWUPD_ERROR_ALREADY_PENDING, /* Since: 0.1.1 */ FWUPD_ERROR_AUTH_FAILED, /* Since: 0.1.1 */ FWUPD_ERROR_READ, /* Since: 0.1.1 */ FWUPD_ERROR_WRITE, /* Since: 0.1.1 */ FWUPD_ERROR_INVALID_FILE, /* Since: 0.1.1 */ FWUPD_ERROR_NOT_FOUND, /* Since: 0.1.1 */ FWUPD_ERROR_NOTHING_TO_DO, /* Since: 0.1.1 */ FWUPD_ERROR_NOT_SUPPORTED, /* Since: 0.1.1 */ FWUPD_ERROR_SIGNATURE_INVALID, /* Since: 0.1.2 */ /*< private >*/ FWUPD_ERROR_LAST } FwupdError; GQuark fwupd_error_quark (void); const gchar *fwupd_error_to_string (FwupdError error); FwupdError fwupd_error_from_string (const gchar *error); #endif /* __FWUPD_ERROR_H */ fwupd-0.7.0/libfwupd/fwupd-result.c000066400000000000000000001341551267747510300173110ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015-2016 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "config.h" #include #include #include #include "fwupd-enums-private.h" #include "fwupd-error.h" #include "fwupd-result.h" static void fwupd_result_finalize (GObject *object); /** * FwupdResultPrivate: * * Private #FwupdResult data **/ typedef struct { gchar *guid; /* device-specific */ gchar *device_checksum; GChecksumType device_checksum_kind; gchar *device_description; gchar *device_id; gchar *device_name; gchar *device_provider; gchar *device_vendor; gchar *device_version; gchar *device_version_lowest; guint64 device_created; guint64 device_flags; guint64 device_modified; /* update-specific */ FwupdTrustFlags update_trust_flags; FwupdUpdateState update_state; gchar *update_checksum; GChecksumType update_checksum_kind; gchar *update_description; gchar *update_error; gchar *update_filename; gchar *update_homepage; gchar *update_id; gchar *update_license; gchar *update_name; gchar *update_summary; gchar *update_uri; gchar *update_vendor; gchar *update_version; guint64 update_size; } FwupdResultPrivate; enum { SIGNAL_LAST }; enum { PROP_0, PROP_DEVICE_ID, PROP_LAST }; G_DEFINE_TYPE_WITH_PRIVATE (FwupdResult, fwupd_result, G_TYPE_OBJECT) #define GET_PRIVATE(o) (fwupd_result_get_instance_private (o)) /** * fwupd_result_get_device_id: * @result: A #FwupdResult * * Gets the ID. * * Returns: the ID, or %NULL if unset * * Since: 0.7.0 **/ const gchar * fwupd_result_get_device_id (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), NULL); return priv->device_id; } /** * fwupd_result_set_device_id: * @result: A #FwupdResult * @device_id: the result ID, e.g. "USB:foo" * * Sets the ID. * * Since: 0.7.0 **/ void fwupd_result_set_device_id (FwupdResult *result, const gchar *device_id) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); g_free (priv->device_id); priv->device_id = g_strdup (device_id); } /** * fwupd_result_get_guid: * @result: A #FwupdResult * * Gets the GUID. * * Returns: the GUID, or %NULL if unset * * Since: 0.7.0 **/ const gchar * fwupd_result_get_guid (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), NULL); return priv->guid; } /** * fwupd_result_set_guid: * @result: A #FwupdResult * @guid: the GUID, e.g. "2082b5e0-7a64-478a-b1b2-e3404fab6dad" * * Sets the GUID. * * Since: 0.7.0 **/ void fwupd_result_set_guid (FwupdResult *result, const gchar *guid) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); g_free (priv->guid); priv->guid = g_strdup (guid); } /** * fwupd_result_get_device_name: * @result: A #FwupdResult * * Gets the device name. * * Returns: the device name, or %NULL if unset * * Since: 0.7.0 **/ const gchar * fwupd_result_get_device_name (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), NULL); return priv->device_name; } /** * fwupd_result_set_device_name: * @result: A #FwupdResult * @device_name: the device update_name, e.g. "ColorHug2" * * Sets the device update_name. * * Since: 0.7.0 **/ void fwupd_result_set_device_name (FwupdResult *result, const gchar *device_name) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); g_free (priv->device_name); priv->device_name = g_strdup (device_name); } /** * fwupd_result_get_device_vendor: * @result: A #FwupdResult * * Gets the device vendor. * * Returns: the device vendor, or %NULL if unset * * Since: 0.7.0 **/ const gchar * fwupd_result_get_device_vendor (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), NULL); return priv->device_vendor; } /** * fwupd_result_set_device_vendor: * @result: A #FwupdResult * @device_vendor: the description * * Sets the device vendor. * * Since: 0.7.0 **/ void fwupd_result_set_device_vendor (FwupdResult *result, const gchar *device_vendor) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); g_free (priv->device_vendor); priv->device_vendor = g_strdup (device_vendor); } /** * fwupd_result_get_device_description: * @result: A #FwupdResult * * Gets the device description in AppStream markup format. * * Returns: the device description, or %NULL if unset * * Since: 0.7.0 **/ const gchar * fwupd_result_get_device_description (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), NULL); return priv->device_description; } /** * fwupd_result_set_device_description: * @result: A #FwupdResult * @device_description: the description in AppStream markup format * * Sets the device description. * * Since: 0.7.0 **/ void fwupd_result_set_device_description (FwupdResult *result, const gchar *device_description) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); g_free (priv->device_description); priv->device_description = g_strdup (device_description); } /** * fwupd_result_get_device_version: * @result: A #FwupdResult * * Gets the device version. * * Returns: the device version, or %NULL if unset * * Since: 0.7.0 **/ const gchar * fwupd_result_get_device_version (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), NULL); return priv->device_version; } /** * fwupd_result_set_device_version: * @result: A #FwupdResult * @device_version: the device version, e.g. "1.2.3" * * Sets the device version. * * Since: 0.7.0 **/ void fwupd_result_set_device_version (FwupdResult *result, const gchar *device_version) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); g_free (priv->device_version); priv->device_version = g_strdup (device_version); } /** * fwupd_result_get_update_version: * @result: A #FwupdResult * * Gets the update version. * * Returns: the update version, or %NULL if unset * * Since: 0.7.0 **/ const gchar * fwupd_result_get_update_version (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), NULL); return priv->update_version; } /** * fwupd_result_get_device_version_lowest: * @result: A #FwupdResult * * Gets the lowest version of firmware the device will accept. * * Returns: the device version_lowest, or %NULL if unset * * Since: 0.7.0 **/ const gchar * fwupd_result_get_device_version_lowest (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), NULL); return priv->device_version_lowest; } /** * fwupd_result_set_device_version_lowest: * @result: A #FwupdResult * @device_version_lowest: the description * * Sets the lowest version of firmware the device will accept. * * Since: 0.7.0 **/ void fwupd_result_set_device_version_lowest (FwupdResult *result, const gchar *device_version_lowest) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); g_free (priv->device_version_lowest); priv->device_version_lowest = g_strdup (device_version_lowest); } /** * fwupd_result_set_update_version: * @result: A #FwupdResult * @update_version: the update version, e.g. "1.2.4" * * Sets the update version. * * Since: 0.7.0 **/ void fwupd_result_set_update_version (FwupdResult *result, const gchar *update_version) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); g_free (priv->update_version); priv->update_version = g_strdup (update_version); } /** * fwupd_result_get_update_filename: * @result: A #FwupdResult * * Gets the update filename. * * Returns: the update filename, or %NULL if unset * * Since: 0.7.0 **/ const gchar * fwupd_result_get_update_filename (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), NULL); return priv->update_filename; } /** * fwupd_result_set_update_filename: * @result: A #FwupdResult * @update_filename: the update filename on disk * * Sets the update filename. * * Since: 0.7.0 **/ void fwupd_result_set_update_filename (FwupdResult *result, const gchar *update_filename) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); g_free (priv->update_filename); priv->update_filename = g_strdup (update_filename); } /** * fwupd_result_get_update_state: * @result: A #FwupdResult * * Gets the update state. * * Returns: the update state, or %FWUPD_UPDATE_STATE_UNKNOWN if unset * * Since: 0.7.0 **/ FwupdUpdateState fwupd_result_get_update_state (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), FWUPD_UPDATE_STATE_UNKNOWN); return priv->update_state; } /** * fwupd_result_set_update_state: * @result: A #FwupdResult * @update_state: the state, e.g. %FWUPD_UPDATE_STATE_PENDING * * Sets the update state. * * Since: 0.7.0 **/ void fwupd_result_set_update_state (FwupdResult *result, FwupdUpdateState update_state) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); priv->update_state = update_state; } /** * fwupd_result_get_update_checksum: * @result: A #FwupdResult * * Gets the update checksum. * * Returns: the update checksum, or %NULL if unset * * Since: 0.7.0 **/ const gchar * fwupd_result_get_update_checksum (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), NULL); return priv->update_checksum; } /** * fwupd_result_set_update_checksum: * @result: A #FwupdResult * @update_checksum: the update checksum * * Sets the update checksum. * * Since: 0.7.0 **/ void fwupd_result_set_update_checksum (FwupdResult *result, const gchar *update_checksum) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); g_free (priv->update_checksum); priv->update_checksum = g_strdup (update_checksum); } /** * fwupd_result_get_update_checksum_kind: * @result: A #FwupdResult * * Gets the update checkum kind. * * Returns: the #GChecksumType * * Since: 0.7.0 **/ GChecksumType fwupd_result_get_update_checksum_kind (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), 0); return priv->update_checksum_kind; } /** * fwupd_result_set_update_checksum_kind: * @result: A #FwupdResult * @checkum_kind: the checksum kind, e.g. %G_CHECKSUM_SHA1 * * Sets the update checkum kind. * * Since: 0.7.0 **/ void fwupd_result_set_update_checksum_kind (FwupdResult *result, GChecksumType checkum_kind) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); priv->update_checksum_kind = checkum_kind; } /** * fwupd_result_get_update_uri: * @result: A #FwupdResult * * Gets the update uri. * * Returns: the update uri, or %NULL if unset * * Since: 0.7.0 **/ const gchar * fwupd_result_get_update_uri (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), NULL); return priv->update_uri; } /** * fwupd_result_set_update_uri: * @result: A #FwupdResult * @update_uri: the update URI * * Sets the update uri, i.e. where you can download the firmware from. * * Since: 0.7.0 **/ void fwupd_result_set_update_uri (FwupdResult *result, const gchar *update_uri) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); g_free (priv->update_uri); priv->update_uri = g_strdup (update_uri); } /** * fwupd_result_get_update_homepage: * @result: A #FwupdResult * * Gets the update homepage. * * Returns: the update homepage, or %NULL if unset * * Since: 0.7.0 **/ const gchar * fwupd_result_get_update_homepage (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), NULL); return priv->update_homepage; } /** * fwupd_result_set_update_homepage: * @result: A #FwupdResult * @update_homepage: the description * * Sets the update homepage. * * Since: 0.7.0 **/ void fwupd_result_set_update_homepage (FwupdResult *result, const gchar *update_homepage) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); g_free (priv->update_homepage); priv->update_homepage = g_strdup (update_homepage); } /** * fwupd_result_get_update_description: * @result: A #FwupdResult * * Gets the update description in AppStream markup format. * * Returns: the update description, or %NULL if unset * * Since: 0.7.0 **/ const gchar * fwupd_result_get_update_description (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), NULL); return priv->update_description; } /** * fwupd_result_set_update_description: * @result: A #FwupdResult * @update_description: the update description in AppStream markup format * * Sets the update description. * * Since: 0.7.0 **/ void fwupd_result_set_update_description (FwupdResult *result, const gchar *update_description) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); g_free (priv->update_description); priv->update_description = g_strdup (update_description); } /** * fwupd_result_get_update_id: * @result: A #FwupdResult * * Gets the update id. * * Returns: the update id, or %NULL if unset * * Since: 0.7.0 **/ const gchar * fwupd_result_get_update_id (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), NULL); return priv->update_id; } /** * fwupd_result_set_update_id: * @result: A #FwupdResult * @update_id: the AppStream component ID, e.g. "org.hughski.ColorHug2.firmware" * * Sets the update id. * * Since: 0.7.0 **/ void fwupd_result_set_update_id (FwupdResult *result, const gchar *update_id) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); g_free (priv->update_id); priv->update_id = g_strdup (update_id); } /** * fwupd_result_get_update_size: * @result: A #FwupdResult * * Gets the update size. * * Returns: the update size in bytes, or 0 if unset * * Since: 0.7.0 **/ guint64 fwupd_result_get_update_size (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), 0); return priv->update_size; } /** * fwupd_result_set_update_size: * @result: A #FwupdResult * @update_size: the update size in bytes * * Sets the update size. * * Since: 0.7.0 **/ void fwupd_result_set_update_size (FwupdResult *result, guint64 update_size) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); priv->update_size = update_size; } /** * fwupd_result_get_device_checksum: * @result: A #FwupdResult * * Gets the device checksum. * * Returns: the device checksum, or %NULL if unset * * Since: 0.7.0 **/ const gchar * fwupd_result_get_device_checksum (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), NULL); return priv->device_checksum; } /** * fwupd_result_set_device_checksum: * @result: A #FwupdResult * @device_checksum: the device checksum * * Sets the device checksum, i.e. what is on the device right now. * * Since: 0.7.0 **/ void fwupd_result_set_device_checksum (FwupdResult *result, const gchar *device_checksum) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); g_free (priv->device_checksum); priv->device_checksum = g_strdup (device_checksum); } /** * fwupd_result_get_device_checksum_kind: * @result: A #FwupdResult * * Gets the device checkum kind. * * Returns: the #GChecksumType * * Since: 0.7.0 **/ GChecksumType fwupd_result_get_device_checksum_kind (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), 0); return priv->device_checksum_kind; } /** * fwupd_result_set_device_checksum_kind: * @result: A #FwupdResult * @checkum_kind: the checksum kind, e.g. %G_CHECKSUM_SHA1 * * Sets the device checkum kind. * * Since: 0.7.0 **/ void fwupd_result_set_device_checksum_kind (FwupdResult *result, GChecksumType checkum_kind) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); priv->device_checksum_kind = checkum_kind; } /** * fwupd_result_get_update_summary: * @result: A #FwupdResult * * Gets the update summary. * * Returns: the update summary, or %NULL if unset * * Since: 0.7.0 **/ const gchar * fwupd_result_get_update_summary (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), NULL); return priv->update_summary; } /** * fwupd_result_set_update_summary: * @result: A #FwupdResult * @update_summary: the update one line summary * * Sets the update summary. * * Since: 0.7.0 **/ void fwupd_result_set_update_summary (FwupdResult *result, const gchar *update_summary) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); g_free (priv->update_summary); priv->update_summary = g_strdup (update_summary); } /** * fwupd_result_get_device_provider: * @result: A #FwupdResult * * Gets the device provider. * * Returns: the device provider, or %NULL if unset * * Since: 0.7.0 **/ const gchar * fwupd_result_get_device_provider (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), NULL); return priv->device_provider; } /** * fwupd_result_set_device_provider: * @result: A #FwupdResult * @device_provider: the provider name, e.g. "colorhug" * * Sets the device provider. * * Since: 0.7.0 **/ void fwupd_result_set_device_provider (FwupdResult *result, const gchar *device_provider) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); g_free (priv->device_provider); priv->device_provider = g_strdup (device_provider); } /** * fwupd_result_get_update_error: * @result: A #FwupdResult * * Gets the update error. * * Returns: the update error, or %NULL if unset * * Since: 0.7.0 **/ const gchar * fwupd_result_get_update_error (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), NULL); return priv->update_error; } /** * fwupd_result_set_update_error: * @result: A #FwupdResult * @update_error: the update error string * * Sets the update error. * * Since: 0.7.0 **/ void fwupd_result_set_update_error (FwupdResult *result, const gchar *update_error) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); g_free (priv->update_error); priv->update_error = g_strdup (update_error); } /** * fwupd_result_get_update_trust_flags: * @result: A #FwupdResult * * Gets the update trust_flags. * * Returns: the #FwupdTrustFlags, or 0 if unset * * Since: 0.7.0 **/ FwupdTrustFlags fwupd_result_get_update_trust_flags (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), 0); return priv->update_trust_flags; } /** * fwupd_result_set_update_trust_flags: * @result: A #FwupdResult * @trust_flags: the trust flags, e.g. %FWUPD_TRUST_FLAG_PAYLOAD * * Sets the update trust_flags. * * Since: 0.7.0 **/ void fwupd_result_set_update_trust_flags (FwupdResult *result, FwupdTrustFlags trust_flags) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); priv->update_trust_flags = trust_flags; } /** * fwupd_result_get_update_vendor: * @result: A #FwupdResult * * Gets the update vendor. * * Returns: the update vendor, or %NULL if unset * * Since: 0.7.0 **/ const gchar * fwupd_result_get_update_vendor (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), NULL); return priv->update_vendor; } /** * fwupd_result_set_update_vendor: * @result: A #FwupdResult * @update_vendor: the vendor name, e.g. "Hughski Limited" * * Sets the update vendor. * * Since: 0.7.0 **/ void fwupd_result_set_update_vendor (FwupdResult *result, const gchar *update_vendor) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); g_free (priv->update_vendor); priv->update_vendor = g_strdup (update_vendor); } /** * fwupd_result_get_update_license: * @result: A #FwupdResult * * Gets the update license. * * Returns: the update license, or %NULL if unset * * Since: 0.7.0 **/ const gchar * fwupd_result_get_update_license (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), NULL); return priv->update_license; } /** * fwupd_result_set_update_license: * @result: A #FwupdResult * @update_license: the description * * Sets the update license. * * Since: 0.7.0 **/ void fwupd_result_set_update_license (FwupdResult *result, const gchar *update_license) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); g_free (priv->update_license); priv->update_license = g_strdup (update_license); } /** * fwupd_result_get_update_name: * @result: A #FwupdResult * * Gets the update name. * * Returns: the update name, or %NULL if unset * * Since: 0.7.0 **/ const gchar * fwupd_result_get_update_name (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), NULL); return priv->update_name; } /** * fwupd_result_set_update_name: * @result: A #FwupdResult * @update_name: the description * * Sets the update name. * * Since: 0.7.0 **/ void fwupd_result_set_update_name (FwupdResult *result, const gchar *update_name) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); g_free (priv->update_name); priv->update_name = g_strdup (update_name); } /** * fwupd_result_get_device_flags: * @result: A #FwupdResult * * Gets the device flags. * * Returns: the device flags, or 0 if unset * * Since: 0.7.0 **/ guint64 fwupd_result_get_device_flags (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), 0); return priv->device_flags; } /** * fwupd_result_set_device_flags: * @result: A #FwupdResult * @device_flags: the device flags, e.g. %FU_DEVICE_FLAG_REQUIRE_AC * * Sets the device flags. * * Since: 0.7.0 **/ void fwupd_result_set_device_flags (FwupdResult *result, guint64 device_flags) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); priv->device_flags = device_flags; } /** * fwupd_result_add_device_flag: * @result: A #FwupdResult * @flag: the #FwupdDeviceFlags * * Adds a specific device flag to the result. * * Since: 0.7.0 **/ void fwupd_result_add_device_flag (FwupdResult *result, FwupdDeviceFlags flag) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); priv->device_flags |= flag; } /** * fwupd_result_has_device_flag: * @result: A #FwupdResult * @flag: the #FwupdDeviceFlags * * Finds if the device has a specific device flag. * * Returns: %TRUE if the flag is set * * Since: 0.7.0 **/ gboolean fwupd_result_has_device_flag (FwupdResult *result, FwupdDeviceFlags flag) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), FALSE); return priv->device_flags & flag; } /** * fwupd_result_get_device_created: * @result: A #FwupdResult * * Gets when the result was device_created. * * Returns: the UNIX time, or 0 if unset * * Since: 0.7.0 **/ guint64 fwupd_result_get_device_created (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), 0); return priv->device_created; } /** * fwupd_result_set_device_created: * @result: A #FwupdResult * @device_created: the UNIX time * * Sets when the result was device_created. * * Since: 0.7.0 **/ void fwupd_result_set_device_created (FwupdResult *result, guint64 device_created) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); priv->device_created = device_created; } /** * fwupd_result_get_device_modified: * @result: A #FwupdResult * * Gets when the result was device_modified. * * Returns: the UNIX time, or 0 if unset * * Since: 0.7.0 **/ guint64 fwupd_result_get_device_modified (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_val_if_fail (FWUPD_IS_RESULT (result), 0); return priv->device_modified; } /** * fwupd_result_set_device_modified: * @result: A #FwupdResult * @device_modified: the UNIX time * * Sets when the result was device_modified. * * Since: 0.7.0 **/ void fwupd_result_set_device_modified (FwupdResult *result, guint64 device_modified) { FwupdResultPrivate *priv = GET_PRIVATE (result); g_return_if_fail (FWUPD_IS_RESULT (result)); priv->device_modified = device_modified; } /** * fwupd_result_to_data: * @result: A #FwupdResult * @type_string: The Gvariant type string, e.g. "{sa{sv}}" or "(a{sv})" * * Creates a GVariant from the result data. * * Returns: the GVariant, or %NULL for error * * Since: 0.7.0 **/ GVariant * fwupd_result_to_data (FwupdResult *result, const gchar *type_string) { FwupdResultPrivate *priv = GET_PRIVATE (result); GVariantBuilder builder; g_return_val_if_fail (FWUPD_IS_RESULT (result), NULL); g_return_val_if_fail (type_string != NULL, NULL); /* create an array with all the metadata in */ g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); if (priv->guid != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_GUID, g_variant_new_string (priv->guid)); } if (priv->device_name != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_DEVICE_NAME, g_variant_new_string (priv->device_name)); } if (priv->device_vendor != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_DEVICE_VENDOR, g_variant_new_string (priv->device_vendor)); } if (priv->device_flags > 0) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_DEVICE_FLAGS, g_variant_new_uint64 (priv->device_flags)); } if (priv->device_created > 0) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_DEVICE_CREATED, g_variant_new_uint64 (priv->device_created)); } if (priv->device_modified > 0) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_DEVICE_MODIFIED, g_variant_new_uint64 (priv->device_modified)); } if (priv->update_id != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_ID, g_variant_new_string (priv->update_id)); } if (priv->device_description != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_DEVICE_DESCRIPTION, g_variant_new_string (priv->device_description)); } if (priv->update_filename != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_FILENAME, g_variant_new_string (priv->update_filename)); } if (priv->device_checksum != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_DEVICE_CHECKSUM, g_variant_new_string (priv->device_checksum)); g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_DEVICE_CHECKSUM_KIND, g_variant_new_uint32 (priv->device_checksum_kind)); } if (priv->update_license != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_LICENSE, g_variant_new_string (priv->update_license)); } if (priv->update_name != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_NAME, g_variant_new_string (priv->update_name)); } if (priv->update_error != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_ERROR, g_variant_new_string (priv->update_error)); } if (priv->update_state != FWUPD_UPDATE_STATE_UNKNOWN) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_STATE, g_variant_new_uint32 (priv->update_state)); } if (priv->device_provider != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_DEVICE_PROVIDER, g_variant_new_string (priv->device_provider)); } if (priv->update_size != 0) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_SIZE, g_variant_new_uint64 (priv->update_size)); } if (priv->update_trust_flags != 0) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_TRUST_FLAGS, g_variant_new_uint64 (priv->update_trust_flags)); } if (priv->update_summary != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_SUMMARY, g_variant_new_string (priv->update_summary)); } if (priv->update_description != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_DESCRIPTION, g_variant_new_string (priv->update_description)); } if (priv->update_checksum != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_CHECKSUM, g_variant_new_string (priv->update_checksum)); g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_CHECKSUM_KIND, g_variant_new_uint32 (priv->update_checksum_kind)); } if (priv->update_uri != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_URI, g_variant_new_string (priv->update_uri)); } if (priv->update_homepage != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_HOMEPAGE, g_variant_new_string (priv->update_homepage)); } if (priv->update_version != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_VERSION, g_variant_new_string (priv->update_version)); } if (priv->update_vendor != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_VENDOR, g_variant_new_string (priv->update_vendor)); } if (priv->device_version != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_DEVICE_VERSION, g_variant_new_string (priv->device_version)); } if (priv->device_version_lowest != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_DEVICE_VERSION_LOWEST, g_variant_new_string (priv->device_version_lowest)); } /* supported types */ if (g_strcmp0 (type_string, "{sa{sv}}") == 0) return g_variant_new ("{sa{sv}}", priv->device_id, &builder); if (g_strcmp0 (type_string, "(a{sv})") == 0) return g_variant_new ("(a{sv})", &builder); return NULL; } /** * fwupd_result_from_kv: **/ static void fwupd_result_from_kv (FwupdResult *result, const gchar *key, GVariant *value) { if (g_strcmp0 (key, FWUPD_RESULT_KEY_DEVICE_FLAGS) == 0) { fwupd_result_set_device_flags (result, g_variant_get_uint64 (value)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_DEVICE_CREATED) == 0) { fwupd_result_set_device_created (result, g_variant_get_uint64 (value)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_DEVICE_MODIFIED) == 0) { fwupd_result_set_device_modified (result, g_variant_get_uint64 (value)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_GUID) == 0) { fwupd_result_set_guid (result, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_DEVICE_NAME) == 0) { fwupd_result_set_device_name (result, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_DEVICE_VENDOR) == 0) { fwupd_result_set_device_vendor (result, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_TRUST_FLAGS) == 0) { fwupd_result_set_update_trust_flags (result, g_variant_get_uint64 (value)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_ID) == 0) { fwupd_result_set_update_id (result, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_DEVICE_DESCRIPTION) == 0) { fwupd_result_set_device_description (result, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_FILENAME) == 0) { fwupd_result_set_update_filename (result, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_DEVICE_CHECKSUM) == 0) { fwupd_result_set_device_checksum (result, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_DEVICE_CHECKSUM_KIND) == 0) { fwupd_result_set_device_checksum_kind (result, g_variant_get_uint32 (value)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_LICENSE) == 0) { fwupd_result_set_update_license (result, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_NAME) == 0) { fwupd_result_set_update_name (result, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_ERROR) == 0) { fwupd_result_set_update_error (result, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_STATE) == 0) { /* old daemon version and new client */ if (g_strcmp0 (g_variant_get_type_string (value), "s") == 0) { FwupdUpdateState tmp; tmp = fwupd_update_state_from_string (g_variant_get_string (value, NULL)); fwupd_result_set_update_state (result, tmp); } else { fwupd_result_set_update_state (result, g_variant_get_uint32 (value)); } return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_DEVICE_PROVIDER) == 0) { fwupd_result_set_device_provider (result, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_SIZE) == 0) { fwupd_result_set_update_size (result, g_variant_get_uint64 (value)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_SUMMARY) == 0) { fwupd_result_set_update_summary (result, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_DESCRIPTION) == 0) { fwupd_result_set_update_description (result, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_CHECKSUM) == 0) { fwupd_result_set_update_checksum (result, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_CHECKSUM_KIND) == 0) { fwupd_result_set_update_checksum_kind (result, g_variant_get_uint32 (value)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_URI) == 0) { fwupd_result_set_update_uri (result, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_HOMEPAGE) == 0) { fwupd_result_set_update_homepage (result, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_VERSION) == 0) { fwupd_result_set_update_version (result, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_VENDOR) == 0) { fwupd_result_set_update_vendor (result, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_DEVICE_VERSION) == 0) { fwupd_result_set_device_version (result, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_DEVICE_VERSION_LOWEST) == 0) { fwupd_result_set_device_version_lowest (result, g_variant_get_string (value, NULL)); return; } } /** * fwupd_pad_kv_str: **/ static void fwupd_pad_kv_str (GString *str, const gchar *key, const gchar *value) { guint i; /* ignore */ if (key == NULL || value == NULL) return; g_string_append_printf (str, " %s: ", key); for (i = strlen (key); i < 20; i++) g_string_append (str, " "); g_string_append_printf (str, "%s\n", value); } /** * fwupd_pad_kv_unx: **/ static void fwupd_pad_kv_unx (GString *str, const gchar *key, guint64 value) { g_autoptr(GDateTime) date = NULL; g_autofree gchar *tmp = NULL; /* ignore */ if (value == 0) return; date = g_date_time_new_from_unix_utc (value); tmp = g_date_time_format (date, "%F"); fwupd_pad_kv_str (str, key, tmp); } /** * fwupd_pad_kv_ups: **/ static void fwupd_pad_kv_ups (GString *str, const gchar *key, FwupdUpdateState value) { if (value == FWUPD_UPDATE_STATE_UNKNOWN) return; fwupd_pad_kv_str (str, key, fwupd_update_state_to_string (value)); } /** * fwupd_pad_kv_siz: **/ static void fwupd_pad_kv_siz (GString *str, const gchar *key, guint64 value) { g_autofree gchar *tmp = NULL; /* ignore */ if (value == 0) return; tmp = g_format_size (value); fwupd_pad_kv_str (str, key, tmp); } /** * fwupd_pad_kv_dfl: **/ static void fwupd_pad_kv_dfl (GString *str, const gchar *key, guint64 device_flags) { guint i; g_autoptr(GString) tmp = NULL; tmp = g_string_new (""); for (i = 1; i < FU_DEVICE_FLAG_LAST; i *= 2) { if ((device_flags & i) == 0) continue; g_string_append_printf (tmp, "%s|", fwupd_device_flag_to_string (i)); } if (tmp->len == 0) { g_string_append (tmp, fwupd_device_flag_to_string (0)); } else { g_string_truncate (tmp, tmp->len - 1); } fwupd_pad_kv_str (str, key, tmp->str); } /** * fwupd_pad_kv_tfl: **/ static void fwupd_pad_kv_tfl (GString *str, const gchar *key, FwupdTrustFlags trust_flags) { guint i; g_autoptr(GString) tmp = NULL; tmp = g_string_new (""); for (i = 1; i < FWUPD_TRUST_FLAG_LAST; i *= 2) { if ((trust_flags & i) == 0) continue; g_string_append_printf (tmp, "%s|", fwupd_trust_flag_to_string (i)); } if (tmp->len == 0) { g_string_append (tmp, fwupd_trust_flag_to_string (0)); } else { g_string_truncate (tmp, tmp->len - 1); } fwupd_pad_kv_str (str, key, tmp->str); } /** * fwupd_pad_kv_csk: **/ static void fwupd_pad_kv_csk (GString *str, const gchar *key, GChecksumType checksum_type) { const gchar *tmp = "unknown"; if (checksum_type == G_CHECKSUM_SHA1) tmp = "sha1"; else if (checksum_type == G_CHECKSUM_SHA256) tmp = "sha256"; else if (checksum_type == G_CHECKSUM_SHA512) tmp = "sha512"; fwupd_pad_kv_str (str, key, tmp); } /** * fwupd_result_to_string: * @result: A #FwupdResult * * Builds a text representation of the object. * * Returns: text, or %NULL for invalid * * Since: 0.7.0 **/ gchar * fwupd_result_to_string (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); GString *str; g_return_val_if_fail (FWUPD_IS_RESULT (result), NULL); str = g_string_new (""); /* not set when using GetDetails */ if (priv->device_id != NULL) g_string_append_printf (str, "%s\n", priv->device_id); /* device */ fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_GUID, priv->guid); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DEVICE_NAME, priv->device_name); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DEVICE_DESCRIPTION, priv->device_description); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DEVICE_PROVIDER, priv->device_provider); fwupd_pad_kv_dfl (str, FWUPD_RESULT_KEY_DEVICE_FLAGS, priv->device_flags); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DEVICE_CHECKSUM, priv->device_checksum); if (priv->device_checksum != NULL) fwupd_pad_kv_csk (str, FWUPD_RESULT_KEY_DEVICE_CHECKSUM_KIND, priv->device_checksum_kind); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DEVICE_VENDOR, priv->device_vendor); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DEVICE_VERSION, priv->device_version); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DEVICE_VERSION_LOWEST, priv->device_version_lowest); fwupd_pad_kv_unx (str, FWUPD_RESULT_KEY_DEVICE_CREATED, priv->device_created); fwupd_pad_kv_unx (str, FWUPD_RESULT_KEY_DEVICE_MODIFIED, priv->device_modified); /* updates */ fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_ID, priv->update_id); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_NAME, priv->update_name); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_SUMMARY, priv->update_summary); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_DESCRIPTION, priv->update_description); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_VERSION, priv->update_version); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_FILENAME, priv->update_filename); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_CHECKSUM, priv->update_checksum); if (priv->update_checksum != NULL) fwupd_pad_kv_csk (str, FWUPD_RESULT_KEY_UPDATE_CHECKSUM_KIND, priv->update_checksum_kind); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_LICENSE, priv->update_license); fwupd_pad_kv_siz (str, FWUPD_RESULT_KEY_UPDATE_SIZE, priv->update_size); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_URI, priv->update_uri); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_HOMEPAGE, priv->update_homepage); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_VENDOR, priv->update_vendor); 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_tfl (str, FWUPD_RESULT_KEY_UPDATE_TRUST_FLAGS, priv->update_trust_flags); return g_string_free (str, FALSE); } /** * fwupd_result_get_property: **/ static void fwupd_result_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { FwupdResult *result = FWUPD_RESULT (object); FwupdResultPrivate *priv = GET_PRIVATE (result); switch (prop_id) { case PROP_DEVICE_ID: g_value_set_string (value, priv->device_id); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } /** * fwupd_result_set_property: **/ static void fwupd_result_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { FwupdResult *result = FWUPD_RESULT (object); FwupdResultPrivate *priv = GET_PRIVATE (result); switch (prop_id) { case PROP_DEVICE_ID: g_free (priv->device_id); priv->device_id = g_strdup (g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } /** * fwupd_result_class_init: **/ static void fwupd_result_class_init (FwupdResultClass *klass) { GParamSpec *pspec; GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = fwupd_result_finalize; object_class->get_property = fwupd_result_get_property; object_class->set_property = fwupd_result_set_property; /** * FwupdResult:device-id: * * The device ID for this result. * * Since: 0.7.0 */ pspec = g_param_spec_string ("device-id", NULL, NULL, NULL, G_PARAM_READWRITE); g_object_class_install_property (object_class, PROP_DEVICE_ID, pspec); } /** * fwupd_result_init: **/ static void fwupd_result_init (FwupdResult *result) { FwupdResultPrivate *priv = GET_PRIVATE (result); priv->device_checksum_kind = G_CHECKSUM_SHA1; priv->update_checksum_kind = G_CHECKSUM_SHA1; } /** * fwupd_result_finalize: **/ static void fwupd_result_finalize (GObject *object) { FwupdResult *result = FWUPD_RESULT (object); FwupdResultPrivate *priv = GET_PRIVATE (result); g_free (priv->device_description); g_free (priv->device_checksum); g_free (priv->device_id); g_free (priv->device_name); g_free (priv->device_vendor); g_free (priv->device_provider); g_free (priv->device_version); g_free (priv->device_version_lowest); g_free (priv->guid); g_free (priv->update_description); g_free (priv->update_error); g_free (priv->update_filename); g_free (priv->update_checksum); g_free (priv->update_id); g_free (priv->update_license); g_free (priv->update_name); g_free (priv->update_summary); g_free (priv->update_uri); g_free (priv->update_homepage); g_free (priv->update_vendor); g_free (priv->update_version); G_OBJECT_CLASS (fwupd_result_parent_class)->finalize (object); } /** * fwupd_result_from_variant_iter: **/ static void fwupd_result_from_variant_iter (FwupdResult *result, GVariantIter *iter) { GVariant *value; const gchar *key; while (g_variant_iter_next (iter, "{&sv}", &key, &value)) { fwupd_result_from_kv (result, key, value); g_variant_unref (value); } } /** * fwupd_result_new_from_data: * @data: a #GVariant * * Creates a new result using packed data. * * Returns: a new #FwupdResult, or %NULL if @data was invalid * * Since: 0.7.0 **/ FwupdResult * fwupd_result_new_from_data (GVariant *data) { FwupdResult *res = NULL; const gchar *id; const gchar *type_string; g_autoptr(GVariantIter) iter = NULL; /* format from GetDetails */ type_string = g_variant_get_type_string (data); if (g_strcmp0 (type_string, "(a{sv})") == 0) { res = fwupd_result_new (); g_variant_get (data, "(a{sv})", &iter); fwupd_result_from_variant_iter (res, iter); } else if (g_strcmp0 (type_string, "{sa{sv}}") == 0) { res = fwupd_result_new (); g_variant_get (data, "{&sa{sv}}", &id, &iter); fwupd_result_set_device_id (res, id); fwupd_result_from_variant_iter (res, iter); } else { g_warning ("type %s not known", type_string); } return res; } /** * fwupd_result_new: * * Creates a new result. * * Returns: a new #FwupdResult * * Since: 0.7.0 **/ FwupdResult * fwupd_result_new (void) { FwupdResult *result; result = g_object_new (FWUPD_TYPE_RESULT, NULL); return FWUPD_RESULT (result); } fwupd-0.7.0/libfwupd/fwupd-result.h000066400000000000000000000153521267747510300173130ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015-2016 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __FWUPD_RESULT_H #define __FWUPD_RESULT_H #include #include "fwupd-enums.h" G_BEGIN_DECLS #define FWUPD_TYPE_RESULT (fwupd_result_get_type ()) G_DECLARE_DERIVABLE_TYPE (FwupdResult, fwupd_result, FWUPD, RESULT, GObject) struct _FwupdResultClass { GObjectClass parent_class; /*< private >*/ void (*_fwupd_reserved1) (void); void (*_fwupd_reserved2) (void); void (*_fwupd_reserved3) (void); void (*_fwupd_reserved4) (void); void (*_fwupd_reserved5) (void); void (*_fwupd_reserved6) (void); void (*_fwupd_reserved7) (void); }; FwupdResult *fwupd_result_new (void); FwupdResult *fwupd_result_new_from_data (GVariant *data); /* device-specific */ const gchar *fwupd_result_get_guid (FwupdResult *result); void fwupd_result_set_guid (FwupdResult *result, const gchar *guid); const gchar *fwupd_result_get_device_id (FwupdResult *result); void fwupd_result_set_device_id (FwupdResult *result, const gchar *device_id); const gchar *fwupd_result_get_device_name (FwupdResult *result); void fwupd_result_set_device_name (FwupdResult *result, const gchar *device_name); const gchar *fwupd_result_get_device_description (FwupdResult *result); void fwupd_result_set_device_description (FwupdResult *result, const gchar *device_description); const gchar *fwupd_result_get_device_version (FwupdResult *result); void fwupd_result_set_device_version (FwupdResult *result, const gchar *device_version); const gchar *fwupd_result_get_device_version_lowest (FwupdResult *result); void fwupd_result_set_device_version_lowest (FwupdResult *result, const gchar *device_version_lowest); guint64 fwupd_result_get_device_flags (FwupdResult *result); void fwupd_result_set_device_flags (FwupdResult *result, guint64 device_flags); void fwupd_result_add_device_flag (FwupdResult *result, FwupdDeviceFlags flag); gboolean fwupd_result_has_device_flag (FwupdResult *result, FwupdDeviceFlags flag); guint64 fwupd_result_get_device_created (FwupdResult *result); void fwupd_result_set_device_created (FwupdResult *result, guint64 device_created); guint64 fwupd_result_get_device_modified (FwupdResult *result); void fwupd_result_set_device_modified (FwupdResult *result, guint64 device_modified); const gchar *fwupd_result_get_device_checksum (FwupdResult *result); void fwupd_result_set_device_checksum (FwupdResult *result, const gchar *device_checksum); GChecksumType fwupd_result_get_device_checksum_kind (FwupdResult *result); void fwupd_result_set_device_checksum_kind (FwupdResult *result, GChecksumType checkum_kind); const gchar *fwupd_result_get_device_provider (FwupdResult *result); void fwupd_result_set_device_provider (FwupdResult *result, const gchar *device_provider); const gchar *fwupd_result_get_device_vendor (FwupdResult *result); void fwupd_result_set_device_vendor (FwupdResult *result, const gchar *device_vendor); /* update-specific */ guint64 fwupd_result_get_update_size (FwupdResult *result); void fwupd_result_set_update_size (FwupdResult *result, guint64 update_size); const gchar *fwupd_result_get_update_version (FwupdResult *result); void fwupd_result_set_update_version (FwupdResult *result, const gchar *update_version); const gchar *fwupd_result_get_update_filename (FwupdResult *result); void fwupd_result_set_update_filename (FwupdResult *result, const gchar *update_filename); FwupdUpdateState fwupd_result_get_update_state (FwupdResult *result); void fwupd_result_set_update_state (FwupdResult *result, FwupdUpdateState update_state); const gchar *fwupd_result_get_update_checksum (FwupdResult *result); void fwupd_result_set_update_checksum (FwupdResult *result, const gchar *update_checksum); GChecksumType fwupd_result_get_update_checksum_kind (FwupdResult *result); void fwupd_result_set_update_checksum_kind (FwupdResult *result, GChecksumType checkum_kind); const gchar *fwupd_result_get_update_uri (FwupdResult *result); void fwupd_result_set_update_uri (FwupdResult *result, const gchar *update_uri); const gchar *fwupd_result_get_update_homepage (FwupdResult *result); void fwupd_result_set_update_homepage (FwupdResult *result, const gchar *update_homepage); const gchar *fwupd_result_get_update_id (FwupdResult *result); void fwupd_result_set_update_id (FwupdResult *result, const gchar *update_id); const gchar *fwupd_result_get_update_description (FwupdResult *result); void fwupd_result_set_update_description (FwupdResult *result, const gchar *update_description); const gchar *fwupd_result_get_update_vendor (FwupdResult *result); void fwupd_result_set_update_vendor (FwupdResult *result, const gchar *update_vendor); const gchar *fwupd_result_get_update_summary (FwupdResult *result); void fwupd_result_set_update_summary (FwupdResult *result, const gchar *update_summary); const gchar *fwupd_result_get_update_error (FwupdResult *result); void fwupd_result_set_update_error (FwupdResult *result, const gchar *update_error); FwupdTrustFlags fwupd_result_get_update_trust_flags (FwupdResult *result); void fwupd_result_set_update_trust_flags (FwupdResult *result, FwupdTrustFlags trust_flags); const gchar *fwupd_result_get_update_license (FwupdResult *result); void fwupd_result_set_update_license (FwupdResult *result, const gchar *update_license); const gchar *fwupd_result_get_update_name (FwupdResult *result); void fwupd_result_set_update_name (FwupdResult *result, const gchar *update_name); /* helpers */ GVariant *fwupd_result_to_data (FwupdResult *result, const gchar *type_string); gchar *fwupd_result_to_string (FwupdResult *result); G_END_DECLS #endif /* __FWUPD_RESULT_H */ fwupd-0.7.0/libfwupd/fwupd-self-test.c000066400000000000000000000154651267747510300177030ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2016 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include "fwupd-client.h" #include "fwupd-enums.h" #include "fwupd-error.h" #include "fwupd-result.h" /** * as_test_compare_lines: **/ static gboolean as_test_compare_lines (const gchar *txt1, const gchar *txt2, GError **error) { g_autofree gchar *output = NULL; /* exactly the same */ if (g_strcmp0 (txt1, txt2) == 0) return TRUE; /* matches a pattern */ if (fnmatch (txt2, txt1, FNM_NOESCAPE) == 0) return TRUE; /* save temp files and diff them */ if (!g_file_set_contents ("/tmp/a", txt1, -1, error)) return FALSE; if (!g_file_set_contents ("/tmp/b", txt2, -1, error)) return FALSE; if (!g_spawn_command_line_sync ("diff -urNp /tmp/b /tmp/a", &output, NULL, NULL, error)) return FALSE; /* just output the diff */ g_set_error_literal (error, 1, 0, output); return FALSE; } static void fwupd_enums_func (void) { const gchar *tmp; guint i; /* enums */ for (i = 0; i < FWUPD_ERROR_LAST; i++) { tmp = fwupd_error_to_string (i); g_assert_cmpstr (tmp, !=, NULL); g_assert_cmpint (fwupd_error_from_string (tmp), ==, i); } for (i = 0; i < FWUPD_STATUS_LAST; i++) { tmp = fwupd_status_to_string (i); g_assert_cmpstr (tmp, !=, NULL); g_assert_cmpint (fwupd_status_from_string (tmp), ==, i); } for (i = 0; i < FWUPD_UPDATE_STATE_LAST; i++) { tmp = fwupd_update_state_to_string (i); g_assert_cmpstr (tmp, !=, NULL); g_assert_cmpint (fwupd_update_state_from_string (tmp), ==, i); } for (i = 0; i < FWUPD_TRUST_FLAG_LAST; i++) { tmp = fwupd_trust_flag_to_string (i); g_assert_cmpstr (tmp, !=, NULL); g_assert_cmpint (fwupd_trust_flag_from_string (tmp), ==, i); } /* bitfield */ for (i = 1; i < FU_DEVICE_FLAG_LAST; i *= 2) { tmp = fwupd_device_flag_to_string (i); g_assert_cmpstr (tmp, !=, NULL); g_assert_cmpint (fwupd_device_flag_from_string (tmp), ==, i); } } static void fwupd_result_func (void) { gboolean ret; g_autofree gchar *str = NULL; g_autoptr(FwupdResult) result = NULL; g_autoptr(GError) error = NULL; /* create dummy object */ result = fwupd_result_new (); fwupd_result_set_device_checksum (result, "beefdead"); fwupd_result_set_device_checksum_kind (result, G_CHECKSUM_SHA256); fwupd_result_set_device_created (result, 1); fwupd_result_set_device_flags (result, FU_DEVICE_FLAG_ALLOW_OFFLINE); fwupd_result_set_device_id (result, "USB:foo"); fwupd_result_set_device_modified (result, 60 * 60 * 24); fwupd_result_set_device_name (result, "ColorHug2"); fwupd_result_set_guid (result, "2082b5e0-7a64-478a-b1b2-e3404fab6dad"); fwupd_result_set_update_checksum (result, "deadbeef"); fwupd_result_set_update_description (result, "

Hi there!

"); fwupd_result_set_update_filename (result, "firmware.bin"); fwupd_result_set_update_id (result, "org.dave.ColorHug.firmware"); fwupd_result_set_update_size (result, 1024); fwupd_result_set_update_uri (result, "http://foo.com"); fwupd_result_add_device_flag (result, FU_DEVICE_FLAG_REQUIRE_AC); fwupd_result_set_update_trust_flags (result, FWUPD_TRUST_FLAG_PAYLOAD); str = fwupd_result_to_string (result); g_print ("\n%s", str); ret = as_test_compare_lines (str, "USB:foo\n" " Guid: 2082b5e0-7a64-478a-b1b2-e3404fab6dad\n" " DisplayName: ColorHug2\n" " Flags: allow-offline|require-ac\n" " FirmwareHash: beefdead\n" " DeviceChecksumKind: sha256\n" " Created: 1970-01-01\n" " Modified: 1970-01-02\n" " AppstreamId: org.dave.ColorHug.firmware\n" " UpdateDescription:

Hi there!

\n" " FilenameCab: firmware.bin\n" " UpdateHash: deadbeef\n" " UpdateChecksumKind: sha1\n" " Size: 1.0 kB\n" " UpdateUri: http://foo.com\n" " Trusted: payload\n", &error); g_assert_no_error (error); g_assert (ret); } static void fwupd_client_devices_func (void) { FwupdResult *res; g_autoptr(FwupdClient) client = NULL; g_autoptr(GPtrArray) array = NULL; g_autoptr(GError) error = NULL; client = fwupd_client_new (); array = fwupd_client_get_devices (client, NULL, &error); if (array == NULL && g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO)) return; g_assert_no_error (error); g_assert (array != NULL); g_assert_cmpint (array->len, >, 0); /* check device */ res = g_ptr_array_index (array, 0); g_assert (FWUPD_IS_RESULT (res)); g_assert_cmpstr (fwupd_result_get_guid (res), !=, NULL); g_assert_cmpstr (fwupd_result_get_device_id (res), !=, NULL); } static void fwupd_client_updates_func (void) { FwupdResult *res; g_autoptr(FwupdClient) client = NULL; g_autoptr(GPtrArray) array = NULL; g_autoptr(GError) error = NULL; client = fwupd_client_new (); array = fwupd_client_get_updates (client, NULL, &error); if (array == NULL && g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO)) return; g_assert_no_error (error); g_assert (array != NULL); g_assert_cmpint (array->len, >, 0); /* check device */ res = g_ptr_array_index (array, 0); g_assert (FWUPD_IS_RESULT (res)); g_assert_cmpstr (fwupd_result_get_guid (res), !=, NULL); g_assert_cmpstr (fwupd_result_get_device_id (res), !=, NULL); } static gboolean fwupd_has_system_bus (void) { g_autoptr(GDBusConnection) conn = NULL; conn = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL); if (conn != NULL) return TRUE; g_debug ("D-Bus system bus unavailable, skipping tests."); return FALSE; } 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/enums", fwupd_enums_func); g_test_add_func ("/fwupd/result", fwupd_result_func); if (fwupd_has_system_bus ()) { g_test_add_func ("/fwupd/client{devices}", fwupd_client_devices_func); g_test_add_func ("/fwupd/client{updates}", fwupd_client_updates_func); } return g_test_run (); } fwupd-0.7.0/libfwupd/fwupd-version.h.in000066400000000000000000000043261267747510300200660ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * SECTION:fwupd-version * @short_description: Obtains the version for the installed fwupd * * These compile time macros allow the user to enable parts of client code * depending on the version of libfwupd installed. */ #if !defined (__FWUPD_H_INSIDE__) && !defined (FWUPD_COMPILATION) #error "Only can be included directly." #endif #ifndef __FWUPD_VERSION_H #define __FWUPD_VERSION_H /** * FWUPD_MAJOR_VERSION: * * The compile-time major version */ #define FWUPD_MAJOR_VERSION (@FWUPD_MAJOR_VERSION@) /** * FWUPD_MINOR_VERSION: * * The compile-time minor version */ #define FWUPD_MINOR_VERSION (@FWUPD_MINOR_VERSION@) /** * FWUPD_MICRO_VERSION: * * The compile-time micro version */ #define FWUPD_MICRO_VERSION (@FWUPD_MICRO_VERSION@) /** * FWUPD_CHECK_VERSION: * @major: Major version number * @minor: Minor version number * @micro: Micro version number * * Check whether a fwupd version equal to or greater than * major.minor.micro. */ #define FWUPD_CHECK_VERSION(major,minor,micro) \ (FWUPD_MAJOR_VERSION > (major) || \ (FWUPD_MAJOR_VERSION == (major) && FWUPD_MINOR_VERSION > (minor)) || \ (FWUPD_MAJOR_VERSION == (major) && FWUPD_MINOR_VERSION == (minor) && \ FWUPD_MICRO_VERSION >= (micro))) #endif /* __FWUPD_VERSION_H */ fwupd-0.7.0/libfwupd/fwupd.h000066400000000000000000000024671267747510300160020ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * SECTION:fwupd * @short_description: Helper objects for accessing fwupd */ #ifndef __FWUPD_H__ #define __FWUPD_H__ #define __FWUPD_H_INSIDE__ #include #include #include #include #include #undef __FWUPD_H_INSIDE__ #endif /* __FWUPD_H__ */ fwupd-0.7.0/libfwupd/fwupd.pc.in000066400000000000000000000004321267747510300165500ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: fwupd Description: fwupd is a system daemon for installing device firmware Version: @VERSION@ Requires: glib-2.0, gobject-2.0, gio-2.0 Libs: -L${libdir} -lfwupd Cflags: -I${includedir}/fwupd-1 fwupd-0.7.0/m4/000077500000000000000000000000001267747510300131775ustar00rootroot00000000000000fwupd-0.7.0/m4/.gitignore000066400000000000000000000000051267747510300151620ustar00rootroot00000000000000*.m4 fwupd-0.7.0/m4/as-linguas.m4000066400000000000000000000014661267747510300155130ustar00rootroot00000000000000# Set ALL_ALL_LINGUAS based on the .po files present. Optional argument is the # name of the po directory. $podir/LINGUAS.ignore can be used to ignore a # subset of the po files. AC_DEFUN([AS_ALL_LINGUAS], [ AC_MSG_CHECKING([for linguas]) podir="m4_default([$1],[$srcdir/po])" linguas=`cd $podir && ls *.po 2>/dev/null | awk 'BEGIN { FS="."; ORS=" " } { print $[]1 }'` if test -f "$podir/LINGUAS.ignore"; then ALL_LINGUAS=""; ignore_linguas=`sed -n -e 's/^\s\+\|\s\+$//g' -e '/^#/b' -e '/\S/!b' \ -e 's/\s\+/\n/g' -e p "$podir/LINGUAS.ignore"`; for lang in $linguas; do if ! echo "$ignore_linguas" | grep -q "^${lang}$"; then ALL_LINGUAS="$ALL_LINGUAS $lang"; fi; done; else ALL_LINGUAS="$linguas"; fi; AC_SUBST([ALL_LINGUAS]) AC_MSG_RESULT($ALL_LINGUAS) ]) fwupd-0.7.0/m4/ax_check_compile_flag.m4000066400000000000000000000062511267747510300177130ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) # # DESCRIPTION # # Check whether the given FLAG works with the current language's compiler # or gives an error. (Warnings, however, are ignored) # # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on # success/failure. # # If EXTRA-FLAGS is defined, it is added to the current language's default # flags (e.g. CFLAGS) when the check is done. The check is thus made with # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 2 AC_DEFUN([AX_CHECK_COMPILE_FLAG], [AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_COMPILE_FLAGS fwupd-0.7.0/m4/ax_check_link_flag.m4000066400000000000000000000057601267747510300172240ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) # # DESCRIPTION # # Check whether the given FLAG works with the linker or gives an error. # (Warnings, however, are ignored) # # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on # success/failure. # # If EXTRA-FLAGS is defined, it is added to the linker's default flags # when the check is done. The check is thus made with the flags: "LDFLAGS # EXTRA-FLAGS FLAG". This can for example be used to force the linker to # issue an error when a bad flag is given. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 2 AC_DEFUN([AX_CHECK_LINK_FLAG], [AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [ ax_check_save_flags=$LDFLAGS LDFLAGS="$LDFLAGS $4 $1" AC_LINK_IFELSE([AC_LANG_PROGRAM()], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) LDFLAGS=$ax_check_save_flags]) AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_LINK_FLAGS fwupd-0.7.0/po/000077500000000000000000000000001267747510300132755ustar00rootroot00000000000000fwupd-0.7.0/po/.gitignore000066400000000000000000000001571267747510300152700ustar00rootroot00000000000000*.gmo *.header .intltool-merge-cache Makefile.in.in Makevars.template POTFILES Rules-quot *.sed *.sin stamp-it fwupd-0.7.0/po/POTFILES.in000066400000000000000000000001441267747510300150510ustar00rootroot00000000000000policy/org.freedesktop.fwupd.policy.in libdfu/dfu-tool.c src/fu-debug.c src/fu-main.c src/fu-util.c fwupd-0.7.0/po/cs.po000066400000000000000000000312131267747510300142420ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Translators: # Marek ÄŒernocký , 2016 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-04-01 14:38+0100\n" "PO-Revision-Date: 2016-04-01 13:38+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Czech (http://www.transifex.com/hughsie/fwupd/language/cs/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: cs\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" msgid "Install signed system firmware" msgstr "Instalace podepsaného systémového firmwaru" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on this machine" msgstr "K aktualizaci firmwaru na tomto poÄítaÄi je vyžadováno ověření" msgid "Install unsigned system firmware" msgstr "Instalace nepodepsaného systémového firmwaru" msgid "Install old version of system firmware" msgstr "Instalace starší verze systémového firmwaru" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" msgstr "K ponížení verze firmwaru na tomto poÄítaÄi je vyžadováno ověření" msgid "Install signed device firmware" msgstr "Instalace podepsaného firmwaru zařízení" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to update the firmware on a removable device" msgstr "K aktualizaci firmwaru na výmÄ›nném zařízení je vyžadováno ověření" msgid "Install unsigned device firmware" msgstr "Instalace nepodepsaného firmwaru zařízení" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to downgrade the firmware on a removable device" msgstr "K ponížení verze firmwaru na výmÄ›nném zařízení je vyžadováno ověření" msgid "Unlock the device to allow access" msgstr "Odemknutí zařízení pro umožnÄ›ní přístupu" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" msgstr "Pro odemknutí zařízení je požadováno ověření" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" msgstr "Alias pro %s" #. TRANSLATORS: error message msgid "Command not found" msgstr "Příkaz nebyl nalezen" #. TRANSLATORS: when an action has completed msgid "OK" msgstr "V pořádku" #. TRANSLATORS: when moving from runtime to DFU mode msgid "Detaching" msgstr "Odpojuje se" #. TRANSLATORS: when moving from DFU to runtime mode msgid "Attaching" msgstr "Napojuje se" #. TRANSLATORS: when copying from host to device msgid "Downloading" msgstr "Stahuje se" #. TRANSLATORS: when copying from device to host msgid "Uploading" msgstr "Nahrává se" #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "PÅ™idáno" #. TRANSLATORS: this is when a device is hotplugged msgid "Removed" msgstr "Odebráno" #. TRANSLATORS: this is when a device is hotplugged msgid "Changed" msgstr "ZmÄ›nÄ›no" #. TRANSLATORS: this is when a device ctrl+c's a watch msgid "Cancelled" msgstr "ZruÅ¡eno" #. TRANSLATORS: Appstream ID for the hardware type msgid "ID" msgstr "ID" #. TRANSLATORS: interface name, e.g. "Flash" msgid "Name" msgstr "Název" #. TRANSLATORS: this is the encryption method used when writing msgid "Cipher" msgstr "Å ifra" #. TRANSLATORS: these are areas of memory on the chip msgid "Region" msgstr "Oblast" #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Nalezeno" #. TRANSLATORS: probably not run as root... #. TRANSLATORS: device has failed to report status #. TRANSLATORS: device status, e.g. "OK" msgid "Status" msgstr "Stav" msgid "Unknown: permission denied" msgstr "Neznámý: odepÅ™en přístup" #. TRANSLATORS: device mode, e.g. runtime or DFU msgid "Mode" msgstr "Režim" #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Stav" #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" msgstr "Zvláštní požadavky" #. TRANSLATORS: command description msgid "Convert firmware to DFU format" msgstr "PÅ™evést firmware do formátu DFU" #. TRANSLATORS: command description msgid "Merge multiple firmware files into one" msgstr "SlouÄit více firmwarů do jednoho" #. TRANSLATORS: command description msgid "Set vendor ID on firmware file" msgstr "Nastavit ID výrobce v souboru s firmwarem" #. TRANSLATORS: command description msgid "Set product ID on firmware file" msgstr "Nastavit ID produktu v souboru s firmwarem" #. TRANSLATORS: command description msgid "Set release version on firmware file" msgstr "Nastavit verzi vydání v souboru s firmwarem" #. TRANSLATORS: command description msgid "Set alternative number on firmware file" msgstr "Nastavit alternativní Äíslo v souboru s firmwarem" #. TRANSLATORS: command description msgid "Set alternative name on firmware file" msgstr "Nastavit alternativní název v souboru s firmwarem" #. TRANSLATORS: command description msgid "Attach DFU capable device back to runtime" msgstr "Napojit zařízení podporující DFU zpÄ›t do bÄ›hového režimu" #. TRANSLATORS: command description msgid "Read firmware from device into a file" msgstr "PÅ™eÄíst firmware ze zařízení do souboru" #. TRANSLATORS: command description msgid "Read firmware from one partition into a file" msgstr "PÅ™eÄíst firmware z jednoho oddílu do souboru" #. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "Zapsat firmware ze souboru do zařízení" #. TRANSLATORS: command description msgid "Write firmware from file into one partition" msgstr "Zapsat firmware ze souboru do jednoho oddílu" #. TRANSLATORS: command description msgid "List currently attached DFU capable devices" msgstr "Vypsat právÄ› napojená zařízení podporující DFU" #. TRANSLATORS: command description msgid "Detach currently attached DFU capable device" msgstr "Odpojit aktuálnÄ› napojené zařízení podporující DFU" #. TRANSLATORS: command description msgid "Dump details about a firmware file" msgstr "Vypsat podrobnosti o souboru s firmwarem" #. TRANSLATORS: command description msgid "Watch DFU devices being hotplugged" msgstr "Sledovat pÅ™ipojení zařízení podporujících DFU" #. TRANSLATORS: command description msgid "Encrypt firmware data" msgstr "ZaÅ¡ifrovat data firmwaru" #. TRANSLATORS: command description msgid "Decrypt firmware data" msgstr "DeÅ¡ifrovat data firmwaru" #. TRANSLATORS: command description msgid "Sets metadata on a firmware file" msgstr "Nastavit metadata v souboru s firmwarem" #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "Nástroj pro práci s DFU" #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Selhalo zpracování argumentů" #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Zobrazovat ladicí informace pro vÅ¡echny soubory" #. TRANSLATORS: for the --verbose arg msgid "Debugging Options" msgstr "Volby ladÄ›ní" #. TRANSLATORS: for the --verbose arg msgid "Show debugging options" msgstr "Zobrazit volby ladÄ›ní" #. TRANSLATORS: exit after we've started up, used for user profiling msgid "Exit after a small delay" msgstr "SkonÄit po krátké prodlevÄ›" #. TRANSLATORS: exit straight away, used for automatic profiling msgid "Exit after the engine has loaded" msgstr "SkonÄit po naÄtení výkonné Äásti" #. TRANSLATORS: program name msgid "Firmware Update Daemon" msgstr "Démon pro aktualizaci firmwaru" #. TRANSLATORS: program summary msgid "Firmware Update D-Bus Service" msgstr "Služba D-Bus pro aktualizaci firmwaru" #. TRANSLATORS: daemon is inactive msgid "Idle" msgstr "NeÄinný" #. TRANSLATORS: decompressing the firmware file msgid "Decompressing firmware" msgstr "Dekomprimuje se firmware" #. TRANSLATORS: parsing the firmware information msgid "Loading firmware" msgstr "Nahrává se firmware" #. TRANSLATORS: restarting the device to pick up new F/W msgid "Restarting device" msgstr "Restartuje se zařízení" #. TRANSLATORS: writing to the flash chips msgid "Writing firmware to device" msgstr "Zapisuje se firmware do zařízení" #. TRANSLATORS: verifying we wrote the firmware correctly msgid "Verifying firmware from device" msgstr "Ověřuje se firmware ze zařízení" #. TRANSLATORS: scheduing an update to be done on the next boot msgid "Scheduling upgrade" msgstr "Plánuje se povýšení" #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "Nebylo nalezeno žádné zařízení schopné aktualizace firmwaru" #. TRANSLATOR: the provider only supports offline msgid "Retrying as an offline update" msgstr "Zkouší se znova jako aktualizace off-line" #. 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 "PÅ™einstalovává se %s na %s…" #. 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 "Ponižuje se %s z verze %s na %s…" #. 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 "Aktualizuje se %s z verze %s na %s…" msgid "Done!" msgstr "Hotovo!" #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" msgstr "%s má aktualizace firmwaru:" #. TRANSLATORS: a GUID for the hardware msgid "GUID" msgstr "GUID" #. TRANSLATORS: section header for firmware version msgid "Version" msgstr "Verze" #. TRANSLATORS: section header for firmware checksum msgid "Checksum" msgstr "Kontrolní souÄet" msgid "Checksum Type" msgstr "" #. TRANSLATORS: section header for firmware remote http:// msgid "Location" msgstr "UmístÄ›ní" #. TRANSLATORS: section header for long firmware desc msgid "Description" msgstr "Popis" #. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "Zobrazovat doplňující informace pro ladÄ›ní" #. TRANSLATORS: command line option msgid "Perform the installation offline where possible" msgstr "Pokud je to možné, provést instalaci off-line" #. TRANSLATORS: command line option msgid "Allow re-installing existing firmware versions" msgstr "Povolit reinstalaci stávající verze firmwaru" #. TRANSLATORS: command line option msgid "Allow downgrading firmware versions" msgstr "Povolit ponížení verze firmwaru" #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Zjistit vÅ¡echna zařízení podporující aktualizaci firmwaru" #. TRANSLATORS: command description msgid "Install prepared updates now" msgstr "Nainstalovat pÅ™ipravené aktualizace nyní" #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "Nainstalovat soubor s firmwarem na tento hardware" #. TRANSLATORS: command description msgid "Gets details about a firmware file" msgstr "Vypsat podrobnosti o souboru s firmwarem" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "Vypsat seznam aktualizací pro pÅ™ipojený hardware" #. TRANSLATORS: command description msgid "Updates all firmware to latest versions available" msgstr "Aktualizovat vÅ¡echen firmware na nejnovÄ›jší dostupné verze" #. TRANSLATORS: command description msgid "Gets the cryptographic hash of the dumped firmware" msgstr "Získat kryptografický otisk vypsaného firmwaru" #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Odemknout zařízení pro přístup k firmwaru" #. TRANSLATORS: command description msgid "Clears the results from the last update" msgstr "Smazat výsledky z poslední aktualizace" #. TRANSLATORS: command description msgid "Gets the results from the last update" msgstr "Vypsat výsledky z poslední aktualizace" #. TRANSLATORS: command description msgid "Refresh metadata from remote server" msgstr "Aktualizovat metadata ze vzdáleného serveru" #. TRANSLATORS: command description msgid "Dump the ROM checksum" msgstr "Vypsat kontrolní souÄet ROM" #. TRANSLATORS: command description msgid "Update the stored metadata with current ROM contents" msgstr "Aktualizovat uložená metadata pomocí aktuálního obsahu ROM" #. TRANSLATORS: program name msgid "Firmware Utility" msgstr "Nástroj pro práci s firmwarem" fwupd-0.7.0/po/de.po000066400000000000000000000313451267747510300142330ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Translators: # Marco Tedaldi , 2015 # Wolfgang Stöggl , 2015 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-04-01 14:38+0100\n" "PO-Revision-Date: 2016-04-01 13:38+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: German (http://www.transifex.com/hughsie/fwupd/language/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: de\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgid "Install signed system firmware" msgstr "Signierte System-Firmware installieren" #. 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" msgid "Install unsigned system firmware" msgstr "Nicht-signierte System-Firmware installieren" msgid "Install old version of system firmware" msgstr "Alte Version der System-Firmware installieren" #. 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" msgid "Install signed device firmware" msgstr "Signierte Geräte-Firmware installieren" #. 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" msgid "Install unsigned device firmware" msgstr "Nicht-signierte Geräte-Firmware installieren" #. 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" msgid "Unlock the device to allow access" msgstr "" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" msgstr "" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" msgstr "Verweis auf %s" #. TRANSLATORS: error message msgid "Command not found" msgstr "Befehl nicht gefunden" #. TRANSLATORS: when an action has completed msgid "OK" msgstr "Ok" #. TRANSLATORS: when moving from runtime to DFU mode msgid "Detaching" msgstr "Entfernen" #. TRANSLATORS: when moving from DFU to runtime mode msgid "Attaching" msgstr "Einhängen" #. TRANSLATORS: when copying from host to device msgid "Downloading" msgstr "Herunterladen" #. TRANSLATORS: when copying from device to host msgid "Uploading" msgstr "Hochladen" #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Hinzugefügt" #. TRANSLATORS: this is when a device is hotplugged msgid "Removed" msgstr "Entfernt" #. TRANSLATORS: this is when a device is hotplugged msgid "Changed" msgstr "Geändert" #. TRANSLATORS: this is when a device ctrl+c's a watch msgid "Cancelled" msgstr "Abgebrochen" #. TRANSLATORS: Appstream ID for the hardware type msgid "ID" msgstr "Kennung" #. TRANSLATORS: interface name, e.g. "Flash" msgid "Name" msgstr "Name" #. TRANSLATORS: this is the encryption method used when writing msgid "Cipher" msgstr "Verschlüsselungsverfahren" #. TRANSLATORS: these are areas of memory on the chip msgid "Region" msgstr "Bereich" #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Gefunden" #. TRANSLATORS: probably not run as root... #. TRANSLATORS: device has failed to report status #. TRANSLATORS: device status, e.g. "OK" msgid "Status" msgstr "Status" msgid "Unknown: permission denied" msgstr "Unbekannt: Zugriff verweigert" #. TRANSLATORS: device mode, e.g. runtime or DFU msgid "Mode" msgstr "Modus" #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Zustand" #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" msgstr "Macken" #. TRANSLATORS: command description msgid "Convert firmware to DFU format" msgstr "Firmware in das DFU-Format konvertieren" #. TRANSLATORS: command description msgid "Merge multiple firmware files into one" msgstr "Mehrere Firmware-Dateien in eine zusammenführen" #. TRANSLATORS: command description msgid "Set vendor ID on firmware file" msgstr "Hersteller-Kennung einer Firmware-Datei festlegen" #. TRANSLATORS: command description msgid "Set product ID on firmware file" msgstr "Produkt-Kennung einer Firmware-Datei festlegen" #. TRANSLATORS: command description msgid "Set release version on firmware file" msgstr "Veröffentlichungsversion einer Firmware-Datei festlegen" #. TRANSLATORS: command description msgid "Set alternative number on firmware file" msgstr "Alternative Nummer einer Firmware-Datei festlegen" #. TRANSLATORS: command description msgid "Set alternative name on firmware file" msgstr "Alternativen Namen einer Firmware-Datei festlegen" #. 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: command description msgid "Read firmware from device into a file" msgstr "Firmware von Gerät in Datei schreiben" #. TRANSLATORS: command description msgid "Read firmware from one partition into a file" msgstr "Firmware von einzelner Partition in Datei lesen" #. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "Firmware von Datei auf Gerät schreiben" #. TRANSLATORS: command description msgid "Write firmware from file into one partition" msgstr "Firmware aus Datei in einzelne Partition schreiben" #. TRANSLATORS: command description msgid "List currently attached DFU capable devices" msgstr "Derzeit angeschlossene DFU-fähige Geräte auflisten" #. TRANSLATORS: command description msgid "Detach currently attached DFU capable device" msgstr "Derzeit eingehängtes DFU-fähiges Gerät entfernen" #. TRANSLATORS: command description msgid "Dump details about a firmware file" msgstr "Details zu einer Firmware-Datei ausgeben" #. TRANSLATORS: command description msgid "Watch DFU devices being hotplugged" msgstr "Geräteanschluss von DFU-Geräten überwachen" #. TRANSLATORS: command description msgid "Encrypt firmware data" msgstr "Firmwaredaten verschlüsseln" #. TRANSLATORS: command description msgid "Decrypt firmware data" msgstr "Firmwaredaten entschlüsseln" #. TRANSLATORS: command description msgid "Sets metadata on a firmware file" msgstr "Metadaten einer Firmware-Datei festlegen" #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "DFU-Werkzeug" #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Verarbeitung der Argumente schlug fehl" #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Debuginformationen für alle Dateien anzeigen" #. TRANSLATORS: for the --verbose arg msgid "Debugging Options" msgstr "Debug Optionen" #. TRANSLATORS: for the --verbose arg msgid "Show debugging options" msgstr "Debug Optionen anzeigen" #. TRANSLATORS: exit after we've started up, used for user profiling msgid "Exit after a small delay" msgstr "Verlassen nach einer kurzen Verzögerung" #. TRANSLATORS: exit straight away, used for automatic profiling msgid "Exit after the engine has loaded" msgstr "Nach dem Laden der Engine beenden" #. TRANSLATORS: program name msgid "Firmware Update Daemon" msgstr "Dienst für Firmware-Aktualisierung" #. TRANSLATORS: program summary msgid "Firmware Update D-Bus Service" msgstr "D-Bus-Dienst für Firmware-Aktualisierung" #. TRANSLATORS: daemon is inactive msgid "Idle" msgstr "Untätig" #. TRANSLATORS: decompressing the firmware file msgid "Decompressing firmware" msgstr "Firmware wird entpackt" #. TRANSLATORS: parsing the firmware information msgid "Loading firmware" msgstr "Firmware wird geladen" #. TRANSLATORS: restarting the device to pick up new F/W msgid "Restarting device" msgstr "Gerät wird neu gestartet" #. TRANSLATORS: writing to the flash chips msgid "Writing firmware to device" msgstr "Firmware auf Gerät schreiben" #. TRANSLATORS: verifying we wrote the firmware correctly msgid "Verifying firmware from device" msgstr "Firmware von Gerät überprüfen" #. TRANSLATORS: scheduing an update to be done on the next boot msgid "Scheduling upgrade" msgstr "Aktualisierung wird geplant" #. 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" #. TRANSLATOR: the provider only supports offline msgid "Retrying as an offline update" msgstr "Erneuter Versuch als Offline-Aktualisierung" #. 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 "Erneute Installation von %s mit %s …" #. 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 …" #. 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 "Aktualisieren von %s von %s nach %s …" msgid "Done!" msgstr "Fertig." #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" msgstr "Firmwareaktualisierungen für %s verfügbar:" #. TRANSLATORS: a GUID for the hardware msgid "GUID" msgstr "GUID" #. TRANSLATORS: section header for firmware version msgid "Version" msgstr "Version" #. TRANSLATORS: section header for firmware checksum msgid "Checksum" msgstr "Prüfsumme" msgid "Checksum Type" msgstr "" #. TRANSLATORS: section header for firmware remote http:// msgid "Location" msgstr "Ort" #. TRANSLATORS: section header for long firmware desc msgid "Description" msgstr "Beschreibung" #. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "Zusätzliche Informationen zur Fehlerdiagnose anzeigen" #. TRANSLATORS: command line option msgid "Perform the installation offline where possible" msgstr "Installation falls möglich offline durchführen" #. TRANSLATORS: command line option msgid "Allow re-installing existing firmware versions" msgstr "Erneute Installation vorhandener Firmware-Versionen erlauben" #. TRANSLATORS: command line option msgid "Allow downgrading firmware versions" msgstr "Einspielen niedrigerer Firmwareversionen zulassen (Downgrade)" #. 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 "Install prepared updates now" msgstr "Vorbereitete Aktualisierungen jetzt installieren" #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "Eine Firmware-Datei auf dieser Hardware installieren" #. TRANSLATORS: command description msgid "Gets details about a firmware file" msgstr "Ermittelt Details über eine Firmware-Datei" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "Ermittelt die Liste der Aktualisierungen für angeschlossene Hardware" #. TRANSLATORS: command description msgid "Updates all firmware to latest versions available" msgstr "Alle Firmware auf die neueste verfügbare Version aktualisieren" #. TRANSLATORS: command description msgid "Gets the cryptographic hash of the dumped firmware" msgstr "Ermittelt den kryptographischen Hash-Wert der abgelegten Firmware" #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "" #. TRANSLATORS: command description msgid "Clears the results from the last update" msgstr "Bereinigt die Ergebnisse der letzten Aktualisierung" #. TRANSLATORS: command description msgid "Gets the results from the last update" msgstr "Ermittelt die Ergebnisse der letzten Aktualisierung" #. TRANSLATORS: command description msgid "Refresh metadata from remote server" msgstr "Metadaten von entferntem Server aktualisieren" #. TRANSLATORS: command description msgid "Dump the ROM checksum" msgstr "Die ROM-Prüfsumme speichern" #. TRANSLATORS: command description msgid "Update the stored metadata with current ROM contents" msgstr "Gespeicherte Metadaten mit dem aktuellen ROM-Inhalt aktualisieren" #. TRANSLATORS: program name msgid "Firmware Utility" msgstr "Firmware-Werkzeug" fwupd-0.7.0/po/en_GB.po000066400000000000000000000276511267747510300146220ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Translators: # Richard Hughes , 2015 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-04-01 14:38+0100\n" "PO-Revision-Date: 2016-04-01 13:38+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: English (United Kingdom) (http://www.transifex.com/hughsie/fwupd/language/en_GB/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: en_GB\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgid "Install signed system firmware" msgstr "Install signed system firmware" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on this machine" msgstr "Authentication is required to update the firmware on this machine" msgid "Install unsigned system firmware" msgstr "Install unsigned system firmware" msgid "Install old version of system firmware" msgstr "Install old version of system firmware" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" msgstr "Authentication is required to downgrade the firmware on this machine" msgid "Install signed device firmware" msgstr "Install signed device firmware" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to update the firmware on a removable device" msgstr "Authentication is required to update the firmware on a removable device" msgid "Install unsigned device firmware" msgstr "Install unsigned device firmware" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to downgrade the firmware on a removable device" msgstr "Authentication is required to downgrade the firmware on a removable device" msgid "Unlock the device to allow access" msgstr "" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" msgstr "" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" msgstr "Alias to %s" #. TRANSLATORS: error message msgid "Command not found" msgstr "Command not found" #. TRANSLATORS: when an action has completed msgid "OK" msgstr "OK" #. TRANSLATORS: when moving from runtime to DFU mode msgid "Detaching" msgstr "Detaching" #. TRANSLATORS: when moving from DFU to runtime mode msgid "Attaching" msgstr "Attaching" #. TRANSLATORS: when copying from host to device msgid "Downloading" msgstr "Downloading" #. TRANSLATORS: when copying from device to host msgid "Uploading" msgstr "Uploading" #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Added" #. TRANSLATORS: this is when a device is hotplugged msgid "Removed" msgstr "Removed" #. TRANSLATORS: this is when a device is hotplugged msgid "Changed" msgstr "Changed" #. TRANSLATORS: this is when a device ctrl+c's a watch msgid "Cancelled" msgstr "Cancelled" #. TRANSLATORS: Appstream ID for the hardware type msgid "ID" msgstr "ID" #. TRANSLATORS: interface name, e.g. "Flash" msgid "Name" msgstr "Name" #. TRANSLATORS: this is the encryption method used when writing msgid "Cipher" msgstr "Cipher" #. TRANSLATORS: these are areas of memory on the chip msgid "Region" msgstr "Region" #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Found" #. TRANSLATORS: probably not run as root... #. TRANSLATORS: device has failed to report status #. TRANSLATORS: device status, e.g. "OK" msgid "Status" msgstr "Status" msgid "Unknown: permission denied" msgstr "Unknown: permission denied" #. TRANSLATORS: device mode, e.g. runtime or DFU msgid "Mode" msgstr "Mode" #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "State" #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" msgstr "Quirks" #. TRANSLATORS: command description msgid "Convert firmware to DFU format" msgstr "Convert firmware to DFU format" #. TRANSLATORS: command description msgid "Merge multiple firmware files into one" msgstr "Merge multiple firmware files into one" #. TRANSLATORS: command description msgid "Set vendor ID on firmware file" msgstr "Set vendor ID on firmware file" #. TRANSLATORS: command description msgid "Set product ID on firmware file" msgstr "Set product ID on firmware file" #. TRANSLATORS: command description msgid "Set release version on firmware file" msgstr "Set release version on firmware file" #. TRANSLATORS: command description msgid "Set alternative number on firmware file" msgstr "Set alternative number on firmware file" #. TRANSLATORS: command description msgid "Set alternative name on firmware file" msgstr "Set alternative name on firmware file" #. TRANSLATORS: command description msgid "Attach DFU capable device back to runtime" msgstr "Attach DFU capable device back to runtime" #. TRANSLATORS: command description msgid "Read firmware from device into a file" msgstr "Read firmware from device into a file" #. TRANSLATORS: command description msgid "Read firmware from one partition into a file" msgstr "Read firmware from one partition into a file" #. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "Write firmware from file into device" #. TRANSLATORS: command description msgid "Write firmware from file into one partition" msgstr "Write firmware from file into one partition" #. TRANSLATORS: command description msgid "List currently attached DFU capable devices" msgstr "List currently attached DFU capable devices" #. TRANSLATORS: command description msgid "Detach currently attached DFU capable device" msgstr "Detach currently attached DFU capable device" #. TRANSLATORS: command description msgid "Dump details about a firmware file" msgstr "Dump details about a firmware file" #. TRANSLATORS: command description msgid "Watch DFU devices being hotplugged" msgstr "Watch DFU devices being hotplugged" #. TRANSLATORS: command description msgid "Encrypt firmware data" msgstr "Encrypt firmware data" #. TRANSLATORS: command description msgid "Decrypt firmware data" msgstr "Decrypt firmware data" #. TRANSLATORS: command description msgid "Sets metadata on a firmware file" msgstr "Sets metadata on a firmware file" #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "DFU Utility" #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Failed to parse arguments" #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Show debugging information for all files" #. TRANSLATORS: for the --verbose arg msgid "Debugging Options" msgstr "Debugging Options" #. TRANSLATORS: for the --verbose arg msgid "Show debugging options" msgstr "Show debugging options" #. TRANSLATORS: exit after we've started up, used for user profiling msgid "Exit after a small delay" msgstr "Exit after a small delay" #. TRANSLATORS: exit straight away, used for automatic profiling msgid "Exit after the engine has loaded" msgstr "Exit after the engine has loaded" #. TRANSLATORS: program name msgid "Firmware Update Daemon" msgstr "Firmware Update Daemon" #. TRANSLATORS: program summary msgid "Firmware Update D-Bus Service" msgstr "Firmware Update D-Bus Service" #. TRANSLATORS: daemon is inactive msgid "Idle" msgstr "Idle" #. TRANSLATORS: decompressing the firmware file msgid "Decompressing firmware" msgstr "Decompressing firmware" #. TRANSLATORS: parsing the firmware information msgid "Loading firmware" msgstr "Loading firmware" #. TRANSLATORS: restarting the device to pick up new F/W msgid "Restarting device" msgstr "Restarting device" #. TRANSLATORS: writing to the flash chips msgid "Writing firmware to device" msgstr "Writing firmware to device" #. TRANSLATORS: verifying we wrote the firmware correctly msgid "Verifying firmware from device" msgstr "Verifying firmware from device" #. TRANSLATORS: scheduing an update to be done on the next boot msgid "Scheduling upgrade" msgstr "Scheduling upgrade" #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "No hardware detected with firmware update capability" #. TRANSLATOR: the provider only supports offline msgid "Retrying as an offline update" msgstr "Retrying as an offline update" #. 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 "Reinstalling %s with %s... " #. 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 "Downgrading %s from %s to %s... " #. 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 "Updating %s from %s to %s... " msgid "Done!" msgstr "Done!" #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" msgstr "%s has firmware updates:" #. TRANSLATORS: a GUID for the hardware msgid "GUID" msgstr "GUID" #. TRANSLATORS: section header for firmware version msgid "Version" msgstr "Version" #. TRANSLATORS: section header for firmware checksum msgid "Checksum" msgstr "Checksum" msgid "Checksum Type" msgstr "" #. TRANSLATORS: section header for firmware remote http:// msgid "Location" msgstr "Location" #. TRANSLATORS: section header for long firmware desc msgid "Description" msgstr "Description" #. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "Show extra debugging information" #. TRANSLATORS: command line option msgid "Perform the installation offline where possible" msgstr "Perform the installation offline where possible" #. TRANSLATORS: command line option msgid "Allow re-installing existing firmware versions" msgstr "Allow re-installing existing firmware versions" #. TRANSLATORS: command line option msgid "Allow downgrading firmware versions" msgstr "Allow downgrading firmware versions" #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Get all devices that support firmware updates" #. TRANSLATORS: command description msgid "Install prepared updates now" msgstr "Install prepared updates now" #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "Install a firmware file on this hardware" #. TRANSLATORS: command description msgid "Gets details about a firmware file" msgstr "Gets details about a firmware file" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "Gets the list of updates for connected hardware" #. TRANSLATORS: command description msgid "Updates all firmware to latest versions available" msgstr "Updates all firmware to latest versions available" #. TRANSLATORS: command description msgid "Gets the cryptographic hash of the dumped firmware" msgstr "Gets the cryptographic hash of the dumped firmware" #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "" #. TRANSLATORS: command description msgid "Clears the results from the last update" msgstr "Clears the results from the last update" #. TRANSLATORS: command description msgid "Gets the results from the last update" msgstr "Gets the results from the last update" #. TRANSLATORS: command description msgid "Refresh metadata from remote server" msgstr "Refresh metadata from remote server" #. TRANSLATORS: command description msgid "Dump the ROM checksum" msgstr "Dump the ROM checksum" #. TRANSLATORS: command description msgid "Update the stored metadata with current ROM contents" msgstr "Update the stored metadata with current ROM contents" #. TRANSLATORS: program name msgid "Firmware Utility" msgstr "Firmware Utility" fwupd-0.7.0/po/fr.po000066400000000000000000000247421267747510300142550ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Translators: # Franck , 2015 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-04-01 14:38+0100\n" "PO-Revision-Date: 2016-04-01 13:38+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: French (http://www.transifex.com/hughsie/fwupd/language/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: fr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" msgid "Install signed system firmware" msgstr "" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on this machine" msgstr "Une authentification est nécessaire pour mettre à jour le micrologiciel sur cette machine" msgid "Install unsigned system firmware" msgstr "" msgid "Install old version of system firmware" msgstr "" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" msgstr "" msgid "Install signed device firmware" msgstr "" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to update the firmware on a removable device" msgstr "" msgid "Install unsigned device firmware" msgstr "" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to downgrade the firmware on a removable device" msgstr "" msgid "Unlock the device to allow access" msgstr "" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" msgstr "" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" msgstr "Alias de %s" #. TRANSLATORS: error message msgid "Command not found" msgstr "" #. TRANSLATORS: when an action has completed msgid "OK" msgstr "" #. TRANSLATORS: when moving from runtime to DFU mode msgid "Detaching" msgstr "" #. TRANSLATORS: when moving from DFU to runtime mode msgid "Attaching" msgstr "" #. TRANSLATORS: when copying from host to device msgid "Downloading" msgstr "" #. TRANSLATORS: when copying from device to host msgid "Uploading" msgstr "" #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "" #. TRANSLATORS: this is when a device is hotplugged msgid "Removed" msgstr "" #. TRANSLATORS: this is when a device is hotplugged msgid "Changed" msgstr "" #. TRANSLATORS: this is when a device ctrl+c's a watch msgid "Cancelled" msgstr "" #. TRANSLATORS: Appstream ID for the hardware type msgid "ID" msgstr "" #. TRANSLATORS: interface name, e.g. "Flash" msgid "Name" msgstr "" #. TRANSLATORS: this is the encryption method used when writing msgid "Cipher" msgstr "" #. TRANSLATORS: these are areas of memory on the chip msgid "Region" msgstr "" #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "" #. TRANSLATORS: probably not run as root... #. TRANSLATORS: device has failed to report status #. TRANSLATORS: device status, e.g. "OK" msgid "Status" msgstr "" msgid "Unknown: permission denied" msgstr "" #. TRANSLATORS: device mode, e.g. runtime or DFU msgid "Mode" msgstr "" #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "" #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" msgstr "" #. TRANSLATORS: command description msgid "Convert firmware to DFU format" msgstr "" #. TRANSLATORS: command description msgid "Merge multiple firmware files into one" msgstr "" #. TRANSLATORS: command description msgid "Set vendor ID on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Set product ID on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Set release version on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Set alternative number on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Set alternative name on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Attach DFU capable device back to runtime" msgstr "" #. TRANSLATORS: command description msgid "Read firmware from device into a file" msgstr "" #. TRANSLATORS: command description msgid "Read firmware from one partition into a file" msgstr "" #. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "" #. TRANSLATORS: command description msgid "Write firmware from file into one partition" msgstr "" #. TRANSLATORS: command description msgid "List currently attached DFU capable devices" msgstr "" #. TRANSLATORS: command description msgid "Detach currently attached DFU capable device" msgstr "" #. TRANSLATORS: command description msgid "Dump details about a firmware file" msgstr "" #. TRANSLATORS: command description msgid "Watch DFU devices being hotplugged" msgstr "" #. TRANSLATORS: command description msgid "Encrypt firmware data" msgstr "" #. TRANSLATORS: command description msgid "Decrypt firmware data" msgstr "" #. TRANSLATORS: command description msgid "Sets metadata on a firmware file" msgstr "" #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "" #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Echec de l'analyse des paramètres" #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Montrer les informations de débogage pour tous les fichiers" #. TRANSLATORS: for the --verbose arg msgid "Debugging Options" msgstr "Options de débogage" #. TRANSLATORS: for the --verbose arg msgid "Show debugging options" msgstr "Montrer les options de débogage" #. TRANSLATORS: exit after we've started up, used for user profiling msgid "Exit after a small delay" msgstr "Quitter après un bref délai" #. TRANSLATORS: exit straight away, used for automatic profiling msgid "Exit after the engine has loaded" msgstr "Quitter après le chargement du moteur" #. TRANSLATORS: program name msgid "Firmware Update Daemon" msgstr "" #. TRANSLATORS: program summary msgid "Firmware Update D-Bus Service" msgstr "Service D-Bus de mise à jour des micrologiciels" #. TRANSLATORS: daemon is inactive msgid "Idle" msgstr "En attente" #. TRANSLATORS: decompressing the firmware file msgid "Decompressing firmware" msgstr "Décompression du micrologiciel" #. TRANSLATORS: parsing the firmware information msgid "Loading firmware" msgstr "Chargement du micrologiciel" #. TRANSLATORS: restarting the device to pick up new F/W msgid "Restarting device" msgstr "Redémarrage du périphérique" #. TRANSLATORS: writing to the flash chips msgid "Writing firmware to device" msgstr "Ecriture du micrologiciel sur le périphérique" #. TRANSLATORS: verifying we wrote the firmware correctly msgid "Verifying firmware from device" msgstr "Vérification du micrologiciel du périphérique" #. TRANSLATORS: scheduing an update to be done on the next boot msgid "Scheduling upgrade" msgstr "Planification de la mise à jour" #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "Aucun matériel ayant des capacités de mise à jour du micrologiciel n'a été détecté" #. TRANSLATOR: the provider only supports offline msgid "Retrying as an offline update" msgstr "" #. 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 "Réinstallation de %s en %s" #. 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 "Rétrogradation de %s de %s en %s" #. 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 "Mise à jour de %s de %s en %s" msgid "Done!" msgstr "Terminé !" #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" msgstr "" #. TRANSLATORS: a GUID for the hardware msgid "GUID" msgstr "" #. TRANSLATORS: section header for firmware version msgid "Version" msgstr "" #. TRANSLATORS: section header for firmware checksum msgid "Checksum" msgstr "" msgid "Checksum Type" msgstr "" #. TRANSLATORS: section header for firmware remote http:// msgid "Location" msgstr "" #. TRANSLATORS: section header for long firmware desc msgid "Description" msgstr "" #. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "Montre des informations de débogage complémentaires" #. TRANSLATORS: command line option msgid "Perform the installation offline where possible" msgstr "" #. TRANSLATORS: command line option msgid "Allow re-installing existing firmware versions" msgstr "" #. TRANSLATORS: command line option msgid "Allow downgrading firmware versions" msgstr "" #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Obtenir la liste des périphériques supportant les mises à jour de micrologiciel" #. TRANSLATORS: command description msgid "Install prepared updates now" msgstr "Installer immédiatement les mises à jour préparées" #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "Installer un fichier de micrologiciel sur ce matériel" #. TRANSLATORS: command description msgid "Gets details about a firmware file" msgstr "Obtenir les détails d'un fichier de micrologiciel" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "" #. TRANSLATORS: command description msgid "Updates all firmware to latest versions available" msgstr "" #. TRANSLATORS: command description msgid "Gets the cryptographic hash of the dumped firmware" msgstr "" #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "" #. TRANSLATORS: command description msgid "Clears the results from the last update" msgstr "" #. TRANSLATORS: command description msgid "Gets the results from the last update" msgstr "" #. TRANSLATORS: command description msgid "Refresh metadata from remote server" msgstr "" #. TRANSLATORS: command description msgid "Dump the ROM checksum" msgstr "" #. TRANSLATORS: command description msgid "Update the stored metadata with current ROM contents" msgstr "" #. TRANSLATORS: program name msgid "Firmware Utility" msgstr "" fwupd-0.7.0/po/he.po000066400000000000000000000252001267747510300142300ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Translators: # dhead666 , 2015 # GenghisKhan , 2015 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-04-01 14:38+0100\n" "PO-Revision-Date: 2016-04-01 13:38+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Hebrew (http://www.transifex.com/hughsie/fwupd/language/he/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: he\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgid "Install signed system firmware" msgstr "" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on this machine" msgstr "×ימות משתמש נדרש לעדכון קושחה מערכת זו" msgid "Install unsigned system firmware" msgstr "" msgid "Install old version of system firmware" msgstr "" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" msgstr "" msgid "Install signed device firmware" msgstr "" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to update the firmware on a removable device" msgstr "" msgid "Install unsigned device firmware" msgstr "" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to downgrade the firmware on a removable device" msgstr "" msgid "Unlock the device to allow access" msgstr "" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" msgstr "" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" msgstr "כינוי עבור %s" #. TRANSLATORS: error message msgid "Command not found" msgstr "פקודה ×œ× × ×ž×¦××”" #. TRANSLATORS: when an action has completed msgid "OK" msgstr "×ישור" #. TRANSLATORS: when moving from runtime to DFU mode msgid "Detaching" msgstr "" #. TRANSLATORS: when moving from DFU to runtime mode msgid "Attaching" msgstr "" #. TRANSLATORS: when copying from host to device msgid "Downloading" msgstr "" #. TRANSLATORS: when copying from device to host msgid "Uploading" msgstr "" #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "" #. TRANSLATORS: this is when a device is hotplugged msgid "Removed" msgstr "" #. TRANSLATORS: this is when a device is hotplugged msgid "Changed" msgstr "" #. TRANSLATORS: this is when a device ctrl+c's a watch msgid "Cancelled" msgstr "" #. TRANSLATORS: Appstream ID for the hardware type msgid "ID" msgstr "" #. TRANSLATORS: interface name, e.g. "Flash" msgid "Name" msgstr "" #. TRANSLATORS: this is the encryption method used when writing msgid "Cipher" msgstr "" #. TRANSLATORS: these are areas of memory on the chip msgid "Region" msgstr "" #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "" #. TRANSLATORS: probably not run as root... #. TRANSLATORS: device has failed to report status #. TRANSLATORS: device status, e.g. "OK" msgid "Status" msgstr "" msgid "Unknown: permission denied" msgstr "" #. TRANSLATORS: device mode, e.g. runtime or DFU msgid "Mode" msgstr "" #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "" #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" msgstr "" #. TRANSLATORS: command description msgid "Convert firmware to DFU format" msgstr "" #. TRANSLATORS: command description msgid "Merge multiple firmware files into one" msgstr "" #. TRANSLATORS: command description msgid "Set vendor ID on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Set product ID on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Set release version on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Set alternative number on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Set alternative name on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Attach DFU capable device back to runtime" msgstr "" #. TRANSLATORS: command description msgid "Read firmware from device into a file" msgstr "" #. TRANSLATORS: command description msgid "Read firmware from one partition into a file" msgstr "" #. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "" #. TRANSLATORS: command description msgid "Write firmware from file into one partition" msgstr "" #. TRANSLATORS: command description msgid "List currently attached DFU capable devices" msgstr "" #. TRANSLATORS: command description msgid "Detach currently attached DFU capable device" msgstr "" #. TRANSLATORS: command description msgid "Dump details about a firmware file" msgstr "" #. TRANSLATORS: command description msgid "Watch DFU devices being hotplugged" msgstr "" #. TRANSLATORS: command description msgid "Encrypt firmware data" msgstr "" #. TRANSLATORS: command description msgid "Decrypt firmware data" msgstr "" #. TRANSLATORS: command description msgid "Sets metadata on a firmware file" msgstr "" #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "" #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "נכשל בפענוח ×”×רגומנטי×" #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "הצג מידע ניפוי שגי×ות לכל הקבצי×" #. TRANSLATORS: for the --verbose arg msgid "Debugging Options" msgstr "×פשרויות ניפוי שגי×ות" #. TRANSLATORS: for the --verbose arg msgid "Show debugging options" msgstr "הצג ×פשרויות ניפוי שגי×ות" #. TRANSLATORS: exit after we've started up, used for user profiling msgid "Exit after a small delay" msgstr "יצי××” ל×חר השהייה קצרה" #. TRANSLATORS: exit straight away, used for automatic profiling msgid "Exit after the engine has loaded" msgstr "יצי××” ל×חר טעינת מנוע התכנה" #. TRANSLATORS: program name msgid "Firmware Update Daemon" msgstr "שדון עדכון קושחה" #. TRANSLATORS: program summary msgid "Firmware Update D-Bus Service" msgstr "שירות D-Bus עדכון קושחה" #. TRANSLATORS: daemon is inactive msgid "Idle" msgstr "מצב סרק" #. TRANSLATORS: decompressing the firmware file msgid "Decompressing firmware" msgstr "מחלץ קושחה" #. TRANSLATORS: parsing the firmware information msgid "Loading firmware" msgstr "טוען קושחה" #. TRANSLATORS: restarting the device to pick up new F/W msgid "Restarting device" msgstr "מפעיל מחדש מכשיר" #. TRANSLATORS: writing to the flash chips msgid "Writing firmware to device" msgstr "כותב קושחה למכשיר" #. TRANSLATORS: verifying we wrote the firmware correctly msgid "Verifying firmware from device" msgstr "מ×מת קושחה שבמכשיר" #. TRANSLATORS: scheduing an update to be done on the next boot msgid "Scheduling upgrade" msgstr "מתזמן שדרוג" #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "×œ× ×ותרה חומרה בעלת יכולת עדכון קושחה" #. TRANSLATOR: the provider only supports offline msgid "Retrying as an offline update" msgstr "" #. 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 "מתקין מחדש %s ×¢× %s..." #. 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 "משנמך גרסת %s מ־%s ל־%s..." #. 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 "מעדכן %s מ־%s ל־%s..." msgid "Done!" msgstr "הסתיי×!" #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" msgstr "×™×©× × ×¢×“×›×•× ×™ קושחה עבור %s:" #. TRANSLATORS: a GUID for the hardware msgid "GUID" msgstr "" #. TRANSLATORS: section header for firmware version msgid "Version" msgstr "גרס×" #. TRANSLATORS: section header for firmware checksum msgid "Checksum" msgstr "×¡×›×•× ×‘×™×§×•×¨×ª" msgid "Checksum Type" msgstr "" #. TRANSLATORS: section header for firmware remote http:// msgid "Location" msgstr "מיקו×" #. TRANSLATORS: section header for long firmware desc msgid "Description" msgstr "תי×ור" #. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "הצג מידע ניפוי שגי×ות מורחב" #. TRANSLATORS: command line option msgid "Perform the installation offline where possible" msgstr "" #. TRANSLATORS: command line option msgid "Allow re-installing existing firmware versions" msgstr "" #. TRANSLATORS: command line option msgid "Allow downgrading firmware versions" msgstr "" #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "מציג כל ×”×ž×›×©×™×¨×™× ×”×ª×•×ž×›×™× ×‘×¢×“×›×•× ×™ קושחה" #. TRANSLATORS: command description msgid "Install prepared updates now" msgstr "מתקין כעת ×¢×“×›×•× ×™× ×ž×•×›× ×™×" #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "מתקין קובץ קושחה בחומרה זו" #. TRANSLATORS: command description msgid "Gets details about a firmware file" msgstr "מציג ×¤×¨×˜×™× ×ודות קובץ קושחה" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "" #. TRANSLATORS: command description msgid "Updates all firmware to latest versions available" msgstr "" #. TRANSLATORS: command description msgid "Gets the cryptographic hash of the dumped firmware" msgstr "" #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "" #. TRANSLATORS: command description msgid "Clears the results from the last update" msgstr "" #. TRANSLATORS: command description msgid "Gets the results from the last update" msgstr "" #. TRANSLATORS: command description msgid "Refresh metadata from remote server" msgstr "" #. TRANSLATORS: command description msgid "Dump the ROM checksum" msgstr "" #. TRANSLATORS: command description msgid "Update the stored metadata with current ROM contents" msgstr "" #. TRANSLATORS: program name msgid "Firmware Utility" msgstr "" fwupd-0.7.0/po/hi_IN.po000066400000000000000000000270101267747510300146230ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Translators: # Prashant Gupta , 2015 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-04-01 14:38+0100\n" "PO-Revision-Date: 2016-04-01 13:38+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Hindi (India) (http://www.transifex.com/hughsie/fwupd/language/hi_IN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: hi_IN\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgid "Install signed system firmware" msgstr "" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on this machine" msgstr "फरà¥à¤®à¤µà¥‡à¤¯à¤° अपडेट के लिठपà¥à¤°à¤®à¤¾à¤£à¥€à¤•रण चाहिठ" msgid "Install unsigned system firmware" msgstr "" msgid "Install old version of system firmware" msgstr "" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" msgstr "" msgid "Install signed device firmware" msgstr "" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to update the firmware on a removable device" msgstr "" msgid "Install unsigned device firmware" msgstr "" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to downgrade the firmware on a removable device" msgstr "" msgid "Unlock the device to allow access" msgstr "" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" msgstr "" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" msgstr "%s का उपनाम " #. TRANSLATORS: error message msgid "Command not found" msgstr "" #. TRANSLATORS: when an action has completed msgid "OK" msgstr "" #. TRANSLATORS: when moving from runtime to DFU mode msgid "Detaching" msgstr "" #. TRANSLATORS: when moving from DFU to runtime mode msgid "Attaching" msgstr "" #. TRANSLATORS: when copying from host to device msgid "Downloading" msgstr "" #. TRANSLATORS: when copying from device to host msgid "Uploading" msgstr "" #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "" #. TRANSLATORS: this is when a device is hotplugged msgid "Removed" msgstr "" #. TRANSLATORS: this is when a device is hotplugged msgid "Changed" msgstr "" #. TRANSLATORS: this is when a device ctrl+c's a watch msgid "Cancelled" msgstr "" #. TRANSLATORS: Appstream ID for the hardware type msgid "ID" msgstr "" #. TRANSLATORS: interface name, e.g. "Flash" msgid "Name" msgstr "" #. TRANSLATORS: this is the encryption method used when writing msgid "Cipher" msgstr "" #. TRANSLATORS: these are areas of memory on the chip msgid "Region" msgstr "" #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "" #. TRANSLATORS: probably not run as root... #. TRANSLATORS: device has failed to report status #. TRANSLATORS: device status, e.g. "OK" msgid "Status" msgstr "" msgid "Unknown: permission denied" msgstr "" #. TRANSLATORS: device mode, e.g. runtime or DFU msgid "Mode" msgstr "" #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "" #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" msgstr "" #. TRANSLATORS: command description msgid "Convert firmware to DFU format" msgstr "" #. TRANSLATORS: command description msgid "Merge multiple firmware files into one" msgstr "" #. TRANSLATORS: command description msgid "Set vendor ID on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Set product ID on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Set release version on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Set alternative number on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Set alternative name on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Attach DFU capable device back to runtime" msgstr "" #. TRANSLATORS: command description msgid "Read firmware from device into a file" msgstr "" #. TRANSLATORS: command description msgid "Read firmware from one partition into a file" msgstr "" #. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "" #. TRANSLATORS: command description msgid "Write firmware from file into one partition" msgstr "" #. TRANSLATORS: command description msgid "List currently attached DFU capable devices" msgstr "" #. TRANSLATORS: command description msgid "Detach currently attached DFU capable device" msgstr "" #. TRANSLATORS: command description msgid "Dump details about a firmware file" msgstr "" #. TRANSLATORS: command description msgid "Watch DFU devices being hotplugged" msgstr "" #. TRANSLATORS: command description msgid "Encrypt firmware data" msgstr "" #. TRANSLATORS: command description msgid "Decrypt firmware data" msgstr "" #. TRANSLATORS: command description msgid "Sets metadata on a firmware file" msgstr "" #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "" #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "आरà¥à¤—à¥à¤®à¥‡à¤‚ट पारà¥à¤¸ करने में असफल " #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "फाइलà¥à¤¸ की डिबगिंग की जानकारी दिखाठ" #. TRANSLATORS: for the --verbose arg msgid "Debugging Options" msgstr "डिबगिंग के विकलà¥à¤ª " #. TRANSLATORS: for the --verbose arg msgid "Show debugging options" msgstr "डिबगिंग के विकलà¥à¤ª दिखाठ" #. TRANSLATORS: exit after we've started up, used for user profiling msgid "Exit after a small delay" msgstr "थोड़ी देरी के बाद बहार जाà¤à¤ " #. TRANSLATORS: exit straight away, used for automatic profiling msgid "Exit after the engine has loaded" msgstr "इंजन के लोड हो जाने पर बहार जाà¤à¤ " #. TRANSLATORS: program name msgid "Firmware Update Daemon" msgstr "" #. TRANSLATORS: program summary msgid "Firmware Update D-Bus Service" msgstr "फरà¥à¤®à¤µà¥‡à¤¯à¤° अपडेट डी-बस सेवा " #. TRANSLATORS: daemon is inactive msgid "Idle" msgstr "सà¥à¤¥à¤¿à¤° " #. TRANSLATORS: decompressing the firmware file msgid "Decompressing firmware" msgstr "फरà¥à¤®à¤µà¥‡à¤¯à¤° डीकमà¥à¤ªà¥à¤°à¥‡à¤¸ हो रहा है " #. TRANSLATORS: parsing the firmware information msgid "Loading firmware" msgstr "फरà¥à¤®à¤µà¥‡à¤¯à¤° लोड हो रहा है " #. TRANSLATORS: restarting the device to pick up new F/W msgid "Restarting device" msgstr "यà¥à¤•à¥à¤¤à¤¿ दोबारा चालू हो रही है " #. TRANSLATORS: writing to the flash chips msgid "Writing firmware to device" msgstr "फरà¥à¤®à¤µà¥‡à¤¯à¤° को यà¥à¤•à¥à¤¤à¤¿ पे लिखा जा रहा है " #. TRANSLATORS: verifying we wrote the firmware correctly msgid "Verifying firmware from device" msgstr "फरà¥à¤®à¤µà¥‡à¤¯à¤° को यà¥à¤•à¥à¤¤à¤¿ से जांचा जा रहा है " #. TRANSLATORS: scheduing an update to be done on the next boot msgid "Scheduling upgrade" msgstr "अपगà¥à¤°à¥‡à¤¡ को सूचि में डाला जा रहा है " #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "अपडेट की कà¥à¤·à¤®à¤¤à¤¾ वाला हारà¥à¤¡à¤µà¥‡à¤¯à¤° उपलबà¥à¤§ नहीं " #. TRANSLATOR: the provider only supports offline msgid "Retrying as an offline update" msgstr "" #. 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 "%s को %s से दोबारा सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करा जा रहा है " #. 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 "%s की %s से %s तक अधोगति हो रही है " #. 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 "%s को %s से %s तक अपडेट करा जा रहा है " msgid "Done!" msgstr "हो गया !" #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" msgstr "" #. TRANSLATORS: a GUID for the hardware msgid "GUID" msgstr "" #. TRANSLATORS: section header for firmware version msgid "Version" msgstr "" #. TRANSLATORS: section header for firmware checksum msgid "Checksum" msgstr "" msgid "Checksum Type" msgstr "" #. TRANSLATORS: section header for firmware remote http:// msgid "Location" msgstr "" #. TRANSLATORS: section header for long firmware desc msgid "Description" msgstr "" #. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "डिबगिंग की अतिरिकà¥à¤¤ जानकारी दिखाà¤à¤ " #. TRANSLATORS: command line option msgid "Perform the installation offline where possible" msgstr "" #. TRANSLATORS: command line option msgid "Allow re-installing existing firmware versions" msgstr "" #. TRANSLATORS: command line option msgid "Allow downgrading firmware versions" msgstr "" #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "फरà¥à¤®à¤µà¥‡à¤¯à¤° अपडेट का समरà¥à¤¥à¤¨ करने वाली सभी यà¥à¤•à¥à¤¤à¤¿à¤¯à¤¾à¤ पà¥à¤°à¤¾à¤ªà¥à¤¤ करें " #. TRANSLATORS: command description msgid "Install prepared updates now" msgstr "तैयार अपडेट अभी सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करें " #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "फरà¥à¤®à¤µà¥‡à¤¯à¤° फाइल को इस हारà¥à¤¡à¤µà¥‡à¤¯à¤° पर सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करें " #. TRANSLATORS: command description msgid "Gets details about a firmware file" msgstr "फरà¥à¤®à¤µà¥‡à¤¯à¤° फाइल की अधिक जानकारी पà¥à¤°à¤¾à¤ªà¥à¤¤ करें " #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "" #. TRANSLATORS: command description msgid "Updates all firmware to latest versions available" msgstr "" #. TRANSLATORS: command description msgid "Gets the cryptographic hash of the dumped firmware" msgstr "" #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "" #. TRANSLATORS: command description msgid "Clears the results from the last update" msgstr "" #. TRANSLATORS: command description msgid "Gets the results from the last update" msgstr "" #. TRANSLATORS: command description msgid "Refresh metadata from remote server" msgstr "" #. TRANSLATORS: command description msgid "Dump the ROM checksum" msgstr "" #. TRANSLATORS: command description msgid "Update the stored metadata with current ROM contents" msgstr "" #. TRANSLATORS: program name msgid "Firmware Utility" msgstr "" fwupd-0.7.0/po/hu.po000066400000000000000000000317501267747510300142570ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Translators: # Balázs Úr , 2015-2016 # Gabor Kelemen , 2016 # kelemeng , 2016 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-04-01 14:38+0100\n" "PO-Revision-Date: 2016-04-01 13:38+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Hungarian (http://www.transifex.com/hughsie/fwupd/language/hu/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: hu\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgid "Install signed system firmware" msgstr "Aláírt rendszer firmware telepítése" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on this machine" msgstr "Hitelesítés szükséges a firmware frissítéséhez ezen a gépen" msgid "Install unsigned system firmware" msgstr "Nem aláírt rendszer firmware telepítése" msgid "Install old version of system firmware" msgstr "A rendszer firmware régi verziójának telepítése" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" msgstr "Hitelesítés szükséges a firmware visszafejlesztéséhez ezen a gépen" msgid "Install signed device firmware" msgstr "Aláírt eszköz firmware telepítése" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to update the firmware on a removable device" msgstr "Hitelesítés szükséges a firmware frissítéséhez egy cserélhetÅ‘ eszközön" msgid "Install unsigned device firmware" msgstr "Nem aláírt eszköz firmware telepítése" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to downgrade the firmware on a removable device" msgstr "Hitelesítés szükséges a firmware visszafejlesztéséhez egy cserélhetÅ‘ eszközön" msgid "Unlock the device to allow access" msgstr "Eszköz feloldása hozzáférés engedélyezéséhez" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" msgstr "Hitelesítés szükséges az eszköz feloldásához" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" msgstr "Ãlnév ehhez: %s" #. TRANSLATORS: error message msgid "Command not found" msgstr "A parancs nem található" #. TRANSLATORS: when an action has completed msgid "OK" msgstr "OK" #. TRANSLATORS: when moving from runtime to DFU mode msgid "Detaching" msgstr "Leválasztás" #. TRANSLATORS: when moving from DFU to runtime mode msgid "Attaching" msgstr "Csatlakozás" #. TRANSLATORS: when copying from host to device msgid "Downloading" msgstr "Letöltés" #. TRANSLATORS: when copying from device to host msgid "Uploading" msgstr "Feltöltés" #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Hozzáadva" #. TRANSLATORS: this is when a device is hotplugged msgid "Removed" msgstr "Eltávolítva" #. TRANSLATORS: this is when a device is hotplugged msgid "Changed" msgstr "Módosítva" #. TRANSLATORS: this is when a device ctrl+c's a watch msgid "Cancelled" msgstr "Megszakítva" #. TRANSLATORS: Appstream ID for the hardware type msgid "ID" msgstr "Azonosító" #. TRANSLATORS: interface name, e.g. "Flash" msgid "Name" msgstr "Név" #. TRANSLATORS: this is the encryption method used when writing msgid "Cipher" msgstr "Titkosító" #. TRANSLATORS: these are areas of memory on the chip msgid "Region" msgstr "Régió" #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Megtalálva" #. TRANSLATORS: probably not run as root... #. TRANSLATORS: device has failed to report status #. TRANSLATORS: device status, e.g. "OK" msgid "Status" msgstr "Ãllapot" msgid "Unknown: permission denied" msgstr "Ismeretlen: hozzáférés megtagadva" #. TRANSLATORS: device mode, e.g. runtime or DFU msgid "Mode" msgstr "Mód" #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Ãllapot" #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" msgstr "Kompatibilitási trükkök" #. TRANSLATORS: command description msgid "Convert firmware to DFU format" msgstr "Firmware átalakítása DFU formátumra" #. TRANSLATORS: command description msgid "Merge multiple firmware files into one" msgstr "Több firmware fájl egyesítése" #. TRANSLATORS: command description msgid "Set vendor ID on firmware file" msgstr "Gyártóazonosító beállítása a firmware fájlon" #. TRANSLATORS: command description msgid "Set product ID on firmware file" msgstr "Termékazonosító beállítása a firmware fájlon" #. TRANSLATORS: command description msgid "Set release version on firmware file" msgstr "Kiadási verzió beállítása a firmware fájlon" #. TRANSLATORS: command description msgid "Set alternative number on firmware file" msgstr "Alternatív szám beállítása a firmware fájlon" #. TRANSLATORS: command description msgid "Set alternative name on firmware file" msgstr "Alternatív név beállítása a firmware fájlon" #. 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 "Read firmware from device into a file" msgstr "Firmware beolvasása eszközrÅ‘l egy fájlba" #. TRANSLATORS: command description msgid "Read firmware from one partition into a file" msgstr "Firmware beolvasása egy partícióról fájlba" #. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "Firmware írása fájlból egy eszközre" #. TRANSLATORS: command description msgid "Write firmware from file into one partition" msgstr "Firmware írása fájlból egy partícióra" #. TRANSLATORS: command description msgid "List currently attached DFU capable devices" msgstr "Jelenleg csatlakoztatott DFU-képes eszközök felsorolása" #. TRANSLATORS: command description msgid "Detach currently attached DFU capable device" msgstr "Jelenleg csatlakoztatott DFU-képes eszközök leválasztása" #. TRANSLATORS: command description msgid "Dump details about a firmware file" msgstr "Részletek kiírása egy firmware fájlról" #. TRANSLATORS: command description msgid "Watch DFU devices being hotplugged" msgstr "DFU-eszközök menet közbeni csatlakoztatásának figyelése" #. TRANSLATORS: command description msgid "Encrypt firmware data" msgstr "Firmware adatok titkosítása" #. TRANSLATORS: command description msgid "Decrypt firmware data" msgstr "Firmware adatok visszafejtése" #. TRANSLATORS: command description msgid "Sets metadata on a firmware file" msgstr "Metaadatok beállítása egy firmware fájlon" #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "DFU segédprogram" #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Nem sikerült feldolgozni az argumentumokat" #. 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" #. TRANSLATORS: for the --verbose arg msgid "Debugging Options" msgstr "Hibakeresési beállítások" #. TRANSLATORS: for the --verbose arg msgid "Show debugging options" msgstr "Hibakeresési beállítások megjelenítése" #. TRANSLATORS: exit after we've started up, used for user profiling msgid "Exit after a small delay" msgstr "Kilépés egy kis késleltetés után" #. TRANSLATORS: exit straight away, used for automatic profiling msgid "Exit after the engine has loaded" msgstr "Kilépés a motor betöltÅ‘dése után" #. TRANSLATORS: program name msgid "Firmware Update Daemon" msgstr "Firmware frissítÅ‘ démon" #. TRANSLATORS: program summary msgid "Firmware Update D-Bus Service" msgstr "Firmware frissítés D-Bus szolgáltatás" #. TRANSLATORS: daemon is inactive msgid "Idle" msgstr "Üresjárat" #. TRANSLATORS: decompressing the firmware file msgid "Decompressing firmware" msgstr "Firmware kibontása" #. TRANSLATORS: parsing the firmware information msgid "Loading firmware" msgstr "Firmware betöltése" #. TRANSLATORS: restarting the device to pick up new F/W msgid "Restarting device" msgstr "Eszköz újraindítása" #. TRANSLATORS: writing to the flash chips msgid "Writing firmware to device" msgstr "Firmware írása az eszközre" #. TRANSLATORS: verifying we wrote the firmware correctly msgid "Verifying firmware from device" msgstr "Firmware ellenÅ‘rzése az eszközrÅ‘l" #. TRANSLATORS: scheduing an update to be done on the next boot msgid "Scheduling upgrade" msgstr "Ütemezett frissítés" #. 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" #. TRANSLATOR: the provider only supports offline msgid "Retrying as an offline update" msgstr "Újrapróbálás kapcsolat nélküli frissítésként" #. 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 "%s újratelepítése ezzel: %s…" #. 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 "%s visszafejlesztése: %s -> %s…" #. 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 "%s frissítése: %s -> %s…" msgid "Done!" msgstr "Kész!" #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" msgstr "%s firmware frissítésekkel rendelkezik:" #. TRANSLATORS: a GUID for the hardware msgid "GUID" msgstr "GUID" #. TRANSLATORS: section header for firmware version msgid "Version" msgstr "Verzió" #. TRANSLATORS: section header for firmware checksum msgid "Checksum" msgstr "EllenÅ‘rzőösszeg" msgid "Checksum Type" msgstr "" #. TRANSLATORS: section header for firmware remote http:// msgid "Location" msgstr "Hely" #. TRANSLATORS: section header for long firmware desc msgid "Description" msgstr "Leírás" #. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "További hibakeresési információk megjelenítése" #. TRANSLATORS: command line option msgid "Perform the installation offline where possible" msgstr "A telepítés végrehajtása kapcsolat nélkül, ha lehetséges" #. TRANSLATORS: command line option msgid "Allow re-installing existing firmware versions" msgstr "MeglévÅ‘ firmware verziók újratelepítésének engedélyezése" #. TRANSLATORS: command line option msgid "Allow downgrading firmware versions" msgstr "Firmware verziók visszafejlesztésének engedélyezése" #. 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 "Install prepared updates now" msgstr "Az elÅ‘készített frissítések telepítés most" #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "Egy firmware fájl telepítése ezen a hardveren" #. TRANSLATORS: command description msgid "Gets details about a firmware file" msgstr "Részleteket kér le egy firmware fájlról" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "A frissítések listáját kéri le a csatlakoztatott hardverhez" #. TRANSLATORS: command description msgid "Updates all firmware to latest versions available" msgstr "Minden firmware-t az elérhetÅ‘ legfrissebb verziókra frissít" #. TRANSLATORS: command description msgid "Gets the cryptographic hash of the dumped firmware" msgstr "Lekéri a kiírt firmware kriptográfiai hash-ét" #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Eszköz feloldása a firmware eléréséhez" #. TRANSLATORS: command description msgid "Clears the results from the last update" msgstr "Törli a legutóbbi frissítésbÅ‘l származó eredményeket" #. TRANSLATORS: command description msgid "Gets the results from the last update" msgstr "A legutóbbi frissítésbÅ‘l származó eredményeket kéri le" #. TRANSLATORS: command description msgid "Refresh metadata from remote server" msgstr "Metaadatok frissítése a távoli kiszolgálóról" #. TRANSLATORS: command description msgid "Dump the ROM checksum" msgstr "A ROM ellenÅ‘rzőösszegének kiírása" #. TRANSLATORS: command description msgid "Update the stored metadata with current ROM contents" msgstr "A tárolt metaadatok frissítése a jelenlegi ROM tartalmával" #. TRANSLATORS: program name msgid "Firmware Utility" msgstr "Firmware segédprogram" fwupd-0.7.0/po/nl_NL.po000066400000000000000000000316041267747510300146430ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Translators: # Heimen Stoffels , 2016 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-04-01 14:38+0100\n" "PO-Revision-Date: 2016-04-01 13:38+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Dutch (Netherlands) (http://www.transifex.com/hughsie/fwupd/language/nl_NL/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: nl_NL\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgid "Install signed system firmware" msgstr "Ondertekende systeemfirmware installeren" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on this machine" msgstr "Om de firmware op deze computer bij te werken moet u toestemming verlenen" msgid "Install unsigned system firmware" msgstr "Niet-ondertekende systeemfirmware installeren" msgid "Install old version of system firmware" msgstr "Oude versie van systeemfirmware installeren" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" msgstr "Om de firmware op deze computer af te waarderen moet u toestemming verlenen" msgid "Install signed device firmware" msgstr "Ondertekende apparaatfirmware installeren" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to update the firmware on a removable device" msgstr "Om de firmware op een verwijderbaar apparaat bij te werken moet u toestemming verlenen" msgid "Install unsigned device firmware" msgstr "Niet-ondertekende apparaatfirmware installeren" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to downgrade the firmware on a removable device" msgstr "Om de firmware op een verwijderbaar apparaat af te waarderen moet u toestemming verlenen" msgid "Unlock the device to allow access" msgstr "Ontgrendel het apparaat om toegang te verlenen" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" msgstr "Om een apparaat te ontgrendelen moet u toestemming verlenen" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" msgstr "Alias voor %s" #. TRANSLATORS: error message msgid "Command not found" msgstr "De opdracht kon niet worden gevonden" #. TRANSLATORS: when an action has completed msgid "OK" msgstr "Oké" #. TRANSLATORS: when moving from runtime to DFU mode msgid "Detaching" msgstr "Bezig met afkoppelen" #. TRANSLATORS: when moving from DFU to runtime mode msgid "Attaching" msgstr "Bezig met aankoppelen" #. TRANSLATORS: when copying from host to device msgid "Downloading" msgstr "Bezig met downloaden" #. TRANSLATORS: when copying from device to host msgid "Uploading" msgstr "Bezig met uploaden" #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Toegevoegd" #. TRANSLATORS: this is when a device is hotplugged msgid "Removed" msgstr "Verwijderd" #. TRANSLATORS: this is when a device is hotplugged msgid "Changed" msgstr "Gewijzigd" #. TRANSLATORS: this is when a device ctrl+c's a watch msgid "Cancelled" msgstr "Geannuleerd" #. TRANSLATORS: Appstream ID for the hardware type msgid "ID" msgstr "ID" #. TRANSLATORS: interface name, e.g. "Flash" msgid "Name" msgstr "Naam" #. TRANSLATORS: this is the encryption method used when writing msgid "Cipher" msgstr "Sleutel" #. TRANSLATORS: these are areas of memory on the chip msgid "Region" msgstr "Gebied" #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Gevonden" #. TRANSLATORS: probably not run as root... #. TRANSLATORS: device has failed to report status #. TRANSLATORS: device status, e.g. "OK" msgid "Status" msgstr "Status" msgid "Unknown: permission denied" msgstr "Onbekend: toestemming is geweigerd" #. TRANSLATORS: device mode, e.g. runtime or DFU msgid "Mode" msgstr "Modus" #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Status" #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" msgstr "Eigenaardigheden" #. TRANSLATORS: command description msgid "Convert firmware to DFU format" msgstr "Firmware converteren naar DFU-formaat" #. TRANSLATORS: command description msgid "Merge multiple firmware files into one" msgstr "Meerdere firmware-bestanden samenvoegen tot één bestand" #. TRANSLATORS: command description msgid "Set vendor ID on firmware file" msgstr "Leveranciers-ID instellen op het firmware-bestand" #. TRANSLATORS: command description msgid "Set product ID on firmware file" msgstr "Product-ID instellen op het firmware-bestand" #. TRANSLATORS: command description msgid "Set release version on firmware file" msgstr "Uitgave-versie instellen op het firmware-bestand" #. TRANSLATORS: command description msgid "Set alternative number on firmware file" msgstr "Alternatief nummer instellen op het firmware-bestand" #. TRANSLATORS: command description msgid "Set alternative name on firmware file" msgstr "Alternatieve naam instellen op het firmware-bestand" #. TRANSLATORS: command description msgid "Attach DFU capable device back to runtime" msgstr "Apparaat geschikt voor DFU aankoppelen aan de runtime" #. TRANSLATORS: command description msgid "Read firmware from device into a file" msgstr "Firmware van het apparaat uitlezen naar een bestand" #. TRANSLATORS: command description msgid "Read firmware from one partition into a file" msgstr "Firmware van één partitie uitlezen naar een bestand" #. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "Firmware van een bestand naar een apparaat schrijven" #. TRANSLATORS: command description msgid "Write firmware from file into one partition" msgstr "Firmware van een bestand naar één partitie schrijven" #. TRANSLATORS: command description msgid "List currently attached DFU capable devices" msgstr "Lijst weergeven van momenteel aangekoppelde voor DFU geschikte apparaten" #. TRANSLATORS: command description msgid "Detach currently attached DFU capable device" msgstr "Momenteel aangekoppeld voor DFU geschikt apparaat afkoppelen" #. TRANSLATORS: command description msgid "Dump details about a firmware file" msgstr "Details over een firmware-bestand wegschrijven" #. TRANSLATORS: command description msgid "Watch DFU devices being hotplugged" msgstr "Het hotpluggen van DFU-apparaten weergeven" #. TRANSLATORS: command description msgid "Encrypt firmware data" msgstr "Firmware-gegevens versleutelen" #. TRANSLATORS: command description msgid "Decrypt firmware data" msgstr "Firmware-gegevens ontsleutelen" #. TRANSLATORS: command description msgid "Sets metadata on a firmware file" msgstr "Stelt metadata in op een firmware-bestand" #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "DFU-hulpmiddel" #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Het doorvoeren van argumenten is mislukt" #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Foutopsporingsinformatie weergeven voor alle bestanden" #. TRANSLATORS: for the --verbose arg msgid "Debugging Options" msgstr "Foutopsporingsopties" #. TRANSLATORS: for the --verbose arg msgid "Show debugging options" msgstr "Foutopsporingsopties weergeven" #. TRANSLATORS: exit after we've started up, used for user profiling msgid "Exit after a small delay" msgstr "Afsluiten na een korte vertraging" #. TRANSLATORS: exit straight away, used for automatic profiling msgid "Exit after the engine has loaded" msgstr "Afsluiten nadat het engine geladen is" #. TRANSLATORS: program name msgid "Firmware Update Daemon" msgstr "Firmware Update Daemon" #. TRANSLATORS: program summary msgid "Firmware Update D-Bus Service" msgstr "Firmware Update D-Bus-dienst" #. TRANSLATORS: daemon is inactive msgid "Idle" msgstr "Slaapt" #. TRANSLATORS: decompressing the firmware file msgid "Decompressing firmware" msgstr "Bezig met uitpakken van firmware" #. TRANSLATORS: parsing the firmware information msgid "Loading firmware" msgstr "Bezig met laden van firmware" #. TRANSLATORS: restarting the device to pick up new F/W msgid "Restarting device" msgstr "Bezig met herstarten van apparaat" #. TRANSLATORS: writing to the flash chips msgid "Writing firmware to device" msgstr "Bezig met schrijven van firmware naar het apparaat" #. TRANSLATORS: verifying we wrote the firmware correctly msgid "Verifying firmware from device" msgstr "Bezig met controleren van firmware van apparaat" #. TRANSLATORS: scheduing an update to be done on the next boot msgid "Scheduling upgrade" msgstr "Bezig met inplannen van upgrade" #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "Er is geen hardware aangetroffen die in staat is om firmware bij te kunnen werken" #. TRANSLATOR: the provider only supports offline msgid "Retrying as an offline update" msgstr "Bezig met opnieuw proberen als een offline update" #. 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 "Bezig met herinstalleren van %s met %s..." #. 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 "Bezig met afwaarderen van %s van %s naar %s..." #. 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 "Bezig met bijwerken van %s van %s naar %s..." msgid "Done!" msgstr "Afgerond!" #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" msgstr "%s heeft firmware-updates:" #. TRANSLATORS: a GUID for the hardware msgid "GUID" msgstr "GUID" #. TRANSLATORS: section header for firmware version msgid "Version" msgstr "Versie" #. TRANSLATORS: section header for firmware checksum msgid "Checksum" msgstr "Controlesom" msgid "Checksum Type" msgstr "" #. TRANSLATORS: section header for firmware remote http:// msgid "Location" msgstr "Locatie" #. TRANSLATORS: section header for long firmware desc msgid "Description" msgstr "Omschrijving" #. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "Extra foutopsporingsinformatie weergeven" #. TRANSLATORS: command line option msgid "Perform the installation offline where possible" msgstr "De installatie offline uitvoeren indien mogelijk" #. TRANSLATORS: command line option msgid "Allow re-installing existing firmware versions" msgstr "Herinstalleren van bestaande firmware-versies toestaan" #. TRANSLATORS: command line option msgid "Allow downgrading firmware versions" msgstr "Afwaarderen van oude firmware-versies toestaan" #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Alle apparaten verkrijgen die firmware-updates ondersteunen" #. TRANSLATORS: command description msgid "Install prepared updates now" msgstr "Voorbereide updates nu installeren" #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "Een firmware-bestand op deze hardware installeren" #. TRANSLATORS: command description msgid "Gets details about a firmware file" msgstr "Verkrijgt details over een firmware-bestand" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "Verkrijgt een lijst van updates voor verbonden hardware" #. TRANSLATORS: command description msgid "Updates all firmware to latest versions available" msgstr "Werkt alle firmware bij naar de nieuwste versies die beschikbaar zijn" #. TRANSLATORS: command description msgid "Gets the cryptographic hash of the dumped firmware" msgstr "Verkrijgt een cryptografische som van de weggeschreven firmware" #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Ontgrendelt het apparaat voor firmware-toegang" #. TRANSLATORS: command description msgid "Clears the results from the last update" msgstr "Wist de resultaten van de laatste update" #. TRANSLATORS: command description msgid "Gets the results from the last update" msgstr "Verkrijgt de resultaten van de laatste update" #. TRANSLATORS: command description msgid "Refresh metadata from remote server" msgstr "Metadata verversen vanuit externe server" #. TRANSLATORS: command description msgid "Dump the ROM checksum" msgstr "De ROM-controlesom wegschrijven" #. TRANSLATORS: command description msgid "Update the stored metadata with current ROM contents" msgstr "De opgeslagen metadata bijwerken met de huidige ROM-inhoud" #. TRANSLATORS: program name msgid "Firmware Utility" msgstr "Firmware-hulpmiddel" fwupd-0.7.0/po/oc.po000066400000000000000000000250671267747510300142500ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Translators: # Cédric Valmary , 2016 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-04-01 14:38+0100\n" "PO-Revision-Date: 2016-04-01 13:38+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Occitan (post 1500) (http://www.transifex.com/hughsie/fwupd/language/oc/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: oc\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" msgid "Install signed system firmware" msgstr "" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on this machine" msgstr "" msgid "Install unsigned system firmware" msgstr "" msgid "Install old version of system firmware" msgstr "" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" msgstr "" msgid "Install signed device firmware" msgstr "" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to update the firmware on a removable device" msgstr "" msgid "Install unsigned device firmware" msgstr "" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to downgrade the firmware on a removable device" msgstr "" msgid "Unlock the device to allow access" msgstr "" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" msgstr "" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" msgstr "Aliàs de %s" #. TRANSLATORS: error message msgid "Command not found" msgstr "" #. TRANSLATORS: when an action has completed msgid "OK" msgstr "D'acòrdi" #. TRANSLATORS: when moving from runtime to DFU mode msgid "Detaching" msgstr "Destacament" #. TRANSLATORS: when moving from DFU to runtime mode msgid "Attaching" msgstr "Estacament" #. TRANSLATORS: when copying from host to device msgid "Downloading" msgstr "Telecargament" #. TRANSLATORS: when copying from device to host msgid "Uploading" msgstr "Cargament" #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Apondut" #. TRANSLATORS: this is when a device is hotplugged msgid "Removed" msgstr "Suprimit" #. TRANSLATORS: this is when a device is hotplugged msgid "Changed" msgstr "Cambiat" #. TRANSLATORS: this is when a device ctrl+c's a watch msgid "Cancelled" msgstr "Anullat" #. TRANSLATORS: Appstream ID for the hardware type msgid "ID" msgstr "ID" #. TRANSLATORS: interface name, e.g. "Flash" msgid "Name" msgstr "Nom" #. TRANSLATORS: this is the encryption method used when writing msgid "Cipher" msgstr "Cipher" #. TRANSLATORS: these are areas of memory on the chip msgid "Region" msgstr "Region" #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Trobat" #. TRANSLATORS: probably not run as root... #. TRANSLATORS: device has failed to report status #. TRANSLATORS: device status, e.g. "OK" msgid "Status" msgstr "Estatut" msgid "Unknown: permission denied" msgstr "" #. TRANSLATORS: device mode, e.g. runtime or DFU msgid "Mode" msgstr "Mòde" #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Estat" #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" msgstr "" #. TRANSLATORS: command description msgid "Convert firmware to DFU format" msgstr "" #. TRANSLATORS: command description msgid "Merge multiple firmware files into one" msgstr "" #. TRANSLATORS: command description msgid "Set vendor ID on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Set product ID on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Set release version on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Set alternative number on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Set alternative name on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Attach DFU capable device back to runtime" msgstr "" #. TRANSLATORS: command description msgid "Read firmware from device into a file" msgstr "" #. TRANSLATORS: command description msgid "Read firmware from one partition into a file" msgstr "" #. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "" #. TRANSLATORS: command description msgid "Write firmware from file into one partition" msgstr "" #. TRANSLATORS: command description msgid "List currently attached DFU capable devices" msgstr "" #. TRANSLATORS: command description msgid "Detach currently attached DFU capable device" msgstr "" #. TRANSLATORS: command description msgid "Dump details about a firmware file" msgstr "" #. TRANSLATORS: command description msgid "Watch DFU devices being hotplugged" msgstr "" #. TRANSLATORS: command description msgid "Encrypt firmware data" msgstr "" #. TRANSLATORS: command description msgid "Decrypt firmware data" msgstr "" #. TRANSLATORS: command description msgid "Sets metadata on a firmware file" msgstr "" #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "" #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Fracàs de l'analisi dels paramètres" #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Mostrar las informacions de desbugatge per totes los fichièrs" #. TRANSLATORS: for the --verbose arg msgid "Debugging Options" msgstr "Opcions de desbugatge" #. TRANSLATORS: for the --verbose arg msgid "Show debugging options" msgstr "Mostrar las opcions de desbugatge" #. TRANSLATORS: exit after we've started up, used for user profiling msgid "Exit after a small delay" msgstr "Quitar aprèp un brèu relambi" #. TRANSLATORS: exit straight away, used for automatic profiling msgid "Exit after the engine has loaded" msgstr "Quitar aprèp lo cargament del motor" #. TRANSLATORS: program name msgid "Firmware Update Daemon" msgstr "" #. TRANSLATORS: program summary msgid "Firmware Update D-Bus Service" msgstr "Servici D-Bus de mesa a jorn dels micrologicials" #. TRANSLATORS: daemon is inactive msgid "Idle" msgstr "En espèra" #. TRANSLATORS: decompressing the firmware file msgid "Decompressing firmware" msgstr "Descompression del micrologicial" #. TRANSLATORS: parsing the firmware information msgid "Loading firmware" msgstr "Cargament del micrologicial" #. TRANSLATORS: restarting the device to pick up new F/W msgid "Restarting device" msgstr "Reaviada del periferic" #. TRANSLATORS: writing to the flash chips msgid "Writing firmware to device" msgstr "Escritura del micrologicial sul periferic" #. TRANSLATORS: verifying we wrote the firmware correctly msgid "Verifying firmware from device" msgstr "Verificacion del micrologicial del periferic" #. TRANSLATORS: scheduing an update to be done on the next boot msgid "Scheduling upgrade" msgstr "Planificacion de la mesa a jorn" #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "Cap de material amb de capacitats de mesa a jorn del micrologicial es pas estat detectat" #. TRANSLATOR: the provider only supports offline msgid "Retrying as an offline update" msgstr "" #. 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 "Reïnstallacion de %s en %s" #. 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 "Retrogradacion de %s de %s en %s" #. 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 "Mesa a jorn de %s de %s en %s" msgid "Done!" msgstr "Acabat !" #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" msgstr "" #. TRANSLATORS: a GUID for the hardware msgid "GUID" msgstr "GUID" #. TRANSLATORS: section header for firmware version msgid "Version" msgstr "Version" #. TRANSLATORS: section header for firmware checksum msgid "Checksum" msgstr "Soma de contraròtle" msgid "Checksum Type" msgstr "" #. TRANSLATORS: section header for firmware remote http:// msgid "Location" msgstr "Emplaçament" #. TRANSLATORS: section header for long firmware desc msgid "Description" msgstr "Descripcion" #. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "Mòstra d'informations de desbugatge complementàrias" #. TRANSLATORS: command line option msgid "Perform the installation offline where possible" msgstr "" #. TRANSLATORS: command line option msgid "Allow re-installing existing firmware versions" msgstr "" #. TRANSLATORS: command line option msgid "Allow downgrading firmware versions" msgstr "" #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Obténer la lista dels periferics que supòrtan las mesas a jorn de micrologicial" #. TRANSLATORS: command description msgid "Install prepared updates now" msgstr "Installar immediatament las mesas a jorn preparadas" #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "Installar un fichièr de micrologicial sus aqueste material" #. TRANSLATORS: command description msgid "Gets details about a firmware file" msgstr "Obténer los detalhs d'un fichièr de micrologicial" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "" #. TRANSLATORS: command description msgid "Updates all firmware to latest versions available" msgstr "" #. TRANSLATORS: command description msgid "Gets the cryptographic hash of the dumped firmware" msgstr "" #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "" #. TRANSLATORS: command description msgid "Clears the results from the last update" msgstr "" #. TRANSLATORS: command description msgid "Gets the results from the last update" msgstr "" #. TRANSLATORS: command description msgid "Refresh metadata from remote server" msgstr "" #. TRANSLATORS: command description msgid "Dump the ROM checksum" msgstr "" #. TRANSLATORS: command description msgid "Update the stored metadata with current ROM contents" msgstr "" #. TRANSLATORS: program name msgid "Firmware Utility" msgstr "" fwupd-0.7.0/po/pl.po000066400000000000000000000327421267747510300142600ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Translators: # Piotr DrÄ…g , 2015-2016 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-04-01 14:38+0100\n" "PO-Revision-Date: 2016-04-01 13:38+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Polish (http://www.transifex.com/hughsie/fwupd/language/pl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: pl\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" msgid "Install signed system firmware" msgstr "Instalacja podpisanego oprogramowania sprzÄ™towego komputera" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on this machine" msgstr "Wymagane jest uwierzytelnienie, aby zaktualizować oprogramowanie sprzÄ™towe tego komputera" msgid "Install unsigned system firmware" msgstr "Instalacja niepodpisanego oprogramowania sprzÄ™towego komputera" msgid "Install old version of system firmware" msgstr "Instalacja poprzedniej wersji oprogramowania sprzÄ™towego komputera" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" msgstr "Wymagane jest uwierzytelnienie, aby zainstalować poprzedniÄ… wersjÄ™ oprogramowania sprzÄ™towego tego komputera" msgid "Install signed device firmware" msgstr "Instalacja podpisanego oprogramowania sprzÄ™towego urzÄ…dzenia" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to update the firmware on a removable device" msgstr "Wymagane jest uwierzytelnienie, aby zaktualizować oprogramowanie sprzÄ™towe wymiennego urzÄ…dzenia" msgid "Install unsigned device firmware" msgstr "Instalacja niepodpisanego oprogramowania sprzÄ™towego urzÄ…dzenia" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to downgrade the firmware on a removable device" msgstr "Wymagane jest uwierzytelnienie, aby zainstalować poprzedniÄ… wersjÄ™ oprogramowania sprzÄ™towego urzÄ…dzenia wymiennego" msgid "Unlock the device to allow access" msgstr "Odblokowanie urzÄ…dzenia" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" msgstr "Wymagane jest uwierzytelnienie, aby odblokować urzÄ…dzenie" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" msgstr "Alias do „%sâ€" #. TRANSLATORS: error message msgid "Command not found" msgstr "Nie odnaleziono polecenia" #. TRANSLATORS: when an action has completed msgid "OK" msgstr "OK" #. TRANSLATORS: when moving from runtime to DFU mode msgid "Detaching" msgstr "Odłączanie" #. TRANSLATORS: when moving from DFU to runtime mode msgid "Attaching" msgstr "Podłączanie" #. TRANSLATORS: when copying from host to device msgid "Downloading" msgstr "Pobieranie" #. TRANSLATORS: when copying from device to host msgid "Uploading" msgstr "WysyÅ‚anie" #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Dodano" #. TRANSLATORS: this is when a device is hotplugged msgid "Removed" msgstr "UsuniÄ™to" #. TRANSLATORS: this is when a device is hotplugged msgid "Changed" msgstr "Zmieniono" #. TRANSLATORS: this is when a device ctrl+c's a watch msgid "Cancelled" msgstr "Anulowano" #. TRANSLATORS: Appstream ID for the hardware type msgid "ID" msgstr "Identyfikator" #. TRANSLATORS: interface name, e.g. "Flash" msgid "Name" msgstr "Nazwa" #. TRANSLATORS: this is the encryption method used when writing msgid "Cipher" msgstr "Szyfr" #. TRANSLATORS: these are areas of memory on the chip msgid "Region" msgstr "Region" #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Odnaleziono" #. TRANSLATORS: probably not run as root... #. TRANSLATORS: device has failed to report status #. TRANSLATORS: device status, e.g. "OK" msgid "Status" msgstr "Stan" msgid "Unknown: permission denied" msgstr "Nieznane: brak uprawnieÅ„" #. TRANSLATORS: device mode, e.g. runtime or DFU msgid "Mode" msgstr "Tryb" #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Stan" #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" msgstr "Poprawki" #. TRANSLATORS: command description msgid "Convert firmware to DFU format" msgstr "Konwertuje oprogramowanie sprzÄ™towe do formatu DFU" #. TRANSLATORS: command description msgid "Merge multiple firmware files into one" msgstr "ÅÄ…czy wiele plików oprogramowania sprzÄ™towego w jeden plik" #. TRANSLATORS: command description msgid "Set vendor ID on firmware file" msgstr "Ustawia identyfikator producenta pliku oprogramowania sprzÄ™towego" #. TRANSLATORS: command description msgid "Set product ID on firmware file" msgstr "Ustawia identyfikator produktu pliku oprogramowania sprzÄ™towego" #. TRANSLATORS: command description msgid "Set release version on firmware file" msgstr "Ustawia wersjÄ™ wydania pliku oprogramowania sprzÄ™towego" #. TRANSLATORS: command description msgid "Set alternative number on firmware file" msgstr "Ustawia alternatywny numer pliku oprogramowania sprzÄ™towego" #. TRANSLATORS: command description msgid "Set alternative name on firmware file" msgstr "Ustawia alternatywnÄ… nazwÄ™ pliku oprogramowania sprzÄ™towego" #. TRANSLATORS: command description msgid "Attach DFU capable device back to runtime" msgstr "Podłącza urzÄ…dzenie DFU z powrotem do uruchamiania systemu" #. TRANSLATORS: command description msgid "Read firmware from device into a file" msgstr "Odczytuje oprogramowanie sprzÄ™towe z urzÄ…dzenia do pliku" #. TRANSLATORS: command description msgid "Read firmware from one partition into a file" msgstr "Odczytuje oprogramowanie sprzÄ™towe z jednej partycji do pliku" #. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "Zapisuje oprogramowanie sprzÄ™towe z pliku na urzÄ…dzenie" #. TRANSLATORS: command description msgid "Write firmware from file into one partition" msgstr "Zapisuje oprogramowanie sprzÄ™towe z pliku na jednÄ… partycjÄ™" #. TRANSLATORS: command description msgid "List currently attached DFU capable devices" msgstr "WyÅ›wietla listÄ™ obecnie podłączonych urzÄ…dzeÅ„ DFU" #. TRANSLATORS: command description msgid "Detach currently attached DFU capable device" msgstr "Odłącza obecnie podłączone urzÄ…dzenie DFU" #. TRANSLATORS: command description msgid "Dump details about a firmware file" msgstr "Zrzuca informacje o pliku oprogramowania sprzÄ™towego" #. TRANSLATORS: command description msgid "Watch DFU devices being hotplugged" msgstr "Obserwuje podłączanie urzÄ…dzeÅ„ DFU w czasie dziaÅ‚ania" #. TRANSLATORS: command description msgid "Encrypt firmware data" msgstr "Szyfruje dane oprogramowania sprzÄ™towego" #. TRANSLATORS: command description msgid "Decrypt firmware data" msgstr "Odszyfrowuje dane oprogramowania sprzÄ™towego" #. TRANSLATORS: command description msgid "Sets metadata on a firmware file" msgstr "Ustawia metadane pliku oprogramowania sprzÄ™towego" #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "NarzÄ™dzie DFU" #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Przetworzenie parametrów siÄ™ nie powiodÅ‚o" #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "WyÅ›wietla informacje o debugowaniu dla wszystkich plików" #. TRANSLATORS: for the --verbose arg msgid "Debugging Options" msgstr "Opcje debugowania" #. TRANSLATORS: for the --verbose arg msgid "Show debugging options" msgstr "WyÅ›wietla opcje debugowania" #. TRANSLATORS: exit after we've started up, used for user profiling msgid "Exit after a small delay" msgstr "KoÅ„czy dziaÅ‚anie po maÅ‚ym opóźnieniu" #. TRANSLATORS: exit straight away, used for automatic profiling msgid "Exit after the engine has loaded" msgstr "KoÅ„czy dziaÅ‚anie po wczytaniu mechanizmu" #. TRANSLATORS: program name msgid "Firmware Update Daemon" msgstr "UsÅ‚uga aktualizacji oprogramowania sprzÄ™towego" #. TRANSLATORS: program summary msgid "Firmware Update D-Bus Service" msgstr "UsÅ‚uga D-Bus aktualizacji oprogramowania sprzÄ™towego" #. TRANSLATORS: daemon is inactive msgid "Idle" msgstr "Bezczynne" #. TRANSLATORS: decompressing the firmware file msgid "Decompressing firmware" msgstr "Dekompresowanie oprogramowania sprzÄ™towego" #. TRANSLATORS: parsing the firmware information msgid "Loading firmware" msgstr "Wczytywanie oprogramowania sprzÄ™towego" #. TRANSLATORS: restarting the device to pick up new F/W msgid "Restarting device" msgstr "Ponowne uruchamianie urzÄ…dzenia" #. TRANSLATORS: writing to the flash chips msgid "Writing firmware to device" msgstr "Zapisywanie oprogramowania sprzÄ™towego w urzÄ…dzeniu" #. TRANSLATORS: verifying we wrote the firmware correctly msgid "Verifying firmware from device" msgstr "Sprawdzanie poprawnoÅ›ci oprogramowania sprzÄ™towego z urzÄ…dzenia" #. TRANSLATORS: scheduing an update to be done on the next boot msgid "Scheduling upgrade" msgstr "Planowanie aktualizacji" #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "Nie wykryto sprzÄ™tu z możliwoÅ›ciÄ… aktualizacji jego oprogramowania" #. TRANSLATOR: the provider only supports offline msgid "Retrying as an offline update" msgstr "Próbowanie ponownie jako aktualizacja w trybie offline" #. 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 "Ponowne instalowanie %s za pomocÄ… %s… " #. 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 "Instalowanie poprzedniej wersji %s z %s do %s… " #. 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 "Aktualizowanie %s z wersji %s do %s… " msgid "Done!" msgstr "Gotowe." #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" msgstr "DostÄ™pne sÄ… aktualizacje oprogramowania sprzÄ™towego dla urzÄ…dzenia %s:" #. TRANSLATORS: a GUID for the hardware msgid "GUID" msgstr "GUID" #. TRANSLATORS: section header for firmware version msgid "Version" msgstr "Wersja" #. TRANSLATORS: section header for firmware checksum msgid "Checksum" msgstr "Suma kontrolna" msgid "Checksum Type" msgstr "" #. TRANSLATORS: section header for firmware remote http:// msgid "Location" msgstr "PoÅ‚ożenie" #. TRANSLATORS: section header for long firmware desc msgid "Description" msgstr "Opis" #. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "WyÅ›wietla dodatkowe informacje o debugowaniu" #. TRANSLATORS: command line option msgid "Perform the installation offline where possible" msgstr "Wykonuje instalacjÄ™ w trybie offline, jeÅ›li to możliwe" #. TRANSLATORS: command line option msgid "Allow re-installing existing firmware versions" msgstr "Umożliwia ponowne instalowanie istniejÄ…cych wersji oprogramowania sprzÄ™towego" #. TRANSLATORS: command line option msgid "Allow downgrading firmware versions" msgstr "Umożliwia instalowanie poprzednich wersji oprogramowania sprzÄ™towego" #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Uzyskuje wszystkie urzÄ…dzenia obsÅ‚ugujÄ…ce aktualizacje oprogramowania sprzÄ™towego" #. TRANSLATORS: command description msgid "Install prepared updates now" msgstr "Instaluje przygotowanÄ… aktualizacjÄ™ teraz" #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "Instaluje plik oprogramowania sprzÄ™towego na tym sprzÄ™cie" #. TRANSLATORS: command description msgid "Gets details about a firmware file" msgstr "Uzyskuje informacje o pliku oprogramowania sprzÄ™towego" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "Uzyskuje listÄ™ aktualizacji dla podłączonego sprzÄ™tu" #. TRANSLATORS: command description msgid "Updates all firmware to latest versions available" msgstr "Aktualizuje caÅ‚e oprogramowanie sprzÄ™towe do najnowszych dostÄ™pnych wersji" #. TRANSLATORS: command description msgid "Gets the cryptographic hash of the dumped firmware" msgstr "Pobiera kryptograficznÄ… sumÄ™ kontrolnÄ… zrzuconego oprogramowania sprzÄ™towego" #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Odblokowuje urzÄ…dzenie" #. TRANSLATORS: command description msgid "Clears the results from the last update" msgstr "CzyÅ›ci wyniki z ostatniej aktualizacji" #. TRANSLATORS: command description msgid "Gets the results from the last update" msgstr "Uzyskuje wyniki z ostatniej aktualizacji" #. TRANSLATORS: command description msgid "Refresh metadata from remote server" msgstr "OdÅ›wieża metadane ze zdalnego serwera" #. TRANSLATORS: command description msgid "Dump the ROM checksum" msgstr "Zrzuca sumÄ™ kontrolnÄ… pamiÄ™ci ROM" #. TRANSLATORS: command description msgid "Update the stored metadata with current ROM contents" msgstr "Aktualizuje przechowywane metadane bieżącÄ… zawartoÅ›ciÄ… pamiÄ™ci ROM" #. TRANSLATORS: program name msgid "Firmware Utility" msgstr "NarzÄ™dzie oprogramowania sprzÄ™towego" fwupd-0.7.0/po/pt_BR.po000066400000000000000000000313451267747510300146510ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Translators: # Derek Stavis , 2015 # Rafael Fontenelle , 2015-2016 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-04-01 14:38+0100\n" "PO-Revision-Date: 2016-04-01 13:38+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Portuguese (Brazil) (http://www.transifex.com/hughsie/fwupd/language/pt_BR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: pt_BR\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" msgid "Install signed system firmware" msgstr "Instalar firmware assinado no sistema" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on this machine" msgstr "É requerida autenticação para atualizar o firmware nesta máquina" msgid "Install unsigned system firmware" msgstr "Instalar firmware não assinado no sistema" msgid "Install old version of system firmware" msgstr "Instalar versão antiga do firmware no sistema" #. 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" msgid "Install signed device firmware" msgstr "Instalar firmware assinado no dispositivo" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to update the firmware on a removable device" msgstr "É requerida autenticação para atualizar o firmware em dispositivo removível" msgid "Install unsigned device firmware" msgstr "Instalar firmware não assinado no dispositivo" #. 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" msgid "Unlock the device to allow access" msgstr "Desbloquear o dispositivo para permitir acesso" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" msgstr "É requerida autenticação para desbloquear um dispositivo" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" msgstr "Atalho para %s" #. TRANSLATORS: error message msgid "Command not found" msgstr "Comando não encontrado" #. TRANSLATORS: when an action has completed msgid "OK" msgstr "OK" #. TRANSLATORS: when moving from runtime to DFU mode msgid "Detaching" msgstr "Desanexando" #. TRANSLATORS: when moving from DFU to runtime mode msgid "Attaching" msgstr "Anexando" #. TRANSLATORS: when copying from host to device msgid "Downloading" msgstr "Baixando" #. TRANSLATORS: when copying from device to host msgid "Uploading" msgstr "Enviando" #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Adicionado" #. TRANSLATORS: this is when a device is hotplugged msgid "Removed" msgstr "Removido" #. TRANSLATORS: this is when a device is hotplugged msgid "Changed" msgstr "Alterado" #. TRANSLATORS: this is when a device ctrl+c's a watch msgid "Cancelled" msgstr "Cancelado" #. TRANSLATORS: Appstream ID for the hardware type msgid "ID" msgstr "ID" #. TRANSLATORS: interface name, e.g. "Flash" msgid "Name" msgstr "Nome" #. TRANSLATORS: this is the encryption method used when writing msgid "Cipher" msgstr "Cifra" #. TRANSLATORS: these are areas of memory on the chip msgid "Region" msgstr "Região" #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Encontrado" #. TRANSLATORS: probably not run as root... #. TRANSLATORS: device has failed to report status #. TRANSLATORS: device status, e.g. "OK" msgid "Status" msgstr "Status" msgid "Unknown: permission denied" msgstr "Desconhecido: permissão negada" #. TRANSLATORS: device mode, e.g. runtime or DFU msgid "Mode" msgstr "Modo" #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Estado" #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" msgstr "Gambiarra" #. TRANSLATORS: command description msgid "Convert firmware to DFU format" msgstr "Converter firmware para formato DFU" #. TRANSLATORS: command description msgid "Merge multiple firmware files into one" msgstr "Mesclar múltiplos arquivos de firmware em um" #. TRANSLATORS: command description msgid "Set vendor ID on firmware file" msgstr "Definir ID de fabricante no arquivo de firmware" #. TRANSLATORS: command description msgid "Set product ID on firmware file" msgstr "Definir ID de produto no arquivo de firmware" #. TRANSLATORS: command description msgid "Set release version on firmware file" msgstr "Definir versão de lançamento no arquivo de firmware" #. TRANSLATORS: command description msgid "Set alternative number on firmware file" msgstr "Definir número alternativo no arquivo de firmware" #. TRANSLATORS: command description msgid "Set alternative name on firmware file" msgstr "Definir nome alternativo no arquivo de firmware" #. TRANSLATORS: command description msgid "Attach DFU capable device back to runtime" msgstr "Anexar dispositivo com capacidade de DFU em tempo real" #. TRANSLATORS: command description msgid "Read firmware from device into a file" msgstr "Ler firmware do dispositivo para um arquivo" #. TRANSLATORS: command description msgid "Read firmware from one partition into a file" msgstr "Ler firmware de uma partição para um arquivo" #. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "Escrever firmware do arquivo para o dispositivo" #. TRANSLATORS: command description msgid "Write firmware from file into one partition" msgstr "Escrever firmware do arquivo para uma partição" #. TRANSLATORS: command description msgid "List currently attached DFU capable devices" msgstr "Lista de dispositivos com capacidade de DFU atualmente anexados" #. TRANSLATORS: command description msgid "Detach currently attached DFU capable device" msgstr "Desanexar dispositivos com capacidade de DFU atualmente anexados" #. TRANSLATORS: command description msgid "Dump details about a firmware file" msgstr "Despejar detalhes sobre um arquivo firmware" #. TRANSLATORS: command description msgid "Watch DFU devices being hotplugged" msgstr "Monitorar dispositivos DFU sendo conectados" #. TRANSLATORS: command description msgid "Encrypt firmware data" msgstr "Criptografar dados do firmware" #. TRANSLATORS: command description msgid "Decrypt firmware data" msgstr "Descriptografar dados do firmware" #. TRANSLATORS: command description msgid "Sets metadata on a firmware file" msgstr "Define metadados em um arquivo de firmware" #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "Utilitário DFU" #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Falha ao interpretar argumentos" #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Mostrar informações de depuração para todos os arquivos" #. TRANSLATORS: for the --verbose arg msgid "Debugging Options" msgstr "Opções de depuração" #. TRANSLATORS: for the --verbose arg msgid "Show debugging options" msgstr "Mostrar opções de depuração" #. TRANSLATORS: exit after we've started up, used for user profiling msgid "Exit after a small delay" msgstr "Sair após pequeno atraso" #. TRANSLATORS: exit straight away, used for automatic profiling msgid "Exit after the engine has loaded" msgstr "Sair após o carregamento do motor" #. TRANSLATORS: program name msgid "Firmware Update Daemon" msgstr "Daemon de Atualização de Firmware" #. TRANSLATORS: program summary msgid "Firmware Update D-Bus Service" msgstr "Serviço D-Bus de Atualização de Firmware" #. TRANSLATORS: daemon is inactive msgid "Idle" msgstr "Ocioso" #. TRANSLATORS: decompressing the firmware file msgid "Decompressing firmware" msgstr "Descomprimindo firmware" #. TRANSLATORS: parsing the firmware information msgid "Loading firmware" msgstr "Carregando firmware" #. TRANSLATORS: restarting the device to pick up new F/W msgid "Restarting device" msgstr "Reiniciando dispositivo" #. TRANSLATORS: writing to the flash chips msgid "Writing firmware to device" msgstr "Escrevendo firmware no dispositivo" #. TRANSLATORS: verifying we wrote the firmware correctly msgid "Verifying firmware from device" msgstr "Verificando firmware do dispositivo" #. TRANSLATORS: scheduing an update to be done on the next boot msgid "Scheduling upgrade" msgstr "Agendando atualização" #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "Nenhum periférico com capacidade de atualização de firmware foi detectado" #. TRANSLATOR: the provider only supports offline msgid "Retrying as an offline update" msgstr "Tentando novamente como atualização offline" #. 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 "Reinstalando %s com %s..." #. 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..." #. 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 "Atualizando %s de %s para %s..." msgid "Done!" msgstr "Feito!" #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" msgstr "%s tem atualizações:" #. TRANSLATORS: a GUID for the hardware msgid "GUID" msgstr "GUID" #. TRANSLATORS: section header for firmware version msgid "Version" msgstr "Versão" #. TRANSLATORS: section header for firmware checksum msgid "Checksum" msgstr "Soma de verificação" msgid "Checksum Type" msgstr "" #. TRANSLATORS: section header for firmware remote http:// msgid "Location" msgstr "Local" #. TRANSLATORS: section header for long firmware desc msgid "Description" msgstr "Descrição" #. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "Mostrar informações adicionais de depuração" #. TRANSLATORS: command line option msgid "Perform the installation offline where possible" msgstr "Executar a instalação offline quando possivel" #. TRANSLATORS: command line option msgid "Allow re-installing existing firmware versions" msgstr "Permitir reinstalar versões existentes de firmware" #. TRANSLATORS: command line option msgid "Allow downgrading firmware versions" msgstr "Permitir reverter versões de firmware" #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Obter todos os dispositivos que suportam atualizações de firmware" #. TRANSLATORS: command description msgid "Install prepared updates now" msgstr "Instalar as atualizações preparadas agora" #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "Instalar um arquivo de firmware neste periférico" #. TRANSLATORS: command description msgid "Gets details about a firmware file" msgstr "Obtém detalhes sobre um arquivo de firmware" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "Obtém a lista de atualizações para os periféricos conectados" #. TRANSLATORS: command description msgid "Updates all firmware to latest versions available" msgstr "Atualiza todos os firmwares para a última versão disponível" #. TRANSLATORS: command description msgid "Gets the cryptographic hash of the dumped firmware" msgstr "Obtém o hash criptográfico do firmware despejado" #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Desbloqueia o dispositivo para acesso do firmware" #. TRANSLATORS: command description msgid "Clears the results from the last update" msgstr "Limpa os resultados da última atualização" #. TRANSLATORS: command description msgid "Gets the results from the last update" msgstr "Obtém os resultados da última atualização" #. TRANSLATORS: command description msgid "Refresh metadata from remote server" msgstr "Renova metadados do servidor remoto" #. TRANSLATORS: command description msgid "Dump the ROM checksum" msgstr "Despeja a soma de verificação da ROM" #. TRANSLATORS: command description msgid "Update the stored metadata with current ROM contents" msgstr "Atualiza os metadados armazenados com o conteúdo da ROM atual" #. TRANSLATORS: program name msgid "Firmware Utility" msgstr "Utilitário de Firmware" fwupd-0.7.0/po/ru.po000066400000000000000000000375771267747510300143060ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Translators: # Serge Vylekzhanin , 2015-2016 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-04-01 14:38+0100\n" "PO-Revision-Date: 2016-04-01 13:38+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Russian (http://www.transifex.com/hughsie/fwupd/language/ru/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ru\n" "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n" msgid "Install signed system firmware" msgstr "УÑтановить подпиÑанную ÑиÑтемную микропрограмму" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on this machine" msgstr "Ð”Ð»Ñ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð¼Ð¸ÐºÑ€Ð¾Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ñ‹ на Ñтой машине требуетÑÑ Ð°ÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ" msgid "Install unsigned system firmware" msgstr "УÑтановить неподпиÑанную ÑиÑтемную микропрограмму" msgid "Install old version of system firmware" msgstr "УÑтановить Ñтарую верÑию ÑиÑтемной микропрограммы" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" msgstr "Ð”Ð»Ñ Ð¿Ð¾Ð½Ð¸Ð¶ÐµÐ½Ð¸Ñ Ð²ÐµÑ€Ñии микропрограммы на Ñтой машине требуетÑÑ Ð°ÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ" msgid "Install signed device firmware" msgstr "УÑтановить подпиÑанную микропрограмму уÑтройÑтва" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to update the firmware on a removable device" msgstr "Ð”Ð»Ñ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð¼Ð¸ÐºÑ€Ð¾Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ñ‹ на Ñъёмном уÑтройÑтве требуетÑÑ Ð°ÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ" msgid "Install unsigned device firmware" msgstr "УÑтановить неподпиÑанную микропрограмму уÑтройÑтва" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to downgrade the firmware on a removable device" msgstr "Ð”Ð»Ñ Ð¿Ð¾Ð½Ð¸Ð¶ÐµÐ½Ð¸Ñ Ð²ÐµÑ€Ñии микропрограммы на Ñъёмном уÑтройÑтве требуетÑÑ Ð°ÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ" msgid "Unlock the device to allow access" msgstr "Разблокировать уÑтройÑтво Ð´Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð´Ð¾Ñтупа" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" msgstr "Ð”Ð»Ñ Ñ€Ð°Ð·Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ уÑтройÑтва требуетÑÑ Ð°ÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" msgstr "ПÑевдоним %s" #. TRANSLATORS: error message msgid "Command not found" msgstr "Команда не найдена" #. TRANSLATORS: when an action has completed msgid "OK" msgstr "ОК" #. TRANSLATORS: when moving from runtime to DFU mode msgid "Detaching" msgstr "ОтÑоединение" #. TRANSLATORS: when moving from DFU to runtime mode msgid "Attaching" msgstr "ПриÑоединение" #. TRANSLATORS: when copying from host to device msgid "Downloading" msgstr "Получение" #. TRANSLATORS: when copying from device to host msgid "Uploading" msgstr "Выгрузка" #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Добавлено" #. TRANSLATORS: this is when a device is hotplugged msgid "Removed" msgstr "Удалено" #. TRANSLATORS: this is when a device is hotplugged msgid "Changed" msgstr "Изменено" #. TRANSLATORS: this is when a device ctrl+c's a watch msgid "Cancelled" msgstr "Отменено" #. TRANSLATORS: Appstream ID for the hardware type msgid "ID" msgstr "ID" #. TRANSLATORS: interface name, e.g. "Flash" msgid "Name" msgstr "Ðаименование" #. TRANSLATORS: this is the encryption method used when writing msgid "Cipher" msgstr "Шифр" #. TRANSLATORS: these are areas of memory on the chip msgid "Region" msgstr "Регион" #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Ðайдено" #. TRANSLATORS: probably not run as root... #. TRANSLATORS: device has failed to report status #. TRANSLATORS: device status, e.g. "OK" msgid "Status" msgstr "СтатуÑ" msgid "Unknown: permission denied" msgstr "ÐеизвеÑтно: доÑтуп запрещён" #. TRANSLATORS: device mode, e.g. runtime or DFU msgid "Mode" msgstr "Режим" #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "СоÑтоÑние" #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" msgstr "Проблемы" #. TRANSLATORS: command description msgid "Convert firmware to DFU format" msgstr "Преобразовать микропрограмму в формат DFU" #. TRANSLATORS: command description msgid "Merge multiple firmware files into one" msgstr "Объединить неÑколько файлов микропрограмм в один" #. TRANSLATORS: command description msgid "Set vendor ID on firmware file" msgstr "УÑтановить идентификатор Ð¿Ñ€Ð¾Ð¸Ð·Ð²Ð¾Ð´Ð¸Ñ‚ÐµÐ»Ñ Ð´Ð»Ñ Ñ„Ð°Ð¹Ð»Ð° микропрограммы" #. TRANSLATORS: command description msgid "Set product ID on firmware file" msgstr "УÑтановить идентификатор продукта Ð´Ð»Ñ Ñ„Ð°Ð¹Ð»Ð° микропрограммы" #. TRANSLATORS: command description msgid "Set release version on firmware file" msgstr "УÑтановить верÑию выпуÑка Ð´Ð»Ñ Ñ„Ð°Ð¹Ð»Ð° микропрограммы" #. TRANSLATORS: command description msgid "Set alternative number on firmware file" msgstr "УÑтановить альтернативный номер Ð´Ð»Ñ Ñ„Ð°Ð¹Ð»Ð° микропрограммы" #. TRANSLATORS: command description msgid "Set alternative name on firmware file" msgstr "УÑтановить альтернативное наименование Ð´Ð»Ñ Ñ„Ð°Ð¹Ð»Ð° микропрограммы" #. TRANSLATORS: command description msgid "Attach DFU capable device back to runtime" msgstr "Вернуть уÑтройÑтво Ñ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾ÑÑ‚Ñми DFU к иÑпользованию" #. TRANSLATORS: command description msgid "Read firmware from device into a file" msgstr "Считать микропрограмму из уÑтройÑтва файл" #. TRANSLATORS: command description msgid "Read firmware from one partition into a file" msgstr "Считать микропрограмму из одного раздела в файл" #. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "ЗапиÑать микропрограмму из файла на уÑтройÑтво" #. TRANSLATORS: command description msgid "Write firmware from file into one partition" msgstr "ЗапиÑать микропрограмму из файла на один раздел" #. TRANSLATORS: command description msgid "List currently attached DFU capable devices" msgstr "ВывеÑти ÑпиÑок подÑоединённых ÑÐµÐ¹Ñ‡Ð°Ñ ÑƒÑтройÑтв Ñ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾ÑÑ‚Ñми DFU" #. TRANSLATORS: command description msgid "Detach currently attached DFU capable device" msgstr "ОтÑоединить подÑоединённое ÑÐµÐ¹Ñ‡Ð°Ñ ÑƒÑтройÑтво Ñ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾ÑÑ‚Ñми DFU" #. TRANSLATORS: command description msgid "Dump details about a firmware file" msgstr "Создать дамп данных по файлу микропрограммы" #. TRANSLATORS: command description msgid "Watch DFU devices being hotplugged" msgstr "Ðаблюдать за уÑтройÑтвами DFU, которые ÑвлÑÑŽÑ‚ÑÑ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡Ñ‘Ð½Ð½Ñ‹Ð¼Ð¸" #. TRANSLATORS: command description msgid "Encrypt firmware data" msgstr "Зашифровать данные микропрограммы" #. TRANSLATORS: command description msgid "Decrypt firmware data" msgstr "РаÑшифровать данные микропрограммы" #. TRANSLATORS: command description msgid "Sets metadata on a firmware file" msgstr "УÑтанавливает метаданные файла микропрограммы" #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "СредÑтво работы Ñ DFU" #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Ðе удалоÑÑŒ разобрать аргументы" #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Показать отладочную информацию Ð´Ð»Ñ Ð²Ñех файлов" #. TRANSLATORS: for the --verbose arg msgid "Debugging Options" msgstr "Параметры отладки" #. TRANSLATORS: for the --verbose arg msgid "Show debugging options" msgstr "Показать параметры отладки" #. TRANSLATORS: exit after we've started up, used for user profiling msgid "Exit after a small delay" msgstr "Выйти поÑле небольшой задержки" #. TRANSLATORS: exit straight away, used for automatic profiling msgid "Exit after the engine has loaded" msgstr "Выйти поÑле загрузки движка" #. TRANSLATORS: program name msgid "Firmware Update Daemon" msgstr "Служба Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð¼Ð¸ÐºÑ€Ð¾Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ñ‹" #. TRANSLATORS: program summary msgid "Firmware Update D-Bus Service" msgstr "D-Bus Ñлужба Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð¼Ð¸ÐºÑ€Ð¾Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ñ‹" #. TRANSLATORS: daemon is inactive msgid "Idle" msgstr "БездейÑтвие" #. TRANSLATORS: decompressing the firmware file msgid "Decompressing firmware" msgstr "РаÑпаковка микропрограммы" #. TRANSLATORS: parsing the firmware information msgid "Loading firmware" msgstr "Загрузка микропрограммы" #. TRANSLATORS: restarting the device to pick up new F/W msgid "Restarting device" msgstr "ПерезапуÑк уÑтройÑтва" #. TRANSLATORS: writing to the flash chips msgid "Writing firmware to device" msgstr "ЗапиÑÑŒ микропрограммы на уÑтройÑтво" #. TRANSLATORS: verifying we wrote the firmware correctly msgid "Verifying firmware from device" msgstr "Проверка микропрограммы Ñ ÑƒÑтройÑтва" #. TRANSLATORS: scheduing an update to be done on the next boot msgid "Scheduling upgrade" msgstr "Планирование обновлениÑ" #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "Ðе обнаружено Ð¾Ð±Ð¾Ñ€ÑƒÐ´Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾Ñтью Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð¼Ð¸ÐºÑ€Ð¾Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ñ‹" #. TRANSLATOR: the provider only supports offline msgid "Retrying as an offline update" msgstr "ÐŸÐ¾Ð²Ñ‚Ð¾Ñ€Ð½Ð°Ñ Ð¿Ð¾Ð¿Ñ‹Ñ‚ÐºÐ° как в режиме автономного обновлениÑ" #. 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 "ПереуÑтановка %s Ñ %s…" #. 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 "Понижение верÑии %s Ñ %s на %s…" #. 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 "Обновление %s Ñ %s на %s…" msgid "Done!" msgstr "Готово!" #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" msgstr "У %s еÑть Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð¼Ð¸ÐºÑ€Ð¾Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ñ‹:" #. TRANSLATORS: a GUID for the hardware msgid "GUID" msgstr "GUID" #. TRANSLATORS: section header for firmware version msgid "Version" msgstr "ВерÑиÑ" #. TRANSLATORS: section header for firmware checksum msgid "Checksum" msgstr "ÐšÐ¾Ð½Ñ‚Ñ€Ð¾Ð»ÑŒÐ½Ð°Ñ Ñумма" msgid "Checksum Type" msgstr "" #. TRANSLATORS: section header for firmware remote http:// msgid "Location" msgstr "РаÑположение" #. TRANSLATORS: section header for long firmware desc msgid "Description" msgstr "ОпиÑание" #. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "Показать дополнительную отладочную информацию" #. TRANSLATORS: command line option msgid "Perform the installation offline where possible" msgstr "Выполнить уÑтановку в автономном режиме, где возможно" #. TRANSLATORS: command line option msgid "Allow re-installing existing firmware versions" msgstr "Разрешить повторную уÑтановку ÑущеÑтвующих верÑий микропрограмм" #. TRANSLATORS: command line option msgid "Allow downgrading firmware versions" msgstr "Разрешить понижение верÑий микропрограмм" #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Получить вÑе уÑтройÑтва, которые поддерживают Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð¼Ð¸ÐºÑ€Ð¾Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ñ‹" #. TRANSLATORS: command description msgid "Install prepared updates now" msgstr "УÑтановить подготовленные Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ ÑейчаÑ" #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "УÑтановить файл микропрограммы на Ñто оборудование" #. TRANSLATORS: command description msgid "Gets details about a firmware file" msgstr "Получает ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ файле микропрограммы" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "Получает ÑпиÑок обновлений Ð´Ð»Ñ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ð¾Ð³Ð¾ оборудованиÑ" #. TRANSLATORS: command description msgid "Updates all firmware to latest versions available" msgstr "ОбновлÑет вÑе микропрограммы до их поÑледних доÑтупных верÑий" #. TRANSLATORS: command description msgid "Gets the cryptographic hash of the dumped firmware" msgstr "Получает криптографичеÑкой Ñ…Ñш дампа микропрограммы" #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Разблокирует уÑтройÑтво Ð´Ð»Ñ Ð´Ð¾Ñтупа к микропрограмме" #. TRANSLATORS: command description msgid "Clears the results from the last update" msgstr "Очищает результаты c поÑледнего обновлениÑ" #. TRANSLATORS: command description msgid "Gets the results from the last update" msgstr "Получает результаты Ñ Ð¿Ð¾Ñледнего обновлениÑ" #. TRANSLATORS: command description msgid "Refresh metadata from remote server" msgstr "Обновить метаданные Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð½Ð¾Ð³Ð¾ Ñервера" #. TRANSLATORS: command description msgid "Dump the ROM checksum" msgstr "Создать дамп контрольной Ñуммы ПЗУ" #. TRANSLATORS: command description msgid "Update the stored metadata with current ROM contents" msgstr "Обновить Ñохранённые метаданные Ñ Ñ‚ÐµÐºÑƒÑ‰Ð¸Ð¼ Ñодержимым ПЗУ" #. TRANSLATORS: program name msgid "Firmware Utility" msgstr "СредÑтво работы Ñ Ð¼Ð¸ÐºÑ€Ð¾Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ð°Ð¼Ð¸" fwupd-0.7.0/po/sk.po000066400000000000000000000314071267747510300142570ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Translators: # DuÅ¡an Kazik , 2015-2016 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-04-01 14:38+0100\n" "PO-Revision-Date: 2016-04-01 13:38+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Slovak (http://www.transifex.com/hughsie/fwupd/language/sk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: sk\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" msgid "Install signed system firmware" msgstr "NainÅ¡taluje podpísaný firmvér systému" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on this machine" msgstr "Na aktualizovanie firmvéru v tomto poÄítaÄi je potrebné overenie totožnosti" msgid "Install unsigned system firmware" msgstr "NainÅ¡taluje nepodpísaný firmvér systému" msgid "Install old version of system firmware" msgstr "NainÅ¡taluje starÅ¡iu verziu firmvéru systému" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" msgstr "Vyžaduje sa overenie totožnosti na prechod na starÅ¡iu verziu firmvéru v tomto poÄítaÄi" msgid "Install signed device firmware" msgstr "NainÅ¡taluje podpísaný firmvér zariadenia" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to update the firmware on a removable device" msgstr "Vyžaduje sa overenie totožnosti na aktualizovanie firmvéru vymeniteľného zariadenia " msgid "Install unsigned device firmware" msgstr "NainÅ¡taluje nepodpísaný firmvér zariadenia" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to downgrade the firmware on a removable device" msgstr "Vyžaduje sa overenie totožnosti na prechod na starÅ¡iu verziu firmvéru vymeniteľného zariadenia" msgid "Unlock the device to allow access" msgstr "Odomknúť zariadenie na umožnenie prístupu" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" msgstr "Na odomknutie zariadenia sa vyžaduje overenie totožnosti" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" msgstr "Prezývka príkazu %s" #. TRANSLATORS: error message msgid "Command not found" msgstr "Príkaz nenájdený" #. TRANSLATORS: when an action has completed msgid "OK" msgstr "OK" #. TRANSLATORS: when moving from runtime to DFU mode msgid "Detaching" msgstr "Uvoľňuje sa" #. TRANSLATORS: when moving from DFU to runtime mode msgid "Attaching" msgstr "Pripája sa" #. TRANSLATORS: when copying from host to device msgid "Downloading" msgstr "Preberá sa" #. TRANSLATORS: when copying from device to host msgid "Uploading" msgstr "Odovzdáva sa" #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Pridané" #. TRANSLATORS: this is when a device is hotplugged msgid "Removed" msgstr "Odstránené" #. TRANSLATORS: this is when a device is hotplugged msgid "Changed" msgstr "Zmenené" #. TRANSLATORS: this is when a device ctrl+c's a watch msgid "Cancelled" msgstr "ZruÅ¡ené" #. TRANSLATORS: Appstream ID for the hardware type msgid "ID" msgstr "ID" #. TRANSLATORS: interface name, e.g. "Flash" msgid "Name" msgstr "Názov" #. TRANSLATORS: this is the encryption method used when writing msgid "Cipher" msgstr "Å ifra" #. TRANSLATORS: these are areas of memory on the chip msgid "Region" msgstr "OblasÅ¥" #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Nájdené" #. TRANSLATORS: probably not run as root... #. TRANSLATORS: device has failed to report status #. TRANSLATORS: device status, e.g. "OK" msgid "Status" msgstr "Stav" msgid "Unknown: permission denied" msgstr "Neznáme: prístup zamietnutý" #. TRANSLATORS: device mode, e.g. runtime or DFU msgid "Mode" msgstr "Režim" #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Stav" #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" msgstr "Neobvyklé požiadavky" #. TRANSLATORS: command description msgid "Convert firmware to DFU format" msgstr "Skonvertuje firmvér do formátu DFU" #. TRANSLATORS: command description msgid "Merge multiple firmware files into one" msgstr "ZlúÄi viacero súborov s firmvérami do jedného" #. TRANSLATORS: command description msgid "Set vendor ID on firmware file" msgstr "Nastaví ID výrobcu pre súbor s firmvérom" #. TRANSLATORS: command description msgid "Set product ID on firmware file" msgstr "Nastaví ID produktu pre súbor s firmvérom" #. TRANSLATORS: command description msgid "Set release version on firmware file" msgstr "Nastaví verziu vydania pre súbor s firmvérom" #. TRANSLATORS: command description msgid "Set alternative number on firmware file" msgstr "Nastaví alternatívne Äíslo pre súbor s firmvérom" #. TRANSLATORS: command description msgid "Set alternative name on firmware file" msgstr "Nastaví alternatívny názov pre súbor s firmvérom" #. TRANSLATORS: command description msgid "Attach DFU capable device back to runtime" msgstr "Zavedie zariadenie DFU späť do prevádzky" #. TRANSLATORS: command description msgid "Read firmware from device into a file" msgstr "PreÄíta firmvér zo zariadenia do súboru" #. TRANSLATORS: command description msgid "Read firmware from one partition into a file" msgstr "PreÄíta firmvér z jedného oddielu do súboru" #. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "Zapíše firmvér zo súboru do zariadenia" #. TRANSLATORS: command description msgid "Write firmware from file into one partition" msgstr "Zapíše firmvér zo súboru do jedného oddielu" #. TRANSLATORS: command description msgid "List currently attached DFU capable devices" msgstr "Vypíše zoznam aktuálne pripojených zariadení DFU" #. TRANSLATORS: command description msgid "Detach currently attached DFU capable device" msgstr "Odpojí aktuálne pripojené zariadenie DFU" #. TRANSLATORS: command description msgid "Dump details about a firmware file" msgstr "Zahodí podrobnosti o súbore s firmvérom" #. TRANSLATORS: command description msgid "Watch DFU devices being hotplugged" msgstr "Sleduje pripojenie zariadení DFU" #. TRANSLATORS: command description msgid "Encrypt firmware data" msgstr "ZaÅ¡ifruje údaje firmvéru" #. TRANSLATORS: command description msgid "Decrypt firmware data" msgstr "DeÅ¡ifruje údaje firmvéru" #. TRANSLATORS: command description msgid "Sets metadata on a firmware file" msgstr "Nastaví metaúdaje pre súbor s firmvérom" #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "Nástroj pre DFU" #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Zlyhalo analyzovanie parametrov" #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Zobrazí ladiace informácie pre vÅ¡etky súbory" #. TRANSLATORS: for the --verbose arg msgid "Debugging Options" msgstr "Voľby ladenia" #. TRANSLATORS: for the --verbose arg msgid "Show debugging options" msgstr "Zobrazí voľby ladenia" #. TRANSLATORS: exit after we've started up, used for user profiling msgid "Exit after a small delay" msgstr "SkonÄí po krátkom oneskorení" #. TRANSLATORS: exit straight away, used for automatic profiling msgid "Exit after the engine has loaded" msgstr "SkonÄí po naÄítaní jadra" #. TRANSLATORS: program name msgid "Firmware Update Daemon" msgstr "Démon aktualizácie firmvéru" #. TRANSLATORS: program summary msgid "Firmware Update D-Bus Service" msgstr "Služba zbernice D-Bus na aktualizovanie firmvéru" #. TRANSLATORS: daemon is inactive msgid "Idle" msgstr "NeÄinný" #. TRANSLATORS: decompressing the firmware file msgid "Decompressing firmware" msgstr "Rozbaľuje sa firmvér" #. TRANSLATORS: parsing the firmware information msgid "Loading firmware" msgstr "NaÄítava sa firmvér" #. TRANSLATORS: restarting the device to pick up new F/W msgid "Restarting device" msgstr "ReÅ¡tartuje sa zariadenie" #. TRANSLATORS: writing to the flash chips msgid "Writing firmware to device" msgstr "Zapisuje sa firmvér do zariadenia" #. TRANSLATORS: verifying we wrote the firmware correctly msgid "Verifying firmware from device" msgstr "Overuje sa firmvér zo zariadenia" #. TRANSLATORS: scheduing an update to be done on the next boot msgid "Scheduling upgrade" msgstr "Plánuje sa aktualizácia" #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "Nezistil sa žiadny hardvér s možnosÅ¥ou aktualizácie firmvéru" #. TRANSLATOR: the provider only supports offline msgid "Retrying as an offline update" msgstr "Skúša sa znovu ako aktualizácia bez pripojenia" #. 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 "PreinÅ¡talováva sa %s verziou %s... " #. 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 "Vracia sa %s z verzie %s na verziu %s... " #. 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 "Aktualizuje sa %s z verzie %s na verziu %s... " msgid "Done!" msgstr "Hotovo!" #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" msgstr "Pre zariadenie %s sú dostupné aktualizácie firmvéru:" #. TRANSLATORS: a GUID for the hardware msgid "GUID" msgstr "GUID" #. TRANSLATORS: section header for firmware version msgid "Version" msgstr "Verzia" #. TRANSLATORS: section header for firmware checksum msgid "Checksum" msgstr "Kontrolný medzisúÄet" msgid "Checksum Type" msgstr "" #. TRANSLATORS: section header for firmware remote http:// msgid "Location" msgstr "Umiestnenie" #. TRANSLATORS: section header for long firmware desc msgid "Description" msgstr "Popis" #. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "ZobrazovaÅ¥ dodatoÄné ladiace informácie" #. TRANSLATORS: command line option msgid "Perform the installation offline where possible" msgstr "Vykoná inÅ¡taláciu bez pripojenia, kde je to možné" #. TRANSLATORS: command line option msgid "Allow re-installing existing firmware versions" msgstr "Umožní preinÅ¡talovanie existujúcich vedzií firmvéru" #. TRANSLATORS: command line option msgid "Allow downgrading firmware versions" msgstr "Umožní zníženie verzií firmvéru" #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Získa vÅ¡etky zariadenia, ktoré podporujú aktualizovanie firmvéru" #. TRANSLATORS: command description msgid "Install prepared updates now" msgstr "NainÅ¡taluje pripravené aktualizácie ihneÄ" #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "NainÅ¡taluje súbor firmvéru do tohoto hardvéru" #. TRANSLATORS: command description msgid "Gets details about a firmware file" msgstr "Získa podrobnosti o súbore firmvéru" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "Získa zoznam aktualizácií pre pripojený hardvér" #. TRANSLATORS: command description msgid "Updates all firmware to latest versions available" msgstr "Aktualizuje vÅ¡etok firmvér na najnovÅ¡iu dostupnú verziu" #. TRANSLATORS: command description msgid "Gets the cryptographic hash of the dumped firmware" msgstr "Získa kryptografický medzisúÄet stiahnutého firmvéru" #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Odomkne zariadenie pre prístup k firmvéru" #. TRANSLATORS: command description msgid "Clears the results from the last update" msgstr "Vymaže výsledky z poslednej aktualizácie" #. TRANSLATORS: command description msgid "Gets the results from the last update" msgstr "Získa výsledky z poslednej aktualizácie" #. TRANSLATORS: command description msgid "Refresh metadata from remote server" msgstr "Obnoví metaúdaje zo vzdialeného servera" #. TRANSLATORS: command description msgid "Dump the ROM checksum" msgstr "Stiahne medzisúÄet pamäte ROM" #. TRANSLATORS: command description msgid "Update the stored metadata with current ROM contents" msgstr "Aktualizuje uložené metaúdaje s aktuálnym obsahom pamäte ROM" #. TRANSLATORS: program name msgid "Firmware Utility" msgstr "Nástroj pre firmvéry" fwupd-0.7.0/po/sr.po000066400000000000000000000355171267747510300142740ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Translators: # Марко М. КоÑтић (Marko M. Kostić) , 2015-2016 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-04-01 14:38+0100\n" "PO-Revision-Date: 2016-04-01 13:38+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Serbian (http://www.transifex.com/hughsie/fwupd/language/sr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: sr\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" msgid "Install signed system firmware" msgstr "ИнÑталирајте потпиÑани ÑиÑтемÑки фирмвер" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on this machine" msgstr "Потребна је пријава за ажурирање фирмвера на овој машини" msgid "Install unsigned system firmware" msgstr "ИнÑталирајте непотпиÑани ÑиÑтемÑки фирмвер" msgid "Install old version of system firmware" msgstr "ИнÑталирајте Ñтаро издање ÑиÑтемÑког фирмвера" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" msgstr "Потребна је пријава за уназађивање фирмвера на овој машини" msgid "Install signed device firmware" msgstr "ИнÑталирајте потпиÑани фирмвер за уређаје" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to update the firmware on a removable device" msgstr "Потребна је пријава за ажурирање фирмвера на преноÑивом уређају" msgid "Install unsigned device firmware" msgstr "ИнÑталирајте непотпиÑани фирмвер за уређаје" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to downgrade the firmware on a removable device" msgstr "Потребна је пријава за уназађивање фирмвера на преноÑивом уређају" msgid "Unlock the device to allow access" msgstr "Откључајте уређај да биÑте дозволили приÑтуп" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" msgstr "Потребна је пријава за откључавање уређаја" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" msgstr "ÐÐ»Ð¸Ñ˜Ð°Ñ Ð½Ð° %s" #. TRANSLATORS: error message msgid "Command not found" msgstr "Ðаредба није пронађена" #. TRANSLATORS: when an action has completed msgid "OK" msgstr "У реду" #. TRANSLATORS: when moving from runtime to DFU mode msgid "Detaching" msgstr "Откачињем" #. TRANSLATORS: when moving from DFU to runtime mode msgid "Attaching" msgstr "Качим" #. TRANSLATORS: when copying from host to device msgid "Downloading" msgstr "Преузимам" #. TRANSLATORS: when copying from device to host msgid "Uploading" msgstr "Отпремам" #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Додао" #. TRANSLATORS: this is when a device is hotplugged msgid "Removed" msgstr "Уклонио" #. TRANSLATORS: this is when a device is hotplugged msgid "Changed" msgstr "Променио" #. TRANSLATORS: this is when a device ctrl+c's a watch msgid "Cancelled" msgstr "Отказао" #. TRANSLATORS: Appstream ID for the hardware type msgid "ID" msgstr "ИБ" #. TRANSLATORS: interface name, e.g. "Flash" msgid "Name" msgstr "Ðазив" #. TRANSLATORS: this is the encryption method used when writing msgid "Cipher" msgstr "Шифрар" #. TRANSLATORS: these are areas of memory on the chip msgid "Region" msgstr "ОблаÑÑ‚" #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Ðашао" #. TRANSLATORS: probably not run as root... #. TRANSLATORS: device has failed to report status #. TRANSLATORS: device status, e.g. "OK" msgid "Status" msgstr "СтатуÑ" msgid "Unknown: permission denied" msgstr "Ðепознато: приÑтуп одбијен" #. TRANSLATORS: device mode, e.g. runtime or DFU msgid "Mode" msgstr "Режим" #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Стање" #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" msgstr "ÐепрецизноÑти" #. TRANSLATORS: command description msgid "Convert firmware to DFU format" msgstr "Претвори фирмвер у ДФУ формат" #. TRANSLATORS: command description msgid "Merge multiple firmware files into one" msgstr "Споји више датотека Ñа фирмвером у једну" #. TRANSLATORS: command description msgid "Set vendor ID on firmware file" msgstr "ПодеÑи ИБ продавца на датотеци Ñа фирмвером" #. TRANSLATORS: command description msgid "Set product ID on firmware file" msgstr "ПодеÑи ИБ производа на датотеци Ñа фирмвером" #. TRANSLATORS: command description msgid "Set release version on firmware file" msgstr "ПодеÑи издање објаве на датотеци Ñа фирмвером" #. TRANSLATORS: command description msgid "Set alternative number on firmware file" msgstr "ПодеÑи алтернативни број на датотеци Ñа фирмвером" #. TRANSLATORS: command description msgid "Set alternative name on firmware file" msgstr "ПодеÑи алтернативно име на датотеци Ñа фирмвером" #. TRANSLATORS: command description msgid "Attach DFU capable device back to runtime" msgstr "Закачи уређај ÑпоÑобан за ДФУ назад на извршно окружење" #. TRANSLATORS: command description msgid "Read firmware from device into a file" msgstr "ИÑчитај фирмвер Ñа уређаја у датотеку" #. TRANSLATORS: command description msgid "Read firmware from one partition into a file" msgstr "ИÑчитај фирмвер Ñа једне партиције у датотеку" #. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "Упиши фирмвер из датотеке у уређај" #. TRANSLATORS: command description msgid "Write firmware from file into one partition" msgstr "Упиши фирмвер из датотеке у једну партицију" #. TRANSLATORS: command description msgid "List currently attached DFU capable devices" msgstr "Прикажи ÑпиÑак закачених уређаја ÑпоÑобних за ДФУ" #. TRANSLATORS: command description msgid "Detach currently attached DFU capable device" msgstr "Откачи тренутно закачен уређај ÑпоÑобан за ДФУ" #. TRANSLATORS: command description msgid "Dump details about a firmware file" msgstr "ИÑтовари детаље о датотеци Ñа фирмвером" #. TRANSLATORS: command description msgid "Watch DFU devices being hotplugged" msgstr "Ðадгледај ДФУ уређаје док Ñе каче на живо" #. TRANSLATORS: command description msgid "Encrypt firmware data" msgstr "Шифруј податке у фирмверу" #. TRANSLATORS: command description msgid "Decrypt firmware data" msgstr "Дешифруј податке у фирмверу" #. TRANSLATORS: command description msgid "Sets metadata on a firmware file" msgstr "Подешава метаподатке у датотеци фирмвера" #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "ДФУ алатка" #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Ðе могу да обрадим аргументе" #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Прикажи податке о отклањању проблема за Ñве датотеке" #. TRANSLATORS: for the --verbose arg msgid "Debugging Options" msgstr "Опције отклањања проблема" #. TRANSLATORS: for the --verbose arg msgid "Show debugging options" msgstr "Прикажи опције за отклањање проблема" #. TRANSLATORS: exit after we've started up, used for user profiling msgid "Exit after a small delay" msgstr "Изађи након малог заÑтоја" #. TRANSLATORS: exit straight away, used for automatic profiling msgid "Exit after the engine has loaded" msgstr "Изађи након учитавања мотора" #. TRANSLATORS: program name msgid "Firmware Update Daemon" msgstr "Демон за ажурирање фирмвера" #. TRANSLATORS: program summary msgid "Firmware Update D-Bus Service" msgstr "Д-Ð‘ÑƒÑ ÑƒÑлуга ажурирања фирмвера" #. TRANSLATORS: daemon is inactive msgid "Idle" msgstr "У мировању" #. TRANSLATORS: decompressing the firmware file msgid "Decompressing firmware" msgstr "РаÑпакивање фирмвера у току" #. TRANSLATORS: parsing the firmware information msgid "Loading firmware" msgstr "Учитавам фирмвер" #. TRANSLATORS: restarting the device to pick up new F/W msgid "Restarting device" msgstr "Поново покрећем уређај" #. TRANSLATORS: writing to the flash chips msgid "Writing firmware to device" msgstr "УпиÑујем фирмвер на уређај" #. TRANSLATORS: verifying we wrote the firmware correctly msgid "Verifying firmware from device" msgstr "Потврђујем фирмвер Ñа уређаја" #. TRANSLATORS: scheduing an update to be done on the next boot msgid "Scheduling upgrade" msgstr "Заказујем надоградњу" #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "Ðема хардвера којем Ñе може ажурирати фирмвер" #. TRANSLATOR: the provider only supports offline msgid "Retrying as an offline update" msgstr "Поново покушавам преко ванмрежног ажурирања" #. 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 "Поново инÑталирам %s Ñа %s..." #. 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 "Уназађујем %s Ñа %s на %s..." #. 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 "Ðжурирам %s Ñа %s на %s..." msgid "Done!" msgstr "Урађено!" #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" msgstr "%s има ажурирања за фирмвер:" #. TRANSLATORS: a GUID for the hardware msgid "GUID" msgstr "ГУИД" #. TRANSLATORS: section header for firmware version msgid "Version" msgstr "Издање" #. TRANSLATORS: section header for firmware checksum msgid "Checksum" msgstr "Чек-Ñума" msgid "Checksum Type" msgstr "" #. TRANSLATORS: section header for firmware remote http:// msgid "Location" msgstr "МеÑто" #. TRANSLATORS: section header for long firmware desc msgid "Description" msgstr "ОпиÑ" #. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "Прикажи додатне податке за отклањање проблема" #. TRANSLATORS: command line option msgid "Perform the installation offline where possible" msgstr "Изврши ажурирања ван мреже где је то могуће" #. TRANSLATORS: command line option msgid "Allow re-installing existing firmware versions" msgstr "Дозволи поновно инÑталирање већ поÑтојећих издања фирмвера" #. TRANSLATORS: command line option msgid "Allow downgrading firmware versions" msgstr "Дозволи уназађивање издања фирмвера" #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Добави Ñве уређаје који подржавају ажурирање фирмвера" #. TRANSLATORS: command description msgid "Install prepared updates now" msgstr "ИнÑталирај припремљена ажурирања Ñад" #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "ИнÑталирај датотеку Ñа фирмвером на овај уређај" #. TRANSLATORS: command description msgid "Gets details about a firmware file" msgstr "Добави појединоÑти о датотеци Ñа фирмвером" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "Добави ÑпиÑак Ñвих ажурирања за повезани уређај" #. TRANSLATORS: command description msgid "Updates all firmware to latest versions available" msgstr "Ðжурира Ñав фирмвер на поÑледња доÑтупна издања" #. TRANSLATORS: command description msgid "Gets the cryptographic hash of the dumped firmware" msgstr "Добавља криптографÑки хеш извађеног фирмвера" #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Откључава уређај за приÑтуп фирмверу" #. TRANSLATORS: command description msgid "Clears the results from the last update" msgstr "ЧиÑти резултате поÑледњег ажурирања" #. TRANSLATORS: command description msgid "Gets the results from the last update" msgstr "Добавља резултате поÑледњег ажурирања" #. TRANSLATORS: command description msgid "Refresh metadata from remote server" msgstr "ОÑвежава метаподатке Ñа удаљеног Ñервера" #. TRANSLATORS: command description msgid "Dump the ROM checksum" msgstr "Извади РОМ чек-Ñуму" #. TRANSLATORS: command description msgid "Update the stored metadata with current ROM contents" msgstr "Ðжурирај уÑкладиштене метаподатке Ñа тренутним Ñадржајима РОМ-а" #. TRANSLATORS: program name msgid "Firmware Utility" msgstr "Ðлатка за фирмвер" fwupd-0.7.0/po/sv.po000066400000000000000000000260211267747510300142660ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Translators: # Josef Andersson , 2015 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-04-01 14:38+0100\n" "PO-Revision-Date: 2016-04-01 13:38+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Swedish (http://www.transifex.com/hughsie/fwupd/language/sv/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: sv\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgid "Install signed system firmware" msgstr "Installera signerad fast programvara för systemet" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on this machine" msgstr "Autentisering krävs för att uppdatera den fasta programvaran för denna maskin" msgid "Install unsigned system firmware" msgstr "Installera osignerad fast programvara för systemet" msgid "Install old version of system firmware" msgstr "Installera en gammal version av fast programvara för systemet" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" msgstr "Autentisering krävs för att nedgradera den fasta programvaran pÃ¥ denna maskin" msgid "Install signed device firmware" msgstr "Installera signerad fast programvara för enhet" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to update the firmware on a removable device" msgstr "Autentisering krävs för att uppdatera den fasta programvaran pÃ¥ en flyttbar enhet" msgid "Install unsigned device firmware" msgstr "Installera osignerad fast programvara för enhet" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to downgrade the firmware on a removable device" msgstr "Autentisering krävs för att nedgradera den fasta programvaran för en flyttbar enhet" msgid "Unlock the device to allow access" msgstr "" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" msgstr "" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" msgstr "Alias till %s" #. TRANSLATORS: error message msgid "Command not found" msgstr "" #. TRANSLATORS: when an action has completed msgid "OK" msgstr "" #. TRANSLATORS: when moving from runtime to DFU mode msgid "Detaching" msgstr "" #. TRANSLATORS: when moving from DFU to runtime mode msgid "Attaching" msgstr "" #. TRANSLATORS: when copying from host to device msgid "Downloading" msgstr "" #. TRANSLATORS: when copying from device to host msgid "Uploading" msgstr "" #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "" #. TRANSLATORS: this is when a device is hotplugged msgid "Removed" msgstr "" #. TRANSLATORS: this is when a device is hotplugged msgid "Changed" msgstr "" #. TRANSLATORS: this is when a device ctrl+c's a watch msgid "Cancelled" msgstr "" #. TRANSLATORS: Appstream ID for the hardware type msgid "ID" msgstr "" #. TRANSLATORS: interface name, e.g. "Flash" msgid "Name" msgstr "" #. TRANSLATORS: this is the encryption method used when writing msgid "Cipher" msgstr "" #. TRANSLATORS: these are areas of memory on the chip msgid "Region" msgstr "" #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "" #. TRANSLATORS: probably not run as root... #. TRANSLATORS: device has failed to report status #. TRANSLATORS: device status, e.g. "OK" msgid "Status" msgstr "" msgid "Unknown: permission denied" msgstr "" #. TRANSLATORS: device mode, e.g. runtime or DFU msgid "Mode" msgstr "" #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "" #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" msgstr "" #. TRANSLATORS: command description msgid "Convert firmware to DFU format" msgstr "" #. TRANSLATORS: command description msgid "Merge multiple firmware files into one" msgstr "" #. TRANSLATORS: command description msgid "Set vendor ID on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Set product ID on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Set release version on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Set alternative number on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Set alternative name on firmware file" msgstr "" #. TRANSLATORS: command description msgid "Attach DFU capable device back to runtime" msgstr "" #. TRANSLATORS: command description msgid "Read firmware from device into a file" msgstr "" #. TRANSLATORS: command description msgid "Read firmware from one partition into a file" msgstr "" #. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "" #. TRANSLATORS: command description msgid "Write firmware from file into one partition" msgstr "" #. TRANSLATORS: command description msgid "List currently attached DFU capable devices" msgstr "" #. TRANSLATORS: command description msgid "Detach currently attached DFU capable device" msgstr "" #. TRANSLATORS: command description msgid "Dump details about a firmware file" msgstr "" #. TRANSLATORS: command description msgid "Watch DFU devices being hotplugged" msgstr "" #. TRANSLATORS: command description msgid "Encrypt firmware data" msgstr "" #. TRANSLATORS: command description msgid "Decrypt firmware data" msgstr "" #. TRANSLATORS: command description msgid "Sets metadata on a firmware file" msgstr "" #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "" #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Misslyckades med att tolka argument" #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Visa felsökningsinformation för alla filer" #. TRANSLATORS: for the --verbose arg msgid "Debugging Options" msgstr "Felsökningsalternativ" #. TRANSLATORS: for the --verbose arg msgid "Show debugging options" msgstr "Visa felsökningsalternativ" #. TRANSLATORS: exit after we've started up, used for user profiling msgid "Exit after a small delay" msgstr "Avsluta efter en kort fördröjning" #. TRANSLATORS: exit straight away, used for automatic profiling msgid "Exit after the engine has loaded" msgstr "Avsluta efter att motorn har lästs in" #. TRANSLATORS: program name msgid "Firmware Update Daemon" msgstr "" #. TRANSLATORS: program summary msgid "Firmware Update D-Bus Service" msgstr "Firmware Update D-Bus-tjänst" #. TRANSLATORS: daemon is inactive msgid "Idle" msgstr "Overksam" #. TRANSLATORS: decompressing the firmware file msgid "Decompressing firmware" msgstr "Dekomprimerar fast programvara" #. TRANSLATORS: parsing the firmware information msgid "Loading firmware" msgstr "Läser in fast programvara" #. TRANSLATORS: restarting the device to pick up new F/W msgid "Restarting device" msgstr "Startar om enhet" #. TRANSLATORS: writing to the flash chips msgid "Writing firmware to device" msgstr "Skriver fast programvara till enhet" #. TRANSLATORS: verifying we wrote the firmware correctly msgid "Verifying firmware from device" msgstr "Verifierar fast programvara frÃ¥n enhet" #. TRANSLATORS: scheduing an update to be done on the next boot msgid "Scheduling upgrade" msgstr "Schemalägger uppdatering" #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "Ingen uppdateringsbar hÃ¥rdvara upptäcktes" #. TRANSLATOR: the provider only supports offline msgid "Retrying as an offline update" msgstr "" #. 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 "Ã…terinstallerar %s med %s…" #. 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 "Nedgraderar %s frÃ¥n %s till %s…" #. 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 "Uppdaterar %s frÃ¥n %s till %s..." msgid "Done!" msgstr "Klar!" #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" msgstr "%s har uppdateringar för fast programvara:" #. TRANSLATORS: a GUID for the hardware msgid "GUID" msgstr "" #. TRANSLATORS: section header for firmware version msgid "Version" msgstr "Version" #. TRANSLATORS: section header for firmware checksum msgid "Checksum" msgstr "Kontrollsumma" msgid "Checksum Type" msgstr "" #. TRANSLATORS: section header for firmware remote http:// msgid "Location" msgstr "Plats" #. TRANSLATORS: section header for long firmware desc msgid "Description" msgstr "Beskrivning" #. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "Visa extra felsökningsinformation" #. TRANSLATORS: command line option msgid "Perform the installation offline where possible" msgstr "" #. TRANSLATORS: command line option msgid "Allow re-installing existing firmware versions" msgstr "" #. TRANSLATORS: command line option msgid "Allow downgrading firmware versions" msgstr "" #. 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 "Install prepared updates now" msgstr "Installera förberedda uppdateringar nu" #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "Installera en fast programvarufil pÃ¥ denna hÃ¥rdvara" #. TRANSLATORS: command description msgid "Gets details about a firmware file" msgstr "Hämta detaljer om en fast programvarufil" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "Hämtar listan över uppdateringar för ansluten hÃ¥rdvara" #. TRANSLATORS: command description msgid "Updates all firmware to latest versions available" msgstr "" #. TRANSLATORS: command description msgid "Gets the cryptographic hash of the dumped firmware" msgstr "" #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "" #. TRANSLATORS: command description msgid "Clears the results from the last update" msgstr "Rensar resultaten frÃ¥n senaste uppdateringen" #. TRANSLATORS: command description msgid "Gets the results from the last update" msgstr "Hämtar resultaten frÃ¥n senaste uppdateringen" #. TRANSLATORS: command description msgid "Refresh metadata from remote server" msgstr "" #. TRANSLATORS: command description msgid "Dump the ROM checksum" msgstr "" #. TRANSLATORS: command description msgid "Update the stored metadata with current ROM contents" msgstr "" #. TRANSLATORS: program name msgid "Firmware Utility" msgstr "" fwupd-0.7.0/po/uk.po000066400000000000000000000373651267747510300142720ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Translators: # Yuri Chornoivan , 2015-2016 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-04-01 14:38+0100\n" "PO-Revision-Date: 2016-04-01 13:38+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Ukrainian (http://www.transifex.com/hughsie/fwupd/language/uk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: uk\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" msgid "Install signed system firmware" msgstr "Ð’Ñтановити підпиÑану мікропрограму ÑиÑтеми" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on this machine" msgstr "Щоб отримати доÑтуп до Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¼Ñ–ÐºÑ€Ð¾Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¸ цього комп’ютера, вам Ñлід пройти розпізнаваннÑ" msgid "Install unsigned system firmware" msgstr "Ð’Ñтановити непідпиÑану мікропрограму ÑиÑтеми" msgid "Install old version of system firmware" msgstr "Ð’Ñтановити Ñтару верÑÑ–ÑŽ мікропрограми ÑиÑтеми" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" msgstr "Ð”Ð»Ñ Ð²ÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð·Ð°Ñтарілої верÑÑ–Ñ— мікропрограми на цей комп’ютер Ñлід пройти розпізнаваннÑ" msgid "Install signed device firmware" msgstr "Ð’Ñтановити підпиÑану мікропрограму приÑтрою" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to update the firmware on a removable device" msgstr "Ð”Ð»Ñ Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¼Ñ–ÐºÑ€Ð¾Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¸ на портативному приÑтрої Ñлід пройти розпізнаваннÑ" msgid "Install unsigned device firmware" msgstr "Ð’Ñтановити непідпиÑану мікропрограму приÑтрою" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to downgrade the firmware on a removable device" msgstr "Ð”Ð»Ñ Ð²ÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð·Ð°Ñтарілої верÑÑ–Ñ— мікропрограми на портативний приÑтрій Ñлід пройти розпізнаваннÑ" msgid "Unlock the device to allow access" msgstr "Ð Ð¾Ð·Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¸Ñтрою Ð´Ð»Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð¾Ñтупу" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" msgstr "Щоб розблокувати приÑтрій, Ñлід пройти розпізнаваннÑ" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" msgstr "Інша назва %s" #. TRANSLATORS: error message msgid "Command not found" msgstr "Такої команди не знайдено" #. TRANSLATORS: when an action has completed msgid "OK" msgstr "Гаразд" #. TRANSLATORS: when moving from runtime to DFU mode msgid "Detaching" msgstr "Від’єднуємо" #. TRANSLATORS: when moving from DFU to runtime mode msgid "Attaching" msgstr "З’єднуємо" #. TRANSLATORS: when copying from host to device msgid "Downloading" msgstr "Отримуємо" #. TRANSLATORS: when copying from device to host msgid "Uploading" msgstr "Вивантажуємо" #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Додано" #. TRANSLATORS: this is when a device is hotplugged msgid "Removed" msgstr "Вилучено" #. TRANSLATORS: this is when a device is hotplugged msgid "Changed" msgstr "Змінено" #. TRANSLATORS: this is when a device ctrl+c's a watch msgid "Cancelled" msgstr "СкаÑовано" #. TRANSLATORS: Appstream ID for the hardware type msgid "ID" msgstr "Ід." #. TRANSLATORS: interface name, e.g. "Flash" msgid "Name" msgstr "Ðазва" #. TRANSLATORS: this is the encryption method used when writing msgid "Cipher" msgstr "Шифр" #. TRANSLATORS: these are areas of memory on the chip msgid "Region" msgstr "Регіон" #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Знайдено" #. TRANSLATORS: probably not run as root... #. TRANSLATORS: device has failed to report status #. TRANSLATORS: device status, e.g. "OK" msgid "Status" msgstr "Стан" msgid "Unknown: permission denied" msgstr "Ðевідомий: доÑтуп заборонено" #. TRANSLATORS: device mode, e.g. runtime or DFU msgid "Mode" msgstr "Режим" #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Стан" #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" msgstr "Ðегаразди" #. TRANSLATORS: command description msgid "Convert firmware to DFU format" msgstr "Перетворити мікропрограму у формат DFU" #. TRANSLATORS: command description msgid "Merge multiple firmware files into one" msgstr "Об’єднати декілька файлів мікропрограм у один" #. TRANSLATORS: command description msgid "Set vendor ID on firmware file" msgstr "Ð’Ñтановити ідентифікатор виробника Ð´Ð»Ñ Ñ„Ð°Ð¹Ð»Ð° мікропрограми" #. TRANSLATORS: command description msgid "Set product ID on firmware file" msgstr "Ð’Ñтановити ідентифікатор продукту Ð´Ð»Ñ Ñ„Ð°Ð¹Ð»Ð° мікропрограми" #. TRANSLATORS: command description msgid "Set release version on firmware file" msgstr "Ð’Ñтановити верÑÑ–ÑŽ випуÑку Ð´Ð»Ñ Ñ„Ð°Ð¹Ð»Ð° мікропрограми" #. TRANSLATORS: command description msgid "Set alternative number on firmware file" msgstr "Ð’Ñтановити альтернативний номер Ð´Ð»Ñ Ñ„Ð°Ð¹Ð»Ð° мікропрограми" #. TRANSLATORS: command description msgid "Set alternative name on firmware file" msgstr "Ð’Ñтановити альтернативну назву Ð´Ð»Ñ Ñ„Ð°Ð¹Ð»Ð° мікропрограми" #. TRANSLATORS: command description msgid "Attach DFU capable device back to runtime" msgstr "Повернути приÑтрій із можливоÑÑ‚Ñми DFU до викориÑтаннÑ" #. TRANSLATORS: command description msgid "Read firmware from device into a file" msgstr "Прочитати мікропрограму з приÑтрою до файла" #. TRANSLATORS: command description msgid "Read firmware from one partition into a file" msgstr "Прочитати мікропрограму з одного розділу до файла" #. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "ЗапиÑати мікропрограму з файла на приÑтрій" #. TRANSLATORS: command description msgid "Write firmware from file into one partition" msgstr "ЗапиÑати мікропрограму з файла на один розділ" #. TRANSLATORS: command description msgid "List currently attached DFU capable devices" msgstr "ВивеÑти поточний ÑпиÑок долучених приÑтроїв із можливоÑÑ‚Ñми DFU" #. TRANSLATORS: command description msgid "Detach currently attached DFU capable device" msgstr "Від’єднати поточний з’єднаний приÑтрій із можливоÑÑ‚Ñми DFU" #. TRANSLATORS: command description msgid "Dump details about a firmware file" msgstr "Створити дамп даних щодо файла мікропрограми" #. TRANSLATORS: command description msgid "Watch DFU devices being hotplugged" msgstr "СпоÑтерігати за приÑтроÑми DFU, Ñкі з’єднують із комп’ютером" #. TRANSLATORS: command description msgid "Encrypt firmware data" msgstr "Зашифрувати дані мікропрограми" #. TRANSLATORS: command description msgid "Decrypt firmware data" msgstr "Розшифрувати дані мікропрограми" #. TRANSLATORS: command description msgid "Sets metadata on a firmware file" msgstr "Ð’Ñтановлює метадані щодо файла мікпропрограми" #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "ЗаÑіб роботи з DFU" #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Ðе вдалоÑÑ Ð¾Ð±Ñ€Ð¾Ð±Ð¸Ñ‚Ð¸ аргументи" #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Показувати діагноÑтичні дані Ð´Ð»Ñ Ð²ÑÑ–Ñ… файлів" #. TRANSLATORS: for the --verbose arg msgid "Debugging Options" msgstr "Параметри діагноÑтики" #. TRANSLATORS: for the --verbose arg msgid "Show debugging options" msgstr "Показувати параметри діагноÑтики" #. TRANSLATORS: exit after we've started up, used for user profiling msgid "Exit after a small delay" msgstr "Завершити роботу з невеличкою затримкою" #. TRANSLATORS: exit straight away, used for automatic profiling msgid "Exit after the engine has loaded" msgstr "Завершити роботу піÑÐ»Ñ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ñ€ÑƒÑˆÑ–Ñ" #. TRANSLATORS: program name msgid "Firmware Update Daemon" msgstr "Служба Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¼Ñ–ÐºÑ€Ð¾Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¸" #. TRANSLATORS: program summary msgid "Firmware Update D-Bus Service" msgstr "Служба D-Bus Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¼Ñ–ÐºÑ€Ð¾Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¸" #. TRANSLATORS: daemon is inactive msgid "Idle" msgstr "БездіÑльніÑть" #. TRANSLATORS: decompressing the firmware file msgid "Decompressing firmware" msgstr "Розпаковуємо мікропрограму" #. TRANSLATORS: parsing the firmware information msgid "Loading firmware" msgstr "Завантажуємо мікропрограму" #. TRANSLATORS: restarting the device to pick up new F/W msgid "Restarting device" msgstr "ПерезапуÑкаємо приÑтрій" #. TRANSLATORS: writing to the flash chips msgid "Writing firmware to device" msgstr "ЗапиÑуємо мікропрограму на приÑтрій" #. TRANSLATORS: verifying we wrote the firmware correctly msgid "Verifying firmware from device" msgstr "ПеревірÑємо мікропрограму з приÑтрою" #. TRANSLATORS: scheduing an update to be done on the next boot msgid "Scheduling upgrade" msgstr "Плануємо оновленнÑ" #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "Ðе виÑвлено Ð¾Ð±Ð»Ð°Ð´Ð½Ð°Ð½Ð½Ñ Ñ–Ð· передбаченою можливіÑтю Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¼Ñ–ÐºÑ€Ð¾Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¸" #. TRANSLATOR: the provider only supports offline msgid "Retrying as an offline update" msgstr "Повторна Ñпроба у режимі автономного оновленнÑ" #. 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 "Повторно вÑтановлюємо %s з номером верÑÑ–Ñ— %s... " #. 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 "Знижуємо верÑÑ–ÑŽ %s з %s до %s... " #. 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 "Оновлюємо %s з %s до %s... " msgid "Done!" msgstr "Виконано!" #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" msgstr "%s має такі Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¼Ñ–ÐºÑ€Ð¾Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¸:" #. TRANSLATORS: a GUID for the hardware msgid "GUID" msgstr "GUID" #. TRANSLATORS: section header for firmware version msgid "Version" msgstr "ВерÑÑ–Ñ" #. TRANSLATORS: section header for firmware checksum msgid "Checksum" msgstr "Контрольна Ñума" msgid "Checksum Type" msgstr "" #. TRANSLATORS: section header for firmware remote http:// msgid "Location" msgstr "МіÑце" #. TRANSLATORS: section header for long firmware desc msgid "Description" msgstr "ОпиÑ" #. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "Показати додаткові діагноÑтичні дані" #. TRANSLATORS: command line option msgid "Perform the installation offline where possible" msgstr "Де можливо, виконати вÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð°Ð²Ñ‚Ð¾Ð½Ð¾Ð¼Ð½Ð¾" #. TRANSLATORS: command line option msgid "Allow re-installing existing firmware versions" msgstr "Дозволити повторне вÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð½Ð°Ñвних верÑій мікропрограми" #. TRANSLATORS: command line option msgid "Allow downgrading firmware versions" msgstr "Дозволити Ð·Ð½Ð¸Ð¶ÐµÐ½Ð½Ñ Ð²ÐµÑ€Ñій мікропрограми" #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Отримати ÑпиÑок уÑÑ–Ñ… приÑтроїв, у Ñких передбачено Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¼Ñ–ÐºÑ€Ð¾Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¸" #. TRANSLATORS: command description msgid "Install prepared updates now" msgstr "Ð’Ñтановити приготовані Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð·Ð°Ñ€Ð°Ð·" #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "Ð’Ñтановити файл мікропрограми на це обладнаннÑ" #. TRANSLATORS: command description msgid "Gets details about a firmware file" msgstr "Отримати параметри файла мікропрограми" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "Отримує ÑпиÑок оновлень Ð´Ð»Ñ Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð¾Ð³Ð¾ обладнаннÑ" #. TRANSLATORS: command description msgid "Updates all firmware to latest versions available" msgstr "Оновлює уÑÑ– мікропрограми до найновіших доÑтупних верÑій" #. TRANSLATORS: command description msgid "Gets the cryptographic hash of the dumped firmware" msgstr "Отримує криптографічні хеш-Ñуми Ð´Ð»Ñ Ð´Ð°Ð¼Ð¿Ñ–Ð² мікропрограм" #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Розблоковує приÑтрій Ð´Ð»Ñ Ð´Ð¾Ñтупу до мікропрограми" #. TRANSLATORS: command description msgid "Clears the results from the last update" msgstr "Вилучає результати оÑтаннього оновленнÑ" #. TRANSLATORS: command description msgid "Gets the results from the last update" msgstr "Отримує результати з оÑтаннього оновленнÑ" #. TRANSLATORS: command description msgid "Refresh metadata from remote server" msgstr "Оновити метадані з віддаленого Ñервера" #. TRANSLATORS: command description msgid "Dump the ROM checksum" msgstr "Створити дамп контрольної Ñуми ROM" #. TRANSLATORS: command description msgid "Update the stored metadata with current ROM contents" msgstr "Оновити збережені метадані на оÑнові поточного вміÑту ROM" #. TRANSLATORS: program name msgid "Firmware Utility" msgstr "ЗаÑіб роботи з мікропрограмами" fwupd-0.7.0/po/zh_CN.po000066400000000000000000000274771267747510300146570ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Translators: # Mingye Wang , 2016 # Mingye Wang , 2015 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-04-01 14:38+0100\n" "PO-Revision-Date: 2016-04-01 13:38+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Chinese (China) (http://www.transifex.com/hughsie/fwupd/language/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: zh_CN\n" "Plural-Forms: nplurals=1; plural=0;\n" msgid "Install signed system firmware" msgstr "安装已签å的系统固件" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on this machine" msgstr "需è¦è®¤è¯ï¼šåœ¨æ­¤æœºå™¨ä¸Šå‡çº§å›ºä»¶" msgid "Install unsigned system firmware" msgstr "安装未签å的系统固件" msgid "Install old version of system firmware" msgstr "安装旧版本的系统固件" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" msgstr "需è¦è®¤è¯ï¼šåœ¨æ­¤æœºå™¨ä¸Šé™çº§å›ºä»¶" msgid "Install signed device firmware" msgstr "安装已签å的设备固件" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to update the firmware on a removable device" msgstr "需è¦è®¤è¯ï¼šåœ¨å¯ç§»åŠ¨è®¾å¤‡ä¸Šå‡çº§å›ºä»¶" msgid "Install unsigned device firmware" msgstr "安装未签å的设备固件" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "" "Authentication is required to downgrade the firmware on a removable device" msgstr "需è¦è®¤è¯ï¼šåœ¨å¯ç§»åŠ¨è®¾å¤‡ä¸Šé™çº§å›ºä»¶" msgid "Unlock the device to allow access" msgstr "" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" msgstr "" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" msgstr "%s 的别å" #. TRANSLATORS: error message msgid "Command not found" msgstr "未找到命令" #. TRANSLATORS: when an action has completed msgid "OK" msgstr "确定" #. TRANSLATORS: when moving from runtime to DFU mode msgid "Detaching" msgstr "断开中" #. TRANSLATORS: when moving from DFU to runtime mode msgid "Attaching" msgstr "连接中" #. TRANSLATORS: when copying from host to device msgid "Downloading" msgstr "下载中" #. TRANSLATORS: when copying from device to host msgid "Uploading" msgstr "上传中" #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "已添加" #. TRANSLATORS: this is when a device is hotplugged msgid "Removed" msgstr "已移除" #. TRANSLATORS: this is when a device is hotplugged msgid "Changed" msgstr "å·²å˜æ›´" #. TRANSLATORS: this is when a device ctrl+c's a watch msgid "Cancelled" msgstr "已喿¶ˆ" #. TRANSLATORS: Appstream ID for the hardware type msgid "ID" msgstr "ID" #. TRANSLATORS: interface name, e.g. "Flash" msgid "Name" msgstr "åç§°" #. TRANSLATORS: this is the encryption method used when writing msgid "Cipher" msgstr "加密" #. TRANSLATORS: these are areas of memory on the chip msgid "Region" msgstr "区域" #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "找到" #. TRANSLATORS: probably not run as root... #. TRANSLATORS: device has failed to report status #. TRANSLATORS: device status, e.g. "OK" msgid "Status" msgstr "状况" msgid "Unknown: permission denied" msgstr "未知:访问被拒ç»" #. TRANSLATORS: device mode, e.g. runtime or DFU msgid "Mode" msgstr "模å¼" #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "状æ€" #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" msgstr "特异情况" #. TRANSLATORS: command description msgid "Convert firmware to DFU format" msgstr "将固件转æ¢ä¸ºå›ºä»¶å‡çº§ï¼ˆDFU)格å¼" #. TRANSLATORS: command description msgid "Merge multiple firmware files into one" msgstr "将多个固件文件åˆå¹¶ä¸ºä¸€ä¸ª" #. TRANSLATORS: command description msgid "Set vendor ID on firmware file" msgstr "设置固件文件上的供应商 ID" #. TRANSLATORS: command description msgid "Set product ID on firmware file" msgstr "è®¾ç½®å›ºä»¶æ–‡ä»¶ä¸Šçš„äº§å“ ID" #. TRANSLATORS: command description msgid "Set release version on firmware file" msgstr "设置固件文件上的å‘布版本" #. TRANSLATORS: command description msgid "Set alternative number on firmware file" msgstr "设置固件文件上的替代数字" #. TRANSLATORS: command description msgid "Set alternative name on firmware file" msgstr "设置固件文件上的替代åç§°" #. TRANSLATORS: command description msgid "Attach DFU capable device back to runtime" msgstr "å°†å¯å›ºä»¶å‡çº§ï¼ˆDFUï¼‰çš„è®¾å¤‡é‡æ–°é™„到è¿è¡Œæ—¶ä¸Š" #. TRANSLATORS: command description msgid "Read firmware from device into a file" msgstr "å°†æ¥è‡ªè®¾å¤‡çš„固件读入文件" #. TRANSLATORS: command description msgid "Read firmware from one partition into a file" msgstr "å°†æ¥è‡ªåˆ†åŒºçš„固件读入文件" #. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "å°†æ¥è‡ªæ–‡ä»¶çš„固件写入设备" #. TRANSLATORS: command description msgid "Write firmware from file into one partition" msgstr "å°†æ¥è‡ªæ–‡ä»¶çš„固件写入分区" #. TRANSLATORS: command description msgid "List currently attached DFU capable devices" msgstr "列出当å‰è¿žæŽ¥çš„å¯å›ºä»¶å‡çº§çš„设备" #. TRANSLATORS: command description msgid "Detach currently attached DFU capable device" msgstr "断开当å‰è¿žæŽ¥çš„å¯å›ºä»¶å‡çº§çš„设备" #. TRANSLATORS: command description msgid "Dump details about a firmware file" msgstr "转储有关æŸå›ºä»¶æ–‡ä»¶çš„详细信æ¯" #. TRANSLATORS: command description msgid "Watch DFU devices being hotplugged" msgstr "注æ„被热æ’入的固件å‡çº§ï¼ˆDFU)设备" #. TRANSLATORS: command description msgid "Encrypt firmware data" msgstr "加密固件数æ®" #. TRANSLATORS: command description msgid "Decrypt firmware data" msgstr "正在解密固件" #. TRANSLATORS: command description msgid "Sets metadata on a firmware file" msgstr "设置固件文件上的元数æ®" #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "固件更新实用程åº" #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "未能解æžå‚æ•°" #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "显示所有文件的调试信æ¯" #. TRANSLATORS: for the --verbose arg msgid "Debugging Options" msgstr "调试选项" #. TRANSLATORS: for the --verbose arg msgid "Show debugging options" msgstr "显示调试选项" #. TRANSLATORS: exit after we've started up, used for user profiling msgid "Exit after a small delay" msgstr "在短暂的延迟åŽé€€å‡º" #. TRANSLATORS: exit straight away, used for automatic profiling msgid "Exit after the engine has loaded" msgstr "在引擎加载åŽé€€å‡º" #. TRANSLATORS: program name msgid "Firmware Update Daemon" msgstr "固件更新守护程åº" #. TRANSLATORS: program summary msgid "Firmware Update D-Bus Service" msgstr "固件更新 D-Bus æœåŠ¡" #. TRANSLATORS: daemon is inactive msgid "Idle" msgstr "空闲" #. TRANSLATORS: decompressing the firmware file msgid "Decompressing firmware" msgstr "正在解压缩固件" #. TRANSLATORS: parsing the firmware information msgid "Loading firmware" msgstr "正在加载固件" #. TRANSLATORS: restarting the device to pick up new F/W msgid "Restarting device" msgstr "正在é‡å¯è®¾å¤‡" #. TRANSLATORS: writing to the flash chips msgid "Writing firmware to device" msgstr "正在将固件写入设备" #. TRANSLATORS: verifying we wrote the firmware correctly msgid "Verifying firmware from device" msgstr "正在校验æ¥è‡ªè®¾å¤‡çš„固件" #. TRANSLATORS: scheduing an update to be done on the next boot msgid "Scheduling upgrade" msgstr "正在计划å‡çº§" #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "æ²¡æœ‰æ£€æµ‹åˆ°æ”¯æŒæ›´æ–°å›ºä»¶çš„硬件" #. TRANSLATOR: the provider only supports offline msgid "Retrying as an offline update" msgstr "作为脱机更新é‡è¯•" #. 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 "æ­£åœ¨é‡æ–°å®‰è£… %s,使用 %s…" #. 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 "正在é™çº§ %s,从 %s 到 %s…" #. 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 "正在更新 %s,从 %s 到 %s…" msgid "Done!" msgstr "完æˆï¼" #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" msgstr "%s 有固件更新:" #. TRANSLATORS: a GUID for the hardware msgid "GUID" msgstr "GUID" #. TRANSLATORS: section header for firmware version msgid "Version" msgstr "版本" #. TRANSLATORS: section header for firmware checksum msgid "Checksum" msgstr "校验和" msgid "Checksum Type" msgstr "" #. TRANSLATORS: section header for firmware remote http:// msgid "Location" msgstr "ä½ç½®" #. TRANSLATORS: section header for long firmware desc msgid "Description" msgstr "æè¿°" #. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "显示é¢å¤–调试信æ¯" #. TRANSLATORS: command line option msgid "Perform the installation offline where possible" msgstr "å°½å¯èƒ½åœ°æ‰§è¡Œè„±æœºå®‰è£…" #. TRANSLATORS: command line option msgid "Allow re-installing existing firmware versions" msgstr "å…è®¸é‡æ–°å®‰è£…现有的固件版本" #. TRANSLATORS: command line option msgid "Allow downgrading firmware versions" msgstr "å…许é™çº§å›ºä»¶ç‰ˆæœ¬" #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "èŽ·å¾—æ‰€æœ‰æ”¯æŒæ›´æ–°å›ºä»¶çš„硬件列表" #. TRANSLATORS: command description msgid "Install prepared updates now" msgstr "现在安装准备好的更新" #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "安装此硬件上的固件文件" #. TRANSLATORS: command description msgid "Gets details about a firmware file" msgstr "èŽ·å–æœ‰å…³æŸå›ºä»¶æ–‡ä»¶çš„详细信æ¯" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "获å–已连接硬件的å¯ç”¨æ›´æ–°åˆ—表" #. TRANSLATORS: command description msgid "Updates all firmware to latest versions available" msgstr "将所有固件都更新为最新版本" #. TRANSLATORS: command description msgid "Gets the cryptographic hash of the dumped firmware" msgstr "获å–转储出的固件的校验和" #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "" #. TRANSLATORS: command description msgid "Clears the results from the last update" msgstr "清除从最åŽä¸€æ¬¡æ›´æ–°èŽ·å–的结果" #. TRANSLATORS: command description msgid "Gets the results from the last update" msgstr "从最åŽä¸€æ¬¡æ›´æ–°ä¸­èŽ·å–结果" #. TRANSLATORS: command description msgid "Refresh metadata from remote server" msgstr "刷新æ¥è‡ªè¿œç¨‹æœåŠ¡å™¨çš„å…ƒæ•°æ®" #. TRANSLATORS: command description msgid "Dump the ROM checksum" msgstr "转储 ROM 校验和" #. TRANSLATORS: command description msgid "Update the stored metadata with current ROM contents" msgstr "使用目å‰çš„ ROM 内容更新存储的元数æ®" #. TRANSLATORS: program name msgid "Firmware Utility" msgstr "固件实用程åº" fwupd-0.7.0/policy/000077500000000000000000000000001267747510300141565ustar00rootroot00000000000000fwupd-0.7.0/policy/Makefile.am000066400000000000000000000007461267747510300162210ustar00rootroot00000000000000 polkit_rulesdir = $(datadir)/polkit-1/rules.d dist_polkit_rules_DATA = \ org.freedesktop.fwupd.rules @INTLTOOL_POLICY_RULE@ polkit_policydir = $(datadir)/polkit-1/actions polkit_policy_in_files = org.freedesktop.fwupd.policy.in polkit_policy_DATA = $(polkit_policy_in_files:.policy.in=.policy) #polkit_policy_DATA = \ # org.freedesktop.fwupd.policy EXTRA_DIST = org.freedesktop.fwupd.policy.in CLEANFILES = \ org.freedesktop.fwupd.policy -include $(top_srcdir)/git.mk fwupd-0.7.0/policy/org.freedesktop.fwupd.policy.in000066400000000000000000000076731267747510300222460ustar00rootroot00000000000000 System firmware update https://github.com/hughsie/fwupd application-vnd.iccprofile <_description>Install signed system firmware <_message>Authentication is required to update the firmware on this machine application-vnd.iccprofile auth_admin no yes <_description>Install unsigned system firmware <_message>Authentication is required to update the firmware on this machine application-vnd.iccprofile auth_admin no auth_admin_keep <_description>Install old version of system firmware <_message>Authentication is required to downgrade the firmware on this machine application-vnd.iccprofile auth_admin no auth_admin_keep <_description>Install signed device firmware <_message>Authentication is required to update the firmware on a removable device application-vnd.iccprofile auth_admin no yes <_description>Install unsigned device firmware <_message>Authentication is required to update the firmware on a removable device application-vnd.iccprofile auth_admin no auth_admin_keep <_description>Install unsigned device firmware <_message>Authentication is required to downgrade the firmware on a removable device application-vnd.iccprofile auth_admin no auth_admin_keep <_description>Unlock the device to allow access <_message>Authentication is required to unlock a device application-vnd.iccprofile auth_admin no auth_admin_keep fwupd-0.7.0/policy/org.freedesktop.fwupd.rules000066400000000000000000000003741267747510300214630ustar00rootroot00000000000000polkit.addRule(function(action, subject) { if (action.id == "org.freedesktop.fwupd.update-internal" && subject.active == true && subject.local == true && subject.isInGroup("wheel")) { return polkit.Result.YES; } }); fwupd-0.7.0/src/000077500000000000000000000000001267747510300134465ustar00rootroot00000000000000fwupd-0.7.0/src/Makefile.am000066400000000000000000000107711267747510300155100ustar00rootroot00000000000000SUBDIRS = plugins introspectiondir = $(datadir)/dbus-1/interfaces dist_introspection_DATA = \ org.freedesktop.fwupd.xml AM_CPPFLAGS = \ $(APPSTREAM_GLIB_CFLAGS) \ $(COLORHUG_CFLAGS) \ $(GUSB_CFLAGS) \ $(GCAB_CFLAGS) \ $(GLIB_CFLAGS) \ $(GUDEV_CFLAGS) \ $(PIE_CFLAGS) \ $(POLKIT_CFLAGS) \ $(UEFI_CFLAGS) \ $(GPGME_CFLAGS) \ $(SOUP_CFLAGS) \ $(ARCHIVE_CFLAGS) \ -I$(top_srcdir) \ -I$(top_builddir) \ -I$(top_srcdir)/libfwupd \ -DG_LOG_DOMAIN=\"Fu\" \ -DLIBEXECDIR=\"$(libexecdir)\" \ -DLIBDIR=\"$(libdir)\" \ -DDATADIR=\"$(datadir)\" \ -DSYSCONFDIR=\""$(sysconfdir)"\" \ -DVERSION="\"$(VERSION)\"" \ -DDAEMON_USER="\"$(daemon_user)\"" \ -DTESTDATADIR=\""$(top_srcdir)/data/tests"\" \ -DG_UDEV_API_IS_SUBJECT_TO_CHANGE \ -DLOCALEDIR=\""$(localedir)"\" FWUPD_LIBS = \ $(top_builddir)/libfwupd/libfwupd.la DFU_LIBS = \ $(top_builddir)/libdfu/libdfu.la bin_PROGRAMS = fwupdmgr fwupdmgr_SOURCES = \ fu-device.c \ fu-device.h \ fu-pending.c \ fu-pending.h \ fu-rom.c \ fu-rom.h \ fu-util.c fwupdmgr_LDADD = \ $(LIBM) \ $(FWUPD_LIBS) \ $(APPSTREAM_GLIB_LIBS) \ $(SQLITE_LIBS) \ $(SOUP_LIBS) \ $(GUDEV_LIBS) \ $(GLIB_LIBS) fwupdmgr_LDFLAGS = \ $(PIE_LDFLAGS) fwupdmgr_CFLAGS = \ -DFU_OFFLINE_DESTDIR=\"\" \ -DLOCALSTATEDIR=\""$(localstatedir)"\" \ $(WARNINGFLAGS_C) fu-resources.c: fwupd.gresource.xml $(dist_introspection_DATA) $(AM_V_GEN) \ glib-compile-resources \ --sourcedir=$(srcdir) \ --sourcedir=$(top_builddir)/data \ --target=$@ \ --generate-source \ --c-name fu \ $(srcdir)/fwupd.gresource.xml fu-resources.h: fwupd.gresource.xml $(AM_V_GEN) \ glib-compile-resources \ --sourcedir=$(srcdir) \ --sourcedir=$(top_builddir)/data \ --target=$@ \ --generate-header \ --c-name fu \ $(srcdir)/fwupd.gresource.xml pkglibexec_PROGRAMS = \ fwupd fwupd_SOURCES = \ fu-debug.c \ fu-debug.h \ fu-device.c \ fu-device.h \ fu-keyring.c \ fu-keyring.h \ fu-pending.c \ fu-pending.h \ fu-plugin.c \ fu-plugin.h \ fu-provider.c \ fu-provider.h \ fu-provider-dfu.c \ fu-provider-dfu.h \ fu-provider-rpi.c \ fu-provider-rpi.h \ fu-provider-udev.c \ fu-provider-udev.h \ fu-provider-usb.c \ fu-provider-usb.h \ fu-quirks.h \ fu-resources.c \ fu-resources.h \ fu-rom.c \ fu-rom.h \ fu-main.c if HAVE_COLORHUG fwupd_SOURCES += \ fu-provider-chug.c \ fu-provider-chug.h endif if HAVE_UEFI fwupd_SOURCES += \ fu-provider-uefi.c \ fu-provider-uefi.h endif fwupd_LDADD = \ $(FWUPD_LIBS) \ $(DFU_LIBS) \ $(APPSTREAM_GLIB_LIBS) \ $(COLORHUG_LIBS) \ $(GUSB_LIBS) \ $(GCAB_LIBS) \ $(GLIB_LIBS) \ $(GUDEV_LIBS) \ $(POLKIT_LIBS) \ $(SQLITE_LIBS) \ $(GPGME_LIBS) \ $(ARCHIVE_LIBS) \ $(UEFI_LIBS) fwupd_LDFLAGS = \ $(PIE_LDFLAGS) \ $(RELRO_LDFLAGS) fwupd_CFLAGS = \ -DFU_OFFLINE_DESTDIR=\"\" \ -DLOCALSTATEDIR=\""$(localstatedir)"\" \ $(WARNINGFLAGS_C) TESTS_ENVIRONMENT = \ libtool --mode=execute valgrind \ --quiet \ --leak-check=full \ --show-possibly-lost=no check_PROGRAMS = \ fu-self-test fu_self_test_SOURCES = \ fu-device.c \ fu-device.h \ fu-keyring.c \ fu-keyring.h \ fu-pending.c \ fu-pending.h \ fu-plugin.c \ fu-plugin.h \ fu-provider.c \ fu-provider.h \ fu-provider-fake.c \ fu-provider-fake.h \ fu-provider-rpi.c \ fu-provider-rpi.h \ fu-rom.c \ fu-rom.h \ fu-self-test.c fu_self_test_LDADD = \ $(LIBM) \ $(FWUPD_LIBS) \ $(APPSTREAM_GLIB_LIBS) \ $(SQLITE_LIBS) \ $(GCAB_LIBS) \ $(GPGME_LIBS) \ $(ARCHIVE_LIBS) \ $(GLIB_LIBS) fu_self_test_CFLAGS = \ -DFU_OFFLINE_DESTDIR=\"/tmp/fwupd-self-test\" \ -DLOCALSTATEDIR=\"/tmp/fwupd-self-test/var\" \ $(WARNINGFLAGS_C) install-data-hook: if test -w $(DESTDIR)$(prefix)/; then \ mkdir -p $(DESTDIR)$(localstatedir)/lib/fwupd; \ chmod 0755 $(DESTDIR)$(localstatedir)/lib/fwupd; \ mkdir -p $(DESTDIR)$(localstatedir)/cache/app-info/xmls; \ mkdir -p $(DESTDIR)$(localstatedir)/cache/app-info/icons; \ fi TESTS = fu-self-test BUILT_SOURCES = \ fu-resources.c \ fu-resources.h CLEANFILES = $(BUILT_SOURCES) *.log *.trs EXTRA_DIST = \ fwupd.gresource.xml -include $(top_srcdir)/git.mk fwupd-0.7.0/src/fu-debug.c000066400000000000000000000112511267747510300153100ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2010-2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include static gboolean _verbose = FALSE; static gboolean _console = FALSE; /** * fu_debug_is_verbose: **/ gboolean fu_debug_is_verbose (void) { /* local first */ if (_verbose) return TRUE; /* fall back to env variable */ if (g_getenv ("VERBOSE") != NULL) return TRUE; return FALSE; } /** * fu_debug_ignore_cb: **/ static void fu_debug_ignore_cb (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) { /* syslog */ switch (log_level) { case G_LOG_LEVEL_INFO: g_print ("%s\n", message); case G_LOG_LEVEL_CRITICAL: case G_LOG_LEVEL_ERROR: case G_LOG_LEVEL_WARNING: g_print ("%s\n", message); break; default: break; } } /** * fu_debug_handler_cb: **/ static void fu_debug_handler_cb (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) { gchar str_time[255]; time_t the_time; /* syslog */ switch (log_level) { case G_LOG_LEVEL_INFO: g_print ("%s\n", message); case G_LOG_LEVEL_CRITICAL: case G_LOG_LEVEL_ERROR: case G_LOG_LEVEL_WARNING: g_print ("%s\n", message); break; default: break; } /* time header */ time (&the_time); strftime (str_time, 254, "%H:%M:%S", localtime (&the_time)); /* no color please, we're British */ if (!_console) { if (log_level == G_LOG_LEVEL_DEBUG) { g_print ("%s\t%s\n", str_time, message); } else { g_print ("***\n%s\t%s\n***\n", str_time, message); } return; } /* critical is also in red */ if (log_level == G_LOG_LEVEL_CRITICAL || log_level == G_LOG_LEVEL_ERROR) { g_print ("%c[%dm%s\t", 0x1B, 32, str_time); g_print ("%c[%dm%s\n%c[%dm", 0x1B, 31, message, 0x1B, 0); } else { /* debug in blue */ g_print ("%c[%dm%s\t", 0x1B, 32, str_time); g_print ("%c[%dm%s\n%c[%dm", 0x1B, 34, message, 0x1B, 0); } } /** * fu_debug_pre_parse_hook: */ static gboolean fu_debug_pre_parse_hook (GOptionContext *context, GOptionGroup *group, gpointer data, GError **error) { const GOptionEntry main_entries[] = { { "verbose", 'v', 0, G_OPTION_ARG_NONE, &_verbose, /* TRANSLATORS: turn on all debugging */ N_("Show debugging information for all files"), NULL }, { NULL} }; /* add main entry */ g_option_context_add_main_entries (context, main_entries, NULL); return TRUE; } /** * fu_debug_destroy: */ void fu_debug_destroy (void) { } /** * fu_debug_setup: */ void fu_debug_setup (gboolean enabled) { if (enabled) { g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_DEBUG | G_LOG_LEVEL_WARNING, fu_debug_handler_cb, NULL); } else { /* hide all debugging */ g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, fu_debug_ignore_cb, NULL); } /* are we on an actual TTY? */ _console = (isatty (fileno (stdout)) == 1); } /** * fu_debug_post_parse_hook: */ static gboolean fu_debug_post_parse_hook (GOptionContext *context, GOptionGroup *group, gpointer data, GError **error) { /* verbose? */ fu_debug_setup (_verbose); g_debug ("Verbose debugging %s (on console %i)", _verbose ? "enabled" : "disabled", _console); return TRUE; } /** * fu_debug_get_option_group: */ GOptionGroup * fu_debug_get_option_group (void) { GOptionGroup *group; group = g_option_group_new ("debug", /* TRANSLATORS: for the --verbose arg */ _("Debugging Options"), /* TRANSLATORS: for the --verbose arg */ _("Show debugging options"), NULL, NULL); g_option_group_set_parse_hooks (group, fu_debug_pre_parse_hook, fu_debug_post_parse_hook); return group; } fwupd-0.7.0/src/fu-debug.h000066400000000000000000000022431267747510300153160ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2010-2011 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __CD_DEBUG_H__ #define __CD_DEBUG_H__ #include gboolean fu_debug_is_verbose (void); GOptionGroup *fu_debug_get_option_group (void); void fu_debug_setup (gboolean enabled); void fu_debug_destroy (void); #endif /* __CD_DEBUG_H__ */ fwupd-0.7.0/src/fu-device.c000066400000000000000000000064601267747510300154670ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include "fu-device.h" static void fu_device_finalize (GObject *object); /** * FuDevicePrivate: * * Private #FuDevice data **/ typedef struct { gchar *equivalent_id; GHashTable *metadata; } FuDevicePrivate; G_DEFINE_TYPE_WITH_PRIVATE (FuDevice, fu_device, FWUPD_TYPE_RESULT) #define GET_PRIVATE(o) (fu_device_get_instance_private (o)) /** * fu_device_get_equivalent_id: **/ const gchar * fu_device_get_equivalent_id (FuDevice *device) { FuDevicePrivate *priv = GET_PRIVATE (device); g_return_val_if_fail (FU_IS_DEVICE (device), NULL); return priv->equivalent_id; } /** * fu_device_set_equivalent_id: **/ void fu_device_set_equivalent_id (FuDevice *device, const gchar *equivalent_id) { FuDevicePrivate *priv = GET_PRIVATE (device); g_return_if_fail (FU_IS_DEVICE (device)); g_free (priv->equivalent_id); priv->equivalent_id = g_strdup (equivalent_id); } /** * fu_device_get_metadata: **/ const gchar * fu_device_get_metadata (FuDevice *device, const gchar *key) { FuDevicePrivate *priv = GET_PRIVATE (device); g_return_val_if_fail (FU_IS_DEVICE (device), NULL); g_return_val_if_fail (key != NULL, NULL); return g_hash_table_lookup (priv->metadata, key); } /** * fu_device_get_id: **/ void fu_device_set_metadata (FuDevice *device, const gchar *key, const gchar *value) { FuDevicePrivate *priv = GET_PRIVATE (device); g_return_if_fail (FU_IS_DEVICE (device)); g_return_if_fail (key != NULL); g_return_if_fail (value != NULL); g_hash_table_insert (priv->metadata, g_strdup (key), g_strdup (value)); } /** * fu_device_class_init: **/ static void fu_device_class_init (FuDeviceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = fu_device_finalize; } /** * fu_device_init: **/ static void fu_device_init (FuDevice *device) { FuDevicePrivate *priv = GET_PRIVATE (device); priv->metadata = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); } /** * fu_device_finalize: **/ static void fu_device_finalize (GObject *object) { FuDevice *device = FU_DEVICE (object); FuDevicePrivate *priv = GET_PRIVATE (device); g_hash_table_unref (priv->metadata); G_OBJECT_CLASS (fu_device_parent_class)->finalize (object); } /** * fu_device_new: **/ FuDevice * fu_device_new (void) { FuDevice *device; device = g_object_new (FU_TYPE_DEVICE, NULL); return FU_DEVICE (device); } fwupd-0.7.0/src/fu-device.h000066400000000000000000000122361267747510300154720ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __FU_DEVICE_H #define __FU_DEVICE_H #include #include G_BEGIN_DECLS #define FU_TYPE_DEVICE (fu_device_get_type ()) G_DECLARE_DERIVABLE_TYPE (FuDevice, fu_device, FU, DEVICE, FwupdResult) struct _FuDeviceClass { FwupdResultClass parent_class; }; /* private */ #define FU_DEVICE_KEY_FWUPD_PLUGIN "fwupd::plugin" /* s */ FuDevice *fu_device_new (void); /* compat setters */ #define fu_device_add_flag(d,v) fwupd_result_add_device_flag(FWUPD_RESULT(d),v) #define fu_device_has_flag(d,v) fwupd_result_has_device_flag(FWUPD_RESULT(d),v) #define fu_device_set_checksum(d,v) fwupd_result_set_device_checksum(FWUPD_RESULT(d),v) #define fu_device_set_checksum_kind(d,v) fwupd_result_set_device_checksum_kind(FWUPD_RESULT(d),v) #define fu_device_set_created(d,v) fwupd_result_set_device_created(FWUPD_RESULT(d),v) #define fu_device_set_description(d,v) fwupd_result_set_device_description(FWUPD_RESULT(d),v) #define fu_device_set_flags(d,v) fwupd_result_set_device_flags(FWUPD_RESULT(d),v) #define fu_device_set_guid(d,v) fwupd_result_set_guid(FWUPD_RESULT(d),v) #define fu_device_set_id(d,v) fwupd_result_set_device_id(FWUPD_RESULT(d),v) #define fu_device_set_modified(d,v) fwupd_result_set_device_modified(FWUPD_RESULT(d),v) #define fu_device_set_name(d,v) fwupd_result_set_device_name(FWUPD_RESULT(d),v) #define fu_device_set_provider(d,v) fwupd_result_set_device_provider(FWUPD_RESULT(d),v) #define fu_device_set_update_checksum(d,v) fwupd_result_set_update_checksum(FWUPD_RESULT(d),v) #define fu_device_set_update_description(d,v) fwupd_result_set_update_description(FWUPD_RESULT(d),v) #define fu_device_set_update_error(d,v) fwupd_result_set_update_error(FWUPD_RESULT(d),v) #define fu_device_set_update_filename(d,v) fwupd_result_set_update_filename(FWUPD_RESULT(d),v) #define fu_device_set_update_homepage(d,v) fwupd_result_set_update_homepage(FWUPD_RESULT(d),v) #define fu_device_set_update_id(d,v) fwupd_result_set_update_id(FWUPD_RESULT(d),v) #define fu_device_set_update_license(d,v) fwupd_result_set_update_license(FWUPD_RESULT(d),v) #define fu_device_set_update_name(d,v) fwupd_result_set_update_name(FWUPD_RESULT(d),v) #define fu_device_set_update_state(d,v) fwupd_result_set_update_state(FWUPD_RESULT(d),v) #define fu_device_set_update_summary(d,v) fwupd_result_set_update_summary(FWUPD_RESULT(d),v) #define fu_device_set_update_uri(d,v) fwupd_result_set_update_uri(FWUPD_RESULT(d),v) #define fu_device_set_update_vendor(d,v) fwupd_result_set_update_vendor(FWUPD_RESULT(d),v) #define fu_device_set_update_version(d,v) fwupd_result_set_update_version(FWUPD_RESULT(d),v) #define fu_device_set_vendor(d,v) fwupd_result_set_device_vendor(FWUPD_RESULT(d),v) #define fu_device_set_version(d,v) fwupd_result_set_device_version(FWUPD_RESULT(d),v) #define fu_device_set_version_lowest(d,v) fwupd_result_set_device_version_lowest(FWUPD_RESULT(d),v) /* compat getters */ #define fu_device_get_checksum(d) fwupd_result_get_device_checksum(FWUPD_RESULT(d)) #define fu_device_get_flags(d) fwupd_result_get_device_flags(FWUPD_RESULT(d)) #define fu_device_get_guid(d) fwupd_result_get_guid(FWUPD_RESULT(d)) #define fu_device_get_id(d) fwupd_result_get_device_id(FWUPD_RESULT(d)) #define fu_device_get_provider(d) fwupd_result_get_device_provider(FWUPD_RESULT(d)) #define fu_device_get_update_checksum(d) fwupd_result_get_update_checksum(FWUPD_RESULT(d)) #define fu_device_get_update_error(d) fwupd_result_get_update_error(FWUPD_RESULT(d)) #define fu_device_get_update_filename(d) fwupd_result_get_update_filename(FWUPD_RESULT(d)) #define fu_device_get_update_state(d) fwupd_result_get_update_state(FWUPD_RESULT(d)) #define fu_device_get_update_version(d) fwupd_result_get_update_version(FWUPD_RESULT(d)) #define fu_device_get_version(d) fwupd_result_get_device_version(FWUPD_RESULT(d)) #define fu_device_get_version_lowest(d) fwupd_result_get_device_version_lowest(FWUPD_RESULT(d)) /* accessors */ const gchar *fu_device_get_equivalent_id (FuDevice *device); void fu_device_set_equivalent_id (FuDevice *device, const gchar *equivalent_id); const gchar *fu_device_get_metadata (FuDevice *device, const gchar *key); void fu_device_set_metadata (FuDevice *device, const gchar *key, const gchar *value); G_END_DECLS #endif /* __FU_DEVICE_H */ fwupd-0.7.0/src/fu-keyring.c000066400000000000000000000261251267747510300157000ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include "fu-keyring.h" static void fu_keyring_finalize (GObject *object); /** * FuKeyringPrivate: * * Private #FuKeyring data **/ typedef struct { gpgme_ctx_t ctx; } FuKeyringPrivate; G_DEFINE_TYPE_WITH_PRIVATE (FuKeyring, fu_keyring, G_TYPE_OBJECT) #define GET_PRIVATE(o) (fu_keyring_get_instance_private (o)) G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gpgme_data_t, gpgme_data_release, NULL) /** * fu_keyring_setup: **/ static gboolean fu_keyring_setup (FuKeyring *keyring, GError **error) { FuKeyringPrivate *priv = GET_PRIVATE (keyring); gpgme_error_t rc; g_return_val_if_fail (FU_IS_KEYRING (keyring), FALSE); if (priv->ctx != NULL) return TRUE; /* check version */ gpgme_check_version (NULL); /* startup gpgme */ rc = gpg_err_init (); if (rc != GPG_ERR_NO_ERROR) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to startup GPG: %s", gpgme_strerror (rc)); return FALSE; } /* create a new GPG context */ rc = gpgme_new (&priv->ctx); if (rc != GPG_ERR_NO_ERROR) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to create context: %s", gpgme_strerror (rc)); return FALSE; } /* set the protocol */ rc = gpgme_set_protocol (priv->ctx, GPGME_PROTOCOL_OpenPGP); if (rc != GPG_ERR_NO_ERROR) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to set protocol: %s", gpgme_strerror (rc)); return FALSE; } /* enable armor mode */ gpgme_set_armor (priv->ctx, TRUE); /* never interactive */ gpgme_set_pinentry_mode (priv->ctx, GPGME_PINENTRY_MODE_ERROR); return TRUE; } /** * fu_keyring_add_public_key: **/ gboolean fu_keyring_add_public_key (FuKeyring *keyring, const gchar *filename, GError **error) { FuKeyringPrivate *priv = GET_PRIVATE (keyring); gpgme_error_t rc; gpgme_import_result_t result; gpgme_import_status_t s; g_auto(gpgme_data_t) data = NULL; g_return_val_if_fail (FU_IS_KEYRING (keyring), FALSE); g_return_val_if_fail (filename != NULL, FALSE); /* import public key */ g_debug ("Adding public key %s", filename); rc = gpgme_data_new_from_file (&data, filename, 1); if (rc != GPG_ERR_NO_ERROR) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to load %s: %s", filename, gpgme_strerror (rc)); return FALSE; } rc = gpgme_op_import (priv->ctx, data); if (rc != GPG_ERR_NO_ERROR) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to import %s: %s", filename, gpgme_strerror (rc)); return FALSE; } /* print what keys were imported */ result = gpgme_op_import_result (priv->ctx); for (s = result->imports; s != NULL; s = s->next) { g_debug ("importing key %s [%i] %s", s->fpr, s->status, gpgme_strerror (s->result)); } /* make sure keys were really imported */ if (result->imported == 0 && result->unchanged == 0) { g_debug("imported: %d, unchanged: %d, not_imported: %d", result->imported, result->unchanged, result->not_imported); g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "key import failed %s", filename); return FALSE; } return TRUE; } /** * fu_keyring_add_public_keys: **/ gboolean fu_keyring_add_public_keys (FuKeyring *keyring, const gchar *dirname, GError **error) { g_autoptr(GDir) dir = NULL; g_return_val_if_fail (FU_IS_KEYRING (keyring), FALSE); g_return_val_if_fail (dirname != NULL, FALSE); /* setup context */ if (!fu_keyring_setup (keyring, error)) return FALSE; /* search all the public key files */ dir = g_dir_open (dirname, 0, error); if (dir == NULL) return FALSE; do { const gchar *filename; g_autofree gchar *path_tmp = NULL; filename = g_dir_read_name (dir); if (filename == NULL) break; path_tmp = g_build_filename (dirname, filename, NULL); if (!fu_keyring_add_public_key (keyring, path_tmp, error)) return FALSE; } while (TRUE); return TRUE; } /** * fu_keyring_check_signature: **/ static gboolean fu_keyring_check_signature (gpgme_signature_t signature, GError **error) { gboolean ret = FALSE; /* look at the signature status */ switch (gpgme_err_code (signature->status)) { case GPG_ERR_NO_ERROR: ret = TRUE; break; case GPG_ERR_SIG_EXPIRED: case GPG_ERR_KEY_EXPIRED: g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID, "valid signature '%s' has expired", signature->fpr); break; case GPG_ERR_CERT_REVOKED: g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID, "valid signature '%s' has been revoked", signature->fpr); break; case GPG_ERR_BAD_SIGNATURE: g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID, "'%s' is not a valid signature", signature->fpr); break; case GPG_ERR_NO_PUBKEY: g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID, "Could not check signature '%s' as no public key", signature->fpr); break; default: g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID, "gpgme failed to verify signature '%s'", signature->fpr); break; } return ret; } /** * fu_keyring_verify_file: **/ gboolean fu_keyring_verify_file (FuKeyring *keyring, const gchar *filename, const gchar *signature, GError **error) { FuKeyringPrivate *priv = GET_PRIVATE (keyring); gboolean has_header; gpgme_error_t rc; gpgme_signature_t s; gpgme_verify_result_t result; g_auto(gpgme_data_t) data = NULL; g_auto(gpgme_data_t) sig = NULL; g_autoptr(GString) sig_v1 = NULL; g_return_val_if_fail (FU_IS_KEYRING (keyring), FALSE); g_return_val_if_fail (filename != NULL, FALSE); g_return_val_if_fail (signature != NULL, FALSE); /* setup context */ if (!fu_keyring_setup (keyring, error)) return FALSE; /* has header already */ has_header = g_strstr_len (signature, -1, "BEGIN PGP SIGNATURE") != NULL; /* load file data */ rc = gpgme_data_new_from_file (&data, filename, 1); if (rc != GPG_ERR_NO_ERROR) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to load %s: %s", filename, gpgme_strerror (rc)); return FALSE; } /* load signature */ sig_v1 = g_string_new (""); if (!has_header) { g_string_append (sig_v1, "-----BEGIN PGP SIGNATURE-----\n"); g_string_append (sig_v1, "Version: GnuPG v1\n\n"); } g_string_append_printf (sig_v1, "%s\n", signature); if (!has_header) g_string_append (sig_v1, "-----END PGP SIGNATURE-----\n"); rc = gpgme_data_new_from_mem (&sig, sig_v1->str, sig_v1->len, 0); if (rc != GPG_ERR_NO_ERROR) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to load signature %s: %s", signature, gpgme_strerror (rc)); return FALSE; } /* verify */ rc = gpgme_op_verify (priv->ctx, sig, data, NULL); if (rc != GPG_ERR_NO_ERROR) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to verify %s: %s", filename, gpgme_strerror (rc)); return FALSE; } /* verify the result */ result = gpgme_op_verify_result (priv->ctx); if (result == NULL) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "no result record from libgpgme"); return FALSE; } /* look at each signature */ for (s = result->signatures; s != NULL ; s = s->next ) { g_debug ("returned signature fingerprint %s", s->fpr); if (!fu_keyring_check_signature (s, error)) return FALSE; } return TRUE; } /** * fu_keyring_verify_data: **/ gboolean fu_keyring_verify_data (FuKeyring *keyring, GBytes *payload, GBytes *payload_signature, GError **error) { FuKeyringPrivate *priv = GET_PRIVATE (keyring); gpgme_error_t rc; gpgme_signature_t s; gpgme_verify_result_t result; g_auto(gpgme_data_t) data = NULL; g_auto(gpgme_data_t) sig = NULL; g_return_val_if_fail (FU_IS_KEYRING (keyring), FALSE); g_return_val_if_fail (payload != NULL, FALSE); g_return_val_if_fail (payload_signature != NULL, FALSE); /* setup context */ if (!fu_keyring_setup (keyring, error)) return FALSE; /* load file data */ rc = gpgme_data_new_from_mem (&data, g_bytes_get_data (payload, NULL), g_bytes_get_size (payload), 0); if (rc != GPG_ERR_NO_ERROR) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to load data: %s", gpgme_strerror (rc)); return FALSE; } rc = gpgme_data_new_from_mem (&sig, g_bytes_get_data (payload_signature, NULL), g_bytes_get_size (payload_signature), 0); if (rc != GPG_ERR_NO_ERROR) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to load signature: %s", gpgme_strerror (rc)); return FALSE; } /* verify */ rc = gpgme_op_verify (priv->ctx, sig, data, NULL); if (rc != GPG_ERR_NO_ERROR) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to verify data: %s", gpgme_strerror (rc)); return FALSE; } /* verify the result */ result = gpgme_op_verify_result (priv->ctx); if (result == NULL) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "no result record from libgpgme"); return FALSE; } /* look at each signature */ for (s = result->signatures; s != NULL ; s = s->next ) { g_debug ("returned signature fingerprint %s", s->fpr); if (!fu_keyring_check_signature (s, error)) return FALSE; } return TRUE; } /** * fu_keyring_class_init: **/ static void fu_keyring_class_init (FuKeyringClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = fu_keyring_finalize; } /** * fu_keyring_init: **/ static void fu_keyring_init (FuKeyring *keyring) { } /** * fu_keyring_finalize: **/ static void fu_keyring_finalize (GObject *object) { FuKeyring *keyring = FU_KEYRING (object); FuKeyringPrivate *priv = GET_PRIVATE (keyring); if (priv->ctx != NULL) gpgme_release (priv->ctx); G_OBJECT_CLASS (fu_keyring_parent_class)->finalize (object); } /** * fu_keyring_new: **/ FuKeyring * fu_keyring_new (void) { FuKeyring *keyring; keyring = g_object_new (FU_TYPE_KEYRING, NULL); return FU_KEYRING (keyring); } fwupd-0.7.0/src/fu-keyring.h000066400000000000000000000034231267747510300157010ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __FU_KEYRING_H #define __FU_KEYRING_H #include #include G_BEGIN_DECLS #define FU_TYPE_KEYRING (fu_keyring_get_type ()) G_DECLARE_DERIVABLE_TYPE (FuKeyring, fu_keyring, FU, KEYRING, GObject) struct _FuKeyringClass { GObjectClass parent_class; }; FuKeyring *fu_keyring_new (void); gboolean fu_keyring_add_public_keys (FuKeyring *keyring, const gchar *dirname, GError **error); gboolean fu_keyring_add_public_key (FuKeyring *keyring, const gchar *filename, GError **error); gboolean fu_keyring_verify_file (FuKeyring *keyring, const gchar *filename, const gchar *signature, GError **error); gboolean fu_keyring_verify_data (FuKeyring *keyring, GBytes *payload, GBytes *payload_signature, GError **error); G_END_DECLS #endif /* __FU_KEYRING_H */ fwupd-0.7.0/src/fu-main.c000066400000000000000000001724331267747510300151600ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015-2016 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include "fwupd-enums-private.h" #include "fu-debug.h" #include "fu-device.h" #include "fu-plugin.h" #include "fu-keyring.h" #include "fu-pending.h" #include "fu-provider.h" #include "fu-provider-dfu.h" #include "fu-provider-rpi.h" #include "fu-provider-udev.h" #include "fu-provider-usb.h" #include "fu-resources.h" #include "fu-quirks.h" #ifdef HAVE_COLORHUG #include "fu-provider-chug.h" #endif #ifdef HAVE_UEFI #include "fu-provider-uefi.h" #endif #ifndef PolkitAuthorizationResult_autoptr G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitAuthorizationResult, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitSubject, g_object_unref) #endif #define FU_MAIN_FIRMWARE_SIZE_MAX (32 * 1024 * 1024) /* bytes */ typedef struct { GDBusConnection *connection; GDBusNodeInfo *introspection_daemon; GDBusProxy *proxy_uid; GDBusProxy *proxy_upower; GMainLoop *loop; GPtrArray *devices; /* of FuDeviceItem */ GPtrArray *providers; PolkitAuthority *authority; FwupdStatus status; FuPending *pending; AsProfile *profile; AsStore *store; guint store_changed_id; GHashTable *plugins; /* of name : FuPlugin */ } FuMainPrivate; typedef struct { FuDevice *device; FuProvider *provider; } FuDeviceItem; /** * fu_main_emit_changed: **/ static void fu_main_emit_changed (FuMainPrivate *priv) { /* not yet connected */ if (priv->connection == NULL) return; g_dbus_connection_emit_signal (priv->connection, NULL, FWUPD_DBUS_PATH, FWUPD_DBUS_INTERFACE, "Changed", NULL, NULL); } /** * fu_main_emit_property_changed: **/ static void fu_main_emit_property_changed (FuMainPrivate *priv, const gchar *property_name, GVariant *property_value) { GVariantBuilder builder; GVariantBuilder invalidated_builder; /* not yet connected */ if (priv->connection == NULL) return; /* build the dict */ g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as")); g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); g_variant_builder_add (&builder, "{sv}", property_name, property_value); g_dbus_connection_emit_signal (priv->connection, NULL, FWUPD_DBUS_PATH, "org.freedesktop.DBus.Properties", "PropertiesChanged", g_variant_new ("(sa{sv}as)", FWUPD_DBUS_INTERFACE, &builder, &invalidated_builder), NULL); g_variant_builder_clear (&builder); g_variant_builder_clear (&invalidated_builder); } /** * fu_main_set_status: **/ static void fu_main_set_status (FuMainPrivate *priv, FwupdStatus status) { if (priv->status == status) return; priv->status = status; /* emit changed */ g_debug ("Emitting PropertyChanged('Status'='%s')", fwupd_status_to_string (status)); fu_main_emit_property_changed (priv, "Status", g_variant_new_uint32 (status)); } /** * fu_main_device_array_to_variant: **/ static GVariant * fu_main_device_array_to_variant (GPtrArray *devices, GError **error) { GVariantBuilder builder; guint i; /* no devices */ if (devices->len == 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO, "Nothing to do"); return NULL; } g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); for (i = 0; i < devices->len; i++) { GVariant *tmp; FuDeviceItem *item; item = g_ptr_array_index (devices, i); tmp = fwupd_result_to_data (FWUPD_RESULT (item->device), "{sa{sv}}"); g_variant_builder_add_value (&builder, tmp); } return g_variant_new ("(a{sa{sv}})", &builder); } /** * fu_main_load_plugins: **/ static gboolean fu_main_load_plugins (GHashTable *plugins, GError **error) { FuPlugin *plugin; GModule *module; GList *l; const gchar *fn; g_autofree gchar *plugin_dir = NULL; g_autoptr(GDir) dir = NULL; g_autoptr(GList) values = NULL; /* search */ plugin_dir = g_build_filename (LIBDIR, "fwupd-plugins-1", NULL); dir = g_dir_open (plugin_dir, 0, error); if (dir == NULL) return FALSE; while ((fn = g_dir_read_name (dir)) != NULL) { g_autofree gchar *filename = NULL; /* ignore non-plugins */ if (!g_str_has_suffix (fn, ".so")) continue; /* open module */ filename = g_build_filename (plugin_dir, fn, NULL); g_debug ("adding plugin %s", filename); module = g_module_open (filename, 0); if (module == NULL) { g_warning ("failed to open plugin %s: %s", filename, g_module_error ()); continue; } plugin = fu_plugin_new (module); if (plugin == NULL) { g_module_close (module); g_warning ("plugin %s requires name", filename); continue; } /* add */ g_hash_table_insert (plugins, g_strdup (plugin->name), plugin); } /* start them all up */ values = g_hash_table_get_values (plugins); for (l = values; l != NULL; l = l->next) { plugin = FU_PLUGIN (l->data); if (!fu_plugin_run_startup (plugin, error)) return FALSE; } return TRUE; } /** * fu_main_get_plugin_for_device: **/ static FuPlugin * fu_main_get_plugin_for_device (GHashTable *plugins, FuDevice *device) { const gchar *tmp; /* does a vendor plugin exist */ tmp = fu_device_get_metadata (device, FU_DEVICE_KEY_FWUPD_PLUGIN); if (tmp == NULL) return NULL; return g_hash_table_lookup (plugins, tmp); } /** * fu_main_item_free: **/ static void fu_main_item_free (FuDeviceItem *item) { g_object_unref (item->device); g_object_unref (item->provider); g_free (item); } /** * fu_main_get_item_by_id: **/ static FuDeviceItem * fu_main_get_item_by_id (FuMainPrivate *priv, const gchar *id) { FuDeviceItem *item; guint i; for (i = 0; i < priv->devices->len; i++) { item = g_ptr_array_index (priv->devices, i); if (g_strcmp0 (fu_device_get_id (item->device), id) == 0) return item; if (g_strcmp0 (fu_device_get_equivalent_id (item->device), id) == 0) return item; } return NULL; } /** * fu_main_get_item_by_guid: **/ static FuDeviceItem * fu_main_get_item_by_guid (FuMainPrivate *priv, const gchar *guid) { FuDeviceItem *item; guint i; for (i = 0; i < priv->devices->len; i++) { item = g_ptr_array_index (priv->devices, i); if (g_strcmp0 (fu_device_get_guid (item->device), guid) == 0) return item; } return NULL; } /** * fu_main_get_provider_by_name: **/ static FuProvider * fu_main_get_provider_by_name (FuMainPrivate *priv, const gchar *name) { FuProvider *provider; guint i; for (i = 0; i < priv->providers->len; i++) { provider = g_ptr_array_index (priv->providers, i); if (g_strcmp0 (fu_provider_get_name (provider), name) == 0) return provider; } return NULL; } /** * fu_main_get_release_trust_flags: **/ static gboolean fu_main_get_release_trust_flags (AsRelease *release, FwupdTrustFlags *trust_flags, GError **error) { AsChecksum *csum_tmp; GBytes *blob_payload; GBytes *blob_signature; const gchar *fn; g_autofree gchar *pki_dir = NULL; g_autofree gchar *fn_signature = NULL; g_autoptr(GError) error_local = NULL; g_autoptr(FuKeyring) kr = NULL; /* no filename? */ csum_tmp = as_release_get_checksum_by_target (release, AS_CHECKSUM_TARGET_CONTENT); 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; } /* no signature == no trust */ fn_signature = g_strdup_printf ("%s.asc", fn); blob_signature = as_release_get_blob (release, fn_signature); if (blob_signature == NULL) { g_debug ("firmware archive contained no GPG signature"); return TRUE; } /* get payload */ blob_payload = as_release_get_blob (release, fn); if (blob_payload == NULL) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "no payload"); return FALSE; } /* check we were installed correctly */ pki_dir = g_build_filename (SYSCONFDIR, "pki", "fwupd", NULL); if (!g_file_test (pki_dir, G_FILE_TEST_EXISTS)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "PKI directory %s not found", pki_dir); return FALSE; } /* verify against the system trusted keys */ kr = fu_keyring_new (); if (!fu_keyring_add_public_keys (kr, pki_dir, error)) return FALSE; if (!fu_keyring_verify_data (kr, blob_payload, blob_signature, &error_local)) { g_warning ("untrusted as failed to verify: %s", error_local->message); return TRUE; } /* awesome! */ g_debug ("marking payload as trusted"); *trust_flags |= FWUPD_TRUST_FLAG_PAYLOAD; return TRUE; } typedef enum { FU_MAIN_AUTH_KIND_UNKNOWN, FU_MAIN_AUTH_KIND_INSTALL, FU_MAIN_AUTH_KIND_UNLOCK, FU_MAIN_AUTH_KIND_LAST } FuMainAuthKind; typedef struct { GDBusMethodInvocation *invocation; AsStore *store; FwupdTrustFlags trust_flags; FuDevice *device; FwupdInstallFlags flags; GBytes *blob_fw; GBytes *blob_cab; gint vercmp; FuMainAuthKind auth_kind; FuMainPrivate *priv; } FuMainAuthHelper; /** * fu_main_helper_free: **/ static void fu_main_helper_free (FuMainAuthHelper *helper) { /* free */ if (helper->device != NULL) g_object_unref (helper->device); if (helper->blob_fw > 0) g_bytes_unref (helper->blob_fw); if (helper->blob_cab > 0) g_bytes_unref (helper->blob_cab); if (helper->store != NULL) g_object_unref (helper->store); g_object_unref (helper->invocation); g_free (helper); } /** * fu_main_on_battery: **/ static gboolean fu_main_on_battery (FuMainPrivate *priv) { g_autoptr(GVariant) value = NULL; if (priv->proxy_upower == NULL) { g_warning ("Failed to get OnBattery property as no UPower"); return FALSE; } value = g_dbus_proxy_get_cached_property (priv->proxy_upower, "OnBattery"); if (value == NULL) { g_warning ("Failed to get OnBattery property value"); return FALSE; } return g_variant_get_boolean (value); } /** * fu_main_provider_unlock_authenticated: **/ static gboolean fu_main_provider_unlock_authenticated (FuMainAuthHelper *helper, GError **error) { FuDeviceItem *item; /* check the device still exists */ item = fu_main_get_item_by_id (helper->priv, fu_device_get_id (helper->device)); if (item == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "device %s was removed", fu_device_get_id (helper->device)); return FALSE; } /* run the correct provider that added this */ if (!fu_provider_unlock (item->provider, item->device, error)) return FALSE; /* make the UI update */ fu_main_emit_changed (helper->priv); return TRUE; } /** * fu_main_provider_update_authenticated: **/ static gboolean fu_main_provider_update_authenticated (FuMainAuthHelper *helper, GError **error) { FuDeviceItem *item; FuPlugin *plugin; /* check the device still exists */ item = fu_main_get_item_by_id (helper->priv, fu_device_get_id (helper->device)); if (item == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "device %s was removed", fu_device_get_id (helper->device)); return FALSE; } /* can we only do this on AC power */ if (fu_device_has_flag (item->device, FU_DEVICE_FLAG_REQUIRE_AC)) { if (fu_main_on_battery (helper->priv)) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "Cannot install update " "when not on AC power"); return FALSE; } } /* run the correct provider that added this */ plugin = fu_main_get_plugin_for_device (helper->priv->plugins, item->device); if (!fu_provider_update (item->provider, item->device, helper->blob_cab, helper->blob_fw, plugin, helper->flags, error)) return FALSE; /* make the UI update */ fu_device_set_modified (item->device, g_get_real_time () / G_USEC_PER_SEC); fu_main_emit_changed (helper->priv); return TRUE; } /** * fu_main_check_authorization_cb: **/ static void fu_main_check_authorization_cb (GObject *source, GAsyncResult *res, gpointer user_data) { FuMainAuthHelper *helper = (FuMainAuthHelper *) user_data; g_autoptr(GError) error = NULL; g_autoptr(PolkitAuthorizationResult) auth = NULL; /* get result */ auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source), res, &error); if (auth == NULL) { g_dbus_method_invocation_return_error (helper->invocation, FWUPD_ERROR, FWUPD_ERROR_AUTH_FAILED, "could not check for auth: %s", error->message); fu_main_helper_free (helper); return; } /* did not auth */ if (!polkit_authorization_result_get_is_authorized (auth)) { g_dbus_method_invocation_return_error (helper->invocation, FWUPD_ERROR, FWUPD_ERROR_AUTH_FAILED, "failed to obtain auth"); fu_main_helper_free (helper); return; } /* we're good to go */ if (helper->auth_kind == FU_MAIN_AUTH_KIND_INSTALL) { if (!fu_main_provider_update_authenticated (helper, &error)) { g_dbus_method_invocation_return_gerror (helper->invocation, error); fu_main_helper_free (helper); return; } } else if (helper->auth_kind == FU_MAIN_AUTH_KIND_UNLOCK) { if (!fu_main_provider_unlock_authenticated (helper, &error)) { g_dbus_method_invocation_return_gerror (helper->invocation, error); fu_main_helper_free (helper); return; } } else { g_assert_not_reached (); } /* success */ g_dbus_method_invocation_return_value (helper->invocation, NULL); fu_main_helper_free (helper); } /** * fu_main_get_guids_from_store: **/ static gchar * fu_main_get_guids_from_store (AsStore *store) { AsApp *app; AsProvide *prov; GPtrArray *provides; GPtrArray *apps; GString *str = g_string_new (""); guint i; guint j; /* return a string with all the firmware apps in the store */ apps = as_store_get_apps (store); for (i = 0; i < apps->len; i++) { app = AS_APP (g_ptr_array_index (apps, i)); provides = as_app_get_provides (app); for (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) return NULL; g_string_truncate (str, str->len - 1); return g_string_free (str, FALSE); } /** * fu_main_vendor_quirk_release_version: **/ static void fu_main_vendor_quirk_release_version (AsApp *app) { AsVersionParseFlag flags = AS_VERSION_PARSE_FLAG_USE_TRIPLET; GPtrArray *releases; guint i; /* no quirk required */ if (as_app_get_kind (app) != AS_APP_KIND_FIRMWARE) return; for (i = 0; quirk_table[i].identifier != NULL; i++) if (g_str_has_prefix (as_app_get_id(app), quirk_table[i].identifier)) flags = quirk_table[i].flags; /* fix each release */ releases = as_app_get_releases (app); for (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 */ if (g_str_has_prefix (version, "0x")) { ver_uint32 = g_ascii_strtoull (version + 2, NULL, 16); } else { ver_uint32 = g_ascii_strtoull (version, NULL, 10); } if (ver_uint32 == 0) continue; /* convert to dotted decimal */ version_new = as_utils_version_from_uint32 (ver_uint32, flags); as_release_set_version (rel, version_new); } } /** * fu_main_update_helper: **/ static gboolean fu_main_update_helper (FuMainAuthHelper *helper, GError **error) { AsApp *app; AsChecksum *csum_tmp; AsRelease *rel; const gchar *tmp; const gchar *version; guint i; /* load store file which also decompresses firmware */ fu_main_set_status (helper->priv, FWUPD_STATUS_DECOMPRESSING); if (!as_store_from_bytes (helper->store, helper->blob_cab, NULL, error)) return FALSE; /* if we've not chosen a device, try and find anything in the * cabinet 'store' that matches any installed device */ if (helper->device == NULL) { for (i = 0; i < helper->priv->devices->len; i++) { FuDeviceItem *item; item = g_ptr_array_index (helper->priv->devices, i); app = as_store_get_app_by_provide (helper->store, AS_PROVIDE_KIND_FIRMWARE_FLASHED, fu_device_get_guid (item->device)); if (app != NULL) { helper->device = g_object_ref (item->device); break; } } /* nothing found */ if (helper->device == NULL) { g_autofree gchar *guid = NULL; guid = fu_main_get_guids_from_store (helper->store); g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "no attached hardware matched %s", guid); return FALSE; } } else { /* find an application from the cabinet 'store' for the * chosen device */ app = as_store_get_app_by_provide (helper->store, AS_PROVIDE_KIND_FIRMWARE_FLASHED, fu_device_get_guid (helper->device)); if (app == NULL) { g_autofree gchar *guid = NULL; guid = fu_main_get_guids_from_store (helper->store); g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "firmware is not for this hw: required %s got %s", fu_device_get_guid (helper->device), guid); return FALSE; } } /* parse the DriverVer */ rel = as_app_get_release_default (app); if (rel == NULL) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "no releases in the firmware component"); 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); g_assert (tmp != NULL); helper->blob_fw = as_release_get_blob (rel, tmp); if (helper->blob_fw == NULL) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_READ, "failed to get firmware blob"); return FALSE; } /* possibly convert the version from 0x to dotted */ fu_main_vendor_quirk_release_version (app); version = as_release_get_version (rel); fu_device_set_update_version (helper->device, version); /* compare to the lowest supported version, if it exists */ tmp = fu_device_get_version_lowest (helper->device); if (tmp != NULL && as_utils_vercmp (tmp, version) > 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_VERSION_NEWER, "Specified firmware is older than the minimum " "required version '%s < %s'", tmp, version); return FALSE; } /* compare the versions of what we have installed */ tmp = fu_device_get_version (helper->device); if (tmp == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "Device %s does not yet have a current version", fu_device_get_id (helper->device)); return FALSE; } helper->vercmp = as_utils_vercmp (tmp, version); if (helper->vercmp == 0 && (helper->flags & FWUPD_INSTALL_FLAG_ALLOW_REINSTALL) == 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_VERSION_SAME, "Specified firmware is already installed '%s'", tmp); return FALSE; } if (helper->vercmp > 0 && (helper->flags & FWUPD_INSTALL_FLAG_ALLOW_OLDER) == 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_VERSION_NEWER, "Specified firmware is older than installed '%s < %s'", tmp, version); return FALSE; } /* verify */ if (!fu_main_get_release_trust_flags (rel, &helper->trust_flags, error)) return FALSE; return TRUE; } /** * fu_main_dbus_get_uid: * * Return value: the UID, or %G_MAXUINT if it could not be obtained **/ static guint fu_main_dbus_get_uid (FuMainPrivate *priv, const gchar *sender) { guint uid; g_autoptr(GError) error = NULL; g_autoptr(GVariant) value = NULL; if (priv->proxy_uid == NULL) return G_MAXUINT; value = g_dbus_proxy_call_sync (priv->proxy_uid, "GetConnectionUnixUser", g_variant_new ("(s)", sender), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (value == NULL) { g_warning ("Failed to get uid for %s: %s", sender, error->message); return G_MAXUINT; } g_variant_get (value, "(u)", &uid); return uid; } /** * fu_main_get_item_by_id_fallback_pending: **/ static FuDeviceItem * fu_main_get_item_by_id_fallback_pending (FuMainPrivate *priv, const gchar *id, GError **error) { FuDevice *dev; FuProvider *provider; FuDeviceItem *item = NULL; FwupdUpdateState update_state; const gchar *tmp; guint i; g_autoptr(GPtrArray) devices = NULL; /* not a wildcard */ if (g_strcmp0 (id, FWUPD_DEVICE_ID_ANY) != 0) { item = fu_main_get_item_by_id (priv, id); if (item == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "no suitable device found for %s", id); } return item; } /* allow '*' for any */ devices = fu_pending_get_devices (priv->pending, error); if (devices == NULL) return NULL; for (i = 0; i < devices->len; i++) { dev = g_ptr_array_index (devices, i); update_state = fu_device_get_update_state (dev); if (update_state == FWUPD_UPDATE_STATE_UNKNOWN) continue; if (update_state == FWUPD_UPDATE_STATE_PENDING) continue; /* if the device is not still connected, fake a FuDeviceItem */ item = fu_main_get_item_by_id (priv, fu_device_get_id (dev)); if (item == NULL) { tmp = fu_device_get_provider (dev); provider = fu_main_get_provider_by_name (priv, tmp); if (provider == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "no provider %s found", tmp); } item = g_new0 (FuDeviceItem, 1); item->device = g_object_ref (dev); item->provider = g_object_ref (provider); g_ptr_array_add (priv->devices, item); /* FIXME: just a boolean on FuDeviceItem? */ fu_device_set_metadata (dev, "FakeDevice", "TRUE"); } break; } /* no device found */ if (item == NULL) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "no suitable devices found"); } return item; } /** * fu_main_get_action_id_for_device: **/ static const gchar * fu_main_get_action_id_for_device (FuMainAuthHelper *helper) { gboolean is_trusted; gboolean is_downgrade; /* only test the payload */ is_trusted = (helper->trust_flags & FWUPD_TRUST_FLAG_PAYLOAD) > 0; is_downgrade = helper->vercmp > 0; /* relax authentication checks for removable devices */ if (!fu_device_has_flag (helper->device, FU_DEVICE_FLAG_INTERNAL)) { if (is_downgrade) return "org.freedesktop.fwupd.downgrade-hotplug"; if (is_trusted) return "org.freedesktop.fwupd.update-hotplug-trusted"; return "org.freedesktop.fwupd.update-hotplug"; } /* internal device */ if (is_downgrade) return "org.freedesktop.fwupd.downgrade-internal"; if (is_trusted) return "org.freedesktop.fwupd.update-internal-trusted"; return "org.freedesktop.fwupd.update-internal"; } /** * fu_main_daemon_update_metadata: * * Supports optionally GZipped AppStream files up to 1MiB in size. **/ static gboolean fu_main_daemon_update_metadata (FuMainPrivate *priv, gint fd, gint fd_sig, GError **error) { const guint8 *data; guint i; gsize size; GPtrArray *apps; g_autofree gchar *xml = NULL; g_autoptr(AsStore) store = NULL; g_autoptr(GBytes) bytes = NULL; g_autoptr(GBytes) bytes_raw = NULL; g_autoptr(GBytes) bytes_sig = NULL; g_autoptr(FuKeyring) kr = NULL; g_autoptr(GConverter) converter = NULL; g_autoptr(GFile) file = NULL; g_autoptr(GInputStream) stream_buf = NULL; g_autoptr(GInputStream) stream_fd = NULL; g_autoptr(GInputStream) stream = NULL; g_autoptr(GInputStream) stream_sig = NULL; /* read the entire file into memory */ stream_fd = g_unix_input_stream_new (fd, TRUE); bytes_raw = g_input_stream_read_bytes (stream_fd, 0x100000, NULL, error); if (bytes_raw == NULL) return FALSE; stream_buf = g_memory_input_stream_new (); g_memory_input_stream_add_bytes (G_MEMORY_INPUT_STREAM (stream_buf), bytes_raw); /* peek the file type and get data */ data = g_bytes_get_data (bytes_raw, &size); if (size < 2) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "file is too small"); return FALSE; } if (data[0] == 0x1f && data[1] == 0x8b) { g_debug ("using GZip decompressor for data"); converter = G_CONVERTER (g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP)); stream = g_converter_input_stream_new (stream_buf, converter); bytes = g_input_stream_read_bytes (stream, 0x100000, NULL, error); if (bytes == NULL) return FALSE; } else if (data[0] == '<' && data[1] == '?') { g_debug ("using no decompressor for data"); bytes = g_bytes_ref (bytes_raw); } else { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "file type '0x%02x,0x%02x' not supported", data[0], data[1]); return FALSE; } /* read signature */ stream_sig = g_unix_input_stream_new (fd_sig, TRUE); bytes_sig = g_input_stream_read_bytes (stream_sig, 0x800, NULL, error); if (bytes_sig == NULL) return FALSE; /* verify file */ kr = fu_keyring_new (); if (!fu_keyring_add_public_keys (kr, "/etc/pki/fwupd-metadata", error)) return FALSE; if (!fu_keyring_verify_data (kr, bytes_raw, bytes_sig, error)) return FALSE; /* load the store locally until we know it is valid */ store = as_store_new (); data = g_bytes_get_data (bytes, &size); xml = g_strndup ((const gchar *) data, size); if (!as_store_from_xml (store, xml, NULL, error)) return FALSE; /* add the new application from the store */ as_store_remove_all (priv->store); apps = as_store_get_apps (store); for (i = 0; i < apps->len; i++) { AsApp *app = g_ptr_array_index (apps, i); as_store_add_app (priv->store, app); } /* save the new file */ as_store_set_api_version (priv->store, 0.9); file = g_file_new_for_path ("/var/cache/app-info/xmls/fwupd.xml"); if (!as_store_to_file (priv->store, file, AS_NODE_TO_XML_FLAG_ADD_HEADER | AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE | AS_NODE_TO_XML_FLAG_FORMAT_INDENT, NULL, error)) { return FALSE; } return TRUE; } /** * fu_main_store_delay_cb: **/ static gboolean fu_main_store_delay_cb (gpointer user_data) { AsApp *app; GPtrArray *apps; guint i; FuMainPrivate *priv = (FuMainPrivate *) user_data; apps = as_store_get_apps (priv->store); if (apps->len == 0) { g_debug ("no devices in store"); } else { g_debug ("devices now in store:"); for (i = 0; i < apps->len; i++) { app = g_ptr_array_index (apps, i); g_debug ("%i\t%s\t%s", i + 1, as_app_get_id (app), as_app_get_name (app, NULL)); } } priv->store_changed_id = 0; return G_SOURCE_REMOVE; } /** * fu_main_store_changed_cb: **/ static void fu_main_store_changed_cb (AsStore *store, FuMainPrivate *priv) { if (priv->store_changed_id != 0) return; priv->store_changed_id = g_timeout_add (200, fu_main_store_delay_cb, priv); } /** * fu_main_get_updates: **/ static GPtrArray * fu_main_get_updates (FuMainPrivate *priv, GError **error) { AsApp *app; AsRelease *rel; FuDeviceItem *item; GPtrArray *updates; guint i; const gchar *tmp; /* find any updates using the AppStream metadata */ updates = g_ptr_array_new (); for (i = 0; i < priv->devices->len; i++) { const gchar *version; AsChecksum *csum; item = g_ptr_array_index (priv->devices, i); /* get device version */ version = fu_device_get_version (item->device); if (version == NULL) continue; /* match the GUID in the XML */ app = as_store_get_app_by_provide (priv->store, AS_PROVIDE_KIND_FIRMWARE_FLASHED, fu_device_get_guid (item->device)); if (app == NULL) continue; /* possibly convert the version from 0x to dotted */ fu_main_vendor_quirk_release_version (app); /* get latest release */ rel = as_app_get_release_default (app); if (rel == NULL) { g_debug ("%s has no firmware update metadata", fu_device_get_id (item->device)); continue; } /* check if actually newer than what we have installed */ if (as_utils_vercmp (as_release_get_version (rel), version) <= 0) { g_debug ("%s has no firmware updates", fu_device_get_id (item->device)); continue; } /* can we only do this on AC power */ if (fu_device_has_flag (item->device, FU_DEVICE_FLAG_REQUIRE_AC) && fu_main_on_battery (priv)) { g_debug ("ignoring update for %s as not on AC power", fu_device_get_id (item->device)); continue; } /* add application metadata */ fu_device_set_update_id (item->device, as_app_get_id (app)); tmp = as_app_get_developer_name (app, NULL); if (tmp != NULL) fu_device_set_update_vendor (item->device, tmp); tmp = as_app_get_name (app, NULL); if (tmp != NULL) fu_device_set_update_name (item->device, tmp); tmp = as_app_get_comment (app, NULL); if (tmp != NULL) fu_device_set_update_summary (item->device, tmp); tmp = as_app_get_description (app, NULL); if (tmp != NULL) fu_device_set_description (item->device, tmp); tmp = as_app_get_url_item (app, AS_URL_KIND_HOMEPAGE); if (tmp != NULL) fu_device_set_update_homepage (item->device, tmp); tmp = as_app_get_project_license (app); if (tmp != NULL) fu_device_set_update_license (item->device, tmp); /* add release information */ tmp = as_release_get_version (rel); if (tmp != NULL) fu_device_set_update_version (item->device, tmp); csum = as_release_get_checksum_by_target (rel, AS_CHECKSUM_TARGET_CONTAINER); if (csum != NULL) { fu_device_set_update_checksum (item->device, as_checksum_get_value (csum)); } tmp = as_release_get_location_default (rel); if (tmp != NULL) fu_device_set_update_uri (item->device, tmp); tmp = as_release_get_description (rel, NULL); if (tmp != NULL) fu_device_set_update_description (item->device, tmp); g_ptr_array_add (updates, item); } return updates; } /** * fu_main_daemon_method_call: **/ static void fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data) { FuMainPrivate *priv = (FuMainPrivate *) user_data; GVariant *val; /* return 'as' */ if (g_strcmp0 (method_name, "GetDevices") == 0) { g_autoptr(GError) error = NULL; g_debug ("Called %s()", method_name); val = fu_main_device_array_to_variant (priv->devices, &error); if (val == NULL) { if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO)) { g_prefix_error (&error, "No detected devices: "); } g_dbus_method_invocation_return_gerror (invocation, error); return; } g_dbus_method_invocation_return_value (invocation, val); fu_main_set_status (priv, FWUPD_STATUS_IDLE); return; } /* return 'as' */ if (g_strcmp0 (method_name, "GetUpdates") == 0) { g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) updates = NULL; g_debug ("Called %s()", method_name); updates = fu_main_get_updates (priv, &error); if (updates == NULL) { g_dbus_method_invocation_return_gerror (invocation, error); return; } val = fu_main_device_array_to_variant (updates, &error); if (val == NULL) { if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO)) { g_prefix_error (&error, "No devices can be updated: "); } g_dbus_method_invocation_return_gerror (invocation, error); return; } g_dbus_method_invocation_return_value (invocation, val); fu_main_set_status (priv, FWUPD_STATUS_IDLE); return; } /* return '' */ if (g_strcmp0 (method_name, "ClearResults") == 0) { FuDeviceItem *item = NULL; const gchar *id = NULL; g_autoptr(GError) error = NULL; g_variant_get (parameters, "(&s)", &id); g_debug ("Called %s(%s)", method_name, id); /* find device */ item = fu_main_get_item_by_id_fallback_pending (priv, id, &error); if (item == NULL) { g_dbus_method_invocation_return_gerror (invocation, error); return; } /* call into the provider */ if (!fu_provider_clear_results (item->provider, item->device, &error)) { g_dbus_method_invocation_return_gerror (invocation, error); return; } /* success */ g_dbus_method_invocation_return_value (invocation, NULL); return; } /* return 'a{sv}' */ if (g_strcmp0 (method_name, "GetResults") == 0) { FuDeviceItem *item = NULL; const gchar *id = NULL; g_autoptr(GError) error = NULL; g_variant_get (parameters, "(&s)", &id); g_debug ("Called %s(%s)", method_name, id); /* find device */ item = fu_main_get_item_by_id_fallback_pending (priv, id, &error); if (item == NULL) { g_dbus_method_invocation_return_gerror (invocation, error); return; } /* call into the provider */ if (!fu_provider_get_results (item->provider, item->device, &error)) { g_dbus_method_invocation_return_gerror (invocation, error); return; } /* success */ val = fwupd_result_to_data (FWUPD_RESULT (item->device), "(a{sv})"); g_dbus_method_invocation_return_value (invocation, val); return; } /* return '' */ if (g_strcmp0 (method_name, "UpdateMetadata") == 0) { GDBusMessage *message; GUnixFDList *fd_list; gint fd_data; gint fd_sig; g_autoptr(GError) error = NULL; message = g_dbus_method_invocation_get_message (invocation); fd_list = g_dbus_message_get_unix_fd_list (message); if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 2) { g_dbus_method_invocation_return_error (invocation, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "invalid handle"); return; } fd_data = g_unix_fd_list_get (fd_list, 0, &error); if (fd_data < 0) { g_dbus_method_invocation_return_gerror (invocation, error); return; } fd_sig = g_unix_fd_list_get (fd_list, 1, &error); if (fd_sig < 0) { g_dbus_method_invocation_return_gerror (invocation, error); return; } if (!fu_main_daemon_update_metadata (priv, fd_data, fd_sig, &error)) { g_prefix_error (&error, "failed to update metadata: "); g_dbus_method_invocation_return_gerror (invocation, error); return; } g_dbus_method_invocation_return_value (invocation, NULL); return; } /* return 's' */ if (g_strcmp0 (method_name, "Unlock") == 0) { FuDeviceItem *item = NULL; FuMainAuthHelper *helper; const gchar *id = NULL; g_autoptr(PolkitSubject) subject = NULL; /* check the id exists */ g_variant_get (parameters, "(&s)", &id); g_debug ("Called %s(%s)", method_name, id); item = fu_main_get_item_by_id (priv, id); if (item == NULL) { g_dbus_method_invocation_return_error (invocation, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "No such device %s", id); return; } /* check the device is locked */ if (!fu_device_has_flag (item->device, FU_DEVICE_FLAG_LOCKED)) { g_dbus_method_invocation_return_error (invocation, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "Device %s is not locked", id); return; } /* process the firmware */ helper = g_new0 (FuMainAuthHelper, 1); helper->auth_kind = FU_MAIN_AUTH_KIND_UNLOCK; helper->invocation = g_object_ref (invocation); helper->device = g_object_ref (item->device); helper->priv = priv; /* authenticate */ subject = polkit_system_bus_name_new (sender); polkit_authority_check_authorization (helper->priv->authority, subject, "org.freedesktop.fwupd.device-unlock", NULL, POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, NULL, fu_main_check_authorization_cb, helper); return; } /* return 's' */ if (g_strcmp0 (method_name, "Verify") == 0) { AsApp *app; AsChecksum *csum; AsRelease *release; FuDeviceItem *item = NULL; const gchar *hash = NULL; const gchar *id = NULL; const gchar *version = NULL; g_autoptr(GError) error = NULL; /* check the id exists */ g_variant_get (parameters, "(&s)", &id); g_debug ("Called %s(%s)", method_name, id); item = fu_main_get_item_by_id (priv, id); if (item == NULL) { g_dbus_method_invocation_return_error (invocation, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "No such device %s", id); return; } /* set the device firmware hash */ if (!fu_provider_verify (item->provider, item->device, FU_PROVIDER_VERIFY_FLAG_NONE, &error)) { g_dbus_method_invocation_return_gerror (invocation, error); return; } /* find component in metadata */ app = as_store_get_app_by_provide (priv->store, AS_PROVIDE_KIND_FIRMWARE_FLASHED, fu_device_get_guid (item->device)); if (app == NULL) { g_dbus_method_invocation_return_error (invocation, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "No metadata"); return; } /* find version in metadata */ version = fu_device_get_version (item->device); release = as_app_get_release (app, version); if (release == NULL) { g_dbus_method_invocation_return_error (invocation, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "No version %s", version); return; } /* find checksum */ csum = as_release_get_checksum_by_target (release, AS_CHECKSUM_TARGET_CONTENT); if (csum == NULL) { g_dbus_method_invocation_return_error (invocation, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "No content checksum for %s", version); return; } hash = fu_device_get_checksum (item->device); if (g_strcmp0 (as_checksum_get_value (csum), hash) != 0) { g_dbus_method_invocation_return_error (invocation, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "For v%s expected %s, got %s", version, as_checksum_get_value (csum), hash); return; } g_dbus_method_invocation_return_value (invocation, NULL); return; } /* return '' */ if (g_strcmp0 (method_name, "Install") == 0) { FuDeviceItem *item = NULL; FuMainAuthHelper *helper; FwupdInstallFlags flags = FWUPD_INSTALL_FLAG_NONE; GDBusMessage *message; GUnixFDList *fd_list; GVariant *prop_value; const gchar *action_id; const gchar *id = NULL; gchar *prop_key; gint32 fd_handle = 0; gint fd; g_autoptr(GError) error = NULL; g_autoptr(PolkitSubject) subject = NULL; g_autoptr(GVariantIter) iter = NULL; g_autoptr(GBytes) blob_cab = NULL; g_autoptr(GInputStream) stream = NULL; /* check the id exists */ g_variant_get (parameters, "(&sha{sv})", &id, &fd_handle, &iter); g_debug ("Called %s(%s,%i)", method_name, id, fd_handle); if (g_strcmp0 (id, FWUPD_DEVICE_ID_ANY) != 0) { item = fu_main_get_item_by_id (priv, id); if (item == NULL) { g_dbus_method_invocation_return_error (invocation, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "no such device %s", id); return; } } /* get options */ while (g_variant_iter_next (iter, "{&sv}", &prop_key, &prop_value)) { g_debug ("got option %s", prop_key); if (g_strcmp0 (prop_key, "offline") == 0 && g_variant_get_boolean (prop_value) == TRUE) flags |= FWUPD_INSTALL_FLAG_OFFLINE; if (g_strcmp0 (prop_key, "allow-older") == 0 && g_variant_get_boolean (prop_value) == TRUE) flags |= FWUPD_INSTALL_FLAG_ALLOW_OLDER; if (g_strcmp0 (prop_key, "allow-reinstall") == 0 && g_variant_get_boolean (prop_value) == TRUE) flags |= FWUPD_INSTALL_FLAG_ALLOW_REINSTALL; g_variant_unref (prop_value); } /* get the fd */ message = g_dbus_method_invocation_get_message (invocation); fd_list = g_dbus_message_get_unix_fd_list (message); if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 1) { g_dbus_method_invocation_return_error (invocation, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "invalid handle"); return; } fd = g_unix_fd_list_get (fd_list, fd_handle, &error); if (fd < 0) { g_dbus_method_invocation_return_gerror (invocation, error); return; } /* read the entire fd to a data blob */ stream = g_unix_input_stream_new (fd, TRUE); blob_cab = g_input_stream_read_bytes (stream, FU_MAIN_FIRMWARE_SIZE_MAX, NULL, &error); if (blob_cab == NULL){ g_dbus_method_invocation_return_gerror (invocation, error); return; } /* process the firmware */ helper = g_new0 (FuMainAuthHelper, 1); helper->auth_kind = FU_MAIN_AUTH_KIND_INSTALL; helper->invocation = g_object_ref (invocation); helper->trust_flags = FWUPD_TRUST_FLAG_NONE; helper->blob_cab = g_bytes_ref (blob_cab); helper->flags = flags; helper->priv = priv; helper->store = as_store_new (); if (item != NULL) helper->device = g_object_ref (item->device); if (!fu_main_update_helper (helper, &error)) { g_dbus_method_invocation_return_gerror (helper->invocation, error); fu_main_set_status (priv, FWUPD_STATUS_IDLE); fu_main_helper_free (helper); return; } /* is root */ if (fu_main_dbus_get_uid (priv, sender) == 0) { if (!fu_main_provider_update_authenticated (helper, &error)) { g_dbus_method_invocation_return_gerror (invocation, error); } else { g_dbus_method_invocation_return_value (invocation, NULL); } fu_main_set_status (priv, FWUPD_STATUS_IDLE); fu_main_helper_free (helper); return; } /* authenticate */ action_id = fu_main_get_action_id_for_device (helper); subject = polkit_system_bus_name_new (sender); polkit_authority_check_authorization (helper->priv->authority, subject, action_id, NULL, POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, NULL, fu_main_check_authorization_cb, helper); return; } /* return 'a{sv}' */ if (g_strcmp0 (method_name, "GetDetails") == 0) { AsApp *app = NULL; AsRelease *rel; GDBusMessage *message; GPtrArray *apps; GPtrArray *provides; GUnixFDList *fd_list; GVariantBuilder builder; FuDeviceItem *item; FwupdDeviceFlags device_flags = 0; FwupdTrustFlags trust_flags = FWUPD_TRUST_FLAG_NONE; const gchar *tmp; const gchar *guid = NULL; gint32 fd_handle = 0; gint fd; guint i; g_autoptr(AsStore) store = NULL; g_autoptr(GBytes) blob_cab = NULL; g_autoptr(GError) error = NULL; g_autoptr(GInputStream) stream = NULL; /* check the id exists */ g_variant_get (parameters, "(h)", &fd_handle); g_debug ("Called %s(%i)", method_name, fd_handle); /* get the fd */ message = g_dbus_method_invocation_get_message (invocation); fd_list = g_dbus_message_get_unix_fd_list (message); if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 1) { g_dbus_method_invocation_return_error (invocation, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "invalid handle"); return; } fd = g_unix_fd_list_get (fd_list, fd_handle, &error); if (fd < 0) { g_dbus_method_invocation_return_gerror (invocation, error); return; } /* read the entire fd to a data blob */ stream = g_unix_input_stream_new (fd, TRUE); blob_cab = g_input_stream_read_bytes (stream, FU_MAIN_FIRMWARE_SIZE_MAX, NULL, &error); if (blob_cab == NULL){ g_dbus_method_invocation_return_gerror (invocation, error); return; } /* load file */ store = as_store_new (); if (!as_store_from_bytes (store, blob_cab, NULL, &error)) { g_dbus_method_invocation_return_gerror (invocation, error); return; } /* get default app */ apps = as_store_get_apps (store); if (apps->len == 0) { g_dbus_method_invocation_return_error (invocation, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "no components"); return; } if (apps->len > 1) { /* we've got a .cab file with multiple components, * so try to find the first thing that's installed */ for (i = 0; i < priv->devices->len; i++) { item = g_ptr_array_index (priv->devices, i); app = as_store_get_app_by_provide (store, AS_PROVIDE_KIND_FIRMWARE_FLASHED, fu_device_get_guid (item->device)); if (app != NULL) break; } } /* well, we've tried our best, just show the first entry */ if (app == NULL) app = AS_APP (g_ptr_array_index (apps, 0)); /* get guid */ provides = as_app_get_provides (app); for (i = 0; i < provides->len; i++) { AsProvide *prov = AS_PROVIDE (g_ptr_array_index (provides, i)); if (as_provide_get_kind (prov) == AS_PROVIDE_KIND_FIRMWARE_FLASHED) { guid = as_provide_get_value (prov); break; } } if (guid == NULL) { g_dbus_method_invocation_return_error (invocation, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "component has no GUID"); return; } /* verify trust */ rel = as_app_get_release_default (app); if (!fu_main_get_release_trust_flags (rel, &trust_flags, &error)) { g_dbus_method_invocation_return_gerror (invocation, error); return; } /* possibly convert the version from 0x to dotted */ fu_main_vendor_quirk_release_version (app); /* is a online or offline update appropriate */ item = fu_main_get_item_by_guid (priv, guid); if (item != NULL) device_flags = fu_device_get_flags (item->device); /* create an array with all the metadata in */ g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_VERSION, g_variant_new_string (as_release_get_version (rel))); g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_GUID, g_variant_new_string (guid)); g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_SIZE, g_variant_new_uint64 (as_release_get_size (rel, AS_SIZE_KIND_INSTALLED))); g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_DEVICE_FLAGS, g_variant_new_uint64 (device_flags)); /* optional properties */ tmp = as_app_get_developer_name (app, NULL); if (tmp != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_VENDOR, g_variant_new_string (tmp)); } tmp = as_app_get_name (app, NULL); if (tmp != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_NAME, g_variant_new_string (tmp)); } tmp = as_app_get_comment (app, NULL); if (tmp != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_SUMMARY, g_variant_new_string (tmp)); } tmp = as_app_get_description (app, NULL); if (tmp != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_DESCRIPTION, g_variant_new_string (tmp)); } tmp = as_app_get_url_item (app, AS_URL_KIND_HOMEPAGE); if (tmp != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_HOMEPAGE, g_variant_new_string (tmp)); } tmp = as_app_get_project_license (app); if (tmp != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_LICENSE, g_variant_new_string (tmp)); } tmp = as_release_get_description (rel, NULL); if (tmp != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_DESCRIPTION, g_variant_new_string (tmp)); } g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_TRUST_FLAGS, g_variant_new_uint64 (trust_flags)); /* return whole array */ val = g_variant_new ("(a{sv})", &builder); g_dbus_method_invocation_return_value (invocation, val); return; } /* we suck */ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, "no such method %s", method_name); } /** * fu_main_daemon_get_property: **/ static GVariant * fu_main_daemon_get_property (GDBusConnection *connection_, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *property_name, GError **error, gpointer user_data) { FuMainPrivate *priv = (FuMainPrivate *) user_data; if (g_strcmp0 (property_name, "DaemonVersion") == 0) return g_variant_new_string (VERSION); if (g_strcmp0 (property_name, "Status") == 0) return g_variant_new_string (fwupd_status_to_string (priv->status)); /* return an error */ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_PROPERTY, "failed to get daemon property %s", property_name); return NULL; } /** * fu_main_providers_coldplug: **/ static void fu_main_providers_coldplug (FuMainPrivate *priv) { FuProvider *provider; guint i; g_autoptr(AsProfileTask) ptask = NULL; ptask = as_profile_start_literal (priv->profile, "FuMain:coldplug"); for (i = 0; i < priv->providers->len; i++) { g_autoptr(GError) error = NULL; g_autoptr(AsProfileTask) ptask2 = NULL; provider = g_ptr_array_index (priv->providers, i); ptask2 = as_profile_start (priv->profile, "FuMain:coldplug{%s}", fu_provider_get_name (provider)); if (!fu_provider_coldplug (FU_PROVIDER (provider), &error)) g_warning ("Failed to coldplug: %s", error->message); } } /** * fu_main_on_bus_acquired_cb: **/ static void fu_main_on_bus_acquired_cb (GDBusConnection *connection, const gchar *name, gpointer user_data) { FuMainPrivate *priv = (FuMainPrivate *) user_data; guint registration_id; g_autoptr(GError) error = NULL; static const GDBusInterfaceVTable interface_vtable = { fu_main_daemon_method_call, fu_main_daemon_get_property, NULL }; priv->connection = g_object_ref (connection); registration_id = g_dbus_connection_register_object (connection, FWUPD_DBUS_PATH, priv->introspection_daemon->interfaces[0], &interface_vtable, priv, /* user_data */ NULL, /* user_data_free_func */ NULL); /* GError** */ g_assert (registration_id > 0); /* add devices */ fu_main_providers_coldplug (priv); /* connect to D-Bus directly */ priv->proxy_uid = g_dbus_proxy_new_sync (priv->connection, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, NULL, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", NULL, &error); if (priv->proxy_uid == NULL) { g_warning ("cannot connect to DBus: %s", error->message); return; } /* connect to UPower */ priv->proxy_upower = 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", "org.freedesktop.UPower", NULL, &error); if (priv->proxy_upower == NULL) { g_warning ("Failed to conect UPower: %s", error->message); return; } /* dump startup profile data */ if (fu_debug_is_verbose ()) as_profile_dump (priv->profile); } /** * fu_main_on_name_acquired_cb: **/ static void fu_main_on_name_acquired_cb (GDBusConnection *connection, const gchar *name, gpointer user_data) { g_debug ("FuMain: acquired name: %s", name); } /** * fu_main_on_name_lost_cb: **/ static void fu_main_on_name_lost_cb (GDBusConnection *connection, const gchar *name, gpointer user_data) { FuMainPrivate *priv = (FuMainPrivate *) user_data; g_debug ("FuMain: lost name: %s", name); g_main_loop_quit (priv->loop); } /** * fu_main_timed_exit_cb: **/ static gboolean fu_main_timed_exit_cb (gpointer user_data) { GMainLoop *loop = (GMainLoop *) user_data; g_main_loop_quit (loop); return G_SOURCE_REMOVE; } /** * fu_main_load_introspection: **/ static GDBusNodeInfo * fu_main_load_introspection (const gchar *filename, GError **error) { g_autoptr(GBytes) data = NULL; g_autofree gchar *path = NULL; /* lookup data */ path = g_build_filename ("/org/freedesktop/fwupd", filename, NULL); data = g_resource_lookup_data (fu_get_resource (), path, G_RESOURCE_LOOKUP_FLAGS_NONE, error); if (data == NULL) return NULL; /* build introspection from XML */ return g_dbus_node_info_new_for_xml (g_bytes_get_data (data, NULL), error); } /** * cd_main_provider_device_added_cb: **/ static void cd_main_provider_device_added_cb (FuProvider *provider, FuDevice *device, gpointer user_data) { FuMainPrivate *priv = (FuMainPrivate *) user_data; FuDeviceItem *item; AsApp *app; FuPlugin *plugin; g_autoptr(GError) error = NULL; /* remove any fake device */ item = fu_main_get_item_by_id (priv, fu_device_get_id (device)); if (item != NULL) { g_debug ("already added %s by %s, ignoring same device from %s", fu_device_get_id (item->device), fu_device_get_provider (item->device), fu_provider_get_name (provider)); return; } /* create new device */ item = g_new0 (FuDeviceItem, 1); item->device = g_object_ref (device); item->provider = g_object_ref (provider); g_ptr_array_add (priv->devices, item); /* does this match anything in the AppStream data */ app = as_store_get_app_by_provide (priv->store, AS_PROVIDE_KIND_FIRMWARE_FLASHED, fu_device_get_guid (item->device)); if (app != NULL) { const gchar *tmp; tmp = as_app_get_metadata_item (app, FU_DEVICE_KEY_FWUPD_PLUGIN); if (tmp != NULL) { g_debug ("setting plugin: %s", tmp); fu_device_set_metadata (item->device, FU_DEVICE_KEY_FWUPD_PLUGIN, tmp); } } /* run any plugins */ plugin = fu_main_get_plugin_for_device (priv->plugins, device); if (plugin != NULL) { if (!fu_plugin_run_device_probe (plugin, device, &error)) { g_warning ("failed to probe %s: %s", fu_device_get_id (item->device), error->message); } } fu_main_emit_changed (priv); } /** * cd_main_provider_device_removed_cb: **/ static void cd_main_provider_device_removed_cb (FuProvider *provider, FuDevice *device, gpointer user_data) { FuMainPrivate *priv = (FuMainPrivate *) user_data; FuDeviceItem *item; item = fu_main_get_item_by_id (priv, fu_device_get_id (device)); if (item == NULL) { g_debug ("no device to remove %s", fu_device_get_id (device)); return; } /* check this came from the same provider */ if (g_strcmp0 (fu_provider_get_name (provider), fu_provider_get_name (item->provider)) != 0) { g_debug ("ignoring duplicate removal from %s", fu_provider_get_name (provider)); return; } g_ptr_array_remove (priv->devices, item); fu_main_emit_changed (priv); } /** * cd_main_provider_status_changed_cb: **/ static void cd_main_provider_status_changed_cb (FuProvider *provider, FwupdStatus status, gpointer user_data) { FuMainPrivate *priv = (FuMainPrivate *) user_data; fu_main_set_status (priv, status); } /** * fu_main_add_provider: **/ static void fu_main_add_provider (FuMainPrivate *priv, FuProvider *provider) { g_signal_connect (provider, "device-added", G_CALLBACK (cd_main_provider_device_added_cb), priv); g_signal_connect (provider, "device-removed", G_CALLBACK (cd_main_provider_device_removed_cb), priv); g_signal_connect (provider, "status-changed", G_CALLBACK (cd_main_provider_status_changed_cb), priv); g_ptr_array_add (priv->providers, provider); } /** * main: **/ int main (int argc, char *argv[]) { FuMainPrivate *priv = NULL; gboolean immediate_exit = FALSE; gboolean ret; gboolean timed_exit = FALSE; GOptionContext *context; guint owner_id = 0; guint retval = 1; const GOptionEntry options[] = { { "timed-exit", '\0', 0, G_OPTION_ARG_NONE, &timed_exit, /* TRANSLATORS: exit after we've started up, used for user profiling */ _("Exit after a small delay"), NULL }, { "immediate-exit", '\0', 0, G_OPTION_ARG_NONE, &immediate_exit, /* TRANSLATORS: exit straight away, used for automatic profiling */ _("Exit after the engine has loaded"), NULL }, { NULL} }; g_autoptr(GError) error = NULL; g_autofree gchar *config_file = NULL; g_autoptr(GKeyFile) config = NULL; setlocale (LC_ALL, ""); bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); /* TRANSLATORS: program name */ g_set_application_name (_("Firmware Update Daemon")); context = g_option_context_new (NULL); g_option_context_add_main_entries (context, options, NULL); g_option_context_add_group (context, fu_debug_get_option_group ()); /* TRANSLATORS: program summary */ g_option_context_set_summary (context, _("Firmware Update D-Bus Service")); ret = g_option_context_parse (context, &argc, &argv, &error); if (!ret) { g_warning ("FuMain: failed to parse command line arguments: %s", error->message); goto out; } /* create new objects */ priv = g_new0 (FuMainPrivate, 1); priv->status = FWUPD_STATUS_IDLE; priv->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_main_item_free); priv->loop = g_main_loop_new (NULL, FALSE); priv->pending = fu_pending_new (); priv->store = as_store_new (); priv->profile = as_profile_new (); g_signal_connect (priv->store, "changed", G_CALLBACK (fu_main_store_changed_cb), priv); as_store_set_watch_flags (priv->store, AS_STORE_WATCH_FLAG_ADDED | AS_STORE_WATCH_FLAG_REMOVED); /* load plugin */ priv->plugins = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) fu_plugin_free); if (!fu_main_load_plugins (priv->plugins, &error)) { g_print ("failed to load plugins: %s\n", error->message); retval = EXIT_FAILURE; goto out; } /* load AppStream */ as_store_add_filter (priv->store, AS_APP_KIND_FIRMWARE); if (!as_store_load (priv->store, AS_STORE_LOAD_FLAG_APP_INFO_SYSTEM, NULL, &error)){ g_warning ("FuMain: failed to load AppStream data: %s", error->message); return FALSE; } /* read config file */ config = g_key_file_new (); config_file = g_build_filename (SYSCONFDIR, "fwupd.conf", NULL); g_debug ("Loading fallback values from %s", config_file); if (!g_key_file_load_from_file (config, config_file, G_KEY_FILE_NONE, &error)) { g_print ("failed to load config file %s: %s\n", config_file, error->message); retval = EXIT_FAILURE; goto out; } /* add providers */ priv->providers = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); if (g_key_file_get_boolean (config, "fwupd", "EnableOptionROM", NULL)) fu_main_add_provider (priv, fu_provider_udev_new ()); fu_main_add_provider (priv, fu_provider_dfu_new ()); fu_main_add_provider (priv, fu_provider_rpi_new ()); #ifdef HAVE_COLORHUG fu_main_add_provider (priv, fu_provider_chug_new ()); #endif #ifdef HAVE_UEFI fu_main_add_provider (priv, fu_provider_uefi_new ()); #endif /* last as least priority */ fu_main_add_provider (priv, fu_provider_usb_new ()); /* load introspection from file */ priv->introspection_daemon = fu_main_load_introspection (FWUPD_DBUS_INTERFACE ".xml", &error); if (priv->introspection_daemon == NULL) { g_warning ("FuMain: failed to load daemon introspection: %s", error->message); goto out; } /* get authority */ priv->authority = polkit_authority_get_sync (NULL, &error); if (priv->authority == NULL) { g_warning ("FuMain: failed to load polkit authority: %s", error->message); goto out; } /* own the object */ owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM, FWUPD_DBUS_SERVICE, G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | G_BUS_NAME_OWNER_FLAGS_REPLACE, fu_main_on_bus_acquired_cb, fu_main_on_name_acquired_cb, fu_main_on_name_lost_cb, priv, NULL); /* Only timeout and close the mainloop if we have specified it * on the command line */ if (immediate_exit) g_idle_add (fu_main_timed_exit_cb, priv->loop); else if (timed_exit) g_timeout_add_seconds (5, fu_main_timed_exit_cb, priv->loop); /* wait */ g_info ("Daemon ready for requests"); g_main_loop_run (priv->loop); /* success */ retval = 0; out: g_option_context_free (context); if (owner_id > 0) g_bus_unown_name (owner_id); if (priv != NULL) { if (priv->loop != NULL) g_main_loop_unref (priv->loop); if (priv->proxy_uid != NULL) g_object_unref (priv->proxy_uid); if (priv->proxy_upower != NULL) g_object_unref (priv->proxy_upower); if (priv->connection != NULL) g_object_unref (priv->connection); if (priv->authority != NULL) g_object_unref (priv->authority); if (priv->profile != NULL) g_object_unref (priv->profile); if (priv->store != NULL) g_object_unref (priv->store); if (priv->introspection_daemon != NULL) g_dbus_node_info_unref (priv->introspection_daemon); if (priv->store_changed_id != 0) g_source_remove (priv->store_changed_id); g_object_unref (priv->pending); if (priv->providers != NULL) g_ptr_array_unref (priv->providers); if (priv->plugins != NULL) g_hash_table_unref (priv->plugins); g_ptr_array_unref (priv->devices); g_free (priv); } return retval; } fwupd-0.7.0/src/fu-pending.c000066400000000000000000000324101267747510300156460ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include "fu-pending.h" static void fu_pending_finalize (GObject *object); /** * FuPendingPrivate: * * Private #FuPending data **/ typedef struct { sqlite3 *db; } FuPendingPrivate; G_DEFINE_TYPE_WITH_PRIVATE (FuPending, fu_pending, G_TYPE_OBJECT) #define GET_PRIVATE(o) (fu_pending_get_instance_private (o)) /** * fu_pending_load: **/ static gboolean fu_pending_load (FuPending *pending, GError **error) { FuPendingPrivate *priv = GET_PRIVATE (pending); char *error_msg = NULL; const char *statement; gint rc; g_autofree gchar *dirname = NULL; g_autofree gchar *filename = NULL; g_autoptr(GFile) file = NULL; g_return_val_if_fail (FU_IS_PENDING (pending), FALSE); g_return_val_if_fail (priv->db == NULL, FALSE); /* create directory */ dirname = g_build_filename (LOCALSTATEDIR, "lib", "fwupd", NULL); file = g_file_new_for_path (dirname); if (!g_file_query_exists (file, NULL)) { if (!g_file_make_directory_with_parents (file, NULL, error)) return FALSE; } /* open */ filename = g_build_filename (dirname, "pending.db", NULL); g_debug ("FuPending: trying to open database '%s'", filename); rc = sqlite3_open (filename, &priv->db); if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_READ, "Can't open %s: %s", filename, sqlite3_errmsg (priv->db)); sqlite3_close (priv->db); return FALSE; } /* check devices */ rc = sqlite3_exec (priv->db, "SELECT * FROM pending LIMIT 1", NULL, NULL, &error_msg); if (rc != SQLITE_OK) { g_debug ("FuPending: creating table to repair: %s", error_msg); sqlite3_free (error_msg); statement = "CREATE TABLE pending (" "device_id TEXT PRIMARY KEY," "state INTEGER DEFAULT 0," "timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL," "error TEXT," "filename TEXT," "display_name TEXT," "provider TEXT," "version_old TEXT," "version_new TEXT);"; rc = sqlite3_exec (priv->db, statement, NULL, NULL, &error_msg); if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, "Cannot create database: %s", error_msg); sqlite3_free (error_msg); return FALSE; } } /* check pending has state and provider (since 0.1.1) */ rc = sqlite3_exec (priv->db, "SELECT provider FROM pending LIMIT 1", NULL, NULL, &error_msg); if (rc != SQLITE_OK) { g_debug ("FuPending: altering table to repair: %s", error_msg); sqlite3_free (error_msg); statement = "ALTER TABLE pending ADD COLUMN state INTEGER DEFAULT 0;"; sqlite3_exec (priv->db, statement, NULL, NULL, NULL); statement = "ALTER TABLE pending ADD COLUMN error TEXT;"; sqlite3_exec (priv->db, statement, NULL, NULL, NULL); statement = "ALTER TABLE pending ADD COLUMN provider TEXT;"; sqlite3_exec (priv->db, statement, NULL, NULL, NULL); } /* check pending has timestamp (since 0.6.2) */ rc = sqlite3_exec (priv->db, "SELECT timestamp FROM pending LIMIT 1", NULL, NULL, &error_msg); if (rc != SQLITE_OK) { g_debug ("FuPending: altering table to repair: %s", error_msg); sqlite3_free (error_msg); statement = "ALTER TABLE pending ADD COLUMN timestamp TIMESTAMP " "DEFAULT CURRENT_TIMESTAMP NOT NULL0;"; sqlite3_exec (priv->db, statement, NULL, NULL, NULL); } return TRUE; } /** * fu_pending_add_device: **/ gboolean fu_pending_add_device (FuPending *pending, FwupdResult *res, GError **error) { FuPendingPrivate *priv = GET_PRIVATE (pending); char *error_msg = NULL; char *statement; gboolean ret = TRUE; gint rc; g_return_val_if_fail (FU_IS_PENDING (pending), FALSE); /* lazy load */ if (priv->db == NULL) { if (!fu_pending_load (pending, error)) return FALSE; } g_debug ("FuPending: add device %s", fwupd_result_get_device_id (res)); statement = sqlite3_mprintf ("INSERT INTO pending (device_id," "state," "filename," "display_name," "provider," "version_old," "version_new) " "VALUES ('%q','%i','%q','%q','%q','%q','%q')", fwupd_result_get_device_id (res), FWUPD_UPDATE_STATE_PENDING, fwupd_result_get_update_filename (res), fwupd_result_get_device_name (res), fwupd_result_get_device_provider (res), fwupd_result_get_device_version (res), fwupd_result_get_update_version (res)); /* insert entry */ rc = sqlite3_exec (priv->db, statement, NULL, NULL, &error_msg); if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, "SQL error: %s", error_msg); sqlite3_free (error_msg); ret = FALSE; goto out; } out: sqlite3_free (statement); return ret; } /** * fu_pending_remove_device: **/ gboolean fu_pending_remove_device (FuPending *pending, FwupdResult *res, GError **error) { FuPendingPrivate *priv = GET_PRIVATE (pending); char *error_msg = NULL; char *statement; gboolean ret = TRUE; gint rc; g_return_val_if_fail (FU_IS_PENDING (pending), FALSE); /* lazy load */ if (priv->db == NULL) { if (!fu_pending_load (pending, error)) return FALSE; } g_debug ("FuPending: remove device %s", fwupd_result_get_device_id (res)); statement = sqlite3_mprintf ("DELETE FROM pending WHERE " "device_id = '%q';", fwupd_result_get_device_id (res)); /* remove entry */ rc = sqlite3_exec (priv->db, statement, NULL, NULL, &error_msg); if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, "SQL error: %s", error_msg); sqlite3_free (error_msg); ret = FALSE; goto out; } out: sqlite3_free (statement); return ret; } /** * fu_pending_device_sqlite_cb: **/ static gint fu_pending_device_sqlite_cb (void *data, gint argc, gchar **argv, gchar **col_name) { GPtrArray *array = (GPtrArray *) data; FwupdResult *res; gint i; /* create new result */ res = fwupd_result_new (); g_ptr_array_add (array, res); g_debug ("FuPending: got sql result %s", argv[0]); for (i = 0; i < argc; i++) { if (g_strcmp0 (col_name[i], "device_id") == 0) { fwupd_result_set_device_id (res, argv[i]); continue; } if (g_strcmp0 (col_name[i], "filename") == 0) { fwupd_result_set_update_filename (res, argv[i]); continue; } if (g_strcmp0 (col_name[i], "display_name") == 0) { fwupd_result_set_device_name (res, argv[i]); continue; } if (g_strcmp0 (col_name[i], "version_old") == 0) { fwupd_result_set_device_version (res, argv[i]); continue; } if (g_strcmp0 (col_name[i], "version_new") == 0) { fwupd_result_set_update_version (res, argv[i]); continue; } if (g_strcmp0 (col_name[i], "provider") == 0) { fwupd_result_set_device_provider (res, argv[i]); continue; } if (g_strcmp0 (col_name[i], "state") == 0) { FwupdUpdateState state = atoi (argv[i]); fwupd_result_set_update_state (res, state); continue; } if (g_strcmp0 (col_name[i], "timestamp") == 0) { guint64 timestamp = g_ascii_strtoull (argv[i], NULL, 10); if (timestamp > 0) fwupd_result_set_device_created (res, timestamp); continue; } if (g_strcmp0 (col_name[i], "error") == 0) { if (argv[i] != NULL) fwupd_result_set_update_error (res, argv[i]); continue; } g_warning ("unhandled %s=%s", col_name[i], argv[i]); } return 0; } /** * fu_pending_get_device: **/ FwupdResult * fu_pending_get_device (FuPending *pending, const gchar *device_id, GError **error) { FuPendingPrivate *priv = GET_PRIVATE (pending); FwupdResult *res = NULL; char *error_msg = NULL; char *statement; gint rc; g_autoptr(GPtrArray) array_tmp = NULL; g_return_val_if_fail (FU_IS_PENDING (pending), NULL); /* lazy load */ if (priv->db == NULL) { if (!fu_pending_load (pending, error)) return NULL; } /* get all the devices */ g_debug ("FuPending: get res"); statement = sqlite3_mprintf ("SELECT * FROM pending WHERE " "device_id = '%q';", device_id); array_tmp = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); rc = sqlite3_exec (priv->db, statement, fu_pending_device_sqlite_cb, array_tmp, &error_msg); if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_READ, "SQL error: %s", error_msg); sqlite3_free (error_msg); goto out; } if (array_tmp->len == 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "No devices found"); goto out; } res = g_object_ref (g_ptr_array_index (array_tmp, 0)); out: sqlite3_free (statement); return res; } /** * fu_pending_get_devices: **/ GPtrArray * fu_pending_get_devices (FuPending *pending, GError **error) { FuPendingPrivate *priv = GET_PRIVATE (pending); GPtrArray *array = NULL; char *error_msg = NULL; char *statement; gint rc; g_autoptr(GPtrArray) array_tmp = NULL; g_return_val_if_fail (FU_IS_PENDING (pending), NULL); /* lazy load */ if (priv->db == NULL) { if (!fu_pending_load (pending, error)) return NULL; } /* get all the devices */ g_debug ("FuPending: get devices"); statement = sqlite3_mprintf ("SELECT * FROM pending;"); array_tmp = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); rc = sqlite3_exec (priv->db, statement, fu_pending_device_sqlite_cb, array_tmp, &error_msg); if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_READ, "SQL error: %s", error_msg); sqlite3_free (error_msg); goto out; } /* success */ array = g_ptr_array_ref (array_tmp); out: sqlite3_free (statement); return array; } /** * fu_pending_set_state: **/ gboolean fu_pending_set_state (FuPending *pending, FwupdResult *res, FwupdUpdateState state, GError **error) { FuPendingPrivate *priv = GET_PRIVATE (pending); char *error_msg = NULL; char *statement; gboolean ret = TRUE; gint rc; g_return_val_if_fail (FU_IS_PENDING (pending), FALSE); /* lazy load */ if (priv->db == NULL) { if (!fu_pending_load (pending, error)) return FALSE; } g_debug ("FuPending: set state of %s to %s", fwupd_result_get_device_id (res), fwupd_update_state_to_string (state)); statement = sqlite3_mprintf ("UPDATE pending SET state='%i' WHERE " "device_id = '%q';", state, fwupd_result_get_device_id (res)); /* remove entry */ rc = sqlite3_exec (priv->db, statement, NULL, NULL, &error_msg); if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, "SQL error: %s", error_msg); sqlite3_free (error_msg); ret = FALSE; goto out; } out: sqlite3_free (statement); return ret; } /** * fu_pending_set_error_msg: **/ gboolean fu_pending_set_error_msg (FuPending *pending, FwupdResult *res, const gchar *error_msg2, GError **error) { FuPendingPrivate *priv = GET_PRIVATE (pending); char *error_msg = NULL; char *statement; gboolean ret = TRUE; gint rc; g_return_val_if_fail (FU_IS_PENDING (pending), FALSE); /* lazy load */ if (priv->db == NULL) { if (!fu_pending_load (pending, error)) return FALSE; } g_debug ("FuPending: add comment to %s: %s", fwupd_result_get_device_id (res), error_msg2); statement = sqlite3_mprintf ("UPDATE pending SET error='%q' WHERE " "device_id = '%q';", error_msg2, fwupd_result_get_device_id (res)); /* remove entry */ rc = sqlite3_exec (priv->db, statement, NULL, NULL, &error_msg); if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, "SQL error: %s", error_msg); sqlite3_free (error_msg); ret = FALSE; goto out; } out: sqlite3_free (statement); return ret; } /** * fu_pending_class_init: **/ static void fu_pending_class_init (FuPendingClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = fu_pending_finalize; } /** * fu_pending_init: **/ static void fu_pending_init (FuPending *pending) { } /** * fu_pending_finalize: **/ static void fu_pending_finalize (GObject *object) { FuPending *pending = FU_PENDING (object); FuPendingPrivate *priv = GET_PRIVATE (pending); if (priv->db != NULL) sqlite3_close (priv->db); G_OBJECT_CLASS (fu_pending_parent_class)->finalize (object); } /** * fu_pending_new: **/ FuPending * fu_pending_new (void) { FuPending *pending; pending = g_object_new (FU_TYPE_PENDING, NULL); return FU_PENDING (pending); } fwupd-0.7.0/src/fu-pending.h000066400000000000000000000037061267747510300156610ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __FU_PENDING_H #define __FU_PENDING_H #include #include "fu-device.h" G_BEGIN_DECLS #define FU_TYPE_PENDING (fu_pending_get_type ()) G_DECLARE_DERIVABLE_TYPE (FuPending, fu_pending, FU, PENDING, GObject) struct _FuPendingClass { GObjectClass parent_class; }; FuPending *fu_pending_new (void); gboolean fu_pending_add_device (FuPending *pending, FwupdResult *res, GError **error); gboolean fu_pending_set_state (FuPending *pending, FwupdResult *res, FwupdUpdateState state, GError **error); gboolean fu_pending_set_error_msg (FuPending *pending, FwupdResult *res, const gchar *error_msg, GError **error); gboolean fu_pending_remove_device (FuPending *pending, FwupdResult *res, GError **error); FwupdResult *fu_pending_get_device (FuPending *pending, const gchar *device_id, GError **error); GPtrArray *fu_pending_get_devices (FuPending *pending, GError **error); G_END_DECLS #endif /* __FU_PENDING_H */ fwupd-0.7.0/src/fu-plugin.c000066400000000000000000000072561267747510300155320ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2016 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include "fu-device.h" #include "fu-plugin.h" /** * fu_plugin_new: **/ FuPlugin * fu_plugin_new (GModule *module) { FuPlugin *plugin; FuPluginInitFunc func; FuPluginGetNameFunc plugin_name = NULL; gboolean ret; /* get description */ ret = g_module_symbol (module, "fu_plugin_get_name", (gpointer *) &plugin_name); if (!ret) return NULL; /* add to registered plugins */ plugin = g_new0 (FuPlugin, 1); plugin->enabled = TRUE; plugin->module = module; plugin->name = g_strdup (plugin_name ()); /* optional */ if (g_module_symbol (plugin->module, "fu_plugin_init", (gpointer *) &func)) { g_debug ("performing init() on %s", plugin->name); func (plugin); } return plugin; } /** * fu_plugin_free: **/ void fu_plugin_free (FuPlugin *plugin) { FuPluginInitFunc func; /* optional */ if (g_module_symbol (plugin->module, "fu_plugin_destroy", (gpointer *) &func)) { g_debug ("performing destroy() on %s", plugin->name); func (plugin); } /* deallocate */ g_module_close (plugin->module); g_free (plugin->name); g_free (plugin->priv); g_free (plugin); } /** * fu_plugin_run_startup: **/ gboolean fu_plugin_run_startup (FuPlugin *plugin, GError **error) { FuPluginStartupFunc func; /* not enabled */ if (!plugin->enabled) return TRUE; /* optional */ if (!g_module_symbol (plugin->module, "fu_plugin_startup", (gpointer *) &func)) return TRUE; g_debug ("performing startup() on %s", plugin->name); if (!func (plugin, error)) { g_prefix_error (error, "failed to startup %s: ", plugin->name); return FALSE; } return TRUE; } /** * fu_plugin_run_device_probe: **/ gboolean fu_plugin_run_device_probe (FuPlugin *plugin, FuDevice *device, GError **error) { FuPluginDeviceProbeFunc func; /* not enabled */ if (!plugin->enabled) return TRUE; /* optional */ if (!g_module_symbol (plugin->module, "fu_plugin_device_probe", (gpointer *) &func)) return TRUE; g_debug ("performing device_probe() on %s", plugin->name); if (!func (plugin, device, error)) { g_prefix_error (error, "failed to device_probe %s: ", plugin->name); return FALSE; } return TRUE; } /** * fu_plugin_run_device_update: **/ gboolean fu_plugin_run_device_update (FuPlugin *plugin, FuDevice *device, GBytes *data, GError **error) { FuPluginDeviceUpdateFunc func; /* not enabled */ if (!plugin->enabled) return TRUE; /* optional */ if (!g_module_symbol (plugin->module, "fu_plugin_device_update", (gpointer *) &func)) return TRUE; /* does a vendor plugin exist */ g_debug ("performing device_update() on %s", plugin->name); if (!func (plugin, device, data, error)) { g_prefix_error (error, "failed to device_update %s: ", plugin->name); return FALSE; } return TRUE; } fwupd-0.7.0/src/fu-plugin.h000066400000000000000000000053141267747510300155300ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2016 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __FU_PLUGIN_H #define __FU_PLUGIN_H #include #include #include "fu-device.h" G_BEGIN_DECLS typedef struct FuPluginPrivate FuPluginPrivate; typedef struct FuPlugin FuPlugin; struct FuPlugin { GModule *module; gboolean enabled; gchar *name; FuPluginPrivate *priv; }; #define FU_PLUGIN_GET_PRIVATE(x) g_new0 (x,1) #define FU_PLUGIN(x) ((FuPlugin *) x); typedef const gchar *(*FuPluginGetNameFunc) (void); typedef void (*FuPluginInitFunc) (FuPlugin *plugin); typedef gboolean (*FuPluginStartupFunc) (FuPlugin *plugin, GError **error); typedef gboolean (*FuPluginDeviceProbeFunc) (FuPlugin *plugin, FuDevice *device, GError **error); typedef gboolean (*FuPluginDeviceUpdateFunc) (FuPlugin *plugin, FuDevice *device, GBytes *data, GError **error); /* these are implemented by the plugin */ const gchar *fu_plugin_get_name (void); void fu_plugin_init (FuPlugin *plugin); void fu_plugin_destroy (FuPlugin *plugin); gboolean fu_plugin_startup (FuPlugin *plugin, GError **error); gboolean fu_plugin_device_probe (FuPlugin *plugin, FuDevice *device, GError **error); gboolean fu_plugin_device_update (FuPlugin *plugin, FuDevice *device, GBytes *data, GError **error); /* these are called from the daemon */ FuPlugin *fu_plugin_new (GModule *module); void fu_plugin_free (FuPlugin *plugin); gboolean fu_plugin_run_startup (FuPlugin *plugin, GError **error); gboolean fu_plugin_run_device_probe (FuPlugin *plugin, FuDevice *device, GError **error); gboolean fu_plugin_run_device_update (FuPlugin *plugin, FuDevice *device, GBytes *data, GError **error); G_END_DECLS #endif /* __FU_PLUGIN_H */ fwupd-0.7.0/src/fu-provider-chug.c000066400000000000000000000440731267747510300170100ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include #include #include "fu-device.h" #include "fu-provider-chug.h" static void fu_provider_chug_finalize (GObject *object); #define FU_PROVIDER_CHUG_POLL_REOPEN 5 /* seconds */ #define FU_PROVIDER_CHUG_FIRMWARE_MAX (64 * 1024) /* bytes */ /** * FuProviderChugPrivate: **/ typedef struct { GHashTable *devices; /* DeviceKey:FuProviderChugItem */ GUsbContext *usb_ctx; ChDeviceQueue *device_queue; } FuProviderChugPrivate; typedef struct { FuDevice *device; FuProviderChug *provider_chug; GUsbDevice *usb_device; gboolean got_version; gboolean is_bootloader; guint timeout_open_id; GBytes *fw_bin; } FuProviderChugItem; G_DEFINE_TYPE_WITH_PRIVATE (FuProviderChug, fu_provider_chug, FU_TYPE_PROVIDER) #define GET_PRIVATE(o) (fu_provider_chug_get_instance_private (o)) /** * fu_provider_chug_get_name: **/ static const gchar * fu_provider_chug_get_name (FuProvider *provider) { return "ColorHug"; } /** * fu_provider_chug_get_device_key: **/ static gchar * fu_provider_chug_get_device_key (GUsbDevice *device) { return g_strdup_printf ("%s_%s", g_usb_device_get_platform_id (device), ch_device_get_guid (device)); } /** * fu_provider_chug_device_free: **/ static void fu_provider_chug_device_free (FuProviderChugItem *item) { g_object_unref (item->device); g_object_unref (item->provider_chug); g_object_unref (item->usb_device); if (item->fw_bin != NULL) g_bytes_unref (item->fw_bin); if (item->timeout_open_id != 0) g_source_remove (item->timeout_open_id); } /** * fu_provider_chug_wait_for_connect: **/ static gboolean fu_provider_chug_wait_for_connect (FuProviderChug *provider_chug, FuProviderChugItem *item, GError **error) { FuProviderChugPrivate *priv = GET_PRIVATE (item->provider_chug); g_autoptr(GUsbDevice) device = NULL; device = g_usb_context_wait_for_replug (priv->usb_ctx, item->usb_device, CH_DEVICE_USB_TIMEOUT, error); if (device == NULL) return FALSE; /* update item */ g_set_object (&item->usb_device, device); return TRUE; } /** * fu_provider_chug_open: **/ static gboolean fu_provider_chug_open (FuProviderChugItem *item, GError **error) { g_autoptr(GError) error_local = NULL; if (!ch_device_open (item->usb_device, &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_READ, "failed to open %s device: %s", fu_device_get_id (item->device), error_local->message); return FALSE; } return TRUE; } /** * fu_provider_chug_get_firmware_version: **/ static void fu_provider_chug_get_firmware_version (FuProviderChugItem *item) { FuProviderChugPrivate *priv = GET_PRIVATE (item->provider_chug); guint16 major; guint16 micro; guint16 minor; guint8 idx; g_autoptr(GError) error = NULL; g_autofree gchar *version = NULL; /* try to get the version without claiming interface */ if (!g_usb_device_open (item->usb_device, &error)) { g_debug ("Failed to open, polling: %s", error->message); return; } idx = g_usb_device_get_custom_index (item->usb_device, G_USB_DEVICE_CLASS_VENDOR_SPECIFIC, 'F', 'W', NULL); if (idx != 0x00) { g_autofree gchar *tmp = NULL; tmp = g_usb_device_get_string_descriptor (item->usb_device, idx, NULL); if (tmp != NULL) { item->got_version = TRUE; g_debug ("obtained fwver using extension '%s'", tmp); fu_device_set_version (item->device, tmp); goto out; } } g_usb_device_close (item->usb_device, NULL); /* attempt to open the device and get the serial number */ if (!ch_device_open (item->usb_device, &error)) { g_debug ("Failed to claim interface, polling: %s", error->message); return; } ch_device_queue_get_firmware_ver (priv->device_queue, item->usb_device, &major, &minor, µ); if (!ch_device_queue_process (priv->device_queue, CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE, NULL, &error)) { g_warning ("Failed to get serial: %s", error->message); goto out; } /* got things the old fashioned way */ item->got_version = TRUE; version = g_strdup_printf ("%i.%i.%i", major, minor, micro); g_debug ("obtained fwver using API '%s'", version); fu_device_set_version (item->device, version); out: /* we're done here */ g_clear_error (&error); if (!g_usb_device_close (item->usb_device, &error)) g_debug ("Failed to close: %s", error->message); } /** * fu_provider_chug_verify: **/ static gboolean fu_provider_chug_verify (FuProvider *provider, FuDevice *device, FuProviderVerifyFlags flags, GError **error) { FuProviderChug *provider_chug = FU_PROVIDER_CHUG (provider); FuProviderChugPrivate *priv = GET_PRIVATE (provider_chug); FuProviderChugItem *item; GChecksumType checksum_type; gsize len; g_autoptr(GError) error_local = NULL; g_autofree gchar *hash = NULL; g_autofree guint8 *data = NULL; /* find item */ item = g_hash_table_lookup (priv->devices, fu_device_get_id (device)); if (item == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "cannot find: %s", fu_device_get_id (device)); return FALSE; } /* open */ if (!fu_provider_chug_open (item, error)) return FALSE; /* get the firmware from the device */ g_debug ("ColorHug: Verifying firmware"); ch_device_queue_read_firmware (priv->device_queue, item->usb_device, &data, &len); fu_provider_set_status (provider, FWUPD_STATUS_DEVICE_VERIFY); if (!ch_device_queue_process (priv->device_queue, CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE, NULL, &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, "failed to dump firmware: %s", error_local->message); g_usb_device_close (item->usb_device, NULL); return FALSE; } /* get the checksum */ checksum_type = fu_provider_get_checksum_type (flags); hash = g_compute_checksum_for_data (checksum_type, (guchar *) data, len); fu_device_set_checksum (device, hash); fu_device_set_checksum_kind (device, checksum_type); /* we're done here */ if (!g_usb_device_close (item->usb_device, &error_local)) g_debug ("Failed to close: %s", error_local->message); return TRUE; } /** * fu_provider_chug_update: **/ static gboolean fu_provider_chug_update (FuProvider *provider, FuDevice *device, GBytes *blob_fw, FwupdInstallFlags flags, GError **error) { FuProviderChug *provider_chug = FU_PROVIDER_CHUG (provider); FuProviderChugPrivate *priv = GET_PRIVATE (provider_chug); FuProviderChugItem *item; g_autoptr(GError) error_local = NULL; /* find item */ item = g_hash_table_lookup (priv->devices, fu_device_get_id (device)); if (item == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "cannot find: %s", fu_device_get_id (device)); return FALSE; } /* this file is so small, just slurp it all in one go */ item->fw_bin = g_bytes_ref (blob_fw); /* check this firmware is actually for this device */ if (!ch_device_check_firmware (item->usb_device, g_bytes_get_data (item->fw_bin, NULL), g_bytes_get_size (item->fw_bin), &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "firmware is not suitable: %s", error_local->message); return FALSE; } /* switch to bootloader mode */ if (!item->is_bootloader) { g_debug ("ColorHug: Switching to bootloader mode"); if (!fu_provider_chug_open (item, error)) return FALSE; ch_device_queue_reset (priv->device_queue, item->usb_device); fu_provider_set_status (provider, FWUPD_STATUS_DEVICE_RESTART); if (!ch_device_queue_process (priv->device_queue, CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE, NULL, &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, "failed to reset device: %s", error_local->message); g_usb_device_close (item->usb_device, NULL); return FALSE; } /* this device has just gone away, no error possible */ g_usb_device_close (item->usb_device, NULL); /* wait for reconnection */ g_debug ("ColorHug: Waiting for bootloader"); if (!fu_provider_chug_wait_for_connect (provider_chug, item, error)) return FALSE; } /* open the device, which is now in bootloader mode */ if (!fu_provider_chug_open (item, error)) return FALSE; /* write firmware */ g_debug ("ColorHug: Writing firmware"); ch_device_queue_write_firmware (priv->device_queue, item->usb_device, g_bytes_get_data (item->fw_bin, NULL), g_bytes_get_size (item->fw_bin)); fu_provider_set_status (provider, FWUPD_STATUS_DEVICE_WRITE); if (!ch_device_queue_process (priv->device_queue, CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE, NULL, &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, "failed to write firmware: %s", error_local->message); g_usb_device_close (item->usb_device, NULL); return FALSE; } /* verify firmware */ g_debug ("ColorHug: Veifying firmware"); ch_device_queue_verify_firmware (priv->device_queue, item->usb_device, g_bytes_get_data (item->fw_bin, NULL), g_bytes_get_size (item->fw_bin)); fu_provider_set_status (provider, FWUPD_STATUS_DEVICE_VERIFY); if (!ch_device_queue_process (priv->device_queue, CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE, NULL, &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, "failed to verify firmware: %s", error_local->message); g_usb_device_close (item->usb_device, NULL); return FALSE; } /* boot into the new firmware */ g_debug ("ColorHug: Booting new firmware"); ch_device_queue_boot_flash (priv->device_queue, item->usb_device); fu_provider_set_status (provider, FWUPD_STATUS_DEVICE_RESTART); if (!ch_device_queue_process (priv->device_queue, CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE, NULL, &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, "failed to boot flash: %s", error_local->message); g_usb_device_close (item->usb_device, NULL); return FALSE; } /* this device has just gone away, no error possible */ g_usb_device_close (item->usb_device, NULL); /* wait for firmware mode */ if (!fu_provider_chug_wait_for_connect (provider_chug, item, error)) return FALSE; if (!fu_provider_chug_open (item, error)) return FALSE; /* set flash success */ g_debug ("ColorHug: Setting flash success"); ch_device_queue_set_flash_success (priv->device_queue, item->usb_device, 1); if (!ch_device_queue_process (priv->device_queue, CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE, NULL, &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, "failed to set flash success: %s", error_local->message); g_usb_device_close (item->usb_device, NULL); return FALSE; } /* close, orderly */ if (!g_usb_device_close (item->usb_device, &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, "failed to close device: %s", error_local->message); g_usb_device_close (item->usb_device, NULL); return FALSE; } /* get the new firmware version */ g_debug ("ColorHug: Getting new firmware version"); item->got_version = FALSE; fu_provider_chug_get_firmware_version (item); if (item->got_version) g_debug ("ColorHug: DONE!"); return TRUE; } /** * fu_provider_chug_open_cb: **/ static gboolean fu_provider_chug_open_cb (gpointer user_data) { FuProviderChugItem *item = (FuProviderChugItem *) user_data; g_debug ("attempt to open %s", g_usb_device_get_platform_id (item->usb_device)); fu_provider_chug_get_firmware_version (item); /* success! */ if (item->got_version) { item->timeout_open_id = 0; return FALSE; } /* keep trying */ return TRUE; } /** * fu_provider_chug_device_added_cb: **/ static void fu_provider_chug_device_added_cb (GUsbContext *ctx, GUsbDevice *device, FuProviderChug *provider_chug) { FuProviderChugPrivate *priv = GET_PRIVATE (provider_chug); FuProviderChugItem *item; ChDeviceMode mode; g_autofree gchar *device_key = NULL; /* ignore */ mode = ch_device_get_mode (device); if (mode == CH_DEVICE_MODE_UNKNOWN) return; /* this is using DFU now */ if (mode == CH_DEVICE_MODE_BOOTLOADER_PLUS || mode == CH_DEVICE_MODE_FIRMWARE_PLUS) return; /* is already in database */ device_key = fu_provider_chug_get_device_key (device); item = g_hash_table_lookup (priv->devices, device_key); if (item == NULL) { item = g_new0 (FuProviderChugItem, 1); item->provider_chug = g_object_ref (provider_chug); item->usb_device = g_object_ref (device); item->device = fu_device_new (); fu_device_set_id (item->device, device_key); fu_device_set_equivalent_id (item->device, g_usb_device_get_platform_id (device)); fu_device_set_guid (item->device, ch_device_get_guid (device)); fu_device_add_flag (item->device, FU_DEVICE_FLAG_ALLOW_OFFLINE); fu_device_add_flag (item->device, FU_DEVICE_FLAG_ALLOW_ONLINE); /* try to get the serial number -- if opening failed then * poll until the device is not busy */ fu_provider_chug_get_firmware_version (item); if (!item->got_version && item->timeout_open_id == 0) { item->timeout_open_id = g_timeout_add_seconds (FU_PROVIDER_CHUG_POLL_REOPEN, fu_provider_chug_open_cb, item); } /* insert to hash */ g_hash_table_insert (priv->devices, g_strdup (device_key), item); } else { /* update the device */ g_object_unref (item->usb_device); item->usb_device = g_object_ref (device); } /* set the display name */ switch (mode) { case CH_DEVICE_MODE_BOOTLOADER: case CH_DEVICE_MODE_FIRMWARE: case CH_DEVICE_MODE_LEGACY: fu_device_set_name (item->device, "ColorHug"); break; case CH_DEVICE_MODE_BOOTLOADER2: case CH_DEVICE_MODE_FIRMWARE2: fu_device_set_name (item->device, "ColorHug2"); break; case CH_DEVICE_MODE_BOOTLOADER_PLUS: case CH_DEVICE_MODE_FIRMWARE_PLUS: fu_device_set_name (item->device, "ColorHug+"); break; case CH_DEVICE_MODE_BOOTLOADER_ALS: case CH_DEVICE_MODE_FIRMWARE_ALS: fu_device_set_name (item->device, "ColorHugALS"); break; default: fu_device_set_name (item->device, "ColorHug??"); break; } /* is the device in bootloader mode */ switch (mode) { case CH_DEVICE_MODE_BOOTLOADER: case CH_DEVICE_MODE_BOOTLOADER2: case CH_DEVICE_MODE_BOOTLOADER_PLUS: case CH_DEVICE_MODE_BOOTLOADER_ALS: item->is_bootloader = TRUE; break; default: item->is_bootloader = FALSE; break; } fu_provider_device_add (FU_PROVIDER (provider_chug), item->device); } /** * fu_provider_chug_device_removed_cb: **/ static void fu_provider_chug_device_removed_cb (GUsbContext *ctx, GUsbDevice *device, FuProviderChug *provider_chug) { FuProviderChugPrivate *priv = GET_PRIVATE (provider_chug); FuProviderChugItem *item; g_autofree gchar *device_key = NULL; /* already in database */ device_key = fu_provider_chug_get_device_key (device); item = g_hash_table_lookup (priv->devices, device_key); if (item == NULL) return; /* no more polling for open */ if (item->timeout_open_id != 0) { g_source_remove (item->timeout_open_id); item->timeout_open_id = 0; } fu_provider_device_remove (FU_PROVIDER (provider_chug), item->device); } /** * fu_provider_chug_coldplug: **/ static gboolean fu_provider_chug_coldplug (FuProvider *provider, GError **error) { FuProviderChug *provider_chug = FU_PROVIDER_CHUG (provider); FuProviderChugPrivate *priv = GET_PRIVATE (provider_chug); g_usb_context_enumerate (priv->usb_ctx); return TRUE; } /** * fu_provider_chug_class_init: **/ static void fu_provider_chug_class_init (FuProviderChugClass *klass) { FuProviderClass *provider_class = FU_PROVIDER_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); provider_class->get_name = fu_provider_chug_get_name; provider_class->coldplug = fu_provider_chug_coldplug; provider_class->update_online = fu_provider_chug_update; provider_class->verify = fu_provider_chug_verify; object_class->finalize = fu_provider_chug_finalize; } /** * fu_provider_chug_init: **/ static void fu_provider_chug_init (FuProviderChug *provider_chug) { FuProviderChugPrivate *priv = GET_PRIVATE (provider_chug); priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) fu_provider_chug_device_free); priv->usb_ctx = g_usb_context_new (NULL); priv->device_queue = ch_device_queue_new (); g_signal_connect (priv->usb_ctx, "device-added", G_CALLBACK (fu_provider_chug_device_added_cb), provider_chug); g_signal_connect (priv->usb_ctx, "device-removed", G_CALLBACK (fu_provider_chug_device_removed_cb), provider_chug); } /** * fu_provider_chug_finalize: **/ static void fu_provider_chug_finalize (GObject *object) { FuProviderChug *provider_chug = FU_PROVIDER_CHUG (object); FuProviderChugPrivate *priv = GET_PRIVATE (provider_chug); g_hash_table_unref (priv->devices); g_object_unref (priv->usb_ctx); g_object_unref (priv->device_queue); G_OBJECT_CLASS (fu_provider_chug_parent_class)->finalize (object); } /** * fu_provider_chug_new: **/ FuProvider * fu_provider_chug_new (void) { FuProviderChug *provider; provider = g_object_new (FU_TYPE_PROVIDER_CHUG, NULL); return FU_PROVIDER (provider); } fwupd-0.7.0/src/fu-provider-chug.h000066400000000000000000000025461267747510300170140ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __FU_PROVIDER_CHUG_H #define __FU_PROVIDER_CHUG_H #include #include "fu-device.h" #include "fu-provider.h" G_BEGIN_DECLS #define FU_TYPE_PROVIDER_CHUG (fu_provider_chug_get_type ()) G_DECLARE_DERIVABLE_TYPE (FuProviderChug, fu_provider_chug, FU, PROVIDER_CHUG, FuProvider) struct _FuProviderChugClass { FuProviderClass parent_class; }; FuProvider *fu_provider_chug_new (void); G_END_DECLS #endif /* __FU_PROVIDER_CHUG_H */ fwupd-0.7.0/src/fu-provider-dfu.c000066400000000000000000000276601267747510300166430ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include "fu-device.h" #include "fu-provider-dfu.h" static void fu_provider_dfu_finalize (GObject *object); /** * FuProviderDfuPrivate: **/ typedef struct { DfuContext *context; GHashTable *devices; /* platform_id:DfuDevice */ } FuProviderDfuPrivate; G_DEFINE_TYPE_WITH_PRIVATE (FuProviderDfu, fu_provider_dfu, FU_TYPE_PROVIDER) #define GET_PRIVATE(o) (fu_provider_dfu_get_instance_private (o)) /** * fu_provider_dfu_get_name: **/ static const gchar * fu_provider_dfu_get_name (FuProvider *provider) { return "DFU"; } /** * fu_provider_dfu_device_update: **/ static void fu_provider_dfu_device_update (FuProviderDfu *provider_dfu, FuDevice *dev, DfuDevice *device) { const gchar *platform_id; guint16 release; g_autofree gchar *guid = NULL; g_autofree gchar *version = NULL; g_autofree gchar *vid_pid = NULL; /* check mode */ platform_id = dfu_device_get_platform_id (device); if (dfu_device_get_runtime_vid (device) == 0xffff) { g_debug ("Ignoring DFU device not in runtime: %s", platform_id); return; } /* check capabilities */ if (dfu_device_can_download (device)) { fu_device_add_flag (dev, FU_DEVICE_FLAG_ALLOW_ONLINE); fu_device_add_flag (dev, FU_DEVICE_FLAG_ALLOW_OFFLINE); } /* get version number, falling back to the DFU device release */ release = dfu_device_get_runtime_release (device); if (release != 0xffff) { version = as_utils_version_from_uint16 (release, AS_VERSION_PARSE_FLAG_NONE); fu_device_set_version (dev, version); } vid_pid = g_strdup_printf ("USB\\VID_%04X&PID_%04X", dfu_device_get_runtime_vid (device), dfu_device_get_runtime_pid (device)); guid = as_utils_guid_from_string (vid_pid); g_debug ("using %s for %s", guid, vid_pid); fu_device_set_guid (dev, guid); } /** * fu_provider_dfu_device_changed_cb: **/ static void fu_provider_dfu_device_changed_cb (DfuContext *ctx, DfuDevice *device, FuProviderDfu *provider_dfu) { FuProviderDfuPrivate *priv = GET_PRIVATE (provider_dfu); FuDevice *dev; const gchar *platform_id; /* convert DfuDevice to FuDevice */ platform_id = dfu_device_get_platform_id (device); dev = g_hash_table_lookup (priv->devices, platform_id); if (dev == NULL) { g_warning ("cannot find device %s", platform_id); return; } fu_provider_dfu_device_update (provider_dfu, dev, device); } /** * fu_provider_dfu_device_added_cb: **/ static void fu_provider_dfu_device_added_cb (DfuContext *ctx, DfuDevice *device, FuProviderDfu *provider_dfu) { FuProviderDfuPrivate *priv = GET_PRIVATE (provider_dfu); const gchar *platform_id; const gchar *display_name; g_autofree gchar *id = NULL; g_autoptr(AsProfile) profile = as_profile_new (); g_autoptr(AsProfileTask) ptask = NULL; g_autoptr(FuDevice) dev = NULL; g_autoptr(GError) error = NULL; platform_id = dfu_device_get_platform_id (device); ptask = as_profile_start (profile, "FuProviderDfu:added{%s} [%04x:%04x]", platform_id, dfu_device_get_runtime_vid (device), dfu_device_get_runtime_pid (device)); /* ignore defective runtimes */ if (dfu_device_get_mode (device) == DFU_MODE_RUNTIME && dfu_device_has_quirk (device, DFU_DEVICE_QUIRK_IGNORE_RUNTIME)) { g_debug ("ignoring %s runtime", platform_id); return; } /* create new device */ dev = fu_device_new (); fu_device_set_id (dev, platform_id); fu_provider_dfu_device_update (provider_dfu, dev, device); /* open device to get display name */ if (!dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE, NULL, &error)) { g_warning ("Failed to open DFU device: %s", error->message); return; } display_name = dfu_device_get_display_name (device); if (display_name != NULL) fu_device_set_name (dev, display_name); /* we're done here */ if (!dfu_device_close (device, &error)) g_debug ("Failed to close %s: %s", platform_id, error->message); /* attempt to add */ fu_provider_device_add (FU_PROVIDER (provider_dfu), dev); g_hash_table_insert (priv->devices, g_strdup (platform_id), g_object_ref (dev)); } /** * fu_provider_dfu_device_removed_cb: **/ static void fu_provider_dfu_device_removed_cb (DfuContext *ctx, DfuDevice *device, FuProviderDfu *provider_dfu) { FuProviderDfuPrivate *priv = GET_PRIVATE (provider_dfu); FuDevice *dev; const gchar *platform_id; /* convert DfuDevice to FuDevice */ platform_id = dfu_device_get_platform_id (device); dev = g_hash_table_lookup (priv->devices, platform_id); if (dev == NULL) { g_warning ("cannot find device %s", platform_id); return; } fu_provider_device_remove (FU_PROVIDER (provider_dfu), dev); } /** * fu_provider_dfu_coldplug: **/ static gboolean fu_provider_dfu_coldplug (FuProvider *provider, GError **error) { FuProviderDfu *provider_dfu = FU_PROVIDER_DFU (provider); FuProviderDfuPrivate *priv = GET_PRIVATE (provider_dfu); dfu_context_enumerate (priv->context, NULL); return TRUE; } /** * fu_provider_dfu_state_changed_cb: **/ static void fu_provider_dfu_state_changed_cb (DfuDevice *device, DfuState state, FuProvider *provider) { switch (state) { case DFU_STATE_DFU_UPLOAD_IDLE: fu_provider_set_status (provider, FWUPD_STATUS_DEVICE_VERIFY); break; case DFU_STATE_DFU_DNLOAD_IDLE: fu_provider_set_status (provider, FWUPD_STATUS_DEVICE_WRITE); break; default: break; } } /** * fu_provider_dfu_update: * * This updates using DFU. **/ static gboolean fu_provider_dfu_update (FuProvider *provider, FuDevice *dev, GBytes *blob_fw, FwupdInstallFlags flags, GError **error) { FuProviderDfu *provider_dfu = FU_PROVIDER_DFU (provider); FuProviderDfuPrivate *priv = GET_PRIVATE (provider_dfu); DfuDevice *device; const gchar *platform_id; g_autoptr(DfuDevice) dfu_device = NULL; g_autoptr(DfuFirmware) dfu_firmware = NULL; g_autoptr(GError) error_local = NULL; /* get device */ platform_id = fu_device_get_id (dev); device = dfu_context_get_device_by_platform_id (priv->context, platform_id, &error_local); if (device == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "cannot find device %s: %s", platform_id, error_local->message); return FALSE; } /* open it */ if (!dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE, NULL, &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to open DFU device %s: %s", platform_id, error_local->message); return FALSE; } g_signal_connect (device, "state-changed", G_CALLBACK (fu_provider_dfu_state_changed_cb), provider); /* hit hardware */ dfu_firmware = dfu_firmware_new (); if (!dfu_firmware_parse_data (dfu_firmware, blob_fw, DFU_FIRMWARE_PARSE_FLAG_NONE, error)) return FALSE; if (!dfu_device_download (device, dfu_firmware, DFU_TARGET_TRANSFER_FLAG_DETACH | DFU_TARGET_TRANSFER_FLAG_VERIFY | DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME, NULL, error)) return FALSE; /* we're done */ if (!dfu_device_close (device, &error_local)) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, error_local->message); return FALSE; } fu_provider_set_status (provider, FWUPD_STATUS_IDLE); return TRUE; } /** * fu_provider_dfu_verify: **/ static gboolean fu_provider_dfu_verify (FuProvider *provider, FuDevice *dev, FuProviderVerifyFlags flags, GError **error) { FuProviderDfu *provider_dfu = FU_PROVIDER_DFU (provider); FuProviderDfuPrivate *priv = GET_PRIVATE (provider_dfu); GBytes *blob_fw; GChecksumType checksum_type; DfuDevice *device; const gchar *platform_id; g_autofree gchar *hash = NULL; g_autoptr(DfuDevice) dfu_device = NULL; g_autoptr(DfuFirmware) dfu_firmware = NULL; g_autoptr(GError) error_local = NULL; /* get device */ platform_id = fu_device_get_id (dev); device = dfu_context_get_device_by_platform_id (priv->context, platform_id, &error_local); if (device == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "cannot find device %s: %s", platform_id, error_local->message); return FALSE; } /* open it */ if (!dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE, NULL, &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to open DFU device %s: %s", platform_id, error_local->message); return FALSE; } g_signal_connect (device, "state-changed", G_CALLBACK (fu_provider_dfu_state_changed_cb), provider); /* get data from hardware */ g_debug ("uploading from device->host"); dfu_firmware = dfu_device_upload (device, DFU_TARGET_TRANSFER_FLAG_DETACH | DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME, NULL, error); if (dfu_firmware == NULL) return FALSE; /* we're done */ if (!dfu_device_close (device, &error_local)) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, error_local->message); return FALSE; } /* get the checksum */ blob_fw = dfu_firmware_write_data (dfu_firmware, error); if (blob_fw == NULL) return FALSE; checksum_type = fu_provider_get_checksum_type (flags); hash = g_compute_checksum_for_bytes (checksum_type, blob_fw); fu_device_set_checksum (dev, hash); fu_device_set_checksum_kind (device, checksum_type); fu_provider_set_status (provider, FWUPD_STATUS_IDLE); return TRUE; } /** * fu_provider_dfu_class_init: **/ static void fu_provider_dfu_class_init (FuProviderDfuClass *klass) { FuProviderClass *provider_class = FU_PROVIDER_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); provider_class->get_name = fu_provider_dfu_get_name; provider_class->coldplug = fu_provider_dfu_coldplug; provider_class->update_online = fu_provider_dfu_update; provider_class->verify = fu_provider_dfu_verify; object_class->finalize = fu_provider_dfu_finalize; } /** * fu_provider_dfu_init: **/ static void fu_provider_dfu_init (FuProviderDfu *provider_dfu) { FuProviderDfuPrivate *priv = GET_PRIVATE (provider_dfu); priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref); priv->context = dfu_context_new (); g_signal_connect (priv->context, "device-added", G_CALLBACK (fu_provider_dfu_device_added_cb), provider_dfu); g_signal_connect (priv->context, "device-removed", G_CALLBACK (fu_provider_dfu_device_removed_cb), provider_dfu); g_signal_connect (priv->context, "device-changed", G_CALLBACK (fu_provider_dfu_device_changed_cb), provider_dfu); } /** * fu_provider_dfu_finalize: **/ static void fu_provider_dfu_finalize (GObject *object) { FuProviderDfu *provider_dfu = FU_PROVIDER_DFU (object); FuProviderDfuPrivate *priv = GET_PRIVATE (provider_dfu); g_hash_table_unref (priv->devices); g_object_unref (priv->context); G_OBJECT_CLASS (fu_provider_dfu_parent_class)->finalize (object); } /** * fu_provider_dfu_new: **/ FuProvider * fu_provider_dfu_new (void) { FuProviderDfu *provider; provider = g_object_new (FU_TYPE_PROVIDER_DFU, NULL); return FU_PROVIDER (provider); } fwupd-0.7.0/src/fu-provider-dfu.h000066400000000000000000000025341267747510300166410ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __FU_PROVIDER_DFU_H #define __FU_PROVIDER_DFU_H #include #include "fu-device.h" #include "fu-provider.h" G_BEGIN_DECLS #define FU_TYPE_PROVIDER_DFU (fu_provider_dfu_get_type ()) G_DECLARE_DERIVABLE_TYPE (FuProviderDfu, fu_provider_dfu, FU, PROVIDER_DFU, FuProvider) struct _FuProviderDfuClass { FuProviderClass parent_class; }; FuProvider *fu_provider_dfu_new (void); G_END_DECLS #endif /* __FU_PROVIDER_DFU_H */ fwupd-0.7.0/src/fu-provider-fake.c000066400000000000000000000060351267747510300167640ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include "fu-device.h" #include "fu-provider-fake.h" static void fu_provider_fake_finalize (GObject *object); G_DEFINE_TYPE (FuProviderFake, fu_provider_fake, FU_TYPE_PROVIDER) /** * fu_provider_fake_get_name: **/ static const gchar * fu_provider_fake_get_name (FuProvider *provider) { return "Fake"; } /** * fu_provider_fake_update: **/ static gboolean fu_provider_fake_update (FuProvider *provider, FuDevice *device, GBytes *blob_fw, FwupdInstallFlags flags, GError **error) { if (flags & FWUPD_INSTALL_FLAG_OFFLINE) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "cannot handle offline"); } fu_provider_set_status (provider, FWUPD_STATUS_DECOMPRESSING); fu_provider_set_status (provider, FWUPD_STATUS_DEVICE_WRITE); return TRUE; } /** * fu_provider_fake_coldplug: **/ static gboolean fu_provider_fake_coldplug (FuProvider *provider, GError **error) { g_autoptr(FuDevice) device = NULL; device = fu_device_new (); fu_device_set_id (device, "FakeDevice"); fu_device_set_guid (device, "00000000-0000-0000-0000-000000000000"); fu_provider_device_add (provider, device); return TRUE; } /** * fu_provider_fake_class_init: **/ static void fu_provider_fake_class_init (FuProviderFakeClass *klass) { FuProviderClass *provider_class = FU_PROVIDER_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); provider_class->get_name = fu_provider_fake_get_name; provider_class->coldplug = fu_provider_fake_coldplug; provider_class->update_online = fu_provider_fake_update; object_class->finalize = fu_provider_fake_finalize; } /** * fu_provider_fake_init: **/ static void fu_provider_fake_init (FuProviderFake *provider_fake) { } /** * fu_provider_fake_finalize: **/ static void fu_provider_fake_finalize (GObject *object) { G_OBJECT_CLASS (fu_provider_fake_parent_class)->finalize (object); } /** * fu_provider_fake_new: **/ FuProvider * fu_provider_fake_new (void) { FuProviderFake *provider; provider = g_object_new (FU_TYPE_PROVIDER_FAKE, NULL); return FU_PROVIDER (provider); } fwupd-0.7.0/src/fu-provider-fake.h000066400000000000000000000025461267747510300167740ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __FU_PROVIDER_FAKE_H #define __FU_PROVIDER_FAKE_H #include #include "fu-device.h" #include "fu-provider.h" G_BEGIN_DECLS #define FU_TYPE_PROVIDER_FAKE (fu_provider_fake_get_type ()) G_DECLARE_DERIVABLE_TYPE (FuProviderFake, fu_provider_fake, FU, PROVIDER_FAKE, FuProvider) struct _FuProviderFakeClass { FuProviderClass parent_class; }; FuProvider *fu_provider_fake_new (void); G_END_DECLS #endif /* __FU_PROVIDER_FAKE_H */ fwupd-0.7.0/src/fu-provider-rpi.c000066400000000000000000000232531267747510300166510ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include #include #include "fu-device.h" #include "fu-provider-rpi.h" static void fu_provider_rpi_finalize (GObject *object); #define FU_PROVIDER_RPI_FIRMWARE_FILENAME "start.elf" /** * FuProviderRpiPrivate: **/ typedef struct { gchar *fw_dir; } FuProviderRpiPrivate; G_DEFINE_TYPE_WITH_PRIVATE (FuProviderRpi, fu_provider_rpi, FU_TYPE_PROVIDER) #define GET_PRIVATE(o) (fu_provider_rpi_get_instance_private (o)) /** * fu_provider_rpi_get_name: **/ static const gchar * fu_provider_rpi_get_name (FuProvider *provider) { return "RaspberryPi"; } /** * fu_provider_rpi_strstr: **/ static gchar * fu_provider_rpi_strstr (const guint8 *haystack, gsize haystack_len, const gchar *needle, guint *offset) { guint i; guint needle_len; if (needle == NULL || needle[0] == '\0') return NULL; if (haystack == NULL || haystack_len == 0) return NULL; needle_len = strlen (needle); if (needle_len > haystack_len) return NULL; for (i = 0; i < haystack_len - needle_len; i++) { if (memcmp (haystack + i, needle, needle_len) == 0) { if (offset != NULL) *offset = i + needle_len; return g_strdup ((const gchar *) &haystack[i + needle_len]); } } return NULL; } /** * fu_provider_rpi_parse_firmware: **/ static gboolean fu_provider_rpi_parse_firmware (FuDevice *device, const gchar *fn, GError **error) { GDate *date; gsize len = 0; guint offset; g_autofree gchar *fwver = NULL; g_autofree gchar *platform = NULL; g_autofree gchar *vc_date = NULL; g_autofree gchar *vc_time = NULL; g_autofree guint8 *data = NULL; /* read file -- things we can find are: * * VC_BUILD_ID_USER: dc4 * VC_BUILD_ID_TIME: 14:58:37 * VC_BUILD_ID_BRANCH: master * VC_BUILD_ID_TIME: Aug 3 2015 * VC_BUILD_ID_HOSTNAME: dc4-XPS13-9333 * VC_BUILD_ID_PLATFORM: raspberrypi_linux * VC_BUILD_ID_VERSION: 4b51d81eb0068a875b336f4cc2c468cbdd06d0c5 (clean) */ if (!g_file_get_contents (fn, (gchar **) &data, &len, error)) return FALSE; /* check the platform matches */ platform = fu_provider_rpi_strstr (data, len, "VC_BUILD_ID_PLATFORM: ", NULL); if (g_strcmp0 (platform, "raspberrypi_linux") != 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "not a RasberryPi, platform is %s", platform); return FALSE; } /* find the VC_BUILD info which paradoxically is split into two * string segments */ vc_time = fu_provider_rpi_strstr (data, len, "VC_BUILD_ID_TIME: ", &offset); if (vc_time == NULL) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Failed to get 1st VC_BUILD_ID_TIME"); return FALSE; } vc_date = fu_provider_rpi_strstr (data + offset, len - offset, "VC_BUILD_ID_TIME: ", NULL); if (vc_date == NULL) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Failed to get 2nd VC_BUILD_ID_TIME"); return FALSE; } /* parse the date */ date = g_date_new (); g_date_set_parse (date, vc_date); if (!g_date_valid (date)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Failed to parse date '%s'", vc_date); return FALSE; } /* create a version number from the date and time */ fwver = g_strdup_printf ("%04i%02i%02i", g_date_get_year (date), g_date_get_month (date), g_date_get_day (date)); fu_device_set_version (device, fwver); g_date_free (date); return TRUE; } /** * fu_provider_rpi_explode_file: **/ static gboolean fu_provider_rpi_explode_file (struct archive_entry *entry, const gchar *dir) { const gchar *tmp; g_autofree gchar *buf = NULL; /* no output file */ if (archive_entry_pathname (entry) == NULL) return FALSE; /* update output path */ tmp = archive_entry_pathname (entry); buf = g_build_filename (dir, tmp, NULL); archive_entry_update_pathname_utf8 (entry, buf); return TRUE; } /** * fu_provider_rpi_update: **/ static gboolean fu_provider_rpi_update (FuProvider *provider, FuDevice *device, GBytes *blob_fw, FwupdInstallFlags flags, GError **error) { FuProviderRpi *provider_rpi = FU_PROVIDER_RPI (provider); FuProviderRpiPrivate *priv = GET_PRIVATE (provider_rpi); gboolean ret = TRUE; gboolean valid; int r; struct archive *arch = NULL; struct archive_entry *entry; g_autofree gchar *fwfn = NULL; /* decompress anything matching either glob */ fu_provider_set_status (provider, FWUPD_STATUS_DECOMPRESSING); arch = archive_read_new (); archive_read_support_format_all (arch); archive_read_support_filter_all (arch); r = archive_read_open_memory (arch, (void *) g_bytes_get_data (blob_fw, NULL), (size_t) g_bytes_get_size (blob_fw)); if (r) { ret = FALSE; g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "Cannot open: %s", archive_error_string (arch)); goto out; } fu_provider_set_status (provider, FWUPD_STATUS_DEVICE_WRITE); for (;;) { g_autofree gchar *path = NULL; r = archive_read_next_header (arch, &entry); if (r == ARCHIVE_EOF) break; if (r != ARCHIVE_OK) { ret = FALSE; g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "Cannot read header: %s", archive_error_string (arch)); goto out; } /* only extract if valid */ valid = fu_provider_rpi_explode_file (entry, priv->fw_dir); if (!valid) continue; r = archive_read_extract (arch, entry, 0); if (r != ARCHIVE_OK) { ret = FALSE; g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "Cannot extract: %s", archive_error_string (arch)); goto out; } } /* get the new VC build info */ fu_provider_set_status (provider, FWUPD_STATUS_DEVICE_VERIFY); fwfn = g_build_filename (priv->fw_dir, FU_PROVIDER_RPI_FIRMWARE_FILENAME, NULL); if (!fu_provider_rpi_parse_firmware (device, fwfn, error)) return FALSE; out: if (arch != NULL) { archive_read_close (arch); archive_read_free (arch); } return ret; } /** * fu_provider_rpi_coldplug: **/ static gboolean fu_provider_rpi_coldplug (FuProvider *provider, GError **error) { FuProviderRpi *provider_rpi = FU_PROVIDER_RPI (provider); FuProviderRpiPrivate *priv = GET_PRIVATE (provider_rpi); g_autofree gchar *fwfn = NULL; g_autofree gchar *fwver = NULL; g_autofree gchar *guid = NULL; g_autoptr(FuDevice) device = NULL; /* anything interesting */ fwfn = g_build_filename (priv->fw_dir, FU_PROVIDER_RPI_FIRMWARE_FILENAME, NULL); if (!g_file_test (fwfn, G_FILE_TEST_EXISTS)) return TRUE; /* create fake device */ device = fu_device_new (); fu_device_set_id (device, "raspberry-pi"); guid = as_utils_guid_from_string ("raspberrypi"); fu_device_set_guid (device, guid); fu_device_set_name (device, "Raspberry Pi"); fu_device_add_flag (device, FU_DEVICE_FLAG_INTERNAL); fu_device_add_flag (device, FU_DEVICE_FLAG_ALLOW_OFFLINE); fu_device_add_flag (device, FU_DEVICE_FLAG_ALLOW_ONLINE); fu_device_add_flag (device, FU_DEVICE_FLAG_REQUIRE_AC); /* get the VC build info */ if (!fu_provider_rpi_parse_firmware (device, fwfn, error)) return FALSE; fu_provider_device_add (provider, device); return TRUE; } /** * fu_provider_rpi_class_init: **/ static void fu_provider_rpi_class_init (FuProviderRpiClass *klass) { FuProviderClass *provider_class = FU_PROVIDER_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); provider_class->get_name = fu_provider_rpi_get_name; provider_class->coldplug = fu_provider_rpi_coldplug; provider_class->update_online = fu_provider_rpi_update; object_class->finalize = fu_provider_rpi_finalize; } /** * fu_provider_rpi_init: **/ static void fu_provider_rpi_init (FuProviderRpi *provider_rpi) { FuProviderRpiPrivate *priv = GET_PRIVATE (provider_rpi); const gchar *tmp; /* allow this to be overidden for testing */ priv->fw_dir = g_strdup ("/boot"); tmp = g_getenv ("FWUPD_RPI_FW_DIR"); if (tmp != NULL) fu_provider_rpi_set_fw_dir (provider_rpi, tmp); } /** * fu_provider_rpi_set_fw_dir: **/ void fu_provider_rpi_set_fw_dir (FuProviderRpi *provider_rpi, const gchar *fw_dir) { FuProviderRpiPrivate *priv = GET_PRIVATE (provider_rpi); g_free (priv->fw_dir); priv->fw_dir = g_strdup (fw_dir); g_mkdir_with_parents (fw_dir, 0700); } /** * fu_provider_rpi_finalize: **/ static void fu_provider_rpi_finalize (GObject *object) { FuProviderRpi *provider_rpi = FU_PROVIDER_RPI (object); FuProviderRpiPrivate *priv = GET_PRIVATE (provider_rpi); g_free (priv->fw_dir); G_OBJECT_CLASS (fu_provider_rpi_parent_class)->finalize (object); } /** * fu_provider_rpi_new: **/ FuProvider * fu_provider_rpi_new (void) { FuProviderRpi *provider; provider = g_object_new (FU_TYPE_PROVIDER_RPI, NULL); return FU_PROVIDER (provider); } fwupd-0.7.0/src/fu-provider-rpi.h000066400000000000000000000026661267747510300166630ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __FU_PROVIDER_RPI_H #define __FU_PROVIDER_RPI_H #include #include "fu-device.h" #include "fu-provider.h" G_BEGIN_DECLS #define FU_TYPE_PROVIDER_RPI (fu_provider_rpi_get_type ()) G_DECLARE_DERIVABLE_TYPE (FuProviderRpi, fu_provider_rpi, FU, PROVIDER_RPI, GObject) struct _FuProviderRpiClass { FuProviderClass parent_class; }; FuProvider *fu_provider_rpi_new (void); void fu_provider_rpi_set_fw_dir (FuProviderRpi *provider_rpi, const gchar *fw_dir); G_END_DECLS #endif /* __FU_PROVIDER_RPI_H */ fwupd-0.7.0/src/fu-provider-udev.c000066400000000000000000000242041267747510300170170ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include "fu-device.h" #include "fu-provider-udev.h" #include "fu-rom.h" static void fu_provider_udev_finalize (GObject *object); /** * FuProviderUdevPrivate: **/ typedef struct { GHashTable *devices; GUdevClient *gudev_client; } FuProviderUdevPrivate; G_DEFINE_TYPE_WITH_PRIVATE (FuProviderUdev, fu_provider_udev, FU_TYPE_PROVIDER) #define GET_PRIVATE(o) (fu_provider_udev_get_instance_private (o)) /** * fu_provider_udev_get_name: **/ static const gchar * fu_provider_udev_get_name (FuProvider *provider) { return "Udev"; } /** * fu_provider_udev_get_id: **/ static gchar * fu_provider_udev_get_id (GUdevDevice *device) { gchar *id; id = g_strdup_printf ("ro-%s", g_udev_device_get_sysfs_path (device)); g_strdelimit (id, "/:.-", '_'); return id; } /** * fu_provider_udev_unlock: **/ static gboolean fu_provider_udev_unlock (FuProvider *provider, FuDevice *device, GError **error) { const gchar *rom_fn; g_autoptr(FuRom) rom = NULL; g_autoptr(GFile) file = NULL; /* get the FW version from the rom */ g_debug ("unlocking UDev device %s", fu_device_get_id (device)); rom_fn = fu_device_get_metadata (device, "RomFilename"); if (rom_fn == NULL) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "Unable to read firmware from device"); return FALSE; } file = g_file_new_for_path (rom_fn); rom = fu_rom_new (); if (!fu_rom_load_file (rom, file, FU_ROM_LOAD_FLAG_BLANK_PPID, NULL, error)) return FALSE; /* update version */ if (g_strcmp0 (fu_device_get_version (device), fu_rom_get_version (rom)) != 0) { g_debug ("changing version of %s from %s to %s", fu_device_get_id (device), fu_device_get_version (device), fu_rom_get_version (rom)); fu_device_set_version (device, fu_rom_get_version (rom)); } /* prefer the GUID from the firmware rather than the * hardware as the firmware may be more generic, which * also allows us to match the GUID when doing 'verify' * on a device with a different PID to the firmware */ if (g_strcmp0 (fu_device_get_guid (device), fu_rom_get_guid (rom)) != 0) { fu_device_set_guid (device, fu_rom_get_guid (rom)); g_debug ("changing GUID of %s from %s to %s", fu_device_get_id (device), fu_device_get_guid (device), fu_rom_get_guid (rom)); } return TRUE; } /** * fu_provider_udev_verify: **/ static gboolean fu_provider_udev_verify (FuProvider *provider, FuDevice *device, FuProviderVerifyFlags flags, GError **error) { const gchar *rom_fn; g_autoptr(GFile) file = NULL; g_autoptr(FuRom) rom = NULL; /* open the file */ rom_fn = fu_device_get_metadata (device, "RomFilename"); if (rom_fn == NULL) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "Unable to read firmware from device"); return FALSE; } file = g_file_new_for_path (rom_fn); rom = fu_rom_new (); if (!fu_rom_load_file (rom, file, FU_ROM_LOAD_FLAG_BLANK_PPID, NULL, error)) return FALSE; fu_device_set_checksum (device, fu_rom_get_checksum (rom)); return TRUE; } /** * fu_provider_udev_client_add: **/ static void fu_provider_udev_client_add (FuProviderUdev *provider_udev, GUdevDevice *device) { FuProviderUdevPrivate *priv = GET_PRIVATE (provider_udev); FuDevice *dev; const gchar *display_name; const gchar *guid; const gchar *product; const gchar *vendor; g_autofree gchar *guid_new = NULL; g_autofree gchar *id = NULL; g_autofree gchar *rom_fn = NULL; g_autofree gchar *version = NULL; g_auto(GStrv) split = NULL; g_autoptr(AsProfile) profile = as_profile_new (); g_autoptr(AsProfileTask) ptask = NULL; /* interesting device? */ guid = g_udev_device_get_property (device, "FWUPD_GUID"); if (guid == NULL) return; /* get data */ ptask = as_profile_start (profile, "FuProviderUdev:client-add{%s}", guid); g_debug ("adding udev device: %s", g_udev_device_get_sysfs_path (device)); /* is already in database */ id = fu_provider_udev_get_id (device); dev = g_hash_table_lookup (priv->devices, id); if (dev != NULL) { g_debug ("ignoring duplicate %s", id); return; } /* get the FW version from the BCD device revision */ product = g_udev_device_get_property (device, "PRODUCT"); if (product != NULL) { split = g_strsplit (product, "/", -1); if (g_strv_length (split) != 3) { g_warning ("env{PRODUCT} is invalid: %s", product); return; } version = g_strdup (split[2]); } /* no GUID from the ROM, so fix up the VID:PID */ if (!as_utils_guid_is_valid (guid)) { guid_new = as_utils_guid_from_string (guid); g_debug ("fixing GUID %s->%s", guid, guid_new); } else { guid_new = g_strdup (guid); } /* did we get enough data */ dev = fu_device_new (); fu_device_add_flag (dev, FU_DEVICE_FLAG_INTERNAL); fu_device_set_id (dev, id); fu_device_set_guid (dev, guid_new); display_name = g_udev_device_get_property (device, "FWUPD_MODEL"); if (display_name == NULL) display_name = g_udev_device_get_property (device, "ID_MODEL_FROM_DATABASE"); if (display_name != NULL) fu_device_set_name (dev, display_name); vendor = g_udev_device_get_property (device, "FWUPD_VENDOR"); if (vendor == NULL) vendor = g_udev_device_get_property (device, "ID_VENDOR_FROM_DATABASE"); if (vendor != NULL) fu_device_set_vendor (dev, vendor); if (version != NULL) fu_device_set_version (dev, version); /* get the FW version from the rom when unlocked */ rom_fn = g_build_filename (g_udev_device_get_sysfs_path (device), "rom", NULL); if (g_file_test (rom_fn, G_FILE_TEST_EXISTS)) { fu_device_set_metadata (dev, "RomFilename", rom_fn); fu_device_add_flag (dev, FU_DEVICE_FLAG_LOCKED); } /* insert to hash */ g_hash_table_insert (priv->devices, g_strdup (id), dev); fu_provider_device_add (FU_PROVIDER (provider_udev), dev); } /** * fu_provider_udev_client_remove: **/ static void fu_provider_udev_client_remove (FuProviderUdev *provider_udev, GUdevDevice *device) { FuProviderUdevPrivate *priv = GET_PRIVATE (provider_udev); FuDevice *dev; g_autofree gchar *id = NULL; /* interesting device? */ if (g_udev_device_get_property (device, "FWUPD_GUID") == NULL) return; /* already in database */ id = fu_provider_udev_get_id (device); dev = g_hash_table_lookup (priv->devices, id); if (dev == NULL) return; fu_provider_device_remove (FU_PROVIDER (provider_udev), dev); } /** * fu_provider_udev_client_uevent_cb: **/ static void fu_provider_udev_client_uevent_cb (GUdevClient *gudev_client, const gchar *action, GUdevDevice *udev_device, FuProviderUdev *provider_udev) { if (g_strcmp0 (action, "remove") == 0) { fu_provider_udev_client_remove (provider_udev, udev_device); return; } if (g_strcmp0 (action, "add") == 0) { fu_provider_udev_client_add (provider_udev, udev_device); return; } } /** * fu_provider_udev_coldplug: **/ static gboolean fu_provider_udev_coldplug (FuProvider *provider, GError **error) { FuProviderUdev *provider_udev = FU_PROVIDER_UDEV (provider); FuProviderUdevPrivate *priv = GET_PRIVATE (provider_udev); GList *devices; GList *l; GUdevDevice *udev_device; const gchar *devclass[] = { "usb", "pci", NULL }; guint i; g_autoptr(AsProfile) profile = as_profile_new (); /* get all devices of class */ for (i = 0; devclass[i] != NULL; i++) { g_autoptr(AsProfileTask) ptask = NULL; ptask = as_profile_start (profile, "FuProviderUdev:coldplug{%s}", devclass[i]); devices = g_udev_client_query_by_subsystem (priv->gudev_client, devclass[i]); for (l = devices; l != NULL; l = l->next) { udev_device = l->data; fu_provider_udev_client_add (provider_udev, udev_device); } g_list_foreach (devices, (GFunc) g_object_unref, NULL); g_list_free (devices); } return TRUE; } /** * fu_provider_udev_class_init: **/ static void fu_provider_udev_class_init (FuProviderUdevClass *klass) { FuProviderClass *provider_class = FU_PROVIDER_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); provider_class->get_name = fu_provider_udev_get_name; provider_class->coldplug = fu_provider_udev_coldplug; provider_class->verify = fu_provider_udev_verify; provider_class->unlock = fu_provider_udev_unlock; object_class->finalize = fu_provider_udev_finalize; } /** * fu_provider_udev_init: **/ static void fu_provider_udev_init (FuProviderUdev *provider_udev) { FuProviderUdevPrivate *priv = GET_PRIVATE (provider_udev); const gchar *subsystems[] = { NULL }; priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref); priv->gudev_client = g_udev_client_new (subsystems); g_signal_connect (priv->gudev_client, "uevent", G_CALLBACK (fu_provider_udev_client_uevent_cb), provider_udev); } /** * fu_provider_udev_finalize: **/ static void fu_provider_udev_finalize (GObject *object) { FuProviderUdev *provider_udev = FU_PROVIDER_UDEV (object); FuProviderUdevPrivate *priv = GET_PRIVATE (provider_udev); g_hash_table_unref (priv->devices); g_object_unref (priv->gudev_client); G_OBJECT_CLASS (fu_provider_udev_parent_class)->finalize (object); } /** * fu_provider_udev_new: **/ FuProvider * fu_provider_udev_new (void) { FuProviderUdev *provider; provider = g_object_new (FU_TYPE_PROVIDER_UDEV, NULL); return FU_PROVIDER (provider); } fwupd-0.7.0/src/fu-provider-udev.h000066400000000000000000000025461267747510300170310ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __FU_PROVIDER_UDEV_H #define __FU_PROVIDER_UDEV_H #include #include "fu-device.h" #include "fu-provider.h" G_BEGIN_DECLS #define FU_TYPE_PROVIDER_UDEV (fu_provider_udev_get_type ()) G_DECLARE_DERIVABLE_TYPE (FuProviderUdev, fu_provider_udev, FU, PROVIDER_UDEV, FuProvider) struct _FuProviderUdevClass { FuProviderClass parent_class; }; FuProvider *fu_provider_udev_new (void); G_END_DECLS #endif /* __FU_PROVIDER_UDEV_H */ fwupd-0.7.0/src/fu-provider-uefi.c000066400000000000000000000275361267747510300170170ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include #include #include "fu-device.h" #include "fu-pending.h" #include "fu-provider-uefi.h" #include "fu-quirks.h" static void fu_provider_uefi_finalize (GObject *object); G_DEFINE_TYPE (FuProviderUefi, fu_provider_uefi, FU_TYPE_PROVIDER) /** * fu_provider_uefi_get_name: **/ static const gchar * fu_provider_uefi_get_name (FuProvider *provider) { return "UEFI"; } /** * fu_provider_uefi_find: **/ static fwup_resource * fu_provider_uefi_find (fwup_resource_iter *iter, const gchar *guid_str, GError **error) { efi_guid_t *guid_raw; fwup_resource *re_matched = NULL; fwup_resource *re = NULL; g_autofree gchar *guid_str_tmp = NULL; /* get the hardware we're referencing */ guid_str_tmp = g_strdup ("00000000-0000-0000-0000-000000000000"); while (fwup_resource_iter_next (iter, &re) > 0) { /* convert to strings */ fwup_get_guid (re, &guid_raw); if (efi_guid_to_str (guid_raw, &guid_str_tmp) < 0) { g_warning ("failed to convert guid to string"); continue; } /* FIXME: also match hardware_instance too */ if (g_strcmp0 (guid_str, guid_str_tmp) == 0) { re_matched = re; break; } } /* paradoxically, no hardware matched */ if (re_matched == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "No UEFI firmware matched %s", guid_str); } return re_matched; } /** * _fwup_resource_iter_free: **/ static void _fwup_resource_iter_free (fwup_resource_iter *iter) { fwup_resource_iter_destroy (&iter); } G_DEFINE_AUTOPTR_CLEANUP_FUNC(fwup_resource_iter, _fwup_resource_iter_free); /** * fu_provider_uefi_clear_results: **/ static gboolean fu_provider_uefi_clear_results (FuProvider *provider, FuDevice *device, GError **error) { fwup_resource *re = NULL; g_autoptr(fwup_resource_iter) iter = NULL; /* get the hardware we're referencing */ fwup_resource_iter_create (&iter); re = fu_provider_uefi_find (iter, fu_device_get_guid (device), error); if (re == NULL) return FALSE; if (fwup_clear_status (re) < 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "Cannot create clear UEFI status for %s", fu_device_get_guid (device)); return FALSE; } return TRUE; } /* only in git master */ #ifndef FWUP_LAST_ATTEMPT_STATUS_SUCCESS #define FWUP_LAST_ATTEMPT_STATUS_SUCCESS 0x00000000 #define FWUP_LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL 0x00000001 #define FWUP_LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES 0x00000002 #define FWUP_LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION 0x00000003 #define FWUP_LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT 0x00000004 #define FWUP_LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR 0x00000005 #define FWUP_LAST_ATTEMPT_STATUS_ERROR_PWR_EVT_AC 0x00000006 #define FWUP_LAST_ATTEMPT_STATUS_ERROR_PWR_EVT_BATT 0x00000007 #endif /** * fu_provider_uefi_last_attempt_status_to_str: **/ static const gchar * fu_provider_uefi_last_attempt_status_to_str (guint32 status) { if (status == FWUP_LAST_ATTEMPT_STATUS_SUCCESS) return "Success"; if (status == FWUP_LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL) return "Unsuccessful"; if (status == FWUP_LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES) return "Insufficient resources"; if (status == FWUP_LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION) return "Incorrect version"; if (status == FWUP_LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT) return "Invalid firmware format"; if (status == FWUP_LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR) return "Authentication signing error"; if (status == FWUP_LAST_ATTEMPT_STATUS_ERROR_PWR_EVT_AC) return "AC power required"; if (status == FWUP_LAST_ATTEMPT_STATUS_ERROR_PWR_EVT_BATT) return "Battery level is too low"; return NULL; } /** * fu_provider_uefi_get_results: **/ static gboolean fu_provider_uefi_get_results (FuProvider *provider, FuDevice *device, GError **error) { const gchar *tmp; fwup_resource *re = NULL; guint32 status = 0; guint32 version = 0; time_t when = 0; g_autofree gchar *version_str = NULL; g_autoptr(fwup_resource_iter) iter = NULL; /* get the hardware we're referencing */ fwup_resource_iter_create (&iter); re = fu_provider_uefi_find (iter, fu_device_get_guid (device), error); if (re == NULL) return FALSE; if (fwup_get_last_attempt_info (re, &version, &status, &when) < 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "Cannot get UEFI status for %s", fu_device_get_guid (device)); return FALSE; } version_str = g_strdup_printf ("%u", version); fu_device_set_update_version (device, version_str); if (status == FWUP_LAST_ATTEMPT_STATUS_SUCCESS) { fu_device_set_update_state (device, FWUPD_UPDATE_STATE_SUCCESS); } else { fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED); tmp = fu_provider_uefi_last_attempt_status_to_str (status); if (tmp != NULL) fu_device_set_update_error (device, tmp); } return TRUE; } /** * fu_provider_uefi_update: **/ static gboolean fu_provider_uefi_update (FuProvider *provider, FuDevice *device, GBytes *blob_fw, FwupdInstallFlags flags, GError **error) { g_autoptr(GError) error_local = NULL; fwup_resource *re = NULL; guint64 hardware_instance = 0; /* FIXME */ int rc; g_autoptr(fwup_resource_iter) iter = NULL; /* get the hardware we're referencing */ fwup_resource_iter_create (&iter); re = fu_provider_uefi_find (iter, fu_device_get_guid (device), error); if (re == NULL) return FALSE; /* perform the update */ g_debug ("Performing UEFI capsule update"); fu_provider_set_status (provider, FWUPD_STATUS_SCHEDULING); rc = fwup_set_up_update_with_buf (re, hardware_instance, g_bytes_get_data (blob_fw, NULL), g_bytes_get_size (blob_fw)); if (rc < 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "UEFI firmware update failed: %s", strerror (rc)); return FALSE; } return TRUE; } /** * fu_provider_uefi_get_version_format: **/ static AsVersionParseFlag fu_provider_uefi_get_version_format (void) { guint i; g_autofree gchar *content = NULL; /* any vendors match */ if (!g_file_get_contents ("/sys/class/dmi/id/sys_vendor", &content, NULL, NULL)) return AS_VERSION_PARSE_FLAG_USE_TRIPLET; g_strchomp (content); for (i = 0; quirk_table[i].sys_vendor != NULL; i++) { if (g_strcmp0 (content, quirk_table[i].sys_vendor) == 0) return quirk_table[i].flags; } /* fall back */ return AS_VERSION_PARSE_FLAG_USE_TRIPLET; } /** * fu_provider_uefi_unlock: **/ static gboolean fu_provider_uefi_unlock (FuProvider *provider, FuDevice *device, GError **error) { #ifdef HAVE_UEFI_UNLOCK gint rc; g_debug ("unlocking UEFI device %s", fu_device_get_id (device)); rc = fwup_enable_esrt(); if (rc <= 0) { g_debug("Failed to unlock UEFI device"); return FALSE; } else if (rc == 1) g_debug("UEFI device is already unlocked"); else if (rc == 2) g_debug("Succesfully unlocked UEFI device"); else if (rc == 3) g_debug("UEFI device will be unlocked on next reboot"); return TRUE; #else g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "Not supported, update libfwupdate!"); return FALSE; #endif } /** * fu_provider_uefi_coldplug: **/ static gboolean fu_provider_uefi_coldplug (FuProvider *provider, GError **error) { AsVersionParseFlag parse_flags; fwup_resource *re; gint supported; g_autofree gchar *guid = NULL; g_autoptr(FuDevice) dev = NULL; g_autoptr(fwup_resource_iter) iter = NULL; /* supported = 0 : ESRT unspported supported = 1 : unlocked, ESRT supported supported = 2 : it is locked but can be unlocked to support ESRT supported = 3 : it is locked, has been marked to be unlocked on next boot calling unlock again is OK. */ supported = fwup_supported (); if (supported == 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "UEFI firmware updating not supported"); return FALSE; } if (supported >= 2) { dev = fu_device_new (); fu_device_set_id (dev, "UEFI-dummy-dev0"); fu_device_set_guid (dev, "2d47f29b-83a2-4f31-a2e8-63474f4d4c2e"); fu_device_set_version (dev, "0"); fu_device_add_flag (dev, FU_DEVICE_FLAG_ALLOW_ONLINE); fu_device_add_flag (dev, FU_DEVICE_FLAG_LOCKED); fu_provider_device_add (provider, dev); return TRUE; } /* this can fail if we have no permissions */ if (fwup_resource_iter_create (&iter) < 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "Cannot create fwup iter"); return FALSE; } /* add each device */ guid = g_strdup ("00000000-0000-0000-0000-000000000000"); parse_flags = fu_provider_uefi_get_version_format (); while (fwup_resource_iter_next (iter, &re) > 0) { efi_guid_t *guid_raw; guint32 version_raw; guint64 hardware_instance = 0; /* FIXME */ g_autofree gchar *id = NULL; g_autofree gchar *version = NULL; g_autofree gchar *version_lowest = NULL; /* convert to strings */ fwup_get_guid (re, &guid_raw); if (efi_guid_to_str (guid_raw, &guid) < 0) { g_warning ("failed to convert guid to string"); continue; } fwup_get_fw_version(re, &version_raw); version = as_utils_version_from_uint32 (version_raw, parse_flags); id = g_strdup_printf ("UEFI-%s-dev%" G_GUINT64_FORMAT, guid, hardware_instance); dev = fu_device_new (); fu_device_set_id (dev, id); fu_device_set_guid (dev, guid); fu_device_set_version (dev, version); fwup_get_lowest_supported_fw_version (re, &version_raw); if (version_raw != 0) { version_lowest = as_utils_version_from_uint32 (version_raw, parse_flags); fu_device_set_version_lowest (dev, version_lowest); } fu_device_add_flag (dev, FU_DEVICE_FLAG_INTERNAL); fu_device_add_flag (dev, FU_DEVICE_FLAG_ALLOW_OFFLINE); fu_device_add_flag (dev, FU_DEVICE_FLAG_REQUIRE_AC); fu_provider_device_add (provider, dev); } return TRUE; } /** * fu_provider_uefi_class_init: **/ static void fu_provider_uefi_class_init (FuProviderUefiClass *klass) { FuProviderClass *provider_class = FU_PROVIDER_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); provider_class->get_name = fu_provider_uefi_get_name; provider_class->coldplug = fu_provider_uefi_coldplug; provider_class->unlock = fu_provider_uefi_unlock; provider_class->update_offline = fu_provider_uefi_update; provider_class->clear_results = fu_provider_uefi_clear_results; provider_class->get_results = fu_provider_uefi_get_results; object_class->finalize = fu_provider_uefi_finalize; } /** * fu_provider_uefi_init: **/ static void fu_provider_uefi_init (FuProviderUefi *provider_uefi) { } /** * fu_provider_uefi_finalize: **/ static void fu_provider_uefi_finalize (GObject *object) { G_OBJECT_CLASS (fu_provider_uefi_parent_class)->finalize (object); } /** * fu_provider_uefi_new: **/ FuProvider * fu_provider_uefi_new (void) { FuProviderUefi *provider; provider = g_object_new (FU_TYPE_PROVIDER_UEFI, NULL); return FU_PROVIDER (provider); } fwupd-0.7.0/src/fu-provider-uefi.h000066400000000000000000000025471267747510300170170ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __FU_PROVIDER_UEFI_H #define __FU_PROVIDER_UEFI_H #include #include "fu-device.h" #include "fu-provider.h" G_BEGIN_DECLS #define FU_TYPE_PROVIDER_UEFI (fu_provider_uefi_get_type ()) G_DECLARE_DERIVABLE_TYPE (FuProviderUefi, fu_provider_uefi, FU, PROVIDER_UEFI, FuProvider) struct _FuProviderUefiClass { FuProviderClass parent_class; }; FuProvider *fu_provider_uefi_new (void); G_END_DECLS #endif /* __FU_PROVIDER_UEFI_H */ fwupd-0.7.0/src/fu-provider-usb.c000066400000000000000000000176621267747510300166570ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include "fu-device.h" #include "fu-provider-usb.h" static void fu_provider_usb_finalize (GObject *object); /** * FuProviderUsbPrivate: **/ typedef struct { GHashTable *devices; GUsbContext *usb_ctx; gboolean done_enumerate; } FuProviderUsbPrivate; G_DEFINE_TYPE_WITH_PRIVATE (FuProviderUsb, fu_provider_usb, FU_TYPE_PROVIDER) #define GET_PRIVATE(o) (fu_provider_usb_get_instance_private (o)) /** * fu_provider_usb_get_name: **/ static const gchar * fu_provider_usb_get_name (FuProvider *provider) { return "USB"; } /** * fu_provider_usb_device_added: **/ static void fu_provider_usb_device_added (FuProviderUsb *provider_usb, GUsbDevice *device) { FuProviderUsbPrivate *priv = GET_PRIVATE (provider_usb); const gchar *platform_id = NULL; guint8 idx = 0x00; g_autofree gchar *guid = NULL; g_autofree gchar *product = NULL; g_autofree gchar *version = NULL; g_autoptr(AsProfile) profile = as_profile_new (); g_autoptr(AsProfileTask) ptask = NULL; g_autoptr(FuDevice) dev = NULL; g_autoptr(GError) error = NULL; /* ignore hubs */ if (g_usb_device_get_device_class (device) == G_USB_DEVICE_CLASS_HUB) return; ptask = as_profile_start (profile, "FuProviderUsb:added{%04x:%04x}", g_usb_device_get_vid (device), g_usb_device_get_pid (device)); /* is already in database */ platform_id = g_usb_device_get_platform_id (device); dev = g_hash_table_lookup (priv->devices, platform_id); if (dev != NULL) { g_debug ("ignoring duplicate %s", platform_id); return; } /* try to get the version without claiming interface */ if (!g_usb_device_open (device, &error)) { g_debug ("Failed to open: %s", error->message); return; } /* insert to hash if valid */ dev = fu_device_new (); fu_device_set_id (dev, platform_id); /* get product */ idx = g_usb_device_get_product_index (device); if (idx != 0x00) { g_autoptr(AsProfileTask) ptask2 = NULL; ptask2 = as_profile_start_literal (profile, "FuProviderUsb:get-string-desc"); product = g_usb_device_get_string_descriptor (device, idx, NULL); } if (product == NULL) { g_debug ("no product string descriptor"); return; } fu_device_set_name (dev, product); /* get version number, falling back to the USB device release */ idx = g_usb_device_get_custom_index (device, G_USB_DEVICE_CLASS_VENDOR_SPECIFIC, 'F', 'W', NULL); if (idx != 0x00) version = g_usb_device_get_string_descriptor (device, idx, NULL); if (version == NULL) { guint16 release; release = g_usb_device_get_release (device); version = as_utils_version_from_uint16 (release, AS_VERSION_PARSE_FLAG_NONE); } fu_device_set_version (dev, version); /* get GUID, falling back to the USB VID:PID hash */ idx = g_usb_device_get_custom_index (device, G_USB_DEVICE_CLASS_VENDOR_SPECIFIC, 'G', 'U', NULL); if (idx != 0x00) guid = g_usb_device_get_string_descriptor (device, idx, NULL); if (guid == NULL) { g_autofree gchar *vid_pid = NULL; vid_pid = g_strdup_printf ("USB\\VID_%04X&PID_%04X", g_usb_device_get_vid (device), g_usb_device_get_pid (device)); guid = as_utils_guid_from_string (vid_pid); } fu_device_set_guid (dev, guid); /* we're done here */ if (!g_usb_device_close (device, &error)) g_debug ("Failed to close: %s", error->message); /* insert to hash */ fu_provider_device_add (FU_PROVIDER (provider_usb), dev); g_hash_table_insert (priv->devices, g_strdup (platform_id), g_object_ref (dev)); } typedef struct { FuProviderUsb *provider_usb; GUsbDevice *device; } FuProviderUsbHelper; /** * fu_provider_usb_device_added_delay_cb: **/ static gboolean fu_provider_usb_device_added_delay_cb (gpointer user_data) { FuProviderUsbHelper *helper = (FuProviderUsbHelper *) user_data; fu_provider_usb_device_added (helper->provider_usb, helper->device); g_object_unref (helper->provider_usb); g_object_unref (helper->device); g_free (helper); return FALSE; } /** * fu_provider_usb_device_added_cb: **/ static void fu_provider_usb_device_added_cb (GUsbContext *ctx, GUsbDevice *device, FuProviderUsb *provider_usb) { FuProviderUsbPrivate *priv = GET_PRIVATE (provider_usb); /* use a small delay for hotplugging so that other, better, providers * can claim this interface and add the FuDevice */ if (priv->done_enumerate) { FuProviderUsbHelper *helper; g_debug ("waiting a small time for other providers"); helper = g_new0 (FuProviderUsbHelper, 1); helper->provider_usb = g_object_ref (provider_usb); helper->device = g_object_ref (device); g_timeout_add (500, fu_provider_usb_device_added_delay_cb, helper); return; } fu_provider_usb_device_added (provider_usb, device); } /** * fu_provider_usb_device_removed_cb: **/ static void fu_provider_usb_device_removed_cb (GUsbContext *ctx, GUsbDevice *device, FuProviderUsb *provider_usb) { FuProviderUsbPrivate *priv = GET_PRIVATE (provider_usb); FuDevice *dev; const gchar *platform_id = NULL; /* already in database */ platform_id = g_usb_device_get_platform_id (device); dev = g_hash_table_lookup (priv->devices, platform_id); if (dev == NULL) return; fu_provider_device_remove (FU_PROVIDER (provider_usb), dev); g_hash_table_remove (priv->devices, platform_id); } /** * fu_provider_usb_coldplug: **/ static gboolean fu_provider_usb_coldplug (FuProvider *provider, GError **error) { FuProviderUsb *provider_usb = FU_PROVIDER_USB (provider); FuProviderUsbPrivate *priv = GET_PRIVATE (provider_usb); g_usb_context_enumerate (priv->usb_ctx); priv->done_enumerate = TRUE; return TRUE; } /** * fu_provider_usb_class_init: **/ static void fu_provider_usb_class_init (FuProviderUsbClass *klass) { FuProviderClass *provider_class = FU_PROVIDER_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); provider_class->get_name = fu_provider_usb_get_name; provider_class->coldplug = fu_provider_usb_coldplug; object_class->finalize = fu_provider_usb_finalize; } /** * fu_provider_usb_init: **/ static void fu_provider_usb_init (FuProviderUsb *provider_usb) { FuProviderUsbPrivate *priv = GET_PRIVATE (provider_usb); priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref); priv->usb_ctx = g_usb_context_new (NULL); g_signal_connect (priv->usb_ctx, "device-added", G_CALLBACK (fu_provider_usb_device_added_cb), provider_usb); g_signal_connect (priv->usb_ctx, "device-removed", G_CALLBACK (fu_provider_usb_device_removed_cb), provider_usb); } /** * fu_provider_usb_finalize: **/ static void fu_provider_usb_finalize (GObject *object) { FuProviderUsb *provider_usb = FU_PROVIDER_USB (object); FuProviderUsbPrivate *priv = GET_PRIVATE (provider_usb); g_hash_table_unref (priv->devices); g_object_unref (priv->usb_ctx); G_OBJECT_CLASS (fu_provider_usb_parent_class)->finalize (object); } /** * fu_provider_usb_new: **/ FuProvider * fu_provider_usb_new (void) { FuProviderUsb *provider; provider = g_object_new (FU_TYPE_PROVIDER_USB, NULL); return FU_PROVIDER (provider); } fwupd-0.7.0/src/fu-provider-usb.h000066400000000000000000000025341267747510300166540ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __FU_PROVIDER_USB_H #define __FU_PROVIDER_USB_H #include #include "fu-device.h" #include "fu-provider.h" G_BEGIN_DECLS #define FU_TYPE_PROVIDER_USB (fu_provider_usb_get_type ()) G_DECLARE_DERIVABLE_TYPE (FuProviderUsb, fu_provider_usb, FU, PROVIDER_USB, FuProvider) struct _FuProviderUsbClass { FuProviderClass parent_class; }; FuProvider *fu_provider_usb_new (void); G_END_DECLS #endif /* __FU_PROVIDER_USB_H */ fwupd-0.7.0/src/fu-provider.c000066400000000000000000000322311267747510300160550ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015-2016 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include #include #include "fu-device.h" #include "fu-pending.h" #include "fu-plugin.h" #include "fu-provider-uefi.h" static void fu_provider_finalize (GObject *object); enum { SIGNAL_DEVICE_ADDED, SIGNAL_DEVICE_REMOVED, SIGNAL_STATUS_CHANGED, SIGNAL_LAST }; static guint signals[SIGNAL_LAST] = { 0 }; G_DEFINE_TYPE (FuProvider, fu_provider, G_TYPE_OBJECT) /** * fu_provider_offline_invalidate: **/ static gboolean fu_provider_offline_invalidate (GError **error) { g_autoptr(GError) error_local = NULL; g_autoptr(GFile) file1 = NULL; g_return_val_if_fail (error == NULL || *error == NULL, FALSE); file1 = g_file_new_for_path (FU_OFFLINE_TRIGGER_FILENAME); if (!g_file_query_exists (file1, NULL)) return TRUE; if (!g_file_delete (file1, NULL, &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "Cannot delete %s: %s", FU_OFFLINE_TRIGGER_FILENAME, error_local->message); return FALSE; } return TRUE; } /** * fu_provider_offline_setup: **/ static gboolean fu_provider_offline_setup (GError **error) { gint rc; g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* create symlink for the systemd-system-update-generator */ rc = symlink ("/var/lib/fwupd", FU_OFFLINE_TRIGGER_FILENAME); if (rc < 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "Failed to create symlink %s to %s: %s", FU_OFFLINE_TRIGGER_FILENAME, "/var/lib", strerror (errno)); return FALSE; } return TRUE; } /** * fu_provider_coldplug: **/ gboolean fu_provider_coldplug (FuProvider *provider, GError **error) { FuProviderClass *klass = FU_PROVIDER_GET_CLASS (provider); if (klass->coldplug != NULL) return klass->coldplug (provider, error); return TRUE; } /** * fu_provider_schedule_update: **/ static gboolean fu_provider_schedule_update (FuProvider *provider, FuDevice *device, GBytes *blob_cab, GError **error) { gchar tmpname[] = {"XXXXXX.cap"}; guint i; g_autofree gchar *dirname = NULL; g_autofree gchar *filename = NULL; g_autoptr(FwupdResult) res_tmp = NULL; g_autoptr(FuPending) pending = NULL; g_autoptr(GFile) file = NULL; /* id already exists */ pending = fu_pending_new (); res_tmp = fu_pending_get_device (pending, fu_device_get_id (device), NULL); if (res_tmp != NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_ALREADY_PENDING, "%s is already scheduled to be updated", fu_device_get_id (device)); return FALSE; } /* create directory */ dirname = g_build_filename (LOCALSTATEDIR, "lib", "fwupd", NULL); file = g_file_new_for_path (dirname); if (!g_file_query_exists (file, NULL)) { if (!g_file_make_directory_with_parents (file, NULL, error)) return FALSE; } /* get a random filename */ for (i = 0; i < 6; i++) tmpname[i] = g_random_int_range ('A', 'Z'); filename = g_build_filename (dirname, tmpname, NULL); /* just copy to the temp file */ fu_provider_set_status (provider, FWUPD_STATUS_SCHEDULING); if (!g_file_set_contents (filename, g_bytes_get_data (blob_cab, NULL), g_bytes_get_size (blob_cab), error)) return FALSE; /* schedule for next boot */ g_debug ("schedule %s to be installed to %s on next boot", filename, fu_device_get_id (device)); fu_device_set_update_filename (device, filename); /* add to database */ if (!fu_pending_add_device (pending, FWUPD_RESULT (device), error)) return FALSE; /* next boot we run offline */ return fu_provider_offline_setup (error); } /** * fu_provider_verify: **/ gboolean fu_provider_verify (FuProvider *provider, FuDevice *device, FuProviderVerifyFlags flags, GError **error) { FuProviderClass *klass = FU_PROVIDER_GET_CLASS (provider); if (klass->verify != NULL) return klass->verify (provider, device, flags, error); return TRUE; } /** * fu_provider_unlock: **/ gboolean fu_provider_unlock (FuProvider *provider, FuDevice *device, GError **error) { guint64 flags; FuProviderClass *klass = FU_PROVIDER_GET_CLASS (provider); /* final check */ flags = fu_device_get_flags (device); if ((flags & FU_DEVICE_FLAG_LOCKED) == 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "Device %s is not locked", fu_device_get_id (device)); return FALSE; } /* run provider method */ if (klass->unlock != NULL) { if (!klass->unlock (provider, device, error)) return FALSE; } /* update with correct flags */ fu_device_set_flags (device, flags &= ~FU_DEVICE_FLAG_LOCKED); fu_device_set_modified (device, g_get_real_time () / G_USEC_PER_SEC); return TRUE; } /** * fu_provider_update: **/ gboolean fu_provider_update (FuProvider *provider, FuDevice *device, GBytes *blob_cab, GBytes *blob_fw, FuPlugin *plugin, FwupdInstallFlags flags, GError **error) { FuProviderClass *klass = FU_PROVIDER_GET_CLASS (provider); g_autoptr(FuPending) pending = NULL; g_autoptr(FwupdResult) res_pending = NULL; GError *error_update = NULL; /* schedule for next reboot, or handle in the provider */ if (flags & FWUPD_INSTALL_FLAG_OFFLINE) { if (klass->update_offline == NULL) return fu_provider_schedule_update (provider, device, blob_cab, error); return klass->update_offline (provider, device, blob_fw, flags, error); } /* cancel the pending action */ if (!fu_provider_offline_invalidate (error)) return FALSE; /* we have support using a plugin */ if (plugin != NULL) { return fu_plugin_run_device_update (plugin, device, blob_fw, error); } /* online */ if (klass->update_online == NULL) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "No online update possible"); return FALSE; } pending = fu_pending_new (); res_pending = fu_pending_get_device (pending, fu_device_get_id (device), NULL); if (!klass->update_online (provider, device, blob_fw, flags, &error_update)) { /* save the error to the database */ if (res_pending != NULL) { fu_pending_set_error_msg (pending, FWUPD_RESULT (device), error_update->message, NULL); } g_propagate_error (error, error_update); return FALSE; } /* cleanup */ if (res_pending != NULL) { const gchar *tmp; /* update pending database */ fu_pending_set_state (pending, FWUPD_RESULT (device), FWUPD_UPDATE_STATE_SUCCESS, NULL); /* delete cab file */ tmp = fwupd_result_get_update_filename (res_pending); if (tmp != NULL && g_str_has_prefix (tmp, LIBEXECDIR)) { g_autoptr(GError) error_local = NULL; g_autoptr(GFile) file = NULL; file = g_file_new_for_path (tmp); if (!g_file_delete (file, NULL, &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Failed to delete %s: %s", tmp, error_local->message); return FALSE; } } } return TRUE; } /** * fu_provider_clear_results: **/ gboolean fu_provider_clear_results (FuProvider *provider, FuDevice *device, GError **error) { FuProviderClass *klass = FU_PROVIDER_GET_CLASS (provider); g_autoptr(GError) error_local = NULL; g_autoptr(FwupdResult) res_pending = NULL; g_autoptr(FuPending) pending = NULL; /* handled by the provider */ if (klass->clear_results != NULL) return klass->clear_results (provider, device, error); /* handled using the database */ pending = fu_pending_new (); res_pending = fu_pending_get_device (pending, fu_device_get_id (device), &error_local); if (res_pending == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Failed to find %s in pending database: %s", fu_device_get_id (device), error_local->message); return FALSE; } /* remove from pending database */ return fu_pending_remove_device (pending, FWUPD_RESULT (device), error); } /** * fu_provider_get_results: **/ gboolean fu_provider_get_results (FuProvider *provider, FuDevice *device, GError **error) { FuProviderClass *klass = FU_PROVIDER_GET_CLASS (provider); FwupdUpdateState update_state; const gchar *tmp; g_autoptr(GError) error_local = NULL; g_autoptr(FwupdResult) res_pending = NULL; g_autoptr(FuPending) pending = NULL; /* handled by the provider */ if (klass->get_results != NULL) return klass->get_results (provider, device, error); /* handled using the database */ pending = fu_pending_new (); res_pending = fu_pending_get_device (pending, fu_device_get_id (device), &error_local); if (res_pending == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO, "Failed to find %s in pending database: %s", fu_device_get_id (device), error_local->message); return FALSE; } /* copy the important parts from the pending device to the real one */ update_state = fwupd_result_get_update_state (res_pending); if (update_state == FWUPD_UPDATE_STATE_UNKNOWN || update_state == FWUPD_UPDATE_STATE_PENDING) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO, "Device %s has not been updated offline yet", fu_device_get_id (device)); return FALSE; } /* copy */ fu_device_set_update_state (device, update_state); tmp = fwupd_result_get_update_error (res_pending); if (tmp != NULL) fu_device_set_update_error (device, tmp); tmp = fwupd_result_get_device_version (res_pending); if (tmp != NULL) fu_device_set_version (device, tmp); tmp = fwupd_result_get_update_version (res_pending); if (tmp != NULL) fu_device_set_update_version (device, tmp); return TRUE; } /** * fu_provider_get_name: **/ const gchar * fu_provider_get_name (FuProvider *provider) { FuProviderClass *klass = FU_PROVIDER_GET_CLASS (provider); if (klass->get_name != NULL) return klass->get_name (provider); return NULL; } /** * fu_provider_device_add: **/ void fu_provider_device_add (FuProvider *provider, FuDevice *device) { g_debug ("emit added from %s: %s", fu_provider_get_name (provider), fu_device_get_id (device)); fu_device_set_created (device, g_get_real_time () / G_USEC_PER_SEC); fu_device_set_provider (device, fu_provider_get_name (provider)); g_signal_emit (provider, signals[SIGNAL_DEVICE_ADDED], 0, device); } /** * fu_provider_device_remove: **/ void fu_provider_device_remove (FuProvider *provider, FuDevice *device) { g_debug ("emit removed from %s: %s", fu_provider_get_name (provider), fu_device_get_id (device)); g_signal_emit (provider, signals[SIGNAL_DEVICE_REMOVED], 0, device); } /** * fu_provider_set_status: **/ void fu_provider_set_status (FuProvider *provider, FwupdStatus status) { g_signal_emit (provider, signals[SIGNAL_STATUS_CHANGED], 0, status); } /** * fu_provider_get_checksum_type: **/ GChecksumType fu_provider_get_checksum_type (FuProviderVerifyFlags flags) { if (flags & FU_PROVIDER_VERIFY_FLAG_USE_SHA256) return G_CHECKSUM_SHA256; return G_CHECKSUM_SHA1; } /** * fu_provider_class_init: **/ static void fu_provider_class_init (FuProviderClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = fu_provider_finalize; signals[SIGNAL_DEVICE_ADDED] = g_signal_new ("device-added", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (FuProviderClass, device_added), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, FU_TYPE_DEVICE); signals[SIGNAL_DEVICE_REMOVED] = g_signal_new ("device-removed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (FuProviderClass, device_removed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, FU_TYPE_DEVICE); signals[SIGNAL_STATUS_CHANGED] = g_signal_new ("status-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (FuProviderClass, status_changed), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); } /** * fu_provider_init: **/ static void fu_provider_init (FuProvider *provider) { } /** * fu_provider_finalize: **/ static void fu_provider_finalize (GObject *object) { G_OBJECT_CLASS (fu_provider_parent_class)->finalize (object); } fwupd-0.7.0/src/fu-provider.h000066400000000000000000000073261267747510300160710ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015-2016 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __FU_PROVIDER_H #define __FU_PROVIDER_H #include #include "fu-device.h" #include "fu-plugin.h" #include "fu-provider.h" G_BEGIN_DECLS #define FU_TYPE_PROVIDER (fu_provider_get_type ()) G_DECLARE_DERIVABLE_TYPE (FuProvider, fu_provider, FU, PROVIDER, GObject) typedef enum { FU_PROVIDER_VERIFY_FLAG_NONE = 0, FU_PROVIDER_VERIFY_FLAG_USE_SHA256 = 1 << 0, FU_PROVIDER_VERIFY_FLAG_LAST } FuProviderVerifyFlags; struct _FuProviderClass { GObjectClass parent_class; /* vfunc */ const gchar *(*get_name) (FuProvider *provider); gboolean (*coldplug) (FuProvider *provider, GError **error); gboolean (*verify) (FuProvider *provider, FuDevice *device, FuProviderVerifyFlags flags, GError **error); gboolean (*unlock) (FuProvider *provider, FuDevice *device, GError **error); gboolean (*update_online) (FuProvider *provider, FuDevice *device, GBytes *blob_fw, FwupdInstallFlags flags, GError **error); gboolean (*update_offline) (FuProvider *provider, FuDevice *device, GBytes *blob_fw, FwupdInstallFlags flags, GError **error); gboolean (*clear_results) (FuProvider *provider, FuDevice *device, GError **error); gboolean (*get_results) (FuProvider *provider, FuDevice *device, GError **error); /* signals */ void (* device_added) (FuProvider *provider, FuDevice *device); void (* device_removed) (FuProvider *provider, FuDevice *device); void (* status_changed) (FuProvider *provider, FwupdStatus status); }; #define FU_OFFLINE_TRIGGER_FILENAME FU_OFFLINE_DESTDIR "/system-update" void fu_provider_device_add (FuProvider *provider, FuDevice *device); void fu_provider_device_remove (FuProvider *provider, FuDevice *device); void fu_provider_set_status (FuProvider *provider, FwupdStatus status); const gchar *fu_provider_get_name (FuProvider *provider); gboolean fu_provider_coldplug (FuProvider *provider, GError **error); gboolean fu_provider_update (FuProvider *provider, FuDevice *device, GBytes *blob_cab, GBytes *blob_fw, FuPlugin *plugin, FwupdInstallFlags flags, GError **error); gboolean fu_provider_verify (FuProvider *provider, FuDevice *device, FuProviderVerifyFlags flags, GError **error); gboolean fu_provider_unlock (FuProvider *provider, FuDevice *device, GError **error); gboolean fu_provider_clear_results (FuProvider *provider, FuDevice *device, GError **error); gboolean fu_provider_get_results (FuProvider *provider, FuDevice *device, GError **error); GChecksumType fu_provider_get_checksum_type (FuProviderVerifyFlags flags); G_END_DECLS #endif /* __FU_PROVIDER_H */ fwupd-0.7.0/src/fu-quirks.h000066400000000000000000000026211267747510300155460ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2016 Mario Limonciello * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __FU_QUIRKS_H #define __FU_QUIRKS_H typedef struct { const gchar *sys_vendor; const gchar *identifier; AsVersionParseFlag flags; } FuVendorQuirks; static const FuVendorQuirks quirk_table[] = { /* Dell & Alienware use AA.BB.CC.DD rather than AA.BB.CCDD */ { "Dell Inc.", "com.dell.uefi", AS_VERSION_PARSE_FLAG_NONE }, { "Alienware", "com.dell.uefi", AS_VERSION_PARSE_FLAG_NONE }, { NULL, NULL, AS_VERSION_PARSE_FLAG_NONE } }; #endif /* __FU_QUIRKS_H */ fwupd-0.7.0/src/fu-rom.c000066400000000000000000000572061267747510300150310ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include #include "fu-rom.h" static void fu_rom_finalize (GObject *object); /* data from http://resources.infosecinstitute.com/pci-expansion-rom/ */ typedef struct { guint8 *rom_data; guint32 rom_len; guint32 rom_offset; guint32 entry_point; guint8 reserved[18]; guint16 cpi_ptr; guint16 vendor_id; guint16 device_id; guint16 device_list_ptr; guint16 data_len; guint8 data_rev; guint32 class_code; guint32 image_len; guint16 revision_level; guint8 code_type; guint8 last_image; guint32 max_runtime_len; guint16 config_header_ptr; guint16 dmtf_clp_ptr; } FuRomPciHeader; /** * FuRomPrivate: * * Private #FuRom data **/ typedef struct { GChecksum *checksum_wip; GChecksumType checksum_type; GInputStream *stream; FuRomKind kind; gchar *version; gchar *guid; guint16 vendor_id; guint16 device_id; GPtrArray *hdrs; /* of FuRomPciHeader */ } FuRomPrivate; G_DEFINE_TYPE_WITH_PRIVATE (FuRom, fu_rom, G_TYPE_OBJECT) #define GET_PRIVATE(o) (fu_rom_get_instance_private (o)) /** * fu_rom_pci_header_free: **/ static void fu_rom_pci_header_free (FuRomPciHeader *hdr) { g_free (hdr->rom_data); g_free (hdr); } /** * fu_rom_kind_to_string: **/ const gchar * fu_rom_kind_to_string (FuRomKind kind) { if (kind == FU_ROM_KIND_UNKNOWN) return "unknown"; if (kind == FU_ROM_KIND_ATI) return "ati"; if (kind == FU_ROM_KIND_NVIDIA) return "nvidia"; if (kind == FU_ROM_KIND_INTEL) return "intel"; if (kind == FU_ROM_KIND_PCI) return "pci"; return NULL; } /** * fu_rom_pci_strstr: **/ static guint8 * fu_rom_pci_strstr (FuRomPciHeader *hdr, const gchar *needle) { guint i; guint needle_len; guint8 *haystack; gsize haystack_len; if (needle == NULL || needle[0] == '\0') return NULL; if (hdr->rom_data == NULL) return NULL; if (hdr->data_len > hdr->rom_len) return NULL; haystack = &hdr->rom_data[hdr->data_len]; haystack_len = hdr->rom_len - hdr->data_len; needle_len = strlen (needle); if (needle_len > haystack_len) return NULL; for (i = 0; i < haystack_len - needle_len; i++) { if (memcmp (haystack + i, needle, needle_len) == 0) return &haystack[i]; } return NULL; } /** * fu_rom_blank_serial_numbers: **/ static guint fu_rom_blank_serial_numbers (guint8 *buffer, guint buffer_sz) { guint i; for (i = 0; i < buffer_sz; i++) { if (buffer[i] == 0xff || buffer[i] == '\0' || buffer[i] == '\n' || buffer[i] == '\r') break; buffer[i] = '\0'; } return i; } /** * fu_rom_get_hex_dump: **/ static gchar * fu_rom_get_hex_dump (guint8 *buffer, gssize sz) { GString *str = NULL; guint i; str = g_string_new (""); if (sz <= 0) return NULL; for (i = 0; i < (guint) sz; i++) g_string_append_printf (str, "%02x ", buffer[i]); g_string_append (str, " "); for (i = 0; i < (guint) sz; i++) { gchar tmp = '?'; if (g_ascii_isprint (buffer[i])) tmp = buffer[i]; g_string_append_printf (str, "%c", tmp); } return g_string_free (str, FALSE); } typedef struct { guint8 segment_kind; guint8 *data; guint16 data_len; guint16 next_offset; } FooRomPciCertificateHdr; /** * fu_rom_pci_print_certificate_data: **/ static void fu_rom_pci_print_certificate_data (guint8 *buffer, gssize sz) { guint16 off = 0; g_autofree gchar *hdr_str = NULL; /* 27 byte header, unknown purpose */ hdr_str = fu_rom_get_hex_dump (buffer+off, 27); g_debug (" ISBN header: %s", hdr_str); buffer += 27; while (TRUE) { /* 29 byte header to the segment, then data: * 0x01 = type. 0x1 = certificate, 0x2 = hashes? * 0x13,0x14 = offset to next segment */ FooRomPciCertificateHdr h; g_autofree gchar *segment_str = NULL; segment_str = fu_rom_get_hex_dump (buffer+off, 29); g_debug (" ISBN segment @%02x: %s", off, segment_str); h.segment_kind = buffer[off+1]; h.next_offset = ((guint16) buffer[off+14] << 8) + buffer[off+13]; h.data = &buffer[off+29]; /* calculate last block length automatically */ if (h.next_offset == 0) h.data_len = sz - off - 29 - 27; else h.data_len = h.next_offset - off - 29; /* print the certificate */ if (h.segment_kind == 0x01) { g_autofree gchar *tmp = NULL; tmp = fu_rom_get_hex_dump (h.data, h.data_len); g_debug ("%s(%i)", tmp, h.data_len); } else if (h.segment_kind == 0x02) { g_autofree gchar *tmp = NULL; tmp = fu_rom_get_hex_dump (h.data, h.data_len < 32 ? h.data_len : 32); g_debug ("%s(%i)", tmp, h.data_len); } else { g_warning ("unknown segment kind %i", h.segment_kind); } /* last block */ if (h.next_offset == 0x0000) break; off = h.next_offset; } } /** * fu_rom_pci_code_type_to_string: **/ static const gchar * fu_rom_pci_code_type_to_string (guint8 code_type) { if (code_type == 0) return "Intel86"; if (code_type == 1) return "OpenFirmware"; if (code_type == 2) return "PA-RISC"; if (code_type == 3) return "EFI"; return "reserved"; } /** * fu_rom_pci_header_get_checksum: **/ static guint8 fu_rom_pci_header_get_checksum (FuRomPciHeader *hdr) { guint8 chksum_check = 0x00; guint i; for (i = 0; i < hdr->rom_len; i++) chksum_check += hdr->rom_data[i]; return chksum_check; } /** * fu_rom_pci_print_header: **/ static void fu_rom_pci_print_header (FuRomPciHeader *hdr) { guint8 chksum_check; guint8 *buffer; g_autofree gchar *data_str = NULL; g_autofree gchar *reserved_str = NULL; g_debug ("PCI Header"); g_debug (" RomOffset: 0x%04x", hdr->rom_offset); g_debug (" RomSize: 0x%04x", hdr->rom_len); g_debug (" EntryPnt: 0x%06x", hdr->entry_point); reserved_str = fu_rom_get_hex_dump (hdr->reserved, 18); g_debug (" Reserved: %s", reserved_str); g_debug (" CpiPtr: 0x%04x", hdr->cpi_ptr); /* print the data */ buffer = &hdr->rom_data[hdr->cpi_ptr]; g_debug (" PCI Data"); g_debug (" VendorID: 0x%04x", hdr->vendor_id); g_debug (" DeviceID: 0x%04x", hdr->device_id); g_debug (" DevList: 0x%04x", hdr->device_list_ptr); g_debug (" DataLen: 0x%04x", hdr->data_len); g_debug (" DataRev: 0x%04x", hdr->data_rev); if (hdr->image_len < 0x0f) { data_str = fu_rom_get_hex_dump (&buffer[hdr->data_len], hdr->image_len); g_debug (" ImageLen: 0x%04x [%s]", hdr->image_len, data_str); } else { data_str = fu_rom_get_hex_dump (&buffer[hdr->data_len], 0x0f); g_debug (" ImageLen: 0x%04x [%s...]", hdr->image_len, data_str); } g_debug (" RevLevel: 0x%04x", hdr->revision_level); g_debug (" CodeType: 0x%02x [%s]", hdr->code_type, fu_rom_pci_code_type_to_string (hdr->code_type)); g_debug (" LastImg: 0x%02x [%s]", hdr->last_image, hdr->last_image == 0x80 ? "yes" : "no"); g_debug (" MaxRunLen: 0x%04x", hdr->max_runtime_len); g_debug (" ConfigHdr: 0x%04x", hdr->config_header_ptr); g_debug (" ClpPtr: 0x%04x", hdr->dmtf_clp_ptr); /* dump the ISBN */ if (hdr->code_type == 0x70 && memcmp (&buffer[hdr->data_len], "ISBN", 4) == 0) { fu_rom_pci_print_certificate_data (&buffer[hdr->data_len], hdr->image_len); } /* verify the checksum byte */ if (hdr->image_len <= hdr->rom_len && hdr->image_len > 0) { buffer = hdr->rom_data; chksum_check = fu_rom_pci_header_get_checksum (hdr); if (chksum_check == 0x00) { g_debug (" ChkSum: 0x%02x [valid]", buffer[hdr->image_len-1]); } else { g_debug (" ChkSum: 0x%02x [failed, got 0x%02x]", buffer[hdr->image_len-1], chksum_check); } } else { g_debug (" ChkSum: 0x?? [unknown]"); } } /** * fu_rom_extract_all: **/ gboolean fu_rom_extract_all (FuRom *rom, const gchar *path, GError **error) { FuRomPrivate *priv = GET_PRIVATE (rom); FuRomPciHeader *hdr; guint i; for (i = 0; i < priv->hdrs->len; i++) { g_autofree gchar *fn = NULL; hdr = g_ptr_array_index (priv->hdrs, i); fn = g_strdup_printf ("%s/%02i.bin", path, i); g_debug ("dumping ROM #%i at 0x%04x [0x%02x] to %s", i, hdr->rom_offset, hdr->rom_len, fn); if (hdr->rom_len == 0) continue; if (!g_file_set_contents (fn, (const gchar *) hdr->rom_data, (gssize) hdr->rom_len, error)) return FALSE; } return TRUE; } /** * fu_rom_find_and_blank_serial_numbers: **/ static void fu_rom_find_and_blank_serial_numbers (FuRom *rom) { FuRomPrivate *priv = GET_PRIVATE (rom); FuRomPciHeader *hdr; guint i; guint8 *tmp; /* bail if not likely */ if (priv->kind == FU_ROM_KIND_PCI || priv->kind == FU_ROM_KIND_INTEL) { g_debug ("no serial numbers likely"); return; } for (i = 0; i < priv->hdrs->len; i++) { hdr = g_ptr_array_index (priv->hdrs, i); g_debug ("looking for PPID at 0x%04x", hdr->rom_offset); tmp = fu_rom_pci_strstr (hdr, "PPID"); if (tmp != NULL) { guint len; guint8 chk; len = fu_rom_blank_serial_numbers (tmp, hdr->rom_len - hdr->data_len); g_debug ("cleared %i chars @ 0x%04lx", len, tmp - &hdr->rom_data[hdr->data_len]); /* we have to fix the checksum */ chk = fu_rom_pci_header_get_checksum (hdr); hdr->rom_data[hdr->rom_len - 1] -= chk; fu_rom_pci_print_header (hdr); } } } /** * fu_rom_pci_get_data: **/ static gboolean fu_rom_pci_parse_data (FuRomPciHeader *hdr) { guint8 *buffer; /* check valid */ if (hdr == NULL || hdr->cpi_ptr == 0x0000) { g_debug ("No PCI DATA @ 0x%04x", hdr->rom_offset); return FALSE; } if (hdr->rom_len > 0 && hdr->cpi_ptr > hdr->rom_len) { g_debug ("Invalid PCI DATA @ 0x%04x", hdr->rom_offset); return FALSE; } /* gahh, CPI is out of the first chunk */ if (hdr->cpi_ptr > hdr->rom_len) { g_debug ("No available PCI DATA @ 0x%04x : 0x%04x > 0x%04x", hdr->rom_offset, hdr->cpi_ptr, hdr->rom_len); return FALSE; } /* check signature */ buffer = &hdr->rom_data[hdr->cpi_ptr]; if (memcmp (buffer, "PCIR", 4) != 0) { if (memcmp (buffer, "RGIS", 4) == 0 || memcmp (buffer, "NPDS", 4) == 0 || memcmp (buffer, "NPDE", 4) == 0) { g_debug ("-- using NVIDIA DATA quirk"); } else { g_debug ("Not PCI DATA: %02x%02x%02x%02x [%c%c%c%c]", buffer[0], buffer[1], buffer[2], buffer[3], buffer[0], buffer[1], buffer[2], buffer[3]); return FALSE; } } /* parse */ hdr->vendor_id = ((guint16) buffer[0x05] << 8) + buffer[0x04]; hdr->device_id = ((guint16) buffer[0x07] << 8) + buffer[0x06]; hdr->device_list_ptr = ((guint16) buffer[0x09] << 8) + buffer[0x08]; hdr->data_len = ((guint16) buffer[0x0b] << 8) + buffer[0x0a]; hdr->data_rev = buffer[0x0c]; hdr->class_code = ((guint16) buffer[0x0f] << 16) + ((guint16) buffer[0x0e] << 8) + buffer[0x0d]; hdr->image_len = (((guint16) buffer[0x11] << 8) + buffer[0x10]) * 512; hdr->revision_level = ((guint16) buffer[0x13] << 8) + buffer[0x12]; hdr->code_type = buffer[0x14]; hdr->last_image = buffer[0x15]; hdr->max_runtime_len = (((guint16) buffer[0x17] << 8) + buffer[0x16]) * 512; hdr->config_header_ptr = ((guint16) buffer[0x19] << 8) + buffer[0x18]; hdr->dmtf_clp_ptr = ((guint16) buffer[0x1b] << 8) + buffer[0x1a]; return TRUE; } /** * fu_rom_pci_get_header: **/ static FuRomPciHeader * fu_rom_pci_get_header (guint8 *buffer, gssize sz) { FuRomPciHeader *hdr; /* check signature */ if (memcmp (buffer, "\x55\xaa", 2) != 0) { if (memcmp (buffer, "\x56\x4e", 2) == 0) { g_debug ("-- using NVIDIA ROM quirk"); } else { g_autofree gchar *sig_str = NULL; sig_str = fu_rom_get_hex_dump (buffer, 16); g_debug ("Not PCI ROM %s", sig_str); return NULL; } } /* decode structure */ hdr = g_new0 (FuRomPciHeader, 1); hdr->rom_len = buffer[0x02] * 512; /* fix up misreporting */ if (hdr->rom_len == 0) { g_debug ("fixing up last image size"); hdr->rom_len = sz; } /* copy this locally to the header */ hdr->rom_data = g_memdup (buffer, hdr->rom_len); /* parse out CPI */ hdr->entry_point = ((guint32) buffer[0x05] << 16) + ((guint16) buffer[0x04] << 8) + buffer[0x03]; memcpy (&hdr->reserved, &buffer[6], 18); hdr->cpi_ptr = ((guint16) buffer[0x19] << 8) + buffer[0x18]; /* parse the header data */ g_debug ("looking for PCI DATA @ 0x%04x", hdr->cpi_ptr); fu_rom_pci_parse_data (hdr); return hdr; } /** * fu_rom_find_version_pci: **/ static gchar * fu_rom_find_version_pci (FuRomPciHeader *hdr) { gchar *str; /* ARC storage */ if (memcmp (hdr->reserved, "\0\0ARC", 5) == 0) { str = (gchar *) fu_rom_pci_strstr (hdr, "BIOS: "); if (str != NULL) return g_strdup (str + 6); } return NULL; } /** * fu_rom_find_version_nvidia: **/ static gchar * fu_rom_find_version_nvidia (FuRomPciHeader *hdr) { gchar *str; /* static location for some firmware */ if (memcmp (hdr->rom_data + 0x013d, "Version ", 8) == 0) return g_strdup ((gchar *) &hdr->rom_data[0x013d + 8]); /* usual search string */ str = (gchar *) fu_rom_pci_strstr (hdr, "Version "); if (str != NULL) return g_strdup (str + 8); /* broken */ str = (gchar *) fu_rom_pci_strstr (hdr, "Vension:"); if (str != NULL) return g_strdup (str + 8); str = (gchar *) fu_rom_pci_strstr (hdr, "Version"); if (str != NULL) return g_strdup (str + 7); /* fallback to VBIOS */ if (memcmp (hdr->rom_data + 0xfa, "VBIOS Ver", 9) == 0) return g_strdup ((gchar *) &hdr->rom_data[0xfa + 9]); return NULL; } /** * fu_rom_find_version_intel: **/ static gchar * fu_rom_find_version_intel (FuRomPciHeader *hdr) { gchar *str; /* 2175_RYan PC 14.34 06/06/2013 21:27:53 */ str = (gchar *) fu_rom_pci_strstr (hdr, "Build Number:"); if (str != NULL) { guint i; g_auto(GStrv) split = NULL; split = g_strsplit (str + 14, " ", -1); for (i = 0; split[i] != NULL; i++) { if (g_strstr_len (split[i], -1, ".") == NULL) continue; return g_strdup (split[i]); } } /* fallback to VBIOS */ str = (gchar *) fu_rom_pci_strstr (hdr, "VBIOS "); if (str != NULL) return g_strdup (str + 6); return NULL; } /** * fu_rom_find_version_ati: **/ static gchar * fu_rom_find_version_ati (FuRomPciHeader *hdr) { gchar *str; str = (gchar *) fu_rom_pci_strstr (hdr, " VER0"); if (str != NULL) return g_strdup (str + 4); /* broken */ str = (gchar *) fu_rom_pci_strstr (hdr, " VR"); if (str != NULL) return g_strdup (str + 4); return NULL; } /** * fu_rom_find_version: **/ static gchar * fu_rom_find_version (FuRomKind kind, FuRomPciHeader *hdr) { if (kind == FU_ROM_KIND_PCI) return fu_rom_find_version_pci (hdr); if (kind == FU_ROM_KIND_NVIDIA) return fu_rom_find_version_nvidia (hdr); if (kind == FU_ROM_KIND_INTEL) return fu_rom_find_version_intel (hdr); if (kind == FU_ROM_KIND_ATI) return fu_rom_find_version_ati (hdr); return NULL; } /** * fu_rom_load_file: **/ gboolean fu_rom_load_file (FuRom *rom, GFile *file, FuRomLoadFlags flags, GCancellable *cancellable, GError **error) { FuRomPrivate *priv = GET_PRIVATE (rom); FuRomPciHeader *hdr = NULL; const gssize buffer_sz = 0x400000; gssize sz; guint32 jump = 0; guint hdr_sz = 0; guint i; guint number_reads = 0; g_autoptr(GError) error_local = NULL; g_autofree gchar *fn = NULL; g_autofree gchar *id = NULL; g_autofree guint8 *buffer = NULL; g_autoptr(GFileOutputStream) output_stream = NULL; g_autoptr(AsProfile) profile = as_profile_new (); g_autoptr(AsProfileTask) ptask = NULL; g_return_val_if_fail (FU_IS_ROM (rom), FALSE); /* open file */ ptask = as_profile_start_literal (profile, "FuRom:reading-data"); priv->stream = G_INPUT_STREAM (g_file_read (file, cancellable, &error_local)); if (priv->stream == NULL) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_AUTH_FAILED, error_local->message); return FALSE; } /* we have to enable the read for devices */ fn = g_file_get_path (file); if (g_str_has_prefix (fn, "/sys")) { output_stream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, cancellable, error); if (output_stream == NULL) return FALSE; if (g_output_stream_write (G_OUTPUT_STREAM (output_stream), "1", 1, cancellable, error) < 0) return FALSE; } /* read out the header */ buffer = g_malloc (buffer_sz); sz = g_input_stream_read (priv->stream, buffer, buffer_sz, cancellable, error); if (sz < 0) return FALSE; if (sz < 1024) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Firmware too small: %" G_GSSIZE_FORMAT " bytes", sz); return FALSE; } /* ensure we got enough data to fill the buffer */ while (sz < buffer_sz) { gssize sz_chunk; sz_chunk = g_input_stream_read (priv->stream, buffer + sz, buffer_sz - sz, cancellable, error); if (sz_chunk == 0) break; g_debug ("ROM returned 0x%04x bytes, adding 0x%04x...", (guint) sz, (guint) sz_chunk); if (sz_chunk < 0) return FALSE; sz += sz_chunk; /* check the firmware isn't serving us small chunks */ if (number_reads++ > 16) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "firmware not fulfilling requests"); return FALSE; } } g_debug ("ROM buffer filled %" G_GSSIZE_FORMAT "kb/%" G_GSSIZE_FORMAT "kb", sz / 0x400, buffer_sz / 0x400); /* detect optional IFR header and skip to option ROM */ if (memcmp (buffer, "NVGI", 4) == 0) hdr_sz = GUINT16_FROM_BE (buffer[0x15]); /* read all the ROM headers */ while (sz > hdr_sz + jump) { guint32 jump_sz; g_debug ("looking for PCI ROM @ 0x%04x", hdr_sz + jump); hdr = fu_rom_pci_get_header (&buffer[hdr_sz + jump], sz - hdr_sz - jump); if (hdr == NULL) { gboolean found_data = FALSE; /* check it's not just NUL padding */ for (i = 0; i < hdr_sz + jump; i++) { if (buffer[hdr_sz + jump + i] != 0x00) { found_data = TRUE; break; } } if (found_data) { g_debug ("found junk data, adding fake"); hdr = g_new0 (FuRomPciHeader, 1); hdr->vendor_id = 0x0000; hdr->device_id = 0x0000; hdr->code_type = 0x00; hdr->last_image = 0x80; hdr->rom_offset = hdr_sz + jump; hdr->rom_len = sz - hdr->rom_offset; hdr->rom_data = g_memdup (&buffer[hdr->rom_offset], hdr->rom_len); hdr->image_len = hdr->rom_len; g_ptr_array_add (priv->hdrs, hdr); } else { g_debug ("ignoring padding"); } break; } /* save this so we can fix checksums */ hdr->rom_offset = hdr_sz + jump; /* we can't break on hdr->last_image as * NVIDIA uses packed but not merged extended headers */ g_ptr_array_add (priv->hdrs, hdr); /* NVIDIA don't always set a ROM size for extensions */ jump_sz = hdr->rom_len; if (jump_sz == 0) jump_sz = hdr->image_len; if (jump_sz == 0x0) break; jump += jump_sz; } /* we found nothing */ if (priv->hdrs->len == 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Failed to detect firmware header [%02x%02x]", buffer[0], buffer[1]); return FALSE; } /* print all headers */ for (i = 0; i < priv->hdrs->len; i++) { hdr = g_ptr_array_index (priv->hdrs, i); fu_rom_pci_print_header (hdr); } /* find first ROM header */ hdr = g_ptr_array_index (priv->hdrs, 0); priv->vendor_id = hdr->vendor_id; priv->device_id = hdr->device_id; priv->kind = FU_ROM_KIND_PCI; /* detect intel header */ if (memcmp (hdr->reserved, "00000000000", 11) == 0) hdr_sz = (buffer[0x1b] << 8) + buffer[0x1a]; if (hdr_sz > sz) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "firmware corrupt (overflow)"); return FALSE; } if (memcmp (buffer + hdr_sz + 0x04, "K74", 3) == 0) { priv->kind = FU_ROM_KIND_NVIDIA; } else if (memcmp (buffer + hdr_sz, "$VBT", 4) == 0) { priv->kind = FU_ROM_KIND_INTEL; } else if (memcmp(buffer + 0x30, " 761295520", 10) == 0) { priv->kind = FU_ROM_KIND_ATI; } /* nothing */ if (priv->kind == FU_ROM_KIND_UNKNOWN) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Failed to detect firmware kind"); return FALSE; } /* find version string */ priv->version = fu_rom_find_version (priv->kind, hdr); if (priv->version != NULL) { g_strstrip (priv->version); g_strdelimit (priv->version, "\r\n ", '\0'); } /* update checksum */ if (flags & FU_ROM_LOAD_FLAG_BLANK_PPID) fu_rom_find_and_blank_serial_numbers (rom); for (i = 0; i < priv->hdrs->len; i++) { hdr = g_ptr_array_index (priv->hdrs, i); g_checksum_update (priv->checksum_wip, hdr->rom_data, hdr->rom_len); } /* update guid */ id = g_strdup_printf ("PCI\\VEN_%04X&DEV_%04X", priv->vendor_id, priv->device_id); priv->guid = as_utils_guid_from_string (id); g_debug ("using %s for %s", priv->guid, id); /* not known */ if (priv->version == NULL) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "Firmware version extractor not known"); return FALSE; } return TRUE; } /** * fu_rom_get_kind: **/ FuRomKind fu_rom_get_kind (FuRom *rom) { FuRomPrivate *priv = GET_PRIVATE (rom); g_return_val_if_fail (FU_IS_ROM (rom), FU_ROM_KIND_UNKNOWN); return priv->kind; } /** * fu_rom_get_version: **/ const gchar * fu_rom_get_version (FuRom *rom) { FuRomPrivate *priv = GET_PRIVATE (rom); g_return_val_if_fail (FU_IS_ROM (rom), NULL); return priv->version; } /** * fu_rom_get_guid: **/ const gchar * fu_rom_get_guid (FuRom *rom) { FuRomPrivate *priv = GET_PRIVATE (rom); g_return_val_if_fail (FU_IS_ROM (rom), NULL); return priv->guid; } /** * fu_rom_get_vendor: **/ guint16 fu_rom_get_vendor (FuRom *rom) { FuRomPrivate *priv = GET_PRIVATE (rom); g_return_val_if_fail (FU_IS_ROM (rom), 0x0000); return priv->vendor_id; } /** * fu_rom_get_model: **/ guint16 fu_rom_get_model (FuRom *rom) { FuRomPrivate *priv = GET_PRIVATE (rom); g_return_val_if_fail (FU_IS_ROM (rom), 0x0000); return priv->device_id; } /** * fu_rom_get_checksum: * * This returns the checksum of the firmware. **/ const gchar * fu_rom_get_checksum (FuRom *rom) { FuRomPrivate *priv = GET_PRIVATE (rom); return g_checksum_get_string (priv->checksum_wip); } /** * fu_rom_get_checksum_kind: **/ GChecksumType fu_rom_get_checksum_kind (FuRom *rom) { FuRomPrivate *priv = GET_PRIVATE (rom); return priv->checksum_type; } /** * fu_rom_class_init: **/ static void fu_rom_class_init (FuRomClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = fu_rom_finalize; } /** * fu_rom_init: **/ static void fu_rom_init (FuRom *rom) { FuRomPrivate *priv = GET_PRIVATE (rom); priv->checksum_type = G_CHECKSUM_SHA1; priv->checksum_wip = g_checksum_new (priv->checksum_type); priv->hdrs = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_rom_pci_header_free); } /** * fu_rom_finalize: **/ static void fu_rom_finalize (GObject *object) { FuRom *rom = FU_ROM (object); FuRomPrivate *priv = GET_PRIVATE (rom); g_checksum_free (priv->checksum_wip); g_free (priv->version); g_free (priv->guid); g_ptr_array_unref (priv->hdrs); if (priv->stream != NULL) g_object_unref (priv->stream); G_OBJECT_CLASS (fu_rom_parent_class)->finalize (object); } /** * fu_rom_new: **/ FuRom * fu_rom_new (void) { FuRom *rom; rom = g_object_new (FU_TYPE_ROM, NULL); return FU_ROM (rom); } fwupd-0.7.0/src/fu-rom.h000066400000000000000000000041531267747510300150270ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __FU_ROM_H #define __FU_ROM_H #include #include G_BEGIN_DECLS #define FU_TYPE_ROM (fu_rom_get_type ()) G_DECLARE_DERIVABLE_TYPE (FuRom, fu_rom, FU, ROM, GObject) struct _FuRomClass { GObjectClass parent_class; }; typedef enum { FU_ROM_KIND_UNKNOWN, FU_ROM_KIND_ATI, FU_ROM_KIND_NVIDIA, FU_ROM_KIND_INTEL, FU_ROM_KIND_PCI, FU_ROM_KIND_LAST } FuRomKind; typedef enum { FU_ROM_LOAD_FLAG_NONE, FU_ROM_LOAD_FLAG_BLANK_PPID = 1, FU_ROM_LOAD_FLAG_LAST } FuRomLoadFlags; FuRom *fu_rom_new (void); gboolean fu_rom_load_file (FuRom *rom, GFile *file, FuRomLoadFlags flags, GCancellable *cancellable, GError **error); gboolean fu_rom_extract_all (FuRom *rom, const gchar *path, GError **error); FuRomKind fu_rom_get_kind (FuRom *rom); const gchar *fu_rom_get_version (FuRom *rom); const gchar *fu_rom_get_checksum (FuRom *rom); GChecksumType fu_rom_get_checksum_kind (FuRom *rom); const gchar *fu_rom_get_guid (FuRom *rom); guint16 fu_rom_get_vendor (FuRom *rom); guint16 fu_rom_get_model (FuRom *rom); const gchar *fu_rom_kind_to_string (FuRomKind kind); G_END_DECLS #endif /* __FU_ROM_H */ fwupd-0.7.0/src/fu-self-test.c000066400000000000000000000361261267747510300161400ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include "fu-keyring.h" #include "fu-pending.h" #include "fu-provider-fake.h" #include "fu-provider-rpi.h" #include "fu-rom.h" /** * fu_test_get_filename: **/ static gchar * fu_test_get_filename (const gchar *filename) { gchar *tmp; char full_tmp[PATH_MAX]; g_autofree gchar *path = NULL; path = g_build_filename (TESTDATADIR, filename, NULL); tmp = realpath (path, full_tmp); if (tmp == NULL) return NULL; return g_strdup (full_tmp); } static void fu_rom_func (void) { guint i; struct { FuRomKind kind; const gchar *fn; const gchar *ver; const gchar *csum; guint16 vendor; guint16 model; } data[] = { { FU_ROM_KIND_ATI, "Asus.9800PRO.256.unknown.031114.rom", "008.015.041.001", "3137385685298bbf7db2c8304f60d89005c731ed", 0x1002, 0x4e48 }, { FU_ROM_KIND_ATI, /* atombios */ "Asus.R9290X.4096.131014.rom", "015.039.000.006.003515", "d8e32fa09a00ab9dcc96a990266f3fe5a99eacc5", 0x1002, 0x67b0 }, { FU_ROM_KIND_ATI, /* atombios, with serial */ "Asus.HD7970.3072.121018.rom", "015.023.000.002.000000", "ba8b6ce38f2499c8463fc9d983b8e0162b1121e4", 0x1002, 0x6798 }, { FU_ROM_KIND_NVIDIA, "Asus.GTX480.1536.100406_1.rom", "70.00.1A.00.02", "3fcab24e60934850246fcfc4f42eceb32540a0ad", 0x10de, 0x06c0 }, { FU_ROM_KIND_NVIDIA, /* nvgi */ "Asus.GTX980.4096.140905.rom", "84.04.1F.00.02", "98f58321145bd347156455356bc04c5b04a292f5", 0x10de, 0x13c0 }, { FU_ROM_KIND_NVIDIA, /* nvgi, with serial */ "Asus.TitanBlack.6144.140212.rom", "80.80.4E.00.01", "3c80f35d4e3c440ffb427957d9271384113d7721", 0x10de, 0x100c }, { FU_ROM_KIND_UNKNOWN, NULL, NULL, NULL, 0x0000, 0x0000 } }; for (i = 0; data[i].fn != NULL; i++) { gboolean ret; g_autoptr(GError) error = NULL; g_autofree gchar *filename = NULL; g_autoptr(FuRom) rom = NULL; g_autoptr(GFile) file = NULL; rom = fu_rom_new (); g_assert (rom != NULL); /* load file */ filename = fu_test_get_filename (data[i].fn); if (filename == NULL) continue; g_print ("\nparsing %s...", filename); file = g_file_new_for_path (filename); ret = fu_rom_load_file (rom, file, FU_ROM_LOAD_FLAG_BLANK_PPID, NULL, &error); g_assert_no_error (error); g_assert (ret); g_assert_cmpstr (fu_rom_get_version (rom), ==, data[i].ver); g_assert_cmpstr (fu_rom_get_checksum (rom), ==, data[i].csum); g_assert_cmpint (fu_rom_get_kind (rom), ==, data[i].kind); g_assert_cmpint (fu_rom_get_vendor (rom), ==, data[i].vendor); g_assert_cmpint (fu_rom_get_model (rom), ==, data[i].model); } } static void fu_rom_all_func (void) { GDir *dir; g_autofree gchar *path = NULL; /* may or may not exist */ path = fu_test_get_filename ("roms"); if (path == NULL) return; g_print ("\n"); dir = g_dir_open (path, 0, NULL); do { const gchar *fn; gboolean ret; g_autoptr(GError) error = NULL; g_autofree gchar *filename = NULL; g_autoptr(FuRom) rom = NULL; g_autoptr(GFile) file = NULL; fn = g_dir_read_name (dir); if (fn == NULL) break; filename = g_build_filename (path, fn, NULL); g_print ("\nparsing %s...", filename); file = g_file_new_for_path (filename); rom = fu_rom_new (); ret = fu_rom_load_file (rom, file, FU_ROM_LOAD_FLAG_BLANK_PPID, NULL, &error); if (!ret) { g_print ("%s %s : %s\n", fu_rom_kind_to_string (fu_rom_get_kind (rom)), filename, error->message); continue; } g_assert_cmpstr (fu_rom_get_version (rom), !=, NULL); g_assert_cmpstr (fu_rom_get_version (rom), !=, "\0"); g_assert_cmpstr (fu_rom_get_checksum (rom), !=, NULL); g_assert_cmpint (fu_rom_get_kind (rom), !=, FU_ROM_KIND_UNKNOWN); } while (TRUE); } static void _provider_status_changed_cb (FuProvider *provider, FwupdStatus status, gpointer user_data) { guint *cnt = (guint *) user_data; (*cnt)++; } static void _provider_device_added_cb (FuProvider *provider, FuDevice *device, gpointer user_data) { FuDevice **dev = (FuDevice **) user_data; *dev = g_object_ref (device); } static void fu_provider_func (void) { GError *error = NULL; FuDevice *device_tmp; FwupdResult *res; gboolean ret; guint cnt = 0; g_autofree gchar *mapped_file_fn = NULL; g_autofree gchar *pending_cap = NULL; g_autofree gchar *pending_db = NULL; g_autoptr(FuDevice) device = NULL; g_autoptr(FuPending) pending = NULL; g_autoptr(FuProvider) provider = NULL; g_autoptr(GBytes) blob_cab = NULL; g_autoptr(GMappedFile) mapped_file = NULL; /* create a fake device */ provider = fu_provider_fake_new (); g_signal_connect (provider, "device-added", G_CALLBACK (_provider_device_added_cb), &device); g_signal_connect (provider, "status-changed", G_CALLBACK (_provider_status_changed_cb), &cnt); ret = fu_provider_coldplug (provider, &error); g_assert_no_error (error); g_assert (ret); /* check we did the right thing */ g_assert_cmpint (cnt, ==, 0); g_assert (device != NULL); g_assert_cmpstr (fu_device_get_id (device), ==, "FakeDevice"); g_assert_cmpstr (fu_device_get_guid (device), ==, "00000000-0000-0000-0000-000000000000"); /* schedule an offline update */ mapped_file_fn = fu_test_get_filename ("colorhug/firmware.bin"); mapped_file = g_mapped_file_new (mapped_file_fn, FALSE, &error); g_assert_no_error (error); g_assert (mapped_file != NULL); blob_cab = g_mapped_file_get_bytes (mapped_file); ret = fu_provider_update (provider, device, blob_cab, NULL, NULL, FWUPD_INSTALL_FLAG_OFFLINE, &error); g_assert_no_error (error); g_assert (ret); g_assert_cmpint (cnt, ==, 1); /* lets check the pending */ pending = fu_pending_new (); res = fu_pending_get_device (pending, fu_device_get_id (device), &error); g_assert_no_error (error); g_assert (res != NULL); g_assert_cmpint (fu_device_get_update_state (res), ==, FWUPD_UPDATE_STATE_PENDING); g_assert_cmpstr (fu_device_get_update_error (res), ==, NULL); g_assert_cmpstr (fu_device_get_update_filename (res), !=, NULL); /* save this; we'll need to delete it later */ pending_cap = g_strdup (fu_device_get_update_filename (res)); g_object_unref (res); /* lets do this online */ ret = fu_provider_update (provider, device, blob_cab, NULL, NULL, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_no_error (error); g_assert (ret); g_assert_cmpint (cnt, ==, 3); /* lets check the pending */ res = fu_pending_get_device (pending, fu_device_get_id (device), &error); g_assert_no_error (error); g_assert (res != NULL); g_assert_cmpint (fu_device_get_update_state (res), ==, FWUPD_UPDATE_STATE_SUCCESS); g_assert_cmpstr (fu_device_get_update_error (res), ==, NULL); g_object_unref (res); /* get the status */ device_tmp = fu_device_new (); fu_device_set_id (device_tmp, "FakeDevice"); ret = fu_provider_get_results (provider, device_tmp, &error); g_assert_no_error (error); g_assert (ret); g_assert_cmpint (fu_device_get_update_state (device_tmp), ==, FWUPD_UPDATE_STATE_SUCCESS); g_assert_cmpstr (fu_device_get_update_error (device_tmp), ==, NULL); /* clear */ ret = fu_provider_clear_results (provider, device_tmp, &error); g_assert_no_error (error); g_assert (ret); /* re-get the status */ ret = fu_provider_get_results (provider, device_tmp, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO); g_assert (!ret); g_object_unref (device_tmp); g_clear_error (&error); /* delete files */ pending_db = g_build_filename (LOCALSTATEDIR, "lib", "fwupd", "pending.db", NULL); g_unlink (pending_db); g_unlink (pending_cap); } static void fu_provider_rpi_func (void) { gboolean ret; guint cnt = 0; g_autoptr(GError) error = NULL; g_autofree gchar *path = NULL; g_autofree gchar *pending_db = NULL; g_autofree gchar *fwfile = NULL; g_autoptr(FuDevice) device = NULL; g_autoptr(FuProvider) provider = NULL; g_autoptr(GBytes) blob_fw = NULL; g_autoptr(GMappedFile) mapped_file = NULL; /* test location */ path = fu_test_get_filename ("rpiboot"); g_assert (path != NULL); /* create a fake device */ provider = fu_provider_rpi_new (); fu_provider_rpi_set_fw_dir (FU_PROVIDER_RPI (provider), path); g_signal_connect (provider, "device-added", G_CALLBACK (_provider_device_added_cb), &device); g_signal_connect (provider, "status-changed", G_CALLBACK (_provider_status_changed_cb), &cnt); ret = fu_provider_coldplug (provider, &error); g_assert_no_error (error); g_assert (ret); /* check we did the right thing */ g_assert_cmpint (cnt, ==, 0); g_assert (device != NULL); g_assert_cmpstr (fu_device_get_id (device), ==, "raspberry-pi"); g_assert_cmpstr (fu_device_get_guid (device), ==, "91dd7368-8640-5d72-a217-a505c034dd0b"); g_assert_cmpstr (fu_device_get_version (device), ==, "20150803"); /* ensure clean */ g_unlink ("/tmp/rpiboot/start.elf"); /* do update */ fu_provider_rpi_set_fw_dir (FU_PROVIDER_RPI (provider), "/tmp/rpiboot"); fwfile = fu_test_get_filename ("rpiupdate/firmware.bin"); g_assert (fwfile != NULL); mapped_file = g_mapped_file_new (fwfile, FALSE, &error); g_assert_no_error (error); g_assert (mapped_file != NULL); blob_fw = g_mapped_file_get_bytes (mapped_file); ret = fu_provider_update (provider, device, NULL, blob_fw, NULL, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_no_error (error); g_assert (ret); g_assert_cmpint (cnt, ==, 3); /* check the file was exploded to the right place */ g_assert (g_file_test ("/tmp/rpiboot/start.elf", G_FILE_TEST_EXISTS)); g_assert (g_file_test ("/tmp/rpiboot/overlays/test.dtb", G_FILE_TEST_EXISTS)); g_assert_cmpstr (fu_device_get_version (device), ==, "20150805"); /* clean up */ pending_db = g_build_filename (LOCALSTATEDIR, "lib", "fwupd", "pending.db", NULL); g_unlink (pending_db); } static void fu_pending_func (void) { GError *error = NULL; gboolean ret; FwupdResult *res; g_autoptr(FuPending) pending = NULL; g_autofree gchar *dirname = NULL; g_autofree gchar *filename = NULL; /* create */ pending = fu_pending_new (); g_assert (pending != NULL); /* delete the database */ dirname = g_build_filename (LOCALSTATEDIR, "lib", "fwupd", NULL); if (!g_file_test (dirname, G_FILE_TEST_IS_DIR)) return; filename = g_build_filename (dirname, "pending.db", NULL); g_unlink (filename); /* add a device */ res = fwupd_result_new (); fu_device_set_id (res, "self-test"); fu_device_set_update_filename (res, "/var/lib/dave.cap"), fu_device_set_name (res, "ColorHug"), fu_device_set_version (res, "3.0.1"), fu_device_set_update_version (res, "3.0.2"); ret = fu_pending_add_device (pending, res, &error); g_assert_no_error (error); g_assert (ret); g_object_unref (res); /* ensure database was created */ g_assert (g_file_test (filename, G_FILE_TEST_EXISTS)); /* add some extra data */ res = fwupd_result_new (); fu_device_set_id (res, "self-test"); ret = fu_pending_set_state (pending, res, FWUPD_UPDATE_STATE_PENDING, &error); g_assert_no_error (error); g_assert (ret); ret = fu_pending_set_error_msg (pending, res, "word", &error); g_assert_no_error (error); g_assert (ret); g_object_unref (res); /* get device */ res = fu_pending_get_device (pending, "self-test", &error); g_assert_no_error (error); g_assert (res != NULL); g_assert_cmpstr (fwupd_result_get_device_id (res), ==, "self-test"); g_assert_cmpstr (fwupd_result_get_update_filename (res), ==, "/var/lib/dave.cap"); g_assert_cmpstr (fwupd_result_get_device_name (res), ==, "ColorHug"); g_assert_cmpstr (fwupd_result_get_device_version (res), ==, "3.0.1"); g_assert_cmpstr (fwupd_result_get_update_version (res), ==, "3.0.2"); g_assert_cmpint (fwupd_result_get_update_state (res), ==, FWUPD_UPDATE_STATE_PENDING); g_assert_cmpstr (fwupd_result_get_update_error (res), ==, "word"); g_object_unref (res); /* get device that does not exist */ res = fu_pending_get_device (pending, "XXXXXXXXXXXXX", &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND); g_assert (res == NULL); g_clear_error (&error); /* remove device */ res = fwupd_result_new (); fu_device_set_id (res, "self-test"); ret = fu_pending_remove_device (pending, res, &error); g_assert_no_error (error); g_assert (ret); g_object_unref (res); /* get device that does not exist */ res = fu_pending_get_device (pending, "self-test", &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND); g_assert (res == NULL); g_clear_error (&error); } static void fu_keyring_func (void) { gboolean ret; g_autoptr(GError) error = NULL; g_autofree gchar *fw_fail = NULL; g_autofree gchar *fw_pass = NULL; g_autofree gchar *pki_dir = NULL; g_autoptr(FuKeyring) keyring = NULL; const gchar *sig = "iQEcBAABCAAGBQJVt0B4AAoJEEim2A5FOLrCFb8IAK+QTLY34Wu8xZ8nl6p3JdMu" "HOaifXAmX7291UrsFRwdabU2m65pqxQLwcoFrqGv738KuaKtu4oIwo9LIrmmTbEh" "IID8uszxBt0bMdcIHrvwd+ADx+MqL4hR3guXEE3YOBTLvv2RF1UBcJPInNf/7Ui1" "3lW1c3trL8RAJyx1B5RdKqAMlyfwiuvKM5oT4SN4uRSbQf+9mt78ZSWfJVZZH/RR" "H9q7PzR5GdmbsRPM0DgC27Trvqjo3MzoVtoLjIyEb/aWqyulUbnJUNKPYTnZgkzM" "v2yVofWKIM3e3wX5+MOtf6EV58mWa2cHJQ4MCYmpKxbIvAIZagZ4c9A8BA6tQWg=" "=fkit"; /* add test keys to keyring */ keyring = fu_keyring_new (); pki_dir = fu_test_get_filename ("pki"); ret = fu_keyring_add_public_keys (keyring, pki_dir, &error); g_assert_no_error (error); g_assert (ret); /* verify */ fw_pass = fu_test_get_filename ("colorhug/firmware.bin"); ret = fu_keyring_verify_file (keyring, fw_pass, sig, &error); g_assert_no_error (error); g_assert (ret); /* verify will fail */ fw_fail = fu_test_get_filename ("colorhug/colorhug-als-3.0.2.cab"); ret = fu_keyring_verify_file (keyring, fw_fail, sig, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID); g_assert (!ret); g_clear_error (&error); } 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); g_assert_cmpint (g_mkdir_with_parents ("/tmp/fwupd-self-test/var/lib/fwupd", 0755), ==, 0); /* tests go here */ g_test_add_func ("/fwupd/rom", fu_rom_func); g_test_add_func ("/fwupd/rom{all}", fu_rom_all_func); g_test_add_func ("/fwupd/pending", fu_pending_func); g_test_add_func ("/fwupd/provider", fu_provider_func); g_test_add_func ("/fwupd/provider{rpi}", fu_provider_rpi_func); g_test_add_func ("/fwupd/keyring", fu_keyring_func); return g_test_run (); } fwupd-0.7.0/src/fu-util.c000066400000000000000000001036451267747510300152100ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015-2016 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fu-pending.h" #include "fu-provider.h" #include "fu-rom.h" #ifndef GUdevClient_autoptr G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevClient, g_object_unref) #endif /* this is only valid in this file */ #define FWUPD_ERROR_INVALID_ARGS (FWUPD_ERROR_LAST+1) typedef struct { GMainLoop *loop; GOptionContext *context; GPtrArray *cmd_array; FwupdInstallFlags flags; FwupdClient *client; } FuUtilPrivate; typedef gboolean (*FuUtilPrivateCb) (FuUtilPrivate *util, gchar **values, GError **error); typedef struct { gchar *name; gchar *arguments; gchar *description; FuUtilPrivateCb callback; } FuUtilItem; /** * fu_util_item_free: **/ static void fu_util_item_free (FuUtilItem *item) { g_free (item->name); g_free (item->arguments); g_free (item->description); g_free (item); } /* * fu_sort_command_name_cb: */ static gint fu_sort_command_name_cb (FuUtilItem **item1, FuUtilItem **item2) { return g_strcmp0 ((*item1)->name, (*item2)->name); } /** * fu_util_add: **/ static void fu_util_add (GPtrArray *array, const gchar *name, const gchar *arguments, const gchar *description, FuUtilPrivateCb callback) { guint i; FuUtilItem *item; g_auto(GStrv) names = NULL; g_return_if_fail (name != NULL); g_return_if_fail (description != NULL); g_return_if_fail (callback != NULL); /* add each one */ names = g_strsplit (name, ",", -1); for (i = 0; names[i] != NULL; i++) { item = g_new0 (FuUtilItem, 1); item->name = g_strdup (names[i]); if (i == 0) { item->description = g_strdup (description); } else { /* TRANSLATORS: this is a command alias, e.g. 'get-devices' */ item->description = g_strdup_printf (_("Alias to %s"), names[0]); } item->arguments = g_strdup (arguments); item->callback = callback; g_ptr_array_add (array, item); } } /** * fu_util_get_descriptions: **/ static gchar * fu_util_get_descriptions (GPtrArray *array) { guint i; guint j; guint len; const guint max_len = 35; FuUtilItem *item; GString *string; /* print each command */ string = g_string_new (""); for (i = 0; i < array->len; i++) { item = g_ptr_array_index (array, i); g_string_append (string, " "); g_string_append (string, item->name); len = strlen (item->name) + 2; if (item->arguments != NULL) { g_string_append (string, " "); g_string_append (string, item->arguments); len += strlen (item->arguments) + 1; } if (len < max_len) { for (j = len; j < max_len + 1; j++) g_string_append_c (string, ' '); g_string_append (string, item->description); g_string_append_c (string, '\n'); } else { g_string_append_c (string, '\n'); for (j = 0; j < max_len + 1; j++) g_string_append_c (string, ' '); g_string_append (string, item->description); g_string_append_c (string, '\n'); } } /* remove trailing newline */ if (string->len > 0) g_string_set_size (string, string->len - 1); return g_string_free (string, FALSE); } /** * fu_util_run: **/ static gboolean fu_util_run (FuUtilPrivate *priv, const gchar *command, gchar **values, GError **error) { guint i; FuUtilItem *item; /* find command */ for (i = 0; i < priv->cmd_array->len; i++) { item = g_ptr_array_index (priv->cmd_array, i); if (g_strcmp0 (item->name, command) == 0) return item->callback (priv, values, error); } /* not found */ g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_ARGS, /* TRANSLATORS: error message */ _("Command not found")); return FALSE; } /** * fu_util_status_changed_cb: **/ static void fu_util_status_changed_cb (FwupdClient *client, FwupdStatus status, FuUtilPrivate *priv) { switch (status) { case FWUPD_STATUS_IDLE: /* TRANSLATORS: daemon is inactive */ g_print (" * %s\n", _("Idle")); break; case FWUPD_STATUS_DECOMPRESSING: /* TRANSLATORS: decompressing the firmware file */ g_print (" * %s\n", _("Decompressing firmware")); break; case FWUPD_STATUS_LOADING: /* TRANSLATORS: parsing the firmware information */ g_print (" * %s\n", _("Loading firmware")); break; case FWUPD_STATUS_DEVICE_RESTART: /* TRANSLATORS: restarting the device to pick up new F/W */ g_print (" * %s\n", _("Restarting device")); break; case FWUPD_STATUS_DEVICE_WRITE: /* TRANSLATORS: writing to the flash chips */ g_print (" * %s\n", _("Writing firmware to device")); break; case FWUPD_STATUS_DEVICE_VERIFY: /* TRANSLATORS: verifying we wrote the firmware correctly */ g_print (" * %s\n", _("Verifying firmware from device")); break; case FWUPD_STATUS_SCHEDULING: /* TRANSLATORS: scheduing an update to be done on the next boot */ g_print (" * %s\n", _("Scheduling upgrade")); break; default: break; } } /** * fu_util_get_devices: **/ static gboolean fu_util_get_devices (FuUtilPrivate *priv, gchar **values, GError **error) { FwupdResult *res; guint i; g_autoptr(GPtrArray) results = NULL; /* get results from daemon */ results = fwupd_client_get_devices (priv->client, NULL, error); if (results == NULL) return FALSE; /* print */ if (results->len == 0) { /* TRANSLATORS: nothing attached that can be upgraded */ g_print ("%s\n", _("No hardware detected with firmware update capability")); return TRUE; } for (i = 0; i < results->len; i++) { g_autofree gchar *tmp = NULL; res = g_ptr_array_index (results, i); tmp = fwupd_result_to_string (res); g_print ("%s\n", tmp); } return TRUE; } /** * fu_util_install_with_fallback: **/ static gboolean fu_util_install_with_fallback (FuUtilPrivate *priv, const gchar *id, const gchar *filename, GError **error) { g_autoptr(GError) error_local = NULL; /* install with flags chosen by the user */ if (fwupd_client_install (priv->client, id, filename, priv->flags, NULL, &error_local)) return TRUE; /* some other failure */ if ((priv->flags & FWUPD_INSTALL_FLAG_OFFLINE) > 0 || !g_error_matches (error_local, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) { g_propagate_error (error, error_local); error_local = NULL; return FALSE; } /* TRANSLATOR: the provider only supports offline */ g_print ("%s...\n", _("Retrying as an offline update")); priv->flags |= FWUPD_INSTALL_FLAG_OFFLINE; return fwupd_client_install (priv->client, id, filename, priv->flags, NULL, error); } /** * fu_util_install: **/ static gboolean fu_util_install (FuUtilPrivate *priv, gchar **values, GError **error) { const gchar *id; /* handle both forms */ if (g_strv_length (values) == 1) { id = FWUPD_DEVICE_ID_ANY; } else if (g_strv_length (values) == 2) { id = values[1]; } else { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_ARGS, "Invalid arguments: expected 'filename' [id]"); return FALSE; } /* install with flags chosen by the user then falling back to offline */ return fu_util_install_with_fallback (priv, id, values[0], error); } /** * fu_util_get_details: **/ static gboolean fu_util_get_details (FuUtilPrivate *priv, gchar **values, GError **error) { g_autofree gchar *tmp = NULL; g_autoptr(FwupdResult) res = NULL; /* check args */ if (g_strv_length (values) != 1) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_ARGS, "Invalid arguments: expected 'filename'"); return FALSE; } res = fwupd_client_get_details (priv->client, values[0], NULL, error); if (res == NULL) return FALSE; tmp = fwupd_result_to_string (res); g_print ("%s", tmp); return TRUE; } /** * fu_util_offline_update_reboot: **/ static void fu_util_offline_update_reboot (void) { g_autoptr(GError) error = NULL; g_autoptr(GDBusConnection) connection = NULL; g_autoptr(GVariant) val = NULL; /* reboot using systemd */ connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); if (connection == NULL) return; val = g_dbus_connection_call_sync (connection, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "Reboot", NULL, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (val == NULL) g_print ("Failed to reboot: %s\n", error->message); } /** * fu_util_install_prepared: **/ static gboolean fu_util_install_prepared (FuUtilPrivate *priv, gchar **values, GError **error) { gint vercmp; guint cnt = 0; guint i; g_autofree gchar *link = NULL; g_autoptr(GPtrArray) results = NULL; g_autoptr(FuPending) pending = NULL; /* verify this is pointing to our cache */ link = g_file_read_link (FU_OFFLINE_TRIGGER_FILENAME, NULL); if (link == NULL) { g_debug ("No %s, exiting", FU_OFFLINE_TRIGGER_FILENAME); return TRUE; } if (g_strcmp0 (link, "/var/lib/fwupd") != 0) { g_debug ("Another framework set up the trigger, exiting"); return TRUE; } /* do this first to avoid a loop if this tool segfaults */ g_unlink (FU_OFFLINE_TRIGGER_FILENAME); if (g_strv_length (values) != 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_ARGS, "Invalid arguments: none expected"); return FALSE; } /* ensure root user */ if (getuid () != 0 || geteuid () != 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_ARGS, "This function can only be used as root"); return FALSE; } /* get prepared updates */ pending = fu_pending_new (); results = fu_pending_get_devices (pending, error); if (results == NULL) return FALSE; /* apply each update */ for (i = 0; i < results->len; i++) { FwupdResult *res; res = g_ptr_array_index (results, i); /* check not already done */ if (fwupd_result_get_update_state (res) != FWUPD_UPDATE_STATE_PENDING) continue; /* tell the user what's going to happen */ vercmp = as_utils_vercmp (fwupd_result_get_device_version (res), fwupd_result_get_update_version (res)); if (vercmp == 0) { /* TRANSLATORS: the first replacement is a display name * e.g. "ColorHugALS" and the second is a version number * e.g. "1.2.3" */ g_print (_("Reinstalling %s with %s... "), fwupd_result_get_device_name (res), fwupd_result_get_update_version (res)); } else if (vercmp > 0) { /* TRANSLATORS: the first replacement is a display name * e.g. "ColorHugALS" and the second and third are * version numbers e.g. "1.2.3" */ g_print (_("Downgrading %s from %s to %s... "), fwupd_result_get_device_name (res), fwupd_result_get_device_version (res), fwupd_result_get_update_version (res)); } else if (vercmp < 0) { /* TRANSLATORS: the first replacement is a display name * e.g. "ColorHugALS" and the second and third are * version numbers e.g. "1.2.3" */ g_print (_("Updating %s from %s to %s... "), fwupd_result_get_device_name (res), fwupd_result_get_device_version (res), fwupd_result_get_update_version (res)); } if (!fwupd_client_install (priv->client, fwupd_result_get_device_id (res), fwupd_result_get_update_filename (res), priv->flags, NULL, error)) return FALSE; cnt++; } /* nothing to do */ if (cnt == 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO, "No updates prepared"); return FALSE; } /* reboot */ fu_util_offline_update_reboot (); g_print ("%s\n", _("Done!")); return TRUE; } /** * fu_util_clear_results: **/ static gboolean fu_util_clear_results (FuUtilPrivate *priv, gchar **values, GError **error) { if (g_strv_length (values) != 1) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_ARGS, "Invalid arguments: expected 'id'"); return FALSE; } return fwupd_client_clear_results (priv->client, values[0], NULL, error); } /** * fu_util_dump_rom: **/ static gboolean fu_util_dump_rom (FuUtilPrivate *priv, gchar **values, GError **error) { guint i; if (g_strv_length (values) == 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_ARGS, "Invalid arguments: expected 'filename.rom'"); return FALSE; } for (i = 0; values[i] != NULL; i++) { g_autoptr(FuRom) rom = NULL; g_autoptr(GFile) file = NULL; g_autoptr(GError) error_local = NULL; file = g_file_new_for_path (values[i]); rom = fu_rom_new (); g_print ("%s:\n", values[i]); if (!fu_rom_load_file (rom, file, FU_ROM_LOAD_FLAG_BLANK_PPID, NULL, &error_local)) { g_print ("%s\n", error_local->message); continue; } g_print ("0x%04x:0x%04x -> %s [%s]\n", fu_rom_get_vendor (rom), fu_rom_get_model (rom), fu_rom_get_checksum (rom), fu_rom_get_version (rom)); } return TRUE; } /** * fu_util_verify_update_internal: **/ static gboolean fu_util_verify_update_internal (FuUtilPrivate *priv, const gchar *filename, gchar **values, GError **error) { guint i; g_autoptr(AsStore) store = NULL; g_autoptr(GFile) xml_file = NULL; store = as_store_new (); /* open existing file */ xml_file = g_file_new_for_path (filename); if (g_file_query_exists (xml_file, NULL)) { if (!as_store_from_file (store, xml_file, NULL, NULL, error)) return FALSE; } /* add new values */ as_store_set_api_version (store, 0.9); for (i = 0; values[i] != NULL; i++) { g_autofree gchar *id = NULL; g_autoptr(AsApp) app = NULL; g_autoptr(AsChecksum) csum = NULL; g_autoptr(AsRelease) rel = NULL; g_autoptr(AsProvide) prov = NULL; g_autoptr(FuRom) rom = NULL; g_autoptr(GFile) file = NULL; g_autoptr(GError) error_local = NULL; file = g_file_new_for_path (values[i]); rom = fu_rom_new (); g_print ("Processing %s...\n", values[i]); if (!fu_rom_load_file (rom, file, FU_ROM_LOAD_FLAG_BLANK_PPID, NULL, &error_local)) { g_print ("%s\n", error_local->message); continue; } /* make a plausible ID */ id = g_strdup_printf ("%s.firmware", fu_rom_get_guid (rom)); /* add app to store */ app = as_app_new (); as_app_set_id (app, id); as_app_set_kind (app, AS_APP_KIND_FIRMWARE); as_app_set_source_kind (app, AS_APP_SOURCE_KIND_INF); rel = as_release_new (); as_release_set_version (rel, fu_rom_get_version (rom)); csum = as_checksum_new (); as_checksum_set_kind (csum, fu_rom_get_checksum_kind (rom)); as_checksum_set_value (csum, fu_rom_get_checksum (rom)); 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_rom_get_guid (rom)); as_app_add_provide (app, prov); as_store_add_app (store, app); } if (!as_store_to_file (store, xml_file, AS_NODE_TO_XML_FLAG_ADD_HEADER | AS_NODE_TO_XML_FLAG_FORMAT_INDENT | AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE, NULL, error)) return FALSE; return TRUE; } /** * fu_util_verify_update_all: **/ static gboolean fu_util_verify_update_all (FuUtilPrivate *priv, const gchar *fn, GError **error) { GList *devices; GList *l; GUdevDevice *dev; const gchar *devclass[] = { "pci", NULL }; const gchar *subsystems[] = { NULL }; guint i; g_autoptr(GUdevClient) gudev_client = NULL; g_autoptr(GPtrArray) roms = NULL; /* get all devices of class */ gudev_client = g_udev_client_new (subsystems); roms = g_ptr_array_new_with_free_func (g_free); for (i = 0; devclass[i] != NULL; i++) { devices = g_udev_client_query_by_subsystem (gudev_client, devclass[i]); for (l = devices; l != NULL; l = l->next) { g_autofree gchar *rom_fn = NULL; dev = l->data; rom_fn = g_build_filename (g_udev_device_get_sysfs_path (dev), "rom", NULL); if (!g_file_test (rom_fn, G_FILE_TEST_EXISTS)) continue; g_ptr_array_add (roms, g_strdup (rom_fn)); } g_list_foreach (devices, (GFunc) g_object_unref, NULL); g_list_free (devices); } /* no ROMs to add */ if (roms->len == 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO, "No hardware with ROM"); return FALSE; } g_ptr_array_add (roms, NULL); return fu_util_verify_update_internal (priv, fn, (gchar **) roms->pdata, error); } /** * fu_util_verify_update: **/ static gboolean fu_util_verify_update (FuUtilPrivate *priv, gchar **values, GError **error) { const gchar *fn = "/var/cache/app-info/xmls/fwupd-verify.xml"; if (g_strv_length (values) == 0) return fu_util_verify_update_all (priv, fn, error); if (g_strv_length (values) == 1) return fu_util_verify_update_all (priv, values[0], error); return fu_util_verify_update_internal (priv, values[0], &values[1], error); } /** * fu_util_download_file: **/ static gboolean fu_util_download_file (FuUtilPrivate *priv, const gchar *uri, const gchar *fn, const gchar *checksum_expected, GChecksumType checksum_type, GError **error) { guint status_code; g_autoptr(GError) error_local = NULL; g_autofree gchar *checksum_actual = NULL; g_autofree gchar *user_agent = NULL; g_autoptr(SoupMessage) msg = NULL; g_autoptr(SoupSession) session = NULL; user_agent = g_strdup_printf ("%s/%s", PACKAGE_NAME, PACKAGE_VERSION); session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT, user_agent, NULL); if (session == NULL) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "%s: failed to setup networking"); return FALSE; } /* this disables the double-compression of the firmware.xml.gz file */ soup_session_remove_feature_by_type (session, SOUP_TYPE_CONTENT_DECODER); /* download data */ g_debug ("downloading %s to %s:", uri, fn); msg = soup_message_new (SOUP_METHOD_GET, uri); status_code = soup_session_send_message (session, msg); if (status_code != SOUP_STATUS_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Failed to download %s: %s", uri, soup_status_get_phrase (status_code)); return FALSE; } /* verify checksum */ if (checksum_expected != NULL) { checksum_actual = g_compute_checksum_for_data (checksum_type, (guchar *) msg->response_body->data, msg->response_body->length); if (g_strcmp0 (checksum_expected, checksum_actual) != 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Checksum invalid, expected %s got %s", checksum_expected, checksum_actual); return FALSE; } } /* save file */ if (!g_file_set_contents (fn, msg->response_body->data, msg->response_body->length, &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, "Failed to save file: %s", error_local->message); return FALSE; } return TRUE; } /** * fu_util_mkdir_with_parents: **/ static gboolean fu_util_mkdir_with_parents (const gchar *path, GError **error) { g_autoptr(GFile) file = g_file_new_for_path (path); if (g_file_query_exists (file, NULL)) return TRUE; return g_file_make_directory_with_parents (file, NULL, error); } /** * fu_util_download_metadata: **/ static gboolean fu_util_download_metadata (FuUtilPrivate *priv, GError **error) { g_autofree gchar *cache_dir = NULL; g_autofree gchar *config_fn = NULL; g_autofree gchar *data_fn = NULL; g_autofree gchar *data_uri = NULL; g_autofree gchar *sig_fn = NULL; g_autofree gchar *sig_uri = NULL; g_autoptr(GKeyFile) config = NULL; /* read config file */ config = g_key_file_new (); config_fn = g_build_filename (SYSCONFDIR, "fwupd.conf", NULL); if (!g_key_file_load_from_file (config, config_fn, G_KEY_FILE_NONE, error)) { g_prefix_error (error, "Failed to load %s: ", config_fn); return FALSE; } /* ensure cache directory exists */ cache_dir = g_build_filename (g_get_user_cache_dir (), "fwupdmgr", NULL); if (!fu_util_mkdir_with_parents (cache_dir, error)) return FALSE; /* download the signature */ data_uri = g_key_file_get_string (config, "fwupd", "DownloadURI", error); if (data_uri == NULL) return FALSE; sig_uri = g_strdup_printf ("%s.asc", data_uri); data_fn = g_build_filename (cache_dir, "firmware.xml.gz", NULL); sig_fn = g_strdup_printf ("%s.asc", data_fn); if (!fu_util_download_file (priv, sig_uri, sig_fn, NULL, 0, error)) return FALSE; /* download the payload */ if (!fu_util_download_file (priv, data_uri, data_fn, NULL, 0, error)) return FALSE; /* send all this to fwupd */ return fwupd_client_update_metadata (priv->client, data_fn, sig_fn, NULL, error); } /** * fu_util_refresh: **/ static gboolean fu_util_refresh (FuUtilPrivate *priv, gchar **values, GError **error) { if (g_strv_length (values) == 0) return fu_util_download_metadata (priv, error); if (g_strv_length (values) != 2) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_ARGS, "Invalid arguments: expected 'filename.xml' 'filename.xml.asc'"); return FALSE; } /* open file */ return fwupd_client_update_metadata (priv->client, values[0], values[1], NULL, error); } /** * fu_util_get_results: **/ static gboolean fu_util_get_results (FuUtilPrivate *priv, gchar **values, GError **error) { g_autofree gchar *tmp = NULL; g_autoptr(FwupdResult) res = NULL; if (g_strv_length (values) != 1) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_ARGS, "Invalid arguments: expected 'id'"); return FALSE; } res = fwupd_client_get_results (priv->client, values[0], NULL, error); if (res == NULL) return FALSE; tmp = fwupd_result_to_string (res); g_print ("%s", tmp); return TRUE; } /** * fu_util_verify_all: **/ static gboolean fu_util_verify_all (FuUtilPrivate *priv, GError **error) { FwupdResult *res; guint i; g_autoptr(GPtrArray) results = NULL; /* get devices from daemon */ results = fwupd_client_get_devices (priv->client, NULL, error); if (results == NULL) return FALSE; /* get results */ for (i = 0; i < results->len; i++) { g_autoptr(GError) error_local = NULL; res = g_ptr_array_index (results, i); if (!fwupd_client_verify (priv->client, fwupd_result_get_device_id (res), NULL, &error_local)) { g_print ("%s\tFAILED: %s\n", fwupd_result_get_guid (res), error_local->message); continue; } g_print ("%s\t%s\n", fwupd_result_get_guid (res), _("OK")); } return TRUE; } /** * fu_util_verify: **/ static gboolean fu_util_verify (FuUtilPrivate *priv, gchar **values, GError **error) { if (g_strv_length (values) == 0) return fu_util_verify_all (priv, error); if (g_strv_length (values) != 1) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_ARGS, "Invalid arguments: expected 'id'"); return FALSE; } return fwupd_client_verify (priv->client, values[0], NULL, error); } /** * fu_util_unlock: **/ static gboolean fu_util_unlock (FuUtilPrivate *priv, gchar **values, GError **error) { if (g_strv_length (values) != 1) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_ARGS, "Invalid arguments: expected 'id'"); return FALSE; } return fwupd_client_unlock (priv->client, values[0], NULL, error); } /** * fu_util_print_data: **/ static void fu_util_print_data (const gchar *title, const gchar *msg) { guint i; guint j; guint title_len; g_auto(GStrv) lines = NULL; if (msg == NULL) return; g_print ("%s:", title); /* pad */ title_len = strlen (title); lines = g_strsplit (msg, "\n", -1); for (j = 0; lines[j] != NULL; j++) { for (i = title_len; i < 20; i++) g_print (" "); g_print ("%s\n", lines[j]); title_len = 0; } } /** * _g_checksum_type_to_string: **/ static const gchar * _g_checksum_type_to_string (GChecksumType checksum_type) { if (checksum_type == G_CHECKSUM_MD5) return "md5"; 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 NULL; } /** * fu_util_get_updates: **/ static gboolean fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) { FwupdResult *res; GPtrArray *results = NULL; GChecksumType checksum_type; const gchar *tmp; guint i; /* print any updates */ results = fwupd_client_get_updates (priv->client, NULL, error); if (results == NULL) return FALSE; for (i = 0; i < results->len; i++) { res = g_ptr_array_index (results, i); /* TRANSLATORS: first replacement is device name */ g_print (_("%s has firmware updates:"), fwupd_result_get_device_name (res)); g_print ("\n"); /* TRANSLATORS: Appstream ID for the hardware type */ fu_util_print_data (_("ID"), fwupd_result_get_update_id (res)); /* TRANSLATORS: a GUID for the hardware */ fu_util_print_data (_("GUID"), fwupd_result_get_guid (res)); /* TRANSLATORS: section header for firmware version */ fu_util_print_data (_("Version"), fwupd_result_get_update_version (res)); /* TRANSLATORS: section header for firmware checksum */ fu_util_print_data (_("Checksum"), fwupd_result_get_update_checksum (res)); /* TRANSLATORS: section header for firmware checksum type */ if (fwupd_result_get_update_checksum (res) != NULL) { checksum_type = fwupd_result_get_update_checksum_kind (res); tmp = _g_checksum_type_to_string (checksum_type); fu_util_print_data (_("Checksum Type"), tmp); } /* TRANSLATORS: section header for firmware remote http:// */ fu_util_print_data (_("Location"), fwupd_result_get_update_uri (res)); /* convert XML -> text */ tmp = fwupd_result_get_update_description (res); if (tmp != NULL) { g_autofree gchar *md = NULL; md = as_markup_convert (tmp, AS_MARKUP_CONVERT_FORMAT_SIMPLE, NULL); if (md != NULL) { /* TRANSLATORS: section header for long firmware desc */ fu_util_print_data (_("Description"), md); } } } return TRUE; } /** * fu_util_update: **/ static gboolean fu_util_update (FuUtilPrivate *priv, gchar **values, GError **error) { FwupdResult *res; GPtrArray *results = NULL; guint i; /* apply any updates */ results = fwupd_client_get_updates (priv->client, NULL, error); if (results == NULL) return FALSE; for (i = 0; i < results->len; i++) { GChecksumType checksum_type; const gchar *checksum; const gchar *uri; g_autofree gchar *basename = NULL; g_autofree gchar *fn = NULL; res = g_ptr_array_index (results, i); /* download file */ checksum = fwupd_result_get_update_checksum (res); if (checksum == NULL) continue; uri = fwupd_result_get_update_uri (res); if (uri == NULL) continue; g_print ("Downloading %s for %s...\n", fwupd_result_get_update_version (res), fwupd_result_get_device_name (res)); basename = g_path_get_basename (uri); fn = g_build_filename (g_get_tmp_dir (), basename, NULL); checksum_type = fwupd_result_get_update_checksum_kind (res); if (!fu_util_download_file (priv, uri, fn, checksum, checksum_type, error)) return FALSE; g_print ("Updating %s on %s...\n", fwupd_result_get_update_version (res), fwupd_result_get_device_name (res)); if (!fu_util_install_with_fallback (priv, fwupd_result_get_device_id (res), fn, error)) return FALSE; } return TRUE; } /** * fu_util_ignore_cb: **/ static void fu_util_ignore_cb (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) { } /** * main: **/ int main (int argc, char *argv[]) { FuUtilPrivate *priv; gboolean allow_older = FALSE; gboolean allow_reinstall = FALSE; gboolean offline = FALSE; gboolean ret; gboolean verbose = FALSE; guint retval = 1; g_autoptr(GError) error = NULL; g_autofree gchar *cmd_descriptions = NULL; const GOptionEntry options[] = { { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, /* TRANSLATORS: command line option */ _("Show extra debugging information"), NULL }, { "offline", '\0', 0, G_OPTION_ARG_NONE, &offline, /* TRANSLATORS: command line option */ _("Perform the installation offline where possible"), NULL }, { "allow-reinstall", '\0', 0, G_OPTION_ARG_NONE, &allow_reinstall, /* TRANSLATORS: command line option */ _("Allow re-installing existing firmware versions"), NULL }, { "allow-older", '\0', 0, G_OPTION_ARG_NONE, &allow_older, /* TRANSLATORS: command line option */ _("Allow downgrading firmware versions"), NULL }, { NULL} }; setlocale (LC_ALL, ""); bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); /* ensure D-Bus errors are registered */ fwupd_error_quark (); /* create helper object */ priv = g_new0 (FuUtilPrivate, 1); priv->loop = g_main_loop_new (NULL, FALSE); /* add commands */ priv->cmd_array = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_util_item_free); fu_util_add (priv->cmd_array, "get-devices", NULL, /* TRANSLATORS: command description */ _("Get all devices that support firmware updates"), fu_util_get_devices); fu_util_add (priv->cmd_array, "install-prepared", NULL, /* TRANSLATORS: command description */ _("Install prepared updates now"), fu_util_install_prepared); fu_util_add (priv->cmd_array, "install", NULL, /* TRANSLATORS: command description */ _("Install a firmware file on this hardware"), fu_util_install); fu_util_add (priv->cmd_array, "get-details", NULL, /* TRANSLATORS: command description */ _("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, "update", NULL, /* TRANSLATORS: command description */ _("Updates all firmware to latest versions available"), fu_util_update); fu_util_add (priv->cmd_array, "verify", NULL, /* TRANSLATORS: command description */ _("Gets the cryptographic hash of the dumped firmware"), fu_util_verify); fu_util_add (priv->cmd_array, "unlock", NULL, /* TRANSLATORS: command description */ _("Unlocks the device for firmware access"), fu_util_unlock); fu_util_add (priv->cmd_array, "clear-results", NULL, /* TRANSLATORS: command description */ _("Clears the results from the last update"), fu_util_clear_results); fu_util_add (priv->cmd_array, "get-results", NULL, /* TRANSLATORS: command description */ _("Gets the results from the last update"), fu_util_get_results); fu_util_add (priv->cmd_array, "refresh", NULL, /* TRANSLATORS: command description */ _("Refresh metadata from remote server"), fu_util_refresh); fu_util_add (priv->cmd_array, "dump-rom", NULL, /* TRANSLATORS: command description */ _("Dump the ROM checksum"), fu_util_dump_rom); fu_util_add (priv->cmd_array, "verify-update", NULL, /* TRANSLATORS: command description */ _("Update the stored metadata with current ROM contents"), fu_util_verify_update); /* sort by command name */ g_ptr_array_sort (priv->cmd_array, (GCompareFunc) fu_sort_command_name_cb); /* get a list of the commands */ priv->context = g_option_context_new (NULL); cmd_descriptions = fu_util_get_descriptions (priv->cmd_array); g_option_context_set_summary (priv->context, cmd_descriptions); /* TRANSLATORS: program name */ g_set_application_name (_("Firmware Utility")); g_option_context_add_main_entries (priv->context, options, NULL); ret = g_option_context_parse (priv->context, &argc, &argv, &error); if (!ret) { /* TRANSLATORS: the user didn't read the man page */ g_print ("%s: %s\n", _("Failed to parse arguments"), error->message); goto out; } /* set verbose? */ if (verbose) { g_setenv ("FWUPD_VERBOSE", "1", FALSE); } else { g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, fu_util_ignore_cb, NULL); } /* set flags */ if (offline) priv->flags |= FWUPD_INSTALL_FLAG_OFFLINE; if (allow_reinstall) priv->flags |= FWUPD_INSTALL_FLAG_ALLOW_REINSTALL; if (allow_older) priv->flags |= FWUPD_INSTALL_FLAG_ALLOW_OLDER; /* connect to the daemon */ priv->client = fwupd_client_new (); g_signal_connect (priv->client, "status-changed", G_CALLBACK (fu_util_status_changed_cb), priv); /* run the specified command */ ret = fu_util_run (priv, argv[1], (gchar**) &argv[2], &error); if (!ret) { if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_ARGS)) { g_autofree gchar *tmp = NULL; tmp = g_option_context_get_help (priv->context, TRUE, NULL); g_print ("%s\n\n%s", error->message, tmp); } else { g_print ("%s\n", error->message); } goto out; } /* success */ retval = 0; out: if (priv != NULL) { if (priv->cmd_array != NULL) g_ptr_array_unref (priv->cmd_array); if (priv->client != NULL) g_object_unref (priv->client); g_main_loop_unref (priv->loop); g_option_context_free (priv->context); g_free (priv); } return retval; } fwupd-0.7.0/src/fwupd.gresource.xml000066400000000000000000000003251267747510300173120ustar00rootroot00000000000000 org.freedesktop.fwupd.xml fwupd-0.7.0/src/org.freedesktop.fwupd.xml000066400000000000000000000177611267747510300204310ustar00rootroot00000000000000 The interface used for quering firmware for the system. The daemon version. The daemon status, e.g. decompressing. Gets a list of all the devices that are supported. An array of devices, with any properties set on each. Gets a list of all the devices that can be updated. An array of devices, with any properties set on each. Gets details about a firmware file. An index into the array of file descriptors that may have been sent with the DBus message. Properties about the firmware, e.g. DisplayName=ColorHug. Schedules a firmware to be installed. An ID, typically a GUID of the hardware to update, or the string * to match any applicable hardware. An index into the array of file descriptors that may have been sent with the DBus message. Options to be used when constructing the profile, e.g. offline=True. Verifies firmware on a device by reading it back and performing a cryptographic hash, typically SHA1. An ID, typically a GUID of the hardware. Unlock the device to allow firmware access. An ID, typically a GUID of the hardware. Gets the results of an offline update. An ID, typically a GUID of the hardware that was updated, or the string * to match any hardware. Results about the update, e.g. success=True Clears the results of an offline update. An ID, typically a GUID of the hardware that was updated, or the string * to match any hardware. Adds AppStream resource information from a session client. File handle to AppStream metadata. File handle to AppStream metadata GPG signature. Some value on the interface or the number of devices or profiles has changed. fwupd-0.7.0/src/plugins/000077500000000000000000000000001267747510300151275ustar00rootroot00000000000000fwupd-0.7.0/src/plugins/Makefile.am000066400000000000000000000014741267747510300171710ustar00rootroot00000000000000 AM_CPPFLAGS = \ $(APPSTREAM_GLIB_CFLAGS) \ $(GUSB_CFLAGS) \ $(GLIB_CFLAGS) \ -I$(top_srcdir) \ -I$(top_srcdir)/libfwupd \ -I$(top_srcdir)/src plugindir = $(libdir)/fwupd-plugins-1 plugin_LTLIBRARIES = \ libfu_plugin_steelseries.la \ libfu_plugin_test.la libfu_plugin_test_la_SOURCES = \ fu-plugin-test.c libfu_plugin_test_la_LIBADD = $(GLIB_LIBS) libfu_plugin_test_la_LDFLAGS = -module -avoid-version libfu_plugin_test_la_CFLAGS = $(WARN_CFLAGS) \ -DG_LOG_DOMAIN=\"FuPluginTest\" libfu_plugin_steelseries_la_SOURCES = \ fu-plugin-steelseries.c libfu_plugin_steelseries_la_LIBADD = $(GUSB_LIBS) libfu_plugin_steelseries_la_LDFLAGS = -module -avoid-version libfu_plugin_steelseries_la_CFLAGS = $(WARN_CFLAGS) \ -DG_LOG_DOMAIN=\"FuPluginSteelSeries\" -include $(top_srcdir)/git.mk fwupd-0.7.0/src/plugins/fu-plugin-steelseries.c000066400000000000000000000115631267747510300215340ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2016 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include "fu-plugin.h" #define STEELSERIES_REPLUG_TIMEOUT 5000 /* ms */ #define STEELSERIES_TRANSACTION_TIMEOUT 1000 /* ms */ /** * fu_plugin_get_name: */ const gchar * fu_plugin_get_name (void) { return "steelseries"; } /** * fu_plugin_device_probe: **/ gboolean fu_plugin_device_probe (FuPlugin *plugin, FuDevice *device, GError **error) { GUsbDeviceClaimInterfaceFlags flags; const gchar *platform_id; const guint iface_idx = 0x00; gboolean ret; gsize actual_len = 0; guint8 data[32]; guint i; g_autofree gchar *version = NULL; g_autoptr(GUsbContext) usb_ctx = NULL; g_autoptr(GUsbDevice) usb_device = NULL; /* get version */ platform_id = fu_device_get_id (device); usb_ctx = g_usb_context_new (NULL); usb_device = g_usb_context_find_by_platform_id (usb_ctx, platform_id, error); if (usb_device == NULL) return FALSE; /* get exclusive access */ if (!g_usb_device_open (usb_device, error)) return FALSE; flags = G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER; if (!g_usb_device_claim_interface (usb_device, iface_idx, flags, error)) { g_prefix_error (error, "failed to claim interface: "); return FALSE; } /* get firmware version on SteelSeries Rival 100 */ memset (data, 0x00, sizeof(data)); data[0] = 0x16; ret = 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, 0x09, 0x0200, 0x0000, data, sizeof(data), &actual_len, STEELSERIES_TRANSACTION_TIMEOUT, NULL, error); if (!ret) { g_prefix_error (error, "failed to do control transfer: "); return FALSE; } if (actual_len != 32) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "only wrote %" G_GSIZE_FORMAT "bytes", actual_len); } ret = g_usb_device_interrupt_transfer (usb_device, 0x81, /* EP1 IN */ data, sizeof(data), &actual_len, STEELSERIES_TRANSACTION_TIMEOUT, NULL, error); if (!ret) { g_prefix_error (error, "failed to do IN transfer: "); return FALSE; } if (actual_len != 32) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "only read %" G_GSIZE_FORMAT "bytes", actual_len); } /* update */ version = g_strdup_printf ("%i.%i.%i", data[0], data[1], data[2]); fu_device_set_version (device, version); g_debug ("overriding the version with %s", version); /* FIXME: we can't do this until we know how to flash the firmware */ // fu_device_add_flag (device, FU_DEVICE_FLAG_ALLOW_ONLINE); /* release device */ if (!g_usb_device_release_interface (usb_device, iface_idx, flags, error)) { g_prefix_error (error, "failed to release interface: "); return FALSE; } if (!g_usb_device_close (usb_device, error)) return FALSE; return TRUE; } /** * fu_plugin_device_update: **/ gboolean fu_plugin_device_update (FuPlugin *plugin, FuDevice *device, GBytes *data, GError **error) { const gchar *platform_id; const gchar *vendor_driver; g_autoptr(GUsbContext) usb_ctx = NULL; g_autoptr(GUsbDevice) usb_device = NULL; g_autoptr(GUsbDevice) usb_devnew = NULL; /* get GUsbDevice */ platform_id = fu_device_get_id (device); usb_ctx = g_usb_context_new (NULL); usb_device = g_usb_context_find_by_platform_id (usb_ctx, platform_id, error); if (usb_device == NULL) return FALSE; // if not bootloader // issue vendor specific command and wait for replug usb_devnew = g_usb_context_wait_for_replug (usb_ctx, usb_device, STEELSERIES_REPLUG_TIMEOUT, error); if (usb_devnew == NULL) return FALSE; /* open device */ if (!g_usb_device_open (usb_devnew, error)) return FALSE; // squirt in firmware /* close device */ if (!g_usb_device_close (usb_devnew, error)) return FALSE; return TRUE; } fwupd-0.7.0/src/plugins/fu-plugin-test.c000066400000000000000000000031141267747510300201550ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2016 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include "fu-plugin.h" struct FuPluginPrivate { GMutex mutex; }; /** * fu_plugin_get_name: */ const gchar * fu_plugin_get_name (void) { return "test"; } /** * fu_plugin_init: */ void fu_plugin_init (FuPlugin *plugin) { plugin->priv = FU_PLUGIN_GET_PRIVATE (FuPluginPrivate); /* only enable when testing */ if (g_getenv ("FWUPD_ENABLE_TEST_PLUGIN") == NULL) { plugin->enabled = FALSE; return; } g_debug ("init"); } /** * fu_plugin_destroy: */ void fu_plugin_destroy (FuPlugin *plugin) { g_debug ("destroy"); } /** * fu_plugin_startup: **/ gboolean fu_plugin_startup (FuPlugin *plugin, GError **error) { g_debug ("startup"); return TRUE; } fwupd-0.7.0/src/run-fwupd.sh000077500000000000000000000003341267747510300157340ustar00rootroot00000000000000#!/usr/bin/sh sudo \ LIBFWUP_ESRT_DIR="../../fwupdate/linux/sys/firmware/efi/esrt/" \ FWUPD_RPI_FW_DIR="../data/tests/rpiboot" \ FWUPD_ENABLE_TEST_PLUGIN="1" \ G_MESSAGES_DEBUG="all" \ ./fwupd --verbose