Codebase list fwupd / 50933bf
New upstream release (v0.6.0) Mario Limonciello 8 years ago
85 changed file(s) with 15559 addition(s) and 649 deletion(s). Raw diff Collapse all Expand all
33
44 SUBDIRS = \
55 libfwupd \
6 libdfu \
67 po \
78 data \
89 docs \
0 Version 0.5.4
0 Version 0.6.0
11 ~~~~~~~~~~~~~
2 Released: 2015-11-18
2 Released: 2015-12-07
3
4 Notes:
5 - This release adds a new GObject library called libdfu and a command line
6 client called dfu-tool. This is a low-level tool used to upgrade USB device
7 firmware and can either be shipped in the same package as fwupd or split off
8 as separate subpackages.
39
410 New Features:
5 - Use API available in fwupdate 0.5 to avoid writing temp files (Richard Hughes)
11 - Add support for automatically updating USB DFU-capable devices (Richard Hughes)
612
713 Bugfixes:
8 - Fix compile error against fwupdate 0.5 due to API bump (Mario Limonciello)
14 - Emit the changed signal after doing an update (Richard Hughes)
15 - Export the AppStream ID when returning device results (Richard Hughes)
16 - Fix compile with --disable-shared (Richard Hughes)
17 - Use new API available in fwup 0.5 (Richard Hughes, Mario Limonciello)
18 - Use the same device identification string format as Microsoft (Richard Hughes)
919
1020 Version 0.5.3
1121 ~~~~~~~~~~~~~
33
44 git shortlog 0.5.3.. | grep -i -v trivial | grep -v Merge > NEWS.new
55
6 Version 0.5.4
6 Version 0.6.0
77 ~~~~~~~~~~~~~
88 Released: 2015-xx-xx
99
2222 2. Commit changes to git:
2323
2424 # MAKE SURE THESE ARE CORRECT
25 export release_ver="0.5.4"
25 export release_ver="0.6.0"
2626
2727 git commit -a -m "Release fwupd ${release_ver}"
2828 git tag -s -f -m "Release fwupd ${release_ver}" "${release_ver}"
2121 fi
2222
2323 autopoint --force
24 gtkdocize || exit 1
2425 ACLOCAL="${ACLOCAL-aclocal} $ACLOCAL_FLAGS" AUTOPOINT='intltoolize --automake --copy' autoreconf --force --install --verbose
2526
2627 cd "$olddir"
11 AC_PREREQ(2.63)
22
33 m4_define([fwupd_major_version], [0])
4 m4_define([fwupd_minor_version], [5])
5 m4_define([fwupd_micro_version], [4])
4 m4_define([fwupd_minor_version], [6])
5 m4_define([fwupd_micro_version], [0])
66 m4_define([fwupd_version],
77 [fwupd_major_version.fwupd_minor_version.fwupd_micro_version])
88
4343
4444 # enable nice build output on automake1.11
4545 m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
46
47 # check for gtk-doc
48 GTK_DOC_CHECK([1.14],[--flavour no-tmpl])
4649
4750 AS_ALL_LINGUAS
4851 AC_PROG_CC
111114 [RELRO_LDFLAGS="-Wl,-z,relro,-z,now"])
112115 AC_SUBST([RELRO_LDFLAGS])
113116
117 # use -lm
118 LT_LIB_M
119 AC_SUBST(LIBM)
120
114121 dnl ---------------------------------------------------------------------------
115122 dnl - Check library dependencies
116123 dnl ---------------------------------------------------------------------------
118125 PKG_CHECK_MODULES(GUDEV, gudev-1.0)
119126 PKG_CHECK_MODULES(POLKIT, polkit-gobject-1 >= 0.103)
120127 PKG_CHECK_MODULES(GCAB, libgcab-1.0)
121 PKG_CHECK_MODULES(APPSTREAM_GLIB, appstream-glib >= 0.5.2)
122 PKG_CHECK_MODULES(GUSB, gusb >= 0.2.2)
128 PKG_CHECK_MODULES(APPSTREAM_GLIB, appstream-glib >= 0.5.4)
129 PKG_CHECK_MODULES(GUSB, gusb >= 0.2.8)
123130 PKG_CHECK_MODULES(SQLITE, sqlite3)
124131 PKG_CHECK_MODULES(ARCHIVE, libarchive)
125132 PKG_CHECK_MODULES(SOUP, libsoup-2.4 >= 2.51.92)
137144 AC_ARG_ENABLE(colorhug, AS_HELP_STRING([--enable-colorhug],[Enable ColorHug support]),
138145 enable_colorhug=$enableval, enable_colorhug=yes)
139146 if test x$enable_colorhug != xno; then
140 PKG_CHECK_MODULES(COLORHUG, colorhug >= 1.2.9)
147 PKG_CHECK_MODULES(COLORHUG, colorhug >= 1.2.12)
141148 AC_DEFINE(HAVE_COLORHUG,1,[Use ColorHug support])
142149 fi
143150 AM_CONDITIONAL(HAVE_COLORHUG, test x$enable_colorhug = xyes)
184191 dnl ---------------------------------------------------------------------------
185192 AC_CONFIG_FILES([
186193 Makefile
194 libdfu/Makefile
195 libdfu/dfu.pc
187196 libfwupd/fwupd-version.h
188197 libfwupd/fwupd.pc
189198 libfwupd/Makefile
192201 data/tests/Makefile
193202 data/tests/rpiupdate/Makefile
194203 data/tests/colorhug/Makefile
204 data/tests/dfu/Makefile
195205 docs/Makefile
206 docs/libdfu/Makefile
196207 docs/man/Makefile
197208 policy/Makefile
198209 po/Makefile.in
8383 %dir %{_libexecdir}/fwupd
8484 %{_libexecdir}/fwupd/fwupd
8585 %{_bindir}/fwupdmgr
86 %{_bindir}/dfu-tool
8687 %{_sysconfdir}/pki/fwupd
8788 %{_sysconfdir}/pki/fwupd-metadata
8889 %{_sysconfdir}/dbus-1/system.d/org.freedesktop.fwupd.conf
9192 %{_datadir}/polkit-1/rules.d/org.freedesktop.fwupd.rules
9293 %{_datadir}/dbus-1/system-services/org.freedesktop.fwupd.service
9394 %{_datadir}/man/man1/fwupdmgr.1.gz
95 %{_datadir}/man/man1/dfu-tool.1.gz
96 %{_datadir}/gtk-doc/html/libdfu
9497 %{_unitdir}/fwupd-offline-update.service
9598 %{_unitdir}/fwupd.service
9699 %{_unitdir}/system-update.target.wants/
00 SUBDIRS = \
11 colorhug \
2 dfu \
23 rpiupdate
34
45 test_files = \
0 EXTRA_DIST = \
1 example.bin \
2 example.dfu \
3 example.xdfu \
4 firmware.bin \
5 firmware.hex \
6 metadata.dfu \
7 kiibohd.dfu.bin \
8 dev_VRBRAIN.dfu
9
10 -include $(top_srcdir)/git.mk
Binary diff not shown
0 :044000003DEF20F080
1 :10400800FACF01F0FBCF02F0E9CF03F0EACF04F0DA
2 :10401800E1CF05F0E2CF06F0D9CF07F0DACF08F00C
3 :10402800F3CF09F0F4CF0AF0F6CF0BF0F7CF0CF08E
4 :10403800F8CF0DF0F5CF0EF00EC0F5FF0DC0F8FF6C
5 :104048000CC0F7FF0BC0F6FF0AC0F4FF09C0F3FF6E
6 :1040580008C0DAFF07C0D9FF06C0E2FF05C0E1FFCC
7 :1040680004C0EAFF03C0E9FF02C0FBFF01C0FAFF7A
8 :1040780011003FEF20F0000142EF20F03DEF20F06B
9 :00000001FF
00 SUBDIRS = \
1 libdfu \
12 man
23
4 EXTRA_DIST = \
5 dfu-metadata-store.md
6
37 -include $(top_srcdir)/git.mk
0
1 DFU File Format - Metadata Store Proposal
2 =========================================
3
4 Introduction
5 ------------
6
7 The DFU specification version 1.1 defines some target-specific data that can
8 optionally be included in the DFU file to ease firmware deployment.
9 These include items such as the runtime vendor, product and device release,
10 but nothing else and with no provision for extra metadata.
11
12 The DFU file specification does not specify any additional data structures
13 allowing vendors to include additional metadata, although does provide the
14 chance to include future additional data fields in the header in a backwards and
15 forwards compatible way by increasing the `header_len` value.
16
17 All software reading and writing DFU-format files should already be reading the
18 footer length from the file, rather than assuming a fixed footer length of 0x10
19 bytes.
20 This ensures that only the raw device firmware is sent to the device and not any
21 additional data fields added in future versions of the DFU specification.
22
23 There are valid reasons why we would want to add additional metadata into the
24 distributed DFU file. Reasons are listed as follows:
25
26 * Legal compliance, to tag a file with copyright and licensing information
27 * Business-specific metadata, for instance the SHA-1 git commit for the source
28 * Cryptographic information such as a SHA-256 hash or a detached GPG signature
29
30 Although the original authors of the specification allowed for future additions
31 to the specification, they only allowed us to extend the footer by 239 bytes as
32 the `header_len` value is specified as just one byte, and 16 bytes are already
33 specified by the specification.
34
35 This would explain why some vendors are using vendor-specific file prefix data
36 segments, for instance the DfuSe prefix specification from ST.
37 This specification is not aiming to expand or standardize the various
38 incompatible vendor-specific prefix specifications, but tries to squeeze the
39 additional metadata into the existing DFU footer space which is compatible with
40 all existing DFU-compliant software.
41
42 Specification
43 -------------
44
45 An additional structure would be present after the binary firmware data, and
46 notionally contained within the DFU footer itself, although specified as a
47 seporate object.
48
49 The representation in memory and on disk would be as follows:
50
51 uint16 signature='MD'
52 uint8 number_of_keys
53 uint8 key(n)_length
54 ... key(n) (no NUL)
55 uint8 value(n)_length
56 ... value(n) (no NUL)
57 <existing DFU footer>
58
59 If there are no metadata keys being set, it is expected that the metadata table
60 signature is not be written to the file, and that the footer should be again
61 0x10 bytes in length.
62
63 The signature of `MD` should also be checked before attempting to parse the
64 metadata store structure to ensure other vendor-specific extensions are not
65 already in use.
66
67 Conclusions
68 -----------
69
70 The metadata store proposal allows us to store a small amount of metadata
71 inside the DFU file footer.
72 If the original specification had included just one more byte for the footer
73 length (for instance a `uint16`, rather than a `uint8`) type then I would have
74 proposed a key type allowing integers, IEEE floating point, and strings, and
75 also made the number of keys and the length of keys much larger.
76 Working with what we've been given, we can support a useful easy-to-parse
77 extension that allows us to solve some of the real-world problems vendors are
78 facing when trying to distribute firmware files for devices that support
79 in-the-field device firmware upgrading.
80
81 Several deliberate compomises have been made to this proposal due to the
82 restricted space available:
83
84 * The metadata table signature is just two bytes
85 * The number of keys is limited to just 59 pairs
86 * Keys are limited to just 233 chars maximum
87 * Values are limited to just 233 chars maximum
88 * Types are limited to just strings (which can includes empty strings)
89 * Strings are written without a `NUL` trailing byte
90 * The metadata table uses variable offsets rather than fixed sizes
91
92 The key-value length in particular leads to some other best practices:
93
94 * A value for the 'License' key should be in SPDX format, NOT the full licence
95 * A value for the 'Copyright' key should just be the company name
96
97 The author is not already aware of any vendors using this additional data area,
98 but would be willing to work with any vendors who have implemented a similar
99 proprietary extension already or are planning to do so.
0 # This is a blank Makefile.am for using gtk-doc.
1 # Copy this to your project's API docs directory and modify the variables to
2 # suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples
3 # of using the various options.
4
5 # The name of the module, e.g. 'glib'.
6 DOC_MODULE=libdfu
7
8 # Uncomment for versioned docs and specify the version of the module, e.g. '2'.
9 #DOC_MODULE_VERSION=2
10
11 # The top-level XML file.
12 DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml
13
14 # Directories containing the source code.
15 # gtk-doc will search all .c and .h files beneath these paths
16 # for inline comments documenting functions and macros.
17 # e.g. DOC_SOURCE_DIR=$(top_srcdir)/gtk $(top_srcdir)/gdk
18 DOC_SOURCE_DIR=$(top_srcdir)/libdfu
19
20 # Extra options to pass to gtkdoc-scangobj. Normally not needed.
21 SCANGOBJ_OPTIONS=
22
23 # Extra options to supply to gtkdoc-scan.
24 # e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
25 SCAN_OPTIONS=
26
27 # Extra options to supply to gtkdoc-mkdb
28 # e.g. MKDB_OPTIONS=--xml-mode --output-format=xml
29 MKDB_OPTIONS=--xml-mode --output-format=xml
30
31 # Extra options to supply to gtkdoc-mkhtml
32 MKHTML_OPTIONS=
33
34 # Extra options to supply to gtkdoc-fixref. Normally not needed.
35 # e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
36 FIXXREF_OPTIONS=
37
38 # Used for dependencies. The docs will be rebuilt if any of these change.
39 # e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
40 # e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
41 HFILE_GLOB=$(top_srcdir)/libdfu/*.h
42 CFILE_GLOB=$(top_srcdir)/libdfu/*.c
43
44 # Extra header to include when scanning, which are not under DOC_SOURCE_DIR
45 # e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h
46 EXTRA_HFILES=
47
48 # Header files or dirs to ignore when scanning. Use base file/dir names
49 # e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
50 IGNORE_HFILES= \
51 dfu-device-private.h \
52 dfu-element-private.h \
53 dfu-image-private.h \
54 dfu-sector-private.h \
55 dfu-target-private.h
56
57 # Images to copy into HTML directory.
58 # e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
59 HTML_IMAGES=
60
61 # Extra files that are included by $(DOC_MAIN_SGML_FILE).
62 # e.g. content_files=running.xml building.xml changes-2.0.xml
63 content_files=
64
65 # Files where gtk-doc abbrevations (#GtkWidget) are expanded
66 # e.g. expand_content_files=running.xml
67 expand_content_files=
68
69 # CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
70 # Only needed if you are using gtkdoc-scangobj to dynamically query widget
71 # signals and properties.
72 # e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
73 # e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
74 GTKDOC_CFLAGS=
75 GTKDOC_LIBS=$(top_builddir)/libdfu/libdfu.la
76
77 # This includes the standard gtk-doc make rules, copied by gtkdocize.
78 include $(top_srcdir)/gtk-doc.make
79
80 # Comment this out if you want 'make check' to test you doc status
81 # and run some sanity checks
82 #if ENABLE_GTK_DOC
83 #TESTS_ENVIRONMENT = \
84 # DOC_MODULE=$(DOC_MODULE) DOC_MAIN_SGML_FILE=$(DOC_MAIN_SGML_FILE) \
85 # SRCDIR=$(abs_srcdir) BUILDDIR=$(abs_builddir)
86 #TESTS = $(GTKDOC_CHECK)
87 #endif
88
89 CLEANFILES= \
90 libdfu.args \
91 libdfu.hierarchy \
92 libdfu.interfaces \
93 libdfu.prerequisites \
94 libdfu.signals \
95 libdfu-*.txt \
96 *.stamp
97
98 -include $(top_srcdir)/git.mk
0 rm -f *.txt
1 rm -f colord-scan*
2 rm -f colord.types
3 rm -rf html/
4 rm -rf xml/
5 rm -rf tmpl/
6 rm -f *.stamp
7
0 <?xml version="1.0"?>
1 <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
2 "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
3 [
4 <!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
5 ]>
6 <book id="index">
7 <bookinfo>
8 <title>libdfu Reference Manual</title>
9 <releaseinfo>
10 for libdfu [VERSION].
11 The latest version of this documentation can be found on-line at
12 <ulink role="online-location" url="http://[SERVER]/libdfu/index.html">http://[SERVER]/libdfu/</ulink>.
13 </releaseinfo>
14 </bookinfo>
15
16 <reference id="intro">
17 <title>About libdfu</title>
18 <partintro>
19 <para>
20 libdfu is a library for updating firmware on DFU-capable devices.
21 <ulink url="https://en.wikipedia.org/wiki/USB#DFU">DFU</ulink>
22 is a standardised protocol used on many millions of devices
23 to safely update device firmware by the user.
24 Is is designed to be easy to implement in device bootloaders and
25 also easy to support in native host drivers.
26 Flashing firmware using DFU is supported in Windows, Linux and OS-X.
27 </para>
28 <para>
29 Updating firmware on a device is typically done using
30 <ulink url="http://www.fwupd.org/">fwupd</ulink> or by a session
31 application like GNOME Software.
32 You can also use <ulink url="http://dfu-util.sourceforge.net/">dfu-util</ulink>
33 which may support mode device types than <command>dfu-tool</command>
34 supplied by fwupd.
35 </para>
36 <para>
37 <command>libdfu</command> provides a medium-level API which is
38 available for all languages that support GObject Introspection.
39 It supports cancellation using <varname>GCancellable</varname>
40 and erro reporting using <varname>GError</varname>.
41 To download a device using the API it is as simple as getting
42 a <varname>GUsbDevice</varname> and then doing something like
43 this:
44 </para>
45 <programlisting>
46 dfu_firmware = dfu_firmware_new ();
47 if (!dfu_firmware_parse_data (dfu_firmware, blob_fw,
48 DFU_FIRMWARE_PARSE_FLAG_NONE, error))
49 return FALSE;
50 dfu_device = dfu_device_new (dev);
51 if (!dfu_device_download (dfu_device, dfu_firmware,
52 DFU_TARGET_TRANSFER_FLAG_DETACH |
53 DFU_TARGET_TRANSFER_FLAG_VERIFY |
54 DFU_TARGET_TRANSFER_FLAG_BOOT_RUNTIME,
55 cancelleable,
56 _progress_cb, userdata,
57 error))
58 return FALSE;
59 </programlisting>
60 <para>
61 You can read more about DFU in the <ulink url="http://www.usb.org/developers/docs/devclass_docs/DFU_1.1.pdf">official specification</ulink>.
62 </para>
63 </partintro>
64 </reference>
65
66 <chapter id="object-tree">
67 <title>Object Hierarchy</title>
68 <xi:include href="xml/tree_index.sgml"/>
69 </chapter>
70
71 <reference id="libdfu">
72 <title>libdfu</title>
73 <partintro>
74 <para>
75 Functionality exported by libdfu.
76 </para>
77 </partintro>
78 <xi:include href="xml/dfu-context.xml"/>
79 <xi:include href="xml/dfu-device.xml"/>
80 <xi:include href="xml/dfu-firmware.xml"/>
81 <xi:include href="xml/dfu-image.xml"/>
82 <xi:include href="xml/dfu-element.xml"/>
83 <xi:include href="xml/dfu-sector.xml"/>
84 <xi:include href="xml/dfu-target.xml"/>
85 <xi:include href="xml/dfu-common.xml"/>
86 <xi:include href="xml/dfu-error.xml"/>
87 </reference>
88
89 <index id="api-index-full">
90 <title>API Index</title>
91 <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
92 <xi:include href="xml/api-index-0.5.4.xml"/>
93 </index>
94
95 <index id="deprecated-api-index" role="deprecated">
96 <title>Index of deprecated API</title>
97 <xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
98 </index>
99 <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
100 </book>
0 dfu_context_get_type
1 dfu_device_get_type
2 dfu_element_get_type
3 dfu_firmware_get_type
4 dfu_image_get_type
5 dfu_target_get_type
6 dfu_sector_get_type
00 man_MANS_DIST = \
1 dfu-tool.1 \
12 fwupdmgr.1
23
34 EXTRA_DIST = \
5 dfu-tool.sgml \
46 fwupdmgr.sgml \
57 $(man_MANS_DIST)
68
810 $(man_MANS_DIST)
911
1012 fwupdmgr.1: fwupdmgr.sgml
13 $(AM_V_GEN) \
14 docbook2man $? > /dev/null
15 dfu-tool.1: dfu-tool.sgml
1116 $(AM_V_GEN) \
1217 docbook2man $? > /dev/null
1318
0 <!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
1 <!-- Please adjust the date whenever revising the manpage. -->
2 <!ENTITY date "<date>26 February,2015</date>">
3 <!ENTITY package "dfu-tool">
4 <!ENTITY gnu "<acronym>GNU</acronym>">
5 <!ENTITY gpl "&gnu; <acronym>GPL</acronym>">
6 ]>
7
8 <refentry>
9 <refentryinfo>
10 <address>
11 <email>richard@hughsie.com</email>;
12 </address>
13 <author>
14 <firstname>Richard</firstname>
15 <surname>Hughes</surname>
16 </author>
17 <copyright>
18 <year>2015</year>
19 <holder>Richard Hughes</holder>
20 </copyright>
21 &date;
22 </refentryinfo>
23 <refmeta>
24 <refentrytitle>dfu-tool</refentrytitle>
25 <manvolnum>1</manvolnum>
26 </refmeta>
27 <refnamediv>
28 <refname>&package;</refname>
29 <refpurpose>Device Firmware Upgrade Tool</refpurpose>
30 </refnamediv>
31 <refsynopsisdiv>
32 <cmdsynopsis>
33 <command>&package;</command>
34 <arg><option>--verbose</option></arg>
35 <arg><option>--version</option></arg>
36 <arg><option>--force</option></arg>
37 <arg><option>--device=VID:PID</option></arg>
38 <arg><option>--transfer-size=BYTES</option></arg>
39 </cmdsynopsis>
40 </refsynopsisdiv>
41 <refsect1>
42 <title>DESCRIPTION</title>
43 <para>
44 This manual page documents briefly the <command>&package;</command> command.
45 </para>
46 <para>
47 <command>&package;</command> allows a user to write various kinds of
48 firmware onto devices supporting the USB Device Firmware Upgrade protocol.
49 This tool can be used to switch the device from runtime and DFU modes to
50 allow reading the device contents from supported devices.
51 Either the whole device can be written in one operation, or individual
52 `targets' can be specified with the alternative name or number.
53 </para>
54 <para>
55 <command>&package;</command> uses the <literal>libdfu</literal> shared
56 library to perform actions.
57 Any syncronous actions can be safely cancelled and on failure will return
58 errors with both a type and a full textual description.
59 libdfu supports DFU 1.0, DFU 1.1 and the ST DfuSe vendor extension, and
60 handles many device `quirks' necessary for the real-world implementations
61 of <acronym>DFU</acronym>.
62 </para>
63 <para>
64 Additionally <command>&package;</command> can be used to convert firmware
65 from various different formats, or to modify details about the elements,
66 images and metadata contained inside the firmware file.
67 For example, you can easily convert DFU 1.1 firmware into the
68 vendor-specific DfuSe format, convert a Intel HEX file into a raw file
69 padded to a specific size, or add new copyright and licensing information
70 to an existing file.
71 Fields such as the vendor and product IDs can be changed, and the firmware
72 elements can be encrypted and decrypted using various different methods.
73 Merging two DfuSe files together is also possible, although specifying
74 different alt-setting numbers before merging is a good idea to avoid
75 confusion.
76 </para>
77 <para>
78 Although <command>&package;</command> tries to provide a large number of
79 easy-to-use commands, it may only be possible to do certain operations
80 using the <literal>libdfu</literal> library directly.
81 This is easier than it sounds, as the library is built with GObject
82 Introspection support making it usable in many languages such as C,
83 Javascript and Python.
84 Furthermore, using the library is a good idea if you want to perform
85 multiple operations on large firmware files, for instance,
86 converting from an Intel HEX file, padding to a certain size, setting
87 vendor and adding licensing information and then saving to a remote
88 location.
89 </para>
90 </refsect1>
91 <refsect1>
92 <title>OPTIONS</title>
93 <para>
94 This program follows the usual &gnu; command line syntax,
95 with long options starting with two dashes (<literal>-</literal>).
96 A summary of options is included below.
97 </para>
98 <variablelist>
99 <varlistentry>
100 <term>
101 <option>--help</option>
102 </term>
103 <listitem>
104 <para>Show summary of all the commands available for use.</para>
105 </listitem>
106 </varlistentry>
107 <varlistentry>
108 <term>
109 <option>--version</option>
110 </term>
111 <listitem>
112 <para>Show the version of <command>&package;</command> installed.</para>
113 </listitem>
114 </varlistentry>
115 <varlistentry>
116 <term>
117 <option>--verbose</option>
118 </term>
119 <listitem>
120 <para>Show extra debugging information.</para>
121 </listitem>
122 </varlistentry>
123 <varlistentry>
124 <term>
125 <option>--device=VID:PID</option>
126 </term>
127 <listitem>
128 <para>
129 If multiple DFU-capable devices are attached you can specify the
130 specific vendor and product ID of the DFU device you want to query.
131 </para>
132 </listitem>
133 </varlistentry>
134 <varlistentry>
135 <term>
136 <option>--transfer-size=BYTES</option>
137 </term>
138 <listitem>
139 <para>
140 Manually override the size of each USB transfer, which you may want
141 for unreliable hardware or when the device lies about the maximum
142 packet size it accepts.
143 </para>
144 </listitem>
145 </varlistentry>
146 <varlistentry>
147 <term>
148 <option>--force</option>
149 </term>
150 <listitem>
151 <para>
152 Force the operation, disregarding warnings or sanity checks like
153 file CRC and checksums.
154 This is useful if you really know what you are doing, or in the
155 specialised case of fuzz-testing libdfu.
156 </para>
157 </listitem>
158 </varlistentry>
159 </variablelist>
160 </refsect1>
161 <refsect1>
162 <title>DEVICE COMMANDS</title>
163 <para>
164 These commands are used to interface with DFU-capable devices.
165 </para>
166 <variablelist>
167 <varlistentry>
168 <term>
169 <option>list</option>
170 </term>
171 <listitem>
172 <para>
173 This command lists currently attached DFU capable devices.
174 Some devices do not support the official DFU <literal>runtime</literal>
175 mode and thus do not support auto-discovery using this command.
176 For those devices, putting the device into DFU mode manually (e.g. by
177 holding a button down when rebooting the device) will make it show
178 up here.
179 </para>
180 </listitem>
181 </varlistentry>
182 <varlistentry>
183 <term>
184 <option>detach</option>
185 </term>
186 <listitem>
187 <para>
188 This command detaches the currently attached DFU capable device into
189 a special programming mode.
190 Whilst the device is in this special <acronym>DFU</acronym> mode it
191 can not be used as a normal device.
192 For example, a printer will not accept documents when in DFU mode.
193 </para>
194 </listitem>
195 </varlistentry>
196 <varlistentry>
197 <term>
198 <option>attach</option>
199 </term>
200 <listitem>
201 <para>
202 This command attaches a DFU capable device back to runtime so it can
203 be used as a normal device.
204 Some devices do not support attaching, and need to be manually
205 disconnected and connected before changing modes.
206 </para>
207 </listitem>
208 </varlistentry>
209 <varlistentry>
210 <term>
211 <option>watch</option>
212 </term>
213 <listitem>
214 <para>
215 This command watches DFU devices being hotplugged and can be used to
216 verify <literal>libdfu</literal> matches up the runtime and DFU modes
217 when attaching and detaching.
218 Use <option>CTRL+C</option> to make this command quit.
219 </para>
220 </listitem>
221 </varlistentry>
222 <varlistentry>
223 <term>
224 <option>read FILENAME</option>
225 </term>
226 <listitem>
227 <para>
228 This command uploads all the firmware from device into a file.
229 If the device has multiple partitions exported as different alternative
230 sections then they will all be read into a multi-image DfuSe-format
231 file.
232 If you just want the contents of one partition, <option>read-alt</option>
233 is the command you want.
234 </para>
235 </listitem>
236 </varlistentry>
237 <varlistentry>
238 <term>
239 <option>read-alt FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID</option>
240 </term>
241 <listitem>
242 <para>
243 This command uploads firmware from one partition into a file.
244 You can specify the partition by either the ALT-ID or ALT-NAME if set.
245 </para>
246 <para>e.g. <command>&package; read-alt backup.dfu SRAM</command></para>
247 </listitem>
248 </varlistentry>
249 <varlistentry>
250 <term>
251 <option>write</option>
252 </term>
253 <listitem>
254 <para>
255 This command downloads firmware from a file into all possible
256 partitions of a device.
257 If you only want to write one partition, <option>write-alt</option>
258 is the command you want.
259 </para>
260 </listitem>
261 </varlistentry>
262 <varlistentry>
263 <term>
264 <option>write-alt FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID [IMAGE-ALT-NAME|IMAGE-ALT-ID]</option>
265 </term>
266 <listitem>
267 <para>
268 This command downloads firmware from the file into one partition.
269 You can specify the partition by either the ALT-ID or ALT-NAME if set.
270 </para>
271 <para>e.g. <command>&package; sram.dfu SRAM __SRAM</command></para>
272 </listitem>
273 </varlistentry>
274 </variablelist>
275 </refsect1>
276 <refsect1>
277 <title>FIRMWARE COMMANDS</title>
278 <para>
279 These commands are used to read and modify existing firmware files.
280 </para>
281 <variablelist>
282 <varlistentry>
283 <term>
284 <option>dump FILENAME</option>
285 </term>
286 <listitem>
287 <para>
288 This command dumps all know details about a firmware file.
289 The complete memory map is shown, along with any metadata or vendor
290 information about the firmware file.
291 </para>
292 </listitem>
293 </varlistentry>
294 <varlistentry>
295 <term>
296 <option>convert FORMAT FILE-IN FILE-OUT [SIZE]</option>
297 </term>
298 <listitem>
299 <para>
300 This command converts the firmware from one format to another, optionally
301 padding to a certain size.
302 Possible values for the destination <option>FORMAT</option> include:
303 <literal>raw</literal>, <literal>ihex</literal>,
304 <literal>dfu</literal> and <literal>dfuse</literal>.
305 The <option>FILE-IN</option> and <option>FILE-OUT</option> values can
306 be the same if the source file is to be overwritten.
307 Although padding increases the file size with no apparent advantages
308 it can be used to support devices that do not store the runtime image
309 size and where validation of the written firmware is required.
310 </para>
311 <para>e.g. <command>&package; dfu firmware.hex firmware.dfu 8000</command></para>
312 </listitem>
313 </varlistentry>
314 <varlistentry>
315 <term>
316 <option>encrypt FILENAME-IN FILENAME-OUT TYPE KEY</option>
317 </term>
318 <listitem>
319 <para>
320 This command encrypts firmware data.
321 Only the image contents are actually modified, the DFU footer and
322 DfuSe header are left unaltered.
323 Possible values for the destination <option>TYPE</option> include:
324 <literal>xtea</literal> and <literal>nop</literal>.
325 If the <option>KEY</option> is not of the required length it is used
326 as an input to a hash function which can produce a key of the
327 required size.
328 </para>
329 <para>e.g. <command>&package; firmware.dfu firmware.xdfu xtea deadbeef</command></para>
330 </listitem>
331 </varlistentry>
332 <varlistentry>
333 <term>
334 <option>decrypt FILENAME-IN FILENAME-OUT TYPE KEY</option>
335 </term>
336 <listitem>
337 <para>
338 This command decrypts firmware data.
339 Only the image contents are actually modified, the DFU footer and
340 DfuSe header are left unaltered.
341 Possible values for the destination <option>TYPE</option> include:
342 <literal>xtea</literal> and <literal>nop</literal>.
343 If the <option>KEY</option> is not of the required length it is used
344 as an input to a hash function which can produce a key of the
345 required size.
346 </para>
347 <para>e.g. <command>&package; firmware.xdfu firmware.dfu xtea deadbeef</command></para>
348 </listitem>
349 </varlistentry>
350 <varlistentry>
351 <term>
352 <option>merge FILE-OUT FILE1 FILE2 [FILE3...]</option>
353 </term>
354 <listitem>
355 <para>
356 This command merges multiple firmware files into one file.
357 Although you can merge files with the same ALT-ID or ALT-NAME this
358 probably isn't what you want to do.
359 </para>
360 <para>e.g. <command>&package; combined.dfu lib.dfu app.dfu</command></para>
361 </listitem>
362 </varlistentry>
363 <varlistentry>
364 <term>
365 <option>set-alt-setting FILE ALT-ID</option>
366 </term>
367 <listitem>
368 <para>
369 This command modifies the alternative number on firmware file.
370 </para>
371 <para>e.g. <command>&package; firmware.dfu 1</command></para>
372 </listitem>
373 </varlistentry>
374 <varlistentry>
375 <term>
376 <option>set-alt-setting-name</option>
377 </term>
378 <listitem>
379 <para>
380 This command modifies the alternative name on firmware file.
381 </para>
382 <para>e.g. <command>&package; firmware.dfu SRAM</command></para>
383 </listitem>
384 </varlistentry>
385 <varlistentry>
386 <term>
387 <option>set-metadata FILE KEY VALUE</option>
388 </term>
389 <listitem>
390 <para>
391 This command adds or modifies existing metadata on a firmware file.
392 NOTE: There is only very limited metadata storage space in DFU files,
393 so keys and values should be kept as short as possible.
394 In particular, the <literal>License</literal> value should be
395 specified in SPDX format.
396 </para>
397 <para>e.g. <command>&package; firmware.dfu Licence GPL-2.0+</command></para>
398 </listitem>
399 </varlistentry>
400 <varlistentry>
401 <term>
402 <option>set-vendor FILE VID</option>
403 </term>
404 <listitem>
405 <para>
406 This command sets vendor ID on a firmware file that will be used to
407 match specific devices.
408 Values of <literal>ffff</literal> will match any device vendor.
409 </para>
410 <para>e.g. <command>&package; firmware.dfu 273f</command></para>
411 </listitem>
412 </varlistentry>
413 <varlistentry>
414 <term>
415 <option>set-product FILE PID</option>
416 </term>
417 <listitem>
418 <para>
419 This command sets the product ID on a firmware file that will be used to
420 match specific devices.
421 Values of <literal>ffff</literal> will match any device product.
422 </para>
423 <para>e.g. <command>&package; firmware.dfu 1004</command></para>
424 </listitem>
425 </varlistentry>
426 <varlistentry>
427 <term>
428 <option>set-release FILE RELEASE</option>
429 </term>
430 <listitem>
431 <para>
432 This command sets the release version on firmware file that will be used to
433 match specific devices.
434 Values of <literal>ffff</literal> will match any device release.
435 </para>
436 <para>e.g. <command>&package; firmware.dfu ffff</command></para>
437 </listitem>
438 </varlistentry>
439 </variablelist>
440 </refsect1>
441 <refsect1>
442 <title>AUTHOR</title>
443 <para>This manual page was written by Richard Hughes <email>richard@hughsie.com</email>.
444 </para>
445 </refsect1>
446 </refentry>
447
448 <!-- Keep this comment at the end of the file
449 Local variables:
450 mode: sgml
451 sgml-omittag:t
452 sgml-shorttag:t
453 sgml-minimize-attributes:nil
454 sgml-always-quote-attributes:t
455 sgml-indent-step:2
456 sgml-indent-data:t
457 sgml-parent-document:nil
458 sgml-default-dtd-file:nil
459 sgml-exposed-tags:nil
460 sgml-local-catalogs:nil
461 sgml-local-ecat-files:nil
462 End:
463 -->
0 if HAVE_INTROSPECTION
1 -include $(INTROSPECTION_MAKEFILE)
2 INTROSPECTION_GIRS =
3 INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir)
4 INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
5 endif
6
7 AM_CPPFLAGS = \
8 $(APPSTREAM_GLIB_CFLAGS) \
9 $(GLIB_CFLAGS) \
10 $(GUSB_CFLAGS) \
11 $(PIE_CFLAGS) \
12 -I$(top_srcdir)/libdfu \
13 -I$(top_srcdir) \
14 -I$(top_builddir) \
15 -DG_USB_API_IS_SUBJECT_TO_CHANGE \
16 -DG_LOG_DOMAIN=\"libdfu\" \
17 -DTESTDATADIR=\""$(top_srcdir)/data/tests/dfu"\" \
18 -DLOCALEDIR=\""$(localedir)"\"
19
20 FWUPD_LIBS = \
21 $(top_builddir)/libfwupd/libfwupd.la
22
23 lib_LTLIBRARIES = \
24 libdfu.la
25
26 libdfu_includedir = $(includedir)/fwupd-1
27 libdfu_include_HEADERS = \
28 dfu.h
29
30 libdfubase_includedir = $(libdfu_includedir)/libdfu
31 libdfubase_include_HEADERS = \
32 dfu-common.h \
33 dfu-context.h \
34 dfu-device.h \
35 dfu-element.h \
36 dfu-error.h \
37 dfu-firmware.h \
38 dfu-image.h \
39 dfu-sector.h \
40 dfu-target.h
41
42 libdfu_la_SOURCES = \
43 dfu.h \
44 dfu-common.c \
45 dfu-common.h \
46 dfu-context.c \
47 dfu-context.h \
48 dfu-device.c \
49 dfu-device.h \
50 dfu-device-private.h \
51 dfu-element.c \
52 dfu-element.h \
53 dfu-element-private.h \
54 dfu-error.c \
55 dfu-error.h \
56 dfu-firmware.c \
57 dfu-firmware.h \
58 dfu-image.c \
59 dfu-image.h \
60 dfu-image-private.h \
61 dfu-sector.c \
62 dfu-sector.h \
63 dfu-sector-private.h \
64 dfu-target.c \
65 dfu-target.h \
66 dfu-target-private.h
67
68 libdfu_la_LIBADD = \
69 $(FWUPD_LIBS) \
70 $(GUSB_LIBS) \
71 $(GLIB_LIBS) \
72 $(LIBM)
73
74 libdfu_la_LDFLAGS = \
75 -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
76 -export-dynamic \
77 -no-undefined \
78 -export-symbols-regex '^dfu_.*'
79
80 libdfu_la_CFLAGS = \
81 $(PIE_CFLAGS) \
82 $(WARNINGFLAGS_C)
83
84 pkgconfigdir = $(libdir)/pkgconfig
85 pkgconfig_DATA = dfu.pc
86
87 EXTRA_DIST = \
88 dfu.pc.in
89
90 bin_PROGRAMS = \
91 dfu-tool
92
93 dfu_tool_SOURCES = \
94 dfu-tool.c
95
96 dfu_tool_LDADD = \
97 $(lib_LTLIBRARIES) \
98 $(APPSTREAM_GLIB_LIBS) \
99 $(GLIB_LIBS) \
100 $(GUSB_LIBS) \
101 $(LIBM)
102
103 dfu_tool_CFLAGS = -DEGG_TEST $(AM_CFLAGS) $(WARNINGFLAGS_C)
104
105 TESTS_ENVIRONMENT = \
106 libtool --mode=execute valgrind \
107 --quiet \
108 --leak-check=full \
109 --show-possibly-lost=no
110
111 check_PROGRAMS = \
112 dfu-self-test
113
114 dfu_self_test_SOURCES = \
115 dfu-self-test.c
116
117 dfu_self_test_LDADD = \
118 $(lib_LTLIBRARIES) \
119 $(GLIB_LIBS) \
120 $(GUSB_LIBS)
121
122 dfu_self_test_CFLAGS = -DEGG_TEST $(AM_CFLAGS) $(WARNINGFLAGS_C)
123
124 TESTS = dfu-self-test
125
126 CLEANFILES = *.log *.trs $(BUILT_SOURCES)
127
128 MAINTAINERCLEANFILES = *.dfu *.bin
129 if HAVE_INTROSPECTION
130 introspection_sources = \
131 $(libdfu_la_SOURCES)
132
133 Dfu-1.0.gir: libdfu.la
134 Dfu_1_0_gir_INCLUDES = GObject-2.0 Gio-2.0 GUsb-1.0
135 Dfu_1_0_gir_CFLAGS = $(AM_CPPFLAGS)
136 Dfu_1_0_gir_SCANNERFLAGS = --identifier-prefix=Dfu \
137 --symbol-prefix=dfu \
138 --warn-all \
139 --add-include-path=$(srcdir) \
140 --c-include="dfu.h"
141 Dfu_1_0_gir_EXPORT_PACKAGES = dfu
142 Dfu_1_0_gir_LIBS = libdfu.la
143 Dfu_1_0_gir_FILES = $(introspection_sources)
144 INTROSPECTION_GIRS += Dfu-1.0.gir
145
146 girdir = $(datadir)/gir-1.0
147 gir_DATA = $(INTROSPECTION_GIRS)
148
149 typelibdir = $(libdir)/girepository-1.0
150 typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
151
152 CLEANFILES += $(gir_DATA) $(typelib_DATA) *.log *.trs *.test
153 endif
154
155 clean-local:
156 rm -f *~
157
158 -include $(top_srcdir)/git.mk
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /**
22 * SECTION:dfu-common
23 * @short_description: Common functions for DFU
24 *
25 * These helper objects allow converting from enum values to strings.
26 */
27
28 #include "config.h"
29
30 #include "dfu-common.h"
31
32 /**
33 * dfu_state_to_string:
34 * @state: a #DfuState, e.g. %DFU_STATE_DFU_MANIFEST
35 *
36 * Converts an enumerated value to a string.
37 *
38 * Return value: a string
39 *
40 * Since: 0.5.4
41 **/
42 const gchar *
43 dfu_state_to_string (DfuState state)
44 {
45 if (state == DFU_STATE_APP_IDLE)
46 return "appIDLE";
47 if (state == DFU_STATE_APP_DETACH)
48 return "appDETACH";
49 if (state == DFU_STATE_DFU_IDLE)
50 return "dfuIDLE";
51 if (state == DFU_STATE_DFU_DNLOAD_SYNC)
52 return "dfuDNLOAD-SYNC";
53 if (state == DFU_STATE_DFU_DNBUSY)
54 return "dfuDNBUSY";
55 if (state == DFU_STATE_DFU_DNLOAD_IDLE)
56 return "dfuDNLOAD-IDLE";
57 if (state == DFU_STATE_DFU_MANIFEST_SYNC)
58 return "dfuMANIFEST-SYNC";
59 if (state == DFU_STATE_DFU_MANIFEST)
60 return "dfuMANIFEST";
61 if (state == DFU_STATE_DFU_MANIFEST_WAIT_RESET)
62 return "dfuMANIFEST-WAIT-RESET";
63 if (state == DFU_STATE_DFU_UPLOAD_IDLE)
64 return "dfuUPLOAD-IDLE";
65 if (state == DFU_STATE_DFU_ERROR)
66 return "dfuERROR";
67 return NULL;
68 }
69
70 /**
71 * dfu_status_to_string:
72 * @status: a #DfuStatus, e.g. %DFU_STATUS_ERR_ERASE
73 *
74 * Converts an enumerated value to a string.
75 *
76 * Return value: a string
77 *
78 * Since: 0.5.4
79 **/
80 const gchar *
81 dfu_status_to_string (DfuStatus status)
82 {
83 if (status == DFU_STATUS_OK)
84 return "OK";
85 if (status == DFU_STATUS_ERR_TARGET)
86 return "errTARGET";
87 if (status == DFU_STATUS_ERR_FILE)
88 return "errFILE";
89 if (status == DFU_STATUS_ERR_WRITE)
90 return "errwrite";
91 if (status == DFU_STATUS_ERR_ERASE)
92 return "errERASE";
93 if (status == DFU_STATUS_ERR_CHECK_ERASED)
94 return "errCHECK_ERASED";
95 if (status == DFU_STATUS_ERR_PROG)
96 return "errPROG";
97 if (status == DFU_STATUS_ERR_VERIFY)
98 return "errVERIFY";
99 if (status == DFU_STATUS_ERR_ADDRESS)
100 return "errADDRESS";
101 if (status == DFU_STATUS_ERR_NOTDONE)
102 return "errNOTDONE";
103 if (status == DFU_STATUS_ERR_FIRMWARE)
104 return "errFIRMWARE";
105 if (status == DFU_STATUS_ERR_VENDOR)
106 return "errVENDOR";
107 if (status == DFU_STATUS_ERR_USBR)
108 return "errUSBR";
109 if (status == DFU_STATUS_ERR_POR)
110 return "errPOR";
111 if (status == DFU_STATUS_ERR_UNKNOWN)
112 return "errUNKNOWN";
113 if (status == DFU_STATUS_ERR_STALLDPKT)
114 return "errSTALLDPKT";
115 return NULL;
116 }
117
118 /**
119 * dfu_mode_to_string:
120 * @mode: a #DfuMode, e.g. %DFU_MODE_RUNTIME
121 *
122 * Converts an enumerated value to a string.
123 *
124 * Return value: a string
125 *
126 * Since: 0.5.4
127 **/
128 const gchar *
129 dfu_mode_to_string (DfuMode mode)
130 {
131 if (mode == DFU_MODE_RUNTIME)
132 return "runtime";
133 if (mode == DFU_MODE_DFU)
134 return "DFU";
135 return NULL;
136 }
137
138 /**
139 * dfu_cipher_kind_to_string:
140 * @cipher_kind: a #DfuCipherKind, e.g. %DFU_CIPHER_KIND_XTEA
141 *
142 * Converts an enumerated value to a string.
143 *
144 * Return value: a string
145 *
146 * Since: 0.5.4
147 **/
148 const gchar *
149 dfu_cipher_kind_to_string (DfuCipherKind cipher_kind)
150 {
151 if (cipher_kind == DFU_CIPHER_KIND_NONE)
152 return "none";
153 if (cipher_kind == DFU_CIPHER_KIND_XTEA)
154 return "xtea";
155 return NULL;
156 }
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #ifndef __DFU_COMMON_H
22 #define __DFU_COMMON_H
23
24 #include <glib.h>
25 #include <gusb.h>
26
27 G_BEGIN_DECLS
28
29 /**
30 * DfuRequest:
31 * @DFU_REQUEST_DETACH: Detach
32 * @DFU_REQUEST_DNLOAD: Download host-to-device
33 * @DFU_REQUEST_UPLOAD: Upload device-to-host
34 * @DFU_REQUEST_GETSTATUS: Get the device status
35 * @DFU_REQUEST_CLRSTATUS: Clear the device status
36 * @DFU_REQUEST_GETSTATE: Get the last set state
37 * @DFU_REQUEST_ABORT: Abort the current transfer
38 *
39 * The DFU request kinds.
40 **/
41 typedef enum {
42 DFU_REQUEST_DETACH = 0x00,
43 DFU_REQUEST_DNLOAD = 0x01,
44 DFU_REQUEST_UPLOAD = 0x02,
45 DFU_REQUEST_GETSTATUS = 0x03,
46 DFU_REQUEST_CLRSTATUS = 0x04,
47 DFU_REQUEST_GETSTATE = 0x05,
48 DFU_REQUEST_ABORT = 0x06,
49 /*< private >*/
50 DFU_REQUEST_LAST
51 } DfuRequest;
52
53 /**
54 * DfuStatus:
55 * @DFU_STATUS_OK: No error condition is present
56 * @DFU_STATUS_ERR_TARGET: File is not targeted for use by this device
57 * @DFU_STATUS_ERR_FILE: File is for this device but fails a verification test
58 * @DFU_STATUS_ERR_WRITE: Device is unable to write memory
59 * @DFU_STATUS_ERR_ERASE: Memory erase function failed
60 * @DFU_STATUS_ERR_CHECK_ERASED: Memory erase check failed
61 * @DFU_STATUS_ERR_PROG: Program memory function failed
62 * @DFU_STATUS_ERR_VERIFY: Programmed memory failed verification
63 * @DFU_STATUS_ERR_ADDRESS: Cannot program memory due to received address that isout of range
64 * @DFU_STATUS_ERR_NOTDONE: Received DFU_DNLOAD with wLength = 0 but data is incomplete
65 * @DFU_STATUS_ERR_FIRMWARE: Device firmware is corrupt
66 * @DFU_STATUS_ERR_VENDOR: iString indicates a vendor-specific error
67 * @DFU_STATUS_ERR_USBR: Device detected unexpected USB reset signaling
68 * @DFU_STATUS_ERR_POR: Device detected unexpected power on reset
69 * @DFU_STATUS_ERR_UNKNOWN: Something unexpected went wrong
70 * @DFU_STATUS_ERR_STALLDPKT: Device stalled an unexpected request
71 *
72 * The status enumerated kind.
73 **/
74 typedef enum {
75 DFU_STATUS_OK = 0x00,
76 DFU_STATUS_ERR_TARGET = 0x01,
77 DFU_STATUS_ERR_FILE = 0x02,
78 DFU_STATUS_ERR_WRITE = 0x03,
79 DFU_STATUS_ERR_ERASE = 0x04,
80 DFU_STATUS_ERR_CHECK_ERASED = 0x05,
81 DFU_STATUS_ERR_PROG = 0x06,
82 DFU_STATUS_ERR_VERIFY = 0x07,
83 DFU_STATUS_ERR_ADDRESS = 0x08,
84 DFU_STATUS_ERR_NOTDONE = 0x09,
85 DFU_STATUS_ERR_FIRMWARE = 0x0a,
86 DFU_STATUS_ERR_VENDOR = 0x0b,
87 DFU_STATUS_ERR_USBR = 0x0c,
88 DFU_STATUS_ERR_POR = 0x0d,
89 DFU_STATUS_ERR_UNKNOWN = 0x0e,
90 DFU_STATUS_ERR_STALLDPKT = 0x0f,
91 /*< private >*/
92 DFU_STATUS_LAST
93 } DfuStatus;
94
95 /**
96 * DfuState:
97 * @DFU_STATE_APP_IDLE: State 0
98 * @DFU_STATE_APP_DETACH: State 1
99 * @DFU_STATE_DFU_IDLE: State 2
100 * @DFU_STATE_DFU_DNLOAD_SYNC: State 3
101 * @DFU_STATE_DFU_DNBUSY: State 4
102 * @DFU_STATE_DFU_DNLOAD_IDLE: State 5
103 * @DFU_STATE_DFU_MANIFEST_SYNC: State 6
104 * @DFU_STATE_DFU_MANIFEST: State 7
105 * @DFU_STATE_DFU_MANIFEST_WAIT_RESET: State 8
106 * @DFU_STATE_DFU_UPLOAD_IDLE: State 9
107 * @DFU_STATE_DFU_ERROR: State 10
108 *
109 * The state enumerated kind.
110 **/
111 typedef enum {
112 DFU_STATE_APP_IDLE = 0x00,
113 DFU_STATE_APP_DETACH = 0x01,
114 DFU_STATE_DFU_IDLE = 0x02,
115 DFU_STATE_DFU_DNLOAD_SYNC = 0x03,
116 DFU_STATE_DFU_DNBUSY = 0x04,
117 DFU_STATE_DFU_DNLOAD_IDLE = 0x05,
118 DFU_STATE_DFU_MANIFEST_SYNC = 0x06,
119 DFU_STATE_DFU_MANIFEST = 0x07,
120 DFU_STATE_DFU_MANIFEST_WAIT_RESET = 0x08,
121 DFU_STATE_DFU_UPLOAD_IDLE = 0x09,
122 DFU_STATE_DFU_ERROR = 0x0a,
123 /*< private >*/
124 DFU_STATE_LAST
125 } DfuState;
126
127 /**
128 * DfuMode:
129 * @DFU_MODE_UNKNOWN: Unknown mode
130 * @DFU_MODE_RUNTIME: Runtime mode
131 * @DFU_MODE_DFU: Bootloader mode
132 *
133 * The mode enumerated kind.
134 **/
135 typedef enum {
136 DFU_MODE_UNKNOWN,
137 DFU_MODE_RUNTIME,
138 DFU_MODE_DFU,
139 /*< private >*/
140 DFU_MODE_LAST
141 } DfuMode;
142
143 /**
144 * DfuCipherKind:
145 * @DFU_CIPHER_KIND_NONE: No cipher detected
146 * @DFU_CIPHER_KIND_XTEA: XTEA cipher detected
147 *
148 * The type of cipher used for transfering the firmware.
149 **/
150 typedef enum {
151 DFU_CIPHER_KIND_NONE,
152 DFU_CIPHER_KIND_XTEA,
153 /*< private >*/
154 DFU_CIPHER_KIND_LAST
155 } DfuCipherKind;
156
157 #define DFU_METADATA_KEY_LICENSE "License"
158 #define DFU_METADATA_KEY_COPYRIGHT "Copyright"
159 #define DFU_METADATA_KEY_CIPHER_KIND "CipherKind"
160
161 const gchar *dfu_state_to_string (DfuState state);
162 const gchar *dfu_status_to_string (DfuStatus status);
163 const gchar *dfu_mode_to_string (DfuMode mode);
164 const gchar *dfu_cipher_kind_to_string (DfuCipherKind cipher_kind);
165
166 G_END_DECLS
167
168 #endif /* __DFU_COMMON_H */
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /**
22 * SECTION:dfu-context
23 * @short_description: A system context for managing DFU-capable devices
24 *
25 * This object allows discovering and monitoring hotpluggable DFU devices.
26 *
27 * When using #DfuContext the device is given some time to re-enumerate after a
28 * detach or reset. This allows client programs to continue using the #DfuDevice
29 * without dealing with the device hotplug and the #GUsbDevice changing.
30 * Using this object may be easier than using GUsbContext directly.
31 *
32 * Please be aware that after device detach or reset the number of #DfuTarget
33 * objects may be different and so need to be re-requested.
34 *
35 * See also: #DfuDevice, #DfuTarget
36 */
37
38 #include "config.h"
39
40 #include <gusb.h>
41
42 #include "dfu-device-private.h"
43 #include "dfu-error.h"
44 #include "dfu-context.h"
45
46 static void dfu_context_finalize (GObject *object);
47
48 /**
49 * DfuContextPrivate:
50 *
51 * Private #DfuContext data
52 **/
53 typedef struct {
54 GUsbContext *usb_ctx;
55 GPtrArray *devices; /* of DfuContextItem */
56 guint timeout; /* in ms */
57 } DfuContextPrivate;
58
59 typedef struct {
60 DfuContext *context; /* not refcounted */
61 DfuDevice *device; /* not refcounted */
62 guint timeout_id;
63 guint state_change_id;
64 } DfuContextItem;
65
66 enum {
67 SIGNAL_DEVICE_ADDED,
68 SIGNAL_DEVICE_REMOVED,
69 SIGNAL_DEVICE_CHANGED,
70 SIGNAL_LAST
71 };
72
73 static guint signals [SIGNAL_LAST] = { 0 };
74
75 G_DEFINE_TYPE_WITH_PRIVATE (DfuContext, dfu_context, G_TYPE_OBJECT)
76 #define GET_PRIVATE(o) (dfu_context_get_instance_private (o))
77
78 /**
79 * dfu_context_device_free:
80 **/
81 static void
82 dfu_context_device_free (DfuContextItem *item)
83 {
84 if (item->timeout_id > 0)
85 g_source_remove (item->timeout_id);
86 if (item->timeout_id > 0) {
87 g_signal_handler_disconnect (item->device,
88 item->state_change_id);
89 }
90 g_object_unref (item->device);
91 g_free (item);
92 }
93
94 /**
95 * dfu_context_class_init:
96 **/
97 static void
98 dfu_context_class_init (DfuContextClass *klass)
99 {
100 GObjectClass *object_class = G_OBJECT_CLASS (klass);
101
102 /**
103 * DfuContext::device-added:
104 * @context: the #DfuContext instance that emitted the signal
105 * @device: the #DfuDevice
106 *
107 * The ::device-added signal is emitted when a new DFU device is connected.
108 *
109 * Since: 0.5.4
110 **/
111 signals [SIGNAL_DEVICE_ADDED] =
112 g_signal_new ("device-added",
113 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
114 G_STRUCT_OFFSET (DfuContextClass, device_added),
115 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
116 G_TYPE_NONE, 1, DFU_TYPE_DEVICE);
117
118 /**
119 * DfuContext::device-removed:
120 * @context: the #DfuContext instance that emitted the signal
121 * @device: the #DfuDevice
122 *
123 * The ::device-removed signal is emitted when a DFU device is removed.
124 *
125 * Since: 0.5.4
126 **/
127 signals [SIGNAL_DEVICE_REMOVED] =
128 g_signal_new ("device-removed",
129 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
130 G_STRUCT_OFFSET (DfuContextClass, device_removed),
131 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
132 G_TYPE_NONE, 1, DFU_TYPE_DEVICE);
133
134 /**
135 * DfuContext::device-changed:
136 * @context: the #DfuContext instance that emitted the signal
137 * @device: the #DfuDevice
138 *
139 * The ::device-changed signal is emitted when a DFU device is changed,
140 * typically when it has detached or been reset.
141 *
142 * Since: 0.5.4
143 **/
144 signals [SIGNAL_DEVICE_CHANGED] =
145 g_signal_new ("device-changed",
146 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
147 G_STRUCT_OFFSET (DfuContextClass, device_changed),
148 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
149 G_TYPE_NONE, 1, DFU_TYPE_DEVICE);
150
151 object_class->finalize = dfu_context_finalize;
152 }
153
154 /**
155 * dfu_context_get_device_id:
156 **/
157 static gchar *
158 dfu_context_get_device_id (DfuDevice *device)
159 {
160 GUsbDevice *dev;
161 dev = dfu_device_get_usb_dev (device);
162 if (dev == NULL)
163 return g_strdup (dfu_device_get_platform_id (device));
164 return g_strdup_printf ("%04x:%04x [%s]",
165 g_usb_device_get_vid (dev),
166 g_usb_device_get_pid (dev),
167 g_usb_device_get_platform_id (dev));
168 }
169
170 /**
171 * dfu_context_find_item_by_platform_id:
172 **/
173 static DfuContextItem *
174 dfu_context_find_item_by_platform_id (DfuContext *context, const gchar *platform_id)
175 {
176 DfuContextPrivate *priv = GET_PRIVATE (context);
177 DfuContextItem *item;
178 guint i;
179
180 /* do we have this device */
181 for (i = 0; i < priv->devices->len; i++) {
182 item = g_ptr_array_index (priv->devices, i);
183 if (g_strcmp0 (dfu_device_get_platform_id (item->device), platform_id) == 0)
184 return item;
185 }
186 return NULL;
187 }
188
189 /**
190 * dfu_context_remove_item:
191 **/
192 static void
193 dfu_context_remove_item (DfuContextItem *item)
194 {
195 DfuContextPrivate *priv = GET_PRIVATE (item->context);
196 g_autofree gchar *device_id = NULL;
197
198 /* log something */
199 device_id = dfu_context_get_device_id (item->device);
200 g_debug ("%s was removed", device_id);
201
202 g_signal_emit (item->context, signals[SIGNAL_DEVICE_REMOVED], 0, item->device);
203 g_ptr_array_remove (priv->devices, item);
204 }
205
206 /**
207 * dfu_context_device_timeout_cb:
208 **/
209 static gboolean
210 dfu_context_device_timeout_cb (gpointer user_data)
211 {
212 DfuContextItem *item = (DfuContextItem *) user_data;
213 g_autofree gchar *device_id = NULL;
214
215 /* bad firmware? */
216 device_id = dfu_context_get_device_id (item->device);
217 g_debug ("%s did not come back as a DFU capable device", device_id);
218 dfu_context_remove_item (item);
219 return FALSE;
220 }
221
222 /**
223 * dfu_context_device_state_cb:
224 **/
225 static void
226 dfu_context_device_state_cb (DfuDevice *device, DfuState state, DfuContext *context)
227 {
228 g_autofree gchar *device_id = NULL;
229 device_id = dfu_context_get_device_id (device);
230 g_debug ("%s state now: %s", device_id, dfu_state_to_string (state));
231 g_signal_emit (context, signals[SIGNAL_DEVICE_CHANGED], 0, device);
232 }
233
234 /**
235 * dfu_context_device_added_cb:
236 **/
237 static void
238 dfu_context_device_added_cb (GUsbContext *usb_context,
239 GUsbDevice *usb_device,
240 DfuContext *context)
241 {
242 DfuContextPrivate *priv = GET_PRIVATE (context);
243 DfuDevice *device;
244 DfuContextItem *item;
245 const gchar *platform_id;
246 g_autofree gchar *device_id = NULL;
247 g_autoptr(GError) error = NULL;
248
249 /* are we waiting for this device to come back? */
250 platform_id = g_usb_device_get_platform_id (usb_device);
251 item = dfu_context_find_item_by_platform_id (context, platform_id);
252 if (item != NULL) {
253 device_id = dfu_context_get_device_id (item->device);
254 if (item->timeout_id > 0) {
255 g_debug ("cancelling the remove timeout");
256 g_source_remove (item->timeout_id);
257 item->timeout_id = 0;
258 }
259
260 /* try and be helpful; we may be a daemon like fwupd watching a
261 * DFU device after dfu-tool or dfu-util has detached the
262 * device on th command line */
263 if (!dfu_device_set_new_usb_dev (item->device, usb_device, NULL, &error))
264 g_warning ("Failed to set new device: %s", error->message);
265
266 /* inform the UI */
267 g_signal_emit (context, signals[SIGNAL_DEVICE_CHANGED], 0, item->device);
268 g_debug ("device %s came back", device_id);
269 return;
270 }
271
272 /* is this a DFU-capable device */
273 device = dfu_device_new (usb_device);
274 if (device == NULL) {
275 g_debug ("device was not DFU capable");
276 return;
277 }
278
279 /* add */
280 item = g_new0 (DfuContextItem, 1);
281 item->context = context;
282 item->device = device;
283 item->state_change_id =
284 g_signal_connect (item->device, "state-changed",
285 G_CALLBACK (dfu_context_device_state_cb), context);
286 g_ptr_array_add (priv->devices, item);
287 g_signal_emit (context, signals[SIGNAL_DEVICE_ADDED], 0, device);
288 device_id = dfu_context_get_device_id (item->device);
289 g_debug ("device %s was added", device_id);
290 }
291
292 /**
293 * dfu_context_device_removed_cb:
294 **/
295 static void
296 dfu_context_device_removed_cb (GUsbContext *usb_context,
297 GUsbDevice *usb_device,
298 DfuContext *context)
299 {
300 DfuContextPrivate *priv = GET_PRIVATE (context);
301 DfuContextItem *item;
302 const gchar *platform_id;
303
304 /* find the item */
305 platform_id = g_usb_device_get_platform_id (usb_device);
306 item = dfu_context_find_item_by_platform_id (context, platform_id);
307 if (item == NULL)
308 return;
309
310 /* mark the backing USB device as invalid */
311 dfu_device_set_new_usb_dev (item->device, NULL, NULL, NULL);
312
313 /* this item has just detached */
314 if (item->timeout_id > 0)
315 g_source_remove (item->timeout_id);
316 item->timeout_id =
317 g_timeout_add (priv->timeout, dfu_context_device_timeout_cb, item);
318 }
319
320 /**
321 * dfu_context_init:
322 **/
323 static void
324 dfu_context_init (DfuContext *context)
325 {
326 DfuContextPrivate *priv = GET_PRIVATE (context);
327 priv->timeout = 5000;
328 priv->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) dfu_context_device_free);
329 priv->usb_ctx = g_usb_context_new (NULL);
330 g_signal_connect (priv->usb_ctx, "device-added",
331 G_CALLBACK (dfu_context_device_added_cb), context);
332 g_signal_connect (priv->usb_ctx, "device-removed",
333 G_CALLBACK (dfu_context_device_removed_cb), context);
334 }
335
336 /**
337 * dfu_context_finalize:
338 **/
339 static void
340 dfu_context_finalize (GObject *object)
341 {
342 DfuContext *context = DFU_CONTEXT (object);
343 DfuContextPrivate *priv = GET_PRIVATE (context);
344
345 g_ptr_array_unref (priv->devices);
346 g_object_unref (priv->usb_ctx);
347
348 G_OBJECT_CLASS (dfu_context_parent_class)->finalize (object);
349 }
350
351 /**
352 * dfu_context_new:
353 *
354 * Creates a new DFU context object.
355 *
356 * Return value: a new #DfuContext
357 *
358 * Since: 0.5.4
359 **/
360 DfuContext *
361 dfu_context_new (void)
362 {
363 DfuContext *context;
364 context = g_object_new (DFU_TYPE_CONTEXT, NULL);
365 return context;
366 }
367
368 /**
369 * dfu_context_get_timeout:
370 * @context: a #DfuContext
371 *
372 * Gets the wait-for-replug timeout.
373 *
374 * Return value: value in milliseconds
375 *
376 * Since: 0.5.4
377 **/
378 guint
379 dfu_context_get_timeout (DfuContext *context)
380 {
381 DfuContextPrivate *priv = GET_PRIVATE (context);
382 g_return_val_if_fail (DFU_IS_CONTEXT (context), 0);
383 return priv->timeout;
384 }
385
386
387 /**
388 * dfu_context_set_timeout:
389 * @context: a #DfuContext
390 * @timeout: a timeout in milliseconds
391 *
392 * Sets the wait-for-replug timeout.
393 * This is the longest we will wait for a device to re-enumerate after
394 * disconnecting. Using longer values will result in any UI not updating in a
395 * good time, but using too short values will result in devices being removed
396 * and re-added as different #DfuDevice's.
397 *
398 * Since: 0.5.4
399 **/
400 void
401 dfu_context_set_timeout (DfuContext *context, guint timeout)
402 {
403 DfuContextPrivate *priv = GET_PRIVATE (context);
404 g_return_if_fail (DFU_IS_CONTEXT (context));
405 priv->timeout = timeout;
406 }
407
408
409 /**
410 * dfu_context_enumerate:
411 * @context: a #DfuContext
412 * @error: a #GError, or %NULL
413 *
414 * Opens a DFU-capable context.
415 *
416 * Return value: %TRUE for success
417 *
418 * Since: 0.5.4
419 **/
420 gboolean
421 dfu_context_enumerate (DfuContext *context, GError **error)
422 {
423 DfuContextPrivate *priv = GET_PRIVATE (context);
424 g_return_val_if_fail (DFU_IS_CONTEXT (context), FALSE);
425 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
426 g_usb_context_enumerate (priv->usb_ctx);
427 return TRUE;
428 }
429
430 /**
431 * dfu_context_get_devices:
432 * @context: a #DfuContext
433 *
434 * Gets all the DFU-capable devices on the system.
435 *
436 * Return value: (element-type DfuDevice) (transfer container): array of devices
437 *
438 * Since: 0.5.4
439 **/
440 GPtrArray *
441 dfu_context_get_devices (DfuContext *context)
442 {
443 DfuContextPrivate *priv = GET_PRIVATE (context);
444 DfuContextItem *item;
445 GPtrArray *devices;
446 guint i;
447
448 g_return_val_if_fail (DFU_IS_CONTEXT (context), NULL);
449
450 devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
451 for (i = 0; i < priv->devices->len; i++) {
452 item = g_ptr_array_index (priv->devices, i);
453 g_ptr_array_add (devices, g_object_ref (item->device));
454 }
455 return devices;
456 }
457
458 /**
459 * dfu_context_get_device_by_vid_pid:
460 * @context: a #DfuContext
461 * @vid: a vendor ID
462 * @pid: a product ID
463 * @error: a #GError, or %NULL
464 *
465 * Finds a device in the context with a specific vendor:product ID.
466 * An error is returned if more than one device matches.
467 *
468 * Return value: (transfer full): a #DfuDevice for success, or %NULL for an error
469 *
470 * Since: 0.5.4
471 **/
472 DfuDevice *
473 dfu_context_get_device_by_vid_pid (DfuContext *context,
474 guint16 vid, guint16 pid,
475 GError **error)
476 {
477 DfuContextPrivate *priv = GET_PRIVATE (context);
478 DfuContextItem *item;
479 DfuDevice *device = NULL;
480 GUsbDevice *dev;
481 guint i;
482
483 g_return_val_if_fail (DFU_IS_CONTEXT (context), FALSE);
484 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
485
486 /* search all devices */
487 for (i = 0; i < priv->devices->len; i++) {
488
489 /* match */
490 item = g_ptr_array_index (priv->devices, i);
491 dev = dfu_device_get_usb_dev (item->device);
492 if (g_usb_device_get_vid (dev) == vid &&
493 g_usb_device_get_pid (dev) == pid) {
494 if (device != NULL) {
495 g_set_error (error,
496 DFU_ERROR,
497 DFU_ERROR_INVALID_DEVICE,
498 "multiple device matches for %04x:%04x",
499 vid, pid);
500 return NULL;
501 }
502 device = item->device;
503 continue;
504 }
505 }
506 if (device == NULL) {
507 g_set_error (error,
508 DFU_ERROR,
509 DFU_ERROR_NOT_FOUND,
510 "no device matches for %04x:%04x",
511 vid, pid);
512 return NULL;
513 }
514 return g_object_ref (device);
515 }
516
517 /**
518 * dfu_context_get_device_by_platform_id:
519 * @context: a #DfuContext
520 * @platform_id: a platform ID
521 * @error: a #GError, or %NULL
522 *
523 * Finds a device in the context with a specific platform ID.
524 *
525 * Return value: (transfer full): a #DfuDevice for success, or %NULL for an error
526 *
527 * Since: 0.5.4
528 **/
529 DfuDevice *
530 dfu_context_get_device_by_platform_id (DfuContext *context,
531 const gchar *platform_id,
532 GError **error)
533 {
534 DfuContextPrivate *priv = GET_PRIVATE (context);
535 DfuContextItem *item;
536 guint i;
537
538 g_return_val_if_fail (DFU_IS_CONTEXT (context), FALSE);
539 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
540
541 /* search all devices */
542 for (i = 0; i < priv->devices->len; i++) {
543 item = g_ptr_array_index (priv->devices, i);
544 if (g_strcmp0 (dfu_device_get_platform_id (item->device),
545 platform_id) == 0) {
546 return g_object_ref (item->device);
547 }
548 }
549 g_set_error (error,
550 DFU_ERROR,
551 DFU_ERROR_NOT_FOUND,
552 "no device matches for %s",
553 platform_id);
554 return NULL;
555 }
556
557 /**
558 * dfu_context_get_device_default:
559 * @context: a #DfuContext
560 * @error: a #GError, or %NULL
561 *
562 * Gets the default device in the context.
563 * An error is returned if more than one device exists.
564 *
565 * Return value: (transfer full): a #DfuDevice for success, or %NULL for an error
566 *
567 * Since: 0.5.4
568 **/
569 DfuDevice *
570 dfu_context_get_device_default (DfuContext *context, GError **error)
571 {
572 DfuContextPrivate *priv = GET_PRIVATE (context);
573 DfuContextItem *item;
574
575 g_return_val_if_fail (DFU_IS_CONTEXT (context), FALSE);
576 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
577
578 /* none */
579 if (priv->devices->len == 0) {
580 g_set_error_literal (error,
581 DFU_ERROR,
582 DFU_ERROR_NOT_FOUND,
583 "no attached DFU device");
584 return NULL;
585 }
586
587 /* multiple */
588 if (priv->devices->len > 1) {
589 g_set_error_literal (error,
590 DFU_ERROR,
591 DFU_ERROR_INVALID_DEVICE,
592 "more than one attached DFU device");
593 return NULL;
594 }
595 item = g_ptr_array_index (priv->devices, 0);
596 return g_object_ref (item->device);
597 }
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #ifndef __DFU_CONTEXT_H
22 #define __DFU_CONTEXT_H
23
24 #include <glib-object.h>
25 #include <gio/gio.h>
26
27 #include "dfu-device.h"
28
29 G_BEGIN_DECLS
30
31 #define DFU_TYPE_CONTEXT (dfu_context_get_type ())
32 G_DECLARE_DERIVABLE_TYPE (DfuContext, dfu_context, DFU, CONTEXT, GObject)
33
34 struct _DfuContextClass
35 {
36 GObjectClass parent_class;
37 void (*device_added) (DfuContext *context,
38 DfuDevice *device);
39 void (*device_removed) (DfuContext *context,
40 DfuDevice *device);
41 void (*device_changed) (DfuContext *context,
42 DfuDevice *device);
43 /*< private >*/
44 /* Padding for future expansion */
45 void (*_dfu_context_reserved1) (void);
46 void (*_dfu_context_reserved2) (void);
47 void (*_dfu_context_reserved3) (void);
48 void (*_dfu_context_reserved4) (void);
49 void (*_dfu_context_reserved5) (void);
50 void (*_dfu_context_reserved6) (void);
51 void (*_dfu_context_reserved7) (void);
52 void (*_dfu_context_reserved8) (void);
53 void (*_dfu_context_reserved9) (void);
54 };
55
56 DfuContext *dfu_context_new (void);
57 gboolean dfu_context_enumerate (DfuContext *context,
58 GError **error);
59 GPtrArray *dfu_context_get_devices (DfuContext *context);
60 guint dfu_context_get_timeout (DfuContext *context);
61 void dfu_context_set_timeout (DfuContext *context,
62 guint timeout);
63 DfuDevice *dfu_context_get_device_by_vid_pid (DfuContext *context,
64 guint16 vid,
65 guint16 pid,
66 GError **error);
67 DfuDevice *dfu_context_get_device_by_platform_id (DfuContext *context,
68 const gchar *platform_id,
69 GError **error);
70 DfuDevice *dfu_context_get_device_default (DfuContext *context,
71 GError **error);
72
73 G_END_DECLS
74
75 #endif /* __DFU_CONTEXT_H */
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #ifndef __DFU_DEVICE_PRIVATE_H
22 #define __DFU_DEVICE_PRIVATE_H
23
24 #include <glib-object.h>
25 #include <gio/gio.h>
26 #include <gusb.h>
27
28 #include "dfu-device.h"
29
30 G_BEGIN_DECLS
31
32 #define DFU_DEVICE_REPLUG_TIMEOUT 5000 /* ms */
33
34 /**
35 * DfuDeviceQuirks:
36 * @DFU_DEVICE_QUIRK_NONE: No device quirks
37 * @DFU_DEVICE_QUIRK_IGNORE_POLLTIMEOUT: Ignore the device download timeout
38 * @DFU_DEVICE_QUIRK_FORCE_DFU_MODE: Force DFU mode
39 * @DFU_DEVICE_QUIRK_IGNORE_INVALID_VERSION: Ignore invalid version numbers
40 * @DFU_DEVICE_QUIRK_USE_PROTOCOL_ZERO: Fix up the protocol number
41 * @DFU_DEVICE_QUIRK_NO_PID_CHANGE: Accept the same VID:PID when changing modes
42 * @DFU_DEVICE_QUIRK_NO_GET_STATUS_UPLOAD: Do not do GetStatus when uploading
43 * @DFU_DEVICE_QUIRK_NO_DFU_RUNTIME: No DFU runtime interface is provided
44 * @DFU_DEVICE_QUIRK_ATTACH_UPLOAD_DOWNLOAD: An upload or download is required for attach
45 *
46 * The workarounds for different devices.
47 **/
48 typedef enum {
49 DFU_DEVICE_QUIRK_NONE = 0,
50 DFU_DEVICE_QUIRK_IGNORE_POLLTIMEOUT = (1 << 0),
51 DFU_DEVICE_QUIRK_FORCE_DFU_MODE = (1 << 1),
52 DFU_DEVICE_QUIRK_IGNORE_INVALID_VERSION = (1 << 2),
53 DFU_DEVICE_QUIRK_USE_PROTOCOL_ZERO = (1 << 3),
54 DFU_DEVICE_QUIRK_NO_PID_CHANGE = (1 << 4),
55 DFU_DEVICE_QUIRK_NO_GET_STATUS_UPLOAD = (1 << 5),
56 DFU_DEVICE_QUIRK_NO_DFU_RUNTIME = (1 << 6),
57 DFU_DEVICE_QUIRK_ATTACH_UPLOAD_DOWNLOAD = (1 << 7),
58 /*< private >*/
59 DFU_DEVICE_QUIRK_LAST
60 } DfuDeviceQuirks;
61
62 /**
63 * DfuDeviceAttributes:
64 * @DFU_DEVICE_ATTRIBUTE_NONE: No attributes set
65 * @DFU_DEVICE_ATTRIBUTE_CAN_DOWNLOAD: Can download from host->device
66 * @DFU_DEVICE_ATTRIBUTE_CAN_UPLOAD: Can upload from device->host
67 * @DFU_DEVICE_ATTRIBUTE_MANIFEST_TOL: Can answer GetStatus in manifest
68 * @DFU_DEVICE_ATTRIBUTE_WILL_DETACH: Will self-detach
69 * @DFU_DEVICE_ATTRIBUTE_CAN_ACCELERATE: Use a larger transfer size for speed
70 *
71 * The device DFU attributes.
72 **/
73 typedef enum {
74 DFU_DEVICE_ATTRIBUTE_NONE = 0,
75 DFU_DEVICE_ATTRIBUTE_CAN_DOWNLOAD = (1 << 0),
76 DFU_DEVICE_ATTRIBUTE_CAN_UPLOAD = (1 << 1),
77 DFU_DEVICE_ATTRIBUTE_MANIFEST_TOL = (1 << 2),
78 DFU_DEVICE_ATTRIBUTE_WILL_DETACH = (1 << 3),
79 DFU_DEVICE_ATTRIBUTE_CAN_ACCELERATE = (1 << 7),
80 /*< private >*/
81 DFU_DEVICE_ATTRIBUTE_LAST
82 } DfuDeviceAttributes;
83
84 GUsbDevice *dfu_device_get_usb_dev (DfuDevice *device);
85
86 gboolean dfu_device_has_dfuse_support (DfuDevice *device);
87 gboolean dfu_device_has_attribute (DfuDevice *device,
88 DfuDeviceAttributes attribute);
89 gboolean dfu_device_has_quirk (DfuDevice *device,
90 DfuDeviceQuirks quirk);
91
92 void dfu_device_error_fixup (DfuDevice *device,
93 GCancellable *cancellable,
94 GError **error);
95 guint dfu_device_get_download_timeout (DfuDevice *device);
96 gchar *dfu_device_get_quirks_as_string (DfuDevice *device);
97 gboolean dfu_device_set_new_usb_dev (DfuDevice *device,
98 GUsbDevice *dev,
99 GCancellable *cancellable,
100 GError **error);
101
102 G_END_DECLS
103
104 #endif /* __DFU_DEVICE_PRIVATE_H */
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /**
22 * SECTION:dfu-device
23 * @short_description: Object representing a DFU-capable device
24 *
25 * This object allows two things:
26 *
27 * - Downloading from the host to the device, optionally with
28 * verification using a DFU or DfuSe firmware file.
29 *
30 * - Uploading from the device to the host to a DFU or DfuSe firmware
31 * file. The file format is chosen automatically, with DfuSe being
32 * chosen if the device contains more than one target.
33 *
34 * See also: #DfuTarget, #DfuFirmware
35 */
36
37 #include "config.h"
38
39 #include <string.h>
40
41 #include "dfu-common.h"
42 #include "dfu-device-private.h"
43 #include "dfu-error.h"
44 #include "dfu-target-private.h"
45
46 static void dfu_device_finalize (GObject *object);
47
48 /**
49 * DfuDevicePrivate:
50 *
51 * Private #DfuDevice data
52 **/
53 typedef struct {
54 DfuDeviceAttributes attributes;
55 DfuDeviceQuirks quirks;
56 DfuMode mode;
57 DfuState state;
58 DfuStatus status;
59 GPtrArray *targets;
60 GUsbDevice *dev;
61 gboolean open_new_dev; /* if set new GUsbDevice */
62 gboolean dfuse_supported;
63 gboolean done_upload_or_download;
64 gchar *display_name;
65 gchar *platform_id;
66 guint16 runtime_pid;
67 guint16 runtime_vid;
68 guint16 runtime_release;
69 guint16 transfer_size;
70 guint8 iface_number;
71 guint dnload_timeout;
72 guint timeout_ms;
73 } DfuDevicePrivate;
74
75 enum {
76 SIGNAL_STATUS_CHANGED,
77 SIGNAL_STATE_CHANGED,
78 SIGNAL_PERCENTAGE_CHANGED,
79 SIGNAL_LAST
80 };
81
82 static guint signals [SIGNAL_LAST] = { 0 };
83
84 G_DEFINE_TYPE_WITH_PRIVATE (DfuDevice, dfu_device, G_TYPE_OBJECT)
85 #define GET_PRIVATE(o) (dfu_device_get_instance_private (o))
86
87 /**
88 * dfu_device_class_init:
89 **/
90 static void
91 dfu_device_class_init (DfuDeviceClass *klass)
92 {
93 GObjectClass *object_class = G_OBJECT_CLASS (klass);
94
95 /**
96 * DfuDevice::status-changed:
97 * @device: the #DfuDevice instance that emitted the signal
98 * @status: the new #DfuStatus
99 *
100 * The ::status-changed signal is emitted when the status changes.
101 *
102 * Since: 0.5.4
103 **/
104 signals [SIGNAL_STATUS_CHANGED] =
105 g_signal_new ("status-changed",
106 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
107 G_STRUCT_OFFSET (DfuDeviceClass, status_changed),
108 NULL, NULL, g_cclosure_marshal_VOID__UINT,
109 G_TYPE_NONE, 1, G_TYPE_UINT);
110
111 /**
112 * DfuDevice::state-changed:
113 * @device: the #DfuDevice instance that emitted the signal
114 * @state: the new #DfuState
115 *
116 * The ::state-changed signal is emitted when the state changes.
117 *
118 * Since: 0.5.4
119 **/
120 signals [SIGNAL_STATE_CHANGED] =
121 g_signal_new ("state-changed",
122 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
123 G_STRUCT_OFFSET (DfuDeviceClass, state_changed),
124 NULL, NULL, g_cclosure_marshal_VOID__UINT,
125 G_TYPE_NONE, 1, G_TYPE_UINT);
126
127 /**
128 * DfuDevice::percentage-changed:
129 * @device: the #DfuDevice instance that emitted the signal
130 * @percentage: the new percentage
131 *
132 * The ::percentage-changed signal is emitted when the percentage changes.
133 *
134 * Since: 0.5.4
135 **/
136 signals [SIGNAL_PERCENTAGE_CHANGED] =
137 g_signal_new ("percentage-changed",
138 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
139 G_STRUCT_OFFSET (DfuDeviceClass, percentage_changed),
140 NULL, NULL, g_cclosure_marshal_VOID__UINT,
141 G_TYPE_NONE, 1, G_TYPE_UINT);
142
143 object_class->finalize = dfu_device_finalize;
144 }
145
146 /**
147 * dfu_device_init:
148 **/
149 static void
150 dfu_device_init (DfuDevice *device)
151 {
152 DfuDevicePrivate *priv = GET_PRIVATE (device);
153 priv->iface_number = 0xff;
154 priv->runtime_pid = 0xffff;
155 priv->runtime_vid = 0xffff;
156 priv->runtime_release = 0xffff;
157 priv->state = DFU_STATE_APP_IDLE;
158 priv->status = DFU_STATUS_OK;
159 priv->targets = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
160 priv->timeout_ms = 500;
161 priv->transfer_size = 64;
162 }
163
164 /**
165 * dfu_device_get_transfer_size:
166 * @device: a #GUsbDevice
167 *
168 * Gets the transfer size in bytes.
169 *
170 * Return value: packet size, or 0 for unknown
171 *
172 * Since: 0.5.4
173 **/
174 guint16
175 dfu_device_get_transfer_size (DfuDevice *device)
176 {
177 DfuDevicePrivate *priv = GET_PRIVATE (device);
178 g_return_val_if_fail (DFU_IS_DEVICE (device), 0xffff);
179 return priv->transfer_size;
180 }
181
182 /**
183 * dfu_device_get_download_timeout:
184 * @device: a #GUsbDevice
185 *
186 * Gets the download timeout in ms.
187 *
188 * Return value: delay, or 0 for unknown
189 *
190 * Since: 0.5.4
191 **/
192 guint
193 dfu_device_get_download_timeout (DfuDevice *device)
194 {
195 DfuDevicePrivate *priv = GET_PRIVATE (device);
196 g_return_val_if_fail (DFU_IS_DEVICE (device), 0);
197 return priv->dnload_timeout;
198 }
199
200 /**
201 * dfu_device_set_transfer_size:
202 * @device: a #GUsbDevice
203 * @transfer_size: maximum packet size
204 *
205 * Sets the transfer size in bytes.
206 *
207 * Since: 0.5.4
208 **/
209 void
210 dfu_device_set_transfer_size (DfuDevice *device, guint16 transfer_size)
211 {
212 DfuDevicePrivate *priv = GET_PRIVATE (device);
213 g_return_if_fail (DFU_IS_DEVICE (device));
214 priv->transfer_size = transfer_size;
215 }
216
217 /**
218 * dfu_device_finalize:
219 **/
220 static void
221 dfu_device_finalize (GObject *object)
222 {
223 DfuDevice *device = DFU_DEVICE (object);
224 DfuDevicePrivate *priv = GET_PRIVATE (device);
225
226 /* don't rely on this */
227 if (priv->dev != NULL)
228 g_usb_device_close (priv->dev, NULL);
229
230 g_free (priv->display_name);
231 g_free (priv->platform_id);
232 g_ptr_array_unref (priv->targets);
233
234 G_OBJECT_CLASS (dfu_device_parent_class)->finalize (object);
235 }
236
237 typedef struct __attribute__((packed)) {
238 guint8 bLength;
239 guint8 bDescriptorType;
240 guint8 bmAttributes;
241 guint16 wDetachTimeOut;
242 guint16 wTransferSize;
243 guint16 bcdDFUVersion;
244 } DfuFuncDescriptor;
245
246 /**
247 * dfu_device_parse_iface_data:
248 **/
249 static void
250 dfu_device_parse_iface_data (DfuDevice *device, GBytes *iface_data)
251 {
252 DfuDevicePrivate *priv = GET_PRIVATE (device);
253 const DfuFuncDescriptor *desc;
254 gsize iface_data_length;
255
256 /* parse the functional descriptor */
257 desc = g_bytes_get_data (iface_data, &iface_data_length);
258 if (iface_data_length != 0x09) {
259 g_warning ("interface found, but not interface data");
260 return;
261 }
262
263 /* check sanity */
264 if (desc->bLength != 0x09) {
265 g_warning ("DFU interface data has incorrect length: 0x%02x",
266 desc->bLength);
267 }
268
269 /* check transfer size */
270 priv->transfer_size = desc->wTransferSize;
271 if (priv->transfer_size == 0x0000) {
272 g_warning ("DFU transfer size invalid, using default: 0x%04x",
273 desc->wTransferSize);
274 priv->transfer_size = 64;
275 }
276
277 /* check DFU version */
278 if (priv->quirks & DFU_DEVICE_QUIRK_IGNORE_INVALID_VERSION) {
279 g_debug ("ignoring quirked DFU version");
280 } else {
281 if (desc->bcdDFUVersion == 0x0100 ||
282 desc->bcdDFUVersion == 0x0101) {
283 g_debug ("basic DFU, no DfuSe support");
284 priv->dfuse_supported = FALSE;
285 } else if (desc->bcdDFUVersion == 0x011a) {
286 g_debug ("DfuSe support");
287 priv->dfuse_supported = TRUE;
288 } else {
289 g_warning ("DFU version is invalid: 0x%04x",
290 desc->bcdDFUVersion);
291 }
292 }
293
294 /* ST-specific */
295 if (priv->dfuse_supported &&
296 desc->bmAttributes & DFU_DEVICE_ATTRIBUTE_CAN_ACCELERATE)
297 priv->transfer_size = 0x1000;
298
299 /* get attributes about the DFU operation */
300 priv->attributes = desc->bmAttributes;
301 }
302
303 /**
304 * dfu_device_update_from_iface:
305 **/
306 static gboolean
307 dfu_device_update_from_iface (DfuDevice *device, GUsbInterface *iface)
308 {
309 DfuMode target_mode = DFU_MODE_UNKNOWN;
310 DfuDevicePrivate *priv = GET_PRIVATE (device);
311
312 /* runtime */
313 if (g_usb_interface_get_protocol (iface) == 0x01)
314 target_mode = DFU_MODE_RUNTIME;
315
316 /* DFU */
317 if (g_usb_interface_get_protocol (iface) == 0x02)
318 target_mode = DFU_MODE_DFU;
319
320 /* the DSO Nano has uses 0 instead of 2 when in DFU target_mode */
321 if (dfu_device_has_quirk (device, DFU_DEVICE_QUIRK_USE_PROTOCOL_ZERO) &&
322 g_usb_interface_get_protocol (iface) == 0x00)
323 target_mode = DFU_MODE_DFU;
324
325 /* nothing found */
326 if (target_mode == DFU_MODE_UNKNOWN)
327 return FALSE;
328
329 /* in DFU mode, the interface is supposed to be 0 */
330 if (target_mode == DFU_MODE_DFU && g_usb_interface_get_number (iface) != 0)
331 g_warning ("iface has to be 0 in DFU mode, got 0x%02i",
332 g_usb_interface_get_number (iface));
333
334 /* some devices set the wrong mode */
335 if (dfu_device_has_quirk (device, DFU_DEVICE_QUIRK_FORCE_DFU_MODE))
336 target_mode = DFU_MODE_DFU;
337
338 /* save for reset */
339 if (target_mode == DFU_MODE_RUNTIME ||
340 (priv->quirks & DFU_DEVICE_QUIRK_NO_PID_CHANGE)) {
341 priv->runtime_vid = g_usb_device_get_vid (priv->dev);
342 priv->runtime_pid = g_usb_device_get_pid (priv->dev);
343 priv->runtime_release = g_usb_device_get_release (priv->dev);
344 }
345
346 priv->mode = target_mode;
347 return TRUE;
348 }
349
350 /**
351 * dfu_device_add_targets:
352 **/
353 static gboolean
354 dfu_device_add_targets (DfuDevice *device)
355 {
356 DfuDevicePrivate *priv = GET_PRIVATE (device);
357 guint i;
358 GUsbInterface *iface;
359 g_autoptr(GPtrArray) ifaces = NULL;
360
361 /* add all DFU-capable targets */
362 ifaces = g_usb_device_get_interfaces (priv->dev, NULL);
363 if (ifaces == NULL)
364 return FALSE;
365 g_ptr_array_set_size (priv->targets, 0);
366 for (i = 0; i < ifaces->len; i++) {
367 GBytes *iface_data = NULL;
368 DfuTarget *target;
369 iface = g_ptr_array_index (ifaces, i);
370 if (g_usb_interface_get_class (iface) != G_USB_DEVICE_CLASS_APPLICATION_SPECIFIC)
371 continue;
372 if (g_usb_interface_get_subclass (iface) != 0x01)
373 continue;
374 target = dfu_target_new (device, iface);
375 if (target == NULL)
376 continue;
377
378 /* add target */
379 priv->iface_number = g_usb_interface_get_number (iface);
380 g_ptr_array_add (priv->targets, target);
381 dfu_device_update_from_iface (device, iface);
382
383 /* parse any interface data */
384 iface_data = g_usb_interface_get_extra (iface);
385 if (g_bytes_get_size (iface_data) > 0)
386 dfu_device_parse_iface_data (device, iface_data);
387 }
388
389 /* the device has no DFU runtime, so cheat */
390 if (priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) {
391 if (priv->targets->len == 0) {
392 g_debug ("no DFU runtime, so faking device");
393 priv->iface_number = 0xff;
394 }
395 return TRUE;
396 }
397
398 return priv->targets->len > 0;
399 }
400
401 /**
402 * dfu_device_has_quirk: (skip)
403 * @device: A #DfuDevice
404 * @quirk: A #DfuDeviceQuirks
405 *
406 * Returns if a device has a specific quirk
407 *
408 * Return value: %TRUE if the device has this quirk
409 *
410 * Since: 0.5.4
411 **/
412 gboolean
413 dfu_device_has_quirk (DfuDevice *device, DfuDeviceQuirks quirk)
414 {
415 DfuDevicePrivate *priv = GET_PRIVATE (device);
416 g_return_val_if_fail (DFU_IS_DEVICE (device), 0x0);
417 return (priv->quirks & quirk) > 0;
418 }
419
420 /**
421 * dfu_device_can_upload:
422 * @device: a #GUsbDevice
423 *
424 * Gets if the device can upload.
425 *
426 * Return value: %TRUE if the device can upload from device to host
427 *
428 * Since: 0.5.4
429 **/
430 gboolean
431 dfu_device_can_upload (DfuDevice *device)
432 {
433 DfuDevicePrivate *priv = GET_PRIVATE (device);
434 g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE);
435 return (priv->attributes & DFU_DEVICE_ATTRIBUTE_CAN_UPLOAD) > 0;
436 }
437
438 /**
439 * dfu_device_can_download:
440 * @device: a #GUsbDevice
441 *
442 * Gets if the device can download.
443 *
444 * Return value: %TRUE if the device can download from host to device
445 *
446 * Since: 0.5.4
447 **/
448 gboolean
449 dfu_device_can_download (DfuDevice *device)
450 {
451 DfuDevicePrivate *priv = GET_PRIVATE (device);
452 g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE);
453 return (priv->attributes & DFU_DEVICE_ATTRIBUTE_CAN_DOWNLOAD) > 0;
454 }
455
456 /**
457 * dfu_device_set_timeout:
458 * @device: a #DfuDevice
459 * @timeout_ms: the timeout in ms
460 *
461 * Sets the USB timeout to use when contacting the USB device.
462 *
463 * Since: 0.5.4
464 **/
465 void
466 dfu_device_set_timeout (DfuDevice *device, guint timeout_ms)
467 {
468 DfuDevicePrivate *priv = GET_PRIVATE (device);
469 g_return_if_fail (DFU_IS_DEVICE (device));
470 priv->timeout_ms = timeout_ms;
471 }
472
473 /**
474 * dfu_device_get_mode:
475 * @device: a #GUsbDevice
476 *
477 * Gets the device mode.
478 *
479 * Return value: enumerated mode, e.g. %DFU_MODE_RUNTIME
480 *
481 * Since: 0.5.4
482 **/
483 DfuMode
484 dfu_device_get_mode (DfuDevice *device)
485 {
486 DfuDevicePrivate *priv = GET_PRIVATE (device);
487 g_return_val_if_fail (DFU_IS_DEVICE (device), DFU_MODE_UNKNOWN);
488 return priv->mode;
489 }
490
491 /**
492 * dfu_device_get_timeout:
493 * @device: a #GUsbDevice
494 *
495 * Gets the device timeout.
496 *
497 * Return value: enumerated timeout in ms
498 *
499 * Since: 0.5.4
500 **/
501 guint
502 dfu_device_get_timeout (DfuDevice *device)
503 {
504 DfuDevicePrivate *priv = GET_PRIVATE (device);
505 g_return_val_if_fail (DFU_IS_DEVICE (device), 0);
506 return priv->timeout_ms;
507 }
508
509 /**
510 * dfu_device_get_state:
511 * @device: a #GUsbDevice
512 *
513 * Gets the device state.
514 *
515 * Return value: enumerated state, e.g. %DFU_STATE_DFU_UPLOAD_IDLE
516 *
517 * Since: 0.5.4
518 **/
519 DfuState
520 dfu_device_get_state (DfuDevice *device)
521 {
522 DfuDevicePrivate *priv = GET_PRIVATE (device);
523 g_return_val_if_fail (DFU_IS_DEVICE (device), 0);
524 return priv->state;
525 }
526
527 /**
528 * dfu_device_get_status:
529 * @device: a #GUsbDevice
530 *
531 * Gets the device status.
532 *
533 * Return value: enumerated status, e.g. %DFU_STATUS_ERR_ADDRESS
534 *
535 * Since: 0.5.4
536 **/
537 DfuStatus
538 dfu_device_get_status (DfuDevice *device)
539 {
540 DfuDevicePrivate *priv = GET_PRIVATE (device);
541 g_return_val_if_fail (DFU_IS_DEVICE (device), 0);
542 return priv->status;
543 }
544
545 /**
546 * dfu_device_has_attribute: (skip)
547 * @device: A #DfuDevice
548 * @attribute: A #DfuDeviceAttributes, e.g. %DFU_DEVICE_ATTRIBUTE_CAN_DOWNLOAD
549 *
550 * Returns if an attribute set for the device.
551 *
552 * Return value: %TRUE if the attribute is set
553 *
554 * Since: 0.5.4
555 **/
556 gboolean
557 dfu_device_has_attribute (DfuDevice *device, DfuDeviceAttributes attribute)
558 {
559 DfuDevicePrivate *priv = GET_PRIVATE (device);
560 g_return_val_if_fail (DFU_IS_DEVICE (device), 0x0);
561 return (priv->attributes & attribute) > 0;
562 }
563
564 /**
565 * dfu_device_has_dfuse_support:
566 * @device: A #DfuDevice
567 *
568 * Returns is DfuSe is supported on a device.
569 *
570 * Return value: %TRUE for DfuSe
571 *
572 * Since: 0.5.4
573 **/
574 gboolean
575 dfu_device_has_dfuse_support (DfuDevice *device)
576 {
577 DfuDevicePrivate *priv = GET_PRIVATE (device);
578 g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE);
579 return priv->dfuse_supported;
580 }
581
582 /**
583 * dfu_device_set_quirks:
584 **/
585 static void
586 dfu_target_set_quirks (DfuDevice *device)
587 {
588 DfuDevicePrivate *priv = GET_PRIVATE (device);
589 guint16 vid, pid, release;
590
591 vid = g_usb_device_get_vid (priv->dev);
592 pid = g_usb_device_get_pid (priv->dev);
593 release = g_usb_device_get_release (priv->dev);
594
595 /* Openmoko Freerunner / GTA02 */
596 if ((vid == 0x1d50 || vid == 0x1457) &&
597 pid >= 0x5117 && pid <= 0x5126)
598 priv->quirks |= DFU_DEVICE_QUIRK_IGNORE_POLLTIMEOUT |
599 DFU_DEVICE_QUIRK_NO_PID_CHANGE |
600 DFU_DEVICE_QUIRK_NO_DFU_RUNTIME |
601 DFU_DEVICE_QUIRK_NO_GET_STATUS_UPLOAD;
602
603 /* OpenPCD Reader */
604 if (vid == 0x16c0 && pid == 0x076b)
605 priv->quirks |= DFU_DEVICE_QUIRK_IGNORE_POLLTIMEOUT;
606
607 /* Siemens AG, PXM 40 & PXM 50 */
608 if (vid == 0x0908 && (pid == 0x02c4 || pid == 0x02c5) && release == 0x0)
609 priv->quirks |= DFU_DEVICE_QUIRK_IGNORE_POLLTIMEOUT;
610
611 /* Midiman M-Audio Transit */
612 if (vid == 0x0763 && pid == 0x2806)
613 priv->quirks |= DFU_DEVICE_QUIRK_IGNORE_POLLTIMEOUT;
614
615 /* the LPC DFU bootloader uses the wrong mode */
616 if (vid == 0x1fc9 && pid == 0x000c)
617 priv->quirks |= DFU_DEVICE_QUIRK_FORCE_DFU_MODE;
618
619 /* the Leaflabs Maple3 is known broken */
620 if (vid == 0x1eaf && pid == 0x0003 && release == 0x0200)
621 priv->quirks |= DFU_DEVICE_QUIRK_IGNORE_INVALID_VERSION;
622
623 /* m-stack DFU implementation */
624 if (vid == 0x273f && pid == 0x1003)
625 priv->quirks |= DFU_DEVICE_QUIRK_ATTACH_UPLOAD_DOWNLOAD;
626
627 /* the DSO Nano has uses 0 instead of 2 when in DFU mode */
628 // quirks |= DFU_DEVICE_QUIRK_USE_PROTOCOL_ZERO;
629 }
630
631 /**
632 * dfu_device_new:
633 * @dev: A #GUsbDevice
634 *
635 * Creates a new DFU device object.
636 *
637 * Return value: a new #DfuDevice, or %NULL if @dev was not DFU-capable
638 *
639 * Since: 0.5.4
640 **/
641 DfuDevice *
642 dfu_device_new (GUsbDevice *dev)
643 {
644 DfuDevicePrivate *priv;
645 DfuDevice *device;
646 device = g_object_new (DFU_TYPE_DEVICE, NULL);
647 priv = GET_PRIVATE (device);
648 priv->dev = g_object_ref (dev);
649 priv->platform_id = g_strdup (g_usb_device_get_platform_id (dev));
650
651 /* set any quirks on the device before adding targets */
652 dfu_target_set_quirks (device);
653
654 /* add each alternate interface, although typically there will
655 * be only one */
656 if (!dfu_device_add_targets (device)) {
657 g_object_unref (device);
658 return NULL;
659 }
660 return device;
661 }
662
663 /**
664 * dfu_device_get_targets:
665 * @device: a #DfuDevice
666 *
667 * Gets all the targets for this device.
668 *
669 * Return value: (transfer none) (element-type DfuTarget): #DfuTarget, or %NULL
670 *
671 * Since: 0.5.4
672 **/
673 GPtrArray *
674 dfu_device_get_targets (DfuDevice *device)
675 {
676 DfuDevicePrivate *priv = GET_PRIVATE (device);
677 g_return_val_if_fail (DFU_IS_DEVICE (device), NULL);
678 return priv->targets;
679 }
680
681 /**
682 * dfu_device_get_target_by_alt_setting:
683 * @device: a #DfuDevice
684 * @alt_setting: the setting used to find
685 * @error: a #GError, or %NULL
686 *
687 * Gets a target with a specific alternative setting.
688 *
689 * Return value: (transfer full): a #DfuTarget, or %NULL
690 *
691 * Since: 0.5.4
692 **/
693 DfuTarget *
694 dfu_device_get_target_by_alt_setting (DfuDevice *device,
695 guint8 alt_setting,
696 GError **error)
697 {
698 DfuDevicePrivate *priv = GET_PRIVATE (device);
699 DfuTarget *target;
700 guint i;
701
702 g_return_val_if_fail (DFU_IS_DEVICE (device), NULL);
703 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
704
705 /* find by ID */
706 for (i = 0; i < priv->targets->len; i++) {
707 target = g_ptr_array_index (priv->targets, i);
708 if (dfu_target_get_alt_setting (target) == alt_setting)
709 return g_object_ref (target);
710 }
711
712 /* failed */
713 g_set_error (error,
714 DFU_ERROR,
715 DFU_ERROR_NOT_FOUND,
716 "No target with alt-setting %i",
717 alt_setting);
718 return NULL;
719 }
720
721 /**
722 * dfu_device_get_target_by_alt_name:
723 * @device: a #DfuDevice
724 * @alt_name: the name used to find
725 * @error: a #GError, or %NULL
726 *
727 * Gets a target with a specific alternative name.
728 *
729 * Return value: (transfer full): a #DfuTarget, or %NULL
730 *
731 * Since: 0.5.4
732 **/
733 DfuTarget *
734 dfu_device_get_target_by_alt_name (DfuDevice *device,
735 const gchar *alt_name,
736 GError **error)
737 {
738 DfuDevicePrivate *priv = GET_PRIVATE (device);
739 DfuTarget *target;
740 guint i;
741
742 g_return_val_if_fail (DFU_IS_DEVICE (device), NULL);
743 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
744
745 /* find by ID */
746 for (i = 0; i < priv->targets->len; i++) {
747 target = g_ptr_array_index (priv->targets, i);
748 if (g_strcmp0 (dfu_target_get_alt_name (target, NULL), alt_name) == 0)
749 return g_object_ref (target);
750 }
751
752 /* failed */
753 g_set_error (error,
754 DFU_ERROR,
755 DFU_ERROR_NOT_FOUND,
756 "No target with alt-name %s",
757 alt_name);
758 return NULL;
759 }
760
761 /**
762 * dfu_device_get_platform_id:
763 * @device: a #DfuDevice
764 *
765 * Gets the platform ID which normally corresponds to the port in some way.
766 *
767 * Return value: string or %NULL
768 *
769 * Since: 0.5.4
770 **/
771 const gchar *
772 dfu_device_get_platform_id (DfuDevice *device)
773 {
774 DfuDevicePrivate *priv = GET_PRIVATE (device);
775 g_return_val_if_fail (DFU_IS_DEVICE (device), NULL);
776 return priv->platform_id;
777 }
778
779 /**
780 * dfu_device_get_runtime_vid:
781 * @device: a #DfuDevice
782 *
783 * Gets the runtime vendor ID.
784 *
785 * Return value: vendor ID, or 0xffff for unknown
786 *
787 * Since: 0.5.4
788 **/
789 guint16
790 dfu_device_get_runtime_vid (DfuDevice *device)
791 {
792 DfuDevicePrivate *priv = GET_PRIVATE (device);
793 g_return_val_if_fail (DFU_IS_DEVICE (device), 0xffff);
794 return priv->runtime_vid;
795 }
796
797 /**
798 * dfu_device_get_runtime_pid:
799 * @device: a #DfuDevice
800 *
801 * Gets the runtime product ID.
802 *
803 * Return value: product ID, or 0xffff for unknown
804 *
805 * Since: 0.5.4
806 **/
807 guint16
808 dfu_device_get_runtime_pid (DfuDevice *device)
809 {
810 DfuDevicePrivate *priv = GET_PRIVATE (device);
811 g_return_val_if_fail (DFU_IS_DEVICE (device), 0xffff);
812 return priv->runtime_pid;
813 }
814
815 /**
816 * dfu_device_get_runtime_release:
817 * @device: a #DfuDevice
818 *
819 * Gets the runtime release number in BCD format.
820 *
821 * Return value: release number, or 0xffff for unknown
822 *
823 * Since: 0.5.4
824 **/
825 guint16
826 dfu_device_get_runtime_release (DfuDevice *device)
827 {
828 DfuDevicePrivate *priv = GET_PRIVATE (device);
829 g_return_val_if_fail (DFU_IS_DEVICE (device), 0xffff);
830 return priv->runtime_release;
831 }
832
833 /**
834 * dfu_device_get_usb_dev: (skip)
835 * @device: a #DfuDevice
836 *
837 * Gets the internal USB device for the #DfuDevice.
838 *
839 * NOTE: This may change at runtime if the device is replugged or
840 * reset.
841 *
842 * Returns: (transfer none): the internal USB device
843 **/
844 GUsbDevice *
845 dfu_device_get_usb_dev (DfuDevice *device)
846 {
847 DfuDevicePrivate *priv = GET_PRIVATE (device);
848 g_return_val_if_fail (DFU_IS_DEVICE (device), NULL);
849 return priv->dev;
850 }
851
852 /**
853 * dfu_device_get_display_name:
854 * @device: a #DfuDevice
855 *
856 * Gets the display name to use for the device.
857 *
858 * Return value: string or %NULL for unset
859 *
860 * Since: 0.5.4
861 **/
862 const gchar *
863 dfu_device_get_display_name (DfuDevice *device)
864 {
865 DfuDevicePrivate *priv = GET_PRIVATE (device);
866 g_return_val_if_fail (DFU_IS_DEVICE (device), NULL);
867 return priv->display_name;
868 }
869
870 /**
871 * dfu_device_set_state:
872 **/
873 static void
874 dfu_device_set_state (DfuDevice *device, DfuState state)
875 {
876 DfuDevicePrivate *priv = GET_PRIVATE (device);
877 if (priv->state == state)
878 return;
879 priv->state = state;
880 g_signal_emit (device, signals[SIGNAL_STATE_CHANGED], 0, state);
881 }
882
883 /**
884 * dfu_device_set_status:
885 **/
886 static void
887 dfu_device_set_status (DfuDevice *device, DfuStatus status)
888 {
889 DfuDevicePrivate *priv = GET_PRIVATE (device);
890 if (priv->status == status)
891 return;
892 priv->status = status;
893 g_signal_emit (device, signals[SIGNAL_STATUS_CHANGED], 0, status);
894 }
895
896 /**
897 * dfu_device_refresh:
898 * @device: a #DfuDevice
899 * @cancellable: a #GCancellable, or %NULL
900 * @error: a #GError, or %NULL
901 *
902 * Refreshes the cached properties on the DFU device.
903 *
904 * Return value: %TRUE for success
905 *
906 * Since: 0.5.4
907 **/
908 gboolean
909 dfu_device_refresh (DfuDevice *device, GCancellable *cancellable, GError **error)
910 {
911 DfuDevicePrivate *priv = GET_PRIVATE (device);
912 gsize actual_length = 0;
913 guint8 buf[6];
914 g_autoptr(GError) error_local = NULL;
915
916 g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE);
917 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
918
919 /* no backing USB device */
920 if (priv->dev == NULL) {
921 g_set_error (error,
922 DFU_ERROR,
923 DFU_ERROR_INTERNAL,
924 "failed to refresh: no GUsbDevice for %s",
925 priv->platform_id);
926 return FALSE;
927 }
928
929 /* the device has no DFU runtime, so cheat */
930 if (priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) {
931 g_set_error_literal (error,
932 DFU_ERROR,
933 DFU_ERROR_NOT_SUPPORTED,
934 "not supported as no DFU runtime");
935 return FALSE;
936 }
937
938 if (!g_usb_device_control_transfer (priv->dev,
939 G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
940 G_USB_DEVICE_REQUEST_TYPE_CLASS,
941 G_USB_DEVICE_RECIPIENT_INTERFACE,
942 DFU_REQUEST_GETSTATUS,
943 0,
944 priv->iface_number,
945 buf, sizeof(buf), &actual_length,
946 priv->timeout_ms,
947 cancellable,
948 &error_local)) {
949 g_set_error (error,
950 DFU_ERROR,
951 DFU_ERROR_NOT_SUPPORTED,
952 "cannot get device state: %s",
953 error_local->message);
954 return FALSE;
955 }
956 if (actual_length != 6) {
957 g_set_error (error,
958 DFU_ERROR,
959 DFU_ERROR_INTERNAL,
960 "cannot get device status, invalid size: %04x",
961 (guint) actual_length);
962 }
963
964 /* status or state changed */
965 dfu_device_set_status (device, buf[0]);
966 dfu_device_set_state (device, buf[4]);
967 if (dfu_device_has_quirk (device, DFU_DEVICE_QUIRK_IGNORE_POLLTIMEOUT)) {
968 priv->dnload_timeout = 5;
969 } else {
970 priv->dnload_timeout = buf[1] +
971 (((guint32) buf[2]) << 8) +
972 (((guint32) buf[3]) << 16);
973 }
974 g_debug ("refreshed status=%s and state=%s",
975 dfu_status_to_string (priv->status),
976 dfu_state_to_string (priv->state));
977 return TRUE;
978 }
979
980 /**
981 * dfu_device_detach:
982 * @device: a #DfuDevice
983 * @cancellable: a #GCancellable, or %NULL
984 * @error: a #GError, or %NULL
985 *
986 * Detaches the device putting it into DFU-mode.
987 *
988 * Return value: %TRUE for success
989 *
990 * Since: 0.5.4
991 **/
992 gboolean
993 dfu_device_detach (DfuDevice *device, GCancellable *cancellable, GError **error)
994 {
995 DfuDevicePrivate *priv = GET_PRIVATE (device);
996 g_autoptr(GError) error_local = NULL;
997
998 g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE);
999 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1000
1001 /* already in DFU mode */
1002 switch (priv->state) {
1003 case DFU_STATE_APP_IDLE:
1004 case DFU_STATE_APP_DETACH:
1005 break;
1006 default:
1007 g_set_error (error,
1008 DFU_ERROR,
1009 DFU_ERROR_NOT_SUPPORTED,
1010 "Already in DFU mode");
1011 return FALSE;
1012 }
1013
1014 /* no backing USB device */
1015 if (priv->dev == NULL) {
1016 g_set_error (error,
1017 DFU_ERROR,
1018 DFU_ERROR_INTERNAL,
1019 "failed to detach: no GUsbDevice for %s",
1020 priv->platform_id);
1021 return FALSE;
1022 }
1023
1024 /* the device has no DFU runtime, so cheat */
1025 if (priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) {
1026 g_set_error_literal (error,
1027 DFU_ERROR,
1028 DFU_ERROR_NOT_SUPPORTED,
1029 "not supported as no DFU runtime");
1030 return FALSE;
1031 }
1032
1033 /* inform UI there's going to be a detach:attach */
1034 dfu_device_set_state (device, DFU_STATE_APP_DETACH);
1035
1036 if (!g_usb_device_control_transfer (priv->dev,
1037 G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
1038 G_USB_DEVICE_REQUEST_TYPE_CLASS,
1039 G_USB_DEVICE_RECIPIENT_INTERFACE,
1040 DFU_REQUEST_DETACH,
1041 0,
1042 priv->iface_number,
1043 NULL, 0, NULL,
1044 priv->timeout_ms,
1045 cancellable,
1046 &error_local)) {
1047 /* refresh the error code */
1048 dfu_device_error_fixup (device, cancellable, &error_local);
1049 g_set_error (error,
1050 DFU_ERROR,
1051 DFU_ERROR_NOT_SUPPORTED,
1052 "cannot detach device: %s",
1053 error_local->message);
1054 return FALSE;
1055 }
1056
1057 /* do a host reset */
1058 if ((priv->attributes & DFU_DEVICE_ATTRIBUTE_WILL_DETACH) == 0) {
1059 g_debug ("doing device reset as host will not self-reset");
1060 if (!dfu_device_reset (device, error))
1061 return FALSE;
1062 }
1063 return TRUE;
1064 }
1065
1066 /**
1067 * dfu_device_abort:
1068 * @device: a #DfuDevice
1069 * @cancellable: a #GCancellable, or %NULL
1070 * @error: a #GError, or %NULL
1071 *
1072 * Aborts any upload or download in progress.
1073 *
1074 * Return value: %TRUE for success
1075 *
1076 * Since: 0.5.4
1077 **/
1078 gboolean
1079 dfu_device_abort (DfuDevice *device, GCancellable *cancellable, GError **error)
1080 {
1081 DfuDevicePrivate *priv = GET_PRIVATE (device);
1082 g_autoptr(GError) error_local = NULL;
1083
1084 g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE);
1085 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1086
1087 /* no backing USB device */
1088 if (priv->dev == NULL) {
1089 g_set_error (error,
1090 DFU_ERROR,
1091 DFU_ERROR_INTERNAL,
1092 "failed to abort: no GUsbDevice for %s",
1093 priv->platform_id);
1094 return FALSE;
1095 }
1096
1097 /* the device has no DFU runtime, so cheat */
1098 if (priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) {
1099 g_set_error_literal (error,
1100 DFU_ERROR,
1101 DFU_ERROR_NOT_SUPPORTED,
1102 "not supported as no DFU runtime");
1103 return FALSE;
1104 }
1105
1106 if (!g_usb_device_control_transfer (priv->dev,
1107 G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
1108 G_USB_DEVICE_REQUEST_TYPE_CLASS,
1109 G_USB_DEVICE_RECIPIENT_INTERFACE,
1110 DFU_REQUEST_ABORT,
1111 0,
1112 priv->iface_number,
1113 NULL, 0, NULL,
1114 priv->timeout_ms,
1115 cancellable,
1116 &error_local)) {
1117 /* refresh the error code */
1118 dfu_device_error_fixup (device, cancellable, &error_local);
1119 g_set_error (error,
1120 DFU_ERROR,
1121 DFU_ERROR_NOT_SUPPORTED,
1122 "cannot abort device: %s",
1123 error_local->message);
1124 return FALSE;
1125 }
1126
1127 return TRUE;
1128 }
1129
1130 /**
1131 * dfu_device_clear_status:
1132 * @device: a #DfuDevice
1133 * @cancellable: a #GCancellable, or %NULL
1134 * @error: a #GError, or %NULL
1135 *
1136 * Clears any error status on the DFU device.
1137 *
1138 * Return value: %TRUE for success
1139 *
1140 * Since: 0.5.4
1141 **/
1142 gboolean
1143 dfu_device_clear_status (DfuDevice *device, GCancellable *cancellable, GError **error)
1144 {
1145 DfuDevicePrivate *priv = GET_PRIVATE (device);
1146 g_autoptr(GError) error_local = NULL;
1147
1148 g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE);
1149 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1150
1151 /* no backing USB device */
1152 if (priv->dev == NULL) {
1153 g_set_error (error,
1154 DFU_ERROR,
1155 DFU_ERROR_INTERNAL,
1156 "failed to clear status: no GUsbDevice for %s",
1157 priv->platform_id);
1158 return FALSE;
1159 }
1160
1161 /* the device has no DFU runtime, so cheat */
1162 if (priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) {
1163 g_set_error_literal (error,
1164 DFU_ERROR,
1165 DFU_ERROR_NOT_SUPPORTED,
1166 "not supported as no DFU runtime");
1167 return FALSE;
1168 }
1169
1170 if (!g_usb_device_control_transfer (priv->dev,
1171 G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
1172 G_USB_DEVICE_REQUEST_TYPE_CLASS,
1173 G_USB_DEVICE_RECIPIENT_INTERFACE,
1174 DFU_REQUEST_CLRSTATUS,
1175 0,
1176 priv->iface_number,
1177 NULL, 0, NULL,
1178 priv->timeout_ms,
1179 cancellable,
1180 &error_local)) {
1181 /* refresh the error code */
1182 dfu_device_error_fixup (device, cancellable, &error_local);
1183 g_set_error (error,
1184 DFU_ERROR,
1185 DFU_ERROR_NOT_SUPPORTED,
1186 "cannot clear status on the device: %s",
1187 error_local->message);
1188 return FALSE;
1189 }
1190 return TRUE;
1191 }
1192
1193 /**
1194 * dfu_device_get_interface:
1195 * @device: a #DfuDevice
1196 *
1197 * Gets the interface number.
1198 *
1199 * Since: 0.5.4
1200 **/
1201 guint8
1202 dfu_device_get_interface (DfuDevice *device)
1203 {
1204 DfuDevicePrivate *priv = GET_PRIVATE (device);
1205 g_return_val_if_fail (DFU_IS_DEVICE (device), 0xff);
1206 return priv->iface_number;
1207 }
1208
1209 /**
1210 * dfu_device_open:
1211 * @device: a #DfuDevice
1212 * @flags: #DfuDeviceOpenFlags, e.g. %DFU_DEVICE_OPEN_FLAG_NONE
1213 * @cancellable: a #GCancellable, or %NULL
1214 * @error: a #GError, or %NULL
1215 *
1216 * Opens a DFU-capable device.
1217 *
1218 * Return value: %TRUE for success
1219 *
1220 * Since: 0.5.4
1221 **/
1222 gboolean
1223 dfu_device_open (DfuDevice *device, DfuDeviceOpenFlags flags,
1224 GCancellable *cancellable, GError **error)
1225 {
1226 DfuDevicePrivate *priv = GET_PRIVATE (device);
1227 guint idx;
1228 g_autoptr(GError) error_local = NULL;
1229
1230 g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE);
1231 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1232
1233 /* no backing USB device */
1234 if (priv->dev == NULL) {
1235 g_set_error (error,
1236 DFU_ERROR,
1237 DFU_ERROR_INTERNAL,
1238 "failed to open: no GUsbDevice for %s",
1239 priv->platform_id);
1240 return FALSE;
1241 }
1242
1243 /* open */
1244 if (!g_usb_device_open (priv->dev, &error_local)) {
1245 if (g_error_matches (error_local,
1246 G_USB_DEVICE_ERROR,
1247 G_USB_DEVICE_ERROR_ALREADY_OPEN)) {
1248 g_debug ("device already open, ignoring");
1249 return TRUE;
1250 }
1251 if (g_error_matches (error_local,
1252 G_USB_DEVICE_ERROR,
1253 G_USB_DEVICE_ERROR_PERMISSION_DENIED)) {
1254 g_set_error (error,
1255 DFU_ERROR,
1256 DFU_ERROR_PERMISSION_DENIED,
1257 "%s", error_local->message);
1258 return FALSE;
1259 }
1260 g_set_error (error,
1261 DFU_ERROR,
1262 DFU_ERROR_INVALID_DEVICE,
1263 "cannot open device %s: %s",
1264 g_usb_device_get_platform_id (priv->dev),
1265 error_local->message);
1266 return FALSE;
1267 }
1268
1269 /* claim the correct interface if set */
1270 if (priv->iface_number != 0xff) {
1271 if (!g_usb_device_claim_interface (priv->dev,
1272 (gint) priv->iface_number,
1273 0,
1274 &error_local)) {
1275 g_set_error (error,
1276 DFU_ERROR,
1277 DFU_ERROR_INVALID_DEVICE,
1278 "cannot claim interface %i: %s",
1279 priv->iface_number, error_local->message);
1280 return FALSE;
1281 }
1282 }
1283
1284 /* get product name if it exists */
1285 idx = g_usb_device_get_product_index (priv->dev);
1286 if (idx != 0x00)
1287 priv->display_name = g_usb_device_get_string_descriptor (priv->dev, idx, NULL);
1288
1289 /* the device has no DFU runtime, so cheat */
1290 if (priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) {
1291 priv->state = DFU_STATE_APP_IDLE;
1292 priv->status = DFU_STATUS_OK;
1293 flags |= DFU_DEVICE_OPEN_FLAG_NO_AUTO_REFRESH;
1294 }
1295
1296 /* automatically abort any uploads or downloads */
1297 if ((flags & DFU_DEVICE_OPEN_FLAG_NO_AUTO_REFRESH) == 0) {
1298 if (!dfu_device_refresh (device, cancellable, error))
1299 return FALSE;
1300 switch (priv->state) {
1301 case DFU_STATE_DFU_UPLOAD_IDLE:
1302 case DFU_STATE_DFU_DNLOAD_IDLE:
1303 case DFU_STATE_DFU_DNLOAD_SYNC:
1304 g_debug ("aborting transfer %s", dfu_status_to_string (priv->status));
1305 if (!dfu_device_abort (device, cancellable, error))
1306 return FALSE;
1307 break;
1308 case DFU_STATE_DFU_ERROR:
1309 g_debug ("clearing error %s", dfu_status_to_string (priv->status));
1310 if (!dfu_device_clear_status (device, cancellable, error))
1311 return FALSE;
1312 break;
1313 default:
1314 break;
1315 }
1316 }
1317
1318 priv->open_new_dev = TRUE;
1319 return TRUE;
1320 }
1321
1322 /**
1323 * dfu_device_close:
1324 * @device: a #DfuDevice
1325 * @error: a #GError, or %NULL
1326 *
1327 * Closes a DFU device.
1328 *
1329 * Return value: %TRUE for success
1330 *
1331 * Since: 0.5.4
1332 **/
1333 gboolean
1334 dfu_device_close (DfuDevice *device, GError **error)
1335 {
1336 DfuDevicePrivate *priv = GET_PRIVATE (device);
1337 g_autoptr(GError) error_local = NULL;
1338
1339 /* no backing USB device */
1340 if (priv->dev == NULL) {
1341 g_set_error (error,
1342 DFU_ERROR,
1343 DFU_ERROR_INTERNAL,
1344 "failed to close: no GUsbDevice for %s",
1345 priv->platform_id);
1346 return FALSE;
1347 }
1348
1349 /* close if open */
1350 if (!g_usb_device_close (priv->dev, &error_local)) {
1351 if (g_error_matches (error_local,
1352 G_USB_DEVICE_ERROR,
1353 G_USB_DEVICE_ERROR_NOT_OPEN)) {
1354 g_debug ("device not open, so ignoring error for close");
1355 return TRUE;
1356 }
1357 g_set_error_literal (error,
1358 DFU_ERROR,
1359 DFU_ERROR_INTERNAL,
1360 error_local->message);
1361 return FALSE;
1362 }
1363 priv->open_new_dev = FALSE;
1364 return TRUE;
1365 }
1366
1367 /**
1368 * dfu_device_set_new_usb_dev:
1369 **/
1370 gboolean
1371 dfu_device_set_new_usb_dev (DfuDevice *device, GUsbDevice *dev,
1372 GCancellable *cancellable, GError **error)
1373 {
1374 DfuDevicePrivate *priv = GET_PRIVATE (device);
1375
1376 /* same */
1377 if (priv->dev == dev) {
1378 g_warning ("setting GUsbDevice with same dev?!");
1379 return TRUE;
1380 }
1381
1382 /* device removed */
1383 if (dev == NULL) {
1384 g_debug ("invalidating backing GUsbDevice");
1385 g_clear_object (&priv->dev);
1386 g_ptr_array_set_size (priv->targets, 0);
1387 return TRUE;
1388 }
1389
1390 /* close */
1391 if (priv->dev != NULL) {
1392 gboolean tmp = priv->open_new_dev;
1393 if (!dfu_device_close (device, error))
1394 return FALSE;
1395 priv->open_new_dev = tmp;
1396 }
1397
1398 /* set the new USB device */
1399 g_set_object (&priv->dev, dev);
1400
1401 /* should be the same */
1402 if (g_strcmp0 (priv->platform_id,
1403 g_usb_device_get_platform_id (dev)) != 0) {
1404 g_warning ("platform ID changed when setting new GUsbDevice?!");
1405 g_free (priv->platform_id);
1406 priv->platform_id = g_strdup (g_usb_device_get_platform_id (dev));
1407 }
1408
1409 /* update all the targets */
1410 if (!dfu_device_add_targets (device)) {
1411 g_set_error_literal (error,
1412 DFU_ERROR,
1413 DFU_ERROR_NOT_SUPPORTED,
1414 "replugged device is not DFU-capable");
1415 return FALSE;
1416 }
1417
1418 /* reclaim */
1419 if (priv->open_new_dev) {
1420 g_debug ("automatically reopening device");
1421 if (!dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE,
1422 cancellable, error))
1423 return FALSE;
1424 }
1425 return TRUE;
1426 }
1427
1428 typedef struct {
1429 DfuDevice *device;
1430 GError **error;
1431 GMainLoop *loop;
1432 GUsbDevice *dev;
1433 guint cnt;
1434 guint timeout;
1435 } DfuDeviceReplugHelper;
1436
1437 /**
1438 * dfu_device_replug_helper_free:
1439 **/
1440 static void
1441 dfu_device_replug_helper_free (DfuDeviceReplugHelper *helper)
1442 {
1443 if (helper->dev != NULL)
1444 g_object_unref (helper->dev);
1445 g_object_unref (helper->device);
1446 g_main_loop_unref (helper->loop);
1447 g_free (helper);
1448 }
1449
1450 /**
1451 * dfu_device_replug_helper_cb:
1452 **/
1453 static gboolean
1454 dfu_device_replug_helper_cb (gpointer user_data)
1455 {
1456 DfuDeviceReplugHelper *helper = (DfuDeviceReplugHelper *) user_data;
1457 DfuDevicePrivate *priv = GET_PRIVATE (helper->device);
1458
1459 /* did the backing GUsbDevice change */
1460 if (helper->dev != priv->dev) {
1461 g_debug ("device changed GUsbDevice %p->%p",
1462 helper->dev, priv->dev);
1463 g_set_object (&helper->dev, priv->dev);
1464
1465 /* success */
1466 if (helper->dev != NULL) {
1467 g_main_loop_quit (helper->loop);
1468 return FALSE;
1469 }
1470 }
1471
1472 /* set a limit */
1473 if (helper->cnt++ * 100 > helper->timeout) {
1474 g_debug ("gave up waiting for device replug");
1475 if (helper->dev == NULL) {
1476 g_set_error_literal (helper->error,
1477 DFU_ERROR,
1478 DFU_ERROR_INVALID_DEVICE,
1479 "target went away but did not come back");
1480 } else {
1481 g_set_error_literal (helper->error,
1482 DFU_ERROR,
1483 DFU_ERROR_INVALID_DEVICE,
1484 "target did not disconnect");
1485 }
1486 g_main_loop_quit (helper->loop);
1487 return FALSE;
1488 }
1489
1490 /* continue waiting */
1491 g_debug ("waiting for device replug for %ims -- state is %s",
1492 helper->cnt * 100, dfu_state_to_string (priv->state));
1493 return TRUE;
1494 }
1495
1496 /**
1497 * dfu_device_wait_for_replug:
1498 * @device: a #DfuDevice
1499 * @timeout: the maximum amount of time to wait
1500 * @cancellable: a #GCancellable, or %NULL
1501 * @error: a #GError, or %NULL
1502 *
1503 * Waits for a DFU device to disconnect and reconnect.
1504 * This does rely on a #DfuContext being set up before this is called.
1505 *
1506 * Return value: %TRUE for success
1507 *
1508 * Since: 0.5.4
1509 **/
1510 gboolean
1511 dfu_device_wait_for_replug (DfuDevice *device, guint timeout,
1512 GCancellable *cancellable, GError **error)
1513 {
1514 DfuDevicePrivate *priv = GET_PRIVATE (device);
1515 DfuDeviceReplugHelper *helper;
1516 GError *error_tmp = NULL;
1517 const guint replug_poll = 100; /* ms */
1518
1519 helper = g_new0 (DfuDeviceReplugHelper, 1);
1520 helper->loop = g_main_loop_new (NULL, FALSE);
1521 helper->device = g_object_ref (device);
1522 helper->dev = g_object_ref (priv->dev);
1523 helper->error = &error_tmp;
1524 helper->timeout = timeout;
1525 g_timeout_add_full (G_PRIORITY_DEFAULT, replug_poll,
1526 dfu_device_replug_helper_cb, helper,
1527 (GDestroyNotify) dfu_device_replug_helper_free);
1528 g_main_loop_run (helper->loop);
1529 if (error_tmp != NULL) {
1530 g_propagate_error (error, error_tmp);
1531 return FALSE;
1532 }
1533 return TRUE;
1534 }
1535
1536 /**
1537 * dfu_device_reset:
1538 * @device: a #DfuDevice
1539 * @error: a #GError, or %NULL
1540 *
1541 * Resets the USB device.
1542 *
1543 * Return value: %TRUE for success
1544 *
1545 * Since: 0.5.4
1546 **/
1547 gboolean
1548 dfu_device_reset (DfuDevice *device, GError **error)
1549 {
1550 DfuDevicePrivate *priv = GET_PRIVATE (device);
1551 g_autoptr(GError) error_local = NULL;
1552
1553 g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE);
1554 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1555
1556 /* no backing USB device */
1557 if (priv->dev == NULL) {
1558 g_set_error (error,
1559 DFU_ERROR,
1560 DFU_ERROR_INTERNAL,
1561 "failed to reset: no GUsbDevice for %s",
1562 priv->platform_id);
1563 return FALSE;
1564 }
1565
1566 if (!g_usb_device_reset (priv->dev, &error_local)) {
1567 g_set_error (error,
1568 DFU_ERROR,
1569 DFU_ERROR_INVALID_DEVICE,
1570 "cannot reset USB device: %s [%i]",
1571 error_local->message,
1572 error_local->code);
1573 return FALSE;
1574 }
1575 return TRUE;
1576 }
1577
1578 /**
1579 * dfu_device_attach:
1580 * @device: a #DfuDevice
1581 * @error: a #GError, or %NULL
1582 *
1583 * Move device from DFU mode to runtime.
1584 *
1585 * Return value: %TRUE for success
1586 *
1587 * Since: 0.5.4
1588 **/
1589 gboolean
1590 dfu_device_attach (DfuDevice *device, GError **error)
1591 {
1592 DfuDevicePrivate *priv = GET_PRIVATE (device);
1593 g_autoptr(GError) error_local = NULL;
1594
1595 g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE);
1596 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1597
1598 /* already in runtime mode */
1599 switch (priv->state) {
1600 case DFU_STATE_APP_IDLE:
1601 case DFU_STATE_APP_DETACH:
1602 g_set_error (error,
1603 DFU_ERROR,
1604 DFU_ERROR_NOT_SUPPORTED,
1605 "Already in application runtime mode");
1606 return FALSE;
1607 default:
1608 break;
1609 }
1610
1611 /* inform UI there's going to be a re-attach */
1612 dfu_device_set_state (device, DFU_STATE_DFU_MANIFEST_WAIT_RESET);
1613
1614 /* handle m-stack DFU bootloaders */
1615 if (!priv->done_upload_or_download &&
1616 (priv->quirks & DFU_DEVICE_QUIRK_ATTACH_UPLOAD_DOWNLOAD) > 0) {
1617 g_autoptr(GBytes) chunk = NULL;
1618 g_autoptr(DfuTarget) target = NULL;
1619 g_debug ("doing dummy upload to work around m-stack quirk");
1620 target = dfu_device_get_target_by_alt_setting (device, 0, error);
1621 if (target == NULL)
1622 return FALSE;
1623 chunk = dfu_target_upload_chunk (target, 0, NULL, error);
1624 if (chunk == NULL)
1625 return FALSE;
1626 }
1627
1628 /* there's a a special command for ST devices */
1629 if (priv->dfuse_supported) {
1630 //FIXME
1631 return TRUE;
1632 }
1633
1634 /* normal DFU mode just needs a bus reset */
1635 return dfu_device_reset (device, error);
1636 }
1637
1638 /**
1639 * dfu_device_percentage_cb:
1640 **/
1641 static void
1642 dfu_device_percentage_cb (DfuTarget *target, guint percentage, DfuDevice *device)
1643 {
1644 /* FIXME: divide by number of targets? */
1645 g_signal_emit (device, signals[SIGNAL_PERCENTAGE_CHANGED], 0, percentage);
1646 }
1647
1648 /**
1649 * dfu_device_upload:
1650 * @device: a #DfuDevice
1651 * @flags: flags to use, e.g. %DFU_TARGET_TRANSFER_FLAG_VERIFY
1652 * @cancellable: a #GCancellable, or %NULL
1653 * @error: a #GError, or %NULL
1654 *
1655 * Uploads firmware from the target to the host.
1656 *
1657 * Return value: (transfer full): the uploaded firmware, or %NULL for error
1658 *
1659 * Since: 0.5.4
1660 **/
1661 DfuFirmware *
1662 dfu_device_upload (DfuDevice *device,
1663 DfuTargetTransferFlags flags,
1664 GCancellable *cancellable,
1665 GError **error)
1666 {
1667 DfuDevicePrivate *priv = GET_PRIVATE (device);
1668 guint i;
1669 g_autoptr(DfuFirmware) firmware = NULL;
1670
1671 /* no backing USB device */
1672 if (priv->dev == NULL) {
1673 g_set_error (error,
1674 DFU_ERROR,
1675 DFU_ERROR_INTERNAL,
1676 "failed to upload: no GUsbDevice for %s",
1677 priv->platform_id);
1678 return NULL;
1679 }
1680
1681 /* create ahead of time */
1682 firmware = dfu_firmware_new ();
1683 dfu_firmware_set_vid (firmware, priv->runtime_vid);
1684 dfu_firmware_set_pid (firmware, priv->runtime_pid);
1685 dfu_firmware_set_release (firmware, 0xffff);
1686
1687 /* APP -> DFU */
1688 if (priv->mode == DFU_MODE_RUNTIME) {
1689 if ((flags & DFU_TARGET_TRANSFER_FLAG_DETACH) == 0) {
1690 g_set_error (error,
1691 DFU_ERROR,
1692 DFU_ERROR_NOT_SUPPORTED,
1693 "device is not in DFU mode");
1694 return FALSE;
1695 }
1696 g_debug ("detaching");
1697
1698 /* detach and USB reset */
1699 if (!dfu_device_detach (device, NULL, error))
1700 return NULL;
1701 if (!dfu_device_wait_for_replug (device,
1702 DFU_DEVICE_REPLUG_TIMEOUT,
1703 cancellable,
1704 error))
1705 return NULL;
1706 }
1707
1708 /* upload from each target */
1709 for (i = 0; i < priv->targets->len; i++) {
1710 DfuTarget *target;
1711 guint id;
1712 g_autoptr(DfuImage) image = NULL;
1713
1714 /* upload to target and proxy signals */
1715 target = g_ptr_array_index (priv->targets, i);
1716 id = g_signal_connect (target, "percentage-changed",
1717 G_CALLBACK (dfu_device_percentage_cb), device);
1718 image = dfu_target_upload (target,
1719 DFU_TARGET_TRANSFER_FLAG_NONE,
1720 cancellable,
1721 error);
1722 g_signal_handler_disconnect (target, id);
1723 if (image == NULL)
1724 return NULL;
1725 dfu_firmware_add_image (firmware, image);
1726 }
1727
1728 /* do not do the dummy upload for quirked devices */
1729 priv->done_upload_or_download = TRUE;
1730
1731 /* choose the most appropriate type */
1732 if (priv->targets->len > 1) {
1733 g_debug ("switching to DefuSe automatically");
1734 dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_DFUSE);
1735 } else {
1736 dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_DFU_1_0);
1737 }
1738
1739 /* do host reset */
1740 if ((flags & DFU_TARGET_TRANSFER_FLAG_ATTACH) > 0 ||
1741 (flags & DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME) > 0) {
1742 if (!dfu_device_attach (device, error))
1743 return NULL;
1744 }
1745
1746 /* boot to runtime */
1747 if (flags & DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME) {
1748 g_debug ("booting to runtime");
1749 if (!dfu_device_wait_for_replug (device,
1750 DFU_DEVICE_REPLUG_TIMEOUT,
1751 cancellable,
1752 error))
1753 return NULL;
1754 }
1755
1756 /* success */
1757 return g_object_ref (firmware);
1758 }
1759
1760 /**
1761 * dfu_device_download:
1762 * @device: a #DfuDevice
1763 * @firmware: a #DfuFirmware
1764 * @flags: flags to use, e.g. %DFU_TARGET_TRANSFER_FLAG_VERIFY
1765 * @cancellable: a #GCancellable, or %NULL
1766 * @error: a #GError, or %NULL
1767 *
1768 * Downloads firmware from the host to the target, optionally verifying
1769 * the transfer.
1770 *
1771 * Return value: %TRUE for success
1772 *
1773 * Since: 0.5.4
1774 **/
1775 gboolean
1776 dfu_device_download (DfuDevice *device,
1777 DfuFirmware *firmware,
1778 DfuTargetTransferFlags flags,
1779 GCancellable *cancellable,
1780 GError **error)
1781 {
1782 DfuDevicePrivate *priv = GET_PRIVATE (device);
1783 GPtrArray *images;
1784 gboolean ret;
1785 guint i;
1786 g_autoptr(GPtrArray) targets = NULL;
1787
1788 /* no backing USB device */
1789 if (priv->dev == NULL) {
1790 g_set_error (error,
1791 DFU_ERROR,
1792 DFU_ERROR_INTERNAL,
1793 "failed to download: no GUsbDevice for %s",
1794 priv->platform_id);
1795 return FALSE;
1796 }
1797
1798 /* do we allow wildcard VID:PID matches */
1799 if ((flags & DFU_TARGET_TRANSFER_FLAG_WILDCARD_VID) == 0) {
1800 if (dfu_firmware_get_vid (firmware) == 0xffff) {
1801 g_set_error (error,
1802 DFU_ERROR,
1803 DFU_ERROR_NOT_SUPPORTED,
1804 "firmware vendor ID not specified");
1805 return FALSE;
1806 }
1807 }
1808 if ((flags & DFU_TARGET_TRANSFER_FLAG_WILDCARD_PID) == 0) {
1809 if (dfu_firmware_get_pid (firmware) == 0xffff) {
1810 g_set_error (error,
1811 DFU_ERROR,
1812 DFU_ERROR_NOT_SUPPORTED,
1813 "firmware product ID not specified");
1814 return FALSE;
1815 }
1816 }
1817
1818 /* check vendor matches */
1819 if (dfu_firmware_get_vid (firmware) != 0xffff &&
1820 priv->runtime_pid != 0xffff &&
1821 dfu_firmware_get_vid (firmware) != priv->runtime_vid) {
1822 g_set_error (error,
1823 DFU_ERROR,
1824 DFU_ERROR_NOT_SUPPORTED,
1825 "vendor ID incorrect, expected 0x%04x got 0x%04x\n",
1826 dfu_firmware_get_vid (firmware),
1827 priv->runtime_vid);
1828 return FALSE;
1829 }
1830
1831 /* check product matches */
1832 if (dfu_firmware_get_pid (firmware) != 0xffff &&
1833 priv->runtime_pid != 0xffff &&
1834 dfu_firmware_get_pid (firmware) != priv->runtime_pid) {
1835 g_set_error (error,
1836 DFU_ERROR,
1837 DFU_ERROR_NOT_SUPPORTED,
1838 "product ID incorrect, expected 0x%04x got 0x%04x",
1839 dfu_firmware_get_pid (firmware),
1840 priv->runtime_pid);
1841 return FALSE;
1842 }
1843
1844 /* APP -> DFU */
1845 if (priv->mode == DFU_MODE_RUNTIME) {
1846 if ((flags & DFU_TARGET_TRANSFER_FLAG_DETACH) == 0) {
1847 g_set_error (error,
1848 DFU_ERROR,
1849 DFU_ERROR_NOT_SUPPORTED,
1850 "device is not in DFU mode");
1851 return FALSE;
1852 }
1853
1854 /* detach and USB reset */
1855 g_debug ("detaching");
1856 if (!dfu_device_detach (device, NULL, error))
1857 return FALSE;
1858 if (!dfu_device_wait_for_replug (device,
1859 DFU_DEVICE_REPLUG_TIMEOUT,
1860 NULL,
1861 error))
1862 return FALSE;
1863 }
1864
1865 /* download each target */
1866 images = dfu_firmware_get_images (firmware);
1867 if (images->len == 0) {
1868 g_set_error_literal (error,
1869 DFU_ERROR,
1870 DFU_ERROR_INVALID_FILE,
1871 "no images in firmware file");
1872 return FALSE;
1873 }
1874 for (i = 0; i < images->len; i++) {
1875 DfuCipherKind cipher_fw;
1876 DfuCipherKind cipher_target;
1877 DfuImage *image;
1878 DfuTargetTransferFlags flags_local = DFU_TARGET_TRANSFER_FLAG_NONE;
1879 const gchar *alt_name;
1880 guint id;
1881 g_autoptr(DfuTarget) target_tmp = NULL;
1882
1883 image = g_ptr_array_index (images, i);
1884 target_tmp = dfu_device_get_target_by_alt_setting (device,
1885 dfu_image_get_alt_setting (image),
1886 error);
1887 if (target_tmp == NULL)
1888 return FALSE;
1889
1890 /* we don't actually need to print this, but it makes sure the
1891 * target is setup prior to doing the cipher checks */
1892 alt_name = dfu_target_get_alt_name (target_tmp, error);
1893 if (alt_name == NULL)
1894 return FALSE;
1895 g_debug ("downloading to target: %s", alt_name);
1896
1897 /* check we're flashing a compatible firmware */
1898 cipher_target = dfu_target_get_cipher_kind (target_tmp);
1899 cipher_fw = dfu_firmware_get_cipher_kind (firmware);
1900 if ((flags & DFU_TARGET_TRANSFER_FLAG_ANY_CIPHER) == 0) {
1901 if (cipher_fw != DFU_CIPHER_KIND_NONE &&
1902 cipher_target == DFU_CIPHER_KIND_NONE) {
1903 g_set_error (error,
1904 DFU_ERROR,
1905 DFU_ERROR_INVALID_FILE,
1906 "Device is only accepting "
1907 "unsigned firmware, not %s",
1908 dfu_cipher_kind_to_string (cipher_fw));
1909 return FALSE;
1910 }
1911 if (cipher_fw == DFU_CIPHER_KIND_NONE &&
1912 cipher_target != DFU_CIPHER_KIND_NONE) {
1913 g_set_error (error,
1914 DFU_ERROR,
1915 DFU_ERROR_INVALID_FILE,
1916 "Device is only accepting "
1917 "firmware with %s cipher kind",
1918 dfu_cipher_kind_to_string (cipher_target));
1919 return FALSE;
1920 }
1921 }
1922
1923 /* download onto target */
1924 if (flags & DFU_TARGET_TRANSFER_FLAG_VERIFY)
1925 flags_local = DFU_TARGET_TRANSFER_FLAG_VERIFY;
1926 id = g_signal_connect (target_tmp, "percentage-changed",
1927 G_CALLBACK (dfu_device_percentage_cb), device);
1928 ret = dfu_target_download (target_tmp,
1929 image,
1930 flags_local,
1931 cancellable,
1932 error);
1933 g_signal_handler_disconnect (target_tmp, id);
1934 if (!ret)
1935 return FALSE;
1936 }
1937
1938 /* do not do the dummy upload for quirked devices */
1939 priv->done_upload_or_download = TRUE;
1940
1941 /* attempt to switch back to runtime */
1942 if ((flags & DFU_TARGET_TRANSFER_FLAG_ATTACH) > 0 ||
1943 (flags & DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME) > 0) {
1944 if (!dfu_device_attach (device, error))
1945 return FALSE;
1946 }
1947
1948 /* boot to runtime */
1949 if (flags & DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME) {
1950 g_debug ("booting to runtime to set auto-boot");
1951 if (!dfu_device_wait_for_replug (device,
1952 DFU_DEVICE_REPLUG_TIMEOUT,
1953 cancellable,
1954 error))
1955 return FALSE;
1956 }
1957
1958 return TRUE;
1959 }
1960
1961 /**
1962 * dfu_device_error_fixup:
1963 **/
1964 void
1965 dfu_device_error_fixup (DfuDevice *device,
1966 GCancellable *cancellable,
1967 GError **error)
1968 {
1969 DfuDevicePrivate *priv = GET_PRIVATE (device);
1970
1971 /* sad panda */
1972 if (error == NULL)
1973 return;
1974
1975 /* not the right error to query */
1976 if (!g_error_matches (*error,
1977 G_USB_DEVICE_ERROR,
1978 G_USB_DEVICE_ERROR_NOT_SUPPORTED))
1979 return;
1980
1981 /* get the status */
1982 if (!dfu_device_refresh (device, cancellable, NULL))
1983 return;
1984
1985 /* not in an error state */
1986 if (priv->state != DFU_STATE_DFU_ERROR)
1987 return;
1988
1989 /* prefix the error */
1990 switch (priv->status) {
1991 case DFU_STATUS_OK:
1992 /* ignore */
1993 break;
1994 case DFU_STATUS_ERR_VENDOR:
1995 g_prefix_error (error, "read protection is active: ");
1996 break;
1997 default:
1998 g_prefix_error (error, "[%s,%s]: ",
1999 dfu_state_to_string (priv->state),
2000 dfu_status_to_string (priv->status));
2001 break;
2002 }
2003 }
2004
2005 /**
2006 * dfu_device_get_quirks_as_string: (skip)
2007 * @device: a #DfuDevice
2008 *
2009 * Gets a string describing the quirks set for a device.
2010 *
2011 * Return value: string, or %NULL for no quirks
2012 *
2013 * Since: 0.5.4
2014 **/
2015 gchar *
2016 dfu_device_get_quirks_as_string (DfuDevice *device)
2017 {
2018 DfuDevicePrivate *priv = GET_PRIVATE (device);
2019 GString *str;
2020
2021 /* just append to a string */
2022 str = g_string_new ("");
2023 if (priv->quirks & DFU_DEVICE_QUIRK_IGNORE_POLLTIMEOUT)
2024 g_string_append_printf (str, "ignore-polltimeout|");
2025 if (priv->quirks & DFU_DEVICE_QUIRK_FORCE_DFU_MODE)
2026 g_string_append_printf (str, "force-dfu-mode|");
2027 if (priv->quirks & DFU_DEVICE_QUIRK_IGNORE_INVALID_VERSION)
2028 g_string_append_printf (str, "ignore-invalid-version|");
2029 if (priv->quirks & DFU_DEVICE_QUIRK_USE_PROTOCOL_ZERO)
2030 g_string_append_printf (str, "use-protocol-zero|");
2031 if (priv->quirks & DFU_DEVICE_QUIRK_NO_PID_CHANGE)
2032 g_string_append_printf (str, "no-pid-change|");
2033 if (priv->quirks & DFU_DEVICE_QUIRK_NO_GET_STATUS_UPLOAD)
2034 g_string_append_printf (str, "no-get-status-upload|");
2035 if (priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME)
2036 g_string_append_printf (str, "no-dfu-runtime|");
2037 if (priv->quirks & DFU_DEVICE_QUIRK_ATTACH_UPLOAD_DOWNLOAD)
2038 g_string_append_printf (str, "attach-upload-download|");
2039
2040 /* a well behaved device */
2041 if (str->len == 0) {
2042 g_string_free (str, TRUE);
2043 return NULL;
2044 }
2045
2046 /* remove trailing pipe */
2047 g_string_truncate (str, str->len - 1);
2048 return g_string_free (str, FALSE);
2049 }
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #ifndef __DFU_DEVICE_H
22 #define __DFU_DEVICE_H
23
24 #include <glib-object.h>
25 #include <gio/gio.h>
26 #include <gusb.h>
27
28 #include "dfu-common.h"
29 #include "dfu-target.h"
30 #include "dfu-firmware.h"
31
32 G_BEGIN_DECLS
33
34 #define DFU_TYPE_DEVICE (dfu_device_get_type ())
35 G_DECLARE_DERIVABLE_TYPE (DfuDevice, dfu_device, DFU, DEVICE, GObject)
36
37 /**
38 * DfuDeviceOpenFlags:
39 * @DFU_DEVICE_OPEN_FLAG_NONE: No flags set
40 * @DFU_DEVICE_OPEN_FLAG_NO_AUTO_REFRESH: Do not do the initial GET_STATUS
41 *
42 * The optional flags used for opening the target.
43 **/
44 typedef enum {
45 DFU_DEVICE_OPEN_FLAG_NONE = 0,
46 DFU_DEVICE_OPEN_FLAG_NO_AUTO_REFRESH = (1 << 0),
47 /*< private >*/
48 DFU_DEVICE_OPEN_FLAG_LAST,
49 } DfuDeviceOpenFlags;
50
51 struct _DfuDeviceClass
52 {
53 GObjectClass parent_class;
54 void (*status_changed) (DfuDevice *device,
55 DfuStatus status);
56 void (*state_changed) (DfuDevice *device,
57 DfuState state);
58 void (*percentage_changed) (DfuDevice *device,
59 guint percentage);
60 /*< private >*/
61 /* Padding for future expansion */
62 void (*_dfu_device_reserved1) (void);
63 void (*_dfu_device_reserved2) (void);
64 void (*_dfu_device_reserved3) (void);
65 void (*_dfu_device_reserved4) (void);
66 void (*_dfu_device_reserved5) (void);
67 void (*_dfu_device_reserved6) (void);
68 void (*_dfu_device_reserved7) (void);
69 void (*_dfu_device_reserved8) (void);
70 void (*_dfu_device_reserved9) (void);
71 };
72
73 DfuDevice *dfu_device_new (GUsbDevice *dev);
74 gboolean dfu_device_open (DfuDevice *device,
75 DfuDeviceOpenFlags flags,
76 GCancellable *cancellable,
77 GError **error);
78 gboolean dfu_device_close (DfuDevice *device,
79 GError **error);
80 const gchar *dfu_device_get_platform_id (DfuDevice *device);
81 GPtrArray *dfu_device_get_targets (DfuDevice *device);
82 DfuTarget *dfu_device_get_target_by_alt_setting (DfuDevice *device,
83 guint8 alt_setting,
84 GError **error);
85 DfuTarget *dfu_device_get_target_by_alt_name (DfuDevice *device,
86 const gchar *alt_name,
87 GError **error);
88 const gchar *dfu_device_get_display_name (DfuDevice *device);
89 guint16 dfu_device_get_runtime_vid (DfuDevice *device);
90 guint16 dfu_device_get_runtime_pid (DfuDevice *device);
91 guint16 dfu_device_get_runtime_release (DfuDevice *device);
92 gboolean dfu_device_reset (DfuDevice *device,
93 GError **error);
94 gboolean dfu_device_attach (DfuDevice *device,
95 GError **error);
96 gboolean dfu_device_wait_for_replug (DfuDevice *device,
97 guint timeout,
98 GCancellable *cancellable,
99 GError **error);
100 DfuFirmware *dfu_device_upload (DfuDevice *device,
101 DfuTargetTransferFlags flags,
102 GCancellable *cancellable,
103 GError **error);
104 gboolean dfu_device_download (DfuDevice *device,
105 DfuFirmware *firmware,
106 DfuTargetTransferFlags flags,
107 GCancellable *cancellable,
108 GError **error);
109 gboolean dfu_device_refresh (DfuDevice *device,
110 GCancellable *cancellable,
111 GError **error);
112 gboolean dfu_device_detach (DfuDevice *device,
113 GCancellable *cancellable,
114 GError **error);
115 gboolean dfu_device_abort (DfuDevice *device,
116 GCancellable *cancellable,
117 GError **error);
118 gboolean dfu_device_clear_status (DfuDevice *device,
119 GCancellable *cancellable,
120 GError **error);
121
122 guint8 dfu_device_get_interface (DfuDevice *device);
123 DfuMode dfu_device_get_mode (DfuDevice *device);
124 DfuState dfu_device_get_state (DfuDevice *device);
125 DfuStatus dfu_device_get_status (DfuDevice *device);
126 guint16 dfu_device_get_transfer_size (DfuDevice *device);
127 guint dfu_device_get_timeout (DfuDevice *device);
128 gboolean dfu_device_can_upload (DfuDevice *device);
129 gboolean dfu_device_can_download (DfuDevice *device);
130
131 void dfu_device_set_transfer_size (DfuDevice *device,
132 guint16 transfer_size);
133 void dfu_device_set_timeout (DfuDevice *device,
134 guint timeout_ms);
135
136 G_END_DECLS
137
138 #endif /* __DFU_DEVICE_H */
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #ifndef __DFU_ELEMENT_PRIVATE_H
22 #define __DFU_ELEMENT_PRIVATE_H
23
24 #include "dfu-element.h"
25
26 G_BEGIN_DECLS
27
28 DfuElement *dfu_element_from_dfuse (const guint8 *data,
29 guint32 length,
30 guint32 *consumed,
31 GError **error);
32 GBytes *dfu_element_to_dfuse (DfuElement *element);
33
34 G_END_DECLS
35
36 #endif /* __DFU_ELEMENT_PRIVATE_H */
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /**
22 * SECTION:dfu-element
23 * @short_description: Object representing a binary element
24 *
25 * This object represents an binary blob of data at a specific address.
26 *
27 * This allows relocatable data segments to be stored in different
28 * locations on the device itself.
29 *
30 * See also: #DfuImage, #DfuFirmware
31 */
32
33 #include "config.h"
34
35 #include <string.h>
36 #include <stdio.h>
37
38 #include "dfu-common.h"
39 #include "dfu-element-private.h"
40 #include "dfu-error.h"
41
42 static void dfu_element_finalize (GObject *object);
43
44 /**
45 * DfuElementPrivate:
46 *
47 * Private #DfuElement data
48 **/
49 typedef struct {
50 GBytes *contents;
51 guint32 target_size;
52 guint32 address;
53 } DfuElementPrivate;
54
55 G_DEFINE_TYPE_WITH_PRIVATE (DfuElement, dfu_element, G_TYPE_OBJECT)
56 #define GET_PRIVATE(o) (dfu_element_get_instance_private (o))
57
58 /**
59 * dfu_element_class_init:
60 **/
61 static void
62 dfu_element_class_init (DfuElementClass *klass)
63 {
64 GObjectClass *object_class = G_OBJECT_CLASS (klass);
65 object_class->finalize = dfu_element_finalize;
66 }
67
68 /**
69 * dfu_element_init:
70 **/
71 static void
72 dfu_element_init (DfuElement *element)
73 {
74 }
75
76 /**
77 * dfu_element_finalize:
78 **/
79 static void
80 dfu_element_finalize (GObject *object)
81 {
82 DfuElement *element = DFU_ELEMENT (object);
83 DfuElementPrivate *priv = GET_PRIVATE (element);
84
85 if (priv->contents != NULL)
86 g_bytes_unref (priv->contents);
87
88 G_OBJECT_CLASS (dfu_element_parent_class)->finalize (object);
89 }
90
91 /**
92 * dfu_element_new:
93 *
94 * Creates a new DFU element object.
95 *
96 * Return value: a new #DfuElement
97 *
98 * Since: 0.5.4
99 **/
100 DfuElement *
101 dfu_element_new (void)
102 {
103 DfuElement *element;
104 element = g_object_new (DFU_TYPE_ELEMENT, NULL);
105 return element;
106 }
107
108 /**
109 * dfu_element_get_contents:
110 * @element: a #DfuElement
111 *
112 * Gets the element data.
113 *
114 * Return value: (transfer none): element data
115 *
116 * Since: 0.5.4
117 **/
118 GBytes *
119 dfu_element_get_contents (DfuElement *element)
120 {
121 DfuElementPrivate *priv = GET_PRIVATE (element);
122 g_return_val_if_fail (DFU_IS_ELEMENT (element), NULL);
123 return priv->contents;
124 }
125
126 /**
127 * dfu_element_get_address:
128 * @element: a #DfuElement
129 *
130 * Gets the alternate setting.
131 *
132 * Return value: integer, or 0x00 for unset
133 *
134 * Since: 0.5.4
135 **/
136 guint32
137 dfu_element_get_address (DfuElement *element)
138 {
139 DfuElementPrivate *priv = GET_PRIVATE (element);
140 g_return_val_if_fail (DFU_IS_ELEMENT (element), 0x00);
141 return priv->address;
142 }
143
144 /**
145 * dfu_element_set_contents:
146 * @element: a #DfuElement
147 * @contents: element data
148 *
149 * Sets the element data.
150 *
151 * Since: 0.5.4
152 **/
153 void
154 dfu_element_set_contents (DfuElement *element, GBytes *contents)
155 {
156 DfuElementPrivate *priv = GET_PRIVATE (element);
157 g_return_if_fail (DFU_IS_ELEMENT (element));
158 g_return_if_fail (contents != NULL);
159 if (priv->contents == contents)
160 return;
161 if (priv->contents != NULL)
162 g_bytes_unref (priv->contents);
163 priv->contents = g_bytes_ref (contents);
164 }
165
166 /**
167 * dfu_element_set_address:
168 * @element: a #DfuElement
169 * @address: vendor ID, or 0xffff for unset
170 *
171 * Sets the vendor ID.
172 *
173 * Since: 0.5.4
174 **/
175 void
176 dfu_element_set_address (DfuElement *element, guint32 address)
177 {
178 DfuElementPrivate *priv = GET_PRIVATE (element);
179 g_return_if_fail (DFU_IS_ELEMENT (element));
180 priv->address = address;
181 }
182
183 /**
184 * dfu_element_to_string:
185 * @element: a #DfuElement
186 *
187 * Returns a string representaiton of the object.
188 *
189 * Return value: NULL terminated string, or %NULL for invalid
190 *
191 * Since: 0.5.4
192 **/
193 gchar *
194 dfu_element_to_string (DfuElement *element)
195 {
196 DfuElementPrivate *priv = GET_PRIVATE (element);
197 GString *str;
198
199 g_return_val_if_fail (DFU_IS_ELEMENT (element), NULL);
200
201 str = g_string_new ("");
202 g_string_append_printf (str, "address: 0x%02x\n", priv->address);
203 if (priv->target_size > 0) {
204 g_string_append_printf (str, "target: 0x%04x\n",
205 priv->target_size);
206 }
207 if (priv->contents != NULL) {
208 g_string_append_printf (str, "contents: 0x%04x\n",
209 (guint32) g_bytes_get_size (priv->contents));
210 }
211
212 g_string_truncate (str, str->len - 1);
213 return g_string_free (str, FALSE);
214 }
215
216 /**
217 * dfu_element_set_target_size:
218 * @element: a #DfuElement
219 * @target_size: size in bytes
220 *
221 * Sets a target size for the element. If the prepared element is smaller
222 * than this then it will be padded with NUL bytes up to the required size.
223 *
224 * Since: 0.5.4
225 **/
226 void
227 dfu_element_set_target_size (DfuElement *element, guint32 target_size)
228 {
229 DfuElementPrivate *priv = GET_PRIVATE (element);
230 const guint8 *data;
231 gsize length;
232 guint8 *buf;
233 g_autoptr(GBytes) contents_padded = NULL;
234
235 g_return_if_fail (DFU_IS_ELEMENT (element));
236
237 /* save for dump */
238 priv->target_size = target_size;
239
240 /* no need to pad */
241 if (priv->contents == NULL)
242 return;
243 if (g_bytes_get_size (priv->contents) >= target_size)
244 return;
245
246 /* reallocate and pad */
247 data = g_bytes_get_data (priv->contents, &length);
248 buf = g_malloc0 (target_size);
249 g_assert (buf != NULL);
250 memcpy (buf, data, length);
251
252 /* replace */
253 g_bytes_unref (priv->contents);
254 priv->contents = g_bytes_new_take (buf, target_size);
255 }
256
257 /* DfuSe element header */
258 typedef struct __attribute__((packed)) {
259 guint32 address;
260 guint32 size;
261 } DfuSeElementPrefix;
262
263 /**
264 * dfu_element_from_dfuse: (skip)
265 * @data: data buffer
266 * @length: length of @data we can access
267 * @consumed: (out): the number of bytes we consued
268 * @error: a #GError, or %NULL
269 *
270 * Unpacks an element from DfuSe data.
271 *
272 * Returns: a #DfuElement, or %NULL for error
273 **/
274 DfuElement *
275 dfu_element_from_dfuse (const guint8 *data,
276 guint32 length,
277 guint32 *consumed,
278 GError **error)
279 {
280 DfuElement *element = NULL;
281 DfuElementPrivate *priv;
282 DfuSeElementPrefix *el = (DfuSeElementPrefix *) data;
283 guint32 size;
284
285 g_assert_cmpint(sizeof(DfuSeElementPrefix), ==, 8);
286
287 /* check input buffer size */
288 if (length < sizeof(DfuSeElementPrefix)) {
289 g_set_error (error,
290 DFU_ERROR,
291 DFU_ERROR_INTERNAL,
292 "invalid element data size %u",
293 (guint32) length);
294 return NULL;
295 }
296
297 /* check size */
298 size = GUINT32_FROM_LE (el->size);
299 if (size + sizeof(DfuSeElementPrefix) > length) {
300 g_set_error (error,
301 DFU_ERROR,
302 DFU_ERROR_INTERNAL,
303 "invalid element size %u, only %u bytes left",
304 size,
305 (guint32) (length - sizeof(DfuSeElementPrefix)));
306 return NULL;
307 }
308
309 /* create new element */
310 element = dfu_element_new ();
311 priv = GET_PRIVATE (element);
312 priv->address = GUINT32_FROM_LE (el->address);
313 priv->contents = g_bytes_new (data + sizeof(DfuSeElementPrefix), size);
314
315 /* return size */
316 if (consumed != NULL)
317 *consumed = sizeof(DfuSeElementPrefix) + size;
318
319 return element;
320 }
321
322 /**
323 * dfu_element_to_dfuse: (skip)
324 * @element: a #DfuElement
325 *
326 * Packs a DfuSe element.
327 *
328 * Returns: (transfer full): the packed data
329 **/
330 GBytes *
331 dfu_element_to_dfuse (DfuElement *element)
332 {
333 DfuElementPrivate *priv = GET_PRIVATE (element);
334 DfuSeElementPrefix *el;
335 const guint8 *data;
336 gsize length;
337 guint8 *buf;
338
339 data = g_bytes_get_data (priv->contents, &length);
340 buf = g_malloc0 (length + sizeof (DfuSeElementPrefix));
341 el = (DfuSeElementPrefix *) buf;
342 el->address = GUINT32_TO_LE (priv->address);
343 el->size = GUINT32_TO_LE (length);
344
345 memcpy (buf + sizeof (DfuSeElementPrefix), data, length);
346 return g_bytes_new_take (buf, length + sizeof (DfuSeElementPrefix));
347 }
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #ifndef __DFU_ELEMENT_H
22 #define __DFU_ELEMENT_H
23
24 #include <glib-object.h>
25 #include <gio/gio.h>
26
27 G_BEGIN_DECLS
28
29 #define DFU_TYPE_ELEMENT (dfu_element_get_type ())
30 G_DECLARE_DERIVABLE_TYPE (DfuElement, dfu_element, DFU, ELEMENT, GObject)
31
32 struct _DfuElementClass
33 {
34 GObjectClass parent_class;
35 /*< private >*/
36 /* Padding for future expansion */
37 void (*_dfu_element_reserved1) (void);
38 void (*_dfu_element_reserved2) (void);
39 void (*_dfu_element_reserved3) (void);
40 void (*_dfu_element_reserved4) (void);
41 void (*_dfu_element_reserved5) (void);
42 void (*_dfu_element_reserved6) (void);
43 void (*_dfu_element_reserved7) (void);
44 void (*_dfu_element_reserved8) (void);
45 void (*_dfu_element_reserved9) (void);
46 };
47
48 DfuElement *dfu_element_new (void);
49
50 GBytes *dfu_element_get_contents (DfuElement *element);
51 guint32 dfu_element_get_address (DfuElement *element);
52
53 void dfu_element_set_contents (DfuElement *element,
54 GBytes *contents);
55 void dfu_element_set_address (DfuElement *element,
56 guint32 address);
57 void dfu_element_set_target_size (DfuElement *element,
58 guint32 target_size);
59
60 gchar *dfu_element_to_string (DfuElement *element);
61
62 G_END_DECLS
63
64 #endif /* __DFU_ELEMENT_H */
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /**
22 * SECTION:dfu-error
23 * @short_description: Error defines for libdfu
24 *
25 * This documents the error domain and codes used by libdfu.
26 */
27
28 #include "config.h"
29
30 #include <gio/gio.h>
31
32 #include "dfu-error.h"
33
34 /**
35 * dfu_error_quark:
36 *
37 * Return value: An error quark.
38 *
39 * Since: 0.5.4
40 **/
41 GQuark
42 dfu_error_quark (void)
43 {
44 static GQuark quark = 0;
45 if (!quark)
46 quark = g_quark_from_static_string ("DfuError");
47 return quark;
48 }
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #ifndef __DFU_ERROR_H
22 #define __DFU_ERROR_H
23
24 #include <glib.h>
25
26 #define DFU_ERROR dfu_error_quark()
27
28 /**
29 * DfuError:
30 * @DFU_ERROR_INTERNAL: Internal error
31 * @DFU_ERROR_VERIFY_FAILED: Failed to verify write
32 * @DFU_ERROR_INVALID_FILE: Invalid file format
33 * @DFU_ERROR_INVALID_DEVICE: Invalid device type
34 * @DFU_ERROR_NOT_FOUND: Resource not found
35 * @DFU_ERROR_NOT_SUPPORTED: Action was not supported
36 * @DFU_ERROR_PERMISSION_DENIED: Failed due to access permissions
37 *
38 * The error code.
39 **/
40 typedef enum {
41 DFU_ERROR_INTERNAL, /* Since: 0.5.4 */
42 DFU_ERROR_VERIFY_FAILED, /* Since: 0.5.4 */
43 DFU_ERROR_INVALID_FILE, /* Since: 0.5.4 */
44 DFU_ERROR_INVALID_DEVICE, /* Since: 0.5.4 */
45 DFU_ERROR_NOT_FOUND, /* Since: 0.5.4 */
46 DFU_ERROR_NOT_SUPPORTED, /* Since: 0.5.4 */
47 DFU_ERROR_PERMISSION_DENIED, /* Since: 0.5.4 */
48 /*< private >*/
49 DFU_ERROR_LAST
50 } DfuError;
51
52 GQuark dfu_error_quark (void);
53
54 #endif /* __DFU_ERROR_H */
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /**
22 * SECTION:dfu-firmware
23 * @short_description: Object representing a DFU or DfuSe firmware file
24 *
25 * This object allows reading and writing firmware files either in
26 * raw, DFU or DfuSe formats.
27 *
28 * A #DfuFirmware can be made up of several #DfuImages, although
29 * typically there is only one.
30 *
31 * See also: #DfuImage
32 */
33
34 #include "config.h"
35
36 #include <string.h>
37 #include <stdio.h>
38
39 #include "dfu-common.h"
40 #include "dfu-error.h"
41 #include "dfu-firmware.h"
42 #include "dfu-image-private.h"
43
44 static void dfu_firmware_finalize (GObject *object);
45
46 /**
47 * DfuFirmwarePrivate:
48 *
49 * Private #DfuFirmware data
50 **/
51 typedef struct {
52 GHashTable *metadata;
53 GPtrArray *images;
54 guint16 vid;
55 guint16 pid;
56 guint16 release;
57 guint32 crc;
58 DfuCipherKind cipher_kind;
59 DfuFirmwareFormat format;
60 } DfuFirmwarePrivate;
61
62 G_DEFINE_TYPE_WITH_PRIVATE (DfuFirmware, dfu_firmware, G_TYPE_OBJECT)
63 #define GET_PRIVATE(o) (dfu_firmware_get_instance_private (o))
64
65 /**
66 * dfu_firmware_class_init:
67 **/
68 static void
69 dfu_firmware_class_init (DfuFirmwareClass *klass)
70 {
71 GObjectClass *object_class = G_OBJECT_CLASS (klass);
72 object_class->finalize = dfu_firmware_finalize;
73 }
74
75 /**
76 * dfu_firmware_init:
77 **/
78 static void
79 dfu_firmware_init (DfuFirmware *firmware)
80 {
81 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
82 priv->vid = 0xffff;
83 priv->pid = 0xffff;
84 priv->release = 0xffff;
85 priv->images = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
86 priv->metadata = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
87 }
88
89 /**
90 * dfu_firmware_finalize:
91 **/
92 static void
93 dfu_firmware_finalize (GObject *object)
94 {
95 DfuFirmware *firmware = DFU_FIRMWARE (object);
96 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
97
98 g_ptr_array_unref (priv->images);
99 g_hash_table_destroy (priv->metadata);
100
101 G_OBJECT_CLASS (dfu_firmware_parent_class)->finalize (object);
102 }
103
104 /**
105 * dfu_firmware_new:
106 *
107 * Creates a new DFU firmware object.
108 *
109 * Return value: a new #DfuFirmware
110 *
111 * Since: 0.5.4
112 **/
113 DfuFirmware *
114 dfu_firmware_new (void)
115 {
116 DfuFirmware *firmware;
117 firmware = g_object_new (DFU_TYPE_FIRMWARE, NULL);
118 return firmware;
119 }
120
121 /**
122 * dfu_firmware_get_image:
123 * @firmware: a #DfuFirmware
124 * @alt_setting: an alternative setting, typically 0x00
125 *
126 * Gets an image from the firmware file.
127 *
128 * Return value: (transfer none): a #DfuImage, or %NULL for not found
129 *
130 * Since: 0.5.4
131 **/
132 DfuImage *
133 dfu_firmware_get_image (DfuFirmware *firmware, guint8 alt_setting)
134 {
135 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
136 DfuImage *im;
137 guint i;
138
139 g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), NULL);
140
141 /* find correct image */
142 for (i = 0; i < priv->images->len; i++) {
143 im = g_ptr_array_index (priv->images, i);
144 if (dfu_image_get_alt_setting (im) == alt_setting)
145 return im;
146 }
147 return NULL;
148 }
149
150 /**
151 * dfu_firmware_get_image_by_name:
152 * @firmware: a #DfuFirmware
153 * @name: an alternative setting name
154 *
155 * Gets an image from the firmware file.
156 *
157 * Return value: (transfer none): a #DfuImage, or %NULL for not found
158 *
159 * Since: 0.5.4
160 **/
161 DfuImage *
162 dfu_firmware_get_image_by_name (DfuFirmware *firmware, const gchar *name)
163 {
164 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
165 DfuImage *im;
166 guint i;
167
168 g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), NULL);
169
170 /* find correct image */
171 for (i = 0; i < priv->images->len; i++) {
172 im = g_ptr_array_index (priv->images, i);
173 if (g_strcmp0 (dfu_image_get_name (im), name) == 0)
174 return im;
175 }
176 return NULL;
177 }
178
179 /**
180 * dfu_firmware_get_image_default:
181 * @firmware: a #DfuFirmware
182 *
183 * Gets the default image from the firmware file.
184 *
185 * Return value: (transfer none): a #DfuImage, or %NULL for not found
186 *
187 * Since: 0.5.4
188 **/
189 DfuImage *
190 dfu_firmware_get_image_default (DfuFirmware *firmware)
191 {
192 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
193 g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), NULL);
194 if (priv->images->len == 0)
195 return NULL;
196 return g_ptr_array_index (priv->images, 0);
197 }
198
199 /**
200 * dfu_firmware_get_images:
201 * @firmware: a #DfuFirmware
202 *
203 * Gets all the images contained in this firmware file.
204 *
205 * Return value: (transfer none) (element-type DfuImage): list of images
206 *
207 * Since: 0.5.4
208 **/
209 GPtrArray *
210 dfu_firmware_get_images (DfuFirmware *firmware)
211 {
212 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
213 g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), NULL);
214 return priv->images;
215 }
216
217 /**
218 * dfu_firmware_get_size:
219 * @firmware: a #DfuFirmware
220 *
221 * Gets the size of all the images in the firmware.
222 *
223 * This only returns actual data that would be sent to the device and
224 * does not include any padding.
225 *
226 * Return value: a integer value, or 0 if there are no images.
227 *
228 * Since: 0.5.4
229 **/
230 guint32
231 dfu_firmware_get_size (DfuFirmware *firmware)
232 {
233 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
234 guint32 length = 0;
235 guint i;
236 g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), 0);
237 for (i = 0; i < priv->images->len; i++) {
238 DfuImage *image = g_ptr_array_index (priv->images, i);
239 length += dfu_image_get_size (image);
240 }
241 return length;
242 }
243
244 /**
245 * dfu_firmware_add_image:
246 * @firmware: a #DfuFirmware
247 * @image: a #DfuImage
248 *
249 * Adds an image to the list of images.
250 *
251 * Since: 0.5.4
252 **/
253 void
254 dfu_firmware_add_image (DfuFirmware *firmware, DfuImage *image)
255 {
256 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
257 g_return_if_fail (DFU_IS_FIRMWARE (firmware));
258 g_return_if_fail (DFU_IS_IMAGE (image));
259 g_ptr_array_add (priv->images, g_object_ref (image));
260 }
261
262 /**
263 * dfu_firmware_get_vid:
264 * @firmware: a #DfuFirmware
265 *
266 * Gets the vendor ID.
267 *
268 * Return value: a vendor ID, or 0xffff for unset
269 *
270 * Since: 0.5.4
271 **/
272 guint16
273 dfu_firmware_get_vid (DfuFirmware *firmware)
274 {
275 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
276 g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), 0xffff);
277 return priv->vid;
278 }
279
280 /**
281 * dfu_firmware_get_pid:
282 * @firmware: a #DfuFirmware
283 *
284 * Gets the product ID.
285 *
286 * Return value: a product ID, or 0xffff for unset
287 *
288 * Since: 0.5.4
289 **/
290 guint16
291 dfu_firmware_get_pid (DfuFirmware *firmware)
292 {
293 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
294 g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), 0xffff);
295 return priv->pid;
296 }
297
298 /**
299 * dfu_firmware_get_release:
300 * @firmware: a #DfuFirmware
301 *
302 * Gets the device ID.
303 *
304 * Return value: a device ID, or 0xffff for unset
305 *
306 * Since: 0.5.4
307 **/
308 guint16
309 dfu_firmware_get_release (DfuFirmware *firmware)
310 {
311 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
312 g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), 0xffff);
313 return priv->release;
314 }
315
316 /**
317 * dfu_firmware_get_format:
318 * @firmware: a #DfuFirmware
319 *
320 * Gets the DFU version.
321 *
322 * Return value: a version, or 0x0 for unset
323 *
324 * Since: 0.5.4
325 **/
326 guint16
327 dfu_firmware_get_format (DfuFirmware *firmware)
328 {
329 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
330 g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), 0xffff);
331 return priv->format;
332 }
333
334 /**
335 * dfu_firmware_set_vid:
336 * @firmware: a #DfuFirmware
337 * @vid: vendor ID, or 0xffff for unset
338 *
339 * Sets the vendor ID.
340 *
341 * Since: 0.5.4
342 **/
343 void
344 dfu_firmware_set_vid (DfuFirmware *firmware, guint16 vid)
345 {
346 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
347 g_return_if_fail (DFU_IS_FIRMWARE (firmware));
348 priv->vid = vid;
349 }
350
351 /**
352 * dfu_firmware_set_pid:
353 * @firmware: a #DfuFirmware
354 * @pid: product ID, or 0xffff for unset
355 *
356 * Sets the product ID.
357 *
358 * Since: 0.5.4
359 **/
360 void
361 dfu_firmware_set_pid (DfuFirmware *firmware, guint16 pid)
362 {
363 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
364 g_return_if_fail (DFU_IS_FIRMWARE (firmware));
365 priv->pid = pid;
366 }
367
368 /**
369 * dfu_firmware_set_release:
370 * @firmware: a #DfuFirmware
371 * @release: device ID, or 0xffff for unset
372 *
373 * Sets the device ID.
374 *
375 * Since: 0.5.4
376 **/
377 void
378 dfu_firmware_set_release (DfuFirmware *firmware, guint16 release)
379 {
380 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
381 g_return_if_fail (DFU_IS_FIRMWARE (firmware));
382 priv->release = release;
383 }
384
385 /**
386 * dfu_firmware_set_format:
387 * @firmware: a #DfuFirmware
388 * @format: a #DfuFirmwareFormat, e.g. %DFU_FIRMWARE_FORMAT_DFUSE
389 *
390 * Sets the DFU version in BCD format.
391 *
392 * Since: 0.5.4
393 **/
394 void
395 dfu_firmware_set_format (DfuFirmware *firmware, DfuFirmwareFormat format)
396 {
397 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
398 g_return_if_fail (DFU_IS_FIRMWARE (firmware));
399 priv->format = format;
400 }
401
402 typedef struct __attribute__((packed)) {
403 guint16 release;
404 guint16 pid;
405 guint16 vid;
406 guint16 ver;
407 guint8 sig[3];
408 guint8 len;
409 guint32 crc;
410 } DfuFirmwareFooter;
411
412 static guint32 _crctbl[] = {
413 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
414 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
415 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
416 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
417 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
418 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
419 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
420 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
421 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
422 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
423 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
424 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
425 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
426 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
427 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
428 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
429 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
430 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
431 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
432 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
433 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
434 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
435 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
436 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
437 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
438 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
439 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
440 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
441 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
442 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
443 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
444 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
445 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
446 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
447 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
448 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
449 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
450 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
451 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
452 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
453 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
454 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
455 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d };
456
457 /**
458 * dfu_firmware_generate_crc32:
459 **/
460 static guint32
461 dfu_firmware_generate_crc32 (const guint8 *data, gsize length)
462 {
463 guint i;
464 guint32 accum = 0xffffffff;
465 for (i = 0; i < length; i++)
466 accum = _crctbl[(accum^data[i]) & 0xff] ^ (accum >> 8);
467 return accum;
468 }
469
470 /**
471 * dfu_firmware_ihex_parse_uint8:
472 **/
473 static guint8
474 dfu_firmware_ihex_parse_uint8 (const gchar *data, guint pos)
475 {
476 gchar buffer[3];
477 memcpy (buffer, data + pos, 2);
478 buffer[2] = '\0';
479 return g_ascii_strtoull (buffer, NULL, 16);
480 }
481
482 /**
483 * dfu_firmware_ihex_parse_uint16:
484 **/
485 static guint16
486 dfu_firmware_ihex_parse_uint16 (const gchar *data, guint pos)
487 {
488 gchar buffer[5];
489 memcpy (buffer, data + pos, 4);
490 buffer[4] = '\0';
491 return g_ascii_strtoull (buffer, NULL, 16);
492 }
493
494 #define DFU_INHX32_RECORD_TYPE_DATA 0
495 #define DFU_INHX32_RECORD_TYPE_EOF 1
496 #define DFU_INHX32_RECORD_TYPE_EXTENDED 4
497
498 /**
499 * dfu_firmware_add_ihex:
500 **/
501 static gboolean
502 dfu_firmware_add_ihex (DfuFirmware *firmware, GBytes *bytes,
503 DfuFirmwareParseFlags flags, GError **error)
504 {
505 const gchar *in_buffer;
506 gsize len_in;
507 guint16 addr_high = 0;
508 guint16 addr_low = 0;
509 guint32 addr32 = 0;
510 guint32 addr32_last = 0;
511 guint8 checksum;
512 guint8 data_tmp;
513 guint8 len_tmp;
514 guint8 type;
515 guint end;
516 guint i;
517 guint j;
518 guint offset = 0;
519 g_autoptr(DfuElement) element = NULL;
520 g_autoptr(DfuImage) image = NULL;
521 g_autoptr(GBytes) contents = NULL;
522 g_autoptr(GString) string = NULL;
523
524 g_return_val_if_fail (bytes != NULL, FALSE);
525
526 /* create element */
527 image = dfu_image_new ();
528 dfu_image_set_name (image, "ihex");
529 element = dfu_element_new ();
530
531 /* parse records */
532 in_buffer = g_bytes_get_data (bytes, &len_in);
533 string = g_string_new ("");
534 while (offset < len_in) {
535
536 /* check starting token */
537 if (in_buffer[offset] != ':') {
538 g_set_error (error,
539 DFU_ERROR,
540 DFU_ERROR_INVALID_FILE,
541 "invalid starting token, got %c at %x",
542 in_buffer[offset], offset);
543 return FALSE;
544 }
545
546 /* check there's enough data for the smallest possible record */
547 if (offset + 12 > (guint) len_in) {
548 g_set_error (error,
549 DFU_ERROR,
550 DFU_ERROR_INVALID_FILE,
551 "record incomplete at %i, length %i",
552 offset, (guint) len_in);
553 return FALSE;
554 }
555
556 /* length, 16-bit address, type */
557 len_tmp = dfu_firmware_ihex_parse_uint8 (in_buffer, offset+1);
558 addr_low = dfu_firmware_ihex_parse_uint16 (in_buffer, offset+3);
559 type = dfu_firmware_ihex_parse_uint8 (in_buffer, offset+7);
560
561 /* position of checksum */
562 end = offset + 9 + len_tmp * 2;
563 if (end > (guint) len_in) {
564 g_set_error (error,
565 DFU_ERROR,
566 DFU_ERROR_INVALID_FILE,
567 "checksum > file length: %u",
568 end);
569 return FALSE;
570 }
571
572 /* verify checksum */
573 if ((flags & DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST) == 0) {
574 checksum = 0;
575 for (i = offset + 1; i < end + 2; i += 2) {
576 data_tmp = dfu_firmware_ihex_parse_uint8 (in_buffer, i);
577 checksum += data_tmp;
578 }
579 if (checksum != 0) {
580 g_set_error_literal (error,
581 DFU_ERROR,
582 DFU_ERROR_INVALID_FILE,
583 "invalid record checksum");
584 return FALSE;
585 }
586 }
587
588 /* process different record types */
589 switch (type) {
590 case DFU_INHX32_RECORD_TYPE_DATA:
591 /* if not contiguous with previous record */
592 if ((addr_high + addr_low) != addr32) {
593 if (addr32 == 0x0) {
594 g_debug ("base address %04x", addr_low);
595 dfu_element_set_address (element, addr_low);
596 }
597 addr32 = addr_high + addr_low;
598 }
599
600 /* parse bytes from line */
601 for (i = offset + 9; i < end; i += 2) {
602 /* any holes in the hex record */
603 len_tmp = addr32 - addr32_last;
604 if (addr32_last > 0x0 && len_tmp > 1) {
605 for (j = 1; j < len_tmp; j++) {
606 g_debug ("filling address 0x%04x",
607 addr32_last + j);
608 /* although 0xff might be clearer,
609 * we can't write 0xffff to pic14 */
610 g_string_append_c (string, 0x00);
611 }
612 }
613 /* write into buf */
614 data_tmp = dfu_firmware_ihex_parse_uint8 (in_buffer, i);
615 g_string_append_c (string, data_tmp);
616 g_debug ("writing address 0x%04x", addr32);
617 addr32_last = addr32++;
618 }
619 break;
620 case DFU_INHX32_RECORD_TYPE_EOF:
621 break;
622 case DFU_INHX32_RECORD_TYPE_EXTENDED:
623 addr_high = dfu_firmware_ihex_parse_uint16 (in_buffer, offset+9);
624 g_error ("set base address %x", addr_high);
625 addr_high <<= 16;
626 addr32 = addr_high + addr_low;
627 break;
628 default:
629 g_set_error (error,
630 DFU_ERROR,
631 DFU_ERROR_INVALID_FILE,
632 "invalid ihex record type %i",
633 type);
634 return FALSE;
635 }
636
637 /* ignore any line return */
638 offset = end + 2;
639 for (; offset < len_in; offset++) {
640 if (in_buffer[offset] != '\n' &&
641 in_buffer[offset] != '\r')
642 break;
643 }
644 }
645
646 /* add single image */
647 contents = g_bytes_new (string->str, string->len);
648 dfu_element_set_contents (element, contents);
649 dfu_image_add_element (image, element);
650 dfu_firmware_add_image (firmware, image);
651 dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_INTEL_HEX);
652 return TRUE;
653 }
654
655 /**
656 * dfu_firmware_write_data_ihex_element:
657 **/
658 static gboolean
659 dfu_firmware_write_data_ihex_element (DfuElement *element,
660 GString *str,
661 GError **error)
662 {
663 GBytes *contents;
664 const guint8 *data;
665 const guint chunk_size = 16;
666 gsize len;
667 guint chunk_len;
668 guint i;
669 guint j;
670
671 /* get number of chunks */
672 contents = dfu_element_get_contents (element);
673 data = g_bytes_get_data (contents, &len);
674 for (i = 0; i < len; i += chunk_size) {
675 guint8 checksum = 0;
676
677 /* length, 16-bit address, type */
678 chunk_len = MIN (len - i, 16);
679 g_string_append_printf (str, ":%02X%04X%02X",
680 chunk_len,
681 dfu_element_get_address (element) + i,
682 DFU_INHX32_RECORD_TYPE_DATA);
683 for (j = 0; j < chunk_len; j++)
684 g_string_append_printf (str, "%02X", data[i+j]);
685
686 /* add checksum */
687 for (j = 0; j < (chunk_len * 2) + 8; j++)
688 checksum += str->str[str->len - (j + 1)];
689 g_string_append_printf (str, "%02X\n", checksum);
690 }
691 return TRUE;
692 }
693
694 /**
695 * dfu_firmware_write_data_ihex:
696 **/
697 static GBytes *
698 dfu_firmware_write_data_ihex (DfuFirmware *firmware, GError **error)
699 {
700 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
701 DfuElement *element;
702 DfuImage *image;
703 GPtrArray *elements;
704 guint i;
705 guint j;
706 g_autoptr(GString) str = NULL;
707
708 /* write all the element data */
709 str = g_string_new ("");
710 for (i = 0; i < priv->images->len; i++) {
711 image = g_ptr_array_index (priv->images, i);
712 elements = dfu_image_get_elements (image);
713 for (j = 0; j < elements->len; j++) {
714 element = g_ptr_array_index (elements, j);
715 if (!dfu_firmware_write_data_ihex_element (element,
716 str,
717 error))
718 return FALSE;
719 }
720 }
721
722 /* add EOF */
723 g_string_append_printf (str, ":000000%02XFF\n", DFU_INHX32_RECORD_TYPE_EOF);
724 return g_bytes_new (str->str, str->len);
725 }
726
727 /**
728 * dfu_firmware_add_binary:
729 **/
730 static gboolean
731 dfu_firmware_add_binary (DfuFirmware *firmware, GBytes *bytes, GError **error)
732 {
733 g_autoptr(DfuElement) element = NULL;
734 g_autoptr(DfuImage) image = NULL;
735 image = dfu_image_new ();
736 element = dfu_element_new ();
737 dfu_element_set_contents (element, bytes);
738 dfu_image_add_element (image, element);
739 dfu_firmware_add_image (firmware, image);
740 return TRUE;
741 }
742
743 /* DfuSe header */
744 typedef struct __attribute__((packed)) {
745 guint8 sig[5];
746 guint8 ver;
747 guint32 image_size;
748 guint8 targets;
749 } DfuSePrefix;
750
751 /**
752 * dfu_firmware_add_dfuse:
753 **/
754 static gboolean
755 dfu_firmware_add_dfuse (DfuFirmware *firmware, GBytes *bytes, GError **error)
756 {
757 DfuSePrefix *prefix;
758 gsize len;
759 guint32 offset = sizeof(DfuSePrefix);
760 guint8 *data;
761 guint i;
762
763 /* check the prefix (BE) */
764 data = (guint8 *) g_bytes_get_data (bytes, &len);
765 prefix = (DfuSePrefix *) data;
766 if (memcmp (prefix->sig, "DfuSe", 5) != 0) {
767 g_set_error_literal (error,
768 DFU_ERROR,
769 DFU_ERROR_INTERNAL,
770 "invalid DfuSe prefix");
771 return FALSE;
772 }
773
774 /* check the version */
775 if (prefix->ver != 0x01) {
776 g_set_error (error,
777 DFU_ERROR,
778 DFU_ERROR_INTERNAL,
779 "invalid DfuSe version, got %02x",
780 prefix->ver);
781 return FALSE;
782 }
783
784 /* check image size */
785 if (GUINT32_FROM_LE (prefix->image_size) != len) {
786 g_set_error (error,
787 DFU_ERROR,
788 DFU_ERROR_INTERNAL,
789 "invalid DfuSe image size, "
790 "got %" G_GUINT32_FORMAT ", "
791 "expected %" G_GSIZE_FORMAT,
792 GUINT32_FROM_LE (prefix->image_size),
793 len);
794 return FALSE;
795 }
796
797 /* parse the image targets */
798 len -= sizeof(DfuSePrefix);
799 for (i = 0; i < prefix->targets; i++) {
800 guint consumed;
801 g_autoptr(DfuImage) image = NULL;
802 image = dfu_image_from_dfuse (data + offset, len,
803 &consumed, error);
804 if (image == NULL)
805 return FALSE;
806 dfu_firmware_add_image (firmware, image);
807 offset += consumed;
808 len -= consumed;
809 }
810 return TRUE;
811 }
812
813 /**
814 * dfu_firmware_write_data_dfuse:
815 **/
816 static GBytes *
817 dfu_firmware_write_data_dfuse (DfuFirmware *firmware, GError **error)
818 {
819 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
820 DfuSePrefix *prefix;
821 guint i;
822 guint32 image_size_total = 0;
823 guint32 offset = sizeof (DfuSePrefix);
824 guint8 *buf;
825 g_autoptr(GPtrArray) dfuse_images = NULL;
826
827 /* get all the image data */
828 dfuse_images = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref);
829 for (i = 0; i < priv->images->len; i++) {
830 DfuImage *im = g_ptr_array_index (priv->images, i);
831 GBytes *contents;
832 contents = dfu_image_to_dfuse (im);
833 image_size_total += g_bytes_get_size (contents);
834 g_ptr_array_add (dfuse_images, contents);
835 }
836 g_debug ("image_size_total: %i", image_size_total);
837
838 buf = g_malloc0 (sizeof (DfuSePrefix) + image_size_total);
839
840 /* DfuSe header */
841 prefix = (DfuSePrefix *) buf;
842 memcpy (prefix->sig, "DfuSe", 5);
843 prefix->ver = 0x01;
844 prefix->image_size = offset + image_size_total;
845 prefix->targets = priv->images->len;
846
847 /* copy images */
848 for (i = 0; i < dfuse_images->len; i++) {
849 GBytes *contents = g_ptr_array_index (dfuse_images, i);
850 gsize length;
851 const guint8 *data;
852 data = g_bytes_get_data (contents, &length);
853 memcpy (buf + offset, data, length);
854 offset += length;
855 }
856
857 /* return blob */
858 return g_bytes_new_take (buf, sizeof (DfuSePrefix) + image_size_total);
859 }
860
861 /**
862 * dfu_firmware_parse_metadata:
863 *
864 * The representation in memory is as follows:
865 *
866 * uint16 signature='MD'
867 * uint8 number_of_keys
868 * uint8 number_of_keys
869 * uint8 key(n)_length
870 * ... key(n) (no NUL)
871 * uint8 value(n)_length
872 * ... value(n) (no NUL)
873 * <existing DFU footer>
874 **/
875 static gboolean
876 dfu_firmware_parse_metadata (DfuFirmware *firmware,
877 const guint8 *data,
878 guint data_length,
879 guint32 footer_size,
880 GError **error)
881 {
882 guint i;
883 guint idx = data_length - footer_size + 2;
884 guint kvlen;
885 guint number_keys;
886
887 /* not big enough */
888 if (footer_size <= 0x10)
889 return TRUE;
890
891 /* signature invalid */
892 if (memcmp (&data[data_length - footer_size], "MD", 2) != 0)
893 return TRUE;
894
895 /* parse key=value store */
896 number_keys = data[idx++];
897 for (i = 0; i < number_keys; i++) {
898 g_autofree gchar *key = NULL;
899 g_autofree gchar *value = NULL;
900
901 /* parse key */
902 kvlen = data[idx++];
903 if (kvlen > 233) {
904 g_set_error (error,
905 DFU_ERROR,
906 DFU_ERROR_INTERNAL,
907 "metadata table corrupt, key=%i",
908 kvlen);
909 return FALSE;
910 }
911 if (idx + kvlen + 0x10 > data_length) {
912 g_set_error_literal (error,
913 DFU_ERROR,
914 DFU_ERROR_INTERNAL,
915 "metadata table corrupt");
916 return FALSE;
917 }
918 key = g_strndup ((const gchar *) data + idx, kvlen);
919 idx += kvlen;
920
921 /* parse value */
922 kvlen = data[idx++];
923 if (kvlen > 233) {
924 g_set_error (error,
925 DFU_ERROR,
926 DFU_ERROR_INTERNAL,
927 "metadata table corrupt, value=%i",
928 kvlen);
929 return FALSE;
930 }
931 if (idx + kvlen + 0x10 > data_length) {
932 g_set_error_literal (error,
933 DFU_ERROR,
934 DFU_ERROR_INTERNAL,
935 "metadata table corrupt");
936 return FALSE;
937 }
938 value = g_strndup ((const gchar *) data + idx, kvlen);
939 idx += kvlen;
940 dfu_firmware_set_metadata (firmware, key, value);
941 }
942 return TRUE;
943 }
944
945 /**
946 * dfu_firmware_parse_data:
947 * @firmware: a #DfuFirmware
948 * @bytes: raw firmware data
949 * @flags: optional flags, e.g. %DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST
950 * @error: a #GError, or %NULL
951 *
952 * Parses firmware data which may have an optional DFU suffix.
953 *
954 * Return value: %TRUE for success
955 *
956 * Since: 0.5.4
957 **/
958 gboolean
959 dfu_firmware_parse_data (DfuFirmware *firmware, GBytes *bytes,
960 DfuFirmwareParseFlags flags, GError **error)
961 {
962 DfuFirmwareFooter *ftr;
963 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
964 const gchar *cipher_str;
965 gsize len;
966 guint32 crc_new;
967 guint32 size;
968 guint8 *data;
969 g_autoptr(GBytes) contents = NULL;
970
971 g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), FALSE);
972 g_return_val_if_fail (bytes != NULL, FALSE);
973 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
974
975 /* sanity check */
976 g_assert_cmpint(sizeof(DfuSePrefix), ==, 11);
977
978 /* set defaults */
979 priv->vid = 0xffff;
980 priv->pid = 0xffff;
981 priv->release = 0xffff;
982
983 /* this is ihex */
984 data = (guint8 *) g_bytes_get_data (bytes, &len);
985 if (data[0] == ':')
986 return dfu_firmware_add_ihex (firmware, bytes, flags, error);
987
988 /* too small to be a DFU file */
989 if (len < 16) {
990 priv->format = DFU_FIRMWARE_FORMAT_RAW;
991 return dfu_firmware_add_binary (firmware, bytes, error);
992 }
993
994 /* check for DFU signature */
995 ftr = (DfuFirmwareFooter *) &data[len-sizeof(DfuFirmwareFooter)];
996 if (memcmp (ftr->sig, "UFD", 3) != 0) {
997 priv->format = DFU_FIRMWARE_FORMAT_RAW;
998 return dfu_firmware_add_binary (firmware, bytes, error);
999 }
1000
1001 /* check version */
1002 priv->format = GUINT16_FROM_LE (ftr->ver);
1003 if ((flags & DFU_FIRMWARE_PARSE_FLAG_NO_VERSION_TEST) == 0) {
1004 if (priv->format != DFU_FIRMWARE_FORMAT_DFU_1_0 &&
1005 priv->format != DFU_FIRMWARE_FORMAT_DFUSE) {
1006 g_set_error (error,
1007 DFU_ERROR,
1008 DFU_ERROR_INTERNAL,
1009 "version check failed, got %04x",
1010 priv->format);
1011 return FALSE;
1012 }
1013 }
1014
1015 /* verify the checksum */
1016 priv->crc = GUINT32_FROM_LE (ftr->crc);
1017 if ((flags & DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST) == 0) {
1018 crc_new = dfu_firmware_generate_crc32 (data, len - 4);
1019 if (priv->crc != crc_new) {
1020 g_set_error (error,
1021 DFU_ERROR,
1022 DFU_ERROR_INTERNAL,
1023 "CRC failed, expected %04x, got %04x",
1024 crc_new, GUINT32_FROM_LE (ftr->crc));
1025 return FALSE;
1026 }
1027 }
1028
1029 /* set from footer */
1030 dfu_firmware_set_vid (firmware, GUINT16_FROM_LE (ftr->vid));
1031 dfu_firmware_set_pid (firmware, GUINT16_FROM_LE (ftr->pid));
1032 dfu_firmware_set_release (firmware, GUINT16_FROM_LE (ftr->release));
1033
1034 /* check reported length */
1035 size = GUINT16_FROM_LE (ftr->len);
1036 if (size > len) {
1037 g_set_error (error,
1038 DFU_ERROR,
1039 DFU_ERROR_INTERNAL,
1040 "reported firmware size %04x larger than file %04x",
1041 (guint) size, (guint) len);
1042 return FALSE;
1043 }
1044
1045 /* parse the optional metadata segment */
1046 if ((flags & DFU_FIRMWARE_PARSE_FLAG_NO_METADATA) == 0) {
1047 if (!dfu_firmware_parse_metadata (firmware, data, len, size, error))
1048 return FALSE;
1049 }
1050
1051 /* set this automatically */
1052 cipher_str = dfu_firmware_get_metadata (firmware, DFU_METADATA_KEY_CIPHER_KIND);
1053 if (cipher_str != NULL) {
1054 if (g_strcmp0 (cipher_str, "XTEA") == 0)
1055 priv->cipher_kind = DFU_CIPHER_KIND_XTEA;
1056 else
1057 g_warning ("Unknown CipherKind: %s", cipher_str);
1058 }
1059
1060 /* parse DfuSe prefix */
1061 contents = g_bytes_new_from_bytes (bytes, 0, len - size);
1062 if (priv->format == DFU_FIRMWARE_FORMAT_DFUSE)
1063 return dfu_firmware_add_dfuse (firmware, contents, error);
1064
1065 /* just copy old-plain DFU file */
1066 return dfu_firmware_add_binary (firmware, contents, error);
1067 }
1068
1069 /**
1070 * dfu_firmware_parse_file:
1071 * @firmware: a #DfuFirmware
1072 * @file: a #GFile to load and parse
1073 * @flags: optional flags, e.g. %DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST
1074 * @cancellable: a #GCancellable, or %NULL
1075 * @error: a #GError, or %NULL
1076 *
1077 * Parses a DFU firmware, which may contain an optional footer.
1078 *
1079 * Return value: %TRUE for success
1080 *
1081 * Since: 0.5.4
1082 **/
1083 gboolean
1084 dfu_firmware_parse_file (DfuFirmware *firmware, GFile *file,
1085 DfuFirmwareParseFlags flags,
1086 GCancellable *cancellable, GError **error)
1087 {
1088 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
1089 gchar *contents = NULL;
1090 gsize length = 0;
1091 g_autofree gchar *basename = NULL;
1092 g_autoptr(GBytes) bytes = NULL;
1093
1094 g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), FALSE);
1095 g_return_val_if_fail (G_IS_FILE (file), FALSE);
1096 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1097
1098 /* guess cipher kind based on file extension */
1099 basename = g_file_get_basename (file);
1100 if (g_str_has_suffix (basename, ".xdfu"))
1101 priv->cipher_kind = DFU_CIPHER_KIND_XTEA;
1102
1103 if (!g_file_load_contents (file, cancellable, &contents,
1104 &length, NULL, error))
1105 return FALSE;
1106 bytes = g_bytes_new_take (contents, length);
1107 return dfu_firmware_parse_data (firmware, bytes, flags, error);
1108 }
1109
1110 /**
1111 * dfu_firmware_get_metadata:
1112 * @firmware: a #DfuFirmware
1113 * @key: metadata string key
1114 *
1115 * Gets metadata from the store with a specific key.
1116 *
1117 * Return value: the metadata value, or %NULL for unset
1118 *
1119 * Since: 0.5.4
1120 **/
1121 const gchar *
1122 dfu_firmware_get_metadata (DfuFirmware *firmware, const gchar *key)
1123 {
1124 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
1125 return g_hash_table_lookup (priv->metadata, key);
1126 }
1127
1128 /**
1129 * dfu_firmware_set_metadata:
1130 * @firmware: a #DfuFirmware
1131 * @key: metadata string key
1132 * @value: metadata string value
1133 *
1134 * Sets a metadata value with a specific key.
1135 *
1136 * Since: 0.5.4
1137 **/
1138 void
1139 dfu_firmware_set_metadata (DfuFirmware *firmware, const gchar *key, const gchar *value)
1140 {
1141 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
1142 g_debug ("adding metadata %s=%s", key, value);
1143 g_hash_table_insert (priv->metadata, g_strdup (key), g_strdup (value));
1144 }
1145
1146 /**
1147 * dfu_firmware_remove_metadata:
1148 * @firmware: a #DfuFirmware
1149 * @key: metadata string key
1150 *
1151 * Removes a metadata item from the store
1152 *
1153 * Since: 0.5.4
1154 **/
1155 void
1156 dfu_firmware_remove_metadata (DfuFirmware *firmware, const gchar *key)
1157 {
1158 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
1159 g_debug ("removing metadata %s", key);
1160 g_hash_table_remove (priv->metadata, key);
1161 }
1162
1163 /**
1164 * dfu_firmware_build_metadata_table:
1165 **/
1166 static GBytes *
1167 dfu_firmware_build_metadata_table (DfuFirmware *firmware, GError **error)
1168 {
1169 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
1170 GList *l;
1171 guint8 mdbuf[239];
1172 guint idx = 0;
1173 guint number_keys;
1174 g_autoptr(GList) keys = NULL;
1175
1176 /* no metadata */
1177 if (g_hash_table_size (priv->metadata) == 0)
1178 return g_bytes_new (NULL, 0);
1179
1180 /* check the number of keys */
1181 keys = g_hash_table_get_keys (priv->metadata);
1182 number_keys = g_list_length (keys);
1183 if (number_keys > 59) {
1184 g_set_error (error,
1185 DFU_ERROR,
1186 DFU_ERROR_NOT_SUPPORTED,
1187 "too many metadata keys (%i)",
1188 number_keys);
1189 return NULL;
1190 }
1191
1192 /* write the signature */
1193 mdbuf[idx++] = 'M';
1194 mdbuf[idx++] = 'D';
1195 mdbuf[idx++] = number_keys;
1196 for (l = keys; l != NULL; l = l->next) {
1197 const gchar *key;
1198 const gchar *value;
1199 guint key_len;
1200 guint value_len;
1201
1202 /* check key and value length */
1203 key = l->data;
1204 key_len = strlen (key);
1205 if (key_len > 233) {
1206 g_set_error (error,
1207 DFU_ERROR,
1208 DFU_ERROR_NOT_SUPPORTED,
1209 "metdata key too long: %s",
1210 key);
1211 return NULL;
1212 }
1213 value = g_hash_table_lookup (priv->metadata, key);
1214 value_len = strlen (value);
1215 if (value_len > 233) {
1216 g_set_error (error,
1217 DFU_ERROR,
1218 DFU_ERROR_NOT_SUPPORTED,
1219 "value too long: %s",
1220 value);
1221 return NULL;
1222 }
1223
1224 /* do we still have space? */
1225 if (idx + key_len + value_len + 2 > sizeof(mdbuf)) {
1226 g_set_error (error,
1227 DFU_ERROR,
1228 DFU_ERROR_NOT_SUPPORTED,
1229 "not enough space in metadata table, "
1230 "already used %i bytes", idx);
1231 return NULL;
1232 }
1233
1234 /* write the key */
1235 mdbuf[idx++] = key_len;
1236 memcpy(mdbuf + idx, key, key_len);
1237 idx += key_len;
1238
1239 /* write the value */
1240 mdbuf[idx++] = value_len;
1241 memcpy(mdbuf + idx, value, value_len);
1242 idx += value_len;
1243 }
1244 g_debug ("metadata table was %i/%i bytes", idx, (guint) sizeof(mdbuf));
1245 return g_bytes_new (mdbuf, idx);
1246 }
1247
1248 /**
1249 * dfu_firmware_add_footer:
1250 **/
1251 static GBytes *
1252 dfu_firmware_add_footer (DfuFirmware *firmware, GBytes *contents, GError **error)
1253 {
1254 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
1255 DfuFirmwareFooter *ftr;
1256 const guint8 *data_bin;
1257 const guint8 *data_md;
1258 gsize length_bin = 0;
1259 gsize length_md = 0;
1260 guint8 *buf;
1261 g_autoptr(GBytes) metadata_table = NULL;
1262
1263 /* get any file metadata */
1264 metadata_table = dfu_firmware_build_metadata_table (firmware, error);
1265 if (metadata_table == NULL)
1266 return NULL;
1267 data_md = g_bytes_get_data (metadata_table, &length_md);
1268
1269 /* add the raw firmware data */
1270 data_bin = g_bytes_get_data (contents, &length_bin);
1271 buf = g_malloc0 (length_bin + length_md + 0x10);
1272 memcpy (buf + 0, data_bin, length_bin);
1273
1274 /* add the metadata table */
1275 memcpy (buf + length_bin, data_md, length_md);
1276
1277 /* set up LE footer */
1278 ftr = (DfuFirmwareFooter *) (buf + length_bin + length_md);
1279 ftr->release = GUINT16_TO_LE (priv->release);
1280 ftr->pid = GUINT16_TO_LE (priv->pid);
1281 ftr->vid = GUINT16_TO_LE (priv->vid);
1282 ftr->ver = GUINT16_TO_LE (priv->format);
1283 ftr->len = GUINT16_TO_LE (0x10 + length_md);
1284 memcpy(ftr->sig, "UFD", 3);
1285 ftr->crc = dfu_firmware_generate_crc32 (buf, length_bin + length_md + 12);
1286
1287 /* return all data */
1288 return g_bytes_new_take (buf, length_bin + length_md + 0x10);
1289 }
1290
1291 /**
1292 * dfu_firmware_write_data:
1293 * @firmware: a #DfuFirmware
1294 * @error: a #GError, or %NULL
1295 *
1296 * Writes DFU data to a data blob with a DFU-specific footer.
1297 *
1298 * Return value: (transfer none): firmware data
1299 *
1300 * Since: 0.5.4
1301 **/
1302 GBytes *
1303 dfu_firmware_write_data (DfuFirmware *firmware, GError **error)
1304 {
1305 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
1306 DfuImage *image;
1307
1308 g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), NULL);
1309 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1310
1311 /* at least one image */
1312 if (priv->images == 0) {
1313 g_set_error_literal (error,
1314 DFU_ERROR,
1315 DFU_ERROR_INTERNAL,
1316 "no image data to write");
1317 return NULL;
1318 }
1319
1320 /* DFU only supports one image */
1321 if (priv->images->len > 1 &&
1322 priv->format != DFU_FIRMWARE_FORMAT_DFUSE) {
1323 g_set_error (error,
1324 DFU_ERROR,
1325 DFU_ERROR_INTERNAL,
1326 "only DfuSe format supports multiple images (%i)",
1327 priv->images->len);
1328 return NULL;
1329 }
1330
1331 /* raw */
1332 if (priv->format == DFU_FIRMWARE_FORMAT_RAW) {
1333 GBytes *contents;
1334 DfuElement *element;
1335 image = dfu_firmware_get_image_default (firmware);
1336 g_assert (image != NULL);
1337 element = dfu_image_get_element (image, 0);
1338 if (element == NULL) {
1339 g_set_error (error,
1340 DFU_ERROR,
1341 DFU_ERROR_NOT_FOUND,
1342 "no firmware element data to write");
1343 return NULL;
1344 }
1345 contents = dfu_element_get_contents (element);
1346 return g_bytes_ref (contents);
1347 }
1348
1349 /* plain-old DFU */
1350 if (priv->format == DFU_FIRMWARE_FORMAT_DFU_1_0) {
1351 GBytes *contents;
1352 DfuElement *element;
1353 image = dfu_firmware_get_image_default (firmware);
1354 g_assert (image != NULL);
1355 element = dfu_image_get_element (image, 0);
1356 if (element == NULL) {
1357 g_set_error (error,
1358 DFU_ERROR,
1359 DFU_ERROR_NOT_FOUND,
1360 "no firmware element data to write");
1361 return NULL;
1362 }
1363 contents = dfu_element_get_contents (element);
1364 g_assert (contents != NULL);
1365 return dfu_firmware_add_footer (firmware, contents, error);
1366 }
1367
1368 /* DfuSe */
1369 if (priv->format == DFU_FIRMWARE_FORMAT_DFUSE) {
1370 g_autoptr(GBytes) contents = NULL;
1371 contents = dfu_firmware_write_data_dfuse (firmware, error);
1372 if (contents == NULL)
1373 return NULL;
1374 return dfu_firmware_add_footer (firmware, contents, error);
1375 }
1376
1377 /* Intel HEX */
1378 if (priv->format == DFU_FIRMWARE_FORMAT_INTEL_HEX)
1379 return dfu_firmware_write_data_ihex (firmware, error);
1380
1381 /* invalid */
1382 g_set_error (error,
1383 DFU_ERROR,
1384 DFU_ERROR_INTERNAL,
1385 "invalid format for write (0x%04x)",
1386 priv->format);
1387 return NULL;
1388 }
1389
1390 /**
1391 * dfu_firmware_write_file:
1392 * @firmware: a #DfuFirmware
1393 * @file: a #GFile
1394 * @cancellable: a #GCancellable, or %NULL
1395 * @error: a #GError, or %NULL
1396 *
1397 * Writes a DFU firmware with the optional footer.
1398 *
1399 * Return value: %TRUE for success
1400 *
1401 * Since: 0.5.4
1402 **/
1403 gboolean
1404 dfu_firmware_write_file (DfuFirmware *firmware, GFile *file,
1405 GCancellable *cancellable, GError **error)
1406 {
1407 const guint8 *data;
1408 gsize length = 0;
1409 g_autoptr(GBytes) bytes = NULL;
1410
1411 g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), FALSE);
1412 g_return_val_if_fail (G_IS_FILE (file), FALSE);
1413 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1414
1415 /* get blob */
1416 bytes = dfu_firmware_write_data (firmware, error);
1417 if (bytes == NULL)
1418 return FALSE;
1419
1420 /* save to firmware */
1421 data = g_bytes_get_data (bytes, &length);
1422 return g_file_replace_contents (file,
1423 (const gchar *) data,
1424 length,
1425 NULL,
1426 FALSE,
1427 G_FILE_CREATE_NONE,
1428 NULL,
1429 cancellable,
1430 error);
1431 }
1432
1433 /**
1434 * dfu_firmware_to_string:
1435 * @firmware: a #DfuFirmware
1436 *
1437 * Returns a string representaiton of the object.
1438 *
1439 * Return value: NULL terminated string, or %NULL for invalid
1440 *
1441 * Since: 0.5.4
1442 **/
1443 gchar *
1444 dfu_firmware_to_string (DfuFirmware *firmware)
1445 {
1446 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
1447 DfuImage *image;
1448 GList *l;
1449 GString *str;
1450 guint i;
1451 g_autoptr(GList) keys = NULL;
1452
1453 g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), NULL);
1454
1455 str = g_string_new ("");
1456 g_string_append_printf (str, "vid: 0x%04x\n", priv->vid);
1457 g_string_append_printf (str, "pid: 0x%04x\n", priv->pid);
1458 g_string_append_printf (str, "release: 0x%04x\n", priv->release);
1459 g_string_append_printf (str, "crc: 0x%08x\n", priv->crc);
1460 g_string_append_printf (str, "format: %s [0x%04x]\n",
1461 dfu_firmware_format_to_string (priv->format),
1462 priv->format);
1463 g_string_append_printf (str, "cipher: %s\n",
1464 dfu_cipher_kind_to_string (priv->cipher_kind));
1465
1466 /* print metadata */
1467 keys = g_hash_table_get_keys (priv->metadata);
1468 for (l = keys; l != NULL; l = l->next) {
1469 const gchar *key;
1470 const gchar *value;
1471 key = l->data;
1472 value = g_hash_table_lookup (priv->metadata, key);
1473 g_string_append_printf (str, "metadata: %s=%s\n", key, value);
1474 }
1475
1476 /* print images */
1477 for (i = 0; i < priv->images->len; i++) {
1478 g_autofree gchar *tmp = NULL;
1479 image = g_ptr_array_index (priv->images, i);
1480 tmp = dfu_image_to_string (image);
1481 g_string_append_printf (str, "= IMAGE %i =\n", i);
1482 g_string_append_printf (str, "%s\n", tmp);
1483 }
1484
1485 g_string_truncate (str, str->len - 1);
1486 return g_string_free (str, FALSE);
1487 }
1488
1489 /**
1490 * dfu_firmware_format_to_string:
1491 * @format: a #DfuFirmwareFormat, e.g. %DFU_FIRMWARE_FORMAT_DFU_1_0
1492 *
1493 * Returns a string representaiton of the format.
1494 *
1495 * Return value: NULL terminated string, or %NULL for invalid
1496 *
1497 * Since: 0.5.4
1498 **/
1499 const gchar *
1500 dfu_firmware_format_to_string (DfuFirmwareFormat format)
1501 {
1502 if (format == DFU_FIRMWARE_FORMAT_RAW)
1503 return "RAW";
1504 if (format == DFU_FIRMWARE_FORMAT_DFU_1_0)
1505 return "DFU";
1506 if (format == DFU_FIRMWARE_FORMAT_DFUSE)
1507 return "DfuSe";
1508 if (format == DFU_FIRMWARE_FORMAT_INTEL_HEX)
1509 return "IHEX";
1510 return NULL;
1511 }
1512
1513 /**
1514 * dfu_firmware_get_cipher_kind:
1515 * @firmware: a #DfuFirmware
1516 *
1517 * Returns the kind of cipher used by the firmware file.
1518 *
1519 * NOTE: this value is based on a heuristic, and may not be accurate.
1520 * The value %DFU_CIPHER_KIND_NONE will be returned when the cipher
1521 * is not recognised.
1522 *
1523 * Return value: NULL terminated string, or %NULL for invalid
1524 *
1525 * Since: 0.5.4
1526 **/
1527 DfuCipherKind
1528 dfu_firmware_get_cipher_kind (DfuFirmware *firmware)
1529 {
1530 DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
1531 g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), 0);
1532 return priv->cipher_kind;
1533 }
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #ifndef __DFU_FIRMWARE_H
22 #define __DFU_FIRMWARE_H
23
24 #include <glib-object.h>
25 #include <gio/gio.h>
26
27 #include "dfu-common.h"
28 #include "dfu-image.h"
29
30 G_BEGIN_DECLS
31
32 #define DFU_TYPE_FIRMWARE (dfu_firmware_get_type ())
33 G_DECLARE_DERIVABLE_TYPE (DfuFirmware, dfu_firmware, DFU, FIRMWARE, GObject)
34
35 struct _DfuFirmwareClass
36 {
37 GObjectClass parent_class;
38 /*< private >*/
39 /* Padding for future expansion */
40 void (*_dfu_firmware_reserved1) (void);
41 void (*_dfu_firmware_reserved2) (void);
42 void (*_dfu_firmware_reserved3) (void);
43 void (*_dfu_firmware_reserved4) (void);
44 void (*_dfu_firmware_reserved5) (void);
45 void (*_dfu_firmware_reserved6) (void);
46 void (*_dfu_firmware_reserved7) (void);
47 void (*_dfu_firmware_reserved8) (void);
48 void (*_dfu_firmware_reserved9) (void);
49 };
50
51 /**
52 * DfuFirmwareParseFlags:
53 * @DFU_FIRMWARE_PARSE_FLAG_NONE: No flags set
54 * @DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST: Do not verify the CRC
55 * @DFU_FIRMWARE_PARSE_FLAG_NO_VERSION_TEST: Do not verify the DFU version
56 * @DFU_FIRMWARE_PARSE_FLAG_NO_METADATA: Do not read the metadata table
57 *
58 * The optional flags used for parsing.
59 **/
60 typedef enum {
61 DFU_FIRMWARE_PARSE_FLAG_NONE = 0,
62 DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST = (1 << 0),
63 DFU_FIRMWARE_PARSE_FLAG_NO_VERSION_TEST = (1 << 1),
64 DFU_FIRMWARE_PARSE_FLAG_NO_METADATA = (1 << 2),
65 /*< private >*/
66 DFU_FIRMWARE_PARSE_FLAG_LAST,
67 } DfuFirmwareParseFlags;
68
69 /**
70 * DfuFirmwareFormat:
71 * @DFU_FIRMWARE_FORMAT_UNKNOWN: Format unknown
72 * @DFU_FIRMWARE_FORMAT_RAW: Raw format
73 * @DFU_FIRMWARE_FORMAT_DFU_1_0: DFU 1.0
74 * @DFU_FIRMWARE_FORMAT_DFUSE: DfuSe extension
75 * @DFU_FIRMWARE_FORMAT_INTEL_HEX: Intel HEX
76 *
77 * The known versions of the DFU standard in BCD format.
78 **/
79 typedef enum {
80 DFU_FIRMWARE_FORMAT_UNKNOWN = 0,
81 DFU_FIRMWARE_FORMAT_RAW = 0x0001,
82 DFU_FIRMWARE_FORMAT_DFU_1_0 = 0x0100,
83 DFU_FIRMWARE_FORMAT_DFUSE = 0x011a,
84 DFU_FIRMWARE_FORMAT_INTEL_HEX = 0x0002,
85 /*< private >*/
86 DFU_FIRMWARE_FORMAT_LAST,
87 } DfuFirmwareFormat;
88
89 DfuFirmware *dfu_firmware_new (void);
90
91 const gchar *dfu_firmware_format_to_string (DfuFirmwareFormat format);
92
93 DfuImage *dfu_firmware_get_image (DfuFirmware *firmware,
94 guint8 alt_setting);
95 DfuImage *dfu_firmware_get_image_by_name (DfuFirmware *firmware,
96 const gchar *name);
97 DfuImage *dfu_firmware_get_image_default (DfuFirmware *firmware);
98 GPtrArray *dfu_firmware_get_images (DfuFirmware *firmware);
99 guint16 dfu_firmware_get_vid (DfuFirmware *firmware);
100 guint16 dfu_firmware_get_pid (DfuFirmware *firmware);
101 guint16 dfu_firmware_get_release (DfuFirmware *firmware);
102 guint16 dfu_firmware_get_format (DfuFirmware *firmware);
103 guint32 dfu_firmware_get_size (DfuFirmware *firmware);
104 DfuCipherKind dfu_firmware_get_cipher_kind (DfuFirmware *firmware);
105
106 void dfu_firmware_add_image (DfuFirmware *firmware,
107 DfuImage *image);
108 void dfu_firmware_set_vid (DfuFirmware *firmware,
109 guint16 vid);
110 void dfu_firmware_set_pid (DfuFirmware *firmware,
111 guint16 pid);
112 void dfu_firmware_set_release (DfuFirmware *firmware,
113 guint16 release);
114 void dfu_firmware_set_format (DfuFirmware *firmware,
115 DfuFirmwareFormat format);
116
117 gboolean dfu_firmware_parse_data (DfuFirmware *firmware,
118 GBytes *bytes,
119 DfuFirmwareParseFlags flags,
120 GError **error);
121 gboolean dfu_firmware_parse_file (DfuFirmware *firmware,
122 GFile *file,
123 DfuFirmwareParseFlags flags,
124 GCancellable *cancellable,
125 GError **error);
126
127 GBytes *dfu_firmware_write_data (DfuFirmware *firmware,
128 GError **error);
129 gboolean dfu_firmware_write_file (DfuFirmware *firmware,
130 GFile *file,
131 GCancellable *cancellable,
132 GError **error);
133 gchar *dfu_firmware_to_string (DfuFirmware *firmware);
134
135 const gchar *dfu_firmware_get_metadata (DfuFirmware *firmware,
136 const gchar *key);
137 void dfu_firmware_set_metadata (DfuFirmware *firmware,
138 const gchar *key,
139 const gchar *value);
140 void dfu_firmware_remove_metadata (DfuFirmware *firmware,
141 const gchar *key);
142
143 G_END_DECLS
144
145 #endif /* __DFU_FIRMWARE_H */
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #ifndef __DFU_IMAGE_PRIVATE_H
22 #define __DFU_IMAGE_PRIVATE_H
23
24 #include "dfu-image.h"
25
26 G_BEGIN_DECLS
27
28 DfuImage *dfu_image_from_dfuse (const guint8 *data,
29 guint32 length,
30 guint32 *consumed,
31 GError **error);
32 GBytes *dfu_image_to_dfuse (DfuImage *image);
33
34 G_END_DECLS
35
36 #endif /* __DFU_IMAGE_PRIVATE_H */
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /**
22 * SECTION:dfu-image
23 * @short_description: Object representing a a firmware image
24 *
25 * A #DfuImage is typically made up of several #DfuElements, although
26 * typically there will only be one.
27 *
28 * See also: #DfuElement
29 */
30
31 #include "config.h"
32
33 #include <string.h>
34 #include <stdio.h>
35
36 #include "dfu-common.h"
37 #include "dfu-element-private.h"
38 #include "dfu-error.h"
39 #include "dfu-image-private.h"
40
41 static void dfu_image_finalize (GObject *object);
42
43 /**
44 * DfuImagePrivate:
45 *
46 * Private #DfuImage data
47 **/
48 typedef struct {
49 GPtrArray *elements;
50 gchar name[255];
51 guint8 alt_setting;
52 } DfuImagePrivate;
53
54 G_DEFINE_TYPE_WITH_PRIVATE (DfuImage, dfu_image, G_TYPE_OBJECT)
55 #define GET_PRIVATE(o) (dfu_image_get_instance_private (o))
56
57 /**
58 * dfu_image_class_init:
59 **/
60 static void
61 dfu_image_class_init (DfuImageClass *klass)
62 {
63 GObjectClass *object_class = G_OBJECT_CLASS (klass);
64 object_class->finalize = dfu_image_finalize;
65 }
66
67 /**
68 * dfu_image_init:
69 **/
70 static void
71 dfu_image_init (DfuImage *image)
72 {
73 DfuImagePrivate *priv = GET_PRIVATE (image);
74 priv->elements = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
75 memset (priv->name, 0x00, 255);
76 }
77
78 /**
79 * dfu_image_finalize:
80 **/
81 static void
82 dfu_image_finalize (GObject *object)
83 {
84 DfuImage *image = DFU_IMAGE (object);
85 DfuImagePrivate *priv = GET_PRIVATE (image);
86
87 g_ptr_array_unref (priv->elements);
88
89 G_OBJECT_CLASS (dfu_image_parent_class)->finalize (object);
90 }
91
92 /**
93 * dfu_image_new:
94 *
95 * Creates a new DFU image object.
96 *
97 * Return value: a new #DfuImage
98 *
99 * Since: 0.5.4
100 **/
101 DfuImage *
102 dfu_image_new (void)
103 {
104 DfuImage *image;
105 image = g_object_new (DFU_TYPE_IMAGE, NULL);
106 return image;
107 }
108
109 /**
110 * dfu_image_get_elements:
111 * @image: a #DfuImage
112 *
113 * Gets the element data.
114 *
115 * Return value: (transfer none) (element-type DfuElement): element data
116 *
117 * Since: 0.5.4
118 **/
119 GPtrArray *
120 dfu_image_get_elements (DfuImage *image)
121 {
122 DfuImagePrivate *priv = GET_PRIVATE (image);
123 g_return_val_if_fail (DFU_IS_IMAGE (image), NULL);
124 return priv->elements;
125 }
126
127 /**
128 * dfu_image_get_element:
129 * @image: a #DfuImage
130 * @idx: an array index
131 *
132 * Gets the element.
133 *
134 * Return value: (transfer none): element data, or %NULL for invalid
135 *
136 * Since: 0.5.4
137 **/
138 DfuElement *
139 dfu_image_get_element (DfuImage *image, guint8 idx)
140 {
141 DfuImagePrivate *priv = GET_PRIVATE (image);
142 g_return_val_if_fail (DFU_IS_IMAGE (image), NULL);
143 if (idx >= priv->elements->len)
144 return NULL;
145 return g_ptr_array_index (priv->elements, idx);
146 }
147
148 /**
149 * dfu_image_get_alt_setting:
150 * @image: a #DfuImage
151 *
152 * Gets the alternate setting.
153 *
154 * Return value: integer, or 0x00 for unset
155 *
156 * Since: 0.5.4
157 **/
158 guint8
159 dfu_image_get_alt_setting (DfuImage *image)
160 {
161 DfuImagePrivate *priv = GET_PRIVATE (image);
162 g_return_val_if_fail (DFU_IS_IMAGE (image), 0xff);
163 return priv->alt_setting;
164 }
165
166 /**
167 * dfu_image_get_name:
168 * @image: a #DfuImage
169 *
170 * Gets the target name.
171 *
172 * Return value: a string, or %NULL for unset
173 *
174 * Since: 0.5.4
175 **/
176 const gchar *
177 dfu_image_get_name (DfuImage *image)
178 {
179 DfuImagePrivate *priv = GET_PRIVATE (image);
180 g_return_val_if_fail (DFU_IS_IMAGE (image), NULL);
181 return priv->name;
182 }
183
184 /**
185 * dfu_image_get_size:
186 * @image: a #DfuImage
187 *
188 * Gets the size of all the elements in the image.
189 *
190 * This only returns actual data that would be sent to the device and
191 * does not include any padding.
192 *
193 * Return value: a integer value, or 0 if there are no elements.
194 *
195 * Since: 0.5.4
196 **/
197 guint32
198 dfu_image_get_size (DfuImage *image)
199 {
200 DfuImagePrivate *priv = GET_PRIVATE (image);
201 guint32 length = 0;
202 guint i;
203 g_return_val_if_fail (DFU_IS_IMAGE (image), 0);
204 for (i = 0; i < priv->elements->len; i++) {
205 DfuElement *element = g_ptr_array_index (priv->elements, i);
206 length += g_bytes_get_size (dfu_element_get_contents (element));
207 }
208 return length;
209 }
210
211 /**
212 * dfu_image_add_element:
213 * @image: a #DfuImage
214 * @element: a #DfuElement
215 *
216 * Adds an element to the image.
217 *
218 * Since: 0.5.4
219 **/
220 void
221 dfu_image_add_element (DfuImage *image, DfuElement *element)
222 {
223 DfuImagePrivate *priv = GET_PRIVATE (image);
224 g_return_if_fail (DFU_IS_IMAGE (image));
225 g_return_if_fail (DFU_IS_ELEMENT (element));
226 g_ptr_array_add (priv->elements, g_object_ref (element));
227 }
228
229 /**
230 * dfu_image_set_alt_setting:
231 * @image: a #DfuImage
232 * @alt_setting: vendor ID, or 0xffff for unset
233 *
234 * Sets the vendor ID.
235 *
236 * Since: 0.5.4
237 **/
238 void
239 dfu_image_set_alt_setting (DfuImage *image, guint8 alt_setting)
240 {
241 DfuImagePrivate *priv = GET_PRIVATE (image);
242 g_return_if_fail (DFU_IS_IMAGE (image));
243 priv->alt_setting = alt_setting;
244 }
245
246 /**
247 * dfu_image_set_name:
248 * @image: a #DfuImage
249 * @name: a target string, or %NULL
250 *
251 * Sets the target name.
252 *
253 * Since: 0.5.4
254 **/
255 void
256 dfu_image_set_name (DfuImage *image, const gchar *name)
257 {
258 guint16 sz;
259 DfuImagePrivate *priv = GET_PRIVATE (image);
260 g_return_if_fail (DFU_IS_IMAGE (image));
261
262 /* this is a hard limit in DfuSe */
263 memset (priv->name, 0x00, 0xff);
264 if (name != NULL) {
265 sz = MIN (strlen (name), 0xff - 1);
266 memcpy (priv->name, name, sz);
267 }
268 }
269
270 /**
271 * dfu_image_to_string:
272 * @image: a #DfuImage
273 *
274 * Returns a string representaiton of the object.
275 *
276 * Return value: NULL terminated string, or %NULL for invalid
277 *
278 * Since: 0.5.4
279 **/
280 gchar *
281 dfu_image_to_string (DfuImage *image)
282 {
283 DfuImagePrivate *priv = GET_PRIVATE (image);
284 GString *str;
285 guint i;
286
287 g_return_val_if_fail (DFU_IS_IMAGE (image), NULL);
288
289 str = g_string_new ("");
290 g_string_append_printf (str, "alt_setting: 0x%02x\n", priv->alt_setting);
291 if (priv->name[0] != '\0')
292 g_string_append_printf (str, "name: %s\n", priv->name);
293 g_string_append_printf (str, "elements: 0x%02x\n",
294 priv->elements->len);
295
296 /* add elements */
297 for (i = 0; i < priv->elements->len; i++) {
298 DfuElement *element = g_ptr_array_index (priv->elements, i);
299 g_autofree gchar *tmp = NULL;
300 tmp = dfu_element_to_string (element);
301 g_string_append_printf (str, "== ELEMENT %i ==\n", i);
302 g_string_append_printf (str, "%s\n", tmp);
303 }
304
305 g_string_truncate (str, str->len - 1);
306 return g_string_free (str, FALSE);
307 }
308
309 /* DfuSe image header */
310 typedef struct __attribute__((packed)) {
311 guint8 sig[6];
312 guint8 alt_setting;
313 guint32 target_named;
314 gchar target_name[255];
315 guint32 target_size;
316 guint32 elements;
317 } DfuSeImagePrefix;
318
319 /**
320 * dfu_image_from_dfuse: (skip)
321 * @data: data buffer
322 * @length: length of @data we can access
323 * @consumed: (out): the number of bytes we consued
324 * @error: a #GError, or %NULL
325 *
326 * Unpacks an image from DfuSe data.
327 *
328 * Returns: a #DfuImage, or %NULL for error
329 **/
330 DfuImage *
331 dfu_image_from_dfuse (const guint8 *data,
332 guint32 length,
333 guint32 *consumed,
334 GError **error)
335 {
336 DfuImagePrivate *priv;
337 DfuSeImagePrefix *im;
338 guint32 offset = sizeof(DfuSeImagePrefix);
339 guint j;
340 g_autoptr(DfuImage) image = NULL;
341
342 g_assert_cmpint(sizeof(DfuSeImagePrefix), ==, 274);
343
344 /* check input buffer size */
345 if (length < sizeof(DfuSeImagePrefix)) {
346 g_set_error (error,
347 DFU_ERROR,
348 DFU_ERROR_INTERNAL,
349 "invalid image data size %u",
350 (guint32) length);
351 return NULL;
352 }
353
354 /* verify image signature */
355 im = (DfuSeImagePrefix *) data;
356 if (memcmp (im->sig, "Target", 6) != 0) {
357 g_set_error_literal (error,
358 DFU_ERROR,
359 DFU_ERROR_INVALID_FILE,
360 "invalid DfuSe target signature");
361 return NULL;
362 }
363
364 /* create new image */
365 image = dfu_image_new ();
366 priv = GET_PRIVATE (image);
367 priv->alt_setting = im->alt_setting;
368 if (im->target_named == 0x01)
369 memcpy (priv->name, im->target_name, 255);
370
371 /* parse elements */
372 length -= offset;
373 for (j = 0; j < im->elements; j++) {
374 guint32 consumed_local;
375 g_autoptr(DfuElement) element = NULL;
376 element = dfu_element_from_dfuse (data + offset, length,
377 &consumed_local, error);
378 if (element == NULL)
379 return NULL;
380 dfu_image_add_element (image, element);
381 offset += consumed_local;
382 length -= consumed_local;
383 }
384
385 /* return size */
386 if (consumed != NULL)
387 *consumed = offset;
388
389 return g_object_ref (image);
390 }
391
392 /**
393 * dfu_image_to_dfuse: (skip)
394 * @image: a #DfuImage
395 *
396 * Packs a DfuSe image
397 *
398 * Returns: (transfer full): the packed data
399 **/
400 GBytes *
401 dfu_image_to_dfuse (DfuImage *image)
402 {
403 DfuImagePrivate *priv = GET_PRIVATE (image);
404 DfuElement *element;
405 DfuSeImagePrefix *im;
406 GBytes *bytes;
407 guint32 length_total = 0;
408 guint32 offset = sizeof (DfuSeImagePrefix);
409 guint8 *buf;
410 guint i;
411 g_autoptr(GPtrArray) element_array = NULL;
412
413 /* get total size */
414 element_array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref);
415 for (i = 0; i < priv->elements->len; i++) {
416 element = g_ptr_array_index (priv->elements, i);
417 bytes = dfu_element_to_dfuse (element);
418 g_ptr_array_add (element_array, bytes);
419 length_total += g_bytes_get_size (bytes);
420 }
421
422 /* add prefix */
423 buf = g_malloc0 (length_total + sizeof (DfuSeImagePrefix));
424 im = (DfuSeImagePrefix *) buf;
425 memcpy (im->sig, "Target", 6);
426 im->alt_setting = priv->alt_setting;
427 if (priv->name != NULL) {
428 im->target_named = 0x01;
429 memcpy (im->target_name, priv->name, 255);
430 }
431 im->target_size = length_total;
432 im->elements = priv->elements->len;
433
434 /* copy data */
435 for (i = 0; i < element_array->len; i++) {
436 const guint8 *data;
437 gsize length;
438 bytes = g_ptr_array_index (element_array, i);
439 data = g_bytes_get_data (bytes, &length);
440 memcpy (buf + offset, data, length);
441 offset += length;
442 }
443 return g_bytes_new_take (buf, length_total + sizeof (DfuSeImagePrefix));
444 }
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #ifndef __DFU_IMAGE_H
22 #define __DFU_IMAGE_H
23
24 #include <glib-object.h>
25 #include <gio/gio.h>
26
27 #include "dfu-element.h"
28
29 G_BEGIN_DECLS
30
31 #define DFU_TYPE_IMAGE (dfu_image_get_type ())
32 G_DECLARE_DERIVABLE_TYPE (DfuImage, dfu_image, DFU, IMAGE, GObject)
33
34 struct _DfuImageClass
35 {
36 GObjectClass parent_class;
37 /*< private >*/
38 /* Padding for future expansion */
39 void (*_dfu_image_reserved1) (void);
40 void (*_dfu_image_reserved2) (void);
41 void (*_dfu_image_reserved3) (void);
42 void (*_dfu_image_reserved4) (void);
43 void (*_dfu_image_reserved5) (void);
44 void (*_dfu_image_reserved6) (void);
45 void (*_dfu_image_reserved7) (void);
46 void (*_dfu_image_reserved8) (void);
47 void (*_dfu_image_reserved9) (void);
48 };
49
50 DfuImage *dfu_image_new (void);
51
52 GPtrArray *dfu_image_get_elements (DfuImage *image);
53 DfuElement *dfu_image_get_element (DfuImage *image,
54 guint8 idx);
55 guint8 dfu_image_get_alt_setting (DfuImage *image);
56 const gchar *dfu_image_get_name (DfuImage *image);
57 guint32 dfu_image_get_size (DfuImage *image);
58
59 void dfu_image_add_element (DfuImage *image,
60 DfuElement *element);
61
62 void dfu_image_set_alt_setting (DfuImage *image,
63 guint8 alt_setting);
64 void dfu_image_set_name (DfuImage *image,
65 const gchar *name);
66
67 gchar *dfu_image_to_string (DfuImage *image);
68
69 G_END_DECLS
70
71 #endif /* __DFU_IMAGE_H */
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #ifndef __DFU_SECTOR_PRIVATE_H
22 #define __DFU_SECTOR_PRIVATE_H
23
24 #include "dfu-sector.h"
25
26 G_BEGIN_DECLS
27
28 DfuSector *dfu_sector_new (guint32 address,
29 guint32 size,
30 guint32 size_left,
31 guint16 zone,
32 guint16 number,
33 DfuSectorCap cap);
34
35 G_END_DECLS
36
37 #endif /* __DFU_SECTOR_PRIVATE_H */
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /**
22 * SECTION:dfu-sector
23 * @short_description: Object representing a sector on a chip
24 *
25 * This object represents an sector of memory at a specific address on the
26 * device itself.
27 *
28 * This allows relocatable data segments to be stored in different
29 * locations on the device itself.
30 *
31 * You can think of these objects as flash segments on devices, where a
32 * complete block can be erased and then written to.
33 *
34 * See also: #DfuElement
35 */
36
37 #include "config.h"
38
39 #include <string.h>
40 #include <stdio.h>
41
42 #include "dfu-common.h"
43 #include "dfu-sector-private.h"
44
45 /**
46 * DfuSectorPrivate:
47 *
48 * Private #DfuSector data
49 **/
50 typedef struct {
51 guint32 address;
52 guint32 size;
53 guint32 size_left;
54 guint16 zone;
55 guint16 number;
56 DfuSectorCap cap;
57 } DfuSectorPrivate;
58
59 G_DEFINE_TYPE_WITH_PRIVATE (DfuSector, dfu_sector, G_TYPE_OBJECT)
60 #define GET_PRIVATE(o) (dfu_sector_get_instance_private (o))
61
62 /**
63 * dfu_sector_class_init:
64 **/
65 static void
66 dfu_sector_class_init (DfuSectorClass *klass)
67 {
68 }
69
70 /**
71 * dfu_sector_init:
72 **/
73 static void
74 dfu_sector_init (DfuSector *sector)
75 {
76 }
77
78 /**
79 * dfu_sector_new: (skip)
80 * address: the address for the sector
81 * size: the size of this sector
82 * size_left: the size of the rest of the sector
83 * zone: the zone of memory the setor belongs
84 * number: the sector number in the zone
85 * cap: the #DfuSectorCap
86 *
87 * Creates a new DFU sector object.
88 *
89 * Return value: a new #DfuSector
90 *
91 * Since: 0.5.4
92 **/
93 DfuSector *
94 dfu_sector_new (guint32 address, guint32 size, guint32 size_left,
95 guint16 zone, guint16 number, DfuSectorCap cap)
96 {
97 DfuSectorPrivate *priv;
98 DfuSector *sector;
99 sector = g_object_new (DFU_TYPE_SECTOR, NULL);
100 priv = GET_PRIVATE (sector);
101 priv->address = address;
102 priv->size = size;
103 priv->size_left = size_left;
104 priv->zone = zone;
105 priv->number = number;
106 priv->cap = cap;
107 return sector;
108 }
109
110 /**
111 * dfu_sector_get_address:
112 * @sector: a #DfuSector
113 *
114 * Gets the alternate setting.
115 *
116 * Return value: integer, or 0x00 for unset
117 *
118 * Since: 0.5.4
119 **/
120 guint32
121 dfu_sector_get_address (DfuSector *sector)
122 {
123 DfuSectorPrivate *priv = GET_PRIVATE (sector);
124 g_return_val_if_fail (DFU_IS_SECTOR (sector), 0x00);
125 return priv->address;
126 }
127
128 /**
129 * dfu_sector_get_size:
130 * @sector: a #DfuSector
131 *
132 * Gets the alternate setting.
133 *
134 * Return value: integer, or 0x00 for unset
135 *
136 * Since: 0.5.4
137 **/
138 guint32
139 dfu_sector_get_size (DfuSector *sector)
140 {
141 DfuSectorPrivate *priv = GET_PRIVATE (sector);
142 g_return_val_if_fail (DFU_IS_SECTOR (sector), 0x00);
143 return priv->size;
144 }
145
146 /**
147 * dfu_sector_get_size_left:
148 * @sector: a #DfuSector
149 *
150 * Gets the alternate setting.
151 *
152 * Return value: integer, or 0x00 for unset
153 *
154 * Since: 0.5.4
155 **/
156 guint32
157 dfu_sector_get_size_left (DfuSector *sector)
158 {
159 DfuSectorPrivate *priv = GET_PRIVATE (sector);
160 g_return_val_if_fail (DFU_IS_SECTOR (sector), 0x00);
161 return priv->size_left;
162 }
163
164 /**
165 * dfu_sector_get_id:
166 * @sector: a #DfuSector
167 *
168 * Gets the sector ID which is a combination of the zone and sector number.
169 * You can use this number to check if the segment is the 'same' as the last
170 * written or read sector.
171 *
172 * Return value: integer ID, or 0x00 for unset
173 *
174 * Since: 0.5.4
175 **/
176 guint32
177 dfu_sector_get_id (DfuSector *sector)
178 {
179 DfuSectorPrivate *priv = GET_PRIVATE (sector);
180 g_return_val_if_fail (DFU_IS_SECTOR (sector), 0x00);
181 return (((guint32) priv->zone) << 16) | priv->number;
182 }
183
184 /**
185 * dfu_sector_has_cap:
186 * @sector: a #DfuSector
187 * @cap: a #DfuSectorCap, e.g. %DFU_SECTOR_CAP_ERASEABLE
188 *
189 * Finds out if the sector has the required capability.
190 *
191 * Return value: %TRUE if the sector has the capabilily
192 *
193 * Since: 0.5.4
194 **/
195 gboolean
196 dfu_sector_has_cap (DfuSector *sector, DfuSectorCap cap)
197 {
198 DfuSectorPrivate *priv = GET_PRIVATE (sector);
199 g_return_val_if_fail (DFU_IS_SECTOR (sector), FALSE);
200 return priv->cap & cap;
201 }
202
203 /**
204 * dfu_sector_to_string:
205 * @sector: a #DfuSector
206 *
207 * Returns a string representaiton of the object.
208 *
209 * Return value: NULL terminated string, or %NULL for invalid
210 *
211 * Since: 0.5.4
212 **/
213 gchar *
214 dfu_sector_to_string (DfuSector *sector)
215 {
216 DfuSectorPrivate *priv = GET_PRIVATE (sector);
217 GString *str;
218
219 g_return_val_if_fail (DFU_IS_SECTOR (sector), NULL);
220
221 str = g_string_new ("");
222 g_string_append_printf (str,
223 "Zone:%i, Sec#:%i, Addr:0x%08x, "
224 "Size:0x%04x, Caps:0x%01x",
225 priv->zone, priv->number, priv->address,
226 priv->size, priv->cap);
227 return g_string_free (str, FALSE);
228 }
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #ifndef __DFU_SECTOR_H
22 #define __DFU_SECTOR_H
23
24 #include <glib-object.h>
25 #include <gio/gio.h>
26
27 G_BEGIN_DECLS
28
29 #define DFU_TYPE_SECTOR (dfu_sector_get_type ())
30 G_DECLARE_DERIVABLE_TYPE (DfuSector, dfu_sector, DFU, SECTOR, GObject)
31
32 struct _DfuSectorClass
33 {
34 GObjectClass parent_class;
35 /*< private >*/
36 /* Padding for future expansion */
37 void (*_dfu_sector_reserved1) (void);
38 void (*_dfu_sector_reserved2) (void);
39 void (*_dfu_sector_reserved3) (void);
40 void (*_dfu_sector_reserved4) (void);
41 void (*_dfu_sector_reserved5) (void);
42 void (*_dfu_sector_reserved6) (void);
43 void (*_dfu_sector_reserved7) (void);
44 void (*_dfu_sector_reserved8) (void);
45 void (*_dfu_sector_reserved9) (void);
46 };
47
48 /**
49 * DfuSectorCap:
50 * @DFU_SECTOR_CAP_NONE: No operations possible
51 * @DFU_SECTOR_CAP_READABLE: Sector can be read
52 * @DFU_SECTOR_CAP_WRITEABLE: Sector can be written
53 * @DFU_SECTOR_CAP_ERASEABLE: Sector can be erased
54 *
55 * The flags indicating what the sector can do.
56 **/
57 typedef enum {
58 DFU_SECTOR_CAP_NONE = 0,
59 DFU_SECTOR_CAP_READABLE = 1 << 0,
60 DFU_SECTOR_CAP_WRITEABLE = 1 << 1,
61 DFU_SECTOR_CAP_ERASEABLE = 1 << 2,
62 /*< private >*/
63 DFU_SECTOR_CAP_LAST
64 } DfuSectorCap;
65
66 guint32 dfu_sector_get_id (DfuSector *sector);
67 guint32 dfu_sector_get_address (DfuSector *sector);
68 guint32 dfu_sector_get_size (DfuSector *sector);
69 guint32 dfu_sector_get_size_left (DfuSector *sector);
70 gboolean dfu_sector_has_cap (DfuSector *sector,
71 DfuSectorCap cap);
72 gchar *dfu_sector_to_string (DfuSector *sector);
73
74 G_END_DECLS
75
76 #endif /* __DFU_SECTOR_H */
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU General Public License Version 2
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "config.h"
22
23 #include <glib-object.h>
24 #include <stdlib.h>
25
26 #include "dfu-common.h"
27 #include "dfu-context.h"
28 #include "dfu-device.h"
29 #include "dfu-error.h"
30 #include "dfu-firmware.h"
31 #include "dfu-sector-private.h"
32 #include "dfu-target-private.h"
33
34 /**
35 * dfu_test_get_filename:
36 **/
37 static gchar *
38 dfu_test_get_filename (const gchar *filename)
39 {
40 gchar *tmp;
41 char full_tmp[PATH_MAX];
42 g_autofree gchar *path = NULL;
43 path = g_build_filename (TESTDATADIR, filename, NULL);
44 tmp = realpath (path, full_tmp);
45 if (tmp == NULL)
46 return NULL;
47 return g_strdup (full_tmp);
48 }
49
50 /**
51 * _g_bytes_compare_verbose:
52 **/
53 static gchar *
54 _g_bytes_compare_verbose (GBytes *bytes1, GBytes *bytes2)
55 {
56 const guint8 *data1;
57 const guint8 *data2;
58 gsize length1;
59 gsize length2;
60 guint i;
61
62 data1 = g_bytes_get_data (bytes1, &length1);
63 data2 = g_bytes_get_data (bytes2, &length2);
64
65 /* not the same length */
66 if (length1 != length2) {
67 return g_strdup_printf ("got %" G_GSIZE_FORMAT " bytes, "
68 "expected %" G_GSIZE_FORMAT,
69 length1, length2);
70 }
71
72 /* return 00 01 02 03 */
73 for (i = 0; i < length1; i++) {
74 if (data1[i] != data2[i]) {
75 return g_strdup_printf ("got 0x%02x, expected 0x%02x @ 0x%04x",
76 data1[i], data2[i], i);
77 }
78 }
79 return NULL;
80 }
81
82 static void
83 dfu_firmware_xdfu_func (void)
84 {
85 gboolean ret;
86 g_autofree gchar *fn = NULL;
87 g_autoptr(DfuFirmware) firmware = NULL;
88 g_autoptr(GError) error = NULL;
89 g_autoptr(GFile) file = NULL;
90
91 fn = dfu_test_get_filename ("example.xdfu");
92 g_assert (fn != NULL);
93 firmware = dfu_firmware_new ();
94 file = g_file_new_for_path (fn);
95 ret = dfu_firmware_parse_file (firmware, file,
96 DFU_FIRMWARE_PARSE_FLAG_NONE,
97 NULL, &error);
98 g_assert_no_error (error);
99 g_assert (ret);
100 g_assert_cmpint (dfu_firmware_get_cipher_kind (firmware), ==, DFU_CIPHER_KIND_XTEA);
101 }
102
103 static void
104 dfu_enums_func (void)
105 {
106 guint i;
107 for (i = 0; i < DFU_STATE_LAST; i++)
108 g_assert_cmpstr (dfu_state_to_string (i), !=, NULL);
109 for (i = 0; i < DFU_STATUS_LAST; i++)
110 g_assert_cmpstr (dfu_status_to_string (i), !=, NULL);
111 }
112
113 static GBytes *
114 dfu_self_test_get_bytes_for_file (GFile *file, GError **error)
115 {
116 gchar *contents = NULL;
117 gsize length = 0;
118 if (!g_file_load_contents (file, NULL, &contents, &length, NULL, error))
119 return NULL;
120 return g_bytes_new_take (contents, length);
121 }
122
123 static void
124 dfu_firmware_raw_func (void)
125 {
126 DfuElement *element;
127 DfuImage *image_tmp;
128 GBytes *no_suffix_contents;
129 gchar buf[256];
130 guint i;
131 gboolean ret;
132 g_autoptr(DfuFirmware) firmware = NULL;
133 g_autoptr(GBytes) fw = NULL;
134 g_autoptr(GBytes) roundtrip_orig = NULL;
135 g_autoptr(GBytes) roundtrip = NULL;
136 g_autoptr(GError) error = NULL;
137
138 /* set up some dummy data */
139 for (i = 0; i < 256; i++)
140 buf[i] = i;
141 fw = g_bytes_new_static (buf, 256);
142
143 /* load a non DFU firmware */
144 firmware = dfu_firmware_new ();
145 ret = dfu_firmware_parse_data (firmware, fw, DFU_FIRMWARE_PARSE_FLAG_NONE, &error);
146 g_assert_no_error (error);
147 g_assert (ret);
148 g_assert_cmpint (dfu_firmware_get_vid (firmware), ==, 0xffff);
149 g_assert_cmpint (dfu_firmware_get_pid (firmware), ==, 0xffff);
150 g_assert_cmpint (dfu_firmware_get_release (firmware), ==, 0xffff);
151 g_assert_cmpint (dfu_firmware_get_format (firmware), ==, DFU_FIRMWARE_FORMAT_RAW);
152 g_assert_cmpint (dfu_firmware_get_cipher_kind (firmware), ==, DFU_CIPHER_KIND_NONE);
153 image_tmp = dfu_firmware_get_image (firmware, 0xfe);
154 g_assert (image_tmp == NULL);
155 image_tmp = dfu_firmware_get_image (firmware, 0);
156 g_assert (image_tmp != NULL);
157 g_assert_cmpint (dfu_image_get_size (image_tmp), ==, 256);
158 element = dfu_image_get_element (image_tmp, 0);
159 g_assert (element != NULL);
160 no_suffix_contents = dfu_element_get_contents (element);
161 g_assert (no_suffix_contents != NULL);
162 g_assert_cmpint (g_bytes_compare (no_suffix_contents, fw), ==, 0);
163
164 /* can we roundtrip without adding data */
165 roundtrip = dfu_firmware_write_data (firmware, &error);
166 g_assert_no_error (error);
167 g_assert (roundtrip != NULL);
168 g_assert_cmpstr (_g_bytes_compare_verbose (roundtrip, fw), ==, NULL);
169 }
170
171 static void
172 dfu_firmware_dfu_func (void)
173 {
174 gchar buf[256];
175 guint i;
176 gboolean ret;
177 g_autofree gchar *filename = NULL;
178 g_autoptr(DfuFirmware) firmware = NULL;
179 g_autoptr(DfuImage) image = NULL;
180 g_autoptr(DfuElement) element = NULL;
181 g_autoptr(GBytes) data = NULL;
182 g_autoptr(GBytes) fw = NULL;
183 g_autoptr(GBytes) roundtrip_orig = NULL;
184 g_autoptr(GBytes) roundtrip = NULL;
185 g_autoptr(GError) error = NULL;
186 g_autoptr(GFile) file = NULL;
187
188 /* set up some dummy data */
189 for (i = 0; i < 256; i++)
190 buf[i] = i;
191 fw = g_bytes_new_static (buf, 256);
192
193 /* write DFU format */
194 firmware = dfu_firmware_new ();
195 dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_DFU_1_0);
196 dfu_firmware_set_vid (firmware, 0x1234);
197 dfu_firmware_set_pid (firmware, 0x5678);
198 dfu_firmware_set_release (firmware, 0xfedc);
199 image = dfu_image_new ();
200 element = dfu_element_new ();
201 dfu_element_set_contents (element, fw);
202 dfu_image_add_element (image, element);
203 dfu_firmware_add_image (firmware, image);
204 g_assert_cmpint (dfu_firmware_get_size (firmware), ==, 256);
205 data = dfu_firmware_write_data (firmware, &error);
206 g_assert_no_error (error);
207 g_assert (data != NULL);
208
209 /* can we load it again? */
210 g_ptr_array_set_size (dfu_firmware_get_images (firmware), 0);
211 ret = dfu_firmware_parse_data (firmware, data, DFU_FIRMWARE_PARSE_FLAG_NONE, &error);
212 g_assert_no_error (error);
213 g_assert (ret);
214 g_assert_cmpint (dfu_firmware_get_vid (firmware), ==, 0x1234);
215 g_assert_cmpint (dfu_firmware_get_pid (firmware), ==, 0x5678);
216 g_assert_cmpint (dfu_firmware_get_release (firmware), ==, 0xfedc);
217 g_assert_cmpint (dfu_firmware_get_format (firmware), ==, DFU_FIRMWARE_FORMAT_DFU_1_0);
218 g_assert_cmpint (dfu_firmware_get_size (firmware), ==, 256);
219
220 /* load a real firmware */
221 filename = dfu_test_get_filename ("kiibohd.dfu.bin");
222 g_assert (filename != NULL);
223 file = g_file_new_for_path (filename);
224 g_ptr_array_set_size (dfu_firmware_get_images (firmware), 0);
225 ret = dfu_firmware_parse_file (firmware, file,
226 DFU_FIRMWARE_PARSE_FLAG_NONE,
227 NULL, &error);
228 g_assert_no_error (error);
229 g_assert (ret);
230 g_assert_cmpint (dfu_firmware_get_vid (firmware), ==, 0x1c11);
231 g_assert_cmpint (dfu_firmware_get_pid (firmware), ==, 0xb007);
232 g_assert_cmpint (dfu_firmware_get_release (firmware), ==, 0xffff);
233 g_assert_cmpint (dfu_firmware_get_format (firmware), ==, DFU_FIRMWARE_FORMAT_DFU_1_0);
234 g_assert_cmpint (dfu_firmware_get_size (firmware), ==, 0x8eB4);
235 g_assert_cmpint (dfu_firmware_get_cipher_kind (firmware), ==, DFU_CIPHER_KIND_NONE);
236
237 /* can we roundtrip without loosing data */
238 roundtrip_orig = dfu_self_test_get_bytes_for_file (file, &error);
239 g_assert_no_error (error);
240 g_assert (roundtrip_orig != NULL);
241 roundtrip = dfu_firmware_write_data (firmware, &error);
242 g_assert_no_error (error);
243 g_assert (roundtrip != NULL);
244 g_assert_cmpstr (_g_bytes_compare_verbose (roundtrip, roundtrip_orig), ==, NULL);
245 }
246
247 static void
248 dfu_firmware_dfuse_func (void)
249 {
250 gboolean ret;
251 g_autofree gchar *filename = NULL;
252 g_autoptr(DfuFirmware) firmware = NULL;
253 g_autoptr(GBytes) roundtrip_orig = NULL;
254 g_autoptr(GBytes) roundtrip = NULL;
255 g_autoptr(GError) error = NULL;
256 g_autoptr(GFile) file = NULL;
257
258 /* load a DeFUse firmware */
259 filename = dfu_test_get_filename ("dev_VRBRAIN.dfu");
260 g_assert (filename != NULL);
261 file = g_file_new_for_path (filename);
262 firmware = dfu_firmware_new ();
263 ret = dfu_firmware_parse_file (firmware, file,
264 DFU_FIRMWARE_PARSE_FLAG_NONE,
265 NULL, &error);
266 g_assert_no_error (error);
267 g_assert (ret);
268 g_assert_cmpint (dfu_firmware_get_vid (firmware), ==, 0x0483);
269 g_assert_cmpint (dfu_firmware_get_pid (firmware), ==, 0x0000);
270 g_assert_cmpint (dfu_firmware_get_release (firmware), ==, 0x0000);
271 g_assert_cmpint (dfu_firmware_get_format (firmware), ==, DFU_FIRMWARE_FORMAT_DFUSE);
272 g_assert_cmpint (dfu_firmware_get_size (firmware), ==, 0x168d5);
273 g_assert_cmpint (dfu_firmware_get_cipher_kind (firmware), ==, DFU_CIPHER_KIND_NONE);
274
275 /* can we roundtrip without loosing data */
276 roundtrip_orig = dfu_self_test_get_bytes_for_file (file, &error);
277 g_assert_no_error (error);
278 g_assert (roundtrip_orig != NULL);
279 roundtrip = dfu_firmware_write_data (firmware, &error);
280 g_assert_no_error (error);
281 g_assert (roundtrip != NULL);
282
283 // g_file_set_contents ("/tmp/1.bin",
284 // g_bytes_get_data (roundtrip, NULL),
285 // g_bytes_get_size (roundtrip), NULL);
286
287 g_assert_cmpstr (_g_bytes_compare_verbose (roundtrip, roundtrip_orig), ==, NULL);
288 }
289
290 static void
291 dfu_firmware_metadata_func (void)
292 {
293 gboolean ret;
294 g_autofree gchar *filename = NULL;
295 g_autoptr(DfuFirmware) firmware = NULL;
296 g_autoptr(GBytes) roundtrip_orig = NULL;
297 g_autoptr(GBytes) roundtrip = NULL;
298 g_autoptr(GError) error = NULL;
299 g_autoptr(GFile) file = NULL;
300
301 /* load a DFU firmware with a metadata table */
302 filename = dfu_test_get_filename ("metadata.dfu");
303 g_assert (filename != NULL);
304 file = g_file_new_for_path (filename);
305 firmware = dfu_firmware_new ();
306 ret = dfu_firmware_parse_file (firmware, file,
307 DFU_FIRMWARE_PARSE_FLAG_NONE,
308 NULL, &error);
309 g_assert_no_error (error);
310 g_assert (ret);
311 g_assert_cmpint (dfu_firmware_get_size (firmware), ==, 6);
312 g_assert_cmpstr (dfu_firmware_get_metadata (firmware, "key"), ==, "value");
313 g_assert_cmpstr (dfu_firmware_get_metadata (firmware, "???"), ==, NULL);
314
315 /* can we roundtrip without loosing data */
316 roundtrip_orig = dfu_self_test_get_bytes_for_file (file, &error);
317 g_assert_no_error (error);
318 g_assert (roundtrip_orig != NULL);
319 roundtrip = dfu_firmware_write_data (firmware, &error);
320 g_assert_no_error (error);
321 g_assert (roundtrip != NULL);
322
323 g_assert_cmpstr (_g_bytes_compare_verbose (roundtrip, roundtrip_orig), ==, NULL);
324 }
325
326 static void
327 dfu_firmware_intel_hex_func (void)
328 {
329 const guint8 *data;
330 gboolean ret;
331 gsize len;
332 g_autofree gchar *filename_hex = NULL;
333 g_autofree gchar *filename_ref = NULL;
334 g_autofree gchar *str = NULL;
335 g_autoptr(DfuFirmware) firmware = NULL;
336 g_autoptr(GBytes) data_bin2 = NULL;
337 g_autoptr(GBytes) data_bin = NULL;
338 g_autoptr(GBytes) data_hex = NULL;
339 g_autoptr(GBytes) data_ref = NULL;
340 g_autoptr(GError) error = NULL;
341 g_autoptr(GFile) file_bin = NULL;
342 g_autoptr(GFile) file_hex = NULL;
343
344 /* load a Intel hex32 file */
345 filename_hex = dfu_test_get_filename ("firmware.hex");
346 g_assert (filename_hex != NULL);
347 file_hex = g_file_new_for_path (filename_hex);
348 firmware = dfu_firmware_new ();
349 ret = dfu_firmware_parse_file (firmware, file_hex,
350 DFU_FIRMWARE_PARSE_FLAG_NONE,
351 NULL, &error);
352 g_assert_no_error (error);
353 g_assert (ret);
354 g_assert_cmpint (dfu_firmware_get_size (firmware), ==, 136);
355 dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_RAW);
356 data_bin = dfu_firmware_write_data (firmware, &error);
357 g_assert_no_error (error);
358 g_assert (data_bin != NULL);
359
360 /* did we match the reference file? */
361 filename_ref = dfu_test_get_filename ("firmware.bin");
362 g_assert (filename_ref != NULL);
363 file_bin = g_file_new_for_path (filename_ref);
364 data_ref = dfu_self_test_get_bytes_for_file (file_bin, &error);
365 g_assert_no_error (error);
366 g_assert (data_ref != NULL);
367 g_assert_cmpstr (_g_bytes_compare_verbose (data_bin, data_ref), ==, NULL);
368
369 /* export a ihex file (which will be slightly different due to
370 * non-continous regions being expanded */
371 dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_INTEL_HEX);
372 data_hex = dfu_firmware_write_data (firmware, &error);
373 g_assert_no_error (error);
374 g_assert (data_hex != NULL);
375 data = g_bytes_get_data (data_hex, &len);
376 str = g_strndup ((const gchar *) data, len);
377 g_assert_cmpstr (str, ==,
378 ":104000003DEF20F000000000FACF01F0FBCF02F0AF\n"
379 ":10401000E9CF03F0EACF04F0E1CF05F0E2CF06F005\n"
380 ":10402000D9CF07F0DACF08F0F3CF09F0F4CF0AF021\n"
381 ":10403000F6CF0BF0F7CF0CF0F8CF0DF0F5CF0EF044\n"
382 ":104040000EC0F5FF0DC0F8FF0CC0F7FF0BC0F6FF45\n"
383 ":104050000AC0F4FF09C0F3FF08C0DAFF07C0D9FF24\n"
384 ":1040600006C0E2FF05C0E1FF04C0EAFF03C0E9FF0A\n"
385 ":1040700002C0FBFF01C0FAFF11003FEF20F00001BB\n"
386 ":0840800042EF20F03DEF20F037\n"
387 ":00000001FF\n");
388
389 /* do we match the binary file again */
390 dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_RAW);
391 data_bin2 = dfu_firmware_write_data (firmware, &error);
392 g_assert_no_error (error);
393 g_assert (data_bin2 != NULL);
394 g_assert_cmpstr (_g_bytes_compare_verbose (data_bin, data_bin2), ==, NULL);
395 }
396
397 static void
398 dfu_device_func (void)
399 {
400 GPtrArray *targets;
401 gboolean ret;
402 g_autoptr(DfuDevice) device = NULL;
403 g_autoptr(DfuTarget) target1 = NULL;
404 g_autoptr(DfuTarget) target2 = NULL;
405 g_autoptr(GError) error = NULL;
406 g_autoptr(GUsbContext) usb_ctx = NULL;
407 g_autoptr(GUsbDevice) usb_device = NULL;
408
409 /* find any DFU in appIDLE mode */
410 usb_ctx = g_usb_context_new (&error);
411 g_assert_no_error (error);
412 g_assert (usb_ctx != NULL);
413 g_usb_context_enumerate (usb_ctx);
414 usb_device = g_usb_context_find_by_vid_pid (usb_ctx,
415 0x273f,
416 0x1005,
417 &error);
418 if (usb_device == NULL)
419 return;
420 g_assert_no_error (error);
421 g_assert (usb_device != NULL);
422
423 /* check it's DFU-capable */
424 device = dfu_device_new (usb_device);
425 g_assert (device != NULL);
426
427 /* get targets */
428 targets = dfu_device_get_targets (device);
429 g_assert_cmpint (targets->len, ==, 2);
430
431 /* get by ID */
432 target1 = dfu_device_get_target_by_alt_setting (device, 1, &error);
433 g_assert_no_error (error);
434 g_assert (target1 != NULL);
435
436 /* ensure open */
437 ret = dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE, NULL, &error);
438 g_assert_no_error (error);
439 g_assert (ret);
440
441 /* get by name */
442 target2 = dfu_device_get_target_by_alt_name (device, "sram", &error);
443 g_assert_no_error (error);
444 g_assert (target2 != NULL);
445
446 /* close */
447 ret = dfu_device_close (device, &error);
448 g_assert_no_error (error);
449 g_assert (ret);
450 }
451
452 static void
453 dfu_colorhug_plus_func (void)
454 {
455 GPtrArray *elements;
456 gboolean ret;
457 gboolean seen_app_idle = FALSE;
458 g_autoptr(DfuContext) context = NULL;
459 g_autoptr(DfuDevice) device = NULL;
460 g_autoptr(DfuDevice) device2 = NULL;
461 g_autoptr(DfuTarget) target = NULL;
462 g_autoptr(DfuImage) image = NULL;
463 g_autoptr(GError) error = NULL;
464
465 /* create context */
466 context = dfu_context_new ();
467 ret = dfu_context_enumerate (context, &error);
468 g_assert_no_error (error);
469 g_assert (ret);
470
471 /* push appIDLE into dfuIDLE */
472 device2 = dfu_context_get_device_by_vid_pid (context,
473 0x273f,
474 0x1002,
475 NULL);
476 if (device2 != NULL) {
477 ret = dfu_device_open (device2, DFU_DEVICE_OPEN_FLAG_NONE, NULL, &error);
478 g_assert_no_error (error);
479 g_assert (ret);
480 ret = dfu_device_detach (device2, NULL, &error);
481 g_assert_no_error (error);
482 g_assert (ret);
483
484 /* wait for it to come back as 273f:1005 */
485 ret = dfu_device_wait_for_replug (device2, 5000, NULL, &error);
486 g_assert_no_error (error);
487 g_assert (ret);
488
489 /* close it */
490 ret = dfu_device_close (device2, &error);
491 g_assert_no_error (error);
492 g_assert (ret);
493 }
494
495 /* find any DFU in dfuIDLE mode */
496 device = dfu_context_get_device_by_vid_pid (context,
497 0x273f,
498 0x1003,
499 NULL);
500 if (device == NULL)
501 return;
502
503 /* we don't know this unless we went from appIDLE -> dfuIDLE */
504 if (device2 == NULL) {
505 g_assert_cmpint (dfu_device_get_runtime_vid (device), ==, 0xffff);
506 g_assert_cmpint (dfu_device_get_runtime_pid (device), ==, 0xffff);
507 }
508
509 /* open it */
510 ret = dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE, NULL, &error);
511 g_assert_no_error (error);
512 g_assert (ret);
513
514 /* is in dfuIDLE mode */
515 g_assert_cmpstr (dfu_state_to_string (dfu_device_get_state (device)), ==, "dfuIDLE");
516
517 /* lets try and flash something inappropriate */
518 if (seen_app_idle) {
519 g_autoptr(DfuFirmware) firmware = NULL;
520 g_autoptr(GFile) file = NULL;
521 g_autofree gchar *filename = NULL;
522
523 filename = dfu_test_get_filename ("kiibohd.dfu.bin");
524 g_assert (filename != NULL);
525 file = g_file_new_for_path (filename);
526 firmware = dfu_firmware_new ();
527 ret = dfu_firmware_parse_file (firmware, file,
528 DFU_FIRMWARE_PARSE_FLAG_NONE,
529 NULL, &error);
530 g_assert_no_error (error);
531 g_assert (ret);
532 ret = dfu_device_download (device, firmware,
533 DFU_TARGET_TRANSFER_FLAG_DETACH |
534 DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME,
535 NULL, &error);
536 g_assert_error (error,
537 DFU_ERROR,
538 DFU_ERROR_INTERNAL);
539 g_assert (ret);
540 g_clear_error (&error);
541 }
542
543 /* get a dump of the existing firmware */
544 target = dfu_device_get_target_by_alt_setting (device, 0, &error);
545 g_assert_no_error (error);
546 g_assert (target != NULL);
547 image = dfu_target_upload (target, DFU_TARGET_TRANSFER_FLAG_NONE,
548 NULL, &error);
549 g_assert_no_error (error);
550 g_assert (DFU_IS_IMAGE (image));
551 elements = dfu_image_get_elements (image);
552 g_assert (elements != NULL);
553 g_assert_cmpint (elements->len, ==, 1);
554
555 /* download a new firmware */
556 ret = dfu_target_download (target, image,
557 DFU_TARGET_TRANSFER_FLAG_VERIFY |
558 DFU_TARGET_TRANSFER_FLAG_ATTACH,
559 NULL, &error);
560 g_assert_no_error (error);
561 g_assert (ret);
562
563 /* wait for it to come back as 273f:1004 */
564 ret = dfu_device_wait_for_replug (device, 5000, NULL, &error);
565 g_assert_no_error (error);
566 g_assert (ret);
567
568 /* we should know now */
569 g_assert_cmpint (dfu_device_get_runtime_vid (device), ==, 0x273f);
570 g_assert_cmpint (dfu_device_get_runtime_pid (device), ==, 0x1002);
571 }
572
573 /**
574 * dfu_target_sectors_to_string:
575 **/
576 static gchar *
577 dfu_target_sectors_to_string (DfuTarget *target)
578 {
579 DfuSector *sector;
580 GPtrArray *sectors;
581 GString *str;
582 guint i;
583
584 str = g_string_new ("");
585 sectors = dfu_target_get_sectors (target);
586 for (i = 0; i < sectors->len; i++) {
587 g_autofree gchar *tmp = NULL;
588 sector = g_ptr_array_index (sectors, i);
589 tmp = dfu_sector_to_string (sector);
590 g_string_append_printf (str, "%s\n", tmp);
591 }
592 if (str->len > 0)
593 g_string_truncate (str, str->len - 1);
594 return g_string_free (str, FALSE);
595 }
596
597 static void
598 dfu_target_dfuse_func (void)
599 {
600 gboolean ret;
601 gchar *tmp;
602 g_autoptr(DfuTarget) target = NULL;
603 g_autoptr(GError) error = NULL;
604
605 /* NULL */
606 target = g_object_new (DFU_TYPE_TARGET, NULL);
607 ret = dfu_target_parse_sectors (target, NULL, &error);
608 g_assert_no_error (error);
609 g_assert (ret);
610 tmp = dfu_target_sectors_to_string (target);
611 g_assert_cmpstr (tmp, ==, "");
612 g_free (tmp);
613
614 /* no addresses */
615 ret = dfu_target_parse_sectors (target, "@Flash3", &error);
616 g_assert_no_error (error);
617 g_assert (ret);
618 tmp = dfu_target_sectors_to_string (target);
619 g_assert_cmpstr (tmp, ==, "");
620 g_free (tmp);
621
622 /* one sector, no space */
623 ret = dfu_target_parse_sectors (target, "@Internal Flash /0x08000000/2*001Ka", &error);
624 g_assert_no_error (error);
625 g_assert (ret);
626 tmp = dfu_target_sectors_to_string (target);
627 g_assert_cmpstr (tmp, ==, "Zone:0, Sec#:0, Addr:0x08000000, Size:0x0400, Caps:0x1\n"
628 "Zone:0, Sec#:0, Addr:0x08000400, Size:0x0400, Caps:0x1");
629 g_free (tmp);
630
631 /* multiple sectors */
632 ret = dfu_target_parse_sectors (target, "@Flash1 /0x08000000/2*001 Ka,4*001 Kg", &error);
633 g_assert_no_error (error);
634 g_assert (ret);
635 tmp = dfu_target_sectors_to_string (target);
636 g_assert_cmpstr (tmp, ==, "Zone:0, Sec#:0, Addr:0x08000000, Size:0x0400, Caps:0x1\n"
637 "Zone:0, Sec#:0, Addr:0x08000400, Size:0x0400, Caps:0x1\n"
638 "Zone:0, Sec#:1, Addr:0x08000000, Size:0x0400, Caps:0x7\n"
639 "Zone:0, Sec#:1, Addr:0x08000400, Size:0x0400, Caps:0x7\n"
640 "Zone:0, Sec#:1, Addr:0x08000800, Size:0x0400, Caps:0x7\n"
641 "Zone:0, Sec#:1, Addr:0x08000c00, Size:0x0400, Caps:0x7");
642 g_free (tmp);
643
644 /* non-contiguous */
645 ret = dfu_target_parse_sectors (target, "@Flash2 /0xF000/4*100Ba/0xE000/3*8Kg/0x80000/2*24Kg", &error);
646 g_assert_no_error (error);
647 g_assert (ret);
648 tmp = dfu_target_sectors_to_string (target);
649 g_assert_cmpstr (tmp, ==, "Zone:0, Sec#:0, Addr:0x0000f000, Size:0x0064, Caps:0x1\n"
650 "Zone:0, Sec#:0, Addr:0x0000f064, Size:0x0064, Caps:0x1\n"
651 "Zone:0, Sec#:0, Addr:0x0000f0c8, Size:0x0064, Caps:0x1\n"
652 "Zone:0, Sec#:0, Addr:0x0000f12c, Size:0x0064, Caps:0x1\n"
653 "Zone:1, Sec#:0, Addr:0x0000e000, Size:0x2000, Caps:0x7\n"
654 "Zone:1, Sec#:0, Addr:0x00010000, Size:0x2000, Caps:0x7\n"
655 "Zone:1, Sec#:0, Addr:0x00012000, Size:0x2000, Caps:0x7\n"
656 "Zone:2, Sec#:0, Addr:0x00080000, Size:0x6000, Caps:0x7\n"
657 "Zone:2, Sec#:0, Addr:0x00086000, Size:0x6000, Caps:0x7");
658 g_free (tmp);
659
660 /* invalid */
661 ret = dfu_target_parse_sectors (target, "Flash", NULL);
662 g_assert (ret);
663 ret = dfu_target_parse_sectors (target, "@Internal Flash /0x08000000", NULL);
664 g_assert (!ret);
665 ret = dfu_target_parse_sectors (target, "@Internal Flash /0x08000000/12*001a", NULL);
666 g_assert (!ret);
667
668 /* indicate a cipher being used */
669 g_assert_cmpint (dfu_target_get_cipher_kind (target), ==, DFU_CIPHER_KIND_NONE);
670 ret = dfu_target_parse_sectors (target, "@Flash|XTEA", &error);
671 g_assert_no_error (error);
672 g_assert (ret);
673 g_assert_cmpint (dfu_target_get_cipher_kind (target), ==, DFU_CIPHER_KIND_XTEA);
674 }
675
676 int
677 main (int argc, char **argv)
678 {
679 g_test_init (&argc, &argv, NULL);
680
681 /* only critical and error are fatal */
682 g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
683
684 /* log everything */
685 g_setenv ("G_MESSAGES_DEBUG", "all", FALSE);
686
687 /* tests go here */
688 g_test_add_func ("/libdfu/enums", dfu_enums_func);
689 g_test_add_func ("/libdfu/target(DfuSe}", dfu_target_dfuse_func);
690 g_test_add_func ("/libdfu/firmware{raw}", dfu_firmware_raw_func);
691 g_test_add_func ("/libdfu/firmware{dfu}", dfu_firmware_dfu_func);
692 g_test_add_func ("/libdfu/firmware{dfuse}", dfu_firmware_dfuse_func);
693 g_test_add_func ("/libdfu/firmware{xdfu}", dfu_firmware_xdfu_func);
694 g_test_add_func ("/libdfu/firmware{metadata}", dfu_firmware_metadata_func);
695 g_test_add_func ("/libdfu/firmware{intel-hex}", dfu_firmware_intel_hex_func);
696 g_test_add_func ("/libdfu/device", dfu_device_func);
697 g_test_add_func ("/libdfu/colorhug+", dfu_colorhug_plus_func);
698 return g_test_run ();
699 }
700
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #ifndef __DFU_TARGET_PRIVATE_H
22 #define __DFU_TARGET_PRIVATE_H
23
24 #include <gusb.h>
25
26 #include "dfu-device.h"
27 #include "dfu-target.h"
28
29 G_BEGIN_DECLS
30
31 DfuTarget *dfu_target_new (DfuDevice *device,
32 GUsbInterface *iface);
33
34 GBytes *dfu_target_upload_chunk (DfuTarget *target,
35 guint8 index,
36 GCancellable *cancellable,
37 GError **error);
38
39 /* export this just for the self tests */
40 gboolean dfu_target_parse_sectors (DfuTarget *target,
41 const gchar *alt_name,
42 GError **error);
43
44 G_END_DECLS
45
46 #endif /* __DFU_TARGET_PRIVATE_H */
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /**
22 * SECTION:dfu-target
23 * @short_description: Object representing a DFU-capable target
24 *
25 * This object allows uploading and downloading an image onto a
26 * specific DFU-capable target.
27 *
28 * You only need to use this in preference to #DfuDevice if you only
29 * want to update one target on the device. Most users will want to
30 * update all the targets on the device at the same time.
31 *
32 * See also: #DfuDevice, #DfuImage
33 */
34
35 #include "config.h"
36
37 #include <string.h>
38 #include <math.h>
39
40 #include "dfu-common.h"
41 #include "dfu-device-private.h"
42 #include "dfu-error.h"
43 #include "dfu-sector-private.h"
44 #include "dfu-target-private.h"
45
46 static void dfu_target_finalize (GObject *object);
47
48 typedef enum {
49 DFU_CMD_DFUSE_GET_COMMAND = 0x00,
50 DFU_CMD_DFUSE_SET_ADDRESS_POINTER = 0x21,
51 DFU_CMD_DFUSE_ERASE = 0x41,
52 DFU_CMD_DFUSE_READ_UNPROTECT = 0x92,
53 } DfuCmdDfuse;
54
55 /**
56 * DfuTargetPrivate:
57 *
58 * Private #DfuTarget data
59 **/
60 typedef struct {
61 DfuDevice *device; /* not refcounted */
62 DfuCipherKind cipher_kind;
63 gboolean done_setup;
64 guint8 alt_setting;
65 guint8 alt_idx;
66 gchar *alt_name;
67 GPtrArray *sectors; /* of DfuSector */
68 GHashTable *sectors_erased; /* of DfuSector:1 */
69 } DfuTargetPrivate;
70
71 enum {
72 SIGNAL_PERCENTAGE_CHANGED,
73 SIGNAL_LAST
74 };
75
76 static guint signals [SIGNAL_LAST] = { 0 };
77
78 G_DEFINE_TYPE_WITH_PRIVATE (DfuTarget, dfu_target, G_TYPE_OBJECT)
79 #define GET_PRIVATE(o) (dfu_target_get_instance_private (o))
80
81 /**
82 * dfu_target_class_init:
83 **/
84 static void
85 dfu_target_class_init (DfuTargetClass *klass)
86 {
87 GObjectClass *object_class = G_OBJECT_CLASS (klass);
88
89 /**
90 * DfuTarget::percentage-changed:
91 * @device: the #DfuTarget instance that emitted the signal
92 * @percentage: the new percentage
93 *
94 * The ::percentage-changed signal is emitted when the percentage changes.
95 *
96 * Since: 0.5.4
97 **/
98 signals [SIGNAL_PERCENTAGE_CHANGED] =
99 g_signal_new ("percentage-changed",
100 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
101 G_STRUCT_OFFSET (DfuTargetClass, percentage_changed),
102 NULL, NULL, g_cclosure_marshal_VOID__UINT,
103 G_TYPE_NONE, 1, G_TYPE_UINT);
104
105 object_class->finalize = dfu_target_finalize;
106 }
107
108 /**
109 * dfu_target_init:
110 **/
111 static void
112 dfu_target_init (DfuTarget *target)
113 {
114 DfuTargetPrivate *priv = GET_PRIVATE (target);
115 priv->sectors = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
116 priv->sectors_erased = g_hash_table_new (g_direct_hash, g_direct_equal);
117 }
118
119 /**
120 * dfu_target_finalize:
121 **/
122 static void
123 dfu_target_finalize (GObject *object)
124 {
125 DfuTarget *target = DFU_TARGET (object);
126 DfuTargetPrivate *priv = GET_PRIVATE (target);
127
128 g_free (priv->alt_name);
129 g_ptr_array_unref (priv->sectors);
130 g_hash_table_unref (priv->sectors_erased);
131
132 /* we no longer care */
133 if (priv->device != NULL) {
134 g_object_remove_weak_pointer (G_OBJECT (priv->device),
135 (gpointer *) &priv->device);
136 }
137
138 G_OBJECT_CLASS (dfu_target_parent_class)->finalize (object);
139 }
140
141 /**
142 * dfu_target_sectors_to_string:
143 **/
144 static gchar *
145 dfu_target_sectors_to_string (DfuTarget *target)
146 {
147 DfuTargetPrivate *priv = GET_PRIVATE (target);
148 DfuSector *sector;
149 GString *str;
150 guint i;
151
152 str = g_string_new ("");
153 for (i = 0; i < priv->sectors->len; i++) {
154 g_autofree gchar *tmp = NULL;
155 sector = g_ptr_array_index (priv->sectors, i);
156 tmp = dfu_sector_to_string (sector);
157 g_string_append_printf (str, "%s\n", tmp);
158 }
159 if (str->len > 0)
160 g_string_truncate (str, str->len - 1);
161 return g_string_free (str, FALSE);
162 }
163
164 /**
165 * dfu_target_get_sector_for_addr:
166 *
167 * Returns: the sector that should be used for a specific address, or %NULL
168 **/
169 static DfuSector *
170 dfu_target_get_sector_for_addr (DfuTarget *target, guint32 addr)
171 {
172 DfuTargetPrivate *priv = GET_PRIVATE (target);
173 DfuSector *sector;
174 guint i;
175
176 for (i = 0; i < priv->sectors->len; i++) {
177 sector = g_ptr_array_index (priv->sectors, i);
178 if (addr < dfu_sector_get_address (sector))
179 continue;
180 if (addr > dfu_sector_get_address (sector) +
181 dfu_sector_get_size (sector))
182 continue;
183 return sector;
184 }
185 return NULL;
186 }
187
188 /**
189 * dfu_target_parse_sector:
190 *
191 * Parse the DfuSe sector format according to UM0424
192 **/
193 static gboolean
194 dfu_target_parse_sector (DfuTarget *target,
195 const gchar *dfuse_sector_id,
196 guint32 addr,
197 guint zone,
198 guint number,
199 GError **error)
200 {
201 DfuTargetPrivate *priv = GET_PRIVATE (target);
202 DfuSectorCap cap = DFU_SECTOR_CAP_NONE;
203 gchar *tmp;
204 guint32 addr_offset = 0;
205 guint64 nr_sectors;
206 guint64 sector_size;
207 guint i;
208
209 /* parse # of sectors */
210 nr_sectors = g_ascii_strtoull (dfuse_sector_id, &tmp, 10);
211 if (nr_sectors > 999) {
212 g_set_error (error,
213 DFU_ERROR,
214 DFU_ERROR_NOT_SUPPORTED,
215 "Invalid number of sectors: %s",
216 dfuse_sector_id);
217 return FALSE;
218 }
219
220 /* check this is the delimiter */
221 if (tmp[0] != '*') {
222 g_set_error (error,
223 DFU_ERROR,
224 DFU_ERROR_NOT_SUPPORTED,
225 "Invalid sector ID: %s",
226 dfuse_sector_id);
227 return FALSE;
228 }
229
230 /* parse sector size */
231 sector_size = g_ascii_strtoull (tmp + 1, &tmp, 10);
232 if (sector_size > 999) {
233 g_set_error (error,
234 DFU_ERROR,
235 DFU_ERROR_NOT_SUPPORTED,
236 "Invalid sector size: %s",
237 dfuse_sector_id);
238 return FALSE;
239 }
240
241 /* optional spaces */
242 while (tmp[0] == ' ')
243 tmp++;
244
245 /* get multiplier */
246 switch (tmp[0]) {
247 case 'B': /* byte */
248 break;
249 case 'K': /* Kilo */
250 sector_size *= 0x400;
251 break;
252 case 'M': /* Mega */
253 sector_size *= 0x100000 ;
254 break;
255 default:
256 g_set_error (error,
257 DFU_ERROR,
258 DFU_ERROR_NOT_SUPPORTED,
259 "Invalid sector multiplier: %s",
260 tmp);
261 return FALSE;
262 }
263
264 /* get sector type */
265 switch (tmp[1]) {
266 case 'a':
267 cap = DFU_SECTOR_CAP_READABLE;
268 break;
269 case 'b':
270 cap = DFU_SECTOR_CAP_ERASEABLE;
271 break;
272 case 'c':
273 cap = DFU_SECTOR_CAP_READABLE |
274 DFU_SECTOR_CAP_ERASEABLE;
275 break;
276 case 'd':
277 cap = DFU_SECTOR_CAP_WRITEABLE;
278 break;
279 case 'e':
280 cap = DFU_SECTOR_CAP_READABLE |
281 DFU_SECTOR_CAP_WRITEABLE;
282 break;
283 case 'f':
284 cap = DFU_SECTOR_CAP_ERASEABLE |
285 DFU_SECTOR_CAP_WRITEABLE;
286 break;
287 case 'g':
288 cap = DFU_SECTOR_CAP_READABLE |
289 DFU_SECTOR_CAP_ERASEABLE |
290 DFU_SECTOR_CAP_WRITEABLE;
291 break;
292 default:
293 g_set_error (error,
294 DFU_ERROR,
295 DFU_ERROR_NOT_SUPPORTED,
296 "Invalid sector type: %s",
297 tmp);
298 return FALSE;
299 }
300
301 /* add all the sectors */
302 for (i = 0; i < nr_sectors; i++) {
303 DfuSector *sector;
304 sector = dfu_sector_new (addr + addr_offset,
305 sector_size,
306 (nr_sectors * sector_size)- addr_offset,
307 zone,
308 number,
309 cap);
310 g_ptr_array_add (priv->sectors, sector);
311 addr_offset += dfu_sector_get_size (sector);
312 }
313 return TRUE;
314 }
315
316 /**
317 * dfu_target_parse_sectors: (skip)
318 *
319 * Parse the DfuSe format according to UM0424
320 **/
321 gboolean
322 dfu_target_parse_sectors (DfuTarget *target, const gchar *alt_name, GError **error)
323 {
324 DfuTargetPrivate *priv = GET_PRIVATE (target);
325 guint64 addr;
326 guint i;
327 guint j;
328 g_autofree gchar *str_debug = NULL;
329 g_auto(GStrv) zones = NULL;
330
331 /* not set */
332 if (alt_name == NULL)
333 return TRUE;
334
335 /* do we have any hint for the cipher */
336 if (g_strstr_len (alt_name, -1, "|XTEA") != NULL)
337 priv->cipher_kind = DFU_CIPHER_KIND_XTEA;
338
339 /* From the Neo Freerunner */
340 if (g_str_has_prefix (alt_name, "RAM 0x")) {
341 DfuSector *sector;
342 addr = g_ascii_strtoull (alt_name + 6, NULL, 16);
343 if (addr == 0 && addr > G_MAXUINT32)
344 return FALSE;
345 g_debug ("RAM descripton, so parsing");
346 sector = dfu_sector_new (addr, /* addr */
347 0x0, /* size */
348 0x0, /* size_left */
349 0x0, /* zone */
350 0x0, /* number */
351 DFU_SECTOR_CAP_READABLE |
352 DFU_SECTOR_CAP_WRITEABLE);
353 g_ptr_array_add (priv->sectors, sector);
354 }
355
356 /* not a DfuSe alternative name */
357 if (alt_name[0] != '@')
358 return TRUE;
359
360 /* clear any existing zones */
361 g_ptr_array_set_size (priv->sectors, 0);
362
363 /* parse zones */
364 zones = g_strsplit (alt_name, "/", -1);
365 g_debug ("DfuSe nice alt-name: %s", g_strchomp (zones[0] + 1));
366 for (i = 1; zones[i] != NULL; i += 2) {
367 g_auto(GStrv) sectors = NULL;
368
369 /* parse address */
370 if (!g_str_has_prefix (zones[i], "0x"))
371 return FALSE;
372 addr = g_ascii_strtoull (zones[i] + 2, NULL, 16);
373 if (addr > G_MAXUINT32)
374 return FALSE;
375
376 /* no sectors?! */
377 if (zones[i+1] == NULL) {
378 g_set_error_literal (error,
379 DFU_ERROR,
380 DFU_ERROR_NOT_SUPPORTED,
381 "No sector section");
382 return FALSE;
383 }
384
385 /* parse sectors */
386 sectors = g_strsplit (zones[i+1], ",", -1);
387 for (j = 0; sectors[j] != NULL; j++) {
388 if (!dfu_target_parse_sector (target,
389 sectors[j],
390 addr,
391 (i - 1) / 2, j,
392 error))
393 return FALSE;
394 }
395 }
396
397 /* success */
398 str_debug = dfu_target_sectors_to_string (target);
399 g_debug ("%s", str_debug);
400 return TRUE;
401 }
402
403 /**
404 * dfu_target_new: (skip)
405 * @device: a #DfuDevice
406 * @iface: a #GUsbInterface
407 *
408 * Creates a new DFU target, which represents an alt-setting on a
409 * DFU-capable device.
410 *
411 * Return value: a #DfuTarget, or %NULL if @iface was not DFU-capable
412 *
413 * Since: 0.5.4
414 **/
415 DfuTarget *
416 dfu_target_new (DfuDevice *device, GUsbInterface *iface)
417 {
418 DfuTargetPrivate *priv;
419 DfuTarget *target;
420 target = g_object_new (DFU_TYPE_TARGET, NULL);
421 priv = GET_PRIVATE (target);
422 priv->device = device;
423 priv->alt_idx = g_usb_interface_get_index (iface);
424 priv->alt_setting = g_usb_interface_get_alternate (iface);
425
426 /* if we try to ref the target and destroy the device */
427 g_object_add_weak_pointer (G_OBJECT (priv->device),
428 (gpointer *) &priv->device);
429
430 return target;
431 }
432
433 /**
434 * dfu_target_get_sectors:
435 * @target: a #GUsbDevice
436 *
437 * Gets the sectors exported by the device.
438 *
439 * Return value: (transfer none) (element-type DfuSector): sectors
440 *
441 * Since: 0.5.4
442 **/
443 GPtrArray *
444 dfu_target_get_sectors (DfuTarget *target)
445 {
446 DfuTargetPrivate *priv = GET_PRIVATE (target);
447 g_return_val_if_fail (DFU_IS_TARGET (target), NULL);
448 return priv->sectors;
449 }
450
451 /**
452 * dfu_target_status_to_error_msg:
453 * @status: a #DfuStatus, e.g. %DFU_STATUS_ERR_ERASE
454 *
455 * Converts an enumerated value to an error description.
456 *
457 * Return value: a string
458 *
459 * Since: 0.5.4
460 **/
461 static const gchar *
462 dfu_target_status_to_error_msg (DfuStatus status)
463 {
464 if (status == DFU_STATUS_OK)
465 return "No error condition is present";
466 if (status == DFU_STATUS_ERR_TARGET)
467 return "Firmware is not for designed this device";
468 if (status == DFU_STATUS_ERR_FILE)
469 return "Firmware is for this device but fails verification";
470 if (status == DFU_STATUS_ERR_WRITE)
471 return "Device is unable to write memory";
472 if (status == DFU_STATUS_ERR_ERASE)
473 return "Memory erase function failed";
474 if (status == DFU_STATUS_ERR_CHECK_ERASED)
475 return "Memory erase check failed";
476 if (status == DFU_STATUS_ERR_PROG)
477 return "Program memory function failed";
478 if (status == DFU_STATUS_ERR_VERIFY)
479 return "Programmed memory failed verification";
480 if (status == DFU_STATUS_ERR_ADDRESS)
481 return "Cannot program memory due to address out of range";
482 if (status == DFU_STATUS_ERR_NOTDONE)
483 return "Received zero-length download but data is incomplete";
484 if (status == DFU_STATUS_ERR_FIRMWARE)
485 return "Device firmware is corrupt";
486 if (status == DFU_STATUS_ERR_VENDOR)
487 return "Vendor-specific error";
488 if (status == DFU_STATUS_ERR_USBR)
489 return "Device detected unexpected USB reset signaling";
490 if (status == DFU_STATUS_ERR_POR)
491 return "Device detected unexpected power on reset";
492 if (status == DFU_STATUS_ERR_UNKNOWN)
493 return "Something unexpected went wrong";
494 if (status == DFU_STATUS_ERR_STALLDPKT)
495 return "Device stalled an unexpected request";
496 return NULL;
497 }
498
499 /**
500 * dfu_target_check_status:
501 **/
502 static gboolean
503 dfu_target_check_status (DfuTarget *target,
504 GCancellable *cancellable,
505 GError **error)
506 {
507 DfuTargetPrivate *priv = GET_PRIVATE (target);
508 DfuStatus status;
509
510 /* get the status */
511 if (!dfu_device_refresh (priv->device, cancellable, error))
512 return FALSE;
513
514 /* not in an error state */
515 if (dfu_device_get_state (priv->device) != DFU_STATE_DFU_ERROR)
516 return TRUE;
517
518 /* DfuSe-specific long errors */
519 status = dfu_device_get_status (priv->device);
520 if (dfu_device_has_dfuse_support (priv->device)) {
521 if (status == DFU_STATUS_ERR_VENDOR) {
522 g_set_error (error,
523 DFU_ERROR,
524 DFU_ERROR_NOT_SUPPORTED,
525 "Read protection is active");
526 return FALSE;
527 }
528 if (status == DFU_STATUS_ERR_TARGET) {
529 g_set_error (error,
530 DFU_ERROR,
531 DFU_ERROR_NOT_SUPPORTED,
532 "Address is wrong or unsupported");
533 return FALSE;
534 }
535 }
536
537 /* use a proper error description */
538 g_set_error_literal (error,
539 DFU_ERROR,
540 DFU_ERROR_NOT_SUPPORTED,
541 dfu_target_status_to_error_msg (status));
542 return FALSE;
543 }
544
545 /**
546 * dfu_target_use_alt_setting:
547 * @target: a #DfuTarget
548 * @error: a #GError, or %NULL
549 *
550 * Opens a DFU-capable target.
551 *
552 * Return value: %TRUE for success
553 *
554 * Since: 0.5.4
555 **/
556 static gboolean
557 dfu_target_use_alt_setting (DfuTarget *target, GError **error)
558 {
559 DfuTargetPrivate *priv = GET_PRIVATE (target);
560 GUsbDevice *dev;
561 g_autoptr(GError) error_local = NULL;
562
563 g_return_val_if_fail (DFU_IS_TARGET (target), FALSE);
564 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
565
566 /* use the correct setting */
567 dev = dfu_device_get_usb_dev (priv->device);
568 if (dfu_device_get_mode (priv->device) == DFU_MODE_DFU) {
569 if (!g_usb_device_set_interface_alt (dev,
570 (gint) dfu_device_get_interface (priv->device),
571 (gint) priv->alt_setting,
572 &error_local)) {
573 g_set_error (error,
574 DFU_ERROR,
575 DFU_ERROR_NOT_SUPPORTED,
576 "cannot set alternate setting 0x%02x on interface %i: %s",
577 priv->alt_setting,
578 dfu_device_get_interface (priv->device),
579 error_local->message);
580 return FALSE;
581 }
582 }
583
584 return TRUE;
585 }
586
587 /**
588 * dfu_target_setup:
589 * @target: a #DfuTarget
590 * @error: a #GError, or %NULL
591 *
592 * Opens a DFU-capable target.
593 *
594 * Return value: %TRUE for success
595 *
596 * Since: 0.5.4
597 **/
598 static gboolean
599 dfu_target_setup (DfuTarget *target, GError **error)
600 {
601 DfuTargetPrivate *priv = GET_PRIVATE (target);
602 g_autoptr(GError) error_local = NULL;
603
604 g_return_val_if_fail (DFU_IS_TARGET (target), FALSE);
605 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
606
607 /* already done */
608 if (priv->done_setup)
609 return TRUE;
610
611 /* get string */
612 if (priv->alt_idx != 0x00) {
613 GUsbDevice *dev;
614 dev = dfu_device_get_usb_dev (priv->device);
615 priv->alt_name =
616 g_usb_device_get_string_descriptor (dev,
617 priv->alt_idx,
618 NULL);
619 }
620
621 /* parse the DfuSe format according to UM0424 */
622 if (!dfu_target_parse_sectors (target,
623 priv->alt_name,
624 error))
625 return FALSE;
626
627 /* add a dummy entry */
628 if (priv->sectors->len == 0) {
629 DfuSector *sector;
630 sector = dfu_sector_new (0x0, /* addr */
631 0x0, /* size */
632 0x0, /* size_left */
633 0x0, /* zone */
634 0x0, /* number */
635 DFU_SECTOR_CAP_READABLE |
636 DFU_SECTOR_CAP_WRITEABLE);
637 g_debug ("no UM0424 sector descripton in %s", priv->alt_name);
638 g_ptr_array_add (priv->sectors, sector);
639 }
640
641 priv->done_setup = TRUE;
642 return TRUE;
643 }
644
645 /**
646 * dfu_target_download_chunk:
647 **/
648 static gboolean
649 dfu_target_download_chunk (DfuTarget *target, guint8 index, GBytes *bytes,
650 GCancellable *cancellable, GError **error)
651 {
652 DfuTargetPrivate *priv = GET_PRIVATE (target);
653 g_autoptr(GError) error_local = NULL;
654 gsize actual_length;
655
656 if (!g_usb_device_control_transfer (dfu_device_get_usb_dev (priv->device),
657 G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
658 G_USB_DEVICE_REQUEST_TYPE_CLASS,
659 G_USB_DEVICE_RECIPIENT_INTERFACE,
660 DFU_REQUEST_DNLOAD,
661 index,
662 dfu_device_get_interface (priv->device),
663 (guint8 *) g_bytes_get_data (bytes, NULL),
664 g_bytes_get_size (bytes),
665 &actual_length,
666 dfu_device_get_timeout (priv->device),
667 cancellable,
668 &error_local)) {
669 /* refresh the error code */
670 dfu_device_error_fixup (priv->device, cancellable, &error_local);
671 g_set_error (error,
672 DFU_ERROR,
673 DFU_ERROR_NOT_SUPPORTED,
674 "cannot download data: %s",
675 error_local->message);
676 return FALSE;
677 }
678
679 /* for ST devices, the action only occurs when we do GetStatus */
680 if (!dfu_target_check_status (target, cancellable, error))
681 return FALSE;
682
683 g_assert (actual_length == g_bytes_get_size (bytes));
684 return TRUE;
685 }
686
687 /**
688 * dfu_target_set_address:
689 * @target: a #DfuTarget
690 * @address: memory address
691 * @cancellable: a #GCancellable, or %NULL
692 * @error: a #GError, or %NULL
693 *
694 * Sets the address used for the next download or upload request.
695 *
696 * IMPORTANT: This only works on DfuSe-capable devices from ST.
697 *
698 * Return value: %TRUE for success
699 *
700 * Since: 0.5.4
701 **/
702 static gboolean
703 dfu_target_set_address (DfuTarget *target,
704 guint32 address,
705 GCancellable *cancellable,
706 GError **error)
707 {
708 DfuTargetPrivate *priv = GET_PRIVATE (target);
709 GBytes *data_in;
710 guint8 buf[5];
711
712 /* invalid */
713 if (!dfu_device_has_dfuse_support (priv->device)) {
714 g_set_error_literal (error,
715 DFU_ERROR,
716 DFU_ERROR_NOT_SUPPORTED,
717 "only supported for DfuSe targets");
718 return FALSE;
719 }
720
721 /* format buffer */
722 buf[0] = DFU_CMD_DFUSE_SET_ADDRESS_POINTER;
723 memcpy (buf + 1, &address, 4);
724 data_in = g_bytes_new_static (buf, sizeof(buf));
725 if (!dfu_target_download_chunk (target, 0, data_in, cancellable, error))
726 return FALSE;
727
728 /* for ST devices, the action only occurs when we do GetStatus */
729 if (!dfu_target_check_status (target, cancellable, error))
730 return FALSE;
731 return TRUE;
732 }
733
734 /**
735 * dfu_target_erase_address:
736 * @target: a #DfuTarget
737 * @address: memory address
738 * @cancellable: a #GCancellable, or %NULL
739 * @error: a #GError, or %NULL
740 *
741 * Erases a memory sector at a given address.
742 *
743 * IMPORTANT: This only works on DfuSe-capable devices from ST.
744 *
745 * Return value: %TRUE for success
746 *
747 * Since: 0.5.4
748 **/
749 static gboolean
750 dfu_target_erase_address (DfuTarget *target,
751 guint32 address,
752 GCancellable *cancellable,
753 GError **error)
754 {
755 DfuTargetPrivate *priv = GET_PRIVATE (target);
756 GBytes *data_in;
757 guint8 buf[5];
758
759 /* invalid */
760 if (!dfu_device_has_dfuse_support (priv->device)) {
761 g_set_error_literal (error,
762 DFU_ERROR,
763 DFU_ERROR_NOT_SUPPORTED,
764 "only supported for DfuSe targets");
765 return FALSE;
766 }
767
768 /* format buffer */
769 buf[0] = DFU_CMD_DFUSE_ERASE;
770 memcpy (buf + 1, &address, 4);
771 data_in = g_bytes_new_static (buf, sizeof(buf));
772 if (!dfu_target_download_chunk (target, 0, data_in, cancellable, error))
773 return FALSE;
774
775 /* for ST devices, the action only occurs when we do GetStatus */
776 if (!dfu_target_check_status (target, cancellable, error))
777 return FALSE;
778
779 /* 2nd check required to get error code */
780 return dfu_target_check_status (target, cancellable, error);
781 }
782
783 #if 0
784
785 /**
786 * dfu_target_mass_erase:
787 * @target: a #DfuTarget
788 * @cancellable: a #GCancellable, or %NULL
789 * @error: a #GError, or %NULL
790 *
791 * Mass erases the device clearing all SRAM and EEPROM memory.
792 *
793 * This may not be supported on all devices, a better way of doing this action
794 * is to enable read protection and then doing dfu_target_read_unprotect().
795 *
796 * IMPORTANT: This only works on DfuSe-capable devices from ST.
797 *
798 * Return value: %TRUE for success
799 *
800 * Since: 0.5.4
801 **/
802 static gboolean
803 dfu_target_mass_erase (DfuTarget *target,
804 GCancellable *cancellable,
805 GError **error)
806 {
807 DfuTargetPrivate *priv = GET_PRIVATE (target);
808 GBytes *data_in;
809 guint8 buf[1];
810
811 /* invalid */
812 if (!dfu_device_has_dfuse_support (priv->device)) {
813 g_set_error_literal (error,
814 DFU_ERROR,
815 DFU_ERROR_NOT_SUPPORTED,
816 "only supported for DfuSe targets");
817 return FALSE;
818 }
819
820 /* format buffer */
821 buf[0] = DFU_CMD_DFUSE_ERASE;
822 data_in = g_bytes_new_static (buf, sizeof(buf));
823 if (!dfu_target_download_chunk (target, 0, data_in, cancellable, error))
824 return FALSE;
825
826 /* for ST devices, the action only occurs when we do GetStatus */
827 if (!dfu_target_check_status (target, cancellable, error))
828 return FALSE;
829
830 /* 2nd check required to get error code */
831 return dfu_target_check_status (target, cancellable, error);
832 }
833
834 /**
835 * dfu_target_read_unprotect:
836 * @target: a #DfuTarget
837 * @cancellable: a #GCancellable, or %NULL
838 * @error: a #GError, or %NULL
839 *
840 * Turns of read protection on the device, clearing all SRAM and EEPROM memory.
841 *
842 * IMPORTANT: This only works on DfuSe-capable devices from ST.
843 *
844 * Return value: %TRUE for success
845 *
846 * Since: 0.5.4
847 **/
848 static gboolean
849 dfu_target_read_unprotect (DfuTarget *target,
850 GCancellable *cancellable,
851 GError **error)
852 {
853 DfuTargetPrivate *priv = GET_PRIVATE (target);
854 GBytes *data_in;
855 guint8 buf[5];
856
857 /* invalid */
858 if (!dfu_device_has_dfuse_support (priv->device)) {
859 g_set_error_literal (error,
860 DFU_ERROR,
861 DFU_ERROR_NOT_SUPPORTED,
862 "only supported for DfuSe targets");
863 return FALSE;
864 }
865
866 /* format buffer */
867 buf[0] = DFU_CMD_DFUSE_READ_UNPROTECT;
868 memcpy (buf + 1, &address, 4);
869 data_in = g_bytes_new_static (buf, sizeof(buf));
870 if (!dfu_target_download_chunk (target, 0, data_in, cancellable, error))
871 return FALSE;
872
873 /* for ST devices, the action only occurs when we do GetStatus */
874 return dfu_target_check_status (target, cancellable, error);
875 }
876
877 #endif
878
879 /**
880 * dfu_target_upload_chunk: (skip)
881 **/
882 GBytes *
883 dfu_target_upload_chunk (DfuTarget *target, guint8 index,
884 GCancellable *cancellable, GError **error)
885 {
886 DfuTargetPrivate *priv = GET_PRIVATE (target);
887 g_autoptr(GError) error_local = NULL;
888 guint8 *buf;
889 gsize actual_length;
890 guint16 transfer_size = dfu_device_get_transfer_size (priv->device);
891
892 buf = g_new0 (guint8, transfer_size);
893 if (!g_usb_device_control_transfer (dfu_device_get_usb_dev (priv->device),
894 G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
895 G_USB_DEVICE_REQUEST_TYPE_CLASS,
896 G_USB_DEVICE_RECIPIENT_INTERFACE,
897 DFU_REQUEST_UPLOAD,
898 index,
899 dfu_device_get_interface (priv->device),
900 buf, (gsize) transfer_size,
901 &actual_length,
902 dfu_device_get_timeout (priv->device),
903 cancellable,
904 &error_local)) {
905 /* refresh the error code */
906 dfu_device_error_fixup (priv->device, cancellable, &error_local);
907 g_set_error (error,
908 DFU_ERROR,
909 DFU_ERROR_NOT_SUPPORTED,
910 "cannot upload data: %s",
911 error_local->message);
912 return NULL;
913 }
914
915 /* for ST devices, the action only occurs when we do GetStatus */
916 if (!dfu_device_has_quirk (priv->device, DFU_DEVICE_QUIRK_NO_GET_STATUS_UPLOAD)) {
917 if (!dfu_target_check_status (target, cancellable, error))
918 return FALSE;
919 }
920
921 return g_bytes_new_take (buf, actual_length);
922 }
923
924 /**
925 * dfu_target_upload_element:
926 **/
927 static DfuElement *
928 dfu_target_upload_element (DfuTarget *target,
929 guint32 address,
930 gsize expected_size,
931 GCancellable *cancellable,
932 GError **error)
933 {
934 DfuTargetPrivate *priv = GET_PRIVATE (target);
935 DfuSector *sector;
936 DfuElement *element = NULL;
937 GBytes *chunk_tmp;
938 gsize chunk_size;
939 gsize offset = 0;
940 gsize total_size = 0;
941 guint16 transfer_size = dfu_device_get_transfer_size (priv->device);
942 guint8 *buffer;
943 guint32 last_sector_id = G_MAXUINT;
944 guint dfuse_sector_offset = 0;
945 guint i;
946 guint old_percentage = G_MAXUINT;
947 g_autoptr(GBytes) contents = NULL;
948 g_autoptr(GPtrArray) chunks = NULL;
949
950 /* ST uses wBlockNum=0 for DfuSe commands and wBlockNum=1 is reserved */
951 if (dfu_device_has_dfuse_support (priv->device)) {
952 offset += address;
953 dfuse_sector_offset = 2;
954 }
955
956 /* get all the chunks from the hardware */
957 chunks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref);
958 for (i = 0; i < 0xffff; i++) {
959
960 /* for DfuSe devices we need to handle the address manually */
961 if (dfu_device_has_dfuse_support (priv->device)) {
962
963 /* check the sector with this element address is suitable */
964 sector = dfu_target_get_sector_for_addr (target, offset);
965 if (sector == NULL) {
966 g_set_error (error,
967 DFU_ERROR,
968 DFU_ERROR_INVALID_DEVICE,
969 "no memory sector at 0x%04x",
970 (guint) offset);
971 return FALSE;
972 }
973 if (!dfu_sector_has_cap (sector, DFU_SECTOR_CAP_READABLE)) {
974 g_set_error (error,
975 DFU_ERROR,
976 DFU_ERROR_INVALID_DEVICE,
977 "memory sector at 0x%04x is not readble",
978 (guint) offset);
979 return FALSE;
980 }
981
982 /* manually set the sector address */
983 if (dfu_sector_get_id (sector) != last_sector_id) {
984 g_debug ("setting DfuSe address to 0x%04x", (guint) offset);
985 if (!dfu_target_set_address (target,
986 offset,
987 cancellable,
988 error))
989 return FALSE;
990 last_sector_id = dfu_sector_get_id (sector);
991 }
992 }
993
994 /* read chunk of data */
995 chunk_tmp = dfu_target_upload_chunk (target,
996 i + dfuse_sector_offset,
997 cancellable,
998 error);
999 if (chunk_tmp == NULL)
1000 return NULL;
1001
1002 /* keep a sum of all the chunks */
1003 chunk_size = g_bytes_get_size (chunk_tmp);
1004 total_size += chunk_size;
1005 offset += chunk_size;
1006
1007 /* add to array */
1008 g_debug ("got #%04x chunk of size %" G_GSIZE_FORMAT,
1009 i, chunk_size);
1010 g_ptr_array_add (chunks, chunk_tmp);
1011
1012 /* update UI */
1013 if (chunk_size > 0) {
1014 guint percentage = (total_size * 100) / expected_size;
1015 if (percentage != old_percentage) {
1016 g_signal_emit (target,
1017 signals[SIGNAL_PERCENTAGE_CHANGED],
1018 0, percentage);
1019 }
1020 }
1021
1022 /* detect short write as EOF */
1023 if (chunk_size < transfer_size)
1024 break;
1025 }
1026
1027 /* check final size */
1028 if (expected_size > 0) {
1029 if (total_size != expected_size) {
1030 g_set_error (error,
1031 DFU_ERROR,
1032 DFU_ERROR_INVALID_FILE,
1033 "invalid size, got %" G_GSIZE_FORMAT ", "
1034 "expected %" G_GSIZE_FORMAT ,
1035 total_size, expected_size);
1036 return NULL;
1037 }
1038 }
1039
1040 /* stitch them all together */
1041 offset = 0;
1042 buffer = g_malloc0 (total_size);
1043 for (i = 0; i < chunks->len; i++) {
1044 const guint8 *chunk_data;
1045 chunk_tmp = g_ptr_array_index (chunks, i);
1046 chunk_data = g_bytes_get_data (chunk_tmp, &chunk_size);
1047 memcpy (buffer + offset, chunk_data, chunk_size);
1048 offset += chunk_size;
1049 }
1050
1051 /* create new image */
1052 contents = g_bytes_new_take (buffer, total_size);
1053 element = dfu_element_new ();
1054 dfu_element_set_contents (element, contents);
1055 return element;
1056 }
1057
1058 /**
1059 * dfu_target_upload:
1060 * @target: a #DfuTarget
1061 * @flags: flags to use, e.g. %DFU_TARGET_TRANSFER_FLAG_VERIFY
1062 * @cancellable: a #GCancellable, or %NULL
1063 * @error: a #GError, or %NULL
1064 *
1065 * Uploads firmware from the target to the host.
1066 *
1067 * Return value: (transfer full): the uploaded image, or %NULL for error
1068 *
1069 * Since: 0.5.4
1070 **/
1071 DfuImage *
1072 dfu_target_upload (DfuTarget *target,
1073 DfuTargetTransferFlags flags,
1074 GCancellable *cancellable,
1075 GError **error)
1076 {
1077 DfuTargetPrivate *priv = GET_PRIVATE (target);
1078 DfuSector *sector;
1079 guint i;
1080 guint32 last_sector_id = G_MAXUINT;
1081 g_autoptr(DfuImage) image = NULL;
1082
1083 g_return_val_if_fail (DFU_IS_TARGET (target), NULL);
1084 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1085
1086 /* ensure populated */
1087 if (!dfu_target_setup (target, error))
1088 return NULL;
1089
1090 /* can the target do this? */
1091 if (!dfu_device_can_upload (priv->device)) {
1092 g_set_error_literal (error,
1093 DFU_ERROR,
1094 DFU_ERROR_NOT_SUPPORTED,
1095 "target cannot do uploading");
1096 return NULL;
1097 }
1098
1099 /* use correct alt */
1100 if (!dfu_target_use_alt_setting (target, error))
1101 return NULL;
1102
1103 /* no open?! */
1104 if (priv->sectors->len == 0) {
1105 g_set_error_literal (error,
1106 DFU_ERROR,
1107 DFU_ERROR_NOT_SUPPORTED,
1108 "no sectors defined for target");
1109 return NULL;
1110 }
1111
1112 /* create a new image */
1113 image = dfu_image_new ();
1114 dfu_image_set_name (image, priv->alt_name);
1115 dfu_image_set_alt_setting (image, priv->alt_setting);
1116
1117 /* get all the sectors for the device */
1118 for (i = 0; i < priv->sectors->len; i++) {
1119 g_autoptr(DfuElement) element = NULL;
1120
1121 /* only upload to the start of any zone:sector */
1122 sector = g_ptr_array_index (priv->sectors, i);
1123 if (dfu_sector_get_id (sector) == last_sector_id)
1124 continue;
1125
1126 /* get the first element from the hardware */
1127 g_debug ("starting upload from 0x%08x (0x%04x)",
1128 dfu_sector_get_address (sector),
1129 dfu_sector_get_size_left (sector));
1130 element = dfu_target_upload_element (target,
1131 dfu_sector_get_address (sector),
1132 dfu_sector_get_size_left (sector),
1133 cancellable,
1134 error);
1135 if (element == NULL)
1136 return NULL;
1137
1138 /* this element was uploaded okay */
1139 dfu_image_add_element (image, element);
1140
1141 /* ignore sectors until one of these changes */
1142 last_sector_id = dfu_sector_get_id (sector);
1143 }
1144
1145 /* do host reset */
1146 if ((flags & DFU_TARGET_TRANSFER_FLAG_ATTACH) > 0 ||
1147 (flags & DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME) > 0) {
1148 if (!dfu_device_attach (priv->device, error))
1149 return NULL;
1150 }
1151
1152 /* boot to runtime */
1153 if (flags & DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME) {
1154 g_debug ("booting to runtime");
1155 if (!dfu_device_wait_for_replug (priv->device,
1156 DFU_DEVICE_REPLUG_TIMEOUT,
1157 cancellable,
1158 error))
1159 return NULL;
1160 }
1161
1162 /* success */
1163 return g_object_ref (image);
1164 }
1165
1166 /**
1167 * _g_bytes_compare_verbose:
1168 **/
1169 static gchar *
1170 _g_bytes_compare_verbose (GBytes *bytes1, GBytes *bytes2)
1171 {
1172 const guint8 *data1;
1173 const guint8 *data2;
1174 gsize length1;
1175 gsize length2;
1176 guint i;
1177
1178 data1 = g_bytes_get_data (bytes1, &length1);
1179 data2 = g_bytes_get_data (bytes2, &length2);
1180
1181 /* not the same length */
1182 if (length1 != length2) {
1183 return g_strdup_printf ("got %" G_GSIZE_FORMAT " bytes, "
1184 "expected %" G_GSIZE_FORMAT,
1185 length1, length2);
1186 }
1187
1188 /* return 00 01 02 03 */
1189 for (i = 0; i < length1; i++) {
1190 if (data1[i] != data2[i]) {
1191 return g_strdup_printf ("got 0x%02x, expected 0x%02x @ 0x%04x",
1192 data1[i], data2[i], i);
1193 }
1194 }
1195 return NULL;
1196 }
1197
1198 /**
1199 * dfu_target_download_element:
1200 **/
1201 static gboolean
1202 dfu_target_download_element (DfuTarget *target,
1203 DfuElement *element,
1204 DfuTargetTransferFlags flags,
1205 GCancellable *cancellable,
1206 GError **error)
1207 {
1208 DfuTargetPrivate *priv = GET_PRIVATE (target);
1209 DfuSector *sector;
1210 GBytes *bytes;
1211 guint i;
1212 guint nr_chunks;
1213 guint dfuse_sector_offset = 0;
1214 guint last_sector_id = G_MAXUINT;
1215 guint old_percentage = G_MAXUINT;
1216 guint16 transfer_size = dfu_device_get_transfer_size (priv->device);
1217 g_autoptr(GError) error_local = NULL;
1218
1219 /* ST uses wBlockNum=0 for DfuSe commands and wBlockNum=1 is reserved */
1220 if (dfu_device_has_dfuse_support (priv->device))
1221 dfuse_sector_offset = 2;
1222
1223 /* round up as we have to transfer incomplete blocks */
1224 bytes = dfu_element_get_contents (element);
1225 nr_chunks = ceil ((gdouble) g_bytes_get_size (bytes) /
1226 (gdouble) transfer_size);
1227 if (nr_chunks == 0) {
1228 g_set_error_literal (error,
1229 DFU_ERROR,
1230 DFU_ERROR_INVALID_FILE,
1231 "zero-length firmware");
1232 return FALSE;
1233 }
1234 for (i = 0; i < nr_chunks + 1; i++) {
1235 gsize length;
1236 gsize offset;
1237 guint percentage;
1238 g_autoptr(GBytes) bytes_tmp = NULL;
1239
1240 /* caclulate the offset into the element data */
1241 offset = i * transfer_size;
1242
1243 /* for DfuSe devices we need to handle the erase and setting
1244 * the address manually */
1245 if (dfu_device_has_dfuse_support (priv->device)) {
1246
1247 /* check the sector with this element address is suitable */
1248 sector = dfu_target_get_sector_for_addr (target, offset);
1249 if (sector == NULL) {
1250 g_set_error (error,
1251 DFU_ERROR,
1252 DFU_ERROR_INVALID_DEVICE,
1253 "no memory sector at 0x%04x",
1254 (guint) offset);
1255 return FALSE;
1256 }
1257 if (!dfu_sector_has_cap (sector, DFU_SECTOR_CAP_WRITEABLE)) {
1258 g_set_error (error,
1259 DFU_ERROR,
1260 DFU_ERROR_INVALID_DEVICE,
1261 "memory sector at 0x%04x is not writable",
1262 (guint) offset);
1263 return FALSE;
1264 }
1265
1266 /* if it's erasable and not yet blanked */
1267 if (!dfu_sector_has_cap (sector, DFU_SECTOR_CAP_ERASEABLE) &&
1268 g_hash_table_lookup (priv->sectors_erased, sector) == NULL) {
1269 g_debug ("erasing DfuSe address at 0x%04x", (guint) offset);
1270 if (!dfu_target_erase_address (target,
1271 offset,
1272 cancellable,
1273 error))
1274 return FALSE;
1275 g_hash_table_insert (priv->sectors_erased,
1276 sector,
1277 GINT_TO_POINTER (1));
1278 }
1279
1280 /* manually set the sector address */
1281 if (dfu_sector_get_id (sector) != last_sector_id) {
1282 g_debug ("setting DfuSe address to 0x%04x", (guint) offset);
1283 if (!dfu_target_set_address (target,
1284 offset,
1285 cancellable,
1286 error))
1287 return FALSE;
1288 last_sector_id = dfu_sector_get_id (sector);
1289 }
1290 }
1291
1292 /* we have to write one final zero-sized chunk for EOF */
1293 if (i < nr_chunks) {
1294 length = g_bytes_get_size (bytes) - offset;
1295 if (length > transfer_size)
1296 length = transfer_size;
1297 bytes_tmp = g_bytes_new_from_bytes (bytes, offset, length);
1298 } else {
1299 bytes_tmp = g_bytes_new (NULL, 0);
1300 }
1301 g_debug ("writing #%04x chunk of size %" G_GSIZE_FORMAT,
1302 i, g_bytes_get_size (bytes_tmp));
1303 if (!dfu_target_download_chunk (target,
1304 i + dfuse_sector_offset,
1305 bytes_tmp,
1306 cancellable,
1307 error))
1308 return FALSE;
1309
1310 /* update UI */
1311 percentage = (offset * 100) / g_bytes_get_size (bytes);
1312 if (percentage != old_percentage) {
1313 g_signal_emit (target,
1314 signals[SIGNAL_PERCENTAGE_CHANGED],
1315 0, percentage);
1316 }
1317
1318 /* give the target a chance to update */
1319 g_usleep (dfu_device_get_download_timeout (priv->device) * 1000);
1320
1321 /* getting the status moves the state machine to DNLOAD-IDLE */
1322 if (!dfu_device_refresh (priv->device, cancellable, error))
1323 return FALSE;
1324 }
1325
1326 /* verify */
1327 if (flags & DFU_TARGET_TRANSFER_FLAG_VERIFY) {
1328 GBytes *bytes_tmp;
1329 g_autoptr(DfuElement) element_tmp = NULL;
1330 element_tmp = dfu_target_upload_element (target,
1331 dfu_element_get_address (element),
1332 g_bytes_get_size (bytes),
1333 cancellable,
1334 error);
1335 if (element_tmp == NULL)
1336 return FALSE;
1337 bytes_tmp = dfu_element_get_contents (element_tmp);
1338 if (g_bytes_compare (bytes_tmp, bytes) != 0) {
1339 g_autofree gchar *bytes_cmp_str = NULL;
1340 bytes_cmp_str = _g_bytes_compare_verbose (bytes_tmp, bytes);
1341 g_set_error (error,
1342 DFU_ERROR,
1343 DFU_ERROR_VERIFY_FAILED,
1344 "verify failed: %s",
1345 bytes_cmp_str);
1346 return FALSE;
1347 }
1348 }
1349
1350 return TRUE;
1351 }
1352
1353 /**
1354 * dfu_target_download:
1355 * @target: a #DfuTarget
1356 * @image: a #DfuImage
1357 * @flags: flags to use, e.g. %DFU_TARGET_TRANSFER_FLAG_VERIFY
1358 * @cancellable: a #GCancellable, or %NULL
1359 * @error: a #GError, or %NULL
1360 *
1361 * Downloads firmware from the host to the target, optionally verifying
1362 * the transfer.
1363 *
1364 * Return value: %TRUE for success
1365 *
1366 * Since: 0.5.4
1367 **/
1368 gboolean
1369 dfu_target_download (DfuTarget *target, DfuImage *image,
1370 DfuTargetTransferFlags flags,
1371 GCancellable *cancellable,
1372 GError **error)
1373 {
1374 DfuTargetPrivate *priv = GET_PRIVATE (target);
1375 DfuElement *element;
1376 GPtrArray *elements;
1377 gboolean ret;
1378 guint i;
1379
1380 g_return_val_if_fail (DFU_IS_TARGET (target), FALSE);
1381 g_return_val_if_fail (DFU_IS_IMAGE (image), FALSE);
1382 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1383
1384 /* ensure populated */
1385 if (!dfu_target_setup (target, error))
1386 return NULL;
1387
1388 /* can the target do this? */
1389 if (!dfu_device_can_download (priv->device)) {
1390 g_set_error_literal (error,
1391 DFU_ERROR,
1392 DFU_ERROR_NOT_SUPPORTED,
1393 "target cannot do downloading");
1394 return FALSE;
1395 }
1396
1397 /* use correct alt */
1398 if (!dfu_target_use_alt_setting (target, error))
1399 return FALSE;
1400
1401 /* mark these as all erased */
1402 if (dfu_device_has_dfuse_support (priv->device))
1403 g_hash_table_remove_all (priv->sectors_erased);
1404
1405 /* download all elements in the image to the device */
1406 elements = dfu_image_get_elements (image);
1407 if (elements->len == 0) {
1408 g_set_error_literal (error,
1409 DFU_ERROR,
1410 DFU_ERROR_INVALID_FILE,
1411 "no image elements");
1412 return FALSE;
1413 }
1414 for (i = 0; i < elements->len; i++) {
1415 element = dfu_image_get_element (image, i);
1416 g_debug ("downloading element at 0x%04x",
1417 dfu_element_get_address (element));
1418 ret = dfu_target_download_element (target,
1419 element,
1420 flags,
1421 cancellable,
1422 error);
1423 if (!ret)
1424 return FALSE;
1425 }
1426
1427 /* attempt to switch back to runtime */
1428 if ((flags & DFU_TARGET_TRANSFER_FLAG_ATTACH) > 0 ||
1429 (flags & DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME) > 0) {
1430 if (!dfu_device_attach (priv->device, error))
1431 return FALSE;
1432 }
1433
1434 /* boot to runtime */
1435 if (flags & DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME) {
1436 g_debug ("booting to runtime to set auto-boot");
1437 if (!dfu_device_wait_for_replug (priv->device,
1438 DFU_DEVICE_REPLUG_TIMEOUT,
1439 cancellable,
1440 error))
1441 return FALSE;
1442 }
1443
1444 /* success */
1445 return TRUE;
1446 }
1447
1448 #if 0
1449 /**
1450 * dfu_target_get_commands:
1451 **/
1452 static gboolean
1453 dfu_target_get_commands (DfuTarget *target,
1454 GCancellable *cancellable,
1455 GError **error)
1456 {
1457 GBytes *data_in;
1458 GBytes *data_out;
1459 guint8 buf[1];
1460
1461 /* invalid */
1462 if (!dfu_device_has_dfuse_support (priv->device)) {
1463 g_set_error_literal (error,
1464 DFU_ERROR,
1465 DFU_ERROR_NOT_SUPPORTED,
1466 "only supported for DfuSe targets");
1467 return FALSE;
1468 }
1469
1470 /* format buffer */
1471 buf[0] = DFU_CMD_DFUSE_GET_COMMAND;
1472 data_in = g_bytes_new_static (buf, sizeof(buf));
1473 if (!dfu_target_download_chunk (target, 0, data_in, cancellable, error))
1474 return FALSE;
1475
1476 /* return results */
1477 data_out = dfu_target_upload_chunk (target, 0, cancellable, error);
1478 if (data_out == NULL)
1479 return FALSE;
1480
1481 // N bytes,
1482 // each byte is the command code
1483
1484 // FIXME: parse?
1485 return TRUE;
1486 }
1487 #endif
1488
1489 /**
1490 * dfu_target_get_alt_setting:
1491 * @target: a #DfuTarget
1492 *
1493 * Gets the alternate setting to use for this interface.
1494 *
1495 * Return value: the alternative setting, typically zero
1496 *
1497 * Since: 0.5.4
1498 **/
1499 guint8
1500 dfu_target_get_alt_setting (DfuTarget *target)
1501 {
1502 DfuTargetPrivate *priv = GET_PRIVATE (target);
1503 g_return_val_if_fail (DFU_IS_TARGET (target), 0xff);
1504 return priv->alt_setting;
1505 }
1506
1507 /**
1508 * dfu_target_get_alt_name:
1509 * @target: a #DfuTarget
1510 * @error: a #GError, or %NULL
1511 *
1512 * Gets the alternate setting name to use for this interface.
1513 *
1514 * Return value: the alternative setting name, typically %NULL
1515 *
1516 * Since: 0.5.4
1517 **/
1518 const gchar *
1519 dfu_target_get_alt_name (DfuTarget *target, GError **error)
1520 {
1521 DfuTargetPrivate *priv = GET_PRIVATE (target);
1522 g_return_val_if_fail (DFU_IS_TARGET (target), NULL);
1523
1524 /* ensure populated */
1525 if (!dfu_target_setup (target, error))
1526 return NULL;
1527
1528 /* nothing */
1529 if (priv->alt_name == NULL) {
1530 g_set_error_literal (error,
1531 DFU_ERROR,
1532 DFU_ERROR_NOT_FOUND,
1533 "no alt-name");
1534 return FALSE;
1535 }
1536
1537 return priv->alt_name;
1538 }
1539
1540 /**
1541 * dfu_target_get_cipher_kind:
1542 * @target: a #DfuTarget
1543 *
1544 * Gets the cipher used for data sent to this interface.
1545 *
1546 * Return value: the cipher, typically %DFU_CIPHER_KIND_NONE
1547 *
1548 * Since: 0.5.4
1549 **/
1550 DfuCipherKind
1551 dfu_target_get_cipher_kind (DfuTarget *target)
1552 {
1553 DfuTargetPrivate *priv = GET_PRIVATE (target);
1554 g_return_val_if_fail (DFU_IS_TARGET (target), 0);
1555 return priv->cipher_kind;
1556 }
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #ifndef __DFU_TARGET_H
22 #define __DFU_TARGET_H
23
24 #include <glib-object.h>
25 #include <gio/gio.h>
26 #include <gusb.h>
27
28 #include "dfu-common.h"
29 #include "dfu-image.h"
30
31 G_BEGIN_DECLS
32
33 #define DFU_TYPE_TARGET (dfu_target_get_type ())
34 G_DECLARE_DERIVABLE_TYPE (DfuTarget, dfu_target, DFU, TARGET, GUsbDevice)
35
36 struct _DfuTargetClass
37 {
38 GUsbDeviceClass parent_class;
39 void (*percentage_changed) (DfuTarget *target,
40 guint percentage);
41 /*< private >*/
42 /* Padding for future expansion */
43 void (*_dfu_target_reserved1) (void);
44 void (*_dfu_target_reserved2) (void);
45 void (*_dfu_target_reserved3) (void);
46 void (*_dfu_target_reserved4) (void);
47 void (*_dfu_target_reserved5) (void);
48 void (*_dfu_target_reserved6) (void);
49 void (*_dfu_target_reserved7) (void);
50 void (*_dfu_target_reserved8) (void);
51 void (*_dfu_target_reserved9) (void);
52 };
53
54 /**
55 * DfuTargetTransferFlags:
56 * @DFU_TARGET_TRANSFER_FLAG_NONE: No flags set
57 * @DFU_TARGET_TRANSFER_FLAG_VERIFY: Verify the download once complete
58 * @DFU_TARGET_TRANSFER_FLAG_DETACH: If required, detach from runtime mode
59 * @DFU_TARGET_TRANSFER_FLAG_ATTACH: Attach the device back to runtime after completion
60 * @DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME: Wait for runtime to load after completion
61 * @DFU_TARGET_TRANSFER_FLAG_WILDCARD_VID: Allow downloading images with wildcard VIDs
62 * @DFU_TARGET_TRANSFER_FLAG_WILDCARD_PID: Allow downloading images with wildcard PIDs
63 * @DFU_TARGET_TRANSFER_FLAG_ANY_CIPHER: Allow any cipher kinds to be downloaded
64 *
65 * The optional flags used for transfering firmware.
66 **/
67 typedef enum {
68 DFU_TARGET_TRANSFER_FLAG_NONE = 0,
69 DFU_TARGET_TRANSFER_FLAG_VERIFY = (1 << 0),
70 DFU_TARGET_TRANSFER_FLAG_DETACH = (1 << 1),
71 DFU_TARGET_TRANSFER_FLAG_ATTACH = (1 << 2),
72 DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME = (1 << 3),
73 DFU_TARGET_TRANSFER_FLAG_WILDCARD_VID = (1 << 4),
74 DFU_TARGET_TRANSFER_FLAG_WILDCARD_PID = (1 << 5),
75 DFU_TARGET_TRANSFER_FLAG_ANY_CIPHER = (1 << 6),
76 /*< private >*/
77 DFU_TARGET_TRANSFER_FLAG_LAST,
78 } DfuTargetTransferFlags;
79
80 GPtrArray *dfu_target_get_sectors (DfuTarget *target);
81 guint8 dfu_target_get_alt_setting (DfuTarget *target);
82 const gchar *dfu_target_get_alt_name (DfuTarget *target,
83 GError **error);
84 DfuImage *dfu_target_upload (DfuTarget *target,
85 DfuTargetTransferFlags flags,
86 GCancellable *cancellable,
87 GError **error);
88 gboolean dfu_target_download (DfuTarget *target,
89 DfuImage *image,
90 DfuTargetTransferFlags flags,
91 GCancellable *cancellable,
92 GError **error);
93 DfuCipherKind dfu_target_get_cipher_kind (DfuTarget *target);
94
95 G_END_DECLS
96
97 #endif /* __DFU_TARGET_H */
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU General Public License Version 2
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "config.h"
22
23 #include <dfu.h>
24 #include <libintl.h>
25 #include <locale.h>
26 #include <stdlib.h>
27 #include <glib/gi18n.h>
28 #include <glib-unix.h>
29 #include <appstream-glib.h>
30
31 #include "dfu-device-private.h"
32
33 typedef struct {
34 GCancellable *cancellable;
35 GPtrArray *cmd_array;
36 gboolean force;
37 gchar *device_vid_pid;
38 guint16 transfer_size;
39 } DfuToolPrivate;
40
41 /**
42 * dfu_tool_print_indent:
43 **/
44 static void
45 dfu_tool_print_indent (const gchar *title, const gchar *message, guint indent)
46 {
47 guint i;
48 for (i = 0; i < indent; i++)
49 g_print (" ");
50 g_print ("%s:", title);
51 for (i = strlen (title) + indent; i < 15; i++)
52 g_print (" ");
53 g_print ("%s\n", message);
54 }
55
56 /**
57 * dfu_tool_private_free:
58 **/
59 static void
60 dfu_tool_private_free (DfuToolPrivate *priv)
61 {
62 if (priv == NULL)
63 return;
64 g_free (priv->device_vid_pid);
65 g_object_unref (priv->cancellable);
66 if (priv->cmd_array != NULL)
67 g_ptr_array_unref (priv->cmd_array);
68 g_free (priv);
69 }
70 G_DEFINE_AUTOPTR_CLEANUP_FUNC(DfuToolPrivate, dfu_tool_private_free)
71
72 typedef gboolean (*FuUtilPrivateCb) (DfuToolPrivate *util,
73 gchar **values,
74 GError **error);
75
76 typedef struct {
77 gchar *name;
78 gchar *arguments;
79 gchar *description;
80 FuUtilPrivateCb callback;
81 } FuUtilItem;
82
83 /**
84 * dfu_tool_item_free:
85 **/
86 static void
87 dfu_tool_item_free (FuUtilItem *item)
88 {
89 g_free (item->name);
90 g_free (item->arguments);
91 g_free (item->description);
92 g_free (item);
93 }
94
95 /**
96 * dfu_tool_sort_command_name_cb:
97 **/
98 static gint
99 dfu_tool_sort_command_name_cb (FuUtilItem **item1, FuUtilItem **item2)
100 {
101 return g_strcmp0 ((*item1)->name, (*item2)->name);
102 }
103
104 /**
105 * dfu_tool_add:
106 **/
107 static void
108 dfu_tool_add (GPtrArray *array,
109 const gchar *name,
110 const gchar *arguments,
111 const gchar *description,
112 FuUtilPrivateCb callback)
113 {
114 guint i;
115 FuUtilItem *item;
116 g_auto(GStrv) names = NULL;
117
118 g_return_if_fail (name != NULL);
119 g_return_if_fail (description != NULL);
120 g_return_if_fail (callback != NULL);
121
122 /* add each one */
123 names = g_strsplit (name, ",", -1);
124 for (i = 0; names[i] != NULL; i++) {
125 item = g_new0 (FuUtilItem, 1);
126 item->name = g_strdup (names[i]);
127 if (i == 0) {
128 item->description = g_strdup (description);
129 } else {
130 /* TRANSLATORS: this is a command alias, e.g. 'get-devices' */
131 item->description = g_strdup_printf (_("Alias to %s"),
132 names[0]);
133 }
134 item->arguments = g_strdup (arguments);
135 item->callback = callback;
136 g_ptr_array_add (array, item);
137 }
138 }
139
140 /**
141 * dfu_tool_get_descriptions:
142 **/
143 static gchar *
144 dfu_tool_get_descriptions (GPtrArray *array)
145 {
146 guint i;
147 guint j;
148 guint len;
149 const guint max_len = 31;
150 FuUtilItem *item;
151 GString *string;
152
153 /* print each command */
154 string = g_string_new ("");
155 for (i = 0; i < array->len; i++) {
156 item = g_ptr_array_index (array, i);
157 g_string_append (string, " ");
158 g_string_append (string, item->name);
159 len = strlen (item->name) + 2;
160 if (item->arguments != NULL) {
161 g_string_append (string, " ");
162 g_string_append (string, item->arguments);
163 len += strlen (item->arguments) + 1;
164 }
165 if (len < max_len) {
166 for (j = len; j < max_len + 1; j++)
167 g_string_append_c (string, ' ');
168 g_string_append (string, item->description);
169 g_string_append_c (string, '\n');
170 } else {
171 g_string_append_c (string, '\n');
172 for (j = 0; j < max_len + 1; j++)
173 g_string_append_c (string, ' ');
174 g_string_append (string, item->description);
175 g_string_append_c (string, '\n');
176 }
177 }
178
179 /* remove trailing newline */
180 if (string->len > 0)
181 g_string_set_size (string, string->len - 1);
182
183 return g_string_free (string, FALSE);
184 }
185
186 /**
187 * dfu_tool_run:
188 **/
189 static gboolean
190 dfu_tool_run (DfuToolPrivate *priv,
191 const gchar *command,
192 gchar **values,
193 GError **error)
194 {
195 guint i;
196 FuUtilItem *item;
197
198 /* find command */
199 for (i = 0; i < priv->cmd_array->len; i++) {
200 item = g_ptr_array_index (priv->cmd_array, i);
201 if (g_strcmp0 (item->name, command) == 0)
202 return item->callback (priv, values, error);
203 }
204
205 /* not found */
206 g_set_error_literal (error,
207 DFU_ERROR,
208 DFU_ERROR_INTERNAL,
209 /* TRANSLATORS: error message */
210 _("Command not found"));
211 return FALSE;
212 }
213
214 /**
215 * dfu_tool_get_defalt_device:
216 **/
217 static DfuDevice *
218 dfu_tool_get_defalt_device (DfuToolPrivate *priv, GError **error)
219 {
220 DfuDevice *device;
221 g_autoptr(DfuContext) dfu_context = NULL;
222
223 /* get all the DFU devices */
224 dfu_context = dfu_context_new ();
225 dfu_context_enumerate (dfu_context, NULL);
226
227 /* we specified it manually */
228 if (priv->device_vid_pid != NULL) {
229 gchar *tmp;
230 guint64 pid;
231 guint64 vid;
232
233 /* parse */
234 vid = g_ascii_strtoull (priv->device_vid_pid, &tmp, 16);
235 if (vid == 0 || vid > G_MAXUINT16) {
236 g_set_error_literal (error,
237 DFU_ERROR,
238 DFU_ERROR_INTERNAL,
239 "Invalid format of VID:PID");
240 return NULL;
241 }
242 if (tmp[0] != ':') {
243 g_set_error_literal (error,
244 DFU_ERROR,
245 DFU_ERROR_INTERNAL,
246 "Invalid format of VID:PID");
247 return NULL;
248 }
249 pid = g_ascii_strtoull (tmp + 1, NULL, 16);
250 if (vid == 0 || vid > G_MAXUINT16) {
251 g_set_error_literal (error,
252 DFU_ERROR,
253 DFU_ERROR_INTERNAL,
254 "Invalid format of VID:PID");
255 return NULL;
256 }
257
258 /* find device */
259 device = dfu_context_get_device_by_vid_pid (dfu_context,
260 vid, pid,
261 error);
262 if (device == NULL)
263 return NULL;
264 } else {
265 /* auto-detect first device */
266 device = dfu_context_get_device_default (dfu_context, error);
267 if (device == NULL)
268 return NULL;
269 }
270
271 /* this has to be added to the device so we can deal with detach */
272 g_object_set_data_full (G_OBJECT (device), "DfuContext",
273 g_object_ref (dfu_context),
274 (GDestroyNotify) g_object_unref);
275 return device;
276 }
277
278 /**
279 * dfu_tool_set_vendor:
280 **/
281 static gboolean
282 dfu_tool_set_vendor (DfuToolPrivate *priv, gchar **values, GError **error)
283 {
284 guint64 tmp;
285 g_autoptr(DfuFirmware) firmware = NULL;
286 g_autoptr(GFile) file = NULL;
287
288 /* check args */
289 if (g_strv_length (values) < 2) {
290 g_set_error_literal (error,
291 DFU_ERROR,
292 DFU_ERROR_INTERNAL,
293 "Invalid arguments, expected FILE VID"
294 " -- e.g. `firmware.dfu 273f");
295 return FALSE;
296 }
297
298 /* open */
299 file = g_file_new_for_path (values[0]);
300 firmware = dfu_firmware_new ();
301 if (!dfu_firmware_parse_file (firmware, file,
302 DFU_FIRMWARE_PARSE_FLAG_NONE,
303 priv->cancellable,
304 error)) {
305 return FALSE;
306 }
307
308 /* parse VID */
309 tmp = g_ascii_strtoull (values[1], NULL, 16);
310 if (tmp == 0 || tmp > 0xffff) {
311 g_set_error (error,
312 DFU_ERROR,
313 DFU_ERROR_INTERNAL,
314 "Failed to parse VID '%s'",
315 values[1]);
316 return FALSE;
317 }
318 dfu_firmware_set_vid (firmware, tmp);
319
320 /* write out new file */
321 return dfu_firmware_write_file (firmware,
322 file,
323 priv->cancellable,
324 error);
325 }
326
327 /**
328 * dfu_tool_set_product:
329 **/
330 static gboolean
331 dfu_tool_set_product (DfuToolPrivate *priv, gchar **values, GError **error)
332 {
333 guint64 tmp;
334 g_autoptr(DfuFirmware) firmware = NULL;
335 g_autoptr(GFile) file = NULL;
336
337 /* check args */
338 if (g_strv_length (values) < 2) {
339 g_set_error_literal (error,
340 DFU_ERROR,
341 DFU_ERROR_INTERNAL,
342 "Invalid arguments, expected FILE PID"
343 " -- e.g. `firmware.dfu 1004");
344 return FALSE;
345 }
346
347 /* open */
348 file = g_file_new_for_path (values[0]);
349 firmware = dfu_firmware_new ();
350 if (!dfu_firmware_parse_file (firmware, file,
351 DFU_FIRMWARE_PARSE_FLAG_NONE,
352 priv->cancellable,
353 error)) {
354 return FALSE;
355 }
356
357 /* parse VID */
358 tmp = g_ascii_strtoull (values[1], NULL, 16);
359 if (tmp == 0 || tmp > 0xffff) {
360 g_set_error (error,
361 DFU_ERROR,
362 DFU_ERROR_INTERNAL,
363 "Failed to parse PID '%s'", values[1]);
364 return FALSE;
365 }
366 dfu_firmware_set_pid (firmware, tmp);
367
368 /* write out new file */
369 return dfu_firmware_write_file (firmware,
370 file,
371 priv->cancellable,
372 error);
373 }
374
375 /**
376 * dfu_tool_set_release:
377 **/
378 static gboolean
379 dfu_tool_set_release (DfuToolPrivate *priv, gchar **values, GError **error)
380 {
381 guint64 tmp;
382 g_autoptr(DfuFirmware) firmware = NULL;
383 g_autoptr(GFile) file = NULL;
384
385 /* check args */
386 if (g_strv_length (values) < 2) {
387 g_set_error_literal (error,
388 DFU_ERROR,
389 DFU_ERROR_INTERNAL,
390 "Invalid arguments, expected FILE RELEASE"
391 " -- e.g. `firmware.dfu ffff");
392 return FALSE;
393 }
394
395 /* open */
396 file = g_file_new_for_path (values[0]);
397 firmware = dfu_firmware_new ();
398 if (!dfu_firmware_parse_file (firmware, file,
399 DFU_FIRMWARE_PARSE_FLAG_NONE,
400 priv->cancellable,
401 error)) {
402 return FALSE;
403 }
404
405 /* parse VID */
406 tmp = g_ascii_strtoull (values[1], NULL, 16);
407 if (tmp == 0 || tmp > 0xffff) {
408 g_set_error (error,
409 DFU_ERROR,
410 DFU_ERROR_INTERNAL,
411 "Failed to parse release '%s'", values[1]);
412 return FALSE;
413 }
414 dfu_firmware_set_release (firmware, tmp);
415
416 /* write out new file */
417 return dfu_firmware_write_file (firmware,
418 file,
419 priv->cancellable,
420 error);
421 }
422
423 /**
424 * dfu_tool_set_metadata:
425 **/
426 static gboolean
427 dfu_tool_set_metadata (DfuToolPrivate *priv, gchar **values, GError **error)
428 {
429 g_autoptr(DfuFirmware) firmware = NULL;
430 g_autoptr(GFile) file = NULL;
431
432 /* check args */
433 if (g_strv_length (values) < 3) {
434 g_set_error_literal (error,
435 DFU_ERROR,
436 DFU_ERROR_INTERNAL,
437 "Invalid arguments, expected FILE KEY VALUE"
438 " -- e.g. `firmware.dfu Licence GPL-2.0+");
439 return FALSE;
440 }
441
442 /* open */
443 file = g_file_new_for_path (values[0]);
444 firmware = dfu_firmware_new ();
445 if (!dfu_firmware_parse_file (firmware, file,
446 DFU_FIRMWARE_PARSE_FLAG_NONE,
447 priv->cancellable,
448 error)) {
449 return FALSE;
450 }
451
452 /* doesn't make sense for non-DFU */
453 if (dfu_firmware_get_format (firmware) == DFU_FIRMWARE_FORMAT_RAW) {
454 g_set_error (error,
455 DFU_ERROR,
456 DFU_ERROR_INTERNAL,
457 "Only possible on DFU/DfuSe images, try convert");
458 return FALSE;
459 }
460
461 /* set metadata */
462 dfu_firmware_set_metadata (firmware, values[1], values[2]);
463
464 /* write out new file */
465 return dfu_firmware_write_file (firmware,
466 file,
467 priv->cancellable,
468 error);
469 }
470
471 /**
472 * dfu_tool_set_alt_setting:
473 **/
474 static gboolean
475 dfu_tool_set_alt_setting (DfuToolPrivate *priv, gchar **values, GError **error)
476 {
477 DfuImage *image;
478 guint64 tmp;
479 g_autoptr(DfuFirmware) firmware = NULL;
480 g_autoptr(GFile) file = NULL;
481
482 /* check args */
483 if (g_strv_length (values) < 2) {
484 g_set_error_literal (error,
485 DFU_ERROR,
486 DFU_ERROR_INTERNAL,
487 "Invalid arguments, expected FILE ALT-ID"
488 " -- e.g. `firmware.dfu 1");
489 return FALSE;
490 }
491
492 /* open */
493 file = g_file_new_for_path (values[0]);
494 firmware = dfu_firmware_new ();
495 if (!dfu_firmware_parse_file (firmware, file,
496 DFU_FIRMWARE_PARSE_FLAG_NONE,
497 priv->cancellable,
498 error)) {
499 return FALSE;
500 }
501
502 /* doesn't make sense for non-DfuSe */
503 if (dfu_firmware_get_format (firmware) != DFU_FIRMWARE_FORMAT_DFUSE) {
504 g_set_error (error,
505 DFU_ERROR,
506 DFU_ERROR_INTERNAL,
507 "Only possible on DfuSe images, try convert");
508 return FALSE;
509 }
510
511 /* parse VID */
512 tmp = g_ascii_strtoull (values[1], NULL, 10);
513 if (tmp == 0 || tmp > 0xff) {
514 g_set_error (error,
515 DFU_ERROR,
516 DFU_ERROR_INTERNAL,
517 "Failed to parse alternative setting '%s'",
518 values[1]);
519 return FALSE;
520 }
521 image = dfu_firmware_get_image_default (firmware);
522 if (image == NULL) {
523 g_set_error (error,
524 DFU_ERROR,
525 DFU_ERROR_INTERNAL,
526 "found no image '%s'", values[1]);
527 return FALSE;
528 }
529 dfu_image_set_alt_setting (image, tmp);
530
531 /* write out new file */
532 return dfu_firmware_write_file (firmware,
533 file,
534 priv->cancellable,
535 error);
536 }
537
538 /**
539 * dfu_tool_set_alt_setting_name:
540 **/
541 static gboolean
542 dfu_tool_set_alt_setting_name (DfuToolPrivate *priv, gchar **values, GError **error)
543 {
544 DfuImage *image;
545 g_autoptr(DfuFirmware) firmware = NULL;
546 g_autoptr(GFile) file = NULL;
547
548 /* check args */
549 if (g_strv_length (values) < 2) {
550 g_set_error_literal (error,
551 DFU_ERROR,
552 DFU_ERROR_INTERNAL,
553 "Invalid arguments, expected FILE ALT-NAME"
554 " -- e.g. `firmware.dfu ST");
555 return FALSE;
556 }
557
558 /* open */
559 file = g_file_new_for_path (values[0]);
560 firmware = dfu_firmware_new ();
561 if (!dfu_firmware_parse_file (firmware, file,
562 DFU_FIRMWARE_PARSE_FLAG_NONE,
563 priv->cancellable,
564 error)) {
565 return FALSE;
566 }
567
568 /* doesn't make sense for non-DfuSe */
569 if (dfu_firmware_get_format (firmware) != DFU_FIRMWARE_FORMAT_DFUSE) {
570 g_set_error (error,
571 DFU_ERROR,
572 DFU_ERROR_INTERNAL,
573 "Only possible on DfuSe images, try convert");
574 return FALSE;
575 }
576
577 /* parse VID */
578 image = dfu_firmware_get_image_default (firmware);
579 if (image == NULL) {
580 g_set_error (error,
581 DFU_ERROR,
582 DFU_ERROR_INTERNAL,
583 "found no image '%s'", values[1]);
584 return FALSE;
585 }
586 dfu_image_set_name (image, values[1]);
587
588 /* write out new file */
589 return dfu_firmware_write_file (firmware,
590 file,
591 priv->cancellable,
592 error);
593 }
594
595 /**
596 * dfu_tool_merge:
597 **/
598 static gboolean
599 dfu_tool_merge (DfuToolPrivate *priv, gchar **values, GError **error)
600 {
601 guint16 pid = 0xffff;
602 guint16 rel = 0xffff;
603 guint16 vid = 0xffff;
604 guint i;
605 g_autofree gchar *str_debug = NULL;
606 g_autoptr(DfuFirmware) firmware = NULL;
607 g_autoptr(GFile) file = NULL;
608
609 /* check args */
610 if (g_strv_length (values) < 3) {
611 g_set_error_literal (error,
612 DFU_ERROR,
613 DFU_ERROR_INTERNAL,
614 "Invalid arguments, expected "
615 "FILE-OUT FILE1 FILE2 [FILE3...]"
616 " -- e.g. `combined.dfu lib.dfu app.dfu`");
617 return FALSE;
618 }
619
620 /* parse source files */
621 firmware = dfu_firmware_new ();
622 dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_DFUSE);
623 for (i = 1; values[i] != NULL; i++) {
624 GPtrArray *images;
625 guint j;
626 g_autoptr(GFile) file_tmp = NULL;
627 g_autoptr(DfuFirmware) firmware_tmp = NULL;
628
629 /* open up source */
630 file_tmp = g_file_new_for_path (values[i]);
631 firmware_tmp = dfu_firmware_new ();
632 if (!dfu_firmware_parse_file (firmware_tmp, file_tmp,
633 DFU_FIRMWARE_PARSE_FLAG_NONE,
634 priv->cancellable,
635 error)) {
636 return FALSE;
637 }
638
639 /* check same vid:pid:rel */
640 if (vid != 0xffff &&
641 dfu_firmware_get_vid (firmware_tmp) != vid) {
642 g_set_error (error,
643 DFU_ERROR,
644 DFU_ERROR_INVALID_FILE,
645 "Vendor ID was already set as "
646 "0x%04x, %s is 0x%04x",
647 vid, values[i],
648 dfu_firmware_get_vid (firmware_tmp));
649 return FALSE;
650 }
651 if (pid != 0xffff &&
652 dfu_firmware_get_pid (firmware_tmp) != pid) {
653 g_set_error (error,
654 DFU_ERROR,
655 DFU_ERROR_INVALID_FILE,
656 "Product ID was already set as "
657 "0x%04x, %s is 0x%04x",
658 pid, values[i],
659 dfu_firmware_get_pid (firmware_tmp));
660 return FALSE;
661 }
662 if (rel != 0xffff &&
663 dfu_firmware_get_release (firmware_tmp) != rel) {
664 g_set_error (error,
665 DFU_ERROR,
666 DFU_ERROR_INVALID_FILE,
667 "Release was already set as "
668 "0x%04x, %s is 0x%04x",
669 rel, values[i],
670 dfu_firmware_get_release (firmware_tmp));
671 return FALSE;
672 }
673
674 /* add all images to destination */
675 images = dfu_firmware_get_images (firmware_tmp);
676 for (j = 0; j < images->len; j++) {
677 DfuImage *image;
678 guint alt_id;
679
680 /* verify the alt-setting does not already exist */
681 image = g_ptr_array_index (images, j);
682 alt_id = dfu_image_get_alt_setting (image);
683 g_print ("Adding alternative setting ID of 0x%02x\n",
684 alt_id);
685 if (dfu_firmware_get_image (firmware, alt_id) != NULL) {
686 if (!priv->force) {
687 g_set_error (error,
688 DFU_ERROR,
689 DFU_ERROR_INVALID_FILE,
690 "The alternative setting ID "
691 "of 0x%02x has already been added",
692 alt_id);
693 return FALSE;
694 }
695 g_print ("WARNING: The alternative setting "
696 "ID of 0x%02x has already been added\n",
697 alt_id);
698 }
699
700 /* add to destination */
701 dfu_firmware_add_image (firmware, image);
702 }
703
704 /* save last IDs */
705 vid = dfu_firmware_get_vid (firmware_tmp);
706 pid = dfu_firmware_get_pid (firmware_tmp);
707 rel = dfu_firmware_get_release (firmware_tmp);
708 }
709
710 /* print the new object */
711 str_debug = dfu_firmware_to_string (firmware);
712 g_print ("New merged file:\n%s\n", str_debug);
713
714 /* write out new file */
715 file = g_file_new_for_path (values[0]);
716 return dfu_firmware_write_file (firmware,
717 file,
718 priv->cancellable,
719 error);
720 }
721
722 /**
723 * dfu_tool_convert:
724 **/
725 static gboolean
726 dfu_tool_convert (DfuToolPrivate *priv, gchar **values, GError **error)
727 {
728 guint64 tmp;
729 guint argc = g_strv_length (values);
730 g_autofree gchar *str_debug = NULL;
731 g_autoptr(DfuFirmware) firmware = NULL;
732 g_autoptr(GFile) file_in = NULL;
733 g_autoptr(GFile) file_out = NULL;
734
735 /* check args */
736 if (argc < 3 || argc > 4) {
737 g_set_error_literal (error,
738 DFU_ERROR,
739 DFU_ERROR_INTERNAL,
740 "Invalid arguments, expected "
741 "FORMAT FILE-IN FILE-OUT [SIZE]"
742 " -- e.g. `dfu firmware.hex firmware.dfu 8000`");
743 return FALSE;
744 }
745
746 /* parse file */
747 file_in = g_file_new_for_path (values[1]);
748 file_out = g_file_new_for_path (values[2]);
749 firmware = dfu_firmware_new ();
750 if (!dfu_firmware_parse_file (firmware, file_in,
751 DFU_FIRMWARE_PARSE_FLAG_NONE,
752 priv->cancellable,
753 error)) {
754 return FALSE;
755 }
756
757 /* set output format */
758 if (g_strcmp0 (values[0], "raw") == 0) {
759 dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_RAW);
760 } else if (g_strcmp0 (values[0], "dfu") == 0) {
761 dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_DFU_1_0);
762 } else if (g_strcmp0 (values[0], "dfuse") == 0) {
763 dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_DFUSE);
764 } else if (g_strcmp0 (values[0], "ihex") == 0) {
765 dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_INTEL_HEX);
766 } else {
767 g_set_error (error,
768 DFU_ERROR,
769 DFU_ERROR_INTERNAL,
770 "unknown format '%s', expected [raw|dfu|dfuse|ihex]",
771 values[0]);
772 return FALSE;
773 }
774
775 /* set target size */
776 if (argc > 3) {
777 DfuImage *image;
778 DfuElement *element;
779 gchar *endptr;
780 tmp = g_ascii_strtoull (values[3], &endptr, 16);
781 if (tmp > 0xffff || endptr[0] != '\0') {
782 g_set_error (error,
783 DFU_ERROR,
784 DFU_ERROR_INTERNAL,
785 "Failed to parse target size '%s'",
786 values[3]);
787 return FALSE;
788 }
789
790 /* doesn't make sense for DfuSe */
791 if (dfu_firmware_get_format (firmware) == DFU_FIRMWARE_FORMAT_DFUSE) {
792 g_set_error (error,
793 DFU_ERROR,
794 DFU_ERROR_INTERNAL,
795 "Cannot pad DfuSe image, try DFU");
796 return FALSE;
797 }
798
799 /* this has to exist */
800 if (tmp > 0) {
801 image = dfu_firmware_get_image_default (firmware);
802 g_assert (image != NULL);
803 element = dfu_image_get_element (image, 0);
804 dfu_element_set_target_size (element, tmp);
805 }
806 }
807
808 /* print the new object */
809 str_debug = dfu_firmware_to_string (firmware);
810 g_debug ("DFU: %s", str_debug);
811
812 /* write out new file */
813 return dfu_firmware_write_file (firmware,
814 file_out,
815 priv->cancellable,
816 error);
817 }
818
819 /**
820 * dfu_tool_attach:
821 **/
822 static gboolean
823 dfu_tool_attach (DfuToolPrivate *priv, gchar **values, GError **error)
824 {
825 g_autoptr(DfuDevice) device = NULL;
826
827 device = dfu_tool_get_defalt_device (priv, error);
828 if (device == NULL)
829 return FALSE;
830 if (!dfu_device_open (device,
831 DFU_DEVICE_OPEN_FLAG_NONE,
832 priv->cancellable,
833 error))
834 return FALSE;
835 if (!dfu_device_attach (device, error))
836 return FALSE;
837 return TRUE;
838 }
839
840 typedef struct {
841 guint marks_total;
842 guint marks_shown;
843 DfuState last_state;
844 } DfuToolProgressHelper;
845
846 /**
847 * fu_tool_state_changed_cb:
848 **/
849 static void
850 fu_tool_state_changed_cb (DfuDevice *device,
851 DfuState state,
852 DfuToolProgressHelper *helper)
853 {
854 const gchar *title = NULL;
855 guint i;
856
857 /* changed state */
858 if (state == helper->last_state)
859 return;
860
861 /* state was left hanging... */
862 if (helper->marks_shown == 0) {
863 switch (helper->last_state) {
864 case DFU_STATE_APP_DETACH:
865 case DFU_STATE_DFU_DNLOAD_IDLE:
866 case DFU_STATE_DFU_MANIFEST_WAIT_RESET:
867 case DFU_STATE_DFU_UPLOAD_IDLE:
868 /* TRANSLATORS: when an action has completed */
869 g_print ("%s\n", _("OK"));
870 break;
871 default:
872 g_debug ("ignore last state transition %s",
873 dfu_state_to_string (helper->last_state));
874 break;
875 }
876 }
877
878 switch (state) {
879 case DFU_STATE_APP_DETACH:
880 /* TRANSLATORS: when moving from runtime to DFU mode */
881 title = _("Detaching");
882 break;
883 case DFU_STATE_DFU_MANIFEST_WAIT_RESET:
884 /* TRANSLATORS: when moving from DFU to runtime mode */
885 title = _("Attaching");
886 break;
887 case DFU_STATE_DFU_DNLOAD_IDLE:
888 /* TRANSLATORS: when copying from host to device */
889 title = _("Downloading");
890 break;
891 case DFU_STATE_DFU_UPLOAD_IDLE:
892 /* TRANSLATORS: when copying from device to host */
893 title = _("Uploading");
894 break;
895 default:
896 g_debug ("ignoring %s", dfu_state_to_string (state));
897 break;
898 }
899
900 /* show title and then pad */
901 if (title != NULL) {
902 g_print ("%s ", title);
903 for (i = strlen (title); i < 15; i++)
904 g_print (" ");
905 g_print (": ");
906 }
907
908 /* reset the progress bar */
909 switch (state) {
910 case DFU_STATE_APP_DETACH:
911 case DFU_STATE_DFU_DNLOAD_IDLE:
912 case DFU_STATE_DFU_MANIFEST_WAIT_RESET:
913 case DFU_STATE_DFU_UPLOAD_IDLE:
914 g_debug ("resetting progress bar");
915 helper->marks_shown = 0;
916 break;
917 default:
918 break;
919 }
920
921 /* ignore if the same */
922 helper->last_state = state;
923 }
924
925 /**
926 * fu_tool_percentage_changed_cb:
927 **/
928 static void
929 fu_tool_percentage_changed_cb (DfuDevice *device,
930 guint percentage,
931 DfuToolProgressHelper *helper)
932 {
933 guint marks_now;
934 guint i;
935
936 /* add any sections */
937 marks_now = percentage * helper->marks_total / 100;
938 for (i = helper->marks_shown; i < marks_now; i++)
939 g_print ("#");
940 helper->marks_shown = marks_now;
941
942 /* this state done */
943 if (percentage == 100)
944 g_print ("\n");
945 }
946
947 /**
948 * dfu_tool_read_alt:
949 **/
950 static gboolean
951 dfu_tool_read_alt (DfuToolPrivate *priv, gchar **values, GError **error)
952 {
953 DfuTargetTransferFlags flags = DFU_TARGET_TRANSFER_FLAG_NONE;
954 DfuToolProgressHelper helper;
955 g_autofree gchar *str_debug = NULL;
956 g_autoptr(DfuDevice) device = NULL;
957 g_autoptr(DfuFirmware) firmware = NULL;
958 g_autoptr(DfuImage) image = NULL;
959 g_autoptr(DfuTarget) target = NULL;
960 g_autoptr(GFile) file = NULL;
961
962 /* check args */
963 if (g_strv_length (values) < 2) {
964 g_set_error_literal (error,
965 DFU_ERROR,
966 DFU_ERROR_INTERNAL,
967 "Invalid arguments, expected "
968 "FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID");
969 return FALSE;
970 }
971
972 /* open correct device */
973 device = dfu_tool_get_defalt_device (priv, error);
974 if (device == NULL)
975 return FALSE;
976 if (priv->transfer_size > 0)
977 dfu_device_set_transfer_size (device, priv->transfer_size);
978 if (!dfu_device_open (device,
979 DFU_DEVICE_OPEN_FLAG_NONE,
980 priv->cancellable,
981 error))
982 return FALSE;
983
984 /* set up progress */
985 helper.last_state = DFU_STATE_DFU_ERROR;
986 helper.marks_total = 30;
987 helper.marks_shown = 0;
988 g_signal_connect (device, "state-changed",
989 G_CALLBACK (fu_tool_state_changed_cb), &helper);
990 g_signal_connect (device, "percentage-changed",
991 G_CALLBACK (fu_tool_percentage_changed_cb), &helper);
992
993 /* APP -> DFU */
994 if (dfu_device_get_mode (device) == DFU_MODE_RUNTIME) {
995 g_debug ("detaching");
996 if (!dfu_device_detach (device, priv->cancellable, error))
997 return FALSE;
998 if (!dfu_device_wait_for_replug (device,
999 DFU_DEVICE_REPLUG_TIMEOUT,
1000 priv->cancellable,
1001 error))
1002 return FALSE;
1003
1004 /* put back in same state */
1005 flags |= DFU_TARGET_TRANSFER_FLAG_ATTACH;
1006 flags |= DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME;
1007 }
1008
1009 /* transfer */
1010 target = dfu_device_get_target_by_alt_name (device,
1011 values[1],
1012 NULL);
1013 if (target == NULL) {
1014 gchar *endptr;
1015 guint64 tmp = g_ascii_strtoull (values[1], &endptr, 10);
1016 if (tmp > 0xff || endptr[0] != '\0') {
1017 g_set_error (error,
1018 DFU_ERROR,
1019 DFU_ERROR_INTERNAL,
1020 "Failed to parse alt-setting '%s'",
1021 values[1]);
1022 return FALSE;
1023 }
1024 target = dfu_device_get_target_by_alt_setting (device,
1025 tmp,
1026 error);
1027 if (target == NULL)
1028 return FALSE;
1029 }
1030
1031 /* do transfer */
1032 image = dfu_target_upload (target, flags, priv->cancellable, error);
1033 if (image == NULL)
1034 return FALSE;
1035
1036 /* create new firmware object */
1037 firmware = dfu_firmware_new ();
1038 dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_DFU_1_0);
1039 dfu_firmware_set_vid (firmware, dfu_device_get_runtime_vid (device));
1040 dfu_firmware_set_pid (firmware, dfu_device_get_runtime_pid (device));
1041 dfu_firmware_add_image (firmware, image);
1042
1043 /* save file */
1044 file = g_file_new_for_path (values[0]);
1045 if (!dfu_firmware_write_file (firmware,
1046 file,
1047 priv->cancellable,
1048 error))
1049 return FALSE;
1050
1051 /* print the new object */
1052 str_debug = dfu_firmware_to_string (firmware);
1053 g_debug ("DFU: %s", str_debug);
1054
1055 /* success */
1056 g_print ("%u bytes successfully uploaded from device\n",
1057 dfu_image_get_size (image));
1058 return TRUE;
1059 }
1060
1061 /**
1062 * dfu_tool_read:
1063 **/
1064 static gboolean
1065 dfu_tool_read (DfuToolPrivate *priv, gchar **values, GError **error)
1066 {
1067 DfuTargetTransferFlags flags = DFU_TARGET_TRANSFER_FLAG_NONE;
1068 DfuToolProgressHelper helper;
1069 g_autofree gchar *str_debug = NULL;
1070 g_autoptr(DfuDevice) device = NULL;
1071 g_autoptr(DfuFirmware) firmware = NULL;
1072 g_autoptr(DfuImage) image = NULL;
1073 g_autoptr(GFile) file = NULL;
1074
1075 /* check args */
1076 if (g_strv_length (values) < 1) {
1077 g_set_error_literal (error,
1078 DFU_ERROR,
1079 DFU_ERROR_INTERNAL,
1080 "Invalid arguments, expected FILENAME");
1081 return FALSE;
1082 }
1083
1084 /* open correct device */
1085 device = dfu_tool_get_defalt_device (priv, error);
1086 if (device == NULL)
1087 return FALSE;
1088 if (!dfu_device_open (device,
1089 DFU_DEVICE_OPEN_FLAG_NONE,
1090 priv->cancellable,
1091 error))
1092 return FALSE;
1093
1094 /* optional reset */
1095 if (dfu_device_get_mode (device) == DFU_MODE_RUNTIME) {
1096 flags |= DFU_TARGET_TRANSFER_FLAG_DETACH;
1097 flags |= DFU_TARGET_TRANSFER_FLAG_ATTACH;
1098 flags |= DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME;
1099 }
1100
1101 /* transfer */
1102 helper.last_state = DFU_STATE_DFU_ERROR;
1103 helper.marks_total = 30;
1104 helper.marks_shown = 0;
1105 g_signal_connect (device, "state-changed",
1106 G_CALLBACK (fu_tool_state_changed_cb), &helper);
1107 g_signal_connect (device, "percentage-changed",
1108 G_CALLBACK (fu_tool_percentage_changed_cb), &helper);
1109 firmware = dfu_device_upload (device,
1110 flags,
1111 priv->cancellable,
1112 error);
1113 if (firmware == NULL)
1114 return FALSE;
1115
1116 /* save file */
1117 file = g_file_new_for_path (values[0]);
1118 if (!dfu_firmware_write_file (firmware,
1119 file,
1120 priv->cancellable,
1121 error))
1122 return FALSE;
1123
1124 /* print the new object */
1125 str_debug = dfu_firmware_to_string (firmware);
1126 g_debug ("DFU: %s", str_debug);
1127
1128 /* success */
1129 g_print ("%u bytes successfully uploaded from device\n",
1130 dfu_firmware_get_size (firmware));
1131 return TRUE;
1132 }
1133
1134 /**
1135 * dfu_tool_get_device_string:
1136 **/
1137 static gchar *
1138 dfu_tool_get_device_string (DfuToolPrivate *priv, DfuDevice *device)
1139 {
1140 gchar *dstr;
1141 GUsbDevice *dev;
1142 g_autoptr(GError) error = NULL;
1143
1144 /* open, and get status */
1145 dev = dfu_device_get_usb_dev (device);
1146 if (dev == NULL) {
1147 return g_strdup_printf ("%04x:%04x [%s]",
1148 dfu_device_get_runtime_vid (device),
1149 dfu_device_get_runtime_pid (device),
1150 "removed");
1151 }
1152 if (!dfu_device_open (device,
1153 DFU_DEVICE_OPEN_FLAG_NONE,
1154 priv->cancellable,
1155 &error)) {
1156 return g_strdup_printf ("%04x:%04x [%s]",
1157 g_usb_device_get_vid (dev),
1158 g_usb_device_get_pid (dev),
1159 error->message);
1160 }
1161 dstr = g_strdup_printf ("%04x:%04x [%s:%s]",
1162 g_usb_device_get_vid (dev),
1163 g_usb_device_get_pid (dev),
1164 dfu_state_to_string (dfu_device_get_state (device)),
1165 dfu_status_to_string (dfu_device_get_status (device)));
1166 dfu_device_close (device, NULL);
1167 return dstr;
1168 }
1169
1170 /**
1171 * dfu_tool_device_added_cb:
1172 **/
1173 static void
1174 dfu_tool_device_added_cb (DfuContext *context,
1175 DfuDevice *device,
1176 gpointer user_data)
1177 {
1178 DfuToolPrivate *priv = (DfuToolPrivate *) user_data;
1179 g_autofree gchar *tmp;
1180 tmp = dfu_tool_get_device_string (priv, device);
1181 /* TRANSLATORS: this is when a device is hotplugged */
1182 dfu_tool_print_indent (_("Added"), tmp, 0);
1183 }
1184
1185 /**
1186 * dfu_tool_device_removed_cb:
1187 **/
1188 static void
1189 dfu_tool_device_removed_cb (DfuContext *context,
1190 DfuDevice *device,
1191 gpointer user_data)
1192 {
1193 DfuToolPrivate *priv = (DfuToolPrivate *) user_data;
1194 g_autofree gchar *tmp;
1195 tmp = dfu_tool_get_device_string (priv, device);
1196 /* TRANSLATORS: this is when a device is hotplugged */
1197 dfu_tool_print_indent (_("Removed"), tmp, 0);
1198 }
1199
1200 /**
1201 * dfu_tool_device_changed_cb:
1202 **/
1203 static void
1204 dfu_tool_device_changed_cb (DfuContext *context, DfuDevice *device, gpointer user_data)
1205 {
1206 DfuToolPrivate *priv = (DfuToolPrivate *) user_data;
1207 g_autofree gchar *tmp;
1208 tmp = dfu_tool_get_device_string (priv, device);
1209 /* TRANSLATORS: this is when a device is hotplugged */
1210 dfu_tool_print_indent (_("Changed"), tmp, 0);
1211 }
1212
1213 /**
1214 * dfu_tool_watch_cancelled_cb:
1215 **/
1216 static void
1217 dfu_tool_watch_cancelled_cb (GCancellable *cancellable, gpointer user_data)
1218 {
1219 GMainLoop *loop = (GMainLoop *) user_data;
1220 /* TRANSLATORS: this is when a device ctrl+c's a watch */
1221 g_print ("%s\n", _("Cancelled"));
1222 g_main_loop_quit (loop);
1223 }
1224
1225 /**
1226 * dfu_tool_parse_xtea_key:
1227 **/
1228 static gboolean
1229 dfu_tool_parse_xtea_key (const gchar *key, guint32 *keys, GError **error)
1230 {
1231 guint i;
1232 guint key_len;
1233 g_autofree gchar *key_pad = NULL;
1234
1235 /* too long */
1236 key_len = strlen (key);
1237 if (key_len > 32) {
1238 g_set_error (error,
1239 DFU_ERROR,
1240 DFU_ERROR_NOT_SUPPORTED,
1241 "Key string too long at %i chars, max 16",
1242 key_len);
1243 return FALSE;
1244 }
1245
1246 /* parse 4x32b values or generate a hash */
1247 if (key_len == 32) {
1248 for (i = 0; i < 4; i++) {
1249 gchar buf[] = "xxxxxxxx";
1250 gchar *endptr;
1251 guint64 tmp;
1252
1253 /* copy to 4-char buf (with NUL) */
1254 memcpy (buf, key + i*8, 8);
1255 tmp = g_ascii_strtoull (buf, &endptr, 16);
1256 if (endptr && endptr[0] != '\0') {
1257 g_set_error (error,
1258 DFU_ERROR,
1259 DFU_ERROR_NOT_SUPPORTED,
1260 "Failed to parse key '%s'", key);
1261 return FALSE;
1262 }
1263 keys[3-i] = tmp;
1264 }
1265 } else {
1266 gsize buf_len = 16;
1267 g_autoptr(GChecksum) csum = NULL;
1268 csum = g_checksum_new (G_CHECKSUM_MD5);
1269 g_checksum_update (csum, (const guchar *) key, key_len);
1270 g_checksum_get_digest (csum, (guint8 *) keys, &buf_len);
1271 g_assert (buf_len == 16);
1272 }
1273
1274 /* success */
1275 g_debug ("using XTEA key %04x%04x%04x%04x",
1276 keys[3], keys[2], keys[1], keys[0]);
1277 return TRUE;
1278 }
1279
1280 /**
1281 * dfu_tool_get_firmware_contents_default:
1282 **/
1283 static guint8 *
1284 dfu_tool_get_firmware_contents_default (DfuFirmware *firmware,
1285 gsize *length,
1286 GError **error)
1287 {
1288 DfuElement *element;
1289 DfuImage *image;
1290 GBytes *contents;
1291
1292 image = dfu_firmware_get_image_default (firmware);
1293 if (image == NULL) {
1294 g_set_error_literal (error,
1295 DFU_ERROR,
1296 DFU_ERROR_INTERNAL,
1297 "No default image");
1298 return NULL;
1299 }
1300 element = dfu_image_get_element (image, 0);
1301 if (element == NULL) {
1302 g_set_error_literal (error,
1303 DFU_ERROR,
1304 DFU_ERROR_INTERNAL,
1305 "No default element");
1306 return NULL;
1307 }
1308 contents = dfu_element_get_contents (element);
1309 if (contents == NULL) {
1310 g_set_error_literal (error,
1311 DFU_ERROR,
1312 DFU_ERROR_INTERNAL,
1313 "No image contents");
1314 return NULL;
1315 }
1316 return (guint8 *) g_bytes_get_data (contents, length);
1317 }
1318
1319 #define XTEA_DELTA 0x9e3779b9
1320 #define XTEA_NUM_ROUNDS 32
1321
1322 /**
1323 * dfu_tool_encrypt_xtea:
1324 **/
1325 static void
1326 dfu_tool_encrypt_xtea (const guint32 key[4], guint8 *data, guint16 length)
1327 {
1328 guint32 sum;
1329 guint32 *tmp = (guint32 *) data;
1330 guint32 v0;
1331 guint32 v1;
1332 guint8 i;
1333 guint j;
1334
1335 for (j = 0; j < length / 4; j += 2) {
1336 sum = 0;
1337 v0 = tmp[j];
1338 v1 = tmp[j+1];
1339 for (i = 0; i < XTEA_NUM_ROUNDS; i++) {
1340 v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
1341 sum += XTEA_DELTA;
1342 v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
1343 }
1344 tmp[j] = v0;
1345 tmp[j+1] = v1;
1346 }
1347 }
1348
1349 /**
1350 * dfu_tool_decrypt_xtea:
1351 **/
1352 static void
1353 dfu_tool_decrypt_xtea (const guint32 key[4], guint8 *data, guint16 length)
1354 {
1355 guint32 sum;
1356 guint32 *tmp = (guint32 *) data;
1357 guint32 v0;
1358 guint32 v1;
1359 guint8 i;
1360 guint j;
1361
1362 for (j = 0; j < length / 4; j += 2) {
1363 v0 = tmp[j];
1364 v1 = tmp[j+1];
1365 sum = XTEA_DELTA * XTEA_NUM_ROUNDS;
1366 for (i = 0; i < XTEA_NUM_ROUNDS; i++) {
1367 v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
1368 sum -= XTEA_DELTA;
1369 v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
1370 }
1371 tmp[j] = v0;
1372 tmp[j+1] = v1;
1373 }
1374 }
1375
1376 /**
1377 * dfu_tool_encrypt:
1378 **/
1379 static gboolean
1380 dfu_tool_encrypt (DfuToolPrivate *priv, gchar **values, GError **error)
1381 {
1382 gsize len;
1383 guint8 *data;
1384 g_autoptr(DfuFirmware) firmware = NULL;
1385 g_autoptr(GFile) file_in = NULL;
1386 g_autoptr(GFile) file_out = NULL;
1387
1388 /* check args */
1389 if (g_strv_length (values) < 4) {
1390 g_set_error_literal (error,
1391 DFU_ERROR,
1392 DFU_ERROR_INTERNAL,
1393 "Invalid arguments, expected "
1394 "FILENAME-IN FILENAME-OUT TYPE KEY"
1395 " -- e.g. firmware.dfu firmware.xdfu xtea deadbeef");
1396 return FALSE;
1397 }
1398
1399 /* check extensions */
1400 if (!priv->force) {
1401 if (!g_str_has_suffix (values[0], ".dfu")) {
1402 g_set_error_literal (error,
1403 DFU_ERROR,
1404 DFU_ERROR_NOT_SUPPORTED,
1405 "Invalid filename, expected *.dfu");
1406 return FALSE;
1407 }
1408 if (!g_str_has_suffix (values[1], ".xdfu")) {
1409 g_set_error_literal (error,
1410 DFU_ERROR,
1411 DFU_ERROR_NOT_SUPPORTED,
1412 "Invalid filename, expected *.xdfu");
1413 return FALSE;
1414 }
1415 }
1416
1417 /* open */
1418 file_in = g_file_new_for_path (values[0]);
1419 firmware = dfu_firmware_new ();
1420 if (!dfu_firmware_parse_file (firmware, file_in,
1421 DFU_FIRMWARE_PARSE_FLAG_NONE,
1422 priv->cancellable,
1423 error)) {
1424 return FALSE;
1425 }
1426
1427 /* get data */
1428 data = dfu_tool_get_firmware_contents_default (firmware, &len, error);
1429 if (data == NULL)
1430 return FALSE;
1431
1432 /* check type */
1433 if (g_strcmp0 (values[2], "xtea") == 0) {
1434 guint32 key[4];
1435 if (!dfu_tool_parse_xtea_key (values[3], key, error))
1436 return FALSE;
1437 dfu_tool_encrypt_xtea (key, data, len);
1438 dfu_firmware_set_metadata (firmware,
1439 DFU_METADATA_KEY_CIPHER_KIND,
1440 "XTEA");
1441 } else {
1442 g_set_error (error,
1443 DFU_ERROR,
1444 DFU_ERROR_INTERNAL,
1445 "unknown type '%s', expected [xtea]",
1446 values[2]);
1447 return FALSE;
1448 }
1449
1450 /* write out new file */
1451 file_out = g_file_new_for_path (values[1]);
1452 g_debug ("wrote %s", values[1]);
1453 return dfu_firmware_write_file (firmware,
1454 file_out,
1455 priv->cancellable,
1456 error);
1457 }
1458
1459 /**
1460 * dfu_tool_decrypt:
1461 **/
1462 static gboolean
1463 dfu_tool_decrypt (DfuToolPrivate *priv, gchar **values, GError **error)
1464 {
1465 gsize len;
1466 guint8 *data;
1467 g_autoptr(DfuFirmware) firmware = NULL;
1468 g_autoptr(GFile) file_in = NULL;
1469 g_autoptr(GFile) file_out = NULL;
1470
1471 /* check args */
1472 if (g_strv_length (values) < 4) {
1473 g_set_error_literal (error,
1474 DFU_ERROR,
1475 DFU_ERROR_INTERNAL,
1476 "Invalid arguments, expected "
1477 "FILENAME-IN FILENAME-OUT TYPE KEY"
1478 " -- e.g. firmware.xdfu firmware.dfu xtea deadbeef");
1479 return FALSE;
1480 }
1481
1482 /* check extensions */
1483 if (!priv->force) {
1484 if (!g_str_has_suffix (values[0], ".xdfu")) {
1485 g_set_error_literal (error,
1486 DFU_ERROR,
1487 DFU_ERROR_NOT_SUPPORTED,
1488 "Invalid filename, expected *.xdfu");
1489 return FALSE;
1490 }
1491 if (!g_str_has_suffix (values[1], ".dfu")) {
1492 g_set_error_literal (error,
1493 DFU_ERROR,
1494 DFU_ERROR_NOT_SUPPORTED,
1495 "Invalid filename, expected *.dfu");
1496 return FALSE;
1497 }
1498 }
1499
1500 /* open */
1501 file_in = g_file_new_for_path (values[0]);
1502 firmware = dfu_firmware_new ();
1503 if (!dfu_firmware_parse_file (firmware, file_in,
1504 DFU_FIRMWARE_PARSE_FLAG_NONE,
1505 priv->cancellable,
1506 error)) {
1507 return FALSE;
1508 }
1509
1510 /* get data */
1511 data = dfu_tool_get_firmware_contents_default (firmware, &len, error);
1512 if (data == NULL)
1513 return FALSE;
1514
1515 /* check type */
1516 if (g_strcmp0 (values[2], "xtea") == 0) {
1517 guint32 key[4];
1518 if (!dfu_tool_parse_xtea_key (values[3], key, error))
1519 return FALSE;
1520 dfu_tool_decrypt_xtea (key, data, len);
1521 dfu_firmware_remove_metadata (firmware,
1522 DFU_METADATA_KEY_CIPHER_KIND);
1523 } else {
1524 g_set_error (error,
1525 DFU_ERROR,
1526 DFU_ERROR_INTERNAL,
1527 "unknown type '%s', expected [xtea]",
1528 values[2]);
1529 return FALSE;
1530 }
1531
1532 /* write out new file */
1533 file_out = g_file_new_for_path (values[1]);
1534 g_debug ("wrote %s", values[1]);
1535 return dfu_firmware_write_file (firmware,
1536 file_out,
1537 priv->cancellable,
1538 error);
1539 }
1540
1541 /**
1542 * dfu_tool_watch:
1543 **/
1544 static gboolean
1545 dfu_tool_watch (DfuToolPrivate *priv, gchar **values, GError **error)
1546 {
1547 guint i;
1548 DfuDevice *device;
1549 g_autoptr(DfuContext) dfu_context = NULL;
1550 g_autoptr(GMainLoop) loop = NULL;
1551 g_autoptr(GPtrArray) devices = NULL;
1552
1553 /* get all the DFU devices */
1554 dfu_context = dfu_context_new ();
1555 dfu_context_enumerate (dfu_context, NULL);
1556
1557 /* print what's already attached */
1558 devices = dfu_context_get_devices (dfu_context);
1559 for (i = 0; i < devices->len; i++) {
1560 device = g_ptr_array_index (devices, i);
1561 dfu_tool_device_added_cb (dfu_context, device, priv);
1562 }
1563
1564 /* watch for any hotplugged device */
1565 loop = g_main_loop_new (NULL, FALSE);
1566 g_signal_connect (dfu_context, "device-added",
1567 G_CALLBACK (dfu_tool_device_added_cb), priv);
1568 g_signal_connect (dfu_context, "device-removed",
1569 G_CALLBACK (dfu_tool_device_removed_cb), priv);
1570 g_signal_connect (dfu_context, "device-changed",
1571 G_CALLBACK (dfu_tool_device_changed_cb), priv);
1572 g_signal_connect (priv->cancellable, "cancelled",
1573 G_CALLBACK (dfu_tool_watch_cancelled_cb), loop);
1574 g_main_loop_run (loop);
1575 return TRUE;
1576 }
1577
1578 /**
1579 * dfu_tool_dump:
1580 **/
1581 static gboolean
1582 dfu_tool_dump (DfuToolPrivate *priv, gchar **values, GError **error)
1583 {
1584 DfuFirmwareParseFlags flags = DFU_FIRMWARE_PARSE_FLAG_NONE;
1585 guint i;
1586
1587 /* check args */
1588 if (g_strv_length (values) < 1) {
1589 g_set_error_literal (error,
1590 DFU_ERROR,
1591 DFU_ERROR_INTERNAL,
1592 "Invalid arguments, expected FILENAME");
1593 return FALSE;
1594 }
1595
1596 /* dump corrupt files */
1597 if (priv->force) {
1598 flags |= DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST;
1599 flags |= DFU_FIRMWARE_PARSE_FLAG_NO_VERSION_TEST;
1600 }
1601
1602 /* open files */
1603 for (i = 0; values[i] != NULL; i++) {
1604 g_autoptr(DfuFirmware) firmware = NULL;
1605 g_autoptr(GFile) file = NULL;
1606 g_autoptr(GError) error_local = NULL;
1607
1608 /* dump to screen */
1609 g_print ("Loading %s:\n", values[i]);
1610 firmware = dfu_firmware_new ();
1611 file = g_file_new_for_path (values[i]);
1612 if (!dfu_firmware_parse_file (firmware, file, flags,
1613 priv->cancellable,
1614 &error_local)) {
1615 g_print ("Failed to load firmware: %s\n",
1616 error_local->message);
1617 continue;
1618 }
1619 g_print ("%s\n", dfu_firmware_to_string (firmware));
1620 }
1621 return TRUE;
1622 }
1623
1624 /**
1625 * dfu_tool_write_alt:
1626 **/
1627 static gboolean
1628 dfu_tool_write_alt (DfuToolPrivate *priv, gchar **values, GError **error)
1629 {
1630 DfuImage *image;
1631 DfuTargetTransferFlags flags = DFU_TARGET_TRANSFER_FLAG_VERIFY;
1632 DfuToolProgressHelper helper;
1633 g_autofree gchar *str_debug = NULL;
1634 g_autoptr(DfuDevice) device = NULL;
1635 g_autoptr(DfuFirmware) firmware = NULL;
1636 g_autoptr(DfuTarget) target = NULL;
1637 g_autoptr(GFile) file = NULL;
1638
1639 /* check args */
1640 if (g_strv_length (values) < 2) {
1641 g_set_error_literal (error,
1642 DFU_ERROR,
1643 DFU_ERROR_INTERNAL,
1644 "Invalid arguments, expected "
1645 "FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID "
1646 "[IMAGE-ALT-NAME|IMAGE-ALT-ID]");
1647 return FALSE;
1648 }
1649
1650 /* open file */
1651 firmware = dfu_firmware_new ();
1652 file = g_file_new_for_path (values[0]);
1653 if (!dfu_firmware_parse_file (firmware, file,
1654 DFU_FIRMWARE_PARSE_FLAG_NONE,
1655 priv->cancellable, error))
1656 return FALSE;
1657
1658 /* open correct device */
1659 device = dfu_tool_get_defalt_device (priv, error);
1660 if (device == NULL)
1661 return FALSE;
1662 if (priv->transfer_size > 0)
1663 dfu_device_set_transfer_size (device, priv->transfer_size);
1664 if (!dfu_device_open (device,
1665 DFU_DEVICE_OPEN_FLAG_NONE,
1666 priv->cancellable,
1667 error))
1668 return FALSE;
1669
1670 /* set up progress */
1671 helper.last_state = DFU_STATE_DFU_ERROR;
1672 helper.marks_total = 30;
1673 helper.marks_shown = 0;
1674 g_signal_connect (device, "state-changed",
1675 G_CALLBACK (fu_tool_state_changed_cb), &helper);
1676 g_signal_connect (device, "percentage-changed",
1677 G_CALLBACK (fu_tool_percentage_changed_cb), &helper);
1678
1679 /* APP -> DFU */
1680 if (dfu_device_get_mode (device) == DFU_MODE_RUNTIME) {
1681 g_debug ("detaching");
1682 if (!dfu_device_detach (device, priv->cancellable, error))
1683 return FALSE;
1684 if (!dfu_device_wait_for_replug (device, 5000, priv->cancellable, error))
1685 return FALSE;
1686
1687 /* put back in same state */
1688 flags |= DFU_TARGET_TRANSFER_FLAG_ATTACH;
1689 flags |= DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME;
1690 }
1691
1692 /* print the new object */
1693 str_debug = dfu_firmware_to_string (firmware);
1694 g_debug ("DFU: %s", str_debug);
1695
1696 /* get correct target on device */
1697 target = dfu_device_get_target_by_alt_name (device,
1698 values[1],
1699 NULL);
1700 if (target == NULL) {
1701 gchar *endptr;
1702 guint64 tmp = g_ascii_strtoull (values[1], &endptr, 10);
1703 if (tmp > 0xff || endptr[0] != '\0') {
1704 g_set_error (error,
1705 DFU_ERROR,
1706 DFU_ERROR_INTERNAL,
1707 "Failed to parse alt-setting '%s'",
1708 values[1]);
1709 return FALSE;
1710 }
1711 target = dfu_device_get_target_by_alt_setting (device,
1712 tmp,
1713 error);
1714 if (target == NULL)
1715 return FALSE;
1716 }
1717
1718 /* allow overriding the firmware alt-setting */
1719 if (g_strv_length (values) > 2) {
1720 image = dfu_firmware_get_image_by_name (firmware, values[2]);
1721 if (image == NULL) {
1722 gchar *endptr;
1723 guint64 tmp = g_ascii_strtoull (values[2], &endptr, 10);
1724 if (tmp > 0xff || endptr[0] != '\0') {
1725 g_set_error (error,
1726 DFU_ERROR,
1727 DFU_ERROR_INTERNAL,
1728 "Failed to parse image alt-setting '%s'",
1729 values[2]);
1730 return FALSE;
1731 }
1732 image = dfu_firmware_get_image (firmware, tmp);
1733 if (image == NULL) {
1734 g_set_error (error,
1735 DFU_ERROR,
1736 DFU_ERROR_INVALID_FILE,
1737 "could not locate image in firmware for %02x",
1738 (guint) tmp);
1739 return FALSE;
1740 }
1741 }
1742 } else {
1743 g_print ("WARNING: Using default firmware image\n");
1744 image = dfu_firmware_get_image_default (firmware);
1745 if (image == NULL) {
1746 g_set_error_literal (error,
1747 DFU_ERROR,
1748 DFU_ERROR_INVALID_FILE,
1749 "no default image");
1750 return FALSE;
1751 }
1752 }
1753
1754 /* allow forcing firmware kinds */
1755 if (priv->force) {
1756 flags |= DFU_TARGET_TRANSFER_FLAG_ANY_CIPHER;
1757 }
1758
1759 /* transfer */
1760 if (!dfu_target_download (target,
1761 image,
1762 flags,
1763 priv->cancellable,
1764 error))
1765 return FALSE;
1766
1767 /* success */
1768 g_print ("%u bytes successfully downloaded to device\n",
1769 dfu_image_get_size (image));
1770 return TRUE;
1771 }
1772
1773 /**
1774 * dfu_tool_write:
1775 **/
1776 static gboolean
1777 dfu_tool_write (DfuToolPrivate *priv, gchar **values, GError **error)
1778 {
1779 DfuTargetTransferFlags flags = DFU_TARGET_TRANSFER_FLAG_VERIFY;
1780 DfuToolProgressHelper helper;
1781 g_autofree gchar *str_debug = NULL;
1782 g_autoptr(DfuDevice) device = NULL;
1783 g_autoptr(DfuFirmware) firmware = NULL;
1784 g_autoptr(GFile) file = NULL;
1785
1786 /* check args */
1787 if (g_strv_length (values) < 1) {
1788 g_set_error_literal (error,
1789 DFU_ERROR,
1790 DFU_ERROR_INTERNAL,
1791 "Invalid arguments, expected FILENAME");
1792 return FALSE;
1793 }
1794
1795 /* open file */
1796 firmware = dfu_firmware_new ();
1797 file = g_file_new_for_path (values[0]);
1798 if (!dfu_firmware_parse_file (firmware, file,
1799 DFU_FIRMWARE_PARSE_FLAG_NONE,
1800 priv->cancellable, error))
1801 return FALSE;
1802
1803 /* open correct device */
1804 device = dfu_tool_get_defalt_device (priv, error);
1805 if (device == NULL)
1806 return FALSE;
1807 if (!dfu_device_open (device,
1808 DFU_DEVICE_OPEN_FLAG_NONE,
1809 priv->cancellable,
1810 error))
1811 return FALSE;
1812
1813 /* print the new object */
1814 str_debug = dfu_firmware_to_string (firmware);
1815 g_debug ("DFU: %s", str_debug);
1816
1817 /* put in correct mode */
1818 if (dfu_device_get_mode (device) == DFU_MODE_RUNTIME) {
1819 flags |= DFU_TARGET_TRANSFER_FLAG_DETACH;
1820 flags |= DFU_TARGET_TRANSFER_FLAG_ATTACH;
1821 flags |= DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME;
1822 }
1823
1824 /* allow wildcards */
1825 if (priv->force) {
1826 flags |= DFU_TARGET_TRANSFER_FLAG_WILDCARD_VID;
1827 flags |= DFU_TARGET_TRANSFER_FLAG_WILDCARD_PID;
1828 flags |= DFU_TARGET_TRANSFER_FLAG_ANY_CIPHER;
1829 }
1830
1831 /* transfer */
1832 helper.last_state = DFU_STATE_DFU_ERROR;
1833 helper.marks_total = 30;
1834 helper.marks_shown = 0;
1835 g_signal_connect (device, "state-changed",
1836 G_CALLBACK (fu_tool_state_changed_cb), &helper);
1837 g_signal_connect (device, "percentage-changed",
1838 G_CALLBACK (fu_tool_percentage_changed_cb), &helper);
1839 if (!dfu_device_download (device,
1840 firmware,
1841 flags,
1842 priv->cancellable,
1843 error))
1844 return FALSE;
1845
1846 /* success */
1847 g_print ("%u bytes successfully downloaded to device\n",
1848 dfu_firmware_get_size (firmware));
1849 return TRUE;
1850 }
1851
1852 /**
1853 * dfu_tool_list_target:
1854 **/
1855 static void
1856 dfu_tool_list_target (DfuTarget *target)
1857 {
1858 DfuCipherKind cipher_kind;
1859 GPtrArray *sectors;
1860 const gchar *tmp;
1861 guint i;
1862 g_autofree gchar *alt_id = NULL;
1863 g_autoptr(GError) error_local = NULL;
1864
1865 /* TRANSLATORS: the identifier name please */
1866 alt_id = g_strdup_printf ("%i", dfu_target_get_alt_setting (target));
1867 dfu_tool_print_indent (_("ID"), alt_id, 1);
1868
1869 /* this is optional */
1870 tmp = dfu_target_get_alt_name (target, NULL);
1871 if (tmp != NULL) {
1872 /* TRANSLATORS: interface name, e.g. "Flash" */
1873 dfu_tool_print_indent (_("Name"), tmp, 2);
1874 }
1875
1876 cipher_kind = dfu_target_get_cipher_kind (target);
1877 /* TRANSLATORS: this is the encryption method used when writing */
1878 dfu_tool_print_indent (_("Cipher"), dfu_cipher_kind_to_string (cipher_kind), 2);
1879
1880 /* print sector information */
1881 sectors = dfu_target_get_sectors (target);
1882 for (i = 0; i < sectors->len; i++) {
1883 DfuSector *sector;
1884 g_autofree gchar *msg = NULL;
1885 g_autofree gchar *title = NULL;
1886 sector = g_ptr_array_index (sectors, i);
1887 msg = dfu_sector_to_string (sector);
1888 /* TRANSLATORS: these are areas of memory on the chip */
1889 title = g_strdup_printf ("%s 0x%02x", _("Region"), i);
1890 dfu_tool_print_indent (title, msg, 2);
1891 }
1892 }
1893
1894 /**
1895 * dfu_tool_list:
1896 **/
1897 static gboolean
1898 dfu_tool_list (DfuToolPrivate *priv, gchar **values, GError **error)
1899 {
1900 guint i;
1901 g_autoptr(DfuContext) dfu_context = NULL;
1902 g_autoptr(GPtrArray) devices = NULL;
1903
1904 /* get all the connected USB devices */
1905 dfu_context = dfu_context_new ();
1906 dfu_context_enumerate (dfu_context, NULL);
1907 devices = dfu_context_get_devices (dfu_context);
1908 for (i = 0; i < devices->len; i++) {
1909 DfuDevice *device = NULL;
1910 DfuTarget *target;
1911 GUsbDevice *dev;
1912 GPtrArray *dfu_targets;
1913 const gchar *tmp;
1914 guint j;
1915 g_autofree gchar *quirks = NULL;
1916 g_autofree gchar *version = NULL;
1917 g_autoptr(GError) error_local = NULL;
1918
1919 /* device specific */
1920 device = g_ptr_array_index (devices, i);
1921 dev = dfu_device_get_usb_dev (device);
1922 version = as_utils_version_from_uint16 (g_usb_device_get_release (dev),
1923 AS_VERSION_PARSE_FLAG_NONE);
1924 g_print ("%s %04x:%04x [v%s]:\n",
1925 /* TRANSLATORS: detected a DFU device */
1926 _("Found"),
1927 g_usb_device_get_vid (dev),
1928 g_usb_device_get_pid (dev),
1929 version);
1930
1931 /* open */
1932 if (!dfu_device_open (device,
1933 DFU_DEVICE_OPEN_FLAG_NONE,
1934 priv->cancellable,
1935 &error_local)) {
1936 if (g_error_matches (error_local,
1937 DFU_ERROR,
1938 DFU_ERROR_PERMISSION_DENIED)) {
1939 /* TRANSLATORS: probably not run as root... */
1940 dfu_tool_print_indent (_("Status"), _("Unknown: permission denied"), 2);
1941 } else {
1942 /* TRANSLATORS: device has failed to report status */
1943 dfu_tool_print_indent (_("Status"), error_local->message, 2);
1944 }
1945 continue;
1946 }
1947
1948 tmp = dfu_mode_to_string (dfu_device_get_mode (device));
1949 /* TRANSLATORS: device mode, e.g. runtime or DFU */
1950 dfu_tool_print_indent (_("Mode"), tmp, 1);
1951
1952 tmp = dfu_status_to_string (dfu_device_get_status (device));
1953 /* TRANSLATORS: device status, e.g. "OK" */
1954 dfu_tool_print_indent (_("Status"), tmp, 1);
1955
1956 tmp = dfu_state_to_string (dfu_device_get_state (device));
1957 /* TRANSLATORS: device state, i.e. appIDLE */
1958 dfu_tool_print_indent (_("State"), tmp, 1);
1959
1960 /* quirks are NULL if none are set */
1961 quirks = dfu_device_get_quirks_as_string (device);
1962 if (quirks != NULL) {
1963 /* TRANSLATORS: device quirks, i.e. things that
1964 * it does that we have to work around */
1965 dfu_tool_print_indent (_("Quirks"), quirks, 1);
1966 }
1967
1968 /* list targets */
1969 dfu_targets = dfu_device_get_targets (device);
1970 for (j = 0; j < dfu_targets->len; j++) {
1971 target = g_ptr_array_index (dfu_targets, j);
1972 dfu_tool_list_target (target);
1973 }
1974 }
1975 return TRUE;
1976 }
1977
1978 /**
1979 * dfu_tool_detach:
1980 **/
1981 static gboolean
1982 dfu_tool_detach (DfuToolPrivate *priv, gchar **values, GError **error)
1983 {
1984 g_autoptr(DfuDevice) device = NULL;
1985
1986 /* open correct device */
1987 device = dfu_tool_get_defalt_device (priv, error);
1988 if (device == NULL)
1989 return FALSE;
1990 if (priv->transfer_size > 0)
1991 dfu_device_set_transfer_size (device, priv->transfer_size);
1992
1993 /* detatch */
1994 if (!dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE,
1995 priv->cancellable, error))
1996 return FALSE;
1997 if (!dfu_device_detach (device, priv->cancellable, error))
1998 return FALSE;
1999 return TRUE;
2000 }
2001
2002 /**
2003 * dfu_tool_sigint_cb:
2004 **/
2005 static gboolean
2006 dfu_tool_sigint_cb (gpointer user_data)
2007 {
2008 DfuToolPrivate *priv = (DfuToolPrivate *) user_data;
2009 g_debug ("Handling SIGINT");
2010 g_cancellable_cancel (priv->cancellable);
2011 return FALSE;
2012 }
2013
2014 /**
2015 * main:
2016 **/
2017 int
2018 main (int argc, char *argv[])
2019 {
2020 gboolean ret;
2021 gboolean verbose = FALSE;
2022 gboolean version = FALSE;
2023 g_autofree gchar *cmd_descriptions = NULL;
2024 g_autoptr(DfuToolPrivate) priv = g_new0 (DfuToolPrivate, 1);
2025 g_autoptr(GError) error = NULL;
2026 g_autoptr(GOptionContext) context = NULL;
2027 const GOptionEntry options[] = {
2028 { "version", '\0', 0, G_OPTION_ARG_NONE, &version,
2029 "Print the version number", NULL },
2030 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
2031 "Print verbose debug statements", NULL },
2032 { "device", 'd', 0, G_OPTION_ARG_STRING, &priv->device_vid_pid,
2033 "Specify Vendor/Product ID(s) of DFU device", "VID:PID" },
2034 { "transfer-size", 't', 0, G_OPTION_ARG_STRING, &priv->transfer_size,
2035 "Specify the number of bytes per USB transfer", "BYTES" },
2036 { "force", '\0', 0, G_OPTION_ARG_NONE, &priv->force,
2037 "Force the action ignoring all warnings", NULL },
2038 { NULL}
2039 };
2040
2041 setlocale (LC_ALL, "");
2042
2043 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
2044 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
2045 textdomain (GETTEXT_PACKAGE);
2046
2047 /* add commands */
2048 priv->cmd_array = g_ptr_array_new_with_free_func ((GDestroyNotify) dfu_tool_item_free);
2049 dfu_tool_add (priv->cmd_array,
2050 "convert",
2051 NULL,
2052 /* TRANSLATORS: command description */
2053 _("Convert firmware to DFU format"),
2054 dfu_tool_convert);
2055 dfu_tool_add (priv->cmd_array,
2056 "merge",
2057 NULL,
2058 /* TRANSLATORS: command description */
2059 _("Merge multiple firmware files into one"),
2060 dfu_tool_merge);
2061 dfu_tool_add (priv->cmd_array,
2062 "set-vendor",
2063 NULL,
2064 /* TRANSLATORS: command description */
2065 _("Set vendor ID on firmware file"),
2066 dfu_tool_set_vendor);
2067 dfu_tool_add (priv->cmd_array,
2068 "set-product",
2069 NULL,
2070 /* TRANSLATORS: command description */
2071 _("Set product ID on firmware file"),
2072 dfu_tool_set_product);
2073 dfu_tool_add (priv->cmd_array,
2074 "set-release",
2075 NULL,
2076 /* TRANSLATORS: command description */
2077 _("Set release version on firmware file"),
2078 dfu_tool_set_release);
2079 dfu_tool_add (priv->cmd_array,
2080 "set-alt-setting",
2081 NULL,
2082 /* TRANSLATORS: command description */
2083 _("Set alternative number on firmware file"),
2084 dfu_tool_set_alt_setting);
2085 dfu_tool_add (priv->cmd_array,
2086 "set-alt-setting-name",
2087 NULL,
2088 /* TRANSLATORS: command description */
2089 _("Set alternative name on firmware file"),
2090 dfu_tool_set_alt_setting_name);
2091 dfu_tool_add (priv->cmd_array,
2092 "attach",
2093 NULL,
2094 /* TRANSLATORS: command description */
2095 _("Attach DFU capable device back to runtime"),
2096 dfu_tool_attach);
2097 dfu_tool_add (priv->cmd_array,
2098 "read",
2099 NULL,
2100 /* TRANSLATORS: command description */
2101 _("Read firmware from device into a file"),
2102 dfu_tool_read);
2103 dfu_tool_add (priv->cmd_array,
2104 "read-alt",
2105 NULL,
2106 /* TRANSLATORS: command description */
2107 _("Read firmware from one partition into a file"),
2108 dfu_tool_read_alt);
2109 dfu_tool_add (priv->cmd_array,
2110 "write",
2111 NULL,
2112 /* TRANSLATORS: command description */
2113 _("Write firmware from file into device"),
2114 dfu_tool_write);
2115 dfu_tool_add (priv->cmd_array,
2116 "write-alt",
2117 NULL,
2118 /* TRANSLATORS: command description */
2119 _("Write firmware from file into one partition"),
2120 dfu_tool_write_alt);
2121 dfu_tool_add (priv->cmd_array,
2122 "list",
2123 NULL,
2124 /* TRANSLATORS: command description */
2125 _("List currently attached DFU capable devices"),
2126 dfu_tool_list);
2127 dfu_tool_add (priv->cmd_array,
2128 "detach",
2129 NULL,
2130 /* TRANSLATORS: command description */
2131 _("Detach currently attached DFU capable device"),
2132 dfu_tool_detach);
2133 dfu_tool_add (priv->cmd_array,
2134 "dump",
2135 NULL,
2136 /* TRANSLATORS: command description */
2137 _("Dump details about a firmware file"),
2138 dfu_tool_dump);
2139 dfu_tool_add (priv->cmd_array,
2140 "watch",
2141 NULL,
2142 /* TRANSLATORS: command description */
2143 _("Watch DFU devices being hotplugged"),
2144 dfu_tool_watch);
2145 dfu_tool_add (priv->cmd_array,
2146 "encrypt",
2147 NULL,
2148 /* TRANSLATORS: command description */
2149 _("Encrypt firmware data"),
2150 dfu_tool_encrypt);
2151 dfu_tool_add (priv->cmd_array,
2152 "decrypt",
2153 NULL,
2154 /* TRANSLATORS: command description */
2155 _("Decrypt firmware data"),
2156 dfu_tool_decrypt);
2157 dfu_tool_add (priv->cmd_array,
2158 "set-metadata",
2159 NULL,
2160 /* TRANSLATORS: command description */
2161 _("Sets metadata on a firmware file"),
2162 dfu_tool_set_metadata);
2163
2164 /* do stuff on ctrl+c */
2165 priv->cancellable = g_cancellable_new ();
2166 g_unix_signal_add_full (G_PRIORITY_DEFAULT,
2167 SIGINT,
2168 dfu_tool_sigint_cb,
2169 priv,
2170 NULL);
2171
2172 /* sort by command name */
2173 g_ptr_array_sort (priv->cmd_array,
2174 (GCompareFunc) dfu_tool_sort_command_name_cb);
2175
2176 /* get a list of the commands */
2177 context = g_option_context_new (NULL);
2178 cmd_descriptions = dfu_tool_get_descriptions (priv->cmd_array);
2179 g_option_context_set_summary (context, cmd_descriptions);
2180
2181 /* TRANSLATORS: DFU stands for device firmware update */
2182 g_set_application_name (_("DFU Utility"));
2183 g_option_context_add_main_entries (context, options, NULL);
2184 ret = g_option_context_parse (context, &argc, &argv, &error);
2185 if (!ret) {
2186 /* TRANSLATORS: the user didn't read the man page */
2187 g_print ("%s: %s\n", _("Failed to parse arguments"), error->message);
2188 return EXIT_FAILURE;
2189 }
2190
2191 /* set verbose? */
2192 if (verbose)
2193 g_setenv ("G_MESSAGES_DEBUG", "all", FALSE);
2194
2195 /* version */
2196 if (version) {
2197 g_print ("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
2198 return EXIT_SUCCESS;
2199 }
2200
2201 /* run the specified command */
2202 ret = dfu_tool_run (priv, argv[1], (gchar**) &argv[2], &error);
2203 if (!ret) {
2204 if (g_error_matches (error, DFU_ERROR, DFU_ERROR_INTERNAL)) {
2205 g_autofree gchar *tmp = NULL;
2206 tmp = g_option_context_get_help (context, TRUE, NULL);
2207 g_print ("%s\n\n%s", error->message, tmp);
2208 } else {
2209 g_print ("%s\n", error->message);
2210 }
2211 return EXIT_FAILURE;
2212 }
2213
2214 /* success/ */
2215 return EXIT_SUCCESS;
2216 }
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /**
22 * SECTION:dfu
23 * @short_description: Helper objects for interacting with DFU devices.
24 */
25
26 #ifndef __DFU_H__
27 #define __DFU_H__
28
29 #define __DFU_H_INSIDE__
30
31 #include <libdfu/dfu-common.h>
32 #include <libdfu/dfu-context.h>
33 #include <libdfu/dfu-device.h>
34 #include <libdfu/dfu-element.h>
35 #include <libdfu/dfu-error.h>
36 #include <libdfu/dfu-firmware.h>
37 #include <libdfu/dfu-image.h>
38 #include <libdfu/dfu-sector.h>
39 #include <libdfu/dfu-target.h>
40
41 #undef __DFU_H_INSIDE__
42
43 #endif /* __DFU_H__ */
44
0 prefix=@prefix@
1 exec_prefix=@exec_prefix@
2 libdir=@libdir@
3 includedir=@includedir@
4
5 Name: dfu
6 Description: libdfu is a library for reading and writing USB device firmware
7 Version: @VERSION@
8 Requires: glib-2.0, gobject-2.0, gio-2.0
9 Libs: -L${libdir} -ldfu
10 Cflags: -I${includedir}/fwupd-1
0 #!/usr/bin/python
1
2 # Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 # Licensed under the GNU General Public License Version 2
4
5 import gi
6 gi.require_version('Dfu', '1.0')
7
8 from gi.repository import Dfu
9 from gi.repository import Gio
10
11 cancellable = Gio.Cancellable.new()
12 ctx = Dfu.Context.new()
13 ctx.enumerate()
14
15 for dev in ctx.get_devices():
16
17 # print details about the device
18 dev.open(Dfu.DeviceOpenFlags.NONE, cancellable)
19 print "getting firmware from %s:%s" % (dev.get_state(), dev.get_status())
20
21 # transfer firmware from device to host and show summary
22 fw = dev.upload(Dfu.TargetTransferFlags.DETACH, cancellable)
23 print fw.to_string()
Binary diff not shown
0 :044000003DEF20F080
1 :10400800FACF01F0FBCF02F0E9CF03F0EACF04F0DA
2 :10401800E1CF05F0E2CF06F0D9CF07F0DACF08F00C
3 :10402800F3CF09F0F4CF0AF0F6CF0BF0F7CF0CF08E
4 :10403800F8CF0DF0F5CF0EF00EC0F5FF0DC0F8FF6C
5 :104048000CC0F7FF0BC0F6FF0AC0F4FF09C0F3FF6E
6 :1040580008C0DAFF07C0D9FF06C0E2FF05C0E1FFCC
7 :1040680004C0EAFF03C0E9FF02C0FBFF01C0FAFF7A
8 :1040780011003FEF20F0000142EF20F03DEF20F06B
9 :00000001FF
0 CC=afl-gcc ./configure --disable-shared
1 AFL_HARDEN=1 make
2 afl-fuzz -m 300 -i fuzzing -o findings ./dfu-tool dump @@
00 policy/org.freedesktop.fwupd.policy.in
1 libdfu/dfu-tool.c
12 src/fu-debug.c
23 src/fu-main.c
34 src/fu-util.c
77 msgstr ""
88 "Project-Id-Version: fwupd\n"
99 "Report-Msgid-Bugs-To: \n"
10 "POT-Creation-Date: 2015-09-10 09:28+0100\n"
11 "PO-Revision-Date: 2015-09-10 08:28+0000\n"
10 "POT-Creation-Date: 2015-12-07 12:22+0000\n"
11 "PO-Revision-Date: 2015-12-07 12:22+0000\n"
1212 "Last-Translator: Richard Hughes <richard@hughsie.com>\n"
1313 "Language-Team: German (http://www.transifex.com/hughsie/fwupd/language/de/)\n"
1414 "MIME-Version: 1.0\n"
5050 "Authentication is required to downgrade the firmware on a removable device"
5151 msgstr ""
5252
53 #. TRANSLATORS: turn on all debugging
54 msgid "Show debugging information for all files"
55 msgstr "Debuginformationen für alle Dateien anzeigen"
56
57 #. TRANSLATORS: for the --verbose arg
58 msgid "Debugging Options"
59 msgstr "Debug Optionen"
60
61 #. TRANSLATORS: for the --verbose arg
62 msgid "Show debugging options"
63 msgstr "Debug Optionen anzeigen"
64
65 #. TRANSLATORS: exit after we've started up, used for user profiling
66 msgid "Exit after a small delay"
67 msgstr "Verlassen nach einer kurzen Verzögerung"
68
69 #. TRANSLATORS: exit straight away, used for automatic profiling
70 msgid "Exit after the engine has loaded"
71 msgstr ""
72
73 #. TRANSLATORS: program name
74 msgid "Firmware Update Daemon"
75 msgstr ""
76
77 #. TRANSLATORS: program summary
78 msgid "Firmware Update D-Bus Service"
79 msgstr ""
80
8153 #. TRANSLATORS: this is a command alias, e.g. 'get-devices'
8254 #, c-format
8355 msgid "Alias to %s"
8557
8658 #. TRANSLATORS: error message
8759 msgid "Command not found"
60 msgstr ""
61
62 #. TRANSLATORS: when an action has completed
63 msgid "OK"
64 msgstr ""
65
66 #. TRANSLATORS: when moving from runtime to DFU mode
67 msgid "Detaching"
68 msgstr ""
69
70 #. TRANSLATORS: when moving from DFU to runtime mode
71 msgid "Attaching"
72 msgstr ""
73
74 #. TRANSLATORS: when copying from host to device
75 msgid "Downloading"
76 msgstr ""
77
78 #. TRANSLATORS: when copying from device to host
79 msgid "Uploading"
80 msgstr ""
81
82 #. TRANSLATORS: this is when a device is hotplugged
83 msgid "Added"
84 msgstr ""
85
86 #. TRANSLATORS: this is when a device is hotplugged
87 msgid "Removed"
88 msgstr ""
89
90 #. TRANSLATORS: this is when a device is hotplugged
91 msgid "Changed"
92 msgstr ""
93
94 #. TRANSLATORS: this is when a device ctrl+c's a watch
95 msgid "Cancelled"
96 msgstr ""
97
98 #. TRANSLATORS: Appstream ID for the hardware type
99 msgid "ID"
100 msgstr ""
101
102 #. TRANSLATORS: interface name, e.g. "Flash"
103 msgid "Name"
104 msgstr ""
105
106 #. TRANSLATORS: this is the encryption method used when writing
107 msgid "Cipher"
108 msgstr ""
109
110 #. TRANSLATORS: these are areas of memory on the chip
111 msgid "Region"
112 msgstr ""
113
114 #. TRANSLATORS: detected a DFU device
115 msgid "Found"
116 msgstr ""
117
118 #. TRANSLATORS: probably not run as root...
119 #. TRANSLATORS: device has failed to report status
120 #. TRANSLATORS: device status, e.g. "OK"
121 msgid "Status"
122 msgstr ""
123
124 msgid "Unknown: permission denied"
125 msgstr ""
126
127 #. TRANSLATORS: device mode, e.g. runtime or DFU
128 msgid "Mode"
129 msgstr ""
130
131 #. TRANSLATORS: device state, i.e. appIDLE
132 msgid "State"
133 msgstr ""
134
135 #. TRANSLATORS: device quirks, i.e. things that
136 #. * it does that we have to work around
137 msgid "Quirks"
138 msgstr ""
139
140 #. TRANSLATORS: command description
141 msgid "Convert firmware to DFU format"
142 msgstr ""
143
144 #. TRANSLATORS: command description
145 msgid "Merge multiple firmware files into one"
146 msgstr ""
147
148 #. TRANSLATORS: command description
149 msgid "Set vendor ID on firmware file"
150 msgstr ""
151
152 #. TRANSLATORS: command description
153 msgid "Set product ID on firmware file"
154 msgstr ""
155
156 #. TRANSLATORS: command description
157 msgid "Set release version on firmware file"
158 msgstr ""
159
160 #. TRANSLATORS: command description
161 msgid "Set alternative number on firmware file"
162 msgstr ""
163
164 #. TRANSLATORS: command description
165 msgid "Set alternative name on firmware file"
166 msgstr ""
167
168 #. TRANSLATORS: command description
169 msgid "Attach DFU capable device back to runtime"
170 msgstr ""
171
172 #. TRANSLATORS: command description
173 msgid "Read firmware from device into a file"
174 msgstr ""
175
176 #. TRANSLATORS: command description
177 msgid "Read firmware from one partition into a file"
178 msgstr ""
179
180 #. TRANSLATORS: command description
181 msgid "Write firmware from file into device"
182 msgstr ""
183
184 #. TRANSLATORS: command description
185 msgid "Write firmware from file into one partition"
186 msgstr ""
187
188 #. TRANSLATORS: command description
189 msgid "List currently attached DFU capable devices"
190 msgstr ""
191
192 #. TRANSLATORS: command description
193 msgid "Detach currently attached DFU capable device"
194 msgstr ""
195
196 #. TRANSLATORS: command description
197 msgid "Dump details about a firmware file"
198 msgstr ""
199
200 #. TRANSLATORS: command description
201 msgid "Watch DFU devices being hotplugged"
202 msgstr ""
203
204 #. TRANSLATORS: command description
205 msgid "Encrypt firmware data"
206 msgstr ""
207
208 #. TRANSLATORS: command description
209 msgid "Decrypt firmware data"
210 msgstr ""
211
212 #. TRANSLATORS: command description
213 msgid "Sets metadata on a firmware file"
214 msgstr ""
215
216 #. TRANSLATORS: DFU stands for device firmware update
217 msgid "DFU Utility"
218 msgstr ""
219
220 #. TRANSLATORS: the user didn't read the man page
221 msgid "Failed to parse arguments"
222 msgstr ""
223
224 #. TRANSLATORS: turn on all debugging
225 msgid "Show debugging information for all files"
226 msgstr "Debuginformationen für alle Dateien anzeigen"
227
228 #. TRANSLATORS: for the --verbose arg
229 msgid "Debugging Options"
230 msgstr "Debug Optionen"
231
232 #. TRANSLATORS: for the --verbose arg
233 msgid "Show debugging options"
234 msgstr "Debug Optionen anzeigen"
235
236 #. TRANSLATORS: exit after we've started up, used for user profiling
237 msgid "Exit after a small delay"
238 msgstr "Verlassen nach einer kurzen Verzögerung"
239
240 #. TRANSLATORS: exit straight away, used for automatic profiling
241 msgid "Exit after the engine has loaded"
242 msgstr ""
243
244 #. TRANSLATORS: program name
245 msgid "Firmware Update Daemon"
246 msgstr ""
247
248 #. TRANSLATORS: program summary
249 msgid "Firmware Update D-Bus Service"
88250 msgstr ""
89251
90252 #. TRANSLATORS: daemon is inactive
148310 msgid "Updating %s from %s to %s... "
149311 msgstr ""
150312
151 msgid "OK"
152 msgstr ""
153
154313 #. TRANSLATORS: first replacement is device name
155314 #, c-format
156315 msgid "%s has firmware updates:"
157316 msgstr ""
158317
318 #. TRANSLATORS: a GUID for the hardware
319 msgid "GUID"
320 msgstr ""
321
159322 #. TRANSLATORS: section header for firmware version
160323 msgid "Version"
161324 msgstr ""
240403 msgid "Firmware Utility"
241404 msgstr ""
242405
243 #. TRANSLATORS: the user didn't read the man page
244 msgid "Failed to parse arguments"
245 msgstr ""
246
247406 #. TRANSLATORS: the user is in a bad place
248407 msgid "Failed to connect to D-Bus"
249408 msgstr ""
33 #
44 # Translators:
55 # Richard Hughes <richard@hughsie.com>, 2015
6 # Robert Readman <robert_readman@hotmail.com>, 2013
76 msgid ""
87 msgstr ""
98 "Project-Id-Version: fwupd\n"
109 "Report-Msgid-Bugs-To: \n"
11 "POT-Creation-Date: 2014-11-10 11:04+0000\n"
12 "PO-Revision-Date: 2014-11-10 11:04+0000\n"
10 "POT-Creation-Date: 2015-12-07 12:22+0000\n"
11 "PO-Revision-Date: 2015-12-07 12:27+0000\n"
1312 "Last-Translator: Richard Hughes <richard@hughsie.com>\n"
14 "Language-Team: English (United Kingdom) (http://www.transifex.com/projects/p/colord/language/en_GB/)\n"
13 "Language-Team: English (United Kingdom) (http://www.transifex.com/hughsie/fwupd/language/en_GB/)\n"
1514 "MIME-Version: 1.0\n"
1615 "Content-Type: text/plain; charset=UTF-8\n"
1716 "Content-Transfer-Encoding: 8bit\n"
1817 "Language: en_GB\n"
1918 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
2019
21 #. TRANSLATORS: this is a command alias
20 msgid "Install signed system firmware"
21 msgstr "Install signed system firmware"
22
23 #. TRANSLATORS: this is the PolicyKit modal dialog
24 msgid "Authentication is required to update the firmware on this machine"
25 msgstr "Authentication is required to update the firmware on this machine"
26
27 msgid "Install unsigned system firmware"
28 msgstr "Install unsigned system firmware"
29
30 msgid "Install old version of system firmware"
31 msgstr "Install old version of system firmware"
32
33 #. TRANSLATORS: this is the PolicyKit modal dialog
34 msgid "Authentication is required to downgrade the firmware on this machine"
35 msgstr "Authentication is required to downgrade the firmware on this machine"
36
37 msgid "Install signed device firmware"
38 msgstr "Install signed device firmware"
39
40 #. TRANSLATORS: this is the PolicyKit modal dialog
41 msgid ""
42 "Authentication is required to update the firmware on a removable device"
43 msgstr "Authentication is required to update the firmware on a removable device"
44
45 msgid "Install unsigned device firmware"
46 msgstr "Install unsigned device firmware"
47
48 #. TRANSLATORS: this is the PolicyKit modal dialog
49 msgid ""
50 "Authentication is required to downgrade the firmware on a removable device"
51 msgstr "Authentication is required to downgrade the firmware on a removable device"
52
53 #. TRANSLATORS: this is a command alias, e.g. 'get-devices'
2254 #, c-format
2355 msgid "Alias to %s"
2456 msgstr "Alias to %s"
57
58 #. TRANSLATORS: error message
59 msgid "Command not found"
60 msgstr "Command not found"
61
62 #. TRANSLATORS: when an action has completed
63 msgid "OK"
64 msgstr "OK"
65
66 #. TRANSLATORS: when moving from runtime to DFU mode
67 msgid "Detaching"
68 msgstr "Detaching"
69
70 #. TRANSLATORS: when moving from DFU to runtime mode
71 msgid "Attaching"
72 msgstr "Attaching"
73
74 #. TRANSLATORS: when copying from host to device
75 msgid "Downloading"
76 msgstr "Downloading"
77
78 #. TRANSLATORS: when copying from device to host
79 msgid "Uploading"
80 msgstr "Uploading"
81
82 #. TRANSLATORS: this is when a device is hotplugged
83 msgid "Added"
84 msgstr "Added"
85
86 #. TRANSLATORS: this is when a device is hotplugged
87 msgid "Removed"
88 msgstr "Removed"
89
90 #. TRANSLATORS: this is when a device is hotplugged
91 msgid "Changed"
92 msgstr "Changed"
93
94 #. TRANSLATORS: this is when a device ctrl+c's a watch
95 msgid "Cancelled"
96 msgstr "Cancelled"
97
98 #. TRANSLATORS: Appstream ID for the hardware type
99 msgid "ID"
100 msgstr "ID"
101
102 #. TRANSLATORS: interface name, e.g. "Flash"
103 msgid "Name"
104 msgstr "Name"
105
106 #. TRANSLATORS: this is the encryption method used when writing
107 msgid "Cipher"
108 msgstr "Cipher"
109
110 #. TRANSLATORS: these are areas of memory on the chip
111 msgid "Region"
112 msgstr "Region"
113
114 #. TRANSLATORS: detected a DFU device
115 msgid "Found"
116 msgstr "Found"
117
118 #. TRANSLATORS: probably not run as root...
119 #. TRANSLATORS: device has failed to report status
120 #. TRANSLATORS: device status, e.g. "OK"
121 msgid "Status"
122 msgstr "Status"
123
124 msgid "Unknown: permission denied"
125 msgstr "Unknown: permission denied"
126
127 #. TRANSLATORS: device mode, e.g. runtime or DFU
128 msgid "Mode"
129 msgstr "Mode"
130
131 #. TRANSLATORS: device state, i.e. appIDLE
132 msgid "State"
133 msgstr "State"
134
135 #. TRANSLATORS: device quirks, i.e. things that
136 #. * it does that we have to work around
137 msgid "Quirks"
138 msgstr "Quirks"
139
140 #. TRANSLATORS: command description
141 msgid "Convert firmware to DFU format"
142 msgstr "Convert firmware to DFU format"
143
144 #. TRANSLATORS: command description
145 msgid "Merge multiple firmware files into one"
146 msgstr "Merge multiple firmware files into one"
147
148 #. TRANSLATORS: command description
149 msgid "Set vendor ID on firmware file"
150 msgstr "Set vendor ID on firmware file"
151
152 #. TRANSLATORS: command description
153 msgid "Set product ID on firmware file"
154 msgstr "Set product ID on firmware file"
155
156 #. TRANSLATORS: command description
157 msgid "Set release version on firmware file"
158 msgstr "Set release version on firmware file"
159
160 #. TRANSLATORS: command description
161 msgid "Set alternative number on firmware file"
162 msgstr "Set alternative number on firmware file"
163
164 #. TRANSLATORS: command description
165 msgid "Set alternative name on firmware file"
166 msgstr "Set alternative name on firmware file"
167
168 #. TRANSLATORS: command description
169 msgid "Attach DFU capable device back to runtime"
170 msgstr "Attach DFU capable device back to runtime"
171
172 #. TRANSLATORS: command description
173 msgid "Read firmware from device into a file"
174 msgstr "Read firmware from device into a file"
175
176 #. TRANSLATORS: command description
177 msgid "Read firmware from one partition into a file"
178 msgstr "Read firmware from one partition into a file"
179
180 #. TRANSLATORS: command description
181 msgid "Write firmware from file into device"
182 msgstr "Write firmware from file into device"
183
184 #. TRANSLATORS: command description
185 msgid "Write firmware from file into one partition"
186 msgstr "Write firmware from file into one partition"
187
188 #. TRANSLATORS: command description
189 msgid "List currently attached DFU capable devices"
190 msgstr "List currently attached DFU capable devices"
191
192 #. TRANSLATORS: command description
193 msgid "Detach currently attached DFU capable device"
194 msgstr "Detach currently attached DFU capable device"
195
196 #. TRANSLATORS: command description
197 msgid "Dump details about a firmware file"
198 msgstr "Dump details about a firmware file"
199
200 #. TRANSLATORS: command description
201 msgid "Watch DFU devices being hotplugged"
202 msgstr "Watch DFU devices being hotplugged"
203
204 #. TRANSLATORS: command description
205 msgid "Encrypt firmware data"
206 msgstr "Encrypt firmware data"
207
208 #. TRANSLATORS: command description
209 msgid "Decrypt firmware data"
210 msgstr "Decrypt firmware data"
211
212 #. TRANSLATORS: command description
213 msgid "Sets metadata on a firmware file"
214 msgstr "Sets metadata on a firmware file"
215
216 #. TRANSLATORS: DFU stands for device firmware update
217 msgid "DFU Utility"
218 msgstr "DFU Utility"
219
220 #. TRANSLATORS: the user didn't read the man page
221 msgid "Failed to parse arguments"
222 msgstr "Failed to parse arguments"
223
224 #. TRANSLATORS: turn on all debugging
225 msgid "Show debugging information for all files"
226 msgstr "Show debugging information for all files"
227
228 #. TRANSLATORS: for the --verbose arg
229 msgid "Debugging Options"
230 msgstr "Debugging Options"
231
232 #. TRANSLATORS: for the --verbose arg
233 msgid "Show debugging options"
234 msgstr "Show debugging options"
235
236 #. TRANSLATORS: exit after we've started up, used for user profiling
237 msgid "Exit after a small delay"
238 msgstr "Exit after a small delay"
239
240 #. TRANSLATORS: exit straight away, used for automatic profiling
241 msgid "Exit after the engine has loaded"
242 msgstr "Exit after the engine has loaded"
243
244 #. TRANSLATORS: program name
245 msgid "Firmware Update Daemon"
246 msgstr "Firmware Update Daemon"
247
248 #. TRANSLATORS: program summary
249 msgid "Firmware Update D-Bus Service"
250 msgstr "Firmware Update D-Bus Service"
251
252 #. TRANSLATORS: daemon is inactive
253 msgid "Idle"
254 msgstr "Idle"
255
256 #. TRANSLATORS: decompressing the firmware file
257 msgid "Decompressing firmware"
258 msgstr "Decompressing firmware"
259
260 #. TRANSLATORS: parsing the firmware information
261 msgid "Loading firmware"
262 msgstr "Loading firmware"
263
264 #. TRANSLATORS: restarting the device to pick up new F/W
265 msgid "Restarting device"
266 msgstr "Restarting device"
267
268 #. TRANSLATORS: writing to the flash chips
269 msgid "Writing firmware to device"
270 msgstr "Writing firmware to device"
271
272 #. TRANSLATORS: verifying we wrote the firmware correctly
273 msgid "Verifying firmware from device"
274 msgstr "Verifying firmware from device"
275
276 #. TRANSLATORS: scheduing an update to be done on the next boot
277 msgid "Scheduling upgrade"
278 msgstr "Scheduling upgrade"
279
280 #. TRANSLATORS: nothing attached that can be upgraded
281 msgid "No hardware detected with firmware update capability"
282 msgstr "No hardware detected with firmware update capability"
283
284 #. TRANSLATORS: update completed, no errors
285 msgid "Done!"
286 msgstr "Done!"
287
288 #. TRANSLATOR: the provider only supports offline
289 msgid "Retrying as an offline update"
290 msgstr "Retrying as an offline update"
291
292 #. TRANSLATORS: the first replacement is a display name
293 #. * e.g. "ColorHugALS" and the second is a version number
294 #. * e.g. "1.2.3"
295 #, c-format
296 msgid "Reinstalling %s with %s... "
297 msgstr "Reinstalling %s with %s... "
298
299 #. TRANSLATORS: the first replacement is a display name
300 #. * e.g. "ColorHugALS" and the second and third are
301 #. * version numbers e.g. "1.2.3"
302 #, c-format
303 msgid "Downgrading %s from %s to %s... "
304 msgstr "Downgrading %s from %s to %s... "
305
306 #. TRANSLATORS: the first replacement is a display name
307 #. * e.g. "ColorHugALS" and the second and third are
308 #. * version numbers e.g. "1.2.3"
309 #, c-format
310 msgid "Updating %s from %s to %s... "
311 msgstr "Updating %s from %s to %s... "
312
313 #. TRANSLATORS: first replacement is device name
314 #, c-format
315 msgid "%s has firmware updates:"
316 msgstr "%s has firmware updates:"
317
318 #. TRANSLATORS: a GUID for the hardware
319 msgid "GUID"
320 msgstr "GUID"
321
322 #. TRANSLATORS: section header for firmware version
323 msgid "Version"
324 msgstr "Version"
325
326 #. TRANSLATORS: section header for firmware SHA1
327 msgid "Checksum"
328 msgstr "Checksum"
329
330 #. TRANSLATORS: section header for firmware remote http://
331 msgid "Location"
332 msgstr "Location"
333
334 #. TRANSLATORS: section header for long firmware desc
335 msgid "Description"
336 msgstr "Description"
337
338 #. TRANSLATORS: command line option
339 msgid "Show extra debugging information"
340 msgstr "Show extra debugging information"
341
342 #. TRANSLATORS: command line option
343 msgid "Perform the installation offline where possible"
344 msgstr "Perform the installation offline where possible"
345
346 #. TRANSLATORS: command line option
347 msgid "Allow re-installing existing firmware versions"
348 msgstr "Allow re-installing existing firmware versions"
349
350 #. TRANSLATORS: command line option
351 msgid "Allow downgrading firmware versions"
352 msgstr "Allow downgrading firmware versions"
353
354 #. TRANSLATORS: command description
355 msgid "Get all devices that support firmware updates"
356 msgstr "Get all devices that support firmware updates"
357
358 #. TRANSLATORS: command description
359 msgid "Install prepared updates now"
360 msgstr "Install prepared updates now"
361
362 #. TRANSLATORS: command description
363 msgid "Install a firmware file on this hardware"
364 msgstr "Install a firmware file on this hardware"
365
366 #. TRANSLATORS: command description
367 msgid "Gets details about a firmware file"
368 msgstr "Gets details about a firmware file"
369
370 #. TRANSLATORS: command description
371 msgid "Gets the list of updates for connected hardware"
372 msgstr "Gets the list of updates for connected hardware"
373
374 #. TRANSLATORS: command description
375 msgid "Updates all firmware to latest versions available"
376 msgstr "Updates all firmware to latest versions available"
377
378 #. TRANSLATORS: command description
379 msgid "Gets the cryptographic hash of the dumped firmware"
380 msgstr "Gets the cryptographic hash of the dumped firmware"
381
382 #. TRANSLATORS: command description
383 msgid "Clears the results from the last update"
384 msgstr "Clears the results from the last update"
385
386 #. TRANSLATORS: command description
387 msgid "Gets the results from the last update"
388 msgstr "Gets the results from the last update"
389
390 #. TRANSLATORS: command description
391 msgid "Refresh metadata from remote server"
392 msgstr "Refresh metadata from remote server"
393
394 #. TRANSLATORS: command description
395 msgid "Dump the ROM checksum"
396 msgstr "Dump the ROM checksum"
397
398 #. TRANSLATORS: command description
399 msgid "Update the stored metadata with current ROM contents"
400 msgstr "Update the stored metadata with current ROM contents"
401
402 #. TRANSLATORS: program name
403 msgid "Firmware Utility"
404 msgstr "Firmware Utility"
405
406 #. TRANSLATORS: the user is in a bad place
407 msgid "Failed to connect to D-Bus"
408 msgstr "Failed to connect to D-Bus"
409
410 #. TRANSLATORS: we can't connect to the daemon
411 msgid "Failed to connect to fwupd"
412 msgstr "Failed to connect to fwupd"
77 msgstr ""
88 "Project-Id-Version: fwupd\n"
99 "Report-Msgid-Bugs-To: \n"
10 "POT-Creation-Date: 2015-09-10 09:28+0100\n"
11 "PO-Revision-Date: 2015-09-10 08:28+0000\n"
10 "POT-Creation-Date: 2015-12-07 12:22+0000\n"
11 "PO-Revision-Date: 2015-12-07 12:22+0000\n"
1212 "Last-Translator: Richard Hughes <richard@hughsie.com>\n"
1313 "Language-Team: French (http://www.transifex.com/hughsie/fwupd/language/fr/)\n"
1414 "MIME-Version: 1.0\n"
5050 "Authentication is required to downgrade the firmware on a removable device"
5151 msgstr ""
5252
53 #. TRANSLATORS: turn on all debugging
54 msgid "Show debugging information for all files"
55 msgstr "Montrer les informations de débogage pour tous les fichiers"
56
57 #. TRANSLATORS: for the --verbose arg
58 msgid "Debugging Options"
59 msgstr "Options de débogage"
60
61 #. TRANSLATORS: for the --verbose arg
62 msgid "Show debugging options"
63 msgstr "Montrer les options de débogage"
64
65 #. TRANSLATORS: exit after we've started up, used for user profiling
66 msgid "Exit after a small delay"
67 msgstr "Quitter après un bref délai"
68
69 #. TRANSLATORS: exit straight away, used for automatic profiling
70 msgid "Exit after the engine has loaded"
71 msgstr "Quitter après le chargement du moteur"
72
73 #. TRANSLATORS: program name
74 msgid "Firmware Update Daemon"
75 msgstr ""
76
77 #. TRANSLATORS: program summary
78 msgid "Firmware Update D-Bus Service"
79 msgstr "Service D-Bus de mise à jour des micrologiciels"
80
8153 #. TRANSLATORS: this is a command alias, e.g. 'get-devices'
8254 #, c-format
8355 msgid "Alias to %s"
8658 #. TRANSLATORS: error message
8759 msgid "Command not found"
8860 msgstr ""
61
62 #. TRANSLATORS: when an action has completed
63 msgid "OK"
64 msgstr ""
65
66 #. TRANSLATORS: when moving from runtime to DFU mode
67 msgid "Detaching"
68 msgstr ""
69
70 #. TRANSLATORS: when moving from DFU to runtime mode
71 msgid "Attaching"
72 msgstr ""
73
74 #. TRANSLATORS: when copying from host to device
75 msgid "Downloading"
76 msgstr ""
77
78 #. TRANSLATORS: when copying from device to host
79 msgid "Uploading"
80 msgstr ""
81
82 #. TRANSLATORS: this is when a device is hotplugged
83 msgid "Added"
84 msgstr ""
85
86 #. TRANSLATORS: this is when a device is hotplugged
87 msgid "Removed"
88 msgstr ""
89
90 #. TRANSLATORS: this is when a device is hotplugged
91 msgid "Changed"
92 msgstr ""
93
94 #. TRANSLATORS: this is when a device ctrl+c's a watch
95 msgid "Cancelled"
96 msgstr ""
97
98 #. TRANSLATORS: Appstream ID for the hardware type
99 msgid "ID"
100 msgstr ""
101
102 #. TRANSLATORS: interface name, e.g. "Flash"
103 msgid "Name"
104 msgstr ""
105
106 #. TRANSLATORS: this is the encryption method used when writing
107 msgid "Cipher"
108 msgstr ""
109
110 #. TRANSLATORS: these are areas of memory on the chip
111 msgid "Region"
112 msgstr ""
113
114 #. TRANSLATORS: detected a DFU device
115 msgid "Found"
116 msgstr ""
117
118 #. TRANSLATORS: probably not run as root...
119 #. TRANSLATORS: device has failed to report status
120 #. TRANSLATORS: device status, e.g. "OK"
121 msgid "Status"
122 msgstr ""
123
124 msgid "Unknown: permission denied"
125 msgstr ""
126
127 #. TRANSLATORS: device mode, e.g. runtime or DFU
128 msgid "Mode"
129 msgstr ""
130
131 #. TRANSLATORS: device state, i.e. appIDLE
132 msgid "State"
133 msgstr ""
134
135 #. TRANSLATORS: device quirks, i.e. things that
136 #. * it does that we have to work around
137 msgid "Quirks"
138 msgstr ""
139
140 #. TRANSLATORS: command description
141 msgid "Convert firmware to DFU format"
142 msgstr ""
143
144 #. TRANSLATORS: command description
145 msgid "Merge multiple firmware files into one"
146 msgstr ""
147
148 #. TRANSLATORS: command description
149 msgid "Set vendor ID on firmware file"
150 msgstr ""
151
152 #. TRANSLATORS: command description
153 msgid "Set product ID on firmware file"
154 msgstr ""
155
156 #. TRANSLATORS: command description
157 msgid "Set release version on firmware file"
158 msgstr ""
159
160 #. TRANSLATORS: command description
161 msgid "Set alternative number on firmware file"
162 msgstr ""
163
164 #. TRANSLATORS: command description
165 msgid "Set alternative name on firmware file"
166 msgstr ""
167
168 #. TRANSLATORS: command description
169 msgid "Attach DFU capable device back to runtime"
170 msgstr ""
171
172 #. TRANSLATORS: command description
173 msgid "Read firmware from device into a file"
174 msgstr ""
175
176 #. TRANSLATORS: command description
177 msgid "Read firmware from one partition into a file"
178 msgstr ""
179
180 #. TRANSLATORS: command description
181 msgid "Write firmware from file into device"
182 msgstr ""
183
184 #. TRANSLATORS: command description
185 msgid "Write firmware from file into one partition"
186 msgstr ""
187
188 #. TRANSLATORS: command description
189 msgid "List currently attached DFU capable devices"
190 msgstr ""
191
192 #. TRANSLATORS: command description
193 msgid "Detach currently attached DFU capable device"
194 msgstr ""
195
196 #. TRANSLATORS: command description
197 msgid "Dump details about a firmware file"
198 msgstr ""
199
200 #. TRANSLATORS: command description
201 msgid "Watch DFU devices being hotplugged"
202 msgstr ""
203
204 #. TRANSLATORS: command description
205 msgid "Encrypt firmware data"
206 msgstr ""
207
208 #. TRANSLATORS: command description
209 msgid "Decrypt firmware data"
210 msgstr ""
211
212 #. TRANSLATORS: command description
213 msgid "Sets metadata on a firmware file"
214 msgstr ""
215
216 #. TRANSLATORS: DFU stands for device firmware update
217 msgid "DFU Utility"
218 msgstr ""
219
220 #. TRANSLATORS: the user didn't read the man page
221 msgid "Failed to parse arguments"
222 msgstr "Echec de l'analyse des paramètres"
223
224 #. TRANSLATORS: turn on all debugging
225 msgid "Show debugging information for all files"
226 msgstr "Montrer les informations de débogage pour tous les fichiers"
227
228 #. TRANSLATORS: for the --verbose arg
229 msgid "Debugging Options"
230 msgstr "Options de débogage"
231
232 #. TRANSLATORS: for the --verbose arg
233 msgid "Show debugging options"
234 msgstr "Montrer les options de débogage"
235
236 #. TRANSLATORS: exit after we've started up, used for user profiling
237 msgid "Exit after a small delay"
238 msgstr "Quitter après un bref délai"
239
240 #. TRANSLATORS: exit straight away, used for automatic profiling
241 msgid "Exit after the engine has loaded"
242 msgstr "Quitter après le chargement du moteur"
243
244 #. TRANSLATORS: program name
245 msgid "Firmware Update Daemon"
246 msgstr ""
247
248 #. TRANSLATORS: program summary
249 msgid "Firmware Update D-Bus Service"
250 msgstr "Service D-Bus de mise à jour des micrologiciels"
89251
90252 #. TRANSLATORS: daemon is inactive
91253 msgid "Idle"
148310 msgid "Updating %s from %s to %s... "
149311 msgstr "Mise à jour de %s de %s en %s"
150312
151 msgid "OK"
152 msgstr ""
153
154313 #. TRANSLATORS: first replacement is device name
155314 #, c-format
156315 msgid "%s has firmware updates:"
157316 msgstr ""
158317
318 #. TRANSLATORS: a GUID for the hardware
319 msgid "GUID"
320 msgstr ""
321
159322 #. TRANSLATORS: section header for firmware version
160323 msgid "Version"
161324 msgstr ""
240403 msgid "Firmware Utility"
241404 msgstr ""
242405
243 #. TRANSLATORS: the user didn't read the man page
244 msgid "Failed to parse arguments"
245 msgstr "Echec de l'analyse des paramètres"
246
247406 #. TRANSLATORS: the user is in a bad place
248407 msgid "Failed to connect to D-Bus"
249408 msgstr ""
88 msgstr ""
99 "Project-Id-Version: fwupd\n"
1010 "Report-Msgid-Bugs-To: \n"
11 "POT-Creation-Date: 2015-10-28 09:58+0000\n"
12 "PO-Revision-Date: 2015-10-22 20:05+0000\n"
13 "Last-Translator: GenghisKhan <genghiskhan@gmx.ca>\n"
11 "POT-Creation-Date: 2015-12-07 12:22+0000\n"
12 "PO-Revision-Date: 2015-12-07 12:22+0000\n"
13 "Last-Translator: Richard Hughes <richard@hughsie.com>\n"
1414 "Language-Team: Hebrew (http://www.transifex.com/hughsie/fwupd/language/he/)\n"
1515 "MIME-Version: 1.0\n"
1616 "Content-Type: text/plain; charset=UTF-8\n"
5151 "Authentication is required to downgrade the firmware on a removable device"
5252 msgstr ""
5353
54 #. TRANSLATORS: turn on all debugging
55 msgid "Show debugging information for all files"
56 msgstr "הצג מידע ניפוי שגיאות לכל הקבצים"
57
58 #. TRANSLATORS: for the --verbose arg
59 msgid "Debugging Options"
60 msgstr "אפשרויות ניפוי שגיאות"
61
62 #. TRANSLATORS: for the --verbose arg
63 msgid "Show debugging options"
64 msgstr "הצג אפשרויות ניפוי שגיאות"
65
66 #. TRANSLATORS: exit after we've started up, used for user profiling
67 msgid "Exit after a small delay"
68 msgstr "יציאה לאחר השהייה קצרה"
69
70 #. TRANSLATORS: exit straight away, used for automatic profiling
71 msgid "Exit after the engine has loaded"
72 msgstr "יציאה לאחר טעינת מנוע התכנה"
73
74 #. TRANSLATORS: program name
75 msgid "Firmware Update Daemon"
76 msgstr "שדון עדכון קושחה"
77
78 #. TRANSLATORS: program summary
79 msgid "Firmware Update D-Bus Service"
80 msgstr "שירות D-Bus עדכון קושחה"
81
8254 #. TRANSLATORS: this is a command alias, e.g. 'get-devices'
8355 #, c-format
8456 msgid "Alias to %s"
8759 #. TRANSLATORS: error message
8860 msgid "Command not found"
8961 msgstr "פקודה לא נמצאה"
62
63 #. TRANSLATORS: when an action has completed
64 msgid "OK"
65 msgstr "אישור"
66
67 #. TRANSLATORS: when moving from runtime to DFU mode
68 msgid "Detaching"
69 msgstr ""
70
71 #. TRANSLATORS: when moving from DFU to runtime mode
72 msgid "Attaching"
73 msgstr ""
74
75 #. TRANSLATORS: when copying from host to device
76 msgid "Downloading"
77 msgstr ""
78
79 #. TRANSLATORS: when copying from device to host
80 msgid "Uploading"
81 msgstr ""
82
83 #. TRANSLATORS: this is when a device is hotplugged
84 msgid "Added"
85 msgstr ""
86
87 #. TRANSLATORS: this is when a device is hotplugged
88 msgid "Removed"
89 msgstr ""
90
91 #. TRANSLATORS: this is when a device is hotplugged
92 msgid "Changed"
93 msgstr ""
94
95 #. TRANSLATORS: this is when a device ctrl+c's a watch
96 msgid "Cancelled"
97 msgstr ""
98
99 #. TRANSLATORS: Appstream ID for the hardware type
100 msgid "ID"
101 msgstr ""
102
103 #. TRANSLATORS: interface name, e.g. "Flash"
104 msgid "Name"
105 msgstr ""
106
107 #. TRANSLATORS: this is the encryption method used when writing
108 msgid "Cipher"
109 msgstr ""
110
111 #. TRANSLATORS: these are areas of memory on the chip
112 msgid "Region"
113 msgstr ""
114
115 #. TRANSLATORS: detected a DFU device
116 msgid "Found"
117 msgstr ""
118
119 #. TRANSLATORS: probably not run as root...
120 #. TRANSLATORS: device has failed to report status
121 #. TRANSLATORS: device status, e.g. "OK"
122 msgid "Status"
123 msgstr ""
124
125 msgid "Unknown: permission denied"
126 msgstr ""
127
128 #. TRANSLATORS: device mode, e.g. runtime or DFU
129 msgid "Mode"
130 msgstr ""
131
132 #. TRANSLATORS: device state, i.e. appIDLE
133 msgid "State"
134 msgstr ""
135
136 #. TRANSLATORS: device quirks, i.e. things that
137 #. * it does that we have to work around
138 msgid "Quirks"
139 msgstr ""
140
141 #. TRANSLATORS: command description
142 msgid "Convert firmware to DFU format"
143 msgstr ""
144
145 #. TRANSLATORS: command description
146 msgid "Merge multiple firmware files into one"
147 msgstr ""
148
149 #. TRANSLATORS: command description
150 msgid "Set vendor ID on firmware file"
151 msgstr ""
152
153 #. TRANSLATORS: command description
154 msgid "Set product ID on firmware file"
155 msgstr ""
156
157 #. TRANSLATORS: command description
158 msgid "Set release version on firmware file"
159 msgstr ""
160
161 #. TRANSLATORS: command description
162 msgid "Set alternative number on firmware file"
163 msgstr ""
164
165 #. TRANSLATORS: command description
166 msgid "Set alternative name on firmware file"
167 msgstr ""
168
169 #. TRANSLATORS: command description
170 msgid "Attach DFU capable device back to runtime"
171 msgstr ""
172
173 #. TRANSLATORS: command description
174 msgid "Read firmware from device into a file"
175 msgstr ""
176
177 #. TRANSLATORS: command description
178 msgid "Read firmware from one partition into a file"
179 msgstr ""
180
181 #. TRANSLATORS: command description
182 msgid "Write firmware from file into device"
183 msgstr ""
184
185 #. TRANSLATORS: command description
186 msgid "Write firmware from file into one partition"
187 msgstr ""
188
189 #. TRANSLATORS: command description
190 msgid "List currently attached DFU capable devices"
191 msgstr ""
192
193 #. TRANSLATORS: command description
194 msgid "Detach currently attached DFU capable device"
195 msgstr ""
196
197 #. TRANSLATORS: command description
198 msgid "Dump details about a firmware file"
199 msgstr ""
200
201 #. TRANSLATORS: command description
202 msgid "Watch DFU devices being hotplugged"
203 msgstr ""
204
205 #. TRANSLATORS: command description
206 msgid "Encrypt firmware data"
207 msgstr ""
208
209 #. TRANSLATORS: command description
210 msgid "Decrypt firmware data"
211 msgstr ""
212
213 #. TRANSLATORS: command description
214 msgid "Sets metadata on a firmware file"
215 msgstr ""
216
217 #. TRANSLATORS: DFU stands for device firmware update
218 msgid "DFU Utility"
219 msgstr ""
220
221 #. TRANSLATORS: the user didn't read the man page
222 msgid "Failed to parse arguments"
223 msgstr "נכשל בפענוח הארגומנטים"
224
225 #. TRANSLATORS: turn on all debugging
226 msgid "Show debugging information for all files"
227 msgstr "הצג מידע ניפוי שגיאות לכל הקבצים"
228
229 #. TRANSLATORS: for the --verbose arg
230 msgid "Debugging Options"
231 msgstr "אפשרויות ניפוי שגיאות"
232
233 #. TRANSLATORS: for the --verbose arg
234 msgid "Show debugging options"
235 msgstr "הצג אפשרויות ניפוי שגיאות"
236
237 #. TRANSLATORS: exit after we've started up, used for user profiling
238 msgid "Exit after a small delay"
239 msgstr "יציאה לאחר השהייה קצרה"
240
241 #. TRANSLATORS: exit straight away, used for automatic profiling
242 msgid "Exit after the engine has loaded"
243 msgstr "יציאה לאחר טעינת מנוע התכנה"
244
245 #. TRANSLATORS: program name
246 msgid "Firmware Update Daemon"
247 msgstr "שדון עדכון קושחה"
248
249 #. TRANSLATORS: program summary
250 msgid "Firmware Update D-Bus Service"
251 msgstr "שירות D-Bus עדכון קושחה"
90252
91253 #. TRANSLATORS: daemon is inactive
92254 msgid "Idle"
149311 msgid "Updating %s from %s to %s... "
150312 msgstr "מעדכן %s מ־%s ל־%s..."
151313
152 msgid "OK"
153 msgstr "אישור"
154
155314 #. TRANSLATORS: first replacement is device name
156315 #, c-format
157316 msgid "%s has firmware updates:"
158317 msgstr "ישנם עדכוני קושחה עבור %s:"
159318
319 #. TRANSLATORS: a GUID for the hardware
320 msgid "GUID"
321 msgstr ""
322
160323 #. TRANSLATORS: section header for firmware version
161324 msgid "Version"
162325 msgstr "גרסא"
241404 msgid "Firmware Utility"
242405 msgstr ""
243406
244 #. TRANSLATORS: the user didn't read the man page
245 msgid "Failed to parse arguments"
246 msgstr "נכשל בפענוח הארגומנטים"
247
248407 #. TRANSLATORS: the user is in a bad place
249408 msgid "Failed to connect to D-Bus"
250409 msgstr ""
77 msgstr ""
88 "Project-Id-Version: fwupd\n"
99 "Report-Msgid-Bugs-To: \n"
10 "POT-Creation-Date: 2015-09-10 09:28+0100\n"
11 "PO-Revision-Date: 2015-09-10 08:28+0000\n"
10 "POT-Creation-Date: 2015-12-07 12:22+0000\n"
11 "PO-Revision-Date: 2015-12-07 12:22+0000\n"
1212 "Last-Translator: Richard Hughes <richard@hughsie.com>\n"
1313 "Language-Team: Hindi (India) (http://www.transifex.com/hughsie/fwupd/language/hi_IN/)\n"
1414 "MIME-Version: 1.0\n"
5050 "Authentication is required to downgrade the firmware on a removable device"
5151 msgstr ""
5252
53 #. TRANSLATORS: turn on all debugging
54 msgid "Show debugging information for all files"
55 msgstr "फाइल्स की डिबगिंग की जानकारी दिखाए "
56
57 #. TRANSLATORS: for the --verbose arg
58 msgid "Debugging Options"
59 msgstr "डिबगिंग के विकल्प "
60
61 #. TRANSLATORS: for the --verbose arg
62 msgid "Show debugging options"
63 msgstr "डिबगिंग के विकल्प दिखाए "
64
65 #. TRANSLATORS: exit after we've started up, used for user profiling
66 msgid "Exit after a small delay"
67 msgstr "थोड़ी देरी के बाद बहार जाएँ "
68
69 #. TRANSLATORS: exit straight away, used for automatic profiling
70 msgid "Exit after the engine has loaded"
71 msgstr "इंजन के लोड हो जाने पर बहार जाएँ "
72
73 #. TRANSLATORS: program name
74 msgid "Firmware Update Daemon"
75 msgstr ""
76
77 #. TRANSLATORS: program summary
78 msgid "Firmware Update D-Bus Service"
79 msgstr "फर्मवेयर अपडेट डी-बस सेवा "
80
8153 #. TRANSLATORS: this is a command alias, e.g. 'get-devices'
8254 #, c-format
8355 msgid "Alias to %s"
8658 #. TRANSLATORS: error message
8759 msgid "Command not found"
8860 msgstr ""
61
62 #. TRANSLATORS: when an action has completed
63 msgid "OK"
64 msgstr ""
65
66 #. TRANSLATORS: when moving from runtime to DFU mode
67 msgid "Detaching"
68 msgstr ""
69
70 #. TRANSLATORS: when moving from DFU to runtime mode
71 msgid "Attaching"
72 msgstr ""
73
74 #. TRANSLATORS: when copying from host to device
75 msgid "Downloading"
76 msgstr ""
77
78 #. TRANSLATORS: when copying from device to host
79 msgid "Uploading"
80 msgstr ""
81
82 #. TRANSLATORS: this is when a device is hotplugged
83 msgid "Added"
84 msgstr ""
85
86 #. TRANSLATORS: this is when a device is hotplugged
87 msgid "Removed"
88 msgstr ""
89
90 #. TRANSLATORS: this is when a device is hotplugged
91 msgid "Changed"
92 msgstr ""
93
94 #. TRANSLATORS: this is when a device ctrl+c's a watch
95 msgid "Cancelled"
96 msgstr ""
97
98 #. TRANSLATORS: Appstream ID for the hardware type
99 msgid "ID"
100 msgstr ""
101
102 #. TRANSLATORS: interface name, e.g. "Flash"
103 msgid "Name"
104 msgstr ""
105
106 #. TRANSLATORS: this is the encryption method used when writing
107 msgid "Cipher"
108 msgstr ""
109
110 #. TRANSLATORS: these are areas of memory on the chip
111 msgid "Region"
112 msgstr ""
113
114 #. TRANSLATORS: detected a DFU device
115 msgid "Found"
116 msgstr ""
117
118 #. TRANSLATORS: probably not run as root...
119 #. TRANSLATORS: device has failed to report status
120 #. TRANSLATORS: device status, e.g. "OK"
121 msgid "Status"
122 msgstr ""
123
124 msgid "Unknown: permission denied"
125 msgstr ""
126
127 #. TRANSLATORS: device mode, e.g. runtime or DFU
128 msgid "Mode"
129 msgstr ""
130
131 #. TRANSLATORS: device state, i.e. appIDLE
132 msgid "State"
133 msgstr ""
134
135 #. TRANSLATORS: device quirks, i.e. things that
136 #. * it does that we have to work around
137 msgid "Quirks"
138 msgstr ""
139
140 #. TRANSLATORS: command description
141 msgid "Convert firmware to DFU format"
142 msgstr ""
143
144 #. TRANSLATORS: command description
145 msgid "Merge multiple firmware files into one"
146 msgstr ""
147
148 #. TRANSLATORS: command description
149 msgid "Set vendor ID on firmware file"
150 msgstr ""
151
152 #. TRANSLATORS: command description
153 msgid "Set product ID on firmware file"
154 msgstr ""
155
156 #. TRANSLATORS: command description
157 msgid "Set release version on firmware file"
158 msgstr ""
159
160 #. TRANSLATORS: command description
161 msgid "Set alternative number on firmware file"
162 msgstr ""
163
164 #. TRANSLATORS: command description
165 msgid "Set alternative name on firmware file"
166 msgstr ""
167
168 #. TRANSLATORS: command description
169 msgid "Attach DFU capable device back to runtime"
170 msgstr ""
171
172 #. TRANSLATORS: command description
173 msgid "Read firmware from device into a file"
174 msgstr ""
175
176 #. TRANSLATORS: command description
177 msgid "Read firmware from one partition into a file"
178 msgstr ""
179
180 #. TRANSLATORS: command description
181 msgid "Write firmware from file into device"
182 msgstr ""
183
184 #. TRANSLATORS: command description
185 msgid "Write firmware from file into one partition"
186 msgstr ""
187
188 #. TRANSLATORS: command description
189 msgid "List currently attached DFU capable devices"
190 msgstr ""
191
192 #. TRANSLATORS: command description
193 msgid "Detach currently attached DFU capable device"
194 msgstr ""
195
196 #. TRANSLATORS: command description
197 msgid "Dump details about a firmware file"
198 msgstr ""
199
200 #. TRANSLATORS: command description
201 msgid "Watch DFU devices being hotplugged"
202 msgstr ""
203
204 #. TRANSLATORS: command description
205 msgid "Encrypt firmware data"
206 msgstr ""
207
208 #. TRANSLATORS: command description
209 msgid "Decrypt firmware data"
210 msgstr ""
211
212 #. TRANSLATORS: command description
213 msgid "Sets metadata on a firmware file"
214 msgstr ""
215
216 #. TRANSLATORS: DFU stands for device firmware update
217 msgid "DFU Utility"
218 msgstr ""
219
220 #. TRANSLATORS: the user didn't read the man page
221 msgid "Failed to parse arguments"
222 msgstr "आर्गुमेंट पार्स करने में असफल "
223
224 #. TRANSLATORS: turn on all debugging
225 msgid "Show debugging information for all files"
226 msgstr "फाइल्स की डिबगिंग की जानकारी दिखाए "
227
228 #. TRANSLATORS: for the --verbose arg
229 msgid "Debugging Options"
230 msgstr "डिबगिंग के विकल्प "
231
232 #. TRANSLATORS: for the --verbose arg
233 msgid "Show debugging options"
234 msgstr "डिबगिंग के विकल्प दिखाए "
235
236 #. TRANSLATORS: exit after we've started up, used for user profiling
237 msgid "Exit after a small delay"
238 msgstr "थोड़ी देरी के बाद बहार जाएँ "
239
240 #. TRANSLATORS: exit straight away, used for automatic profiling
241 msgid "Exit after the engine has loaded"
242 msgstr "इंजन के लोड हो जाने पर बहार जाएँ "
243
244 #. TRANSLATORS: program name
245 msgid "Firmware Update Daemon"
246 msgstr ""
247
248 #. TRANSLATORS: program summary
249 msgid "Firmware Update D-Bus Service"
250 msgstr "फर्मवेयर अपडेट डी-बस सेवा "
89251
90252 #. TRANSLATORS: daemon is inactive
91253 msgid "Idle"
148310 msgid "Updating %s from %s to %s... "
149311 msgstr "%s को %s से %s तक अपडेट करा जा रहा है "
150312
151 msgid "OK"
152 msgstr ""
153
154313 #. TRANSLATORS: first replacement is device name
155314 #, c-format
156315 msgid "%s has firmware updates:"
157316 msgstr ""
158317
318 #. TRANSLATORS: a GUID for the hardware
319 msgid "GUID"
320 msgstr ""
321
159322 #. TRANSLATORS: section header for firmware version
160323 msgid "Version"
161324 msgstr ""
240403 msgid "Firmware Utility"
241404 msgstr ""
242405
243 #. TRANSLATORS: the user didn't read the man page
244 msgid "Failed to parse arguments"
245 msgstr "आर्गुमेंट पार्स करने में असफल "
246
247406 #. TRANSLATORS: the user is in a bad place
248407 msgid "Failed to connect to D-Bus"
249408 msgstr ""
77 msgstr ""
88 "Project-Id-Version: fwupd\n"
99 "Report-Msgid-Bugs-To: \n"
10 "POT-Creation-Date: 2015-09-10 09:28+0100\n"
11 "PO-Revision-Date: 2015-09-10 08:28+0000\n"
10 "POT-Creation-Date: 2015-12-07 12:22+0000\n"
11 "PO-Revision-Date: 2015-12-07 12:22+0000\n"
1212 "Last-Translator: Richard Hughes <richard@hughsie.com>\n"
1313 "Language-Team: Hungarian (http://www.transifex.com/hughsie/fwupd/language/hu/)\n"
1414 "MIME-Version: 1.0\n"
5050 "Authentication is required to downgrade the firmware on a removable device"
5151 msgstr "Hitelesítés szükséges a firmware visszafejlesztéséhez egy cserélhető eszközön"
5252
53 #. TRANSLATORS: turn on all debugging
54 msgid "Show debugging information for all files"
55 msgstr "Hibakeresési információk megjelenítése minden fájlnál"
56
57 #. TRANSLATORS: for the --verbose arg
58 msgid "Debugging Options"
59 msgstr "Hibakeresési beállítások"
60
61 #. TRANSLATORS: for the --verbose arg
62 msgid "Show debugging options"
63 msgstr "Hibakeresési beállítások megjelenítése"
64
65 #. TRANSLATORS: exit after we've started up, used for user profiling
66 msgid "Exit after a small delay"
67 msgstr "Kilépés egy kis késleltetés után"
68
69 #. TRANSLATORS: exit straight away, used for automatic profiling
70 msgid "Exit after the engine has loaded"
71 msgstr "Kilépés a motor betöltődése után"
72
73 #. TRANSLATORS: program name
74 msgid "Firmware Update Daemon"
75 msgstr ""
76
77 #. TRANSLATORS: program summary
78 msgid "Firmware Update D-Bus Service"
79 msgstr "Firmware frissítés D-Bus szolgáltatás"
80
8153 #. TRANSLATORS: this is a command alias, e.g. 'get-devices'
8254 #, c-format
8355 msgid "Alias to %s"
8658 #. TRANSLATORS: error message
8759 msgid "Command not found"
8860 msgstr ""
61
62 #. TRANSLATORS: when an action has completed
63 msgid "OK"
64 msgstr ""
65
66 #. TRANSLATORS: when moving from runtime to DFU mode
67 msgid "Detaching"
68 msgstr ""
69
70 #. TRANSLATORS: when moving from DFU to runtime mode
71 msgid "Attaching"
72 msgstr ""
73
74 #. TRANSLATORS: when copying from host to device
75 msgid "Downloading"
76 msgstr ""
77
78 #. TRANSLATORS: when copying from device to host
79 msgid "Uploading"
80 msgstr ""
81
82 #. TRANSLATORS: this is when a device is hotplugged
83 msgid "Added"
84 msgstr ""
85
86 #. TRANSLATORS: this is when a device is hotplugged
87 msgid "Removed"
88 msgstr ""
89
90 #. TRANSLATORS: this is when a device is hotplugged
91 msgid "Changed"
92 msgstr ""
93
94 #. TRANSLATORS: this is when a device ctrl+c's a watch
95 msgid "Cancelled"
96 msgstr ""
97
98 #. TRANSLATORS: Appstream ID for the hardware type
99 msgid "ID"
100 msgstr ""
101
102 #. TRANSLATORS: interface name, e.g. "Flash"
103 msgid "Name"
104 msgstr ""
105
106 #. TRANSLATORS: this is the encryption method used when writing
107 msgid "Cipher"
108 msgstr ""
109
110 #. TRANSLATORS: these are areas of memory on the chip
111 msgid "Region"
112 msgstr ""
113
114 #. TRANSLATORS: detected a DFU device
115 msgid "Found"
116 msgstr ""
117
118 #. TRANSLATORS: probably not run as root...
119 #. TRANSLATORS: device has failed to report status
120 #. TRANSLATORS: device status, e.g. "OK"
121 msgid "Status"
122 msgstr ""
123
124 msgid "Unknown: permission denied"
125 msgstr ""
126
127 #. TRANSLATORS: device mode, e.g. runtime or DFU
128 msgid "Mode"
129 msgstr ""
130
131 #. TRANSLATORS: device state, i.e. appIDLE
132 msgid "State"
133 msgstr ""
134
135 #. TRANSLATORS: device quirks, i.e. things that
136 #. * it does that we have to work around
137 msgid "Quirks"
138 msgstr ""
139
140 #. TRANSLATORS: command description
141 msgid "Convert firmware to DFU format"
142 msgstr ""
143
144 #. TRANSLATORS: command description
145 msgid "Merge multiple firmware files into one"
146 msgstr ""
147
148 #. TRANSLATORS: command description
149 msgid "Set vendor ID on firmware file"
150 msgstr ""
151
152 #. TRANSLATORS: command description
153 msgid "Set product ID on firmware file"
154 msgstr ""
155
156 #. TRANSLATORS: command description
157 msgid "Set release version on firmware file"
158 msgstr ""
159
160 #. TRANSLATORS: command description
161 msgid "Set alternative number on firmware file"
162 msgstr ""
163
164 #. TRANSLATORS: command description
165 msgid "Set alternative name on firmware file"
166 msgstr ""
167
168 #. TRANSLATORS: command description
169 msgid "Attach DFU capable device back to runtime"
170 msgstr ""
171
172 #. TRANSLATORS: command description
173 msgid "Read firmware from device into a file"
174 msgstr ""
175
176 #. TRANSLATORS: command description
177 msgid "Read firmware from one partition into a file"
178 msgstr ""
179
180 #. TRANSLATORS: command description
181 msgid "Write firmware from file into device"
182 msgstr ""
183
184 #. TRANSLATORS: command description
185 msgid "Write firmware from file into one partition"
186 msgstr ""
187
188 #. TRANSLATORS: command description
189 msgid "List currently attached DFU capable devices"
190 msgstr ""
191
192 #. TRANSLATORS: command description
193 msgid "Detach currently attached DFU capable device"
194 msgstr ""
195
196 #. TRANSLATORS: command description
197 msgid "Dump details about a firmware file"
198 msgstr ""
199
200 #. TRANSLATORS: command description
201 msgid "Watch DFU devices being hotplugged"
202 msgstr ""
203
204 #. TRANSLATORS: command description
205 msgid "Encrypt firmware data"
206 msgstr ""
207
208 #. TRANSLATORS: command description
209 msgid "Decrypt firmware data"
210 msgstr ""
211
212 #. TRANSLATORS: command description
213 msgid "Sets metadata on a firmware file"
214 msgstr ""
215
216 #. TRANSLATORS: DFU stands for device firmware update
217 msgid "DFU Utility"
218 msgstr ""
219
220 #. TRANSLATORS: the user didn't read the man page
221 msgid "Failed to parse arguments"
222 msgstr "Nem sikerült feldolgozni az argumentumokat"
223
224 #. TRANSLATORS: turn on all debugging
225 msgid "Show debugging information for all files"
226 msgstr "Hibakeresési információk megjelenítése minden fájlnál"
227
228 #. TRANSLATORS: for the --verbose arg
229 msgid "Debugging Options"
230 msgstr "Hibakeresési beállítások"
231
232 #. TRANSLATORS: for the --verbose arg
233 msgid "Show debugging options"
234 msgstr "Hibakeresési beállítások megjelenítése"
235
236 #. TRANSLATORS: exit after we've started up, used for user profiling
237 msgid "Exit after a small delay"
238 msgstr "Kilépés egy kis késleltetés után"
239
240 #. TRANSLATORS: exit straight away, used for automatic profiling
241 msgid "Exit after the engine has loaded"
242 msgstr "Kilépés a motor betöltődése után"
243
244 #. TRANSLATORS: program name
245 msgid "Firmware Update Daemon"
246 msgstr ""
247
248 #. TRANSLATORS: program summary
249 msgid "Firmware Update D-Bus Service"
250 msgstr "Firmware frissítés D-Bus szolgáltatás"
89251
90252 #. TRANSLATORS: daemon is inactive
91253 msgid "Idle"
148310 msgid "Updating %s from %s to %s... "
149311 msgstr "%s frissítése: %s -> %s…"
150312
151 msgid "OK"
152 msgstr ""
153
154313 #. TRANSLATORS: first replacement is device name
155314 #, c-format
156315 msgid "%s has firmware updates:"
157316 msgstr "%s firmware frissítésekkel rendelkezik:"
158317
318 #. TRANSLATORS: a GUID for the hardware
319 msgid "GUID"
320 msgstr ""
321
159322 #. TRANSLATORS: section header for firmware version
160323 msgid "Version"
161324 msgstr "Verzió"
240403 msgid "Firmware Utility"
241404 msgstr ""
242405
243 #. TRANSLATORS: the user didn't read the man page
244 msgid "Failed to parse arguments"
245 msgstr "Nem sikerült feldolgozni az argumentumokat"
246
247406 #. TRANSLATORS: the user is in a bad place
248407 msgid "Failed to connect to D-Bus"
249408 msgstr "Nem sikerült csatlakozni a D-Bus rendszerhez"
77 msgstr ""
88 "Project-Id-Version: fwupd\n"
99 "Report-Msgid-Bugs-To: \n"
10 "POT-Creation-Date: 2015-09-10 09:28+0100\n"
11 "PO-Revision-Date: 2015-09-10 08:28+0000\n"
12 "Last-Translator: Richard Hughes <richard@hughsie.com>\n"
10 "POT-Creation-Date: 2015-12-07 12:22+0000\n"
11 "PO-Revision-Date: 2015-12-07 14:56+0000\n"
12 "Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n"
1313 "Language-Team: Polish (http://www.transifex.com/hughsie/fwupd/language/pl/)\n"
1414 "MIME-Version: 1.0\n"
1515 "Content-Type: text/plain; charset=UTF-8\n"
5050 "Authentication is required to downgrade the firmware on a removable device"
5151 msgstr "Wymagane jest uwierzytelnienie, aby zainstalować poprzednią wersję oprogramowania sprzętowego urządzenia wymiennego"
5252
53 #. TRANSLATORS: turn on all debugging
54 msgid "Show debugging information for all files"
55 msgstr "Wyświetla informacje o debugowaniu dla wszystkich plików"
56
57 #. TRANSLATORS: for the --verbose arg
58 msgid "Debugging Options"
59 msgstr "Opcje debugowania"
60
61 #. TRANSLATORS: for the --verbose arg
62 msgid "Show debugging options"
63 msgstr "Wyświetla opcje debugowania"
64
65 #. TRANSLATORS: exit after we've started up, used for user profiling
66 msgid "Exit after a small delay"
67 msgstr "Kończy działanie po małym opóźnieniu"
68
69 #. TRANSLATORS: exit straight away, used for automatic profiling
70 msgid "Exit after the engine has loaded"
71 msgstr "Kończy działanie po wczytaniu mechanizmu"
72
73 #. TRANSLATORS: program name
74 msgid "Firmware Update Daemon"
75 msgstr "Usługa aktualizacji oprogramowania sprzętowego"
76
77 #. TRANSLATORS: program summary
78 msgid "Firmware Update D-Bus Service"
79 msgstr "Usługa D-Bus aktualizacji oprogramowania sprzętowego"
80
8153 #. TRANSLATORS: this is a command alias, e.g. 'get-devices'
8254 #, c-format
8355 msgid "Alias to %s"
8658 #. TRANSLATORS: error message
8759 msgid "Command not found"
8860 msgstr "Nie odnaleziono polecenia"
61
62 #. TRANSLATORS: when an action has completed
63 msgid "OK"
64 msgstr "OK"
65
66 #. TRANSLATORS: when moving from runtime to DFU mode
67 msgid "Detaching"
68 msgstr "Odłączanie"
69
70 #. TRANSLATORS: when moving from DFU to runtime mode
71 msgid "Attaching"
72 msgstr "Podłączanie"
73
74 #. TRANSLATORS: when copying from host to device
75 msgid "Downloading"
76 msgstr "Pobieranie"
77
78 #. TRANSLATORS: when copying from device to host
79 msgid "Uploading"
80 msgstr "Wysyłanie"
81
82 #. TRANSLATORS: this is when a device is hotplugged
83 msgid "Added"
84 msgstr "Dodano"
85
86 #. TRANSLATORS: this is when a device is hotplugged
87 msgid "Removed"
88 msgstr "Usunięto"
89
90 #. TRANSLATORS: this is when a device is hotplugged
91 msgid "Changed"
92 msgstr "Zmieniono"
93
94 #. TRANSLATORS: this is when a device ctrl+c's a watch
95 msgid "Cancelled"
96 msgstr "Anulowano"
97
98 #. TRANSLATORS: Appstream ID for the hardware type
99 msgid "ID"
100 msgstr "Identyfikator"
101
102 #. TRANSLATORS: interface name, e.g. "Flash"
103 msgid "Name"
104 msgstr "Nazwa"
105
106 #. TRANSLATORS: this is the encryption method used when writing
107 msgid "Cipher"
108 msgstr "Szyfr"
109
110 #. TRANSLATORS: these are areas of memory on the chip
111 msgid "Region"
112 msgstr "Region"
113
114 #. TRANSLATORS: detected a DFU device
115 msgid "Found"
116 msgstr "Odnaleziono"
117
118 #. TRANSLATORS: probably not run as root...
119 #. TRANSLATORS: device has failed to report status
120 #. TRANSLATORS: device status, e.g. "OK"
121 msgid "Status"
122 msgstr "Stan"
123
124 msgid "Unknown: permission denied"
125 msgstr "Nieznane: brak uprawnień"
126
127 #. TRANSLATORS: device mode, e.g. runtime or DFU
128 msgid "Mode"
129 msgstr "Tryb"
130
131 #. TRANSLATORS: device state, i.e. appIDLE
132 msgid "State"
133 msgstr "Stan"
134
135 #. TRANSLATORS: device quirks, i.e. things that
136 #. * it does that we have to work around
137 msgid "Quirks"
138 msgstr "Poprawki"
139
140 #. TRANSLATORS: command description
141 msgid "Convert firmware to DFU format"
142 msgstr "Konwertuje oprogramowanie sprzętowe do formatu DFU"
143
144 #. TRANSLATORS: command description
145 msgid "Merge multiple firmware files into one"
146 msgstr "Łączy wiele plików oprogramowania sprzętowego w jeden plik"
147
148 #. TRANSLATORS: command description
149 msgid "Set vendor ID on firmware file"
150 msgstr "Ustawia identyfikator producenta pliku oprogramowania sprzętowego"
151
152 #. TRANSLATORS: command description
153 msgid "Set product ID on firmware file"
154 msgstr "Ustawia identyfikator produktu pliku oprogramowania sprzętowego"
155
156 #. TRANSLATORS: command description
157 msgid "Set release version on firmware file"
158 msgstr "Ustawia wersję wydania pliku oprogramowania sprzętowego"
159
160 #. TRANSLATORS: command description
161 msgid "Set alternative number on firmware file"
162 msgstr "Ustawia alternatywny numer pliku oprogramowania sprzętowego"
163
164 #. TRANSLATORS: command description
165 msgid "Set alternative name on firmware file"
166 msgstr "Ustawia alternatywną nazwę pliku oprogramowania sprzętowego"
167
168 #. TRANSLATORS: command description
169 msgid "Attach DFU capable device back to runtime"
170 msgstr "Podłącza urządzenie DFU z powrotem do środowiska wykonawczego"
171
172 #. TRANSLATORS: command description
173 msgid "Read firmware from device into a file"
174 msgstr "Odczytuje oprogramowanie sprzętowe z urządzenia do pliku"
175
176 #. TRANSLATORS: command description
177 msgid "Read firmware from one partition into a file"
178 msgstr "Odczytuje oprogramowanie sprzętowe z jednej partycji do pliku"
179
180 #. TRANSLATORS: command description
181 msgid "Write firmware from file into device"
182 msgstr "Zapisuje oprogramowanie sprzętowe z pliku na urządzenie"
183
184 #. TRANSLATORS: command description
185 msgid "Write firmware from file into one partition"
186 msgstr "Zapisuje oprogramowanie sprzętowe z pliku na jedną partycję"
187
188 #. TRANSLATORS: command description
189 msgid "List currently attached DFU capable devices"
190 msgstr "Wyświetla listę obecnie podłączonych urządzeń DFU"
191
192 #. TRANSLATORS: command description
193 msgid "Detach currently attached DFU capable device"
194 msgstr "Odłącza obecnie podłączone urządzenie DFU"
195
196 #. TRANSLATORS: command description
197 msgid "Dump details about a firmware file"
198 msgstr "Zrzuca informacje o pliku oprogramowania sprzętowego"
199
200 #. TRANSLATORS: command description
201 msgid "Watch DFU devices being hotplugged"
202 msgstr "Obserwuje podłączanie urządzeń DFU w czasie działania"
203
204 #. TRANSLATORS: command description
205 msgid "Encrypt firmware data"
206 msgstr "Szyfruje dane oprogramowania sprzętowego"
207
208 #. TRANSLATORS: command description
209 msgid "Decrypt firmware data"
210 msgstr "Odszyfrowuje dane oprogramowania sprzętowego"
211
212 #. TRANSLATORS: command description
213 msgid "Sets metadata on a firmware file"
214 msgstr "Ustawia metadane pliku oprogramowania sprzętowego"
215
216 #. TRANSLATORS: DFU stands for device firmware update
217 msgid "DFU Utility"
218 msgstr "Narzędzie DFU"
219
220 #. TRANSLATORS: the user didn't read the man page
221 msgid "Failed to parse arguments"
222 msgstr "Przetworzenie parametrów się nie powiodło"
223
224 #. TRANSLATORS: turn on all debugging
225 msgid "Show debugging information for all files"
226 msgstr "Wyświetla informacje o debugowaniu dla wszystkich plików"
227
228 #. TRANSLATORS: for the --verbose arg
229 msgid "Debugging Options"
230 msgstr "Opcje debugowania"
231
232 #. TRANSLATORS: for the --verbose arg
233 msgid "Show debugging options"
234 msgstr "Wyświetla opcje debugowania"
235
236 #. TRANSLATORS: exit after we've started up, used for user profiling
237 msgid "Exit after a small delay"
238 msgstr "Kończy działanie po małym opóźnieniu"
239
240 #. TRANSLATORS: exit straight away, used for automatic profiling
241 msgid "Exit after the engine has loaded"
242 msgstr "Kończy działanie po wczytaniu mechanizmu"
243
244 #. TRANSLATORS: program name
245 msgid "Firmware Update Daemon"
246 msgstr "Usługa aktualizacji oprogramowania sprzętowego"
247
248 #. TRANSLATORS: program summary
249 msgid "Firmware Update D-Bus Service"
250 msgstr "Usługa D-Bus aktualizacji oprogramowania sprzętowego"
89251
90252 #. TRANSLATORS: daemon is inactive
91253 msgid "Idle"
148310 msgid "Updating %s from %s to %s... "
149311 msgstr "Aktualizowanie %s z wersji %s do %s… "
150312
151 msgid "OK"
152 msgstr "OK"
153
154313 #. TRANSLATORS: first replacement is device name
155314 #, c-format
156315 msgid "%s has firmware updates:"
157316 msgstr "Dostępne są aktualizacje oprogramowania sprzętowego dla urządzenia %s:"
158317
318 #. TRANSLATORS: a GUID for the hardware
319 msgid "GUID"
320 msgstr "GUID"
321
159322 #. TRANSLATORS: section header for firmware version
160323 msgid "Version"
161324 msgstr "Wersja"
240403 msgid "Firmware Utility"
241404 msgstr "Narzędzie oprogramowania sprzętowego"
242405
243 #. TRANSLATORS: the user didn't read the man page
244 msgid "Failed to parse arguments"
245 msgstr "Przetworzenie parametrów się nie powiodło"
246
247406 #. TRANSLATORS: the user is in a bad place
248407 msgid "Failed to connect to D-Bus"
249408 msgstr "Połączenie z magistralą D-Bus się nie powiodło"
88 msgstr ""
99 "Project-Id-Version: fwupd\n"
1010 "Report-Msgid-Bugs-To: \n"
11 "POT-Creation-Date: 2015-10-28 09:58+0000\n"
12 "PO-Revision-Date: 2015-10-07 12:34+0000\n"
13 "Last-Translator: Derek Stavis <dekestavis@gmail.com>\n"
11 "POT-Creation-Date: 2015-12-07 12:22+0000\n"
12 "PO-Revision-Date: 2015-12-07 12:22+0000\n"
13 "Last-Translator: Richard Hughes <richard@hughsie.com>\n"
1414 "Language-Team: Portuguese (Brazil) (http://www.transifex.com/hughsie/fwupd/language/pt_BR/)\n"
1515 "MIME-Version: 1.0\n"
1616 "Content-Type: text/plain; charset=UTF-8\n"
5151 "Authentication is required to downgrade the firmware on a removable device"
5252 msgstr "É requerida autenticação para voltar a versão do firmware em um dispositivo removível"
5353
54 #. TRANSLATORS: turn on all debugging
55 msgid "Show debugging information for all files"
56 msgstr "Mostrar informações de depuração para todos os arquivos"
57
58 #. TRANSLATORS: for the --verbose arg
59 msgid "Debugging Options"
60 msgstr "Opções de depuração"
61
62 #. TRANSLATORS: for the --verbose arg
63 msgid "Show debugging options"
64 msgstr "Mostrar opções de depuração"
65
66 #. TRANSLATORS: exit after we've started up, used for user profiling
67 msgid "Exit after a small delay"
68 msgstr "Sair após pequeno atraso"
69
70 #. TRANSLATORS: exit straight away, used for automatic profiling
71 msgid "Exit after the engine has loaded"
72 msgstr "Sair após o carregamento do motor"
73
74 #. TRANSLATORS: program name
75 msgid "Firmware Update Daemon"
76 msgstr "Daemon de Atualização de Firmware"
77
78 #. TRANSLATORS: program summary
79 msgid "Firmware Update D-Bus Service"
80 msgstr "Serviço D-Bus de Atualização de Firmware"
81
8254 #. TRANSLATORS: this is a command alias, e.g. 'get-devices'
8355 #, c-format
8456 msgid "Alias to %s"
8759 #. TRANSLATORS: error message
8860 msgid "Command not found"
8961 msgstr "Comando não encontrado"
62
63 #. TRANSLATORS: when an action has completed
64 msgid "OK"
65 msgstr "OK"
66
67 #. TRANSLATORS: when moving from runtime to DFU mode
68 msgid "Detaching"
69 msgstr ""
70
71 #. TRANSLATORS: when moving from DFU to runtime mode
72 msgid "Attaching"
73 msgstr ""
74
75 #. TRANSLATORS: when copying from host to device
76 msgid "Downloading"
77 msgstr ""
78
79 #. TRANSLATORS: when copying from device to host
80 msgid "Uploading"
81 msgstr ""
82
83 #. TRANSLATORS: this is when a device is hotplugged
84 msgid "Added"
85 msgstr ""
86
87 #. TRANSLATORS: this is when a device is hotplugged
88 msgid "Removed"
89 msgstr ""
90
91 #. TRANSLATORS: this is when a device is hotplugged
92 msgid "Changed"
93 msgstr ""
94
95 #. TRANSLATORS: this is when a device ctrl+c's a watch
96 msgid "Cancelled"
97 msgstr ""
98
99 #. TRANSLATORS: Appstream ID for the hardware type
100 msgid "ID"
101 msgstr ""
102
103 #. TRANSLATORS: interface name, e.g. "Flash"
104 msgid "Name"
105 msgstr ""
106
107 #. TRANSLATORS: this is the encryption method used when writing
108 msgid "Cipher"
109 msgstr ""
110
111 #. TRANSLATORS: these are areas of memory on the chip
112 msgid "Region"
113 msgstr ""
114
115 #. TRANSLATORS: detected a DFU device
116 msgid "Found"
117 msgstr ""
118
119 #. TRANSLATORS: probably not run as root...
120 #. TRANSLATORS: device has failed to report status
121 #. TRANSLATORS: device status, e.g. "OK"
122 msgid "Status"
123 msgstr ""
124
125 msgid "Unknown: permission denied"
126 msgstr ""
127
128 #. TRANSLATORS: device mode, e.g. runtime or DFU
129 msgid "Mode"
130 msgstr ""
131
132 #. TRANSLATORS: device state, i.e. appIDLE
133 msgid "State"
134 msgstr ""
135
136 #. TRANSLATORS: device quirks, i.e. things that
137 #. * it does that we have to work around
138 msgid "Quirks"
139 msgstr ""
140
141 #. TRANSLATORS: command description
142 msgid "Convert firmware to DFU format"
143 msgstr ""
144
145 #. TRANSLATORS: command description
146 msgid "Merge multiple firmware files into one"
147 msgstr ""
148
149 #. TRANSLATORS: command description
150 msgid "Set vendor ID on firmware file"
151 msgstr ""
152
153 #. TRANSLATORS: command description
154 msgid "Set product ID on firmware file"
155 msgstr ""
156
157 #. TRANSLATORS: command description
158 msgid "Set release version on firmware file"
159 msgstr ""
160
161 #. TRANSLATORS: command description
162 msgid "Set alternative number on firmware file"
163 msgstr ""
164
165 #. TRANSLATORS: command description
166 msgid "Set alternative name on firmware file"
167 msgstr ""
168
169 #. TRANSLATORS: command description
170 msgid "Attach DFU capable device back to runtime"
171 msgstr ""
172
173 #. TRANSLATORS: command description
174 msgid "Read firmware from device into a file"
175 msgstr ""
176
177 #. TRANSLATORS: command description
178 msgid "Read firmware from one partition into a file"
179 msgstr ""
180
181 #. TRANSLATORS: command description
182 msgid "Write firmware from file into device"
183 msgstr ""
184
185 #. TRANSLATORS: command description
186 msgid "Write firmware from file into one partition"
187 msgstr ""
188
189 #. TRANSLATORS: command description
190 msgid "List currently attached DFU capable devices"
191 msgstr ""
192
193 #. TRANSLATORS: command description
194 msgid "Detach currently attached DFU capable device"
195 msgstr ""
196
197 #. TRANSLATORS: command description
198 msgid "Dump details about a firmware file"
199 msgstr ""
200
201 #. TRANSLATORS: command description
202 msgid "Watch DFU devices being hotplugged"
203 msgstr ""
204
205 #. TRANSLATORS: command description
206 msgid "Encrypt firmware data"
207 msgstr ""
208
209 #. TRANSLATORS: command description
210 msgid "Decrypt firmware data"
211 msgstr ""
212
213 #. TRANSLATORS: command description
214 msgid "Sets metadata on a firmware file"
215 msgstr ""
216
217 #. TRANSLATORS: DFU stands for device firmware update
218 msgid "DFU Utility"
219 msgstr ""
220
221 #. TRANSLATORS: the user didn't read the man page
222 msgid "Failed to parse arguments"
223 msgstr "Falha ao interpretar argumentos"
224
225 #. TRANSLATORS: turn on all debugging
226 msgid "Show debugging information for all files"
227 msgstr "Mostrar informações de depuração para todos os arquivos"
228
229 #. TRANSLATORS: for the --verbose arg
230 msgid "Debugging Options"
231 msgstr "Opções de depuração"
232
233 #. TRANSLATORS: for the --verbose arg
234 msgid "Show debugging options"
235 msgstr "Mostrar opções de depuração"
236
237 #. TRANSLATORS: exit after we've started up, used for user profiling
238 msgid "Exit after a small delay"
239 msgstr "Sair após pequeno atraso"
240
241 #. TRANSLATORS: exit straight away, used for automatic profiling
242 msgid "Exit after the engine has loaded"
243 msgstr "Sair após o carregamento do motor"
244
245 #. TRANSLATORS: program name
246 msgid "Firmware Update Daemon"
247 msgstr "Daemon de Atualização de Firmware"
248
249 #. TRANSLATORS: program summary
250 msgid "Firmware Update D-Bus Service"
251 msgstr "Serviço D-Bus de Atualização de Firmware"
90252
91253 #. TRANSLATORS: daemon is inactive
92254 msgid "Idle"
149311 msgid "Updating %s from %s to %s... "
150312 msgstr "Atualizando %s de %s para %s..."
151313
152 msgid "OK"
153 msgstr "OK"
154
155314 #. TRANSLATORS: first replacement is device name
156315 #, c-format
157316 msgid "%s has firmware updates:"
158317 msgstr "%s tem atualizações:"
159318
319 #. TRANSLATORS: a GUID for the hardware
320 msgid "GUID"
321 msgstr ""
322
160323 #. TRANSLATORS: section header for firmware version
161324 msgid "Version"
162325 msgstr "Versão"
241404 msgid "Firmware Utility"
242405 msgstr "Utilitário de Firmware"
243406
244 #. TRANSLATORS: the user didn't read the man page
245 msgid "Failed to parse arguments"
246 msgstr "Falha ao interpretar argumentos"
247
248407 #. TRANSLATORS: the user is in a bad place
249408 msgid "Failed to connect to D-Bus"
250409 msgstr "Falha ao conectar ao D-Bus"
77 msgstr ""
88 "Project-Id-Version: fwupd\n"
99 "Report-Msgid-Bugs-To: \n"
10 "POT-Creation-Date: 2015-09-10 09:28+0100\n"
11 "PO-Revision-Date: 2015-09-10 08:28+0000\n"
10 "POT-Creation-Date: 2015-12-07 12:22+0000\n"
11 "PO-Revision-Date: 2015-12-07 12:22+0000\n"
1212 "Last-Translator: Richard Hughes <richard@hughsie.com>\n"
1313 "Language-Team: Russian (http://www.transifex.com/hughsie/fwupd/language/ru/)\n"
1414 "MIME-Version: 1.0\n"
5050 "Authentication is required to downgrade the firmware on a removable device"
5151 msgstr "Для понижения версии микропрограммы на съёмном устройстве требуется аутентификация"
5252
53 #. TRANSLATORS: turn on all debugging
54 msgid "Show debugging information for all files"
55 msgstr "Показать отладочную информацию для всех файлов"
56
57 #. TRANSLATORS: for the --verbose arg
58 msgid "Debugging Options"
59 msgstr "Параметры отладки"
60
61 #. TRANSLATORS: for the --verbose arg
62 msgid "Show debugging options"
63 msgstr "Показать параметры отладки"
64
65 #. TRANSLATORS: exit after we've started up, used for user profiling
66 msgid "Exit after a small delay"
67 msgstr "Выйти после небольшой задержки"
68
69 #. TRANSLATORS: exit straight away, used for automatic profiling
70 msgid "Exit after the engine has loaded"
71 msgstr "Выйти после загрузки движка"
72
73 #. TRANSLATORS: program name
74 msgid "Firmware Update Daemon"
75 msgstr "Служба обновления микропрограммы"
76
77 #. TRANSLATORS: program summary
78 msgid "Firmware Update D-Bus Service"
79 msgstr "D-Bus служба обновления микропрограммы"
80
8153 #. TRANSLATORS: this is a command alias, e.g. 'get-devices'
8254 #, c-format
8355 msgid "Alias to %s"
8658 #. TRANSLATORS: error message
8759 msgid "Command not found"
8860 msgstr "Команда не найдена"
61
62 #. TRANSLATORS: when an action has completed
63 msgid "OK"
64 msgstr "ОК"
65
66 #. TRANSLATORS: when moving from runtime to DFU mode
67 msgid "Detaching"
68 msgstr ""
69
70 #. TRANSLATORS: when moving from DFU to runtime mode
71 msgid "Attaching"
72 msgstr ""
73
74 #. TRANSLATORS: when copying from host to device
75 msgid "Downloading"
76 msgstr ""
77
78 #. TRANSLATORS: when copying from device to host
79 msgid "Uploading"
80 msgstr ""
81
82 #. TRANSLATORS: this is when a device is hotplugged
83 msgid "Added"
84 msgstr ""
85
86 #. TRANSLATORS: this is when a device is hotplugged
87 msgid "Removed"
88 msgstr ""
89
90 #. TRANSLATORS: this is when a device is hotplugged
91 msgid "Changed"
92 msgstr ""
93
94 #. TRANSLATORS: this is when a device ctrl+c's a watch
95 msgid "Cancelled"
96 msgstr ""
97
98 #. TRANSLATORS: Appstream ID for the hardware type
99 msgid "ID"
100 msgstr ""
101
102 #. TRANSLATORS: interface name, e.g. "Flash"
103 msgid "Name"
104 msgstr ""
105
106 #. TRANSLATORS: this is the encryption method used when writing
107 msgid "Cipher"
108 msgstr ""
109
110 #. TRANSLATORS: these are areas of memory on the chip
111 msgid "Region"
112 msgstr ""
113
114 #. TRANSLATORS: detected a DFU device
115 msgid "Found"
116 msgstr ""
117
118 #. TRANSLATORS: probably not run as root...
119 #. TRANSLATORS: device has failed to report status
120 #. TRANSLATORS: device status, e.g. "OK"
121 msgid "Status"
122 msgstr ""
123
124 msgid "Unknown: permission denied"
125 msgstr ""
126
127 #. TRANSLATORS: device mode, e.g. runtime or DFU
128 msgid "Mode"
129 msgstr ""
130
131 #. TRANSLATORS: device state, i.e. appIDLE
132 msgid "State"
133 msgstr ""
134
135 #. TRANSLATORS: device quirks, i.e. things that
136 #. * it does that we have to work around
137 msgid "Quirks"
138 msgstr ""
139
140 #. TRANSLATORS: command description
141 msgid "Convert firmware to DFU format"
142 msgstr ""
143
144 #. TRANSLATORS: command description
145 msgid "Merge multiple firmware files into one"
146 msgstr ""
147
148 #. TRANSLATORS: command description
149 msgid "Set vendor ID on firmware file"
150 msgstr ""
151
152 #. TRANSLATORS: command description
153 msgid "Set product ID on firmware file"
154 msgstr ""
155
156 #. TRANSLATORS: command description
157 msgid "Set release version on firmware file"
158 msgstr ""
159
160 #. TRANSLATORS: command description
161 msgid "Set alternative number on firmware file"
162 msgstr ""
163
164 #. TRANSLATORS: command description
165 msgid "Set alternative name on firmware file"
166 msgstr ""
167
168 #. TRANSLATORS: command description
169 msgid "Attach DFU capable device back to runtime"
170 msgstr ""
171
172 #. TRANSLATORS: command description
173 msgid "Read firmware from device into a file"
174 msgstr ""
175
176 #. TRANSLATORS: command description
177 msgid "Read firmware from one partition into a file"
178 msgstr ""
179
180 #. TRANSLATORS: command description
181 msgid "Write firmware from file into device"
182 msgstr ""
183
184 #. TRANSLATORS: command description
185 msgid "Write firmware from file into one partition"
186 msgstr ""
187
188 #. TRANSLATORS: command description
189 msgid "List currently attached DFU capable devices"
190 msgstr ""
191
192 #. TRANSLATORS: command description
193 msgid "Detach currently attached DFU capable device"
194 msgstr ""
195
196 #. TRANSLATORS: command description
197 msgid "Dump details about a firmware file"
198 msgstr ""
199
200 #. TRANSLATORS: command description
201 msgid "Watch DFU devices being hotplugged"
202 msgstr ""
203
204 #. TRANSLATORS: command description
205 msgid "Encrypt firmware data"
206 msgstr ""
207
208 #. TRANSLATORS: command description
209 msgid "Decrypt firmware data"
210 msgstr ""
211
212 #. TRANSLATORS: command description
213 msgid "Sets metadata on a firmware file"
214 msgstr ""
215
216 #. TRANSLATORS: DFU stands for device firmware update
217 msgid "DFU Utility"
218 msgstr ""
219
220 #. TRANSLATORS: the user didn't read the man page
221 msgid "Failed to parse arguments"
222 msgstr "Не удалось разобрать аргументы"
223
224 #. TRANSLATORS: turn on all debugging
225 msgid "Show debugging information for all files"
226 msgstr "Показать отладочную информацию для всех файлов"
227
228 #. TRANSLATORS: for the --verbose arg
229 msgid "Debugging Options"
230 msgstr "Параметры отладки"
231
232 #. TRANSLATORS: for the --verbose arg
233 msgid "Show debugging options"
234 msgstr "Показать параметры отладки"
235
236 #. TRANSLATORS: exit after we've started up, used for user profiling
237 msgid "Exit after a small delay"
238 msgstr "Выйти после небольшой задержки"
239
240 #. TRANSLATORS: exit straight away, used for automatic profiling
241 msgid "Exit after the engine has loaded"
242 msgstr "Выйти после загрузки движка"
243
244 #. TRANSLATORS: program name
245 msgid "Firmware Update Daemon"
246 msgstr "Служба обновления микропрограммы"
247
248 #. TRANSLATORS: program summary
249 msgid "Firmware Update D-Bus Service"
250 msgstr "D-Bus служба обновления микропрограммы"
89251
90252 #. TRANSLATORS: daemon is inactive
91253 msgid "Idle"
148310 msgid "Updating %s from %s to %s... "
149311 msgstr "Обновление %s с %s на %s…"
150312
151 msgid "OK"
152 msgstr "ОК"
153
154313 #. TRANSLATORS: first replacement is device name
155314 #, c-format
156315 msgid "%s has firmware updates:"
157316 msgstr "У %s есть обновления микропрограммы:"
158317
318 #. TRANSLATORS: a GUID for the hardware
319 msgid "GUID"
320 msgstr ""
321
159322 #. TRANSLATORS: section header for firmware version
160323 msgid "Version"
161324 msgstr "Версия"
240403 msgid "Firmware Utility"
241404 msgstr "Средство работы с микропрограммами"
242405
243 #. TRANSLATORS: the user didn't read the man page
244 msgid "Failed to parse arguments"
245 msgstr "Не удалось разобрать аргументы"
246
247406 #. TRANSLATORS: the user is in a bad place
248407 msgid "Failed to connect to D-Bus"
249408 msgstr "Не удалось подключиться к D-Bus"
77 msgstr ""
88 "Project-Id-Version: fwupd\n"
99 "Report-Msgid-Bugs-To: \n"
10 "POT-Creation-Date: 2015-09-10 09:28+0100\n"
11 "PO-Revision-Date: 2015-09-10 08:28+0000\n"
12 "Last-Translator: Richard Hughes <richard@hughsie.com>\n"
10 "POT-Creation-Date: 2015-12-07 12:22+0000\n"
11 "PO-Revision-Date: 2015-12-07 12:35+0000\n"
12 "Last-Translator: Dušan Kazik <prescott66@gmail.com>\n"
1313 "Language-Team: Slovak (http://www.transifex.com/hughsie/fwupd/language/sk/)\n"
1414 "MIME-Version: 1.0\n"
1515 "Content-Type: text/plain; charset=UTF-8\n"
5050 "Authentication is required to downgrade the firmware on a removable device"
5151 msgstr "Vyžaduje sa overenie totožnosti na prechod na staršiu verziu firmvéru vymeniteľného zariadenia"
5252
53 #. TRANSLATORS: turn on all debugging
54 msgid "Show debugging information for all files"
55 msgstr "Zobrazí ladiace informácie pre všetky súbory"
56
57 #. TRANSLATORS: for the --verbose arg
58 msgid "Debugging Options"
59 msgstr "Voľby ladenia"
60
61 #. TRANSLATORS: for the --verbose arg
62 msgid "Show debugging options"
63 msgstr "Zobrazí voľby ladenia"
64
65 #. TRANSLATORS: exit after we've started up, used for user profiling
66 msgid "Exit after a small delay"
67 msgstr "Skončí po krátkom oneskorení"
68
69 #. TRANSLATORS: exit straight away, used for automatic profiling
70 msgid "Exit after the engine has loaded"
71 msgstr "Skončí po načítaní jadra"
72
73 #. TRANSLATORS: program name
74 msgid "Firmware Update Daemon"
75 msgstr "Démon aktualizácie firmvéru"
76
77 #. TRANSLATORS: program summary
78 msgid "Firmware Update D-Bus Service"
79 msgstr "Služba zbernice D-Bus na aktualizovanie firmvéru"
80
8153 #. TRANSLATORS: this is a command alias, e.g. 'get-devices'
8254 #, c-format
8355 msgid "Alias to %s"
8658 #. TRANSLATORS: error message
8759 msgid "Command not found"
8860 msgstr "Príkaz nenájdený"
61
62 #. TRANSLATORS: when an action has completed
63 msgid "OK"
64 msgstr "OK"
65
66 #. TRANSLATORS: when moving from runtime to DFU mode
67 msgid "Detaching"
68 msgstr ""
69
70 #. TRANSLATORS: when moving from DFU to runtime mode
71 msgid "Attaching"
72 msgstr ""
73
74 #. TRANSLATORS: when copying from host to device
75 msgid "Downloading"
76 msgstr "Preberá sa"
77
78 #. TRANSLATORS: when copying from device to host
79 msgid "Uploading"
80 msgstr "Odovzdáva sa"
81
82 #. TRANSLATORS: this is when a device is hotplugged
83 msgid "Added"
84 msgstr "Pridané"
85
86 #. TRANSLATORS: this is when a device is hotplugged
87 msgid "Removed"
88 msgstr "Odstránené"
89
90 #. TRANSLATORS: this is when a device is hotplugged
91 msgid "Changed"
92 msgstr "Zmenené"
93
94 #. TRANSLATORS: this is when a device ctrl+c's a watch
95 msgid "Cancelled"
96 msgstr "Zrušené"
97
98 #. TRANSLATORS: Appstream ID for the hardware type
99 msgid "ID"
100 msgstr "ID"
101
102 #. TRANSLATORS: interface name, e.g. "Flash"
103 msgid "Name"
104 msgstr "Názov"
105
106 #. TRANSLATORS: this is the encryption method used when writing
107 msgid "Cipher"
108 msgstr "Šifra"
109
110 #. TRANSLATORS: these are areas of memory on the chip
111 msgid "Region"
112 msgstr "Oblasť"
113
114 #. TRANSLATORS: detected a DFU device
115 msgid "Found"
116 msgstr "Nájdené"
117
118 #. TRANSLATORS: probably not run as root...
119 #. TRANSLATORS: device has failed to report status
120 #. TRANSLATORS: device status, e.g. "OK"
121 msgid "Status"
122 msgstr "Stav"
123
124 msgid "Unknown: permission denied"
125 msgstr "Neznáme: prístup zamietnutý"
126
127 #. TRANSLATORS: device mode, e.g. runtime or DFU
128 msgid "Mode"
129 msgstr "Režim"
130
131 #. TRANSLATORS: device state, i.e. appIDLE
132 msgid "State"
133 msgstr "Stav"
134
135 #. TRANSLATORS: device quirks, i.e. things that
136 #. * it does that we have to work around
137 msgid "Quirks"
138 msgstr ""
139
140 #. TRANSLATORS: command description
141 msgid "Convert firmware to DFU format"
142 msgstr "Skonvertuje firmvér do formátu DFU"
143
144 #. TRANSLATORS: command description
145 msgid "Merge multiple firmware files into one"
146 msgstr "Zlúči viacero súborov s firmvérami do jedného"
147
148 #. TRANSLATORS: command description
149 msgid "Set vendor ID on firmware file"
150 msgstr "Nastaví ID výrobcu pre súbor s firmvérom"
151
152 #. TRANSLATORS: command description
153 msgid "Set product ID on firmware file"
154 msgstr "Nastaví ID produktu pre súbor s firmvérom"
155
156 #. TRANSLATORS: command description
157 msgid "Set release version on firmware file"
158 msgstr "Nastaví verziu vydania pre súbor s firmvérom"
159
160 #. TRANSLATORS: command description
161 msgid "Set alternative number on firmware file"
162 msgstr "Nastaví alternatívne číslo pre súbor s firmvérom"
163
164 #. TRANSLATORS: command description
165 msgid "Set alternative name on firmware file"
166 msgstr "Nastaví alternatívny názov pre súbor s firmvérom"
167
168 #. TRANSLATORS: command description
169 msgid "Attach DFU capable device back to runtime"
170 msgstr ""
171
172 #. TRANSLATORS: command description
173 msgid "Read firmware from device into a file"
174 msgstr "Prečíta firmvér zo zariadenia do súboru"
175
176 #. TRANSLATORS: command description
177 msgid "Read firmware from one partition into a file"
178 msgstr ""
179
180 #. TRANSLATORS: command description
181 msgid "Write firmware from file into device"
182 msgstr ""
183
184 #. TRANSLATORS: command description
185 msgid "Write firmware from file into one partition"
186 msgstr ""
187
188 #. TRANSLATORS: command description
189 msgid "List currently attached DFU capable devices"
190 msgstr ""
191
192 #. TRANSLATORS: command description
193 msgid "Detach currently attached DFU capable device"
194 msgstr ""
195
196 #. TRANSLATORS: command description
197 msgid "Dump details about a firmware file"
198 msgstr ""
199
200 #. TRANSLATORS: command description
201 msgid "Watch DFU devices being hotplugged"
202 msgstr ""
203
204 #. TRANSLATORS: command description
205 msgid "Encrypt firmware data"
206 msgstr ""
207
208 #. TRANSLATORS: command description
209 msgid "Decrypt firmware data"
210 msgstr ""
211
212 #. TRANSLATORS: command description
213 msgid "Sets metadata on a firmware file"
214 msgstr ""
215
216 #. TRANSLATORS: DFU stands for device firmware update
217 msgid "DFU Utility"
218 msgstr ""
219
220 #. TRANSLATORS: the user didn't read the man page
221 msgid "Failed to parse arguments"
222 msgstr "Zlyhalo analyzovanie parametrov"
223
224 #. TRANSLATORS: turn on all debugging
225 msgid "Show debugging information for all files"
226 msgstr "Zobrazí ladiace informácie pre všetky súbory"
227
228 #. TRANSLATORS: for the --verbose arg
229 msgid "Debugging Options"
230 msgstr "Voľby ladenia"
231
232 #. TRANSLATORS: for the --verbose arg
233 msgid "Show debugging options"
234 msgstr "Zobrazí voľby ladenia"
235
236 #. TRANSLATORS: exit after we've started up, used for user profiling
237 msgid "Exit after a small delay"
238 msgstr "Skončí po krátkom oneskorení"
239
240 #. TRANSLATORS: exit straight away, used for automatic profiling
241 msgid "Exit after the engine has loaded"
242 msgstr "Skončí po načítaní jadra"
243
244 #. TRANSLATORS: program name
245 msgid "Firmware Update Daemon"
246 msgstr "Démon aktualizácie firmvéru"
247
248 #. TRANSLATORS: program summary
249 msgid "Firmware Update D-Bus Service"
250 msgstr "Služba zbernice D-Bus na aktualizovanie firmvéru"
89251
90252 #. TRANSLATORS: daemon is inactive
91253 msgid "Idle"
148310 msgid "Updating %s from %s to %s... "
149311 msgstr "Aktualizuje sa %s z verzie %s na verziu %s... "
150312
151 msgid "OK"
152 msgstr "OK"
153
154313 #. TRANSLATORS: first replacement is device name
155314 #, c-format
156315 msgid "%s has firmware updates:"
157316 msgstr "Pre zariadenie %s sú dostupné aktualizácie firmvéru:"
158317
318 #. TRANSLATORS: a GUID for the hardware
319 msgid "GUID"
320 msgstr ""
321
159322 #. TRANSLATORS: section header for firmware version
160323 msgid "Version"
161324 msgstr "Verzia"
240403 msgid "Firmware Utility"
241404 msgstr "Nástroj pre firmvéry"
242405
243 #. TRANSLATORS: the user didn't read the man page
244 msgid "Failed to parse arguments"
245 msgstr "Zlyhalo analyzovanie parametrov"
246
247406 #. TRANSLATORS: the user is in a bad place
248407 msgid "Failed to connect to D-Bus"
249408 msgstr "Zlyhalo pripojenie k zbernici D-Bus"
77 msgstr ""
88 "Project-Id-Version: fwupd\n"
99 "Report-Msgid-Bugs-To: \n"
10 "POT-Creation-Date: 2015-10-28 09:58+0000\n"
11 "PO-Revision-Date: 2015-10-15 21:00+0000\n"
12 "Last-Translator: Марко М. Костић (Marko M. Kostić) <marko.m.kostic@gmail.com>\n"
10 "POT-Creation-Date: 2015-12-07 12:22+0000\n"
11 "PO-Revision-Date: 2015-12-07 12:22+0000\n"
12 "Last-Translator: Richard Hughes <richard@hughsie.com>\n"
1313 "Language-Team: Serbian (http://www.transifex.com/hughsie/fwupd/language/sr/)\n"
1414 "MIME-Version: 1.0\n"
1515 "Content-Type: text/plain; charset=UTF-8\n"
5050 "Authentication is required to downgrade the firmware on a removable device"
5151 msgstr "Потребна је пријава за уназађивање фирмвера на преносивом уређају"
5252
53 #. TRANSLATORS: turn on all debugging
54 msgid "Show debugging information for all files"
55 msgstr "Прикажи податке о отклањању проблема за све датотеке"
56
57 #. TRANSLATORS: for the --verbose arg
58 msgid "Debugging Options"
59 msgstr "Опције отклањања проблема"
60
61 #. TRANSLATORS: for the --verbose arg
62 msgid "Show debugging options"
63 msgstr "Прикажи опције за отклањање проблема"
64
65 #. TRANSLATORS: exit after we've started up, used for user profiling
66 msgid "Exit after a small delay"
67 msgstr "Изађи након малог застоја"
68
69 #. TRANSLATORS: exit straight away, used for automatic profiling
70 msgid "Exit after the engine has loaded"
71 msgstr "Изађи након учитавања мотора"
72
73 #. TRANSLATORS: program name
74 msgid "Firmware Update Daemon"
75 msgstr "Демон за ажурирање фирмвера"
76
77 #. TRANSLATORS: program summary
78 msgid "Firmware Update D-Bus Service"
79 msgstr "Д-Бус услуга ажурирања фирмвера"
80
8153 #. TRANSLATORS: this is a command alias, e.g. 'get-devices'
8254 #, c-format
8355 msgid "Alias to %s"
8658 #. TRANSLATORS: error message
8759 msgid "Command not found"
8860 msgstr "Наредба није пронађена"
61
62 #. TRANSLATORS: when an action has completed
63 msgid "OK"
64 msgstr "У реду"
65
66 #. TRANSLATORS: when moving from runtime to DFU mode
67 msgid "Detaching"
68 msgstr ""
69
70 #. TRANSLATORS: when moving from DFU to runtime mode
71 msgid "Attaching"
72 msgstr ""
73
74 #. TRANSLATORS: when copying from host to device
75 msgid "Downloading"
76 msgstr ""
77
78 #. TRANSLATORS: when copying from device to host
79 msgid "Uploading"
80 msgstr ""
81
82 #. TRANSLATORS: this is when a device is hotplugged
83 msgid "Added"
84 msgstr ""
85
86 #. TRANSLATORS: this is when a device is hotplugged
87 msgid "Removed"
88 msgstr ""
89
90 #. TRANSLATORS: this is when a device is hotplugged
91 msgid "Changed"
92 msgstr ""
93
94 #. TRANSLATORS: this is when a device ctrl+c's a watch
95 msgid "Cancelled"
96 msgstr ""
97
98 #. TRANSLATORS: Appstream ID for the hardware type
99 msgid "ID"
100 msgstr ""
101
102 #. TRANSLATORS: interface name, e.g. "Flash"
103 msgid "Name"
104 msgstr ""
105
106 #. TRANSLATORS: this is the encryption method used when writing
107 msgid "Cipher"
108 msgstr ""
109
110 #. TRANSLATORS: these are areas of memory on the chip
111 msgid "Region"
112 msgstr ""
113
114 #. TRANSLATORS: detected a DFU device
115 msgid "Found"
116 msgstr ""
117
118 #. TRANSLATORS: probably not run as root...
119 #. TRANSLATORS: device has failed to report status
120 #. TRANSLATORS: device status, e.g. "OK"
121 msgid "Status"
122 msgstr ""
123
124 msgid "Unknown: permission denied"
125 msgstr ""
126
127 #. TRANSLATORS: device mode, e.g. runtime or DFU
128 msgid "Mode"
129 msgstr ""
130
131 #. TRANSLATORS: device state, i.e. appIDLE
132 msgid "State"
133 msgstr ""
134
135 #. TRANSLATORS: device quirks, i.e. things that
136 #. * it does that we have to work around
137 msgid "Quirks"
138 msgstr ""
139
140 #. TRANSLATORS: command description
141 msgid "Convert firmware to DFU format"
142 msgstr ""
143
144 #. TRANSLATORS: command description
145 msgid "Merge multiple firmware files into one"
146 msgstr ""
147
148 #. TRANSLATORS: command description
149 msgid "Set vendor ID on firmware file"
150 msgstr ""
151
152 #. TRANSLATORS: command description
153 msgid "Set product ID on firmware file"
154 msgstr ""
155
156 #. TRANSLATORS: command description
157 msgid "Set release version on firmware file"
158 msgstr ""
159
160 #. TRANSLATORS: command description
161 msgid "Set alternative number on firmware file"
162 msgstr ""
163
164 #. TRANSLATORS: command description
165 msgid "Set alternative name on firmware file"
166 msgstr ""
167
168 #. TRANSLATORS: command description
169 msgid "Attach DFU capable device back to runtime"
170 msgstr ""
171
172 #. TRANSLATORS: command description
173 msgid "Read firmware from device into a file"
174 msgstr ""
175
176 #. TRANSLATORS: command description
177 msgid "Read firmware from one partition into a file"
178 msgstr ""
179
180 #. TRANSLATORS: command description
181 msgid "Write firmware from file into device"
182 msgstr ""
183
184 #. TRANSLATORS: command description
185 msgid "Write firmware from file into one partition"
186 msgstr ""
187
188 #. TRANSLATORS: command description
189 msgid "List currently attached DFU capable devices"
190 msgstr ""
191
192 #. TRANSLATORS: command description
193 msgid "Detach currently attached DFU capable device"
194 msgstr ""
195
196 #. TRANSLATORS: command description
197 msgid "Dump details about a firmware file"
198 msgstr ""
199
200 #. TRANSLATORS: command description
201 msgid "Watch DFU devices being hotplugged"
202 msgstr ""
203
204 #. TRANSLATORS: command description
205 msgid "Encrypt firmware data"
206 msgstr ""
207
208 #. TRANSLATORS: command description
209 msgid "Decrypt firmware data"
210 msgstr ""
211
212 #. TRANSLATORS: command description
213 msgid "Sets metadata on a firmware file"
214 msgstr ""
215
216 #. TRANSLATORS: DFU stands for device firmware update
217 msgid "DFU Utility"
218 msgstr ""
219
220 #. TRANSLATORS: the user didn't read the man page
221 msgid "Failed to parse arguments"
222 msgstr "Не могу да обрадим аргументе"
223
224 #. TRANSLATORS: turn on all debugging
225 msgid "Show debugging information for all files"
226 msgstr "Прикажи податке о отклањању проблема за све датотеке"
227
228 #. TRANSLATORS: for the --verbose arg
229 msgid "Debugging Options"
230 msgstr "Опције отклањања проблема"
231
232 #. TRANSLATORS: for the --verbose arg
233 msgid "Show debugging options"
234 msgstr "Прикажи опције за отклањање проблема"
235
236 #. TRANSLATORS: exit after we've started up, used for user profiling
237 msgid "Exit after a small delay"
238 msgstr "Изађи након малог застоја"
239
240 #. TRANSLATORS: exit straight away, used for automatic profiling
241 msgid "Exit after the engine has loaded"
242 msgstr "Изађи након учитавања мотора"
243
244 #. TRANSLATORS: program name
245 msgid "Firmware Update Daemon"
246 msgstr "Демон за ажурирање фирмвера"
247
248 #. TRANSLATORS: program summary
249 msgid "Firmware Update D-Bus Service"
250 msgstr "Д-Бус услуга ажурирања фирмвера"
89251
90252 #. TRANSLATORS: daemon is inactive
91253 msgid "Idle"
148310 msgid "Updating %s from %s to %s... "
149311 msgstr "Ажурирам %s са %s на %s..."
150312
151 msgid "OK"
152 msgstr "У реду"
153
154313 #. TRANSLATORS: first replacement is device name
155314 #, c-format
156315 msgid "%s has firmware updates:"
157316 msgstr "%s има ажурирања за фирмвер:"
158317
318 #. TRANSLATORS: a GUID for the hardware
319 msgid "GUID"
320 msgstr ""
321
159322 #. TRANSLATORS: section header for firmware version
160323 msgid "Version"
161324 msgstr "Издање"
240403 msgid "Firmware Utility"
241404 msgstr "Алатка за фирмвер"
242405
243 #. TRANSLATORS: the user didn't read the man page
244 msgid "Failed to parse arguments"
245 msgstr "Не могу да обрадим аргументе"
246
247406 #. TRANSLATORS: the user is in a bad place
248407 msgid "Failed to connect to D-Bus"
249408 msgstr "Не могу да се повежем на Д-Бус"
77 msgstr ""
88 "Project-Id-Version: fwupd\n"
99 "Report-Msgid-Bugs-To: \n"
10 "POT-Creation-Date: 2015-09-10 09:28+0100\n"
11 "PO-Revision-Date: 2015-09-10 08:28+0000\n"
10 "POT-Creation-Date: 2015-12-07 12:22+0000\n"
11 "PO-Revision-Date: 2015-12-07 12:22+0000\n"
1212 "Last-Translator: Richard Hughes <richard@hughsie.com>\n"
1313 "Language-Team: Swedish (http://www.transifex.com/hughsie/fwupd/language/sv/)\n"
1414 "MIME-Version: 1.0\n"
5050 "Authentication is required to downgrade the firmware on a removable device"
5151 msgstr "Autentisering krävs för att nedgradera den fasta programvaran för en flyttbar enhet"
5252
53 #. TRANSLATORS: turn on all debugging
54 msgid "Show debugging information for all files"
55 msgstr "Visa felsökningsinformation för alla filer"
56
57 #. TRANSLATORS: for the --verbose arg
58 msgid "Debugging Options"
59 msgstr "Felsökningsalternativ"
60
61 #. TRANSLATORS: for the --verbose arg
62 msgid "Show debugging options"
63 msgstr "Visa felsökningsalternativ"
64
65 #. TRANSLATORS: exit after we've started up, used for user profiling
66 msgid "Exit after a small delay"
67 msgstr "Avsluta efter en kort fördröjning"
68
69 #. TRANSLATORS: exit straight away, used for automatic profiling
70 msgid "Exit after the engine has loaded"
71 msgstr "Avsluta efter att motorn har lästs in"
72
73 #. TRANSLATORS: program name
74 msgid "Firmware Update Daemon"
75 msgstr ""
76
77 #. TRANSLATORS: program summary
78 msgid "Firmware Update D-Bus Service"
79 msgstr "Firmware Update D-Bus-tjänst"
80
8153 #. TRANSLATORS: this is a command alias, e.g. 'get-devices'
8254 #, c-format
8355 msgid "Alias to %s"
8658 #. TRANSLATORS: error message
8759 msgid "Command not found"
8860 msgstr ""
61
62 #. TRANSLATORS: when an action has completed
63 msgid "OK"
64 msgstr ""
65
66 #. TRANSLATORS: when moving from runtime to DFU mode
67 msgid "Detaching"
68 msgstr ""
69
70 #. TRANSLATORS: when moving from DFU to runtime mode
71 msgid "Attaching"
72 msgstr ""
73
74 #. TRANSLATORS: when copying from host to device
75 msgid "Downloading"
76 msgstr ""
77
78 #. TRANSLATORS: when copying from device to host
79 msgid "Uploading"
80 msgstr ""
81
82 #. TRANSLATORS: this is when a device is hotplugged
83 msgid "Added"
84 msgstr ""
85
86 #. TRANSLATORS: this is when a device is hotplugged
87 msgid "Removed"
88 msgstr ""
89
90 #. TRANSLATORS: this is when a device is hotplugged
91 msgid "Changed"
92 msgstr ""
93
94 #. TRANSLATORS: this is when a device ctrl+c's a watch
95 msgid "Cancelled"
96 msgstr ""
97
98 #. TRANSLATORS: Appstream ID for the hardware type
99 msgid "ID"
100 msgstr ""
101
102 #. TRANSLATORS: interface name, e.g. "Flash"
103 msgid "Name"
104 msgstr ""
105
106 #. TRANSLATORS: this is the encryption method used when writing
107 msgid "Cipher"
108 msgstr ""
109
110 #. TRANSLATORS: these are areas of memory on the chip
111 msgid "Region"
112 msgstr ""
113
114 #. TRANSLATORS: detected a DFU device
115 msgid "Found"
116 msgstr ""
117
118 #. TRANSLATORS: probably not run as root...
119 #. TRANSLATORS: device has failed to report status
120 #. TRANSLATORS: device status, e.g. "OK"
121 msgid "Status"
122 msgstr ""
123
124 msgid "Unknown: permission denied"
125 msgstr ""
126
127 #. TRANSLATORS: device mode, e.g. runtime or DFU
128 msgid "Mode"
129 msgstr ""
130
131 #. TRANSLATORS: device state, i.e. appIDLE
132 msgid "State"
133 msgstr ""
134
135 #. TRANSLATORS: device quirks, i.e. things that
136 #. * it does that we have to work around
137 msgid "Quirks"
138 msgstr ""
139
140 #. TRANSLATORS: command description
141 msgid "Convert firmware to DFU format"
142 msgstr ""
143
144 #. TRANSLATORS: command description
145 msgid "Merge multiple firmware files into one"
146 msgstr ""
147
148 #. TRANSLATORS: command description
149 msgid "Set vendor ID on firmware file"
150 msgstr ""
151
152 #. TRANSLATORS: command description
153 msgid "Set product ID on firmware file"
154 msgstr ""
155
156 #. TRANSLATORS: command description
157 msgid "Set release version on firmware file"
158 msgstr ""
159
160 #. TRANSLATORS: command description
161 msgid "Set alternative number on firmware file"
162 msgstr ""
163
164 #. TRANSLATORS: command description
165 msgid "Set alternative name on firmware file"
166 msgstr ""
167
168 #. TRANSLATORS: command description
169 msgid "Attach DFU capable device back to runtime"
170 msgstr ""
171
172 #. TRANSLATORS: command description
173 msgid "Read firmware from device into a file"
174 msgstr ""
175
176 #. TRANSLATORS: command description
177 msgid "Read firmware from one partition into a file"
178 msgstr ""
179
180 #. TRANSLATORS: command description
181 msgid "Write firmware from file into device"
182 msgstr ""
183
184 #. TRANSLATORS: command description
185 msgid "Write firmware from file into one partition"
186 msgstr ""
187
188 #. TRANSLATORS: command description
189 msgid "List currently attached DFU capable devices"
190 msgstr ""
191
192 #. TRANSLATORS: command description
193 msgid "Detach currently attached DFU capable device"
194 msgstr ""
195
196 #. TRANSLATORS: command description
197 msgid "Dump details about a firmware file"
198 msgstr ""
199
200 #. TRANSLATORS: command description
201 msgid "Watch DFU devices being hotplugged"
202 msgstr ""
203
204 #. TRANSLATORS: command description
205 msgid "Encrypt firmware data"
206 msgstr ""
207
208 #. TRANSLATORS: command description
209 msgid "Decrypt firmware data"
210 msgstr ""
211
212 #. TRANSLATORS: command description
213 msgid "Sets metadata on a firmware file"
214 msgstr ""
215
216 #. TRANSLATORS: DFU stands for device firmware update
217 msgid "DFU Utility"
218 msgstr ""
219
220 #. TRANSLATORS: the user didn't read the man page
221 msgid "Failed to parse arguments"
222 msgstr "Misslyckades med att tolka argument"
223
224 #. TRANSLATORS: turn on all debugging
225 msgid "Show debugging information for all files"
226 msgstr "Visa felsökningsinformation för alla filer"
227
228 #. TRANSLATORS: for the --verbose arg
229 msgid "Debugging Options"
230 msgstr "Felsökningsalternativ"
231
232 #. TRANSLATORS: for the --verbose arg
233 msgid "Show debugging options"
234 msgstr "Visa felsökningsalternativ"
235
236 #. TRANSLATORS: exit after we've started up, used for user profiling
237 msgid "Exit after a small delay"
238 msgstr "Avsluta efter en kort fördröjning"
239
240 #. TRANSLATORS: exit straight away, used for automatic profiling
241 msgid "Exit after the engine has loaded"
242 msgstr "Avsluta efter att motorn har lästs in"
243
244 #. TRANSLATORS: program name
245 msgid "Firmware Update Daemon"
246 msgstr ""
247
248 #. TRANSLATORS: program summary
249 msgid "Firmware Update D-Bus Service"
250 msgstr "Firmware Update D-Bus-tjänst"
89251
90252 #. TRANSLATORS: daemon is inactive
91253 msgid "Idle"
148310 msgid "Updating %s from %s to %s... "
149311 msgstr "Uppdaterar %s från %s till %s..."
150312
151 msgid "OK"
152 msgstr ""
153
154313 #. TRANSLATORS: first replacement is device name
155314 #, c-format
156315 msgid "%s has firmware updates:"
157316 msgstr "%s har uppdateringar för fast programvara:"
158317
318 #. TRANSLATORS: a GUID for the hardware
319 msgid "GUID"
320 msgstr ""
321
159322 #. TRANSLATORS: section header for firmware version
160323 msgid "Version"
161324 msgstr "Version"
240403 msgid "Firmware Utility"
241404 msgstr ""
242405
243 #. TRANSLATORS: the user didn't read the man page
244 msgid "Failed to parse arguments"
245 msgstr "Misslyckades med att tolka argument"
246
247406 #. TRANSLATORS: the user is in a bad place
248407 msgid "Failed to connect to D-Bus"
249408 msgstr "Misslyckades med att ansluta till D-Bus"
77 msgstr ""
88 "Project-Id-Version: fwupd\n"
99 "Report-Msgid-Bugs-To: \n"
10 "POT-Creation-Date: 2015-09-10 09:28+0100\n"
11 "PO-Revision-Date: 2015-09-10 08:28+0000\n"
12 "Last-Translator: Richard Hughes <richard@hughsie.com>\n"
10 "POT-Creation-Date: 2015-12-07 12:22+0000\n"
11 "PO-Revision-Date: 2015-12-07 12:48+0000\n"
12 "Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
1313 "Language-Team: Ukrainian (http://www.transifex.com/hughsie/fwupd/language/uk/)\n"
1414 "MIME-Version: 1.0\n"
1515 "Content-Type: text/plain; charset=UTF-8\n"
5050 "Authentication is required to downgrade the firmware on a removable device"
5151 msgstr "Для встановлення застарілої версії мікропрограми на портативний пристрій слід пройти розпізнавання"
5252
53 #. TRANSLATORS: turn on all debugging
54 msgid "Show debugging information for all files"
55 msgstr "Показувати діагностичні дані для всіх файлів"
56
57 #. TRANSLATORS: for the --verbose arg
58 msgid "Debugging Options"
59 msgstr "Параметри діагностики"
60
61 #. TRANSLATORS: for the --verbose arg
62 msgid "Show debugging options"
63 msgstr "Показувати параметри діагностики"
64
65 #. TRANSLATORS: exit after we've started up, used for user profiling
66 msgid "Exit after a small delay"
67 msgstr "Завершити роботу з невеличкою затримкою"
68
69 #. TRANSLATORS: exit straight away, used for automatic profiling
70 msgid "Exit after the engine has loaded"
71 msgstr "Завершити роботу після завантаження рушія"
72
73 #. TRANSLATORS: program name
74 msgid "Firmware Update Daemon"
75 msgstr "Служба оновлення мікропрограми"
76
77 #. TRANSLATORS: program summary
78 msgid "Firmware Update D-Bus Service"
79 msgstr "Служба D-Bus оновлення мікропрограми"
80
8153 #. TRANSLATORS: this is a command alias, e.g. 'get-devices'
8254 #, c-format
8355 msgid "Alias to %s"
8658 #. TRANSLATORS: error message
8759 msgid "Command not found"
8860 msgstr "Такої команди не знайдено"
61
62 #. TRANSLATORS: when an action has completed
63 msgid "OK"
64 msgstr "Гаразд"
65
66 #. TRANSLATORS: when moving from runtime to DFU mode
67 msgid "Detaching"
68 msgstr "Від’єднуємо"
69
70 #. TRANSLATORS: when moving from DFU to runtime mode
71 msgid "Attaching"
72 msgstr "З’єднуємо"
73
74 #. TRANSLATORS: when copying from host to device
75 msgid "Downloading"
76 msgstr "Отримуємо"
77
78 #. TRANSLATORS: when copying from device to host
79 msgid "Uploading"
80 msgstr "Вивантажуємо"
81
82 #. TRANSLATORS: this is when a device is hotplugged
83 msgid "Added"
84 msgstr "Додано"
85
86 #. TRANSLATORS: this is when a device is hotplugged
87 msgid "Removed"
88 msgstr "Вилучено"
89
90 #. TRANSLATORS: this is when a device is hotplugged
91 msgid "Changed"
92 msgstr "Змінено"
93
94 #. TRANSLATORS: this is when a device ctrl+c's a watch
95 msgid "Cancelled"
96 msgstr "Скасовано"
97
98 #. TRANSLATORS: Appstream ID for the hardware type
99 msgid "ID"
100 msgstr "Ід."
101
102 #. TRANSLATORS: interface name, e.g. "Flash"
103 msgid "Name"
104 msgstr "Назва"
105
106 #. TRANSLATORS: this is the encryption method used when writing
107 msgid "Cipher"
108 msgstr "Шифр"
109
110 #. TRANSLATORS: these are areas of memory on the chip
111 msgid "Region"
112 msgstr "Регіон"
113
114 #. TRANSLATORS: detected a DFU device
115 msgid "Found"
116 msgstr "Знайдено"
117
118 #. TRANSLATORS: probably not run as root...
119 #. TRANSLATORS: device has failed to report status
120 #. TRANSLATORS: device status, e.g. "OK"
121 msgid "Status"
122 msgstr "Стан"
123
124 msgid "Unknown: permission denied"
125 msgstr "Невідомий: доступ заборонено"
126
127 #. TRANSLATORS: device mode, e.g. runtime or DFU
128 msgid "Mode"
129 msgstr "Режим"
130
131 #. TRANSLATORS: device state, i.e. appIDLE
132 msgid "State"
133 msgstr "Стан"
134
135 #. TRANSLATORS: device quirks, i.e. things that
136 #. * it does that we have to work around
137 msgid "Quirks"
138 msgstr "Негаразди"
139
140 #. TRANSLATORS: command description
141 msgid "Convert firmware to DFU format"
142 msgstr "Перетворити мікропрограму у формат DFU"
143
144 #. TRANSLATORS: command description
145 msgid "Merge multiple firmware files into one"
146 msgstr "Об’єднати декілька файлів мікропрограм у один"
147
148 #. TRANSLATORS: command description
149 msgid "Set vendor ID on firmware file"
150 msgstr "Встановити ідентифікатор виробника для файла мікропрограми"
151
152 #. TRANSLATORS: command description
153 msgid "Set product ID on firmware file"
154 msgstr "Встановити ідентифікатор продукту для файла мікропрограми"
155
156 #. TRANSLATORS: command description
157 msgid "Set release version on firmware file"
158 msgstr "Встановити версію випуску для файла мікропрограми"
159
160 #. TRANSLATORS: command description
161 msgid "Set alternative number on firmware file"
162 msgstr "Встановити альтернативний номер для файла мікропрограми"
163
164 #. TRANSLATORS: command description
165 msgid "Set alternative name on firmware file"
166 msgstr "Встановити альтернативну назву для файла мікропрограми"
167
168 #. TRANSLATORS: command description
169 msgid "Attach DFU capable device back to runtime"
170 msgstr "Повернути пристрій із можливостями DFU до використання"
171
172 #. TRANSLATORS: command description
173 msgid "Read firmware from device into a file"
174 msgstr "Прочитати мікропрограму з пристрою до файла"
175
176 #. TRANSLATORS: command description
177 msgid "Read firmware from one partition into a file"
178 msgstr "Прочитати мікропрограму з одного розділу до файла"
179
180 #. TRANSLATORS: command description
181 msgid "Write firmware from file into device"
182 msgstr "Записати мікропрограму з файла на пристрій"
183
184 #. TRANSLATORS: command description
185 msgid "Write firmware from file into one partition"
186 msgstr "Записати мікропрограму з файла на один розділ"
187
188 #. TRANSLATORS: command description
189 msgid "List currently attached DFU capable devices"
190 msgstr "Вивести поточний список долучених пристроїв із можливостями DFU"
191
192 #. TRANSLATORS: command description
193 msgid "Detach currently attached DFU capable device"
194 msgstr "Від’єднати поточний з’єднаний пристрій із можливостями DFU"
195
196 #. TRANSLATORS: command description
197 msgid "Dump details about a firmware file"
198 msgstr "Створити дамп даних щодо файла мікропрограми"
199
200 #. TRANSLATORS: command description
201 msgid "Watch DFU devices being hotplugged"
202 msgstr "Спостерігати за пристроями DFU, які з’єднують із комп’ютером"
203
204 #. TRANSLATORS: command description
205 msgid "Encrypt firmware data"
206 msgstr "Зашифрувати дані мікропрограми"
207
208 #. TRANSLATORS: command description
209 msgid "Decrypt firmware data"
210 msgstr "Розшифрувати дані мікропрограми"
211
212 #. TRANSLATORS: command description
213 msgid "Sets metadata on a firmware file"
214 msgstr "Встановлює метадані щодо файла мікпропрограми"
215
216 #. TRANSLATORS: DFU stands for device firmware update
217 msgid "DFU Utility"
218 msgstr "Засіб роботи з DFU"
219
220 #. TRANSLATORS: the user didn't read the man page
221 msgid "Failed to parse arguments"
222 msgstr "Не вдалося обробити аргументи"
223
224 #. TRANSLATORS: turn on all debugging
225 msgid "Show debugging information for all files"
226 msgstr "Показувати діагностичні дані для всіх файлів"
227
228 #. TRANSLATORS: for the --verbose arg
229 msgid "Debugging Options"
230 msgstr "Параметри діагностики"
231
232 #. TRANSLATORS: for the --verbose arg
233 msgid "Show debugging options"
234 msgstr "Показувати параметри діагностики"
235
236 #. TRANSLATORS: exit after we've started up, used for user profiling
237 msgid "Exit after a small delay"
238 msgstr "Завершити роботу з невеличкою затримкою"
239
240 #. TRANSLATORS: exit straight away, used for automatic profiling
241 msgid "Exit after the engine has loaded"
242 msgstr "Завершити роботу після завантаження рушія"
243
244 #. TRANSLATORS: program name
245 msgid "Firmware Update Daemon"
246 msgstr "Служба оновлення мікропрограми"
247
248 #. TRANSLATORS: program summary
249 msgid "Firmware Update D-Bus Service"
250 msgstr "Служба D-Bus оновлення мікропрограми"
89251
90252 #. TRANSLATORS: daemon is inactive
91253 msgid "Idle"
148310 msgid "Updating %s from %s to %s... "
149311 msgstr "Оновлюємо %s з %s до %s... "
150312
151 msgid "OK"
152 msgstr "Гаразд"
153
154313 #. TRANSLATORS: first replacement is device name
155314 #, c-format
156315 msgid "%s has firmware updates:"
157316 msgstr "%s має такі оновлення мікропрограми:"
158317
318 #. TRANSLATORS: a GUID for the hardware
319 msgid "GUID"
320 msgstr "GUID"
321
159322 #. TRANSLATORS: section header for firmware version
160323 msgid "Version"
161324 msgstr "Версія"
240403 msgid "Firmware Utility"
241404 msgstr "Засіб роботи з мікропрограмами"
242405
243 #. TRANSLATORS: the user didn't read the man page
244 msgid "Failed to parse arguments"
245 msgstr "Не вдалося обробити аргументи"
246
247406 #. TRANSLATORS: the user is in a bad place
248407 msgid "Failed to connect to D-Bus"
249408 msgstr "Не вдалося з’єднатися з D-Bus"
3232 FWUPD_LIBS = \
3333 $(top_builddir)/libfwupd/libfwupd.la
3434
35 DFU_LIBS = \
36 $(top_builddir)/libdfu/libdfu.la
37
3538 bin_PROGRAMS = fwupdmgr
3639
3740 fwupdmgr_SOURCES = \
4447 fu-util.c
4548
4649 fwupdmgr_LDADD = \
50 $(LIBM) \
4751 $(FWUPD_LIBS) \
4852 $(APPSTREAM_GLIB_LIBS) \
4953 $(SQLITE_LIBS) \
9195 fu-pending.h \
9296 fu-provider.c \
9397 fu-provider.h \
98 fu-provider-dfu.c \
99 fu-provider-dfu.h \
94100 fu-provider-rpi.c \
95101 fu-provider-rpi.h \
96102 fu-provider-udev.c \
117123
118124 fwupd_LDADD = \
119125 $(FWUPD_LIBS) \
126 $(DFU_LIBS) \
120127 $(APPSTREAM_GLIB_LIBS) \
121128 $(COLORHUG_LIBS) \
122129 $(GUSB_LIBS) \
164171 fu-self-test.c
165172
166173 fu_self_test_LDADD = \
174 $(LIBM) \
167175 $(FWUPD_LIBS) \
168176 $(APPSTREAM_GLIB_LIBS) \
169177 $(SQLITE_LIBS) \
5656 #define FU_DEVICE_KEY_UPDATE_HASH "UpdateHash" /* s */
5757 #define FU_DEVICE_KEY_UPDATE_URI "UpdateUri" /* s */
5858 #define FU_DEVICE_KEY_UPDATE_DESCRIPTION "UpdateDescription" /* s */
59 #define FU_DEVICE_KEY_APPSTREAM_ID "AppstreamId" /* s */
5960
6061 FuDevice *fu_device_new (void);
6162
3737 #include "fu-keyring.h"
3838 #include "fu-pending.h"
3939 #include "fu-provider.h"
40 #include "fu-provider-dfu.h"
4041 #include "fu-provider-rpi.h"
4142 #include "fu-provider-udev.h"
4243 #include "fu-provider-usb.h"
341342 }
342343
343344 /* run the correct provider that added this */
344 return fu_provider_update (item->provider,
345 item->device,
346 helper->blob_cab,
347 helper->blob_fw,
348 helper->flags,
349 error);
345 if (!fu_provider_update (item->provider,
346 item->device,
347 helper->blob_cab,
348 helper->blob_fw,
349 helper->flags,
350 error))
351 return FALSE;
352
353 /* make the UI update */
354 fu_main_emit_changed (helper->priv);
355 return TRUE;
350356 }
351357
352358 /**
874880 }
875881
876882 /* add application metadata */
883 fu_device_set_metadata (item->device,
884 FU_DEVICE_KEY_APPSTREAM_ID,
885 as_app_get_id (app));
877886 tmp = as_app_get_developer_name (app, NULL);
878887 if (tmp != NULL) {
879888 fu_device_set_metadata (item->device,
16341643
16351644 /* remove any fake device */
16361645 item = fu_main_get_item_by_id (priv, fu_device_get_id (device));
1637 if (item != NULL)
1638 g_ptr_array_remove (priv->devices, item);
1646 if (item != NULL) {
1647 g_debug ("already added %s by %s, ignoring same device from %s",
1648 fu_device_get_id (item->device),
1649 fu_device_get_metadata (item->device, FU_DEVICE_KEY_PROVIDER),
1650 fu_provider_get_name (provider));
1651 return;
1652 }
16391653
16401654 /* create new device */
16411655 item = g_new0 (FuDeviceItem, 1);
16581672
16591673 item = fu_main_get_item_by_id (priv, fu_device_get_id (device));
16601674 if (item == NULL) {
1661 g_warning ("can't remove device %s", fu_device_get_id (device));
1675 g_debug ("no device to remove %s", fu_device_get_id (device));
16621676 return;
16631677 }
1678
1679 /* check this came from the same provider */
1680 if (g_strcmp0 (fu_provider_get_name (provider),
1681 fu_provider_get_name (item->provider)) != 0) {
1682 g_debug ("ignoring duplicate removal from %s",
1683 fu_provider_get_name (provider));
1684 return;
1685 }
1686
16641687 g_ptr_array_remove (priv->devices, item);
16651688 fu_main_emit_changed (priv);
16661689 }
17801803 priv->providers = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
17811804 if (g_key_file_get_boolean (config, "fwupd", "EnableOptionROM", NULL))
17821805 fu_main_add_provider (priv, fu_provider_udev_new ());
1783 fu_main_add_provider (priv, fu_provider_usb_new ());
1806 fu_main_add_provider (priv, fu_provider_dfu_new ());
17841807 fu_main_add_provider (priv, fu_provider_rpi_new ());
17851808 #ifdef HAVE_COLORHUG
17861809 fu_main_add_provider (priv, fu_provider_chug_new ());
17881811 #ifdef HAVE_UEFI
17891812 fu_main_add_provider (priv, fu_provider_uefi_new ());
17901813 #endif
1814
1815 /* last as least priority */
1816 fu_main_add_provider (priv, fu_provider_usb_new ());
17911817
17921818 /* load introspection from file */
17931819 priv->introspection_daemon = fu_main_load_introspection (FWUPD_DBUS_INTERFACE ".xml",
142142 }
143143
144144 /**
145 * fu_provider_chug_get_id:
146 **/
147 static gchar *
148 fu_provider_chug_get_id (GUsbDevice *device)
149 {
150 /* this identifies the *port* the device is plugged into and
151 * the kind of device */
152 return g_strdup_printf ("CHug-%s-%s",
153 g_usb_device_get_platform_id (device),
154 ch_device_get_guid (device));
155 }
156
157 /**
158145 * fu_provider_chug_get_firmware_version:
159146 **/
160147 static void
164151 guint16 major;
165152 guint16 micro;
166153 guint16 minor;
167 #if G_USB_CHECK_VERSION(0,2,5)
168154 guint8 idx;
169 #endif
170155 g_autoptr(GError) error = NULL;
171156 g_autofree gchar *version = NULL;
172157
173158 /* try to get the version without claiming interface */
174 #if G_USB_CHECK_VERSION(0,2,5)
175159 if (!g_usb_device_open (item->usb_device, &error)) {
176160 g_debug ("Failed to open, polling: %s", error->message);
177161 return;
193177 }
194178 }
195179 g_usb_device_close (item->usb_device, NULL);
196 #endif
197180
198181 /* attempt to open the device and get the serial number */
199182 item->persist_after_unplug = TRUE;
251234 return FALSE;
252235 }
253236
254 #if !CD_CHECK_VERSION(1,2,12)
255 /* recompile colord */
256 g_set_error_literal (error,
257 FWUPD_ERROR,
258 FWUPD_ERROR_NOT_SUPPORTED,
259 "Cannot read firmware: colord too old");
260 return FALSE;
261 #endif
262
263237 /* open */
264238 if (!fu_provider_chug_open (item, error))
265239 return FALSE;
266240
267241 /* get the firmware from the device */
268242 g_debug ("ColorHug: Verifying firmware");
269 #if CD_CHECK_VERSION(1,2,12)
270243 ch_device_queue_read_firmware (priv->device_queue, item->usb_device,
271244 &data, &len);
272 #endif
273245 fu_provider_set_status (provider, FWUPD_STATUS_DEVICE_VERIFY);
274246 if (!ch_device_queue_process (priv->device_queue,
275247 CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE,
488460 return TRUE;
489461 }
490462
491 #if !CD_CHECK_VERSION(1,2,10)
492 #define CH_DEVICE_GUID_COLORHUG "40338ceb-b966-4eae-adae-9c32edfcc484"
493 #define CH_DEVICE_GUID_COLORHUG2 "2082b5e0-7a64-478a-b1b2-e3404fab6dad"
494 #define CH_DEVICE_GUID_COLORHUG_ALS "84f40464-9272-4ef7-9399-cd95f12da696"
495 #define CH_DEVICE_GUID_COLORHUG_PLUS "6d6f05a9-3ecb-43a2-bcbb-3844f1825366"
496
497 static const gchar *
498 ch_device_get_guid (GUsbDevice *device)
499 {
500 ChDeviceMode mode = ch_device_get_mode (device);
501 if (mode == CH_DEVICE_MODE_LEGACY ||
502 mode == CH_DEVICE_MODE_FIRMWARE ||
503 mode == CH_DEVICE_MODE_BOOTLOADER)
504 return CH_DEVICE_GUID_COLORHUG;
505 if (mode == CH_DEVICE_MODE_FIRMWARE2 ||
506 mode == CH_DEVICE_MODE_BOOTLOADER2)
507 return CH_DEVICE_GUID_COLORHUG2;
508 if (mode == CH_DEVICE_MODE_FIRMWARE_PLUS ||
509 mode == CH_DEVICE_MODE_BOOTLOADER_PLUS)
510 return CH_DEVICE_GUID_COLORHUG_PLUS;
511 if (mode == CH_DEVICE_MODE_FIRMWARE_ALS ||
512 mode == CH_DEVICE_MODE_BOOTLOADER_ALS)
513 return CH_DEVICE_GUID_COLORHUG_ALS;
514 return NULL;
515 }
516 #endif
517
518463 /**
519464 * fu_provider_chug_device_added_cb:
520465 **/
526471 FuProviderChugPrivate *priv = GET_PRIVATE (provider_chug);
527472 FuProviderChugItem *item;
528473 ChDeviceMode mode;
529 g_autofree gchar *id = NULL;
474 const gchar *platform_id = NULL;
530475
531476 /* ignore */
532477 mode = ch_device_get_mode (device);
533478 if (mode == CH_DEVICE_MODE_UNKNOWN)
534479 return;
535480
481 /* this is using DFU now */
482 if (mode == CH_DEVICE_MODE_BOOTLOADER_PLUS ||
483 mode == CH_DEVICE_MODE_FIRMWARE_PLUS)
484 return;
485
536486 /* is already in database */
537 id = fu_provider_chug_get_id (device);
538 item = g_hash_table_lookup (priv->devices, id);
487 platform_id = g_usb_device_get_platform_id (device);
488 item = g_hash_table_lookup (priv->devices, platform_id);
539489 if (item == NULL) {
540490 item = g_new0 (FuProviderChugItem, 1);
541491 item->loop = g_main_loop_new (NULL, FALSE);
542492 item->provider_chug = g_object_ref (provider_chug);
543493 item->usb_device = g_object_ref (device);
544494 item->device = fu_device_new ();
545 fu_device_set_id (item->device, id);
495 fu_device_set_id (item->device, platform_id);
546496 fu_device_set_guid (item->device, ch_device_get_guid (device));
547497 fu_device_add_flag (item->device, FU_DEVICE_FLAG_ALLOW_OFFLINE);
548498 fu_device_add_flag (item->device, FU_DEVICE_FLAG_ALLOW_ONLINE);
557507
558508 /* insert to hash */
559509 g_hash_table_insert (priv->devices,
560 g_strdup (id), item);
510 g_strdup (platform_id), item);
561511 } else {
562512 /* update the device */
563513 g_object_unref (item->usb_device);
617567 {
618568 FuProviderChugPrivate *priv = GET_PRIVATE (provider_chug);
619569 FuProviderChugItem *item;
620 g_autofree gchar *id = NULL;
570 const gchar *platform_id = NULL;
621571
622572 /* already in database */
623 id = fu_provider_chug_get_id (device);
624 item = g_hash_table_lookup (priv->devices, id);
573 platform_id = g_usb_device_get_platform_id (device);
574 item = g_hash_table_lookup (priv->devices, platform_id);
625575 if (item == NULL)
626576 return;
627577
636586 * rescan each time so we don't get confused when different
637587 * kinds of ColorHug device are plugged in... */
638588 if (!item->persist_after_unplug)
639 g_hash_table_remove (priv->devices, id);
589 g_hash_table_remove (priv->devices, platform_id);
640590 }
641591
642592 /**
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU General Public License Version 2
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "config.h"
22
23 #include <appstream-glib.h>
24 #include <fwupd.h>
25 #include <glib-object.h>
26 #include <libdfu/dfu.h>
27
28 #include "fu-device.h"
29 #include "fu-provider-dfu.h"
30
31 static void fu_provider_dfu_finalize (GObject *object);
32
33 /**
34 * FuProviderDfuPrivate:
35 **/
36 typedef struct {
37 DfuContext *context;
38 GHashTable *devices; /* platform_id:DfuDevice */
39 } FuProviderDfuPrivate;
40
41 G_DEFINE_TYPE_WITH_PRIVATE (FuProviderDfu, fu_provider_dfu, FU_TYPE_PROVIDER)
42 #define GET_PRIVATE(o) (fu_provider_dfu_get_instance_private (o))
43
44 /**
45 * fu_provider_dfu_get_name:
46 **/
47 static const gchar *
48 fu_provider_dfu_get_name (FuProvider *provider)
49 {
50 return "DFU";
51 }
52
53 /**
54 * fu_provider_dfu_device_update:
55 **/
56 static void
57 fu_provider_dfu_device_update (FuProviderDfu *provider_dfu,
58 FuDevice *dev,
59 DfuDevice *device)
60 {
61 const gchar *platform_id;
62 guint16 release;
63 g_autofree gchar *guid = NULL;
64 g_autofree gchar *version = NULL;
65 g_autofree gchar *vid_pid = NULL;
66
67 /* check mode */
68 platform_id = dfu_device_get_platform_id (device);
69 if (dfu_device_get_runtime_vid (device) == 0xffff) {
70 g_debug ("Ignoring DFU device not in runtime: %s", platform_id);
71 return;
72 }
73
74 /* check capabilities */
75 if (dfu_device_can_download (device)) {
76 fu_device_add_flag (dev, FU_DEVICE_FLAG_ALLOW_ONLINE);
77 fu_device_add_flag (dev, FU_DEVICE_FLAG_ALLOW_OFFLINE);
78 }
79
80 /* get version number, falling back to the DFU device release */
81 release = dfu_device_get_runtime_release (device);
82 if (release != 0xffff) {
83 version = as_utils_version_from_uint16 (release,
84 AS_VERSION_PARSE_FLAG_NONE);
85 fu_device_set_metadata (dev, FU_DEVICE_KEY_VERSION, version);
86 }
87
88 vid_pid = g_strdup_printf ("USB\\VID_%04X&PID_%04X",
89 dfu_device_get_runtime_vid (device),
90 dfu_device_get_runtime_pid (device));
91 guid = as_utils_guid_from_string (vid_pid);
92 g_debug ("using %s for %s", guid, vid_pid);
93 fu_device_set_guid (dev, guid);
94 }
95
96 /**
97 * fu_provider_dfu_device_changed_cb:
98 **/
99 static void
100 fu_provider_dfu_device_changed_cb (DfuContext *ctx,
101 DfuDevice *device,
102 FuProviderDfu *provider_dfu)
103 {
104 FuProviderDfuPrivate *priv = GET_PRIVATE (provider_dfu);
105 FuDevice *dev;
106 const gchar *platform_id;
107
108 /* convert DfuDevice to FuDevice */
109 platform_id = dfu_device_get_platform_id (device);
110 dev = g_hash_table_lookup (priv->devices, platform_id);
111 if (dev == NULL) {
112 g_warning ("cannot find device %s", platform_id);
113 return;
114 }
115 fu_provider_dfu_device_update (provider_dfu, dev, device);
116 }
117
118 /**
119 * fu_provider_dfu_device_added_cb:
120 **/
121 static void
122 fu_provider_dfu_device_added_cb (DfuContext *ctx,
123 DfuDevice *device,
124 FuProviderDfu *provider_dfu)
125 {
126 FuProviderDfuPrivate *priv = GET_PRIVATE (provider_dfu);
127 const gchar *platform_id;
128 const gchar *display_name;
129 g_autofree gchar *id = NULL;
130 g_autoptr(AsProfile) profile = as_profile_new ();
131 g_autoptr(AsProfileTask) ptask = NULL;
132 g_autoptr(FuDevice) dev = NULL;
133 g_autoptr(GError) error = NULL;
134
135 platform_id = dfu_device_get_platform_id (device);
136 ptask = as_profile_start (profile, "FuProviderDfu:added{%s} [%04x:%04x]",
137 platform_id,
138 dfu_device_get_runtime_vid (device),
139 dfu_device_get_runtime_pid (device));
140
141 /* create new device */
142 dev = fu_device_new ();
143 fu_device_set_id (dev, platform_id);
144 fu_provider_dfu_device_update (provider_dfu, dev, device);
145
146 /* open device to get display name */
147 if (!dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE, NULL, &error)) {
148 g_warning ("Failed to open DFU device: %s", error->message);
149 return;
150 }
151 display_name = dfu_device_get_display_name (device);
152 if (display_name != NULL)
153 fu_device_set_display_name (dev, display_name);
154
155 /* we're done here */
156 if (!dfu_device_close (device, &error))
157 g_debug ("Failed to close %s: %s", platform_id, error->message);
158
159 /* attempt to add */
160 fu_provider_device_add (FU_PROVIDER (provider_dfu), dev);
161 g_hash_table_insert (priv->devices,
162 g_strdup (platform_id),
163 g_object_ref (dev));
164 }
165
166 /**
167 * fu_provider_dfu_device_removed_cb:
168 **/
169 static void
170 fu_provider_dfu_device_removed_cb (DfuContext *ctx,
171 DfuDevice *device,
172 FuProviderDfu *provider_dfu)
173 {
174 FuProviderDfuPrivate *priv = GET_PRIVATE (provider_dfu);
175 FuDevice *dev;
176 const gchar *platform_id;
177
178 /* convert DfuDevice to FuDevice */
179 platform_id = dfu_device_get_platform_id (device);
180 dev = g_hash_table_lookup (priv->devices, platform_id);
181 if (dev == NULL) {
182 g_warning ("cannot find device %s", platform_id);
183 return;
184 }
185
186 fu_provider_device_remove (FU_PROVIDER (provider_dfu), dev);
187 }
188
189 /**
190 * fu_provider_dfu_coldplug:
191 **/
192 static gboolean
193 fu_provider_dfu_coldplug (FuProvider *provider, GError **error)
194 {
195 FuProviderDfu *provider_dfu = FU_PROVIDER_DFU (provider);
196 FuProviderDfuPrivate *priv = GET_PRIVATE (provider_dfu);
197 dfu_context_enumerate (priv->context, NULL);
198 return TRUE;
199 }
200
201 /**
202 * fu_provider_dfu_state_changed_cb:
203 **/
204 static void
205 fu_provider_dfu_state_changed_cb (DfuDevice *device,
206 DfuState state,
207 FuProvider *provider)
208 {
209 switch (state) {
210 case DFU_STATE_DFU_UPLOAD_IDLE:
211 fu_provider_set_status (provider, FWUPD_STATUS_DEVICE_VERIFY);
212 break;
213 case DFU_STATE_DFU_DNLOAD_IDLE:
214 fu_provider_set_status (provider, FWUPD_STATUS_DEVICE_WRITE);
215 break;
216 default:
217 break;
218 }
219 }
220
221 /**
222 * fu_provider_dfu_update:
223 *
224 * This updates using DFU.
225 **/
226 static gboolean
227 fu_provider_dfu_update (FuProvider *provider,
228 FuDevice *dev,
229 GBytes *blob_fw,
230 FuProviderFlags flags,
231 GError **error)
232 {
233 FuProviderDfu *provider_dfu = FU_PROVIDER_DFU (provider);
234 FuProviderDfuPrivate *priv = GET_PRIVATE (provider_dfu);
235 DfuDevice *device;
236 const gchar *platform_id;
237 g_autoptr(DfuDevice) dfu_device = NULL;
238 g_autoptr(DfuFirmware) dfu_firmware = NULL;
239 g_autoptr(GError) error_local = NULL;
240
241 /* get device */
242 platform_id = fu_device_get_id (dev);
243 device = dfu_context_get_device_by_platform_id (priv->context,
244 platform_id,
245 &error_local);
246 if (device == NULL) {
247 g_set_error (error,
248 FWUPD_ERROR,
249 FWUPD_ERROR_INTERNAL,
250 "cannot find device %s: %s",
251 platform_id, error_local->message);
252 return FALSE;
253 }
254
255 /* open it */
256 if (!dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE,
257 NULL, &error_local)) {
258 g_set_error (error,
259 FWUPD_ERROR,
260 FWUPD_ERROR_INTERNAL,
261 "failed to open DFU device %s: %s",
262 platform_id, error_local->message);
263 return FALSE;
264 }
265 g_signal_connect (device, "state-changed",
266 G_CALLBACK (fu_provider_dfu_state_changed_cb), provider);
267
268 /* hit hardware */
269 dfu_firmware = dfu_firmware_new ();
270 if (!dfu_firmware_parse_data (dfu_firmware, blob_fw,
271 DFU_FIRMWARE_PARSE_FLAG_NONE, error))
272 return FALSE;
273 if (!dfu_device_download (device, dfu_firmware,
274 DFU_TARGET_TRANSFER_FLAG_DETACH |
275 DFU_TARGET_TRANSFER_FLAG_VERIFY |
276 DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME,
277 NULL,
278 error))
279 return FALSE;
280
281 /* we're done */
282 if (!dfu_device_close (device, &error_local)) {
283 g_set_error_literal (error,
284 FWUPD_ERROR,
285 FWUPD_ERROR_INTERNAL,
286 error_local->message);
287 return FALSE;
288 }
289 fu_provider_set_status (provider, FWUPD_STATUS_IDLE);
290 return TRUE;
291 }
292
293 /**
294 * fu_provider_dfu_verify:
295 **/
296 static gboolean
297 fu_provider_dfu_verify (FuProvider *provider,
298 FuDevice *dev,
299 FuProviderVerifyFlags flags,
300 GError **error)
301 {
302 FuProviderDfu *provider_dfu = FU_PROVIDER_DFU (provider);
303 FuProviderDfuPrivate *priv = GET_PRIVATE (provider_dfu);
304 GBytes *blob_fw;
305 DfuDevice *device;
306 const gchar *platform_id;
307 g_autofree gchar *hash = NULL;
308 g_autoptr(DfuDevice) dfu_device = NULL;
309 g_autoptr(DfuFirmware) dfu_firmware = NULL;
310 g_autoptr(GError) error_local = NULL;
311
312 /* get device */
313 platform_id = fu_device_get_id (dev);
314 device = dfu_context_get_device_by_platform_id (priv->context,
315 platform_id,
316 &error_local);
317 if (device == NULL) {
318 g_set_error (error,
319 FWUPD_ERROR,
320 FWUPD_ERROR_INTERNAL,
321 "cannot find device %s: %s",
322 platform_id, error_local->message);
323 return FALSE;
324 }
325
326 /* open it */
327 if (!dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE,
328 NULL, &error_local)) {
329 g_set_error (error,
330 FWUPD_ERROR,
331 FWUPD_ERROR_INTERNAL,
332 "failed to open DFU device %s: %s",
333 platform_id, error_local->message);
334 return FALSE;
335 }
336 g_signal_connect (device, "state-changed",
337 G_CALLBACK (fu_provider_dfu_state_changed_cb), provider);
338
339 /* get data from hardware */
340 g_debug ("uploading from device->host");
341 dfu_firmware = dfu_device_upload (device,
342 DFU_TARGET_TRANSFER_FLAG_DETACH |
343 DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME,
344 NULL,
345 error);
346 if (dfu_firmware == NULL)
347 return FALSE;
348
349 /* we're done */
350 if (!dfu_device_close (device, &error_local)) {
351 g_set_error_literal (error,
352 FWUPD_ERROR,
353 FWUPD_ERROR_INTERNAL,
354 error_local->message);
355 return FALSE;
356 }
357
358 /* get the SHA1 hash */
359 blob_fw = dfu_firmware_write_data (dfu_firmware, error);
360 if (blob_fw == NULL)
361 return FALSE;
362 hash = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, blob_fw);
363 fu_device_set_metadata (dev, FU_DEVICE_KEY_FIRMWARE_HASH, hash);
364 fu_provider_set_status (provider, FWUPD_STATUS_IDLE);
365 return TRUE;
366 }
367
368 /**
369 * fu_provider_dfu_class_init:
370 **/
371 static void
372 fu_provider_dfu_class_init (FuProviderDfuClass *klass)
373 {
374 FuProviderClass *provider_class = FU_PROVIDER_CLASS (klass);
375 GObjectClass *object_class = G_OBJECT_CLASS (klass);
376
377 provider_class->get_name = fu_provider_dfu_get_name;
378 provider_class->coldplug = fu_provider_dfu_coldplug;
379 provider_class->update_online = fu_provider_dfu_update;
380 provider_class->verify = fu_provider_dfu_verify;
381 object_class->finalize = fu_provider_dfu_finalize;
382 }
383
384 /**
385 * fu_provider_dfu_init:
386 **/
387 static void
388 fu_provider_dfu_init (FuProviderDfu *provider_dfu)
389 {
390 FuProviderDfuPrivate *priv = GET_PRIVATE (provider_dfu);
391 priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal,
392 g_free, (GDestroyNotify) g_object_unref);
393 priv->context = dfu_context_new ();
394 g_signal_connect (priv->context, "device-added",
395 G_CALLBACK (fu_provider_dfu_device_added_cb),
396 provider_dfu);
397 g_signal_connect (priv->context, "device-removed",
398 G_CALLBACK (fu_provider_dfu_device_removed_cb),
399 provider_dfu);
400 g_signal_connect (priv->context, "device-changed",
401 G_CALLBACK (fu_provider_dfu_device_changed_cb),
402 provider_dfu);
403 }
404
405 /**
406 * fu_provider_dfu_finalize:
407 **/
408 static void
409 fu_provider_dfu_finalize (GObject *object)
410 {
411 FuProviderDfu *provider_dfu = FU_PROVIDER_DFU (object);
412 FuProviderDfuPrivate *priv = GET_PRIVATE (provider_dfu);
413
414 g_hash_table_unref (priv->devices);
415 g_object_unref (priv->context);
416
417 G_OBJECT_CLASS (fu_provider_dfu_parent_class)->finalize (object);
418 }
419
420 /**
421 * fu_provider_dfu_new:
422 **/
423 FuProvider *
424 fu_provider_dfu_new (void)
425 {
426 FuProviderDfu *provider;
427 provider = g_object_new (FU_TYPE_PROVIDER_DFU, NULL);
428 return FU_PROVIDER (provider);
429 }
0 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
1 *
2 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
3 *
4 * Licensed under the GNU General Public License Version 2
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #ifndef __FU_PROVIDER_DFU_H
22 #define __FU_PROVIDER_DFU_H
23
24 #include <glib-object.h>
25
26 #include "fu-device.h"
27 #include "fu-provider.h"
28
29 G_BEGIN_DECLS
30
31 #define FU_TYPE_PROVIDER_DFU (fu_provider_dfu_get_type ())
32 G_DECLARE_DERIVABLE_TYPE (FuProviderDfu, fu_provider_dfu, FU, PROVIDER_DFU, FuProvider)
33
34 struct _FuProviderDfuClass
35 {
36 FuProviderClass parent_class;
37 };
38
39 FuProvider *fu_provider_dfu_new (void);
40
41 G_END_DECLS
42
43 #endif /* __FU_PROVIDER_DFU_H */
292292 continue;
293293 }
294294 fwup_get_fw_version(re, &version_raw);
295 #if AS_CHECK_VERSION(0,5,2)
296295 version = as_utils_version_from_uint32 (version_raw,
297296 AS_VERSION_PARSE_FLAG_USE_TRIPLET);
298 #else
299 version = g_strdup_printf ("%" G_GUINT32_FORMAT, version_raw);
300 #endif
301297 id = g_strdup_printf ("UEFI-%s-dev%" G_GUINT64_FORMAT,
302298 guid, hardware_instance);
303299
307303 fu_device_set_metadata (dev, FU_DEVICE_KEY_VERSION, version);
308304 fwup_get_lowest_supported_fw_version (re, &version_raw);
309305 if (version_raw != 0) {
310 #if AS_CHECK_VERSION(0,5,2)
311306 version_lowest = as_utils_version_from_uint32 (version_raw,
312307 AS_VERSION_PARSE_FLAG_USE_TRIPLET);
313 #else
314 version_lowest = g_strdup_printf ("%" G_GUINT32_FORMAT,
315 version_raw);
316 #endif
317308 fu_device_set_metadata (dev, FU_DEVICE_KEY_VERSION_LOWEST,
318309 version_lowest);
319310 }
3636 typedef struct {
3737 GHashTable *devices;
3838 GUsbContext *usb_ctx;
39 gboolean done_enumerate;
3940 } FuProviderUsbPrivate;
4041
4142 G_DEFINE_TYPE_WITH_PRIVATE (FuProviderUsb, fu_provider_usb, FU_TYPE_PROVIDER)
5152 }
5253
5354 /**
54 * fu_provider_usb_get_id:
55 **/
56 static gchar *
57 fu_provider_usb_get_id (GUsbDevice *device)
58 {
59 /* this identifies the *port* the device is plugged into */
60 return g_strdup_printf ("ro-%s", g_usb_device_get_platform_id (device));
61 }
62
63 /**
64 * fu_provider_usb_device_add:
65 *
66 * Important, the device must already be open!
67 **/
68 static void
69 fu_provider_usb_device_add (FuProviderUsb *provider_usb, const gchar *id, GUsbDevice *device)
70 {
71 FuProviderUsbPrivate *priv = GET_PRIVATE (provider_usb);
72 FuDevice *dev;
55 * fu_provider_usb_device_added:
56 **/
57 static void
58 fu_provider_usb_device_added (FuProviderUsb *provider_usb, GUsbDevice *device)
59 {
60 FuProviderUsbPrivate *priv = GET_PRIVATE (provider_usb);
61 const gchar *platform_id = NULL;
7362 guint8 idx = 0x00;
7463 g_autofree gchar *guid = NULL;
7564 g_autofree gchar *product = NULL;
7665 g_autofree gchar *version = NULL;
7766 g_autoptr(AsProfile) profile = as_profile_new ();
7867 g_autoptr(AsProfileTask) ptask = NULL;
68 g_autoptr(FuDevice) dev = NULL;
69 g_autoptr(GError) error = NULL;
70
71 /* ignore hubs */
72 if (g_usb_device_get_device_class (device) == G_USB_DEVICE_CLASS_HUB)
73 return;
74 ptask = as_profile_start (profile, "FuProviderUsb:added{%04x:%04x}",
75 g_usb_device_get_vid (device),
76 g_usb_device_get_pid (device));
77
78 /* is already in database */
79 platform_id = g_usb_device_get_platform_id (device);
80 dev = g_hash_table_lookup (priv->devices, platform_id);
81 if (dev != NULL) {
82 g_debug ("ignoring duplicate %s", platform_id);
83 return;
84 }
85
86 /* try to get the version without claiming interface */
87 if (!g_usb_device_open (device, &error)) {
88 g_debug ("Failed to open: %s", error->message);
89 return;
90 }
91
92 /* insert to hash if valid */
93 dev = fu_device_new ();
94 fu_device_set_id (dev, platform_id);
7995
8096 /* get product */
8197 idx = g_usb_device_get_product_index (device);
85101 product = g_usb_device_get_string_descriptor (device, idx, NULL);
86102 }
87103 if (product == NULL) {
88 g_debug ("ignoring %s as no product string descriptor", id);
89 return;
90 }
91
92 ptask = as_profile_start_literal (profile, "FuProviderUsb:get-custom-index");
93 #if G_USB_CHECK_VERSION(0,2,5)
104 g_debug ("no product string descriptor");
105 return;
106 }
107 fu_device_set_display_name (dev, product);
108
109 /* get version number, falling back to the USB device release */
94110 idx = g_usb_device_get_custom_index (device,
95111 G_USB_DEVICE_CLASS_VENDOR_SPECIFIC,
96112 'F', 'W', NULL);
97 #endif
98113 if (idx != 0x00)
99114 version = g_usb_device_get_string_descriptor (device, idx, NULL);
100115 if (version == NULL) {
101 g_debug ("ignoring %s [%s] as no version", id, product);
102 return;
103 }
104 #if G_USB_CHECK_VERSION(0,2,5)
116 guint16 release;
117 release = g_usb_device_get_release (device);
118 version = as_utils_version_from_uint16 (release,
119 AS_VERSION_PARSE_FLAG_NONE);
120 }
121 fu_device_set_metadata (dev, FU_DEVICE_KEY_VERSION, version);
122
123 /* get GUID, falling back to the USB VID:PID hash */
105124 idx = g_usb_device_get_custom_index (device,
106125 G_USB_DEVICE_CLASS_VENDOR_SPECIFIC,
107126 'G', 'U', NULL);
108 #endif
109127 if (idx != 0x00)
110128 guid = g_usb_device_get_string_descriptor (device, idx, NULL);
111129 if (guid == NULL) {
112 g_debug ("ignoring %s [%s] as no GUID", id, product);
113 return;
114 }
130 g_autofree gchar *vid_pid = NULL;
131 vid_pid = g_strdup_printf ("USB\\VID_%04X&PID_%04X",
132 g_usb_device_get_vid (device),
133 g_usb_device_get_pid (device));
134 guid = as_utils_guid_from_string (vid_pid);
135 }
136 fu_device_set_guid (dev, guid);
137
138 /* we're done here */
139 if (!g_usb_device_close (device, &error))
140 g_debug ("Failed to close: %s", error->message);
115141
116142 /* insert to hash */
117 dev = fu_device_new ();
118 fu_device_set_id (dev, id);
119 fu_device_set_guid (dev, guid);
120 fu_device_set_display_name (dev, product);
121 fu_device_set_metadata (dev, FU_DEVICE_KEY_VERSION, version);
122 g_hash_table_insert (priv->devices,
123 g_strdup (id), dev);
124143 fu_provider_device_add (FU_PROVIDER (provider_usb), dev);
144 g_hash_table_insert (priv->devices, g_strdup (platform_id), g_object_ref (dev));
145 }
146
147 typedef struct {
148 FuProviderUsb *provider_usb;
149 GUsbDevice *device;
150 } FuProviderUsbHelper;
151
152 /**
153 * fu_provider_usb_device_added_delay_cb:
154 **/
155 static gboolean
156 fu_provider_usb_device_added_delay_cb (gpointer user_data)
157 {
158 FuProviderUsbHelper *helper = (FuProviderUsbHelper *) user_data;
159 fu_provider_usb_device_added (helper->provider_usb, helper->device);
160 g_object_unref (helper->provider_usb);
161 g_object_unref (helper->device);
162 g_free (helper);
163 return FALSE;
125164 }
126165
127166 /**
133172 FuProviderUsb *provider_usb)
134173 {
135174 FuProviderUsbPrivate *priv = GET_PRIVATE (provider_usb);
136 FuDevice *dev;
137 g_autoptr(GError) error = NULL;
138 g_autofree gchar *id = NULL;
139 g_autoptr(AsProfile) profile = as_profile_new ();
140 g_autoptr(AsProfileTask) ptask = NULL;
141
142 /* ignore hubs */
143 #if G_USB_CHECK_VERSION(0,2,5)
144 if (g_usb_device_get_device_class (device) == G_USB_DEVICE_CLASS_HUB)
145 return;
146 #endif
147 ptask = as_profile_start (profile, "FuProviderUsb:added{%04x:%04x}",
148 g_usb_device_get_vid (device),
149 g_usb_device_get_pid (device));
150
151 /* handled by another provider */
152 id = fu_provider_usb_get_id (device);
153 if (g_usb_device_get_vid (device) == 0x273f) {
154 g_debug ("handling %s in another provider", id);
155 return;
156 }
157
158 /* is already in database */
159 dev = g_hash_table_lookup (priv->devices, id);
160 if (dev != NULL) {
161 g_debug ("ignoring duplicate %s", id);
162 return;
163 }
164
165 /* try to get the version without claiming interface */
166 if (!g_usb_device_open (device, &error)) {
167 g_debug ("Failed to open: %s", error->message);
168 return;
169 }
170
171 /* try to add the device */
172 fu_provider_usb_device_add (provider_usb, id, device);
173
174 /* we're done here */
175 if (!g_usb_device_close (device, &error))
176 g_debug ("Failed to close: %s", error->message);
175
176 /* use a small delay for hotplugging so that other, better, providers
177 * can claim this interface and add the FuDevice */
178 if (priv->done_enumerate) {
179 FuProviderUsbHelper *helper;
180 g_debug ("waiting a small time for other providers");
181 helper = g_new0 (FuProviderUsbHelper, 1);
182 helper->provider_usb = g_object_ref (provider_usb);
183 helper->device = g_object_ref (device);
184 g_timeout_add (500, fu_provider_usb_device_added_delay_cb, helper);
185 return;
186 }
187 fu_provider_usb_device_added (provider_usb, device);
177188 }
178189
179190 /**
186197 {
187198 FuProviderUsbPrivate *priv = GET_PRIVATE (provider_usb);
188199 FuDevice *dev;
189 g_autofree gchar *id = NULL;
200 const gchar *platform_id = NULL;
190201
191202 /* already in database */
192 id = fu_provider_usb_get_id (device);
193 dev = g_hash_table_lookup (priv->devices, id);
203 platform_id = g_usb_device_get_platform_id (device);
204 dev = g_hash_table_lookup (priv->devices, platform_id);
194205 if (dev == NULL)
195206 return;
207
196208 fu_provider_device_remove (FU_PROVIDER (provider_usb), dev);
209 g_hash_table_remove (priv->devices, platform_id);
197210 }
198211
199212 /**
204217 {
205218 FuProviderUsb *provider_usb = FU_PROVIDER_USB (provider);
206219 FuProviderUsbPrivate *priv = GET_PRIVATE (provider_usb);
207
208220 g_usb_context_enumerate (priv->usb_ctx);
221 priv->done_enumerate = TRUE;
209222 return TRUE;
210223 }
211224
370370 void
371371 fu_provider_device_add (FuProvider *provider, FuDevice *device)
372372 {
373 g_debug ("emit added: %s", fu_device_get_id (device));
373 g_debug ("emit added from %s: %s",
374 fu_provider_get_name (provider),
375 fu_device_get_id (device));
374376 fu_device_set_metadata (device, FU_DEVICE_KEY_PROVIDER,
375377 fu_provider_get_name (provider));
376378 g_signal_emit (provider, signals[SIGNAL_DEVICE_ADDED], 0, device);
382384 void
383385 fu_provider_device_remove (FuProvider *provider, FuDevice *device)
384386 {
385 g_debug ("emit removed: %s", fu_device_get_id (device));
387 g_debug ("emit removed from %s: %s",
388 fu_provider_get_name (provider),
389 fu_device_get_id (device));
386390 g_signal_emit (provider, signals[SIGNAL_DEVICE_REMOVED], 0, device);
387391 }
388392
6565 FuRomKind kind;
6666 gchar *version;
6767 gchar *guid;
68 guint16 vendor;
69 guint16 model;
68 guint16 vendor_id;
69 guint16 device_id;
7070 GPtrArray *hdrs; /* of FuRomPciHeader */
7171 } FuRomPrivate;
7272
160160 str = g_string_new ("");
161161 if (sz <= 0)
162162 return NULL;
163 for (i = 0; i < sz; i++)
163 for (i = 0; i < (guint) sz; i++)
164164 g_string_append_printf (str, "%02x ", buffer[i]);
165165 g_string_append (str, " ");
166 for (i = 0; i < sz; i++) {
166 for (i = 0; i < (guint) sz; i++) {
167167 gchar tmp = '?';
168168 if (g_ascii_isprint (buffer[i]))
169169 tmp = buffer[i];
670670 g_set_error (error,
671671 FWUPD_ERROR,
672672 FWUPD_ERROR_INVALID_FILE,
673 "Firmware too small: %" G_GSIZE_FORMAT " bytes", sz);
673 "Firmware too small: %" G_GSSIZE_FORMAT " bytes", sz);
674674 return FALSE;
675675 }
676676
699699 return FALSE;
700700 }
701701 }
702 g_debug ("ROM buffer filled %likb/%likb", sz / 0x400, buffer_sz / 0x400);
702 g_debug ("ROM buffer filled %" G_GSSIZE_FORMAT "kb/%" G_GSSIZE_FORMAT "kb",
703 sz / 0x400, buffer_sz / 0x400);
703704
704705 /* detect optional IFR header and skip to option ROM */
705706 if (memcmp (buffer, "NVGI", 4) == 0)
772773
773774 /* find first ROM header */
774775 hdr = g_ptr_array_index (priv->hdrs, 0);
775 priv->vendor = hdr->vendor_id;
776 priv->model = hdr->device_id;
776 priv->vendor_id = hdr->vendor_id;
777 priv->device_id = hdr->device_id;
777778 priv->kind = FU_ROM_KIND_PCI;
778779
779780 /* detect intel header */
820821 }
821822
822823 /* update guid */
823 id = g_strdup_printf ("0x%04x:0x%04x", priv->vendor, priv->model);
824 id = g_strdup_printf ("PCI\\VEN_%04X&DEV_%04X",
825 priv->vendor_id, priv->device_id);
824826 priv->guid = as_utils_guid_from_string (id);
825827 g_debug ("using %s for %s", priv->guid, id);
826828
877879 {
878880 FuRomPrivate *priv = GET_PRIVATE (rom);
879881 g_return_val_if_fail (FU_IS_ROM (rom), 0x0000);
880 return priv->vendor;
882 return priv->vendor_id;
881883 }
882884
883885 /**
888890 {
889891 FuRomPrivate *priv = GET_PRIVATE (rom);
890892 g_return_val_if_fail (FU_IS_ROM (rom), 0x0000);
891 return priv->model;
893 return priv->device_id;
892894 }
893895
894896 /**
311311 g_assert (device != NULL);
312312 g_assert_cmpstr (fu_device_get_id (device), ==, "raspberry-pi");
313313 g_assert_cmpstr (fu_device_get_guid (device), ==,
314 "c77029fe-ffb2-3706-dc67-67af4a132afd");
314 "91dd7368-8640-5d72-a217-a505c034dd0b");
315315 g_assert_cmpstr (fu_device_get_metadata (device, FU_DEVICE_KEY_VERSION), ==,
316316 "20150803");
317317
346346 const gchar *keys[] = {
347347 FU_DEVICE_KEY_DISPLAY_NAME,
348348 FU_DEVICE_KEY_PROVIDER,
349 FU_DEVICE_KEY_APPSTREAM_ID,
349350 FU_DEVICE_KEY_GUID,
350351 FU_DEVICE_KEY_VERSION,
351352 FU_DEVICE_KEY_URL_HOMEPAGE,
13601361 /* TRANSLATORS: first replacement is device name */
13611362 g_print (_("%s has firmware updates:"), fu_device_get_display_name (dev));
13621363 g_print ("\n");
1364
1365 /* TRANSLATORS: Appstream ID for the hardware type */
1366 fu_util_print_data (_("ID"),
1367 fu_device_get_metadata (dev, FU_DEVICE_KEY_APPSTREAM_ID));
1368
1369 /* TRANSLATORS: a GUID for the hardware */
1370 fu_util_print_data (_("GUID"),
1371 fu_device_get_metadata (dev, FU_DEVICE_KEY_GUID));
13631372
13641373 /* TRANSLATORS: section header for firmware version */
13651374 fu_util_print_data (_("Version"),