expo: Add a function to poll for input

Both bootflow_menu and cedit use similar logic to poll an expo. Move
this into the expo library so the code can be shared.

Update bootflow_menu_run() to return -EPIPE when the user quits without
choosing anything, since -EAGAIN is ambiguous and elsewhere means that
there is no input yet.

Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/boot/bootflow_menu.c b/boot/bootflow_menu.c
index 43125e1..268c93a 100644
--- a/boot/bootflow_menu.c
+++ b/boot/bootflow_menu.c
@@ -216,39 +216,8 @@
 	done = false;
 	do {
 		struct expo_action act;
-		int ichar, key;
 
-		ret = expo_render(exp);
-		if (ret)
-			break;
-
-		ichar = cli_ch_process(&exp->cch, 0);
-		if (!ichar) {
-			while (!ichar && !tstc()) {
-				schedule();
-				mdelay(2);
-				ichar = cli_ch_process(&exp->cch, -ETIMEDOUT);
-			}
-			if (!ichar) {
-				ichar = getchar();
-				ichar = cli_ch_process(&exp->cch, ichar);
-			}
-		}
-
-		key = 0;
-		if (ichar) {
-			key = bootmenu_conv_key(ichar);
-			if (key == BKEY_NONE)
-				key = ichar;
-		}
-		if (!key)
-			continue;
-
-		ret = expo_send_key(exp, key);
-		if (ret)
-			break;
-
-		ret = expo_action_get(exp, &act);
+		ret = expo_poll(exp, &act);
 		if (!ret) {
 			switch (act.type) {
 			case EXPOACT_SELECT:
@@ -256,17 +225,15 @@
 				done = true;
 				break;
 			case EXPOACT_QUIT:
-				done = true;
-				break;
+				return -EPIPE;
 			default:
 				break;
 			}
+		} else if (ret != -EPIPE && ret != -EAGAIN) {
+			return log_msg_ret("bmr", ret);
 		}
 	} while (!done);
 
-	if (ret)
-		return log_msg_ret("end", ret);
-
 	if (sel_id) {
 		struct bootflow *bflow;
 		int i;
diff --git a/boot/cedit.c b/boot/cedit.c
index ed499f1..b7b9cc5 100644
--- a/boot/cedit.c
+++ b/boot/cedit.c
@@ -166,39 +166,8 @@
 	save = false;
 	do {
 		struct expo_action act;
-		int ichar, key;
 
-		ret = expo_render(exp);
-		if (ret)
-			break;
-
-		ichar = cli_ch_process(&exp->cch, 0);
-		if (!ichar) {
-			while (!ichar && !tstc()) {
-				schedule();
-				mdelay(2);
-				ichar = cli_ch_process(&exp->cch, -ETIMEDOUT);
-			}
-			if (!ichar) {
-				ichar = getchar();
-				ichar = cli_ch_process(&exp->cch, ichar);
-			}
-		}
-
-		key = 0;
-		if (ichar) {
-			key = bootmenu_conv_key(ichar);
-			if (key == BKEY_NONE || key >= BKEY_FIRST_EXTRA)
-				key = ichar;
-		}
-		if (!key)
-			continue;
-
-		ret = expo_send_key(exp, key);
-		if (ret)
-			break;
-
-		ret = expo_action_get(exp, &act);
+		ret = expo_poll(exp, &act);
 		if (!ret) {
 			switch (act.type) {
 			case EXPOACT_POINT_OBJ:
@@ -233,6 +202,8 @@
 			default:
 				break;
 			}
+		} else if (ret != -EAGAIN) {
+			return log_msg_ret("cep", ret);
 		}
 	} while (!done);
 
diff --git a/boot/expo.c b/boot/expo.c
index 9c042f1..301bbfa 100644
--- a/boot/expo.c
+++ b/boot/expo.c
@@ -10,8 +10,12 @@
 
 #include <dm.h>
 #include <expo.h>
+#include <log.h>
 #include <malloc.h>
+#include <menu.h>
 #include <video.h>
+#include <watchdog.h>
+#include <linux/delay.h>
 #include "scene_internal.h"
 
 int expo_new(const char *name, void *priv, struct expo **expp)
@@ -286,3 +290,43 @@
 
 	return 0;
 }
+
+int expo_poll(struct expo *exp, struct expo_action *act)
+{
+	int ichar, key, ret;
+
+	ret = expo_render(exp);
+	if (ret)
+		return log_msg_ret("ere", ret);
+
+	ichar = cli_ch_process(&exp->cch, 0);
+	if (!ichar) {
+		while (!ichar && !tstc()) {
+			schedule();
+			mdelay(2);
+			ichar = cli_ch_process(&exp->cch, -ETIMEDOUT);
+		}
+		if (!ichar) {
+			ichar = getchar();
+			ichar = cli_ch_process(&exp->cch, ichar);
+		}
+	}
+
+	key = 0;
+	if (ichar) {
+		key = bootmenu_conv_key(ichar);
+		if (key == BKEY_NONE || key >= BKEY_FIRST_EXTRA)
+			key = ichar;
+	}
+	if (!key)
+		return -EAGAIN;
+
+	ret = expo_send_key(exp, key);
+	if (ret)
+		return log_msg_ret("epk", ret);
+	ret = expo_action_get(exp, act);
+	if (ret)
+		return log_msg_ret("eag", ret);
+
+	return 0;
+}