libdfu: Allow setting the alternate settings in DfuSe firmware

This commit is contained in:
Richard Hughes 2015-11-15 16:52:46 +00:00
parent 8bbe21a6f8
commit 31aa1dd3df
4 changed files with 323 additions and 51 deletions

View File

@ -143,6 +143,26 @@ dfu_firmware_get_image (DfuFirmware *firmware, guint8 alt_setting)
return NULL;
}
/**
* dfu_firmware_get_image_default:
* @firmware: a #DfuFirmware
*
* Gets the default image from the firmware file.
*
* Return value: (transfer none): a #DfuImage, or %NULL for not found
*
* Since: 0.5.4
**/
DfuImage *
dfu_firmware_get_image_default (DfuFirmware *firmware)
{
DfuFirmwarePrivate *priv = GET_PRIVATE (firmware);
g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), NULL);
if (priv->images->len == 0)
return NULL;
return g_ptr_array_index (priv->images, 0);
}
/**
* dfu_firmware_get_images:
* @firmware: a #DfuFirmware
@ -905,7 +925,7 @@ dfu_firmware_write_data (DfuFirmware *firmware, GError **error)
if (priv->format == DFU_FIRMWARE_FORMAT_RAW) {
GBytes *contents;
DfuElement *element;
image = dfu_firmware_get_image (firmware, 0);
image = dfu_firmware_get_image_default (firmware);
g_assert (image != NULL);
element = dfu_image_get_element (image, 0);
g_assert (element != NULL);
@ -917,7 +937,7 @@ dfu_firmware_write_data (DfuFirmware *firmware, GError **error)
if (priv->format == DFU_FIRMWARE_FORMAT_DFU_1_0) {
GBytes *contents;
DfuElement *element;
image = dfu_firmware_get_image (firmware, 0);
image = dfu_firmware_get_image_default (firmware);
g_assert (image != NULL);
element = dfu_image_get_element (image, 0);
g_assert (element != NULL);

View File

@ -77,6 +77,7 @@ const gchar *dfu_firmware_format_to_string (DfuFirmwareFormat format);
DfuImage *dfu_firmware_get_image (DfuFirmware *firmware,
guint8 alt_setting);
DfuImage *dfu_firmware_get_image_default (DfuFirmware *firmware);
GPtrArray *dfu_firmware_get_images (DfuFirmware *firmware);
guint16 dfu_firmware_get_vid (DfuFirmware *firmware);
guint16 dfu_firmware_get_pid (DfuFirmware *firmware);

View File

@ -261,7 +261,8 @@ dfu_image_set_name (DfuImage *image, const gchar *name)
g_return_if_fail (DFU_IS_IMAGE (image));
/* this is a hard limit in DfuSe */
sz = MAX (strlen (name), 254);
sz = MIN (strlen (name), 254);
memset (priv->name, 0x00, 254);
memcpy (priv->name, name, sz);
}

View File

