dfu: Set the DfuDevice as a proxy to the DfuTarget

Set the alt_name_for_display as the target name and use the logical ID
as the target alt-name. This allows us to use the ->to_string() vfunc.
This commit is contained in:
Richard Hughes 2022-05-09 16:52:38 +01:00
parent 5bc1b60bf0
commit 3047ed1517
10 changed files with 203 additions and 512 deletions

View File

@ -109,120 +109,151 @@ typedef enum {
FU_DFU_STATE_LAST
} FuDfuState;
/**
* FU_DFU_DEVICE_FLAG_CAN_DOWNLOAD:
*
* Can download from host->device.
*/
#define FU_DFU_DEVICE_FLAG_CAN_DOWNLOAD (1ull << 0)
/**
* FU_DFU_DEVICE_FLAG_CAN_UPLOAD:
*
* Can upload from device->host.
*/
#define FU_DFU_DEVICE_FLAG_CAN_UPLOAD (1ull << 1)
/**
* FU_DFU_DEVICE_FLAG_MANIFEST_TOL:
*
* Can answer GetStatus in manifest.
*/
#define FU_DFU_DEVICE_FLAG_MANIFEST_TOL (1ull << 2)
/**
* FU_DFU_DEVICE_FLAG_WILL_DETACH:
*
* Will self-detach.
*/
#define FU_DFU_DEVICE_FLAG_WILL_DETACH (1ull << 3)
/**
* FU_DFU_DEVICE_FLAG_CAN_ACCELERATE:
*
* Use a larger transfer size for speed.
*/
#define FU_DFU_DEVICE_FLAG_CAN_ACCELERATE (1ull << 7)
/**
* FU_DFU_DEVICE_FLAG_ATTACH_EXTRA_RESET:
*
* Device needs resetting twice for attach.
*/
#define FU_DFU_DEVICE_FLAG_ATTACH_EXTRA_RESET (1 << 0)
#define FU_DFU_DEVICE_FLAG_ATTACH_EXTRA_RESET (1ull << (8 + 0))
/**
* FU_DFU_DEVICE_FLAG_ATTACH_UPLOAD_DOWNLOAD:
*
* An upload or download is required for attach.
*/
#define FU_DFU_DEVICE_FLAG_ATTACH_UPLOAD_DOWNLOAD (1 << 1)
#define FU_DFU_DEVICE_FLAG_ATTACH_UPLOAD_DOWNLOAD (1ull << (8 + 1))
/**
* FU_DFU_DEVICE_FLAG_FORCE_DFU_MODE:
*
* Force DFU mode.
*/
#define FU_DFU_DEVICE_FLAG_FORCE_DFU_MODE (1 << 2)
#define FU_DFU_DEVICE_FLAG_FORCE_DFU_MODE (1ull << (8 + 2))
/**
* FU_DFU_DEVICE_FLAG_IGNORE_POLLTIMEOUT:
*
* Ignore the device download timeout.
*/
#define FU_DFU_DEVICE_FLAG_IGNORE_POLLTIMEOUT (1 << 3)
#define FU_DFU_DEVICE_FLAG_IGNORE_POLLTIMEOUT (1ull << (8 + 3))
/**
* FU_DFU_DEVICE_FLAG_IGNORE_RUNTIME:
*
* Device has broken DFU runtime support.
*/
#define FU_DFU_DEVICE_FLAG_IGNORE_RUNTIME (1 << 4)
#define FU_DFU_DEVICE_FLAG_IGNORE_RUNTIME (1ull << (8 + 4))
/**
* FU_DFU_DEVICE_FLAG_IGNORE_UPLOAD:
*
* Uploading from the device is broken.
*/
#define FU_DFU_DEVICE_FLAG_IGNORE_UPLOAD (1 << 5)
#define FU_DFU_DEVICE_FLAG_IGNORE_UPLOAD (1ull << (8 + 5))
/**
* FU_DFU_DEVICE_FLAG_NO_DFU_RUNTIME:
*
* No DFU runtime interface is provided.
*/
#define FU_DFU_DEVICE_FLAG_NO_DFU_RUNTIME (1 << 6)
#define FU_DFU_DEVICE_FLAG_NO_DFU_RUNTIME (1ull << (8 + 6))
/**
* FU_DFU_DEVICE_FLAG_NO_GET_STATUS_UPLOAD:
*
* Do not do GetStatus when uploading.
*/
#define FU_DFU_DEVICE_FLAG_NO_GET_STATUS_UPLOAD (1 << 7)
#define FU_DFU_DEVICE_FLAG_NO_GET_STATUS_UPLOAD (1ull << (8 + 7))
/**
* FU_DFU_DEVICE_FLAG_NO_PID_CHANGE:
*
* Accept the same VID:PID when changing modes.
*/
#define FU_DFU_DEVICE_FLAG_NO_PID_CHANGE (1 << 8)
#define FU_DFU_DEVICE_FLAG_NO_PID_CHANGE (1ull << (8 + 8))
/**
* FU_DFU_DEVICE_FLAG_USE_ANY_INTERFACE:
*
* Use any interface for DFU.
*/
#define FU_DFU_DEVICE_FLAG_USE_ANY_INTERFACE (1 << 9)
#define FU_DFU_DEVICE_FLAG_USE_ANY_INTERFACE (1ull << (8 + 9))
/**
* FU_DFU_DEVICE_FLAG_USE_ATMEL_AVR:
*
* Device uses the ATMEL bootloader.
*/
#define FU_DFU_DEVICE_FLAG_USE_ATMEL_AVR (1 << 10)
#define FU_DFU_DEVICE_FLAG_USE_ATMEL_AVR (1ull << (8 + 10))
/**
* FU_DFU_DEVICE_FLAG_USE_PROTOCOL_ZERO:
*
* Fix up the protocol number.
*/
#define FU_DFU_DEVICE_FLAG_USE_PROTOCOL_ZERO (1 << 11)
#define FU_DFU_DEVICE_FLAG_USE_PROTOCOL_ZERO (1ull << (8 + 11))
/**
* FU_DFU_DEVICE_FLAG_LEGACY_PROTOCOL:
*
* Use a legacy protocol version.
*/
#define FU_DFU_DEVICE_FLAG_LEGACY_PROTOCOL (1 << 12)
#define FU_DFU_DEVICE_FLAG_LEGACY_PROTOCOL (1ull << (8 + 12))
/**
* FU_DFU_DEVICE_FLAG_DETACH_FOR_ATTACH:
*
* Requires a FU_DFU_REQUEST_DETACH to attach.
*/
#define FU_DFU_DEVICE_FLAG_DETACH_FOR_ATTACH (1 << 13)
#define FU_DFU_DEVICE_FLAG_DETACH_FOR_ATTACH (1ull << (8 + 13))
/**
* FU_DFU_DEVICE_FLAG_ABSENT_SECTOR_SIZE:
*
* In absence of sector size, assume byte.
*/
#define FU_DFU_DEVICE_FLAG_ABSENT_SECTOR_SIZE (1 << 14)
#define FU_DFU_DEVICE_FLAG_ABSENT_SECTOR_SIZE (1ull << (8 + 14))
/**
* FU_DFU_DEVICE_FLAG_MANIFEST_POLL:
*
* Requires polling via GetStatus in dfuManifest state.
*/
#define FU_DFU_DEVICE_FLAG_MANIFEST_POLL (1 << 15)
#define FU_DFU_DEVICE_FLAG_MANIFEST_POLL (1ull << (8 + 15))
/**
* FU_DFU_DEVICE_FLAG_NO_BUS_RESET_ATTACH:
*
* Do not require a bus reset to attach to normal.
*/
#define FU_DFU_DEVICE_FLAG_NO_BUS_RESET_ATTACH (1 << 16)
#define FU_DFU_DEVICE_FLAG_NO_BUS_RESET_ATTACH (1ull << (8 + 16))
/**
* FU_DFU_DEVICE_FLAG_GD32:
*
* Uses the slightly weird GD32 variant of DFU.
*/
#define FU_DFU_DEVICE_FLAG_GD32 (1 << 17)
#define FU_DFU_DEVICE_FLAG_GD32 (1ull << (8 + 17))
/**
* FU_DFU_DEVICE_FLAG_ALLOW_ZERO_POLLTIMEOUT:
*
* Allows the zero bwPollTimeout from GetStatus in dfuDNLOAD-SYNC state.
*/
#define FU_DFU_DEVICE_FLAG_ALLOW_ZERO_POLLTIMEOUT (1 << 18)
#define FU_DFU_DEVICE_FLAG_ALLOW_ZERO_POLLTIMEOUT (1ull << (8 + 18))
const gchar *
fu_dfu_state_to_string(FuDfuState state);

View File

