libdfu: Fix multi-interface devices like the Neo Freerunner

The DFU specification specifies that only one of the DFU interfaces has to
export a functional descriptor; I assumed they all had to. Adding support
for this kind of device rapidly turned into a massive restructure and it was
all too complicated anyway.

Reorganise the code so that we can support these kinds of devices and clean up
the API so it's sane and easy to use. This also allows us to generate the
GObject introspection GIR and to also install libdfu as a shared library.

If you've got any comments about the API, please shout now as when 6.0 is
released it will become API and ABI stable.
This commit is contained in:
Richard Hughes 2015-11-22 10:15:48 +00:00
parent e7ba943cf5
commit e7aaf39de2
18 changed files with 1242 additions and 1196 deletions

View File

@ -100,7 +100,6 @@ find %{buildroot} -name '*.la' -exec rm -f {} ';'
%{_unitdir}/system-update.target.wants/
%dir %{_localstatedir}/lib/fwupd
%{_libdir}/lib*.so.*
%{_libdir}/fwupd/libdfu-private.so
%{_libdir}/girepository-1.0/*.typelib
%dir %{_localstatedir}/cache/app-info
%dir %{_localstatedir}/cache/app-info/icons

View File

@ -73,7 +73,7 @@ expand_content_files=
# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
GTKDOC_CFLAGS=
GTKDOC_LIBS=$(top_builddir)/libdfu/libdfu-private.la
GTKDOC_LIBS=$(top_builddir)/libdfu/libdfu.la
# This includes the standard gtk-doc make rules, copied by gtkdocize.
include $(top_srcdir)/gtk-doc.make

View File

@ -1,3 +1,10 @@
if HAVE_INTROSPECTION
-include $(INTROSPECTION_MAKEFILE)
INTROSPECTION_GIRS =
INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir)
INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
endif
AM_CPPFLAGS = \
$(APPSTREAM_GLIB_CFLAGS) \
$(GLIB_CFLAGS) \
@ -13,11 +20,25 @@ AM_CPPFLAGS = \
FWUPD_LIBS = \
$(top_builddir)/libfwupd/libfwupd.la
privlibdir=$(libdir)/fwupd
privlib_LTLIBRARIES = \
libdfu-private.la
lib_LTLIBRARIES = \
libdfu.la
libdfu_private_la_SOURCES = \
libdfu_includedir = $(includedir)/fwupd-1
libdfu_include_HEADERS = \
dfu.h
libdfubase_includedir = $(libdfu_includedir)/libdfu
libdfubase_include_HEADERS = \
dfu-common.h \
dfu-device.h \
dfu-element.h \
dfu-error.h \
dfu-firmware.h \
dfu-image.h \
dfu-sector.h \
dfu-target.h
libdfu_la_SOURCES = \
dfu.h \
dfu-common.c \
dfu-common.h \
@ -41,18 +62,18 @@ libdfu_private_la_SOURCES = \
dfu-target.h \
dfu-target-private.h
libdfu_private_la_LIBADD = \
libdfu_la_LIBADD = \
$(FWUPD_LIBS) \
$(GUSB_LIBS) \
$(GLIB_LIBS)
libdfu_private_la_LDFLAGS = \
libdfu_la_LDFLAGS = \
-export-dynamic \
-no-undefined \
-avoid-version \
-export-symbols-regex '^dfu_.*'
libdfu_private_la_CFLAGS = \
libdfu_la_CFLAGS = \
$(WARNINGFLAGS_C)
bin_PROGRAMS = \
@ -62,7 +83,7 @@ dfu_tool_SOURCES = \
dfu-tool.c
dfu_tool_LDADD = \
$(privlib_LTLIBRARIES) \
$(lib_LTLIBRARIES) \
$(APPSTREAM_GLIB_LIBS) \
$(GLIB_LIBS) \
$(GUSB_LIBS)
@ -82,7 +103,7 @@ dfu_self_test_SOURCES = \
dfu-self-test.c
dfu_self_test_LDADD = \
$(privlib_LTLIBRARIES) \
$(lib_LTLIBRARIES) \
$(GLIB_LIBS) \
$(GUSB_LIBS)
@ -93,6 +114,31 @@ TESTS = dfu-self-test
CLEANFILES = *.log *.trs $(BUILT_SOURCES)
MAINTAINERCLEANFILES = *.dfu *.bin
if HAVE_INTROSPECTION
introspection_sources = \
$(libdfu_la_SOURCES)
Dfu-1.0.gir: libdfu.la
Dfu_1_0_gir_INCLUDES = GObject-2.0 Gio-2.0 GUsb-1.0
Dfu_1_0_gir_CFLAGS = $(AM_CPPFLAGS)
Dfu_1_0_gir_SCANNERFLAGS = --identifier-prefix=Dfu \
--symbol-prefix=dfu \
--warn-all \
--add-include-path=$(srcdir) \
--c-include="dfu.h"
Dfu_1_0_gir_EXPORT_PACKAGES = dfu
Dfu_1_0_gir_LIBS = libdfu.la
Dfu_1_0_gir_FILES = $(introspection_sources)
INTROSPECTION_GIRS += Dfu-1.0.gir
girdir = $(datadir)/gir-1.0
gir_DATA = $(INTROSPECTION_GIRS)
typelibdir = $(libdir)/girepository-1.0
typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
CLEANFILES += $(gir_DATA) $(typelib_DATA) *.log *.trs *.test
endif
clean-local:
rm -f *~

View File

@ -30,11 +30,64 @@
G_BEGIN_DECLS
GUsbDevice *_dfu_device_get_usb_dev (DfuDevice *device);
void _dfu_device_set_runtime_vid (DfuDevice *device,
guint16 runtime_vid);
void _dfu_device_set_runtime_pid (DfuDevice *device,
guint16 runtime_pid);
/**
* DfuDeviceQuirks:
* @DFU_DEVICE_QUIRK_NONE: No device quirks
* @DFU_DEVICE_QUIRK_IGNORE_POLLTIMEOUT: Ignore the device download timeout
* @DFU_DEVICE_QUIRK_FORCE_DFU_MODE: Force DFU mode
* @DFU_DEVICE_QUIRK_IGNORE_INVALID_VERSION: Ignore invalid version numbers
* @DFU_DEVICE_QUIRK_USE_PROTOCOL_ZERO: Fix up the protocol number
* @DFU_DEVICE_QUIRK_NO_PID_CHANGE: Accept the same VID:PID when changing modes
* @DFU_DEVICE_QUIRK_NO_GET_STATUS_UPLOAD: Do not do GetStatus when uploading
*
* The workarounds for different devices.
**/
typedef enum {
DFU_DEVICE_QUIRK_NONE = 0,
DFU_DEVICE_QUIRK_IGNORE_POLLTIMEOUT = (1 << 0),
DFU_DEVICE_QUIRK_FORCE_DFU_MODE = (1 << 1),
DFU_DEVICE_QUIRK_IGNORE_INVALID_VERSION = (1 << 2),
DFU_DEVICE_QUIRK_USE_PROTOCOL_ZERO = (1 << 3),
DFU_DEVICE_QUIRK_NO_PID_CHANGE = (1 << 4),
DFU_DEVICE_QUIRK_NO_GET_STATUS_UPLOAD = (1 << 5),
/*< private >*/
DFU_DEVICE_QUIRK_LAST
} DfuDeviceQuirks;
/**
* DfuDeviceAttributes:
* @DFU_DEVICE_ATTRIBUTE_NONE: No attributes set
* @DFU_DEVICE_ATTRIBUTE_CAN_DOWNLOAD: Can download from host->device
* @DFU_DEVICE_ATTRIBUTE_CAN_UPLOAD: Can upload from device->host
* @DFU_DEVICE_ATTRIBUTE_MANIFEST_TOL: Can answer GetStatus in manifest
* @DFU_DEVICE_ATTRIBUTE_WILL_DETACH: Will self-detach
* @DFU_DEVICE_ATTRIBUTE_CAN_ACCELERATE: Use a larger transfer size for speed
*
* The device DFU attributes.
**/
typedef enum {
DFU_DEVICE_ATTRIBUTE_NONE = 0,
DFU_DEVICE_ATTRIBUTE_CAN_DOWNLOAD = (1 << 0),
DFU_DEVICE_ATTRIBUTE_CAN_UPLOAD = (1 << 1),
DFU_DEVICE_ATTRIBUTE_MANIFEST_TOL = (1 << 2),
DFU_DEVICE_ATTRIBUTE_WILL_DETACH = (1 << 3),
DFU_DEVICE_ATTRIBUTE_CAN_ACCELERATE = (1 << 7),
/*< private >*/
DFU_DEVICE_ATTRIBUTE_LAST
} DfuDeviceAttributes;
GUsbDevice *dfu_device_get_usb_dev (DfuDevice *device);
gboolean dfu_device_has_dfuse_support (DfuDevice *device);
gboolean dfu_device_has_attribute (DfuDevice *device,
DfuDeviceAttributes attribute);
gboolean dfu_device_has_quirk (DfuDevice *device,
DfuDeviceQuirks quirk);
void dfu_device_error_fixup (DfuDevice *device,
GCancellable *cancellable,
GError **error);
guint dfu_device_get_download_timeout (DfuDevice *device);
G_END_DECLS

