input: Add a function to add a keycode to the existing set

Most keyboards can be scanned to produce a list of the keycodes which are
depressed. With the i8042 keyboard this scanning is done internally and
only the processed results are returned.

In this case, when a key is pressed, a 'make' code is sent. When the key
is released a 'break' code is sent. This means that the driver needs to
keep track of which keys are pressed. It also means that any protocol error
can lead to stuck keys.

In order to support this type of keyboard, add a function when can be used
to provide a single keycode and either add it to the list of what is pressed
or remove it from the list. Then the normal input_send_keycodes() function
can be used to actually do the decoding work.

Add debugging to display the ASCII characters written to the input queue
also.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
diff --git a/drivers/input/input.c b/drivers/input/input.c
index e65942e..530bf51 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -107,6 +107,7 @@
 			return -1; /* buffer full */
 		config->fifo_in++;
 	}
+	debug(" {%02x} ", ch);
 	config->fifo[config->fifo_in] = (uchar)ch;
 
 	return 0;
@@ -394,8 +395,8 @@
 	return ch_count;
 }
 
-int input_send_keycodes(struct input_config *config,
-			int keycode[], int num_keycodes)
+static int _input_send_keycodes(struct input_config *config, int keycode[],
+				int num_keycodes, bool do_send)
 {
 	char ch[num_keycodes * ANSI_CHAR_MAX];
 	int count, i, same = 0;
@@ -420,8 +421,10 @@
 
 	count = input_keycodes_to_ascii(config, keycode, num_keycodes,
 					ch, sizeof(ch), is_repeat ? 0 : same);
-	for (i = 0; i < count; i++)
-		input_queue_ascii(config, ch[i]);
+	if (do_send) {
+		for (i = 0; i < count; i++)
+			input_queue_ascii(config, ch[i]);
+	}
 	delay_ms = is_repeat ?
 			config->repeat_rate_ms :
 			config->repeat_delay_ms;
@@ -431,6 +434,41 @@
 	return count;
 }
 
+int input_send_keycodes(struct input_config *config, int keycode[],
+			int num_keycodes)
+{
+	return _input_send_keycodes(config, keycode, num_keycodes, true);
+}
+
+int input_add_keycode(struct input_config *config, int new_keycode,
+		      bool release)
+{
+	int keycode[INPUT_MAX_MODIFIERS + 1];
+	int count, i;
+
+	/* Add the old keycodes which are not removed by this new one */
+	for (i = 0, count = 0; i < config->num_prev_keycodes; i++) {
+		int code = config->prev_keycodes[i];
+
+		if (new_keycode == code) {
+			if (release)
+				continue;
+			new_keycode = -1;
+		}
+		keycode[count++] = code;
+	}
+
+	if (!release && new_keycode != -1)
+		keycode[count++] = new_keycode;
+	debug("\ncodes for %02x/%d: ", new_keycode, release);
+	for (i = 0; i < count; i++)
+		debug("%02x ", keycode[i]);
+	debug("\n");
+
+	/* Don't output any ASCII characters if this is a key release */
+	return _input_send_keycodes(config, keycode, count, !release);
+}
+
 int input_add_table(struct input_config *config, int left_keycode,
 		    int right_keycode, const uchar *xlate, int num_entries)
 {