[U-Boot] [PATCH 2/6] efi_loader: support Unicode text input

Alexander Graf agraf at suse.de
Mon Sep 10 10:05:35 UTC 2018


On 09/09/2018 07:57 AM, Heinrich Schuchardt wrote:
> Up to now the EFI_TEXT_INPUT_PROTOCOL only supported ASCII characters.
>
> With the patch it can consume UTF-8 from the serial console or
> codepage 437 special characters from the local keyboard.
>
> Signed-off-by: Heinrich Schuchardt <xypron.glpk at gmx.de>
> ---
>   lib/efi_loader/efi_console.c | 80 ++++++++++++++++++++++++++++++++++--
>   1 file changed, 76 insertions(+), 4 deletions(-)
>
> diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
> index 3ca6fe536c..8c45290b2e 100644
> --- a/lib/efi_loader/efi_console.c
> +++ b/lib/efi_loader/efi_console.c
> @@ -15,12 +15,18 @@
>   #define EFI_COUT_MODE_2 2
>   #define EFI_MAX_COUT_MODE 3
>   
> +/* Keyboard layouts */
> +#define KBD_US		0	/* default US layout */
> +#define KBD_GER		1	/* German layout */
> +
>   struct cout_mode {
>   	unsigned long columns;
>   	unsigned long rows;
>   	int present;
>   };
>   
> +static int keymap = KBD_US;
> +
>   static struct cout_mode efi_cout_modes[] = {
>   	/* EFI Mode 0 is 80x25 and always present */
>   	{
> @@ -390,6 +396,19 @@ struct efi_simple_text_output_protocol efi_con_out = {
>   	.mode = (void*)&efi_con_mode,
>   };
>   
> +static void efi_set_keymap(void)
> +{
> +	char *penv;
> +
> +	/* Init keyboard device (default US layout) */
> +	keymap = KBD_US;
> +	penv = env_get("keymap");
> +	if (penv) {
> +		if (strncmp(penv, "de", 3) == 0)
> +			keymap = KBD_GER;

I'm not terribly happy with this. It's very i8042 specific. Currently 
U-Boot only implements the keymap variable there. Couldn't we add an 
extended getc() that reads a full 32bit unicode value from the target 
device? That way we could add an interim layer that everyone - not just 
efi_loader - can use to extract keycodes coherently from any input.

> +	}
> +}
> +
>   static efi_status_t EFIAPI efi_cin_reset(
>   			struct efi_simple_text_input_protocol *this,
>   			bool extended_verification)
> @@ -453,17 +472,16 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke(
>   		.scan_code = 0,
>   		.unicode_char = 0,
>   	};
> -	char ch;
> +	int ch;
>   
>   	EFI_ENTRY("%p, %p", this, key);
>   
>   	/* We don't do interrupts, so check for timers cooperatively */
>   	efi_timer_check();
>   
> -	if (!tstc()) {
> +	if (!tstc())
>   		/* No key pressed */
> -		return EFI_EXIT(EFI_NOT_READY);
> -	}
> +		goto error;
>   
>   	ch = getc();
>   	if (ch == cESC) {
> @@ -550,12 +568,63 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke(
>   	} else if (ch == 0x7f) {
>   		/* Backspace */
>   		ch = 0x08;
> +	} else if (keymap == KBD_US && ch >= 0xc2 && ch <= 0xf4) {
> +		/*
> +		 * Unicode
> +		 *
> +		 * We assume here that the serial console is using UTF-8.
> +		 * This of cause depends on the terminal settings.
> +		 */
> +		int code = 0;
> +
> +		if (ch >= 0xe0) {
> +			if (ch >= 0xf0) {
> +				/* 0xf0 - 0xf4 */
> +				ch &= 0x07;
> +				code = ch << 18;
> +				ch = getc();
> +				if (ch < 0x80 || ch > 0xbf)
> +					goto error;
> +				ch &= 0x3f;
> +			} else {
> +				/* 0xe0 - 0xef */
> +				ch &= 0x0f;
> +			}
> +			code += ch << 12;
> +			if ((code >= 0xD800 && code <= 0xDFFF) ||
> +			    code >= 0x110000)
> +				goto error;
> +			ch = getc();
> +			if (ch < 0x80 || ch > 0xbf)
> +				goto error;
> +		}
> +		/* 0xc0 - 0xdf or continuation byte (0x80 - 0xbf) */
> +		ch &= 0x3f;
> +		code += ch << 6;
> +		ch = getc();
> +		if (ch < 0x80 || ch > 0xbf)
> +			goto error;
> +		ch &= 0x3f;
> +		ch += code;

All of the logic above for example really shouldn't live inside of 
efi_loader. It belongs somewhere more generic.


Alex

> +	} else if (keymap != KBD_US && ch >= 0x80 && ch <= 0xff) {
> +		/*
> +		 * Code page 437 special characters
> +		 *
> +		 * The keyboard drivers emit code page 437 characters. Support
> +		 * for German language special characters can be enabled via
> +		 * environment variable 'keymap' in the i8042 driver.
> +		 */
> +		ch = codepage_437[ch - 0x80];
> +	} else if (ch >= 0x80) {
> +		goto error;
>   	}
>   	if (!pressed_key.scan_code)
>   		pressed_key.unicode_char = ch;
>   	*key = pressed_key;
>   
>   	return EFI_EXIT(EFI_SUCCESS);
> +error:
> +	return EFI_EXIT(EFI_NOT_READY);
>   }
>   
>   struct efi_simple_text_input_protocol efi_con_in = {
> @@ -597,6 +666,9 @@ int efi_console_register(void)
>   	struct efi_object *efi_console_output_obj;
>   	struct efi_object *efi_console_input_obj;
>   
> +	/* Set keymap */
> +	efi_set_keymap();
> +
>   	/* Set up mode information */
>   	query_console_size();
>   




More information about the U-Boot mailing list