From fbb0ce04a8306525ed02d62ae1fb4b7c0bc998b4 Mon Sep 17 00:00:00 2001
From: Richard Hughes <richard@hughsie.com>
Date: Fri, 15 Jan 2021 09:48:12 +0000
Subject: [PATCH] libflashrom: Return progress state to the library user

Change-Id: I7197572bb7f19e3bdb2bde855d70a0f50fd3854c
Signed-off-by: Richard Hughes <richard@hughsie.com>
---
 flash.h       |  1 +
 libflashrom.c | 25 +++++++++++++++++++++++++
 libflashrom.h | 11 +++++++++++
 spi.c         |  6 ++++++
 spi25.c       | 13 +++++++++++++
 5 files changed, 56 insertions(+)

diff --git flash.h flash.h
index 883b6f4b..827a46d0 100644
--- flash.h
+++ flash.h
@@ -415,6 +415,7 @@ __attribute__((format(printf, 2, 3)));
 #define msg_gspew(...)	print(FLASHROM_MSG_SPEW, __VA_ARGS__)	/* general debug spew  */
 #define msg_pspew(...)	print(FLASHROM_MSG_SPEW, __VA_ARGS__)	/* programmer debug spew  */
 #define msg_cspew(...)	print(FLASHROM_MSG_SPEW, __VA_ARGS__)	/* chip debug spew  */
+void set_progress(const enum flashrom_progress_stage stage, size_t current, size_t total);
 
 /* layout.c */
 int register_include_arg(struct layout_include_args **args, char *name);
diff --git libflashrom.c libflashrom.c
index ae2d33da..ed7704ba 100644
--- libflashrom.c
+++ libflashrom.c
@@ -40,6 +40,8 @@
 
 /** Pointer to log callback function. */
 static flashrom_log_callback *global_log_callback = NULL;
+static flashrom_progress_callback *global_progress_callback = NULL;
+static void *global_progress_userdata = NULL;
 
 /**
  * @brief Initialize libflashrom.
@@ -95,6 +97,29 @@ int print(const enum flashrom_log_level level, const char *const fmt, ...)
 	return 0;
 }
 
+/**
+ * @brief Set the progress callback function.
+ *
+ * Set a callback function which will be invoked whenever libflashrom wants
+ * to indicate the progress has chaned. This allows frontends to do whatever
+ * they see fit with such values, e.g. update a progress bar in a GUI tool.
+ *
+ * @param progress_callback Pointer to the new progress callback function.
+ * @param userdata Userdata pointer to include with the progress callback.
+ */
+void flashrom_set_progress_callback(flashrom_progress_callback *const progress_callback, void *progress_userdata)
+{
+	global_progress_callback = progress_callback;
+	global_progress_userdata = progress_userdata;
+}
+/** @private */
+void set_progress(const enum flashrom_progress_stage stage, size_t current, size_t total)
+{
+	if (global_progress_callback == NULL)
+		return;
+	global_progress_callback(stage, current, total, global_progress_userdata);
+}
+
 /** @} */ /* end flashrom-general */
 
 
diff --git libflashrom.h libflashrom.h
index d0d58261..8d1caf7d 100644
--- libflashrom.h
+++ libflashrom.h
@@ -35,10 +35,21 @@ enum flashrom_log_level {
 	FLASHROM_MSG_DEBUG2	= 4,
 	FLASHROM_MSG_SPEW	= 5,
 };
+
+/** @ingroup flashrom-general */
+enum flashrom_progress_stage {
+	FLASHROM_PROGRESS_READ,
+	FLASHROM_PROGRESS_WRITE,
+};
+
 /** @ingroup flashrom-general */
 typedef int(flashrom_log_callback)(enum flashrom_log_level, const char *format, va_list);
 void flashrom_set_log_callback(flashrom_log_callback *);
 
+/** @ingroup flashrom-general */
+typedef void(flashrom_progress_callback)(enum flashrom_progress_stage stage, size_t current, size_t total, void *user_data);
+void flashrom_set_progress_callback(flashrom_progress_callback *, void *);
+
 /** @ingroup flashrom-query */
 enum flashrom_test_state {
 	FLASHROM_TESTED_OK  = 0,
diff --git spi.c spi.c
index aed2a927..9e991fcb 100644
--- spi.c
+++ spi.c
@@ -101,6 +101,8 @@ int spi_chip_read(struct flashctx *flash, uint8_t *buf, unsigned int start,
 {
 	int ret;
 	size_t to_read;
+	size_t progress_current = 0;
+	size_t progress_total = len - start;
 	for (; len; len -= to_read, buf += to_read, start += to_read) {
 		/* Do not cross 16MiB boundaries in a single transfer.
 		   This helps with
@@ -110,6 +112,10 @@ int spi_chip_read(struct flashctx *flash, uint8_t *buf, unsigned int start,
 		ret = flash->mst->spi.read(flash, buf, start, to_read);
 		if (ret)
 			return ret;
+
+		/* Emit progress to client */
+		progress_current += to_read;
+		set_progress(FLASHROM_PROGRESS_READ, progress_current, progress_total);
 	}
 	return 0;
 }
diff --git spi25.c spi25.c
index 213273f2..b3b98c81 100644
--- spi25.c
+++ spi25.c
@@ -669,11 +669,17 @@ int spi_read_chunked(struct flashctx *flash, uint8_t *buf, unsigned int start,
 {
 	int ret;
 	size_t to_read;
+	size_t progress_current = 0;
+	size_t progress_total = len - start;
 	for (; len; len -= to_read, buf += to_read, start += to_read) {
 		to_read = min(chunksize, len);
 		ret = spi_nbyte_read(flash, start, buf, to_read);
 		if (ret)
 			return ret;
+
+		/* Emit progress to client */
+		progress_current += to_read;
+		set_progress(FLASHROM_PROGRESS_READ, progress_current, progress_total);
 	}
 	return 0;
 }
@@ -693,6 +699,8 @@ int spi_write_chunked(struct flashctx *flash, const uint8_t *buf, unsigned int s
 	 * we're OK for now.
 	 */
 	unsigned int page_size = flash->chip->page_size;
+	size_t progress_current = 0;
+	size_t progress_total = len - start;
 
 	/* Warning: This loop has a very unusual condition and body.
 	 * The loop needs to go through each page with at least one affected
@@ -717,6 +725,10 @@ int spi_write_chunked(struct flashctx *flash, const uint8_t *buf, unsigned int s
 			if (rc)
 				return rc;
 		}
+
+		/* Emit progress to client */
+		progress_current += lenhere;
+		set_progress(FLASHROM_PROGRESS_WRITE, progress_current, progress_total);
 	}
 
 	return 0;
@@ -736,6 +748,7 @@ int spi_chip_write_1(struct flashctx *flash, const uint8_t *buf, unsigned int st
 	for (i = start; i < start + len; i++) {
 		if (spi_nbyte_program(flash, i, buf + i - start, 1))
 			return 1;
+		set_progress(FLASHROM_PROGRESS_WRITE, i - start, len - start);
 	}
 	return 0;
 }
-- 
2.29.2

