[PATCH 21/25] efw-downloader: file-cntr: add parser for data binary shipped by Echo Digital Audio corporation

Takashi Sakamoto o-takashi at sakamocchi.jp
Fri Aug 21 09:31:07 CEST 2020


Echo Digital Audio corporation designed data format of firmware. The
format seems to be suitable for their SDK for customers and closed.

FFADO project implements the format parser in libffado2. Although the
implementation is not enough in several points, it's good point to guess
the format.

I captured asynchronous packet by bus analyzer during updating firmware by
Windows driver, aggregated the content of packet by script, then compared
it to content of firmware. Some points are cleared (but not all).

This commit adds parser for data binary shipped by Echo Digital Audio
corporation. I note that driver package shipped by vendors for Fireworks
based devices includes no EULA. I think this kind of reimplementation
is not limited in the case.

The content of file consists of two parts; header after magic bytes, and
payload. The header includes metadata about the data of payload. There are
four kind of data; for DSP, for IceLynx Micro, for arbitrary data, and
for FPGA.

The content except for magic bytes is hexadecimal string,
therefore it's possible to print out by simple dump tool; cat(1) and
less(1). The header includes CRC32 value of the decoded data and checksum
of every bytes of the decoded data.

When the header includes a flag, the CRC32 value is written to the end of
area for firmware.

Signed-off-by: Takashi Sakamoto <o-takashi at sakamocchi.jp>
---
 efw-downloader/src/file-cntr.c | 183 +++++++++++++++++++++++++++++++++
 efw-downloader/src/file-cntr.h |  39 +++++++
 efw-downloader/src/meson.build |   5 +
 3 files changed, 227 insertions(+)
 create mode 100644 efw-downloader/src/file-cntr.c
 create mode 100644 efw-downloader/src/file-cntr.h