@ -50,7 +50,6 @@ static void
fu_dfu_device_finalize(GObject *object);
typedef struct {
FuDfuDeviceAttrs attributes;
FuDfuState state;
FuDfuStatus status;
GPtrArray *targets;
@ -101,9 +100,10 @@ fu_dfu_device_to_string(FuDevice *device, guint idt, GString *str)
fu_common_string_append_kx(str, idt, "IfaceNumber", priv->iface_number);
fu_common_string_append_kx(str, idt, "DnloadTimeout", priv->dnload_timeout);
fu_common_string_append_kx(str, idt, "TimeoutMs", priv->timeout_ms);
for (guint i = 0; i < priv->targets->len; i++) {
FuDfuTarget *target = g_ptr_array_index(priv->targets, i);
fu_dfu_target_to_string(target, idt + 1, str);
fu_device_add_string(FU_DEVICE(target), idt + 1, str);
}
}
@ -221,11 +221,11 @@ fu_dfu_device_parse_iface_data(FuDfuDevice *self, GBytes *iface_data, GError **e
/* ST-specific */
if (priv->version == FU_DFU_FIRMARE_VERSION_DFUSE &&
desc.bmAttributes & FU_DFU_DEVICE_ATTR_CAN_ACCELERATE)
desc.bmAttributes & FU_DFU_DEVICE_FLAG_CAN_ACCELERATE)
priv->transfer_size = 0x1000;
/* get attributes about the DFU operation */
priv->attributes = desc.bmAttributes;
fu_device_add_private_flag(FU_DEVICE(self), desc.bmAttributes);
return TRUE;
}
@ -293,8 +293,9 @@ fu_dfu_device_add_targets(FuDfuDevice *self, GError **error)
continue;
}
} else {
priv->attributes |=
FU_DFU_DEVICE_ATTR_CAN_DOWNLOAD | FU_DFU_DEVICE_ATTR_CAN_UPLOAD;
fu_device_add_private_flag(FU_DEVICE(self),
FU_DFU_DEVICE_FLAG_CAN_DOWNLOAD |
FU_DFU_DEVICE_FLAG_CAN_UPLOAD);
}
/* fix up the version */
@ -349,7 +350,7 @@ fu_dfu_device_add_targets(FuDfuDevice *self, GError **error)
target = fu_dfu_target_new();
break;
}
fu_dfu_target_set_device(target, self);
fu_device_set_proxy(FU_DEVICE(target), FU_DEVICE(self));
fu_dfu_target_set_alt_idx(target, g_usb_interface_get_index(iface));
fu_dfu_target_set_alt_setting(target, g_usb_interface_get_alternate(iface));
@ -376,7 +377,9 @@ fu_dfu_device_add_targets(FuDfuDevice *self, GError **error)
priv->runtime_vid = g_usb_device_get_vid(usb_device);
priv->runtime_pid = g_usb_device_get_pid(usb_device);
priv->runtime_release = g_usb_device_get_release(usb_device);
priv->attributes = FU_DFU_DEVICE_ATTR_CAN_DOWNLOAD | FU_DFU_DEVICE_ATTR_CAN_UPLOAD;
fu_device_add_private_flag(FU_DEVICE(self),
FU_DFU_DEVICE_FLAG_CAN_DOWNLOAD |
FU_DFU_DEVICE_FLAG_CAN_UPLOAD);
return TRUE;
}
@ -391,43 +394,11 @@ fu_dfu_device_add_targets(FuDfuDevice *self, GError **error)
/* the device upload is broken */
if (fu_device_has_private_flag(FU_DEVICE(self), FU_DFU_DEVICE_FLAG_IGNORE_UPLOAD))
priv->attributes &= ~FU_DFU_DEVICE_ATTR_CAN_UPLOAD;
fu_device_remove_private_flag(FU_DEVICE(self), FU_DFU_DEVICE_FLAG_CAN_UPLOAD);
return TRUE;
}
/**
* fu_dfu_device_can_upload:
* @self: a #FuDfuDevice
*
* Gets if the device can upload.
*
* Returns: %TRUE if the device can upload from device to host
**/
gboolean
fu_dfu_device_can_upload(FuDfuDevice *self)
{
FuDfuDevicePrivate *priv = GET_PRIVATE(self);
g_return_val_if_fail(FU_IS_DFU_DEVICE(self), FALSE);
return (priv->attributes & FU_DFU_DEVICE_ATTR_CAN_UPLOAD) > 0;
}
/**
* fu_dfu_device_can_download:
* @self: a #FuDfuDevice
*
* Gets if the device can download.
*
* Returns: %TRUE if the device can download from host to device
**/
gboolean
fu_dfu_device_can_download(FuDfuDevice *self)
{
FuDfuDevicePrivate *priv = GET_PRIVATE(self);
g_return_val_if_fail(FU_IS_DFU_DEVICE(self), FALSE);
return (priv->attributes & FU_DFU_DEVICE_ATTR_CAN_DOWNLOAD) > 0;
}
/**
* fu_dfu_device_set_timeout:
* @self: a #FuDfuDevice
@ -491,38 +462,6 @@ fu_dfu_device_get_status(FuDfuDevice *self)
return priv->status;
}
/**
* fu_dfu_device_has_attribute: (skip)
* @self: a #FuDfuDevice
* @attribute: a device attribute, e.g. %FU_DFU_DEVICE_ATTR_CAN_DOWNLOAD
*
* Returns if an attribute set for the device.
*
* Returns: %TRUE if the attribute is set
**/
gboolean
fu_dfu_device_has_attribute(FuDfuDevice *self, FuDfuDeviceAttrs attribute)
{
FuDfuDevicePrivate *priv = GET_PRIVATE(self);
g_return_val_if_fail(FU_IS_DFU_DEVICE(self), FALSE);
return (priv->attributes & attribute) > 0;
}
/**
* fu_dfu_device_remove_attribute: (skip)
* @self: a #FuDfuDevice
* @attribute: a device attribute, e.g. %FU_DFU_DEVICE_ATTR_CAN_DOWNLOAD
*
* Removes an attribute from the device.
**/
void
fu_dfu_device_remove_attribute(FuDfuDevice *self, FuDfuDeviceAttrs attribute)
{
FuDfuDevicePrivate *priv = GET_PRIVATE(self);
g_return_if_fail(FU_IS_DFU_DEVICE(self));
priv->attributes &= ~attribute;
}
/**
* fu_dfu_device_new:
*
@ -538,22 +477,6 @@ fu_dfu_device_new(FuContext *ctx, GUsbDevice *usb_device)
return self;
}
/**
* fu_dfu_device_get_targets:
* @self: a #FuDfuDevice
*
* Gets all the targets for this device.
*
* Returns: (transfer none) (element-type FuDfuTarget): #FuDfuTarget, or %NULL
**/
GPtrArray *
fu_dfu_device_get_targets(FuDfuDevice *self)
{
FuDfuDevicePrivate *priv = GET_PRIVATE(self);
g_return_val_if_fail(FU_IS_DFU_DEVICE(self), NULL);
return priv->targets;
}
/**
* fu_dfu_device_get_target_by_alt_setting:
* @self: a #FuDfuDevice
@ -609,7 +532,7 @@ fu_dfu_device_get_target_by_alt_name(FuDfuDevice *self, const gchar *alt_name, G
/* find by ID */
for (guint i = 0; i < priv->targets->len; i++) {
FuDfuTarget *target = g_ptr_array_index(priv->targets, i);
if (g_strcmp0(fu_dfu_target_get_alt_name(target, NULL), alt_name) == 0)
if (g_strcmp0(fu_device_get_logical_id(FU_DEVICE(target)), alt_name) == 0)
return g_object_ref(target);
}
@ -622,22 +545,6 @@ fu_dfu_device_get_target_by_alt_name(FuDfuDevice *self, const gchar *alt_name, G
return NULL;
}
/**
* fu_dfu_device_get_platform_id:
* @self: a #FuDfuDevice
*
* Gets the platform ID which normally corresponds to the port in some way.
*
* Returns: string or %NULL
**/
const gchar *
fu_dfu_device_get_platform_id(FuDfuDevice *self)
{
GUsbDevice *usb_device = fu_usb_device_get_dev(FU_USB_DEVICE(self));
g_return_val_if_fail(FU_IS_DFU_DEVICE(self), NULL);
return g_usb_device_get_platform_id(usb_device);
}
/**
* fu_dfu_device_get_runtime_vid:
* @self: a #FuDfuDevice
@ -819,16 +726,6 @@ fu_dfu_device_refresh(FuDfuDevice *self, GError **error)
g_return_val_if_fail(FU_IS_DFU_DEVICE(self), FALSE);
g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
/* no backing USB device */
if (usb_device == NULL) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"failed to refresh: no GUsbDevice for %s",
fu_dfu_device_get_platform_id(self));
return FALSE;
}
/* the device has no DFU runtime, so cheat */
if (priv->state == FU_DFU_STATE_APP_IDLE &&
fu_device_has_private_flag(FU_DEVICE(self), FU_DFU_DEVICE_FLAG_NO_DFU_RUNTIME))
@ -843,7 +740,7 @@ fu_dfu_device_refresh(FuDfuDevice *self, GError **error)
* host by clearing bmAttributes bit bitManifestationTolerant.
* so we assume the operation was successful */
if (priv->state == FU_DFU_STATE_DFU_MANIFEST &&
!(priv->attributes & FU_DFU_DEVICE_ATTR_MANIFEST_TOL))
!fu_device_has_private_flag(FU_DEVICE(self), FU_DFU_DEVICE_FLAG_MANIFEST_TOL))
return TRUE;
if (!g_usb_device_control_transfer(usb_device,
@ -957,7 +854,6 @@ fu_dfu_device_detach(FuDevice *device, FuProgress *progress, GError **error)
{
FuDfuDevice *self = FU_DFU_DEVICE(device);
FuDfuDevicePrivate *priv = GET_PRIVATE(self);
GUsbDevice *usb_device = fu_usb_device_get_dev(FU_USB_DEVICE(device));
g_return_val_if_fail(FU_IS_DFU_DEVICE(self), FALSE);
g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
@ -968,16 +864,6 @@ fu_dfu_device_detach(FuDevice *device, FuProgress *progress, GError **error)
if (fu_device_has_flag(device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER))
return TRUE;
/* no backing USB device */
if (usb_device == NULL) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"failed to detach: no GUsbDevice for %s",
fu_dfu_device_get_platform_id(self));
return FALSE;
}
/* the device has no DFU runtime, so cheat */
if (priv->state == FU_DFU_STATE_APP_IDLE &&
fu_device_has_private_flag(FU_DEVICE(self), FU_DFU_DEVICE_FLAG_NO_DFU_RUNTIME))
@ -992,7 +878,7 @@ fu_dfu_device_detach(FuDevice *device, FuProgress *progress, GError **error)
return FALSE;
/* do a host reset */
if ((priv->attributes & FU_DFU_DEVICE_ATTR_WILL_DETACH) == 0) {
if (!fu_device_has_private_flag(FU_DEVICE(self), FU_DFU_DEVICE_FLAG_WILL_DETACH)) {
g_debug("doing device reset as host will not self-reset");
if (!fu_dfu_device_reset(self, progress, error))
return FALSE;
@ -1021,18 +907,9 @@ fu_dfu_device_abort(FuDfuDevice *self, GError **error)
g_autoptr(GError) error_local = NULL;
g_return_val_if_fail(FU_IS_DFU_DEVICE(self), FALSE);
g_return_val_if_fail(G_USB_IS_DEVICE(usb_device), FALSE);
g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
/* no backing USB device */
if (usb_device == NULL) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"failed to abort: no GUsbDevice for %s",
fu_dfu_device_get_platform_id(self));
return FALSE;
}
/* the device has no DFU runtime, so cheat */
if (priv->state == FU_DFU_STATE_APP_IDLE &&
fu_device_has_private_flag(FU_DEVICE(self), FU_DFU_DEVICE_FLAG_NO_DFU_RUNTIME)) {
@ -1086,22 +963,11 @@ gboolean
fu_dfu_device_clear_status(FuDfuDevice *self, GError **error)
{
FuDfuDevicePrivate *priv = GET_PRIVATE(self);
GUsbDevice *usb_device = fu_usb_device_get_dev(FU_USB_DEVICE(self));
g_autoptr(GError) error_local = NULL;
g_return_val_if_fail(FU_IS_DFU_DEVICE(self), FALSE);
g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
/* no backing USB device */
if (usb_device == NULL) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"failed to clear status: no GUsbDevice for %s",
fu_dfu_device_get_platform_id(self));
return FALSE;
}
/* the device has no DFU runtime, so cheat */
if (priv->state == FU_DFU_STATE_APP_IDLE &&
fu_device_has_private_flag(FU_DEVICE(self), FU_DFU_DEVICE_FLAG_NO_DFU_RUNTIME)) {
@ -1116,7 +982,7 @@ fu_dfu_device_clear_status(FuDfuDevice *self, GError **error)
if (!fu_dfu_device_ensure_interface(self, error))
return FALSE;
if (!g_usb_device_control_transfer(usb_device,
if (!g_usb_device_control_transfer(fu_usb_device_get_dev(FU_USB_DEVICE(self)),
G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
G_USB_DEVICE_REQUEST_TYPE_CLASS,
G_USB_DEVICE_RECIPIENT_INTERFACE,
@ -1169,7 +1035,6 @@ fu_dfu_device_open(FuDevice *device, GError **error)
{
FuDfuDevice *self = FU_DFU_DEVICE(device);
FuDfuDevicePrivate *priv = GET_PRIVATE(self);
GPtrArray *targets = fu_dfu_device_get_targets(self);
g_return_val_if_fail(FU_IS_DFU_DEVICE(device), FALSE);
g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
@ -1230,8 +1095,8 @@ fu_dfu_device_open(FuDevice *device, GError **error)
}
/* set up target ready for use */
for (guint j = 0; j < targets->len; j++) {
FuDfuTarget *target = g_ptr_array_index(targets, j);
for (guint j = 0; j < priv->targets->len; j++) {
FuDfuTarget *target = g_ptr_array_index(priv->targets, j);
if (!fu_dfu_target_setup(target, error))
return FALSE;
}
@ -1296,7 +1161,7 @@ fu_dfu_device_probe(FuDevice *device, GError **error)
}
/* check capabilities */
if (!fu_dfu_device_can_download(self)) {
if (!fu_device_has_private_flag(device, FU_DFU_DEVICE_FLAG_CAN_DOWNLOAD)) {
g_debug("%04x:%04x is missing download capability",
g_usb_device_get_vid(usb_device),
g_usb_device_get_pid(usb_device));
@ -1316,24 +1181,13 @@ fu_dfu_device_probe(FuDevice *device, GError **error)
gboolean
fu_dfu_device_reset(FuDfuDevice *self, FuProgress *progress, GError **error)
{
GUsbDevice *usb_device = fu_usb_device_get_dev(FU_USB_DEVICE(self));
g_autoptr(GError) error_local = NULL;
g_autoptr(GTimer) timer = g_timer_new();
g_return_val_if_fail(FU_IS_DFU_DEVICE(self), FALSE);
g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
/* no backing USB device */
if (usb_device == NULL) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"failed to reset: no GUsbDevice for %s",
fu_dfu_device_get_platform_id(self));
return FALSE;
}
if (!g_usb_device_reset(usb_device, &error_local)) {
if (!g_usb_device_reset(fu_usb_device_get_dev(FU_USB_DEVICE(self)), &error_local)) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
@ -1392,7 +1246,7 @@ fu_dfu_device_attach(FuDevice *device, FuProgress *progress, GError **error)
/* normal DFU mode just needs a bus reset */
if (fu_device_has_private_flag(FU_DEVICE(self), FU_DFU_DEVICE_FLAG_NO_BUS_RESET_ATTACH) &&
fu_dfu_device_has_attribute(self, FU_DFU_DEVICE_ATTR_WILL_DETACH)) {
fu_device_has_private_flag(FU_DEVICE(self), FU_DFU_DEVICE_FLAG_WILL_DETACH)) {
g_debug("Bus reset is not required. Device will reboot to normal");
} else if (!fu_dfu_target_attach(target, progress, error)) {
g_prefix_error(error, "failed to attach target: ");
@ -1426,20 +1280,9 @@ fu_dfu_device_upload(FuDfuDevice *self,
GError **error)
{
FuDfuDevicePrivate *priv = GET_PRIVATE(self);
GUsbDevice *usb_device = fu_usb_device_get_dev(FU_USB_DEVICE(self));
gboolean use_dfuse = FALSE;
g_autoptr(FuFirmware) firmware = NULL;
/* no backing USB device */
if (usb_device == NULL) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"failed to upload: no GUsbDevice for %s",
fu_dfu_device_get_platform_id(self));
return NULL;
}
/* ensure interface is claimed */
if (!fu_dfu_device_ensure_interface(self, error))
return NULL;
@ -1447,7 +1290,7 @@ fu_dfu_device_upload(FuDfuDevice *self,
/* choose the most appropriate type */
for (guint i = 0; i < priv->targets->len; i++) {
FuDfuTarget *target = g_ptr_array_index(priv->targets, i);
if (fu_dfu_target_get_alt_name(target, NULL) != NULL || i > 0) {
if (fu_device_get_logical_id(FU_DEVICE(target)) != NULL || i > 0) {
use_dfuse = TRUE;
break;
}
@ -1467,15 +1310,13 @@ fu_dfu_device_upload(FuDfuDevice *self,
fu_progress_set_steps(progress, priv->targets->len);
for (guint i = 0; i < priv->targets->len; i++) {
FuDfuTarget *target;
const gchar *alt_name;
/* upload to target and proxy signals */
target = g_ptr_array_index(priv->targets, i);
/* ignore some target types */
alt_name = fu_dfu_target_get_alt_name_for_display(target, NULL);
if (g_strcmp0(alt_name, "Option Bytes") == 0) {
g_debug("ignoring target %s", alt_name);
if (g_strcmp0(fu_device_get_name(FU_DEVICE(target)), "Option Bytes") == 0) {
g_debug("ignoring target %s", fu_device_get_name(target));
continue;
}
if (!fu_dfu_target_upload(target,
@ -1532,22 +1373,11 @@ fu_dfu_device_download(FuDfuDevice *self,
GError **error)
{
FuDfuDevicePrivate *priv = GET_PRIVATE(self);
GUsbDevice *usb_device = fu_usb_device_get_dev(FU_USB_DEVICE(self));
gboolean ret;
g_autoptr(GPtrArray) images = NULL;
guint16 firmware_pid = 0xffff;
guint16 firmware_vid = 0xffff;
/* no backing USB device */
if (usb_device == NULL) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"failed to download: no GUsbDevice for %s",
fu_dfu_device_get_platform_id(self));
return FALSE;
}
/* ensure interface is claimed */
if (!fu_dfu_device_ensure_interface(self, error))
return FALSE;
@ -1632,27 +1462,17 @@ fu_dfu_device_download(FuDfuDevice *self,
for (guint i = 0; i < images->len; i++) {
FuFirmware *image = g_ptr_array_index(images, i);
FuDfuTargetTransferFlags flags_local = DFU_TARGET_TRANSFER_FLAG_NONE;
const gchar *alt_name;
guint8 alt;
g_autoptr(FuDfuTarget) target_tmp = NULL;
g_autoptr(GError) error_local = NULL;
alt = fu_firmware_get_idx(image);
target_tmp = fu_dfu_device_get_target_by_alt_setting(self, alt, error);
if (target_tmp == NULL)
return FALSE;
/* we don't actually need to print this */
alt_name = fu_dfu_target_get_alt_name(target_tmp, &error_local);
if (alt_name == NULL) {
if (g_error_matches(error_local, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND)) {
alt_name = "unknown";
} else {
g_propagate_error(error, g_steal_pointer(&error_local));
if (!fu_dfu_target_setup(target_tmp, error))
return FALSE;
}
}
g_debug("downloading to target: %s", alt_name);
g_debug("downloading to target: %s",
fu_device_get_logical_id(FU_DEVICE(target_tmp)));
/* download onto target */
if (flags & DFU_TARGET_TRANSFER_FLAG_VERIFY)
@ -1815,38 +1635,6 @@ fu_dfu_device_set_quirk_kv(FuDevice *device, const gchar *key, const gchar *valu
return FALSE;
}
/**
* fu_dfu_device_get_attributes_as_string: (skip)
* @self: a #FuDfuDevice
*
* Gets a string describing the attributes for a device.
*
* Returns: a string, possibly empty
**/
gchar *
fu_dfu_device_get_attributes_as_string(FuDfuDevice *self)
{
FuDfuDevicePrivate *priv = GET_PRIVATE(self);
GString *str;
/* just append to a string */
str = g_string_new("");
if (priv->attributes & FU_DFU_DEVICE_ATTR_CAN_DOWNLOAD)
g_string_append_printf(str, "can-download|");
if (priv->attributes & FU_DFU_DEVICE_ATTR_CAN_UPLOAD)
g_string_append_printf(str, "can-upload|");
if (priv->attributes & FU_DFU_DEVICE_ATTR_MANIFEST_TOL)
g_string_append_printf(str, "manifest-tol|");
if (priv->attributes & FU_DFU_DEVICE_ATTR_WILL_DETACH)
g_string_append_printf(str, "will-detach|");
if (priv->attributes & FU_DFU_DEVICE_ATTR_CAN_ACCELERATE)
g_string_append_printf(str, "can-accelerate|");
/* remove trailing pipe */
g_string_truncate(str, str->len - 1);
return g_string_free(str, FALSE);
}
static void
fu_dfu_device_set_progress(FuDevice *self, FuProgress *progress)
{
@ -1907,6 +1695,21 @@ fu_dfu_device_init(FuDfuDevice *self)
fu_device_add_internal_flag(FU_DEVICE(self), FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID);
fu_device_set_remove_delay(FU_DEVICE(self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE);
fu_device_register_private_flag(FU_DEVICE(self),
FU_DFU_DEVICE_FLAG_CAN_DOWNLOAD,
"can-download");
fu_device_register_private_flag(FU_DEVICE(self),
FU_DFU_DEVICE_FLAG_CAN_UPLOAD,
"can-upload");
fu_device_register_private_flag(FU_DEVICE(self),
FU_DFU_DEVICE_FLAG_MANIFEST_TOL,
"manifest-tol");
fu_device_register_private_flag(FU_DEVICE(self),
FU_DFU_DEVICE_FLAG_WILL_DETACH,
"will-detach");
fu_device_register_private_flag(FU_DEVICE(self),
FU_DFU_DEVICE_FLAG_CAN_ACCELERATE,
"can-accelerate");
fu_device_register_private_flag(FU_DEVICE(self),
FU_DFU_DEVICE_FLAG_ATTACH_EXTRA_RESET,
"attach-extra-reset");

View File

@ -18,38 +18,12 @@
#define FU_TYPE_DFU_DEVICE (fu_dfu_device_get_type())
G_DECLARE_DERIVABLE_TYPE(FuDfuDevice, fu_dfu_device, FU, DFU_DEVICE, FuUsbDevice)
/**
* FuDfuDeviceAttrs:
* @FU_DFU_DEVICE_ATTR_NONE: No attributes set
* @FU_DFU_DEVICE_ATTR_CAN_DOWNLOAD: Can download from host->device
* @FU_DFU_DEVICE_ATTR_CAN_UPLOAD: Can upload from device->host
* @FU_DFU_DEVICE_ATTR_MANIFEST_TOL: Can answer GetStatus in manifest
* @FU_DFU_DEVICE_ATTR_WILL_DETACH: Will self-detach
* @FU_DFU_DEVICE_ATTR_CAN_ACCELERATE: Use a larger transfer size for speed
*
* The device DFU attributes.
**/
typedef enum {
FU_DFU_DEVICE_ATTR_NONE = 0,
FU_DFU_DEVICE_ATTR_CAN_DOWNLOAD = (1 << 0),
FU_DFU_DEVICE_ATTR_CAN_UPLOAD = (1 << 1),
FU_DFU_DEVICE_ATTR_MANIFEST_TOL = (1 << 2),
FU_DFU_DEVICE_ATTR_WILL_DETACH = (1 << 3),
FU_DFU_DEVICE_ATTR_CAN_ACCELERATE = (1 << 7),
/*< private >*/
FU_DFU_DEVICE_ATTR_LAST
} FuDfuDeviceAttrs;
struct _FuDfuDeviceClass {
FuUsbDeviceClass parent_class;
};
FuDfuDevice *
fu_dfu_device_new(FuContext *ctx, GUsbDevice *usb_device);
const gchar *
fu_dfu_device_get_platform_id(FuDfuDevice *self);
GPtrArray *
fu_dfu_device_get_targets(FuDfuDevice *self);
FuDfuTarget *
fu_dfu_device_get_target_by_alt_setting(FuDfuDevice *self, guint8 alt_setting, GError **error);
FuDfuTarget *
@ -92,15 +66,6 @@ guint16
fu_dfu_device_get_version(FuDfuDevice *self);
guint
fu_dfu_device_get_timeout(FuDfuDevice *self);
gboolean
fu_dfu_device_can_upload(FuDfuDevice *self);
gboolean
fu_dfu_device_can_download(FuDfuDevice *self);
gboolean
fu_dfu_device_has_attribute(FuDfuDevice *self, FuDfuDeviceAttrs attribute);
void
fu_dfu_device_remove_attribute(FuDfuDevice *self, FuDfuDeviceAttrs attribute);
void
fu_dfu_device_set_transfer_size(FuDfuDevice *self, guint16 transfer_size);
@ -110,7 +75,5 @@ void
fu_dfu_device_error_fixup(FuDfuDevice *self, GError **error);
guint
fu_dfu_device_get_download_timeout(FuDfuDevice *self);
gchar *
fu_dfu_device_get_attributes_as_string(FuDfuDevice *self);
gboolean
fu_dfu_device_ensure_interface(FuDfuDevice *self, GError **error);

View File

@ -72,7 +72,7 @@ fu_dfu_target_dfuse_func(void)
/* NULL */
target = g_object_new(FU_TYPE_DFU_TARGET, NULL);
fu_dfu_target_set_device(target, device);
fu_device_set_proxy(FU_DEVICE(target), FU_DEVICE(device));
ret = fu_dfu_target_parse_sectors(target, NULL, &error);
g_assert_no_error(error);
g_assert_true(ret);

View File

@ -88,7 +88,7 @@ fu_dfu_target_avr_mass_erase(FuDfuTarget *target, FuProgress *progress, GError *
guint8 buf[3];
/* this takes a long time on some devices */
fu_dfu_device_set_timeout(fu_dfu_target_get_device(target), 5000);
fu_dfu_device_set_timeout(FU_DFU_DEVICE(fu_device_get_proxy(FU_DEVICE(target))), 5000);
/* format buffer */
buf[0] = DFU_AVR32_GROUP_EXEC;
@ -178,7 +178,7 @@ fu_dfu_target_avr_select_memory_unit(FuDfuTarget *target,
guint8 buf[4];
/* check legacy protocol quirk */
if (fu_device_has_private_flag(FU_DEVICE(fu_dfu_target_get_device(target)),
if (fu_device_has_private_flag(fu_device_get_proxy(FU_DEVICE(target)),
FU_DFU_DEVICE_FLAG_LEGACY_PROTOCOL)) {
g_debug("ignoring select memory unit as legacy protocol");
return TRUE;
@ -504,7 +504,7 @@ fu_dfu_target_avr_setup(FuDfuTarget *target, GError **error)
return TRUE;
/* different methods for AVR vs. AVR32 */
if (fu_device_has_private_flag(FU_DEVICE(fu_dfu_target_get_device(target)),
if (fu_device_has_private_flag(fu_device_get_proxy(FU_DEVICE(target)),
FU_DFU_DEVICE_FLAG_LEGACY_PROTOCOL)) {
chunk_sig = fu_dfu_target_avr_get_chip_signature(target, progress, error);
if (chunk_sig == NULL)
@ -549,16 +549,16 @@ fu_dfu_target_avr_setup(FuDfuTarget *target, GError **error)
}
/* set the alt-name using the chip ID via a quirk */
device = fu_dfu_target_get_device(target);
device = FU_DFU_DEVICE(fu_device_get_proxy(FU_DEVICE(target)));
fu_device_add_instance_str(FU_DEVICE(device), "CID", chip_id_guid);
if (!fu_device_build_instance_id(FU_DEVICE(device), error, "DFU_AVR", "CID", NULL))
return FALSE;
chip_id = fu_dfu_device_get_chip_id(device);
if (chip_id == NULL) {
fu_dfu_device_remove_attribute(fu_dfu_target_get_device(target),
FU_DFU_DEVICE_ATTR_CAN_DOWNLOAD);
fu_dfu_device_remove_attribute(fu_dfu_target_get_device(target),
FU_DFU_DEVICE_ATTR_CAN_UPLOAD);
fu_device_remove_private_flag(fu_device_get_proxy(FU_DEVICE(target)),
FU_DFU_DEVICE_FLAG_CAN_DOWNLOAD);
fu_device_remove_private_flag(fu_device_get_proxy(FU_DEVICE(target)),
FU_DFU_DEVICE_FLAG_CAN_UPLOAD);
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
@ -567,7 +567,7 @@ fu_dfu_target_avr_setup(FuDfuTarget *target, GError **error)
chip_id_guid);
return FALSE;
}
fu_dfu_target_set_alt_name(target, chip_id);
fu_device_set_logical_id(FU_DEVICE(target), chip_id);
return TRUE;
}
@ -608,7 +608,7 @@ fu_dfu_target_avr_download_element_chunks(FuDfuTarget *target,
/* select page if required */
if (fu_chunk_get_page(chk) != *page_last) {
g_autoptr(FuProgress) progress_tmp = fu_progress_new(G_STRLOC);
if (fu_device_has_private_flag(FU_DEVICE(fu_dfu_target_get_device(target)),
if (fu_device_has_private_flag(fu_device_get_proxy(FU_DEVICE(target)),
FU_DFU_DEVICE_FLAG_LEGACY_PROTOCOL)) {
if (!fu_dfu_target_avr_select_memory_page(target,
fu_chunk_get_page(chk),
@ -716,7 +716,7 @@ fu_dfu_target_avr_download_element(FuDfuTarget *target,
}
/* the original AVR protocol uses a half-size control block */
if (fu_device_has_private_flag(FU_DEVICE(fu_dfu_target_get_device(target)),
if (fu_device_has_private_flag(fu_device_get_proxy(FU_DEVICE(target)),
FU_DFU_DEVICE_FLAG_LEGACY_PROTOCOL)) {
header_sz = ATMEL_AVR_CONTROL_BLOCK_SIZE;
}
@ -809,7 +809,7 @@ fu_dfu_target_avr_upload_element_chunks(FuDfuTarget *target,
/* select page if required */
if (fu_chunk_get_page(chk) != page_last) {
g_autoptr(FuProgress) progress_tmp = fu_progress_new(G_STRLOC);
if (fu_device_has_private_flag(FU_DEVICE(fu_dfu_target_get_device(target)),
if (fu_device_has_private_flag(fu_device_get_proxy(FU_DEVICE(target)),
FU_DFU_DEVICE_FLAG_LEGACY_PROTOCOL)) {
if (!fu_dfu_target_avr_select_memory_page(target,
fu_chunk_get_page(chk),

View File

@ -37,10 +37,6 @@ fu_dfu_target_set_alt_setting(FuDfuTarget *self, guint8 alt_setting);
/* for the other implementations */
void
fu_dfu_target_set_alt_name(FuDfuTarget *self, const gchar *alt_name);
void
fu_dfu_target_set_device(FuDfuTarget *self, FuDfuDevice *device);
FuDfuDevice *
fu_dfu_target_get_device(FuDfuTarget *self);
gboolean
fu_dfu_target_check_status(FuDfuTarget *self, GError **error);
FuDfuSector *

View File

@ -94,7 +94,7 @@ fu_dfu_target_stm_upload_element(FuDfuTarget *target,
FuProgress *progress,
GError **error)
{
FuDfuDevice *device = fu_dfu_target_get_device(target);
FuDfuDevice *device = FU_DFU_DEVICE(fu_device_get_proxy(FU_DEVICE(target)));
FuDfuSector *sector;
FuChunk *chk = NULL;
GBytes *chunk_tmp;
@ -413,7 +413,7 @@ fu_dfu_target_stm_download_element(FuDfuTarget *target,
FuDfuTargetTransferFlags flags,
GError **error)
{
FuDfuDevice *device = fu_dfu_target_get_device(target);
FuDfuDevice *device = FU_DFU_DEVICE(fu_device_get_proxy(FU_DEVICE(target)));
g_autoptr(GBytes) bytes = NULL;
g_autoptr(GPtrArray) chunks = NULL;
g_autoptr(GPtrArray) sectors_array = g_ptr_array_new();

View File

@ -30,29 +30,16 @@
#define DFU_TARGET_MANIFEST_MAX_POLLING_TRIES 200
static void
fu_dfu_target_finalize(GObject *object);
typedef struct {
FuDfuDevice *device; /* not refcounted */
gboolean done_setup;
guint8 alt_setting;
guint8 alt_idx;
gchar *alt_name;
gchar *alt_name_for_display;
GPtrArray *sectors; /* of FuDfuSector */
} FuDfuTargetPrivate;
G_DEFINE_TYPE_WITH_PRIVATE(FuDfuTarget, fu_dfu_target, G_TYPE_OBJECT)
G_DEFINE_TYPE_WITH_PRIVATE(FuDfuTarget, fu_dfu_target, FU_TYPE_DEVICE)
#define GET_PRIVATE(o) (fu_dfu_target_get_instance_private(o))
static void
fu_dfu_target_class_init(FuDfuTargetClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->finalize = fu_dfu_target_finalize;
}
static void
fu_dfu_target_init(FuDfuTarget *self)
{
@ -66,32 +53,18 @@ fu_dfu_target_finalize(GObject *object)
FuDfuTarget *self = FU_DFU_TARGET(object);
FuDfuTargetPrivate *priv = GET_PRIVATE(self);
g_free(priv->alt_name);
g_free(priv->alt_name_for_display);
g_ptr_array_unref(priv->sectors);
/* we no longer care */
if (priv->device != NULL) {
g_object_remove_weak_pointer(G_OBJECT(priv->device), (gpointer *)&priv->device);
}
G_OBJECT_CLASS(fu_dfu_target_parent_class)->finalize(object);
}
void
fu_dfu_target_to_string(FuDfuTarget *self, guint idt, GString *str)
static void
fu_dfu_target_to_string(FuDevice *device, guint idt, GString *str)
{
FuDfuTarget *self = FU_DFU_TARGET(device);
FuDfuTargetPrivate *priv = GET_PRIVATE(self);
fu_common_string_append_kx(str, idt, "AltSetting", priv->alt_setting);
fu_common_string_append_kx(str, idt, "AltIdx", priv->alt_idx);
if (priv->alt_name != NULL)
fu_common_string_append_kv(str, idt, "AltName", priv->alt_name);
if (priv->alt_name_for_display != NULL) {
fu_common_string_append_kv(str,
idt,
"AltNameForDisplay",
priv->alt_name_for_display);
}
for (guint i = 0; i < priv->sectors->len; i++) {
FuDfuSector *sector = g_ptr_array_index(priv->sectors, i);
g_autofree gchar *tmp1 = g_strdup_printf("Idx%02x", i);
@ -164,7 +137,7 @@ fu_dfu_target_parse_sector(FuDfuTarget *self,
}
/* handle weirdness */
if (fu_device_has_private_flag(FU_DEVICE(priv->device),
if (fu_device_has_private_flag(fu_device_get_proxy(FU_DEVICE(self)),
FU_DFU_DEVICE_FLAG_ABSENT_SECTOR_SIZE)) {
if (tmp[1] == '\0') {
tmp[1] = tmp[0];
@ -279,8 +252,7 @@ fu_dfu_target_parse_sectors(FuDfuTarget *self, const gchar *alt_name, GError **e
/* parse zones */
zones = g_strsplit(alt_name, "/", -1);
g_free(priv->alt_name_for_display);
priv->alt_name_for_display = g_strdup(g_strchomp(zones[0] + 1));
fu_device_set_name(FU_DEVICE(self), g_strchomp(zones[0] + 1));
for (guint i = 1; zones[i] != NULL; i += 2) {
guint32 addr;
guint64 addr_tmp;
@ -431,16 +403,16 @@ fu_dfu_target_status_to_error_msg(FuDfuStatus status)
static gboolean
fu_dfu_target_manifest_wait(FuDfuTarget *self, GError **error)
{
FuDfuTargetPrivate *priv = GET_PRIVATE(self);
FuDfuDevice *device = FU_DFU_DEVICE(fu_device_get_proxy(FU_DEVICE(self)));
guint polling_count = 0;
/* get the status */
if (!fu_dfu_device_refresh(priv->device, error))
if (!fu_dfu_device_refresh(device, error))
return FALSE;
/* wait for FU_DFU_STATE_DFU_MANIFEST to not be set */
while (fu_dfu_device_get_state(priv->device) == FU_DFU_STATE_DFU_MANIFEST_SYNC ||
fu_dfu_device_get_state(priv->device) == FU_DFU_STATE_DFU_MANIFEST) {
while (fu_dfu_device_get_state(device) == FU_DFU_STATE_DFU_MANIFEST_SYNC ||
fu_dfu_device_get_state(device) == FU_DFU_STATE_DFU_MANIFEST) {
g_debug("waiting for FU_DFU_STATE_DFU_MANIFEST to clear");
if (polling_count++ > DFU_TARGET_MANIFEST_MAX_POLLING_TRIES) {
@ -451,18 +423,18 @@ fu_dfu_target_manifest_wait(FuDfuTarget *self, GError **error)
return FALSE;
}
g_usleep((fu_dfu_device_get_download_timeout(priv->device) + 1000) * 1000);
if (!fu_dfu_device_refresh(priv->device, error))
g_usleep((fu_dfu_device_get_download_timeout(device) + 1000) * 1000);
if (!fu_dfu_device_refresh(device, error))
return FALSE;
}
/* in an error state */
if (fu_dfu_device_get_state(priv->device) == FU_DFU_STATE_DFU_ERROR) {
if (fu_dfu_device_get_state(device) == FU_DFU_STATE_DFU_ERROR) {
g_set_error_literal(
error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
fu_dfu_target_status_to_error_msg(fu_dfu_device_get_status(priv->device)));
fu_dfu_target_status_to_error_msg(fu_dfu_device_get_status(device)));
return FALSE;
}
@ -472,19 +444,19 @@ fu_dfu_target_manifest_wait(FuDfuTarget *self, GError **error)
gboolean
fu_dfu_target_check_status(FuDfuTarget *self, GError **error)
{
FuDfuTargetPrivate *priv = GET_PRIVATE(self);
FuDfuDevice *device = FU_DFU_DEVICE(fu_device_get_proxy(FU_DEVICE(self)));
FuDfuStatus status;
g_autoptr(GTimer) timer = g_timer_new();
/* get the status */
if (!fu_dfu_device_refresh(priv->device, error))
if (!fu_dfu_device_refresh(device, error))
return FALSE;
/* wait for dfuDNBUSY to not be set */
while (fu_dfu_device_get_state(priv->device) == FU_DFU_STATE_DFU_DNBUSY) {
while (fu_dfu_device_get_state(device) == FU_DFU_STATE_DFU_DNBUSY) {
g_debug("waiting for FU_DFU_STATE_DFU_DNBUSY to clear");
g_usleep(fu_dfu_device_get_download_timeout(priv->device) * 1000);
if (!fu_dfu_device_refresh(priv->device, error))
g_usleep(fu_dfu_device_get_download_timeout(device) * 1000);
if (!fu_dfu_device_refresh(device, error))
return FALSE;
/* this is a really long time to save fwupd in case
* the device has got wedged */
@ -498,12 +470,12 @@ fu_dfu_target_check_status(FuDfuTarget *self, GError **error)
}
/* not in an error state */
if (fu_dfu_device_get_state(priv->device) != FU_DFU_STATE_DFU_ERROR)
if (fu_dfu_device_get_state(device) != FU_DFU_STATE_DFU_ERROR)
return TRUE;
/* STM32-specific long errors */
status = fu_dfu_device_get_status(priv->device);
if (fu_dfu_device_get_version(priv->device) == FU_DFU_FIRMARE_VERSION_DFUSE) {
status = fu_dfu_device_get_status(device);
if (fu_dfu_device_get_version(device) == FU_DFU_FIRMARE_VERSION_DFUSE) {
if (status == FU_DFU_STATUS_ERR_VENDOR) {
g_set_error(error,
FWUPD_ERROR,
@ -540,21 +512,22 @@ fu_dfu_target_check_status(FuDfuTarget *self, GError **error)
static gboolean
fu_dfu_target_use_alt_setting(FuDfuTarget *self, GError **error)
{
FuDfuDevice *device = FU_DFU_DEVICE(fu_device_get_proxy(FU_DEVICE(self)));
FuDfuTargetPrivate *priv = GET_PRIVATE(self);
GUsbDevice *usb_device = fu_usb_device_get_dev(FU_USB_DEVICE(priv->device));
GUsbDevice *usb_device = fu_usb_device_get_dev(FU_USB_DEVICE(device));
g_autoptr(GError) error_local = NULL;
g_return_val_if_fail(FU_IS_DFU_TARGET(self), FALSE);
g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
/* ensure interface is claimed */
if (!fu_dfu_device_ensure_interface(priv->device, error))
if (!fu_dfu_device_ensure_interface(device, error))
return FALSE;
/* use the correct setting */
if (fu_device_has_flag(FU_DEVICE(priv->device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) {
if (fu_device_has_flag(FU_DEVICE(device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) {
if (!g_usb_device_set_interface_alt(usb_device,
(gint)fu_dfu_device_get_interface(priv->device),
(gint)fu_dfu_device_get_interface(device),
(gint)priv->alt_setting,
&error_local)) {
g_set_error(error,
@ -562,7 +535,7 @@ fu_dfu_target_use_alt_setting(FuDfuTarget *self, GError **error)
FWUPD_ERROR_NOT_SUPPORTED,
"cannot set alternate setting 0x%02x on interface %i: %s",
priv->alt_setting,
fu_dfu_device_get_interface(priv->device),
fu_dfu_device_get_interface(device),
error_local->message);
return FALSE;
}
@ -571,29 +544,6 @@ fu_dfu_target_use_alt_setting(FuDfuTarget *self, GError **error)
return TRUE;
}
void
fu_dfu_target_set_alt_name(FuDfuTarget *self, const gchar *alt_name)
{
FuDfuTargetPrivate *priv = GET_PRIVATE(self);
/* not changed */
if (g_strcmp0(priv->alt_name, alt_name) == 0)
return;
g_free(priv->alt_name);
priv->alt_name = g_strdup(alt_name);
}
void
fu_dfu_target_set_device(FuDfuTarget *self, FuDfuDevice *device)
{
FuDfuTargetPrivate *priv = GET_PRIVATE(self);
g_set_object(&priv->device, device);
/* if we try to ref the target and destroy the device */
g_object_add_weak_pointer(G_OBJECT(priv->device), (gpointer *)&priv->device);
}
/**
* fu_dfu_target_setup:
* @self: a #FuDfuTarget
@ -608,7 +558,7 @@ fu_dfu_target_setup(FuDfuTarget *self, GError **error)
{
FuDfuTargetClass *klass = FU_DFU_TARGET_GET_CLASS(self);
FuDfuTargetPrivate *priv = GET_PRIVATE(self);
FuDevice *device = FU_DEVICE(priv->device);
FuDevice *device = fu_device_get_proxy(FU_DEVICE(self));
g_return_val_if_fail(FU_IS_DFU_TARGET(self), FALSE);
g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
@ -625,7 +575,7 @@ fu_dfu_target_setup(FuDfuTarget *self, GError **error)
/* GD32VF103 devices features and peripheral list */
if (priv->alt_setting == 0x0 &&
fu_device_has_private_flag(FU_DEVICE(priv->device), FU_DFU_DEVICE_FLAG_GD32)) {
fu_device_has_private_flag(device, FU_DFU_DEVICE_FLAG_GD32)) {
/* RB R8 R6 R4 VB V8
* Flash (KB) 128 64 32 16 128 64
* TB T8 T6 T4 CB C8 C6 C4
@ -641,17 +591,23 @@ fu_dfu_target_setup(FuDfuTarget *self, GError **error)
return FALSE;
}
if (serial[2] == '2') {
fu_dfu_target_set_alt_name(self, "@Internal Flash /0x8000000/8*1Kg");
fu_device_set_logical_id(FU_DEVICE(self),
"@Internal Flash /0x8000000/8*1Kg");
} else if (serial[2] == '4') {
fu_dfu_target_set_alt_name(self, "@Internal Flash /0x8000000/16*1Kg");
fu_device_set_logical_id(FU_DEVICE(self),
"@Internal Flash /0x8000000/16*1Kg");
} else if (serial[2] == '6') {
fu_dfu_target_set_alt_name(self, "@Internal Flash /0x8000000/32*1Kg");
fu_device_set_logical_id(FU_DEVICE(self),
"@Internal Flash /0x8000000/32*1Kg");
} else if (serial[2] == '8') {
fu_dfu_target_set_alt_name(self, "@Internal Flash /0x8000000/64*1Kg");
fu_device_set_logical_id(FU_DEVICE(self),
"@Internal Flash /0x8000000/64*1Kg");
} else if (serial[2] == 'B') {
fu_dfu_target_set_alt_name(self, "@Internal Flash /0x8000000/128*1Kg");
fu_device_set_logical_id(FU_DEVICE(self),
"@Internal Flash /0x8000000/128*1Kg");
} else if (serial[2] == 'D') {
fu_dfu_target_set_alt_name(self, "@Internal Flash /0x8000000/256*1Kg");
fu_device_set_logical_id(FU_DEVICE(self),
"@Internal Flash /0x8000000/256*1Kg");
} else {
g_set_error(error,
FWUPD_ERROR,
@ -663,15 +619,18 @@ fu_dfu_target_setup(FuDfuTarget *self, GError **error)
}
/* get string */
if (priv->alt_idx != 0x00 && priv->alt_name == NULL) {
GUsbDevice *usb_device = fu_usb_device_get_dev(FU_USB_DEVICE(priv->device));
priv->alt_name =
g_usb_device_get_string_descriptor(usb_device, priv->alt_idx, NULL);
if (priv->alt_idx != 0x00 && fu_device_get_logical_id(FU_DEVICE(self)) == NULL) {
GUsbDevice *usb_device = fu_usb_device_get_dev(FU_USB_DEVICE(device));
fu_device_set_logical_id(
FU_DEVICE(self),
g_usb_device_get_string_descriptor(usb_device, priv->alt_idx, NULL));
}
/* parse the DfuSe format according to UM0424 */
if (priv->sectors->len == 0) {
if (!fu_dfu_target_parse_sectors(self, priv->alt_name, error))
if (!fu_dfu_target_parse_sectors(self,
fu_device_get_logical_id(FU_DEVICE(self)),
error))
return FALSE;
}
@ -684,7 +643,8 @@ fu_dfu_target_setup(FuDfuTarget *self, GError **error)
0x0, /* zone */
0x0, /* number */
DFU_SECTOR_CAP_READABLE | DFU_SECTOR_CAP_WRITEABLE);
g_debug("no UM0424 sector description in %s", priv->alt_name);
g_debug("no UM0424 sector description in %s",
fu_device_get_logical_id(FU_DEVICE(self)));
g_ptr_array_add(priv->sectors, sector);
}
@ -726,8 +686,8 @@ fu_dfu_target_download_chunk(FuDfuTarget *self,
FuProgress *progress,
GError **error)
{
FuDfuTargetPrivate *priv = GET_PRIVATE(self);
GUsbDevice *usb_device = fu_usb_device_get_dev(FU_USB_DEVICE(priv->device));
FuDfuDevice *device = FU_DFU_DEVICE(fu_device_get_proxy(FU_DEVICE(self)));
GUsbDevice *usb_device = fu_usb_device_get_dev(FU_USB_DEVICE(device));
g_autoptr(GError) error_local = NULL;
gsize actual_length;
@ -741,15 +701,15 @@ fu_dfu_target_download_chunk(FuDfuTarget *self,
G_USB_DEVICE_RECIPIENT_INTERFACE,
FU_DFU_REQUEST_DNLOAD,
index,
fu_dfu_device_get_interface(priv->device),
fu_dfu_device_get_interface(device),
(guint8 *)g_bytes_get_data(bytes, NULL),
g_bytes_get_size(bytes),
&actual_length,
fu_dfu_device_get_timeout(priv->device),
fu_dfu_device_get_timeout(device),
NULL,
&error_local)) {
/* refresh the error code */
fu_dfu_device_error_fixup(priv->device, &error_local);
fu_dfu_device_error_fixup(device, &error_local);
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
@ -759,17 +719,17 @@ fu_dfu_target_download_chunk(FuDfuTarget *self,
}
/* for STM32 devices, the action only occurs when we do GetStatus */
if (fu_dfu_device_get_version(priv->device) == FU_DFU_FIRMARE_VERSION_DFUSE) {
if (!fu_dfu_device_refresh(priv->device, error))
if (fu_dfu_device_get_version(device) == FU_DFU_FIRMARE_VERSION_DFUSE) {
if (!fu_dfu_device_refresh(device, error))
return FALSE;
}
/* wait for the device to write contents to the EEPROM */
if (g_bytes_get_size(bytes) == 0 && fu_dfu_device_get_download_timeout(priv->device) > 0)
if (g_bytes_get_size(bytes) == 0 && fu_dfu_device_get_download_timeout(device) > 0)
fu_progress_set_status(progress, FWUPD_STATUS_DEVICE_BUSY);
if (fu_dfu_device_get_download_timeout(priv->device) > 0) {
g_debug("sleeping for %ums…", fu_dfu_device_get_download_timeout(priv->device));
g_usleep(fu_dfu_device_get_download_timeout(priv->device) * 1000);
if (fu_dfu_device_get_download_timeout(device) > 0) {
g_debug("sleeping for %ums…", fu_dfu_device_get_download_timeout(device));
g_usleep(fu_dfu_device_get_download_timeout(device) * 1000);
}
/* find out if the write was successful, waiting for BUSY to clear */
@ -789,15 +749,15 @@ fu_dfu_target_upload_chunk(FuDfuTarget *self,
FuProgress *progress,
GError **error)
{
FuDfuTargetPrivate *priv = GET_PRIVATE(self);
GUsbDevice *usb_device = fu_usb_device_get_dev(FU_USB_DEVICE(priv->device));
FuDfuDevice *device = FU_DFU_DEVICE(fu_device_get_proxy(FU_DEVICE(self)));
GUsbDevice *usb_device = fu_usb_device_get_dev(FU_USB_DEVICE(device));
g_autoptr(GError) error_local = NULL;
guint8 *buf;
gsize actual_length;
/* unset */
if (buf_sz == 0)
buf_sz = (gsize)fu_dfu_device_get_transfer_size(priv->device);
buf_sz = (gsize)fu_dfu_device_get_transfer_size(device);
buf = g_new0(guint8, buf_sz);
if (!g_usb_device_control_transfer(usb_device,
@ -806,15 +766,15 @@ fu_dfu_target_upload_chunk(FuDfuTarget *self,
G_USB_DEVICE_RECIPIENT_INTERFACE,
FU_DFU_REQUEST_UPLOAD,
index,
fu_dfu_device_get_interface(priv->device),
fu_dfu_device_get_interface(device),
buf,
buf_sz,
&actual_length,
fu_dfu_device_get_timeout(priv->device),
fu_dfu_device_get_timeout(device),
NULL,
&error_local)) {
/* refresh the error code */
fu_dfu_device_error_fixup(priv->device, &error_local);
fu_dfu_device_error_fixup(device, &error_local);
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
@ -844,17 +804,10 @@ fu_dfu_target_set_alt_setting(FuDfuTarget *self, guint8 alt_setting)
priv->alt_setting = alt_setting;
}
FuDfuDevice *
fu_dfu_target_get_device(FuDfuTarget *self)
{
FuDfuTargetPrivate *priv = GET_PRIVATE(self);
return priv->device;
}
gboolean
fu_dfu_target_attach(FuDfuTarget *self, FuProgress *progress, GError **error)
{
FuDfuTargetPrivate *priv = GET_PRIVATE(self);
FuDfuDevice *device = FU_DFU_DEVICE(fu_device_get_proxy(FU_DEVICE(self)));
FuDfuTargetClass *klass = FU_DFU_TARGET_GET_CLASS(self);
/* ensure populated */
@ -866,7 +819,7 @@ fu_dfu_target_attach(FuDfuTarget *self, FuProgress *progress, GError **error)
return klass->attach(self, progress, error);
/* normal DFU mode just needs a bus reset */
return fu_dfu_device_reset(priv->device, progress, error);
return fu_dfu_device_reset(device, progress, error);
}
static FuChunk *
@ -877,11 +830,11 @@ fu_dfu_target_upload_element_dfu(FuDfuTarget *self,
FuProgress *progress,
GError **error)
{
FuDfuTargetPrivate *priv = GET_PRIVATE(self);
FuDfuDevice *device = FU_DFU_DEVICE(fu_device_get_proxy(FU_DEVICE(self)));
GBytes *chunk_tmp;
guint percentage_size = expected_size > 0 ? expected_size : maximum_size;
gsize total_size = 0;
guint16 transfer_size = fu_dfu_device_get_transfer_size(priv->device);
guint16 transfer_size = fu_dfu_device_get_transfer_size(device);
g_autoptr(GBytes) contents = NULL;
g_autoptr(GPtrArray) chunks = NULL;
@ -1001,7 +954,8 @@ fu_dfu_target_upload(FuDfuTarget *self,
return FALSE;
/* can the target do this? */
if (!fu_dfu_device_can_upload(priv->device)) {
if (!fu_device_has_private_flag(fu_device_get_proxy(FU_DEVICE(self)),
FU_DFU_DEVICE_FLAG_CAN_UPLOAD)) {
g_set_error_literal(error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
@ -1024,7 +978,7 @@ fu_dfu_target_upload(FuDfuTarget *self,
/* create a new image */
image = fu_firmware_new();
fu_firmware_set_id(image, priv->alt_name);
fu_firmware_set_id(image, fu_device_get_logical_id(FU_DEVICE(self)));
fu_firmware_set_idx(image, priv->alt_setting);
/* get all the sectors for the device */
@ -1104,9 +1058,9 @@ fu_dfu_target_download_element_dfu(FuDfuTarget *self,
FuDfuTargetTransferFlags flags,
GError **error)
{
FuDfuTargetPrivate *priv = GET_PRIVATE(self);
FuDfuDevice *device = FU_DFU_DEVICE(fu_device_get_proxy(FU_DEVICE(self)));
guint32 nr_chunks;
guint16 transfer_size = fu_dfu_device_get_transfer_size(priv->device);
guint16 transfer_size = fu_dfu_device_get_transfer_size(device);
g_autoptr(GBytes) bytes = NULL;
/* round up as we have to transfer incomplete blocks */
@ -1160,12 +1114,12 @@ fu_dfu_target_download_element(FuDfuTarget *self,
FuDfuTargetTransferFlags flags,
GError **error)
{
FuDfuTargetPrivate *priv = GET_PRIVATE(self);
FuDevice *device = fu_device_get_proxy(FU_DEVICE(self));
FuDfuTargetClass *klass = FU_DFU_TARGET_GET_CLASS(self);
/* progress */
if (flags & DFU_TARGET_TRANSFER_FLAG_VERIFY &&
fu_dfu_device_has_attribute(priv->device, FU_DFU_DEVICE_ATTR_CAN_UPLOAD)) {
fu_device_has_private_flag(device, FU_DFU_DEVICE_FLAG_CAN_UPLOAD)) {
fu_progress_set_id(progress, G_STRLOC);
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 96);
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_VERIFY, 4);
@ -1194,7 +1148,7 @@ fu_dfu_target_download_element(FuDfuTarget *self,
/* verify */
if (flags & DFU_TARGET_TRANSFER_FLAG_VERIFY &&
fu_dfu_device_has_attribute(priv->device, FU_DFU_DEVICE_ATTR_CAN_UPLOAD)) {
fu_device_has_private_flag(device, FU_DFU_DEVICE_FLAG_CAN_UPLOAD)) {
g_autoptr(GBytes) bytes = NULL;
g_autoptr(GBytes) bytes_tmp = NULL;
g_autoptr(FuChunk) chunk_tmp = NULL;
@ -1243,6 +1197,7 @@ fu_dfu_target_download(FuDfuTarget *self,
FuDfuTargetTransferFlags flags,
GError **error)
{
FuDevice *device = fu_device_get_proxy(FU_DEVICE(self));
FuDfuTargetPrivate *priv = GET_PRIVATE(self);
g_autoptr(GPtrArray) chunks = NULL;
@ -1255,7 +1210,7 @@ fu_dfu_target_download(FuDfuTarget *self,
return FALSE;
/* can the target do this? */
if (!fu_dfu_device_can_download(priv->device)) {
if (!fu_device_has_private_flag(device, FU_DFU_DEVICE_FLAG_CAN_DOWNLOAD)) {
g_set_error_literal(error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
@ -1306,8 +1261,8 @@ fu_dfu_target_download(FuDfuTarget *self,
fu_progress_step_done(progress);
}
if (fu_device_has_private_flag(FU_DEVICE(priv->device), FU_DFU_DEVICE_FLAG_MANIFEST_POLL) &&
fu_dfu_device_has_attribute(priv->device, FU_DFU_DEVICE_ATTR_MANIFEST_TOL))
if (fu_device_has_private_flag(device, FU_DFU_DEVICE_FLAG_MANIFEST_POLL) &&
fu_device_has_private_flag(device, FU_DFU_DEVICE_FLAG_MANIFEST_TOL))
if (!fu_dfu_target_manifest_wait(self, error))
return FALSE;
@ -1331,62 +1286,11 @@ fu_dfu_target_get_alt_setting(FuDfuTarget *self)
return priv->alt_setting;
}
/**
* fu_dfu_target_get_alt_name:
* @self: a #FuDfuTarget
* @error: (nullable): optional return location for an error
*
* Gets the alternate setting name to use for this interface.
*
* Returns: the alternative setting name, typically %NULL
**/
const gchar *
fu_dfu_target_get_alt_name(FuDfuTarget *self, GError **error)
static void
fu_dfu_target_class_init(FuDfuTargetClass *klass)
{
FuDfuTargetPrivate *priv = GET_PRIVATE(self);
g_return_val_if_fail(FU_IS_DFU_TARGET(self), NULL);
/* ensure populated */
if (!fu_dfu_target_setup(self, error))
return NULL;
/* nothing */
if (priv->alt_name == NULL) {
g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "no alt-name");
return NULL;
}
return priv->alt_name;
}
/**
* fu_dfu_target_get_alt_name_for_display:
* @self: a #FuDfuTarget
* @error: (nullable): optional return location for an error
*
* Gets the alternate setting name to use for this interface that can be
* shown on the display.
*
* Returns: the alternative setting name
**/
const gchar *
fu_dfu_target_get_alt_name_for_display(FuDfuTarget *self, GError **error)
{
FuDfuTargetPrivate *priv = GET_PRIVATE(self);
g_return_val_if_fail(FU_IS_DFU_TARGET(self), NULL);
/* ensure populated */
if (!fu_dfu_target_setup(self, error))
return NULL;
/* nothing */
if (priv->alt_name_for_display == NULL) {
g_set_error_literal(error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_FOUND,
"no alt-name for display");
return NULL;
}
return priv->alt_name_for_display;
GObjectClass *object_class = G_OBJECT_CLASS(klass);
FuDeviceClass *klass_device = FU_DEVICE_CLASS(klass);
klass_device->to_string = fu_dfu_target_to_string;
object_class->finalize = fu_dfu_target_finalize;
}

View File

@ -16,7 +16,7 @@
#include "fu-dfu-sector.h"
#define FU_TYPE_DFU_TARGET (fu_dfu_target_get_type())
G_DECLARE_DERIVABLE_TYPE(FuDfuTarget, fu_dfu_target, FU, DFU_TARGET, GUsbDevice)
G_DECLARE_DERIVABLE_TYPE(FuDfuTarget, fu_dfu_target, FU, DFU_TARGET, FuDevice)
/**
* FuDfuTargetTransferFlags:
@ -39,7 +39,7 @@ typedef enum {
} FuDfuTargetTransferFlags;
struct _FuDfuTargetClass {
GUsbDeviceClass parent_class;
FuDeviceClass parent_class;
gboolean (*setup)(FuDfuTarget *self, GError **error);
gboolean (*attach)(FuDfuTarget *self, FuProgress *progress, GError **error);
gboolean (*detach)(FuDfuTarget *self, FuProgress *progress, GError **error);
@ -63,10 +63,6 @@ FuDfuSector *
fu_dfu_target_get_sector_default(FuDfuTarget *self);
guint8
fu_dfu_target_get_alt_setting(FuDfuTarget *self);
const gchar *
fu_dfu_target_get_alt_name(FuDfuTarget *self, GError **error);
const gchar *
fu_dfu_target_get_alt_name_for_display(FuDfuTarget *self, GError **error);
gboolean
fu_dfu_target_upload(FuDfuTarget *self,
FuFirmware *firmware,
@ -83,5 +79,3 @@ fu_dfu_target_download(FuDfuTarget *self,
GError **error);
gboolean
fu_dfu_target_mass_erase(FuDfuTarget *self, FuProgress *progress, GError **error);
void
fu_dfu_target_to_string(FuDfuTarget *self, guint idt, GString *str);

View File

@ -690,7 +690,7 @@ fu_dfu_tool_write(FuDfuTool *self, gchar **values, GError **error)
if (!fu_device_attach_full(FU_DEVICE(device), progress, error))
return FALSE;
if (fu_dfu_device_has_attribute(device, FU_DFU_DEVICE_ATTR_MANIFEST_TOL)) {
if (fu_device_has_private_flag(FU_DEVICE(device), FU_DFU_DEVICE_FLAG_MANIFEST_TOL)) {
if (!fu_dfu_device_wait_for_replug(self,
device,
fu_device_get_remove_delay(FU_DEVICE(device)),