File diff suppressed because it is too large Load Diff

View File

@ -34,6 +34,20 @@ G_BEGIN_DECLS
#define DFU_TYPE_DEVICE (dfu_device_get_type ())
G_DECLARE_DERIVABLE_TYPE (DfuDevice, dfu_device, DFU, DEVICE, GObject)
/**
* DfuDeviceOpenFlags:
* @DFU_DEVICE_OPEN_FLAG_NONE: No flags set
* @DFU_DEVICE_OPEN_FLAG_NO_AUTO_REFRESH: Do not do the initial GET_STATUS
*
* The optional flags used for opening the target.
**/
typedef enum {
DFU_DEVICE_OPEN_FLAG_NONE = 0,
DFU_DEVICE_OPEN_FLAG_NO_AUTO_REFRESH = (1 << 0),
/*< private >*/
DFU_DEVICE_OPEN_FLAG_LAST,
} DfuDeviceOpenFlags;
struct _DfuDeviceClass
{
GObjectClass parent_class;
@ -41,12 +55,12 @@ struct _DfuDeviceClass
DfuDevice *dfu_device_new (GUsbDevice *dev);
gboolean dfu_device_open (DfuDevice *device,
DfuDeviceOpenFlags flags,
GCancellable *cancellable,
GError **error);
gboolean dfu_device_close (DfuDevice *device,
GError **error);
GPtrArray *dfu_device_get_targets (DfuDevice *device);
DfuTarget *dfu_device_get_target_default (DfuDevice *device,
GError **error);
DfuTarget *dfu_device_get_target_by_alt_setting (DfuDevice *device,
guint8 alt_setting,
GError **error);
@ -74,6 +88,32 @@ gboolean dfu_device_download (DfuDevice *device,
DfuProgressCallback progress_cb,
gpointer progress_cb_data,
GError **error);
gboolean dfu_device_refresh (DfuDevice *device,
GCancellable *cancellable,
GError **error);
gboolean dfu_device_detach (DfuDevice *device,
GCancellable *cancellable,
GError **error);
gboolean dfu_device_abort (DfuDevice *device,
GCancellable *cancellable,
GError **error);
gboolean dfu_device_clear_status (DfuDevice *device,
GCancellable *cancellable,
GError **error);
guint8 dfu_device_get_interface (DfuDevice *device);
DfuMode dfu_device_get_mode (DfuDevice *device);
DfuState dfu_device_get_state (DfuDevice *device);
DfuStatus dfu_device_get_status (DfuDevice *device);
guint16 dfu_device_get_transfer_size (DfuDevice *device);
guint dfu_device_get_timeout (DfuDevice *device);
gboolean dfu_device_can_upload (DfuDevice *device);
gboolean dfu_device_can_download (DfuDevice *device);
void dfu_device_set_transfer_size (DfuDevice *device,
guint16 transfer_size);
void dfu_device_set_timeout (DfuDevice *device,
guint timeout_ms);
G_END_DECLS

View File

@ -26,11 +26,11 @@
G_BEGIN_DECLS
DfuElement *_dfu_element_from_dfuse (const guint8 *data,
DfuElement *dfu_element_from_dfuse (const guint8 *data,
gsize length,
guint32 *consumed,
GError **error);
GBytes *_dfu_element_to_dfuse (DfuElement *element);
GBytes *dfu_element_to_dfuse (DfuElement *element);
G_END_DECLS

View File

@ -261,7 +261,7 @@ typedef struct __attribute__((packed)) {
} DfuSeElementPrefix;
/**
* _dfu_element_from_dfuse: (skip)
* dfu_element_from_dfuse: (skip)
* @data: data buffer
* @length: length of @data we can access
* @consumed: (out): the number of bytes we consued
@ -272,7 +272,7 @@ typedef struct __attribute__((packed)) {
* Returns: a #DfuElement, or %NULL for error
**/
DfuElement *
_dfu_element_from_dfuse (const guint8 *data,
dfu_element_from_dfuse (const guint8 *data,
gsize length,
guint32 *consumed,
GError **error)
@ -298,7 +298,7 @@ _dfu_element_from_dfuse (const guint8 *data,
}
/**
* _dfu_element_to_dfuse: (skip)
* dfu_element_to_dfuse: (skip)
* @element: a #DfuElement
*
* Packs a DfuSe element.
@ -306,7 +306,7 @@ _dfu_element_from_dfuse (const guint8 *data,
* Returns: (transfer full): the packed data
**/
GBytes *
_dfu_element_to_dfuse (DfuElement *element)
dfu_element_to_dfuse (DfuElement *element)
{
DfuElementPrivate *priv = GET_PRIVATE (element);
DfuSeElementPrefix *el;

View File

@ -662,7 +662,7 @@ dfu_firmware_add_dfuse (DfuFirmware *firmware, GBytes *bytes, GError **error)
for (i = 0; i < prefix->targets; i++) {
guint consumed;
g_autoptr(DfuImage) image = NULL;
image = _dfu_image_from_dfuse (data + offset,
image = dfu_image_from_dfuse (data + offset,
len - offset,
&consumed,
error);
@ -693,7 +693,7 @@ dfu_firmware_write_data_dfuse (DfuFirmware *firmware, GError **error)
for (i = 0; i < priv->images->len; i++) {
DfuImage *im = g_ptr_array_index (priv->images, i);
GBytes *contents;
contents = _dfu_image_to_dfuse (im);
contents = dfu_image_to_dfuse (im);
image_size_total += g_bytes_get_size (contents);
g_ptr_array_add (dfuse_images, contents);
}
@ -878,7 +878,7 @@ dfu_firmware_add_footer (DfuFirmware *firmware, GBytes *contents)
ftr->crc = dfu_firmware_generate_crc32 (buf, length + 12);
/* return all data */
return g_bytes_new (buf, length + 0x10);
return g_bytes_new_take (buf, length + 0x10);
}
/**

View File

@ -26,11 +26,11 @@
G_BEGIN_DECLS
DfuImage *_dfu_image_from_dfuse (const guint8 *data,
DfuImage *dfu_image_from_dfuse (const guint8 *data,
gsize length,
guint32 *consumed,
GError **error);
GBytes *_dfu_image_to_dfuse (DfuImage *image);
GBytes *dfu_image_to_dfuse (DfuImage *image);
G_END_DECLS

View File

@ -113,7 +113,7 @@ dfu_image_new (void)
*
* Gets the element data.
*
* Return value: (transfer none): element data
* Return value: (transfer none) (element-type DfuElement): element data
*
* Since: 0.5.4
**/
@ -318,7 +318,7 @@ typedef struct __attribute__((packed)) {
} DfuSeImagePrefix;
/**
* _dfu_image_from_dfuse: (skip)
* dfu_image_from_dfuse: (skip)
* @data: data buffer
* @length: length of @data we can access
* @consumed: (out): the number of bytes we consued
@ -329,7 +329,7 @@ typedef struct __attribute__((packed)) {
* Returns: a #DfuImage, or %NULL for error
**/
DfuImage *
_dfu_image_from_dfuse (const guint8 *data,
dfu_image_from_dfuse (const guint8 *data,
gsize length,
guint32 *consumed,
GError **error)
@ -339,7 +339,6 @@ _dfu_image_from_dfuse (const guint8 *data,
DfuSeImagePrefix *im;
guint32 offset = sizeof(DfuSeImagePrefix);
guint j;
g_autoptr(GBytes) contents = NULL;
g_assert_cmpint(sizeof(DfuSeImagePrefix), ==, 274);
@ -359,13 +358,12 @@ _dfu_image_from_dfuse (const guint8 *data,
priv->alt_setting = im->alt_setting;
if (im->target_named == 0x01)
memcpy (priv->name, im->target_name, 255);
contents = g_bytes_new (data + offset,
GUINT32_FROM_LE (im->target_size));
/* parse elements */
for (j = 0; j < im->elements; j++) {
guint32 consumed_local;
g_autoptr(DfuElement) element = NULL;
element = _dfu_element_from_dfuse (data + offset, length,
element = dfu_element_from_dfuse (data + offset, length,
&consumed_local, error);
if (element == NULL)
return NULL;
@ -381,7 +379,7 @@ _dfu_image_from_dfuse (const guint8 *data,
}
/**
* _dfu_image_to_dfuse: (skip)
* dfu_image_to_dfuse: (skip)
* @image: a #DfuImage
*
* Packs a DfuSe image
@ -389,7 +387,7 @@ _dfu_image_from_dfuse (const guint8 *data,
* Returns: (transfer full): the packed data
**/
GBytes *
_dfu_image_to_dfuse (DfuImage *image)
dfu_image_to_dfuse (DfuImage *image)
{
DfuImagePrivate *priv = GET_PRIVATE (image);
DfuElement *element;
@ -405,7 +403,7 @@ _dfu_image_to_dfuse (DfuImage *image)
element_array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref);
for (i = 0; i < priv->elements->len; i++) {
element = g_ptr_array_index (priv->elements, i);
bytes = _dfu_element_to_dfuse (element);
bytes = dfu_element_to_dfuse (element);
g_ptr_array_add (element_array, bytes);
length_total += g_bytes_get_size (bytes);
}

View File

@ -103,24 +103,23 @@ dfu_firmware_raw_func (void)
{
DfuElement *element;
DfuImage *image_tmp;
GBytes *no_suffix_contents;
gchar buf[256];
guint i;
gboolean ret;
g_autoptr(DfuFirmware) firmware = NULL;
g_autoptr(GBytes) fw = NULL;
g_autoptr(GBytes) no_suffix_contents = NULL;
g_autoptr(GBytes) roundtrip_orig = NULL;
g_autoptr(GBytes) roundtrip = NULL;
g_autoptr(GError) error = NULL;
firmware = dfu_firmware_new ();
/* set up some dummy data */
for (i = 0; i < 256; i++)
buf[i] = i;
fw = g_bytes_new_static (buf, 256);
/* load a non DFU firmware */
firmware = dfu_firmware_new ();
ret = dfu_firmware_parse_data (firmware, fw, DFU_FIRMWARE_PARSE_FLAG_NONE, &error);
g_assert_no_error (error);
g_assert (ret);
@ -163,8 +162,6 @@ dfu_firmware_dfu_func (void)
g_autoptr(GError) error = NULL;
g_autoptr(GFile) file = NULL;
firmware = dfu_firmware_new ();
/* set up some dummy data */
for (i = 0; i < 256; i++)
buf[i] = i;
@ -305,7 +302,7 @@ dfu_device_func (void)
g_assert (target1 != NULL);
/* ensure open */
ret = dfu_target_open (target1, DFU_TARGET_OPEN_FLAG_NONE, NULL, &error);
ret = dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE, NULL, &error);
g_assert_no_error (error);
g_assert (ret);
@ -315,7 +312,7 @@ dfu_device_func (void)
g_assert (target2 != NULL);
/* close */
ret = dfu_target_close (target1, &error);
ret = dfu_device_close (device, &error);
g_assert_no_error (error);
g_assert (ret);
}
@ -344,16 +341,13 @@ dfu_colorhug_plus_func (void)
NULL);
if (usb_device != NULL) {
g_autoptr(DfuDevice) device2 = NULL;
g_autoptr(DfuTarget) target2 = NULL;
device2 = dfu_device_new (usb_device);
g_assert (device2 != NULL);
target2 = dfu_device_get_target_by_alt_setting (device2, 0, &error);
g_assert_no_error (error);
g_assert (target2 != NULL);
ret = dfu_target_open (target2, DFU_TARGET_OPEN_FLAG_NO_AUTO_REFRESH, NULL, &error);
ret = dfu_device_open (device2, DFU_DEVICE_OPEN_FLAG_NONE, NULL, &error);
g_assert_no_error (error);
g_assert (ret);
ret = dfu_target_detach (target2, NULL, &error);
ret = dfu_device_detach (device2, NULL, &error);
g_assert_no_error (error);
g_assert (ret);
@ -363,9 +357,6 @@ dfu_colorhug_plus_func (void)
g_assert (ret);
/* close it */
ret = dfu_target_close (target2, &error);
g_assert_no_error (error);
g_assert (ret);
ret = dfu_device_close (device2, &error);
g_assert_no_error (error);
g_assert (ret);
@ -384,21 +375,18 @@ dfu_colorhug_plus_func (void)
/* check it's DFU-capable */
device = dfu_device_new (usb_device);
g_assert (device != NULL);
target = dfu_device_get_target_by_alt_setting (device, 0, &error);
g_assert_no_error (error);
g_assert (target != NULL);
/* we don't know this yet */
g_assert_cmpint (dfu_device_get_runtime_vid (device), ==, 0xffff);
g_assert_cmpint (dfu_device_get_runtime_pid (device), ==, 0xffff);
/* open it */
ret = dfu_target_open (target, DFU_TARGET_OPEN_FLAG_NONE, NULL, &error);
ret = dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE, NULL, &error);
g_assert_no_error (error);
g_assert (ret);
/* is in dfuIDLE mode */
g_assert_cmpstr (dfu_state_to_string (dfu_target_get_state (target)), ==, "dfuIDLE");
g_assert_cmpstr (dfu_state_to_string (dfu_device_get_state (device)), ==, "dfuIDLE");
/* lets try and flash something inappropriate */
if (seen_app_idle) {
@ -427,12 +415,15 @@ dfu_colorhug_plus_func (void)
}
/* get a dump of the existing firmware */
target = dfu_device_get_target_by_alt_setting (device, 0, &error);
g_assert_no_error (error);
g_assert (target != NULL);
image = dfu_target_upload (target, DFU_TARGET_TRANSFER_FLAG_NONE,
NULL, NULL, NULL, &error);
g_assert_no_error (error);
g_assert (DFU_IS_IMAGE (image));
elements = dfu_image_get_elements (image);
g_assert_nonnull (elements);
g_assert (elements != NULL);
g_assert_cmpint (elements->len, ==, 1);
/* download a new firmware */
@ -453,23 +444,13 @@ dfu_colorhug_plus_func (void)
/* we should know now */
g_assert_cmpint (dfu_device_get_runtime_vid (device), ==, 0x273f);
g_assert_cmpint (dfu_device_get_runtime_pid (device), ==, 0x1002);
/* close it */
ret = dfu_target_close (target, &error);
g_assert_no_error (error);
g_assert (ret);
/* close it again */
ret = dfu_target_close (target, &error);
g_assert_no_error (error);
g_assert (ret);
}
/**
* _dfu_target_sectors_to_string:
* dfu_target_sectors_to_string:
**/
static gchar *
_dfu_target_sectors_to_string (DfuTarget *target)
dfu_target_sectors_to_string (DfuTarget *target)
{
DfuSector *sector;
GPtrArray *sectors;
@ -502,7 +483,7 @@ dfu_target_dfuse_func (void)
ret = dfu_target_parse_sectors (target, NULL, &error);
g_assert_no_error (error);
g_assert (ret);
tmp = _dfu_target_sectors_to_string (target);
tmp = dfu_target_sectors_to_string (target);
g_assert_cmpstr (tmp, ==, "");
g_free (tmp);
@ -510,7 +491,7 @@ dfu_target_dfuse_func (void)
ret = dfu_target_parse_sectors (target, "@Flash3", &error);
g_assert_no_error (error);
g_assert (ret);
tmp = _dfu_target_sectors_to_string (target);
tmp = dfu_target_sectors_to_string (target);
g_assert_cmpstr (tmp, ==, "");
g_free (tmp);
@ -518,7 +499,7 @@ dfu_target_dfuse_func (void)
ret = dfu_target_parse_sectors (target, "@Internal Flash /0x08000000/2*001Ka", &error);
g_assert_no_error (error);
g_assert (ret);
tmp = _dfu_target_sectors_to_string (target);
tmp = dfu_target_sectors_to_string (target);
g_assert_cmpstr (tmp, ==, "Zone:0, Sec#:0, Addr:0x08000000, Size:0x0400, Caps:0x1\n"
"Zone:0, Sec#:0, Addr:0x08000400, Size:0x0400, Caps:0x1");
g_free (tmp);
@ -527,7 +508,7 @@ dfu_target_dfuse_func (void)
ret = dfu_target_parse_sectors (target, "@Flash1 /0x08000000/2*001 Ka,4*001 Kg", &error);
g_assert_no_error (error);
g_assert (ret);
tmp = _dfu_target_sectors_to_string (target);
tmp = dfu_target_sectors_to_string (target);
g_assert_cmpstr (tmp, ==, "Zone:0, Sec#:0, Addr:0x08000000, Size:0x0400, Caps:0x1\n"
"Zone:0, Sec#:0, Addr:0x08000400, Size:0x0400, Caps:0x1\n"
"Zone:0, Sec#:1, Addr:0x08000000, Size:0x0400, Caps:0x7\n"
@ -540,7 +521,7 @@ dfu_target_dfuse_func (void)
ret = dfu_target_parse_sectors (target, "@Flash2 /0xF000/4*100Ba/0xE000/3*8Kg/0x80000/2*24Kg", &error);
g_assert_no_error (error);
g_assert (ret);
tmp = _dfu_target_sectors_to_string (target);
tmp = dfu_target_sectors_to_string (target);
g_assert_cmpstr (tmp, ==, "Zone:0, Sec#:0, Addr:0x0000f000, Size:0x0064, Caps:0x1\n"
"Zone:0, Sec#:0, Addr:0x0000f064, Size:0x0064, Caps:0x1\n"
"Zone:0, Sec#:0, Addr:0x0000f0c8, Size:0x0064, Caps:0x1\n"

View File

@ -29,12 +29,8 @@
G_BEGIN_DECLS
DfuTarget *_dfu_target_new (DfuDevice *device,
DfuTarget *dfu_target_new (DfuDevice *device,
GUsbInterface *iface);
gboolean _dfu_target_update (DfuTarget *target,
GUsbInterface *iface,
GCancellable *cancellable,
GError **error);
/* export this just for the self tests */
gboolean dfu_target_parse_sectors (DfuTarget *target,

File diff suppressed because it is too large Load Diff

View File

@ -38,20 +38,6 @@ struct _DfuTargetClass
GUsbDeviceClass parent_class;
};
/**
* DfuTargetOpenFlags:
* @DFU_TARGET_OPEN_FLAG_NONE: No flags set
* @DFU_TARGET_OPEN_FLAG_NO_AUTO_REFRESH: Do not do the initial GET_STATUS
*
* The optional flags used for opening the target.
**/
typedef enum {
DFU_TARGET_OPEN_FLAG_NONE = 0,
DFU_TARGET_OPEN_FLAG_NO_AUTO_REFRESH = (1 << 0),
/*< private >*/
DFU_TARGET_OPEN_FLAG_LAST,
} DfuTargetOpenFlags;
/**
* DfuTargetTransferFlags:
* @DFU_TARGET_TRANSFER_FLAG_NONE: No flags set
@ -81,29 +67,9 @@ typedef void (*DfuProgressCallback) (DfuState state,
goffset total,
gpointer user_data);
gboolean dfu_target_open (DfuTarget *target,
DfuTargetOpenFlags flags,
GCancellable *cancellable,
GError **error);
gboolean dfu_target_close (DfuTarget *target,
GError **error);
DfuMode dfu_target_get_mode (DfuTarget *target);
DfuState dfu_target_get_state (DfuTarget *target);
DfuStatus dfu_target_get_status (DfuTarget *target);
GPtrArray *dfu_target_get_sectors (DfuTarget *target);
gboolean dfu_target_can_upload (DfuTarget *target);
gboolean dfu_target_can_download (DfuTarget *target);
gboolean dfu_target_refresh (DfuTarget *target,
GCancellable *cancellable,
GError **error);
gboolean dfu_target_detach (DfuTarget *target,
GCancellable *cancellable,
GError **error);
gboolean dfu_target_abort (DfuTarget *target,
GCancellable *cancellable,
GError **error);
gboolean dfu_target_clear_status (DfuTarget *target,
GCancellable *cancellable,
guint8 dfu_target_get_alt_setting (DfuTarget *target);
const gchar *dfu_target_get_alt_name (DfuTarget *target,
GError **error);
DfuImage *dfu_target_upload (DfuTarget *target,
DfuTargetTransferFlags flags,
@ -118,14 +84,6 @@ gboolean dfu_target_download (DfuTarget *target,
DfuProgressCallback progress_cb,
gpointer progress_cb_data,
GError **error);
void dfu_target_set_timeout (DfuTarget *target,
guint timeout_ms);
guint8 dfu_target_get_interface_number (DfuTarget *target);
guint8 dfu_target_get_interface_alt_setting (DfuTarget *target);
const gchar *dfu_target_get_interface_alt_name (DfuTarget *target);
guint16 dfu_target_get_transfer_size (DfuTarget *target);
void dfu_target_set_transfer_size (DfuTarget *target,
guint16 transfer_size);
G_END_DECLS

View File

@ -208,12 +208,29 @@ dfu_tool_get_defalt_device (DfuToolPrivate *priv, GError **error)
/* we specified it manually */
if (priv->device_vid_pid != NULL) {
DfuDevice *device;
g_auto(GStrv) vid_pid = NULL;
gchar *tmp;
guint64 pid;
guint64 vid;
g_autoptr(GUsbDevice) usb_device = NULL;
/* split up */
vid_pid = g_strsplit (priv->device_vid_pid, ":", -1);
if (g_strv_length (vid_pid) != 2) {
/* parse */
vid = g_ascii_strtoull (priv->device_vid_pid, &tmp, 16);
if (vid == 0 || vid > G_MAXUINT16) {
g_set_error_literal (error,
DFU_ERROR,
DFU_ERROR_INTERNAL,
"Invalid format of VID:PID");
return NULL;
}
if (tmp[0] != ':') {
g_set_error_literal (error,
DFU_ERROR,
DFU_ERROR_INTERNAL,
"Invalid format of VID:PID");
return NULL;
}
pid = g_ascii_strtoull (tmp + 1, NULL, 16);
if (vid == 0 || vid > G_MAXUINT16) {
g_set_error_literal (error,
DFU_ERROR,
DFU_ERROR_INTERNAL,
@ -223,8 +240,7 @@ dfu_tool_get_defalt_device (DfuToolPrivate *priv, GError **error)
/* find device */
usb_device = g_usb_context_find_by_vid_pid (usb_ctx,
atoi (vid_pid[0]),
atoi (vid_pid[1]),
vid, pid,
error);
if (usb_device == NULL)
return NULL;
@ -724,22 +740,16 @@ static gboolean
dfu_tool_reset (DfuToolPrivate *priv, gchar **values, GError **error)
{
g_autoptr(DfuDevice) device = NULL;
g_autoptr(DfuTarget) target = NULL;
device = dfu_tool_get_defalt_device (priv, error);
if (device == NULL)
return FALSE;
target = dfu_device_get_target_by_alt_setting (device, priv->alt_setting, error);
if (target == NULL)
return FALSE;
if (!dfu_target_open (target,
DFU_TARGET_OPEN_FLAG_NO_AUTO_REFRESH,
if (!dfu_device_open (device,
DFU_DEVICE_OPEN_FLAG_NO_AUTO_REFRESH,
NULL, error))
return FALSE;
if (!dfu_device_reset (device, error))
return FALSE;
return TRUE;
}
@ -841,23 +851,24 @@ dfu_tool_upload_target (DfuToolPrivate *priv, gchar **values, GError **error)
device = dfu_tool_get_defalt_device (priv, error);
if (device == NULL)
return FALSE;
target = dfu_device_get_target_by_alt_setting (device, priv->alt_setting, error);
if (target == NULL)
return FALSE;
if (priv->transfer_size > 0)
dfu_target_set_transfer_size (target, priv->transfer_size);
if (!dfu_target_open (target, DFU_TARGET_OPEN_FLAG_NONE, NULL, error))
dfu_device_set_transfer_size (device, priv->transfer_size);
if (!dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE, NULL, error))
return FALSE;
/* APP -> DFU */
if (dfu_target_get_mode (target) == DFU_MODE_RUNTIME) {
if (dfu_device_get_mode (device) == DFU_MODE_RUNTIME) {
g_debug ("detaching");
if (!dfu_device_detach (device, NULL, error))
return FALSE;
if (!dfu_device_wait_for_replug (device, 5000, NULL, error))
return FALSE;
flags |= DFU_TARGET_TRANSFER_FLAG_BOOT_RUNTIME;
}
/* transfer */
target = dfu_device_get_target_by_alt_setting (device, priv->alt_setting, error);
if (target == NULL)
return FALSE;
helper.last_state = DFU_STATE_DFU_ERROR;
helper.marks_total = 30;
helper.marks_shown = 0;
@ -916,6 +927,8 @@ dfu_tool_upload (DfuToolPrivate *priv, gchar **values, GError **error)
device = dfu_tool_get_defalt_device (priv, error);
if (device == NULL)
return FALSE;
if (!dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE, NULL, error))
return FALSE;
/* optional reset */
if (priv->reset) {
@ -1017,19 +1030,15 @@ dfu_tool_download_target (DfuToolPrivate *priv, gchar **values, GError **error)
device = dfu_tool_get_defalt_device (priv, error);
if (device == NULL)
return FALSE;
target = dfu_device_get_target_by_alt_setting (device, priv->alt_setting, error);
if (target == NULL)
return FALSE;
if (priv->transfer_size > 0)
dfu_target_set_transfer_size (target, priv->transfer_size);
if (!dfu_target_open (target, DFU_TARGET_OPEN_FLAG_NONE, NULL, error))
dfu_device_set_transfer_size (device, priv->transfer_size);
if (!dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE, NULL, error))
return FALSE;
/* APP -> DFU */
if (dfu_target_get_mode (target) == DFU_MODE_RUNTIME) {
if (dfu_device_get_mode (device) == DFU_MODE_RUNTIME) {
g_debug ("detaching");
if (!dfu_target_detach (target, NULL, error))
if (!dfu_device_detach (device, NULL, error))
return FALSE;
if (!dfu_device_wait_for_replug (device, 5000, NULL, error))
return FALSE;
@ -1077,6 +1086,9 @@ dfu_tool_download_target (DfuToolPrivate *priv, gchar **values, GError **error)
}
/* transfer */
target = dfu_device_get_target_by_alt_setting (device, priv->alt_setting, error);
if (target == NULL)
return FALSE;
helper.last_state = DFU_STATE_DFU_ERROR;
helper.marks_total = 30;
helper.marks_shown = 0;
@ -1125,6 +1137,8 @@ dfu_tool_download (DfuToolPrivate *priv, gchar **values, GError **error)
device = dfu_tool_get_defalt_device (priv, error);
if (device == NULL)
return FALSE;
if (!dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE, NULL, error))
return FALSE;
/* print the new object */
str_debug = dfu_firmware_to_string (firmware);
@ -1179,61 +1193,35 @@ dfu_tool_print_indent (const gchar *title, const gchar *message, guint indent)
static void
dfu_tool_list_target (DfuTarget *target)
{
GPtrArray *sectors;
const gchar *tmp;
gboolean ret;
guint i;
g_autofree gchar *alt_id = NULL;
g_autoptr(GError) error_local = NULL;
/* TRANSLATORS: the identifier name please */
alt_id = g_strdup_printf ("%i", dfu_target_get_interface_alt_setting (target));
alt_id = g_strdup_printf ("%i", dfu_target_get_alt_setting (target));
dfu_tool_print_indent (_("ID"), alt_id, 1);
/* TRANSLATORS: device mode, e.g. runtime or DFU */
dfu_tool_print_indent (_("Mode"), dfu_mode_to_string (dfu_target_get_mode (target)), 2);
tmp = dfu_target_get_interface_alt_name (target);
/* this is optional */
tmp = dfu_target_get_alt_name (target, NULL);
if (tmp != NULL) {
/* TRANSLATORS: interface name, e.g. "Flash" */
dfu_tool_print_indent (_("Name"), tmp, 2);
}
ret = dfu_target_open (target,
DFU_TARGET_OPEN_FLAG_NONE,
NULL, &error_local);
if (ret) {
GPtrArray *sectors;
tmp = dfu_status_to_string (dfu_target_get_status (target));
/* TRANSLATORS: device status, e.g. "OK" */
dfu_tool_print_indent (_("Status"), tmp, 2);
tmp = dfu_state_to_string (dfu_target_get_state (target));
/* TRANSLATORS: device state, i.e. appIDLE */
dfu_tool_print_indent (_("State"), tmp, 2);
/* print sector information */
sectors = dfu_target_get_sectors (target);
for (i = 0; i < sectors->len; i++) {
DfuSector *sector;
g_autofree gchar *msg = NULL;
g_autofree gchar *title = NULL;
sector = g_ptr_array_index (sectors, i);
msg = dfu_sector_to_string (sector);
/* TRANSLATORS: these are areas of memory on the chip */
title = g_strdup_printf ("%s 0x%02x", _("Region"), i);
dfu_tool_print_indent (title, msg, 3);
}
} else {
if (g_error_matches (error_local,
DFU_ERROR,
DFU_ERROR_PERMISSION_DENIED)) {
/* TRANSLATORS: probably not run as root... */
dfu_tool_print_indent (_("Status"), _("Unknown: permission denied"), 2);
} else {
/* TRANSLATORS: device has failed to report status */
dfu_tool_print_indent (_("Status"), error_local->message, 2);
}
/* print sector information */
sectors = dfu_target_get_sectors (target);
for (i = 0; i < sectors->len; i++) {
DfuSector *sector;
g_autofree gchar *msg = NULL;
g_autofree gchar *title = NULL;
sector = g_ptr_array_index (sectors, i);
msg = dfu_sector_to_string (sector);
/* TRANSLATORS: these are areas of memory on the chip */
title = g_strdup_printf ("%s 0x%02x", _("Region"), i);
dfu_tool_print_indent (title, msg, 2);
}
dfu_target_close (target, NULL);
}
/**
@ -1252,11 +1240,13 @@ dfu_tool_list (DfuToolPrivate *priv, gchar **values, GError **error)
g_usb_context_enumerate (usb_ctx);
devices = g_usb_context_get_devices (usb_ctx);
for (i = 0; i < devices->len; i++) {
g_autoptr(DfuDevice) device = NULL;
GPtrArray *dfu_targets;
DfuTarget *target;
const gchar *tmp;
guint j;
g_autofree gchar *version = NULL;
g_autoptr(DfuDevice) device = NULL;
g_autoptr(GError) error_local = NULL;
usb_device = g_ptr_array_index (devices, i);
g_debug ("PROBING [%04x:%04x]",
@ -1276,6 +1266,34 @@ dfu_tool_list (DfuToolPrivate *priv, gchar **values, GError **error)
g_usb_device_get_pid (usb_device),
version);
/* open */
if (!dfu_device_open (device,
DFU_DEVICE_OPEN_FLAG_NONE,
NULL, &error_local)) {
if (g_error_matches (error_local,
DFU_ERROR,
DFU_ERROR_PERMISSION_DENIED)) {
/* TRANSLATORS: probably not run as root... */
dfu_tool_print_indent (_("Status"), _("Unknown: permission denied"), 2);
} else {
/* TRANSLATORS: device has failed to report status */
dfu_tool_print_indent (_("Status"), error_local->message, 2);
}
continue;
}
tmp = dfu_mode_to_string (dfu_device_get_mode (device));
/* TRANSLATORS: device mode, e.g. runtime or DFU */
dfu_tool_print_indent (_("Mode"), tmp, 1);
tmp = dfu_status_to_string (dfu_device_get_status (device));
/* TRANSLATORS: device status, e.g. "OK" */
dfu_tool_print_indent (_("Status"), tmp, 1);
tmp = dfu_state_to_string (dfu_device_get_state (device));
/* TRANSLATORS: device state, i.e. appIDLE */
dfu_tool_print_indent (_("State"), tmp, 1);
/* list targets */
dfu_targets = dfu_device_get_targets (device);
for (j = 0; j < dfu_targets->len; j++) {
@ -1293,22 +1311,18 @@ static gboolean
dfu_tool_detach (DfuToolPrivate *priv, gchar **values, GError **error)
{
g_autoptr(DfuDevice) device = NULL;
g_autoptr(DfuTarget) target = NULL;
/* open correct device */
device = dfu_tool_get_defalt_device (priv, error);
if (device == NULL)
return FALSE;
target = dfu_device_get_target_by_alt_setting (device, priv->alt_setting, error);
if (target == NULL)
return FALSE;
if (priv->transfer_size > 0)
dfu_target_set_transfer_size (target, priv->transfer_size);
if (!dfu_target_open (target, DFU_TARGET_OPEN_FLAG_NONE, NULL, error))
return FALSE;
dfu_device_set_transfer_size (device, priv->transfer_size);
/* detatch */
if (!dfu_target_detach (target, NULL, error))
if (!dfu_device_open (device, DFU_DEVICE_OPEN_FLAG_NONE, NULL, error))
return FALSE;
if (!dfu_device_detach (device, NULL, error))
return FALSE;
return TRUE;
}

View File

@ -34,7 +34,7 @@ FWUPD_LIBS = \
$(top_builddir)/libfwupd/libfwupd.la
DFU_LIBS = \
$(top_builddir)/libdfu/libdfu-private.la
$(top_builddir)/libdfu/libdfu.la
bin_PROGRAMS = fwupdmgr

View File

@ -83,7 +83,6 @@ fu_provider_usb_device_add (FuProviderUsb *provider_usb, const gchar *id, GUsbDe
g_autoptr(AsProfile) profile = as_profile_new ();
g_autoptr(AsProfileTask) ptask = NULL;
g_autoptr(DfuDevice) dfu_device = NULL;
g_autoptr(DfuTarget) dfu_target = NULL;
/* get product */
idx = g_usb_device_get_product_index (device);
@ -135,20 +134,12 @@ fu_provider_usb_device_add (FuProviderUsb *provider_usb, const gchar *id, GUsbDe
/* is there a DFU interface */
dfu_device = dfu_device_new (device);
if (dfu_device != NULL) {
dfu_target = dfu_device_get_target_by_alt_setting (dfu_device, 0, NULL);
if (dfu_target != NULL) {
if (dfu_target_can_download (dfu_target)) {
fu_device_add_flag (dev, FU_DEVICE_FLAG_ALLOW_ONLINE);
fu_device_add_flag (dev, FU_DEVICE_FLAG_ALLOW_OFFLINE);
} else {
g_debug ("DFU device does not support downloading?!");
/* FIXME: is the CH+ correct here? */
fu_device_add_flag (dev, FU_DEVICE_FLAG_ALLOW_ONLINE);
fu_device_add_flag (dev, FU_DEVICE_FLAG_ALLOW_OFFLINE);
}
} else {
g_debug ("not a DFU device");
if (dfu_device_can_download (dfu_device)) {
fu_device_add_flag (dev, FU_DEVICE_FLAG_ALLOW_ONLINE);
fu_device_add_flag (dev, FU_DEVICE_FLAG_ALLOW_OFFLINE);
}
} else {
g_debug ("not a DFU device");
}
/* good to go */
@ -310,6 +301,15 @@ fu_provider_usb_update (FuProvider *provider,
platform_id);
return FALSE;
}
if (!dfu_device_open (dfu_device, DFU_DEVICE_OPEN_FLAG_NONE,
NULL, &error_local)) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"failed to open DFU device %s: %s",
platform_id, error_local->message);
return FALSE;
}
/* hit hardware */
dfu_firmware = dfu_firmware_new ();
@ -414,6 +414,15 @@ fu_provider_usb_verify (FuProvider *provider,
platform_id);
return FALSE;
}
if (!dfu_device_open (dfu_device, DFU_DEVICE_OPEN_FLAG_NONE,
NULL, &error_local)) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"failed to open DFU device %s: %s",
platform_id, error_local->message);
return FALSE;
}
/* get data from hardware */
dfu_firmware = dfu_device_upload (dfu_device,