@ -256,6 +256,253 @@ dfu_tool_get_defalt_device (DfuToolPrivate *priv, GError **error)
return NULL;
}
/**
* dfu_tool_set_vendor:
**/
static gboolean
dfu_tool_set_vendor (DfuToolPrivate *priv, gchar **values, GError **error)
{
guint64 tmp;
g_autoptr(DfuFirmware) firmware = NULL;
g_autoptr(GFile) file = NULL;
/* check args */
if (g_strv_length (values) < 2) {
g_set_error_literal (error,
DFU_ERROR,
DFU_ERROR_INTERNAL,
"Invalid arguments, expected FILE VID"
" -- e.g. `firmware.dfu 273f");
return FALSE;
}
/* open */
file = g_file_new_for_path (values[0]);
firmware = dfu_firmware_new ();
if (!dfu_firmware_parse_file (firmware, file,
DFU_FIRMWARE_PARSE_FLAG_NONE,
NULL, error)) {
return FALSE;
}
/* parse VID */
tmp = g_ascii_strtoull (values[1], NULL, 16);
if (tmp == 0 || tmp > 0xffff) {
g_set_error (error,
DFU_ERROR,
DFU_ERROR_INTERNAL,
"Failed to parse VID '%s'", values[1]);
return FALSE;
}
dfu_firmware_set_vid (firmware, tmp);
/* write out new file */
return dfu_firmware_write_file (firmware, file, NULL, error);
}
/**
* dfu_tool_set_product:
**/
static gboolean
dfu_tool_set_product (DfuToolPrivate *priv, gchar **values, GError **error)
{
guint64 tmp;
g_autoptr(DfuFirmware) firmware = NULL;
g_autoptr(GFile) file = NULL;
/* check args */
if (g_strv_length (values) < 2) {
g_set_error_literal (error,
DFU_ERROR,
DFU_ERROR_INTERNAL,
"Invalid arguments, expected FILE PID"
" -- e.g. `firmware.dfu 1004");
return FALSE;
}
/* open */
file = g_file_new_for_path (values[0]);
firmware = dfu_firmware_new ();
if (!dfu_firmware_parse_file (firmware, file,
DFU_FIRMWARE_PARSE_FLAG_NONE,
NULL, error)) {
return FALSE;
}
/* parse VID */
tmp = g_ascii_strtoull (values[1], NULL, 16);
if (tmp == 0 || tmp > 0xffff) {
g_set_error (error,
DFU_ERROR,
DFU_ERROR_INTERNAL,
"Failed to parse PID '%s'", values[1]);
return FALSE;
}
dfu_firmware_set_pid (firmware, tmp);
/* write out new file */
return dfu_firmware_write_file (firmware, file, NULL, error);
}
/**
* dfu_tool_set_release:
**/
static gboolean
dfu_tool_set_release (DfuToolPrivate *priv, gchar **values, GError **error)
{
guint64 tmp;
g_autoptr(DfuFirmware) firmware = NULL;
g_autoptr(GFile) file = NULL;
/* check args */
if (g_strv_length (values) < 2) {
g_set_error_literal (error,
DFU_ERROR,
DFU_ERROR_INTERNAL,
"Invalid arguments, expected FILE RELEASE"
" -- e.g. `firmware.dfu ffff");
return FALSE;
}
/* open */
file = g_file_new_for_path (values[0]);
firmware = dfu_firmware_new ();
if (!dfu_firmware_parse_file (firmware, file,
DFU_FIRMWARE_PARSE_FLAG_NONE,
NULL, error)) {
return FALSE;
}
/* parse VID */
tmp = g_ascii_strtoull (values[1], NULL, 16);
if (tmp == 0 || tmp > 0xffff) {
g_set_error (error,
DFU_ERROR,
DFU_ERROR_INTERNAL,
"Failed to parse release '%s'", values[1]);
return FALSE;
}
dfu_firmware_set_release (firmware, tmp);
/* write out new file */
return dfu_firmware_write_file (firmware, file, NULL, error);
}
/**
* dfu_tool_set_alt_setting:
**/
static gboolean
dfu_tool_set_alt_setting (DfuToolPrivate *priv, gchar **values, GError **error)
{
DfuImage *image;
guint64 tmp;
g_autoptr(DfuFirmware) firmware = NULL;
g_autoptr(GFile) file = NULL;
/* check args */
if (g_strv_length (values) < 2) {
g_set_error_literal (error,
DFU_ERROR,
DFU_ERROR_INTERNAL,
"Invalid arguments, expected FILE ALT-ID"
" -- e.g. `firmware.dfu 1");
return FALSE;
}
/* open */
file = g_file_new_for_path (values[0]);
firmware = dfu_firmware_new ();
if (!dfu_firmware_parse_file (firmware, file,
DFU_FIRMWARE_PARSE_FLAG_NONE,
NULL, error)) {
return FALSE;
}
/* doesn't make sense for non-DfuSe */
if (dfu_firmware_get_format (firmware) != DFU_FIRMWARE_FORMAT_DFUSE) {
g_set_error (error,
DFU_ERROR,
DFU_ERROR_INTERNAL,
"Only possible on DfuSe images, try convert");
return FALSE;
}
/* parse VID */
tmp = g_ascii_strtoull (values[1], NULL, 10);
if (tmp == 0 || tmp > 0xff) {
g_set_error (error,
DFU_ERROR,
DFU_ERROR_INTERNAL,
"Failed to parse alternative setting '%s'", values[1]);
return FALSE;
}
image = dfu_firmware_get_image_default (firmware);
if (image == NULL) {
g_set_error (error,
DFU_ERROR,
DFU_ERROR_INTERNAL,
"found no image '%s'", values[1]);
return FALSE;
}
dfu_image_set_alt_setting (image, tmp);
/* write out new file */
return dfu_firmware_write_file (firmware, file, NULL, error);
}
/**
* dfu_tool_set_alt_setting_name:
**/
static gboolean
dfu_tool_set_alt_setting_name (DfuToolPrivate *priv, gchar **values, GError **error)
{
DfuImage *image;
g_autoptr(DfuFirmware) firmware = NULL;
g_autoptr(GFile) file = NULL;
/* check args */
if (g_strv_length (values) < 2) {
g_set_error_literal (error,
DFU_ERROR,
DFU_ERROR_INTERNAL,
"Invalid arguments, expected FILE ALT-NAME"
" -- e.g. `firmware.dfu ST");
return FALSE;
}
/* open */
file = g_file_new_for_path (values[0]);
firmware = dfu_firmware_new ();
if (!dfu_firmware_parse_file (firmware, file,
DFU_FIRMWARE_PARSE_FLAG_NONE,
NULL, error)) {
return FALSE;
}
/* doesn't make sense for non-DfuSe */
if (dfu_firmware_get_format (firmware) != DFU_FIRMWARE_FORMAT_DFUSE) {
g_set_error (error,
DFU_ERROR,
DFU_ERROR_INTERNAL,
"Only possible on DfuSe images, try convert");
return FALSE;
}
/* parse VID */
image = dfu_firmware_get_image_default (firmware);
if (image == NULL) {
g_set_error (error,
DFU_ERROR,
DFU_ERROR_INTERNAL,
"found no image '%s'", values[1]);
return FALSE;
}
dfu_image_set_name (image, values[1]);
/* write out new file */
return dfu_firmware_write_file (firmware, file, NULL, error);
}
/**
* dfu_tool_convert:
**/
@ -275,8 +522,8 @@ dfu_tool_convert (DfuToolPrivate *priv, gchar **values, GError **error)
DFU_ERROR,
DFU_ERROR_INTERNAL,
"Invalid arguments, expected "
"FORMAT FILE-IN FILE-OUT [VID] [PID] [PRODUCT] [SIZE]"
" -- e.g. `dfu firmware.hex firmware.dfu 273f 1004 ffff 8000`");
"FORMAT FILE-IN FILE-OUT [SIZE]"
" -- e.g. `dfu firmware.hex firmware.dfu 8000`");
return FALSE;
}
@ -306,62 +553,35 @@ dfu_tool_convert (DfuToolPrivate *priv, gchar **values, GError **error)
return FALSE;
}
/* set VID */
if (argc > 3) {
tmp = g_ascii_strtoull (values[3], NULL, 16);
if (tmp == 0 || tmp > 0xffff) {
g_set_error (error,
DFU_ERROR,
DFU_ERROR_INTERNAL,
"Failed to parse VID '%s'", values[3]);
return FALSE;
}
dfu_firmware_set_vid (firmware, tmp);
}
/* set PID */
if (argc > 4) {
tmp = g_ascii_strtoull (values[4], NULL, 16);
if (tmp == 0 || tmp > 0xffff) {
g_set_error (error,
DFU_ERROR,
DFU_ERROR_INTERNAL,
"Failed to parse PID '%s'", values[4]);
return FALSE;
}
dfu_firmware_set_pid (firmware, tmp);
}
/* set release */
if (argc > 5) {
tmp = g_ascii_strtoull (values[5], NULL, 16);
if (tmp == 0 || tmp > 0xffff) {
g_set_error (error,
DFU_ERROR,
DFU_ERROR_INTERNAL,
"Failed to parse release '%s'", values[5]);
return FALSE;
}
dfu_firmware_set_release (firmware, tmp);
}
/* set target size */
if (argc > 6) {
if (argc > 3) {
DfuImage *image;
DfuElement *element;
tmp = g_ascii_strtoull (values[6], NULL, 16);
if (tmp == 0 || tmp > 0xffff) {
tmp = g_ascii_strtoull (values[3], NULL, 16);
if (tmp > 0xffff) {
g_set_error (error,
DFU_ERROR,
DFU_ERROR_INTERNAL,
"Failed to parse target size '%s'", values[6]);
"Failed to parse target size '%s'", values[3]);
return FALSE;
}
/* doesn't make sense for DfuSe */
if (dfu_firmware_get_format (firmware) == DFU_FIRMWARE_FORMAT_DFUSE) {
g_set_error (error,
DFU_ERROR,
DFU_ERROR_INTERNAL,
"Cannot pad DfuSe image, try DFU");
return FALSE;
}
/* this has to exist */
image = dfu_firmware_get_image (firmware, 0);
element = dfu_image_get_element (image, 0);
dfu_element_set_target_size (element, tmp);
if (tmp > 0) {
image = dfu_firmware_get_image_default (firmware);
g_assert (image != NULL);
element = dfu_image_get_element (image, 0);
dfu_element_set_target_size (element, tmp);
}
}
/* print the new object */
@ -885,6 +1105,36 @@ main (int argc, char *argv[])
/* TRANSLATORS: command description */
_("Convert firmware to DFU format"),
dfu_tool_convert);
dfu_tool_add (priv->cmd_array,
"set-vendor",
NULL,
/* TRANSLATORS: command description */
_("Set vendor ID on firmware file"),
dfu_tool_set_vendor);
dfu_tool_add (priv->cmd_array,
"set-product",
NULL,
/* TRANSLATORS: command description */
_("Set product ID on firmware file"),
dfu_tool_set_product);
dfu_tool_add (priv->cmd_array,
"set-release",
NULL,
/* TRANSLATORS: command description */
_("Set release version on firmware file"),
dfu_tool_set_release);
dfu_tool_add (priv->cmd_array,
"set-alt-setting",
NULL,
/* TRANSLATORS: command description */
_("Set alternative number on firmware file"),
dfu_tool_set_alt_setting);
dfu_tool_add (priv->cmd_array,
"set-alt-setting-name",
NULL,
/* TRANSLATORS: command description */
_("Set alternative name on firmware file"),
dfu_tool_set_alt_setting_name);
dfu_tool_add (priv->cmd_array,
"reset",
NULL,