diff --git a/efw-downloader/src/file-cntr.c b/efw-downloader/src/file-cntr.c
new file mode 100644
index 0000000..1e159f7
--- /dev/null
+++ b/efw-downloader/src/file-cntr.c
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+// Copyright (c) 2020 Takashi Sakamoto
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <zlib.h>
+
+#include "file-cntr.h"
+
+#define MAGIC_BYTES             "1651 1 0 0 0\r\n"
+#define PAYLOAD_OFFSET_QUADS    0x3f
+
+static int parse_entry(FILE *handle, uint32_t *val)
+{
+    char buf[16];
+    char *end;
+    size_t len;
+    int err = 0;
+
+    if (fgets(buf, sizeof(buf), handle) != buf) {
+        if (ferror(handle))
+            err = -errno;
+        else
+            err = INT_MAX;  // Use the value for EOF.
+        return err;
+    }
+
+    len = strlen(buf);
+    if (buf[0] != '0' || buf[1] != 'x' || buf[len - 2] != '\r' || buf[len - 1] != '\n')
+        return -EPROTO;
+    buf[len - 2] = '\0';
+
+    *val = strtoul(buf, &end, 16);
+    if (*end != '\0')
+        return -EPROTO;
+
+    return err;
+}
+
+static int parse_header(FILE *handle, struct file_cntr_header *header)
+{
+    uint32_t *buf = (uint32_t *)header;
+    int err = 0;
+    int i;
+
+    for (i = 0; i < 8; ++i) {
+        uint32_t val;
+
+        err = parse_entry(handle, &val);
+        if (err != 0)
+            break;
+
+        buf[i] = val;
+    }
+
+    if (err == INT_MAX)
+        err = -ENODATA;
+
+    return err;
+}
+
+static int parse_payload(FILE *handle, unsigned int quads, uint32_t *blob)
+{
+    int err = 0;
+    int i;
+
+    for (i = 0; i < quads; ++i) {
+        uint32_t val;
+
+        err = parse_entry(handle, &val);
+        if (err != 0)
+            break;
+
+        blob[i] = val;
+    }
+
+    if (i != quads || err == INT_MAX)
+        err = -ENODATA;
+
+    return err;
+}
+
+static int check_crc32(struct file_cntr *cntr)
+{
+    uint32_t blob_crc32;
+
+    blob_crc32 = crc32(0ul, (const uint8_t *)cntr->payload.blob,
+                       cntr->payload.count * sizeof(*cntr->payload.blob));
+    if (blob_crc32 != cntr->header.blob_crc32)
+        return -EINVAL;
+
+    return 0;
+}
+
+static int check_checksum(struct file_cntr *cntr)
+{
+    uint32_t checksum = 0;
+    int i, j;
+
+    for (i = 0; i < cntr->payload.count; ++i) {
+        for (j = 3; j >= 0; --j)
+            checksum += (cntr->payload.blob[i] >> (j * 8)) & 0xff;
+    }
+
+    if (checksum != cntr->header.blob_checksum)
+        return -EINVAL;
+
+    return 0;
+}
+
+int file_cntr_parse(struct file_cntr *cntr, const char *filepath)
+{
+    FILE *handle;
+    char buf[16];
+    size_t till_data;
+    int err = 0;
+
+    handle = fopen(filepath, "r");
+    if (handle == NULL)
+        return -errno;
+
+    // Check magic bytes.
+    if (fgets(buf, sizeof(buf), handle) != buf) {
+        if (ferror(handle))
+            err = -errno;
+        else
+            err = -ENODATA;
+        goto end;
+    }
+
+    if (memcmp(buf, MAGIC_BYTES, sizeof(MAGIC_BYTES))) {
+        err = -EPROTO;
+        goto end;
+    }
+
+    // Parse header.
+    err = parse_header(handle, &cntr->header);
+    if (err < 0)
+        goto end;
+
+    // Skip to area for data.
+    till_data = (PAYLOAD_OFFSET_QUADS - 7) * 12;
+    if (fseek(handle, till_data, SEEK_CUR) < 0) {
+        err = -errno;
+        goto end;
+    }
+
+    cntr->payload.blob = calloc(cntr->header.blob_quads, sizeof(*cntr->payload.blob));
+    if (cntr->payload.blob == NULL) {
+        err = -ENOMEM;
+        goto end;
+    }
+    cntr->payload.count = cntr->header.blob_quads;
+
+    err = parse_payload(handle, cntr->header.blob_quads, cntr->payload.blob);
+    if (err < 0) {
+        free(cntr->payload.blob);
+        goto end;
+    }
+
+    err = check_crc32(cntr);
+    if (err < 0) {
+        free(cntr->payload.blob);
+        goto end;
+    }
+
+    err = check_checksum(cntr);
+    if (err < 0)
+        free(cntr->payload.blob);
+end:
+    fclose(handle);
+
+    return err;
+}
+
+void file_cntr_release(struct file_cntr *cntr)
+{
+    if (cntr->payload.blob != NULL)
+        free(cntr->payload.blob);
+    cntr->payload.blob = NULL;
+}
diff --git a/efw-downloader/src/file-cntr.h b/efw-downloader/src/file-cntr.h
new file mode 100644
index 0000000..c4657f1
--- /dev/null
+++ b/efw-downloader/src/file-cntr.h
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+// Copyright (c) 2020 Takashi Sakamoto
+#ifndef __FILE_CNTR__
+#define __FILE_CNTR__
+
+#include <stdint.h>
+
+enum blob_type {
+    BLOB_TYPE_DSP = 0,
+    BLOB_TYPE_ICELYNX = 1,
+    BLOB_TYPE_DATA = 2,
+    BLOB_TYPE_FPGA = 3,
+};
+
+struct file_cntr_header {
+    enum blob_type type;
+    uint32_t offset_addr;
+    uint32_t blob_quads;
+    uint32_t blob_crc32;
+    uint32_t blob_checksum;
+    uint32_t version;
+    uint32_t crc_in_region_end;
+    uint32_t cntr_quads;
+};
+
+struct file_cntr_payload {
+    uint32_t *blob;
+    size_t count;
+};
+
+struct file_cntr {
+    struct file_cntr_header header;
+    struct file_cntr_payload payload;
+};
+
+int file_cntr_parse(struct file_cntr *cntr, const char *filepath);
+void file_cntr_release(struct file_cntr *cntr);
+
+#endif
diff --git a/efw-downloader/src/meson.build b/efw-downloader/src/meson.build
index 8738d76..05d491d 100644
--- a/efw-downloader/src/meson.build
+++ b/efw-downloader/src/meson.build
@@ -11,12 +11,15 @@ hinawa = dependency('hinawa',
   version: '>=2.1',
 )
 
+zlib = dependency('zlib')
+
 sources = [
   'main.c',
   'efw-proto.c',
   'config-rom.c',
   'node-dispatcher.c',
   'efw-commands.c',
+  'file-cntr.c',
   'subcmd-device.c',
   'op-device-read.c',
 ]
@@ -26,6 +29,7 @@ headers = [
   'config-rom.h',
   'node-dispatcher.h',
   'efw-commands.h',
+  'file-cntr.h',
   'subcmds.h',
 ]
 
@@ -42,6 +46,7 @@ executable('efw-downloader',
   dependencies: [
     gobject,
     hinawa,
+    zlib,
   ],
   install: true,
 )
-- 
2.25.1



More information about the Alsa-devel mailing list