/** * dfu_target_use_alt_setting: * @target: a #DfuTarget * @error: a #GError, or %NULL * * Opens a DFU-capable target. * * Return value: %TRUE for success * * Since: 0.5.4 **/ static gboolean dfu_target_use_alt_setting (DfuTarget *target, GError **error) { DfuTargetPrivate *priv = GET_PRIVATE (target); GUsbDevice *dev; g_autoptr(GError) error_local = NULL; g_return_val_if_fail (DFU_IS_TARGET (target), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* use the correct setting */ dev = dfu_device_get_usb_dev (priv->device); if (dfu_device_get_mode (priv->device) == DFU_MODE_DFU) { if (!g_usb_device_set_interface_alt (dev, (gint) dfu_device_get_interface (priv->device), (gint) priv->alt_setting, &error_local)) { g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "cannot set alternate setting 0x%02x on interface %i: %s", priv->alt_setting, dfu_device_get_interface (priv->device), error_local->message); return FALSE; } } return TRUE; }
static gchar * dfu_context_get_device_id (DfuDevice *device) { GUsbDevice *dev; dev = dfu_device_get_usb_dev (device); if (dev == NULL) return g_strdup (dfu_device_get_platform_id (device)); return g_strdup_printf ("%04x:%04x [%s]", g_usb_device_get_vid (dev), g_usb_device_get_pid (dev), g_usb_device_get_platform_id (dev)); }
/** * dfu_target_setup: * @target: a #DfuTarget * @error: a #GError, or %NULL * * Opens a DFU-capable target. * * Return value: %TRUE for success * * Since: 0.5.4 **/ static gboolean dfu_target_setup (DfuTarget *target, GError **error) { DfuTargetPrivate *priv = GET_PRIVATE (target); g_autoptr(GError) error_local = NULL; g_return_val_if_fail (DFU_IS_TARGET (target), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* already done */ if (priv->done_setup) return TRUE; /* get string */ if (priv->alt_idx != 0x00) { GUsbDevice *dev; dev = dfu_device_get_usb_dev (priv->device); priv->alt_name = g_usb_device_get_string_descriptor (dev, priv->alt_idx, NULL); } /* parse the DfuSe format according to UM0424 */ if (!dfu_target_parse_sectors (target, priv->alt_name, error)) return FALSE; /* add a dummy entry */ if (priv->sectors->len == 0) { DfuSector *sector; sector = dfu_sector_new (0x0, /* addr */ 0x0, /* size */ 0x0, /* size_left */ 0x0, /* zone */ 0x0, /* number */ DFU_SECTOR_CAP_READABLE | DFU_SECTOR_CAP_WRITEABLE); g_debug ("no UM0424 sector descripton in %s", priv->alt_name); g_ptr_array_add (priv->sectors, sector); } priv->done_setup = TRUE; return TRUE; }
/** * dfu_context_get_device_by_vid_pid: * @context: a #DfuContext * @vid: a vendor ID * @pid: a product ID * @error: a #GError, or %NULL * * Finds a device in the context with a specific vendor:product ID. * An error is returned if more than one device matches. * * Return value: (transfer full): a #DfuDevice for success, or %NULL for an error * * Since: 0.5.4 **/ DfuDevice * dfu_context_get_device_by_vid_pid (DfuContext *context, guint16 vid, guint16 pid, GError **error) { DfuContextPrivate *priv = GET_PRIVATE (context); DfuContextItem *item; DfuDevice *device = NULL; GUsbDevice *dev; guint i; g_return_val_if_fail (DFU_IS_CONTEXT (context), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* search all devices */ for (i = 0; i < priv->devices->len; i++) { /* match */ item = g_ptr_array_index (priv->devices, i); dev = dfu_device_get_usb_dev (item->device); if (g_usb_device_get_vid (dev) == vid && g_usb_device_get_pid (dev) == pid) { if (device != NULL) { g_set_error (error, DFU_ERROR, DFU_ERROR_INVALID_DEVICE, "multiple device matches for %04x:%04x", vid, pid); return NULL; } device = item->device; continue; } } if (device == NULL) { g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_FOUND, "no device matches for %04x:%04x", vid, pid); return NULL; } return g_object_ref (device); }
/** * dfu_target_upload_chunk: (skip) **/ GBytes * dfu_target_upload_chunk (DfuTarget *target, guint8 index, GCancellable *cancellable, GError **error) { DfuTargetPrivate *priv = GET_PRIVATE (target); g_autoptr(GError) error_local = NULL; guint8 *buf; gsize actual_length; guint16 transfer_size = dfu_device_get_transfer_size (priv->device); buf = g_new0 (guint8, transfer_size); if (!g_usb_device_control_transfer (dfu_device_get_usb_dev (priv->device), G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, G_USB_DEVICE_REQUEST_TYPE_CLASS, G_USB_DEVICE_RECIPIENT_INTERFACE, DFU_REQUEST_UPLOAD, index, dfu_device_get_interface (priv->device), buf, (gsize) transfer_size, &actual_length, dfu_device_get_timeout (priv->device), cancellable, &error_local)) { /* refresh the error code */ dfu_device_error_fixup (priv->device, cancellable, &error_local); g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "cannot upload data: %s", error_local->message); return NULL; } /* for ST devices, the action only occurs when we do GetStatus */ if (!dfu_device_has_quirk (priv->device, DFU_DEVICE_QUIRK_NO_GET_STATUS_UPLOAD)) { if (!dfu_target_check_status (target, cancellable, error)) return FALSE; } return g_bytes_new_take (buf, actual_length); }
/** * dfu_target_download_chunk: **/ static gboolean dfu_target_download_chunk (DfuTarget *target, guint8 index, GBytes *bytes, GCancellable *cancellable, GError **error) { DfuTargetPrivate *priv = GET_PRIVATE (target); g_autoptr(GError) error_local = NULL; gsize actual_length; if (!g_usb_device_control_transfer (dfu_device_get_usb_dev (priv->device), G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, G_USB_DEVICE_REQUEST_TYPE_CLASS, G_USB_DEVICE_RECIPIENT_INTERFACE, DFU_REQUEST_DNLOAD, index, dfu_device_get_interface (priv->device), (guint8 *) g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), &actual_length, dfu_device_get_timeout (priv->device), cancellable, &error_local)) { /* refresh the error code */ dfu_device_error_fixup (priv->device, cancellable, &error_local); g_set_error (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "cannot download data: %s", error_local->message); return FALSE; } /* for ST devices, the action only occurs when we do GetStatus */ if (!dfu_target_check_status (target, cancellable, error)) return FALSE; g_assert (actual_length == g_bytes_get_size (bytes)); return TRUE; }