Allow the registration of functions to be called at programmer shutdown
Some programmers want to run certain functions during programmer
shutdown, but the function choice depends on the code path taken
during programmer init. Rather than rebuilding the whole init logic in
the shutdown function, it is now possible to register functions for
execution on programmer shutdown. The behaviour is similar to atexit(),
but the registered functions will be run on programmer shutdown instead
of on exit and the functions will be called with a void * argument
that is specified on registration. Registered functions must have
the prototype void function(void *); and will be executed in reverse
registration order directly before calling the programmer-specific
shutdown() function. It is recommended to have shutdown() only disable
programmer/hardware access and leave all code path sensitive shutdown to
functions registered with register_shutdown().
The most prominent use case is resetting the EC after flashing on
laptops.
Note: There are quite a few code paths in flashrom which proceed to
terminate flashrom without any programmer shutdown. Those code paths
will not get the benefit of register_shutdown() and they should be
changed wherever possible.
Corresponding to flashrom svn r904.
Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
diff --git a/flash.h b/flash.h
index 9238c2a..1474a38 100644
--- a/flash.h
+++ b/flash.h
@@ -99,6 +99,8 @@
extern const struct programmer_entry programmer_table[];
+int register_shutdown(void (*function) (void *data), void *data);
+
int programmer_init(void);
int programmer_shutdown(void);
void *programmer_map_flash_region(const char *descr, unsigned long phys_addr,
diff --git a/flashrom.c b/flashrom.c
index 3710606..b8de3c1 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -308,6 +308,35 @@
{}, /* This entry corresponds to PROGRAMMER_INVALID. */
};
+#define SHUTDOWN_MAXFN 4
+static int shutdown_fn_count = 0;
+struct shutdown_func_data {
+ void (*func) (void *data);
+ void *data;
+} shutdown_fn[SHUTDOWN_MAXFN];
+
+/* Register a function to be executed on programmer shutdown.
+ * The advantage over atexit() is that you can supply a void pointer which will
+ * be used as parameter to the registered function upon programmer shutdown.
+ * This pointer can point to arbitrary data used by said function, e.g. undo
+ * information for GPIO settings etc. If unneeded, set data=NULL.
+ * Please note that the first (void *data) belongs to the function signature of
+ * the function passed as first parameter.
+ */
+int register_shutdown(void (*function) (void *data), void *data)
+{
+ if (shutdown_fn_count >= SHUTDOWN_MAXFN) {
+ msg_perr("Tried to register more than %n shutdown functions.\n",
+ SHUTDOWN_MAXFN);
+ return 1;
+ }
+ shutdown_fn[shutdown_fn_count].func = function;
+ shutdown_fn[shutdown_fn_count].data = data;
+ shutdown_fn_count++;
+
+ return 0;
+}
+
int programmer_init(void)
{
return programmer_table[programmer].init();
@@ -315,6 +344,10 @@
int programmer_shutdown(void)
{
+ int i;
+
+ for (i = shutdown_fn_count - 1; i >= 0; i--)
+ shutdown_fn[i].func(shutdown_fn[i].data);
return programmer_table[programmer].shutdown();
}