diff mbox series

[U-Boot,1/2] usb: kbd: allow multibyte sequences to be put into ring buffer

Message ID 20180222120418.12832-2-xypron.glpk@gmx.de
State Changes Requested
Delegated to: Marek Vasut
Headers show
Series usb: kbd: implement special keys | expand

Commit Message

Heinrich Schuchardt Feb. 22, 2018, 12:04 p.m. UTC
The USB keyboard driver provides a ring buffer for key strokes.

Function keys cannot be encoded as single bytes. Instead xterm control
sequences have to be put into the ring buffer.

This preparatory patch changes function usb_kbd_put_queue() to allow adding
multiple characters at once. If the buffer cannot accommodate the whole
sequence, it is rejected completely.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
 common/usb_kbd.c | 42 +++++++++++++++++++++++++-----------------
 1 file changed, 25 insertions(+), 17 deletions(-)

Comments

Marek Vasut Feb. 22, 2018, 2:20 p.m. UTC | #1
On 02/22/2018 01:04 PM, Heinrich Schuchardt wrote:
> The USB keyboard driver provides a ring buffer for key strokes.
> 
> Function keys cannot be encoded as single bytes. Instead xterm control
> sequences have to be put into the ring buffer.

Does it work without xterm or with any other terminal ?

> This preparatory patch changes function usb_kbd_put_queue() to allow adding
> multiple characters at once. If the buffer cannot accommodate the whole
> sequence, it is rejected completely.
> 
> Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
> ---
>  common/usb_kbd.c | 42 +++++++++++++++++++++++++-----------------
>  1 file changed, 25 insertions(+), 17 deletions(-)
> 
> diff --git a/common/usb_kbd.c b/common/usb_kbd.c
> index 8cbdba6ac2..706cc350a6 100644
> --- a/common/usb_kbd.c
> +++ b/common/usb_kbd.c
> @@ -125,24 +125,32 @@ extern int __maybe_unused net_busy_flag;
>  /* The period of time between two calls of usb_kbd_testc(). */
>  static unsigned long __maybe_unused kbd_testc_tms;
>  
> -/* Puts character in the queue and sets up the in and out pointer. */
> -static void usb_kbd_put_queue(struct usb_kbd_pdata *data, char c)
> +/*
> + * Put characters into ring buffer.
> + *
> + * @data:	private data
> + * @buf		buffer with data to be queued
> + * @count:	number of characters to be queued
> + */
> +static void usb_kbd_put_queue(struct usb_kbd_pdata *data,
> +			      uint8_t *buf, int count)
>  {
> -	if (data->usb_in_pointer == USB_KBD_BUFFER_LEN - 1) {
> -		/* Check for buffer full. */
> -		if (data->usb_out_pointer == 0)
> -			return;
> -
> -		data->usb_in_pointer = 0;
> -	} else {
> -		/* Check for buffer full. */
> -		if (data->usb_in_pointer == data->usb_out_pointer - 1)
> -			return;
> -
> -		data->usb_in_pointer++;
> +	int i, used;
> +
> +	/* Check if buffer holds at least 'count' free slots */
> +	used = data->usb_in_pointer - data->usb_out_pointer;
> +	if (used < 0)
> +		used += USB_KBD_BUFFER_LEN;
> +	if (used + count >= USB_KBD_BUFFER_LEN)
> +		return;
> +
> +	/* Copy to buffer */
> +	for (i = 0; i < count; ++i) {
> +		++data->usb_in_pointer;
> +		if (data->usb_in_pointer == USB_KBD_BUFFER_LEN)
> +			data->usb_in_pointer = 0;
> +		data->usb_kbd_buffer[data->usb_in_pointer] = buf[i];

memcpy() ?

>  	}
> -
> -	data->usb_kbd_buffer[data->usb_in_pointer] = c;
>  }
>  
>  /*
> @@ -237,7 +245,7 @@ static int usb_kbd_translate(struct usb_kbd_pdata *data, unsigned char scancode,
>  	/* Report keycode if any */
>  	if (keycode) {
>  		debug("%c", keycode);
> -		usb_kbd_put_queue(data, keycode);
> +		usb_kbd_put_queue(data, &keycode, 1);
>  	}
>  
>  	return 0;
>
Heinrich Schuchardt Feb. 22, 2018, 6:06 p.m. UTC | #2
On 02/22/2018 03:20 PM, Marek Vasut wrote:
> On 02/22/2018 01:04 PM, Heinrich Schuchardt wrote:
>> The USB keyboard driver provides a ring buffer for key strokes.
>>
>> Function keys cannot be encoded as single bytes. Instead xterm control
>> sequences have to be put into the ring buffer.
> 
> Does it work without xterm or with any other terminal ?
I use two testing environments:

- USB keyboard and HDMI monitor. This does not involve xterm.
- Connection from Linux via serial cable. Linux screen or minicom
   transfer xterm escape sequences when typing special keys.

My target is calling iPXE and Grub as EFI applications. For navigation 
in Grub we need at least up, down, left, right, delete and F10. In 
lib/efi_loader/efi_console.c xterm escape sequences are translated to 
EFI scan codes.

Before the patch series the U-Boot USB keyboard driver signals up, down, 
left and right as non-standard character codes 0x6, 0x2, 0xe, 0x10. 
F1-F12, Insert, Delete, Home, End, Page Up, and Page Down are not supported.

Function cread_line() (in common/cli_readline.c) interprets both xterm 
escape sequences and non-standard control characters provided by the USB 
keyboard driver.

JinHua Luo's patch
Add readline cmdline-editing extension
501090aaa67b6072ebe8b721c8328d32be607660
which introduced command line editing unfortunately does not describe 
why it chose CTRL+B, CTRL+F, CTRL+N, and CTRL+P for navigation. These 
codes are not documented in any README.

> 
>> This preparatory patch changes function usb_kbd_put_queue() to allow adding
>> multiple characters at once. If the buffer cannot accommodate the whole
>> sequence, it is rejected completely.
>>
>> Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
>> ---
>>   common/usb_kbd.c | 42 +++++++++++++++++++++++++-----------------
>>   1 file changed, 25 insertions(+), 17 deletions(-)
>>
>> diff --git a/common/usb_kbd.c b/common/usb_kbd.c
>> index 8cbdba6ac2..706cc350a6 100644
>> --- a/common/usb_kbd.c
>> +++ b/common/usb_kbd.c
>> @@ -125,24 +125,32 @@ extern int __maybe_unused net_busy_flag;
>>   /* The period of time between two calls of usb_kbd_testc(). */
>>   static unsigned long __maybe_unused kbd_testc_tms;
>>   
>> -/* Puts character in the queue and sets up the in and out pointer. */
>> -static void usb_kbd_put_queue(struct usb_kbd_pdata *data, char c)
>> +/*
>> + * Put characters into ring buffer.
>> + *
>> + * @data:	private data
>> + * @buf		buffer with data to be queued
>> + * @count:	number of characters to be queued
>> + */
>> +static void usb_kbd_put_queue(struct usb_kbd_pdata *data,
>> +			      uint8_t *buf, int count)
>>   {
>> -	if (data->usb_in_pointer == USB_KBD_BUFFER_LEN - 1) {
>> -		/* Check for buffer full. */
>> -		if (data->usb_out_pointer == 0)
>> -			return;
>> -
>> -		data->usb_in_pointer = 0;
>> -	} else {
>> -		/* Check for buffer full. */
>> -		if (data->usb_in_pointer == data->usb_out_pointer - 1)
>> -			return;
>> -
>> -		data->usb_in_pointer++;
>> +	int i, used;
>> +
>> +	/* Check if buffer holds at least 'count' free slots */
>> +	used = data->usb_in_pointer - data->usb_out_pointer;
>> +	if (used < 0)
>> +		used += USB_KBD_BUFFER_LEN;
>> +	if (used + count >= USB_KBD_BUFFER_LEN)
>> +		return;
>> +
>> +	/* Copy to buffer */
>> +	for (i = 0; i < count; ++i) {
>> +		++data->usb_in_pointer;
>> +		if (data->usb_in_pointer == USB_KBD_BUFFER_LEN)
>> +			data->usb_in_pointer = 0;
>> +		data->usb_kbd_buffer[data->usb_in_pointer] = buf[i];
> 
> memcpy() ?

Typically we copy only one byte. But escape sequences have maximum 
length are 8 bytes (e.g. CTRL+F8).

We have to consider the case with wrap around. This would require two 
memcpy() calls.

The coding would neither get faster in the average nor less complex 
using memcpy(). So let's keep it as it is.

Best regards

Heinrich

> 
>>   	}
>> -
>> -	data->usb_kbd_buffer[data->usb_in_pointer] = c;
>>   }
>>   
>>   /*
>> @@ -237,7 +245,7 @@ static int usb_kbd_translate(struct usb_kbd_pdata *data, unsigned char scancode,
>>   	/* Report keycode if any */
>>   	if (keycode) {
>>   		debug("%c", keycode);
>> -		usb_kbd_put_queue(data, keycode);
>> +		usb_kbd_put_queue(data, &keycode, 1);
>>   	}
>>   
>>   	return 0;
>>
> 
>
Marek Vasut Feb. 22, 2018, 7:55 p.m. UTC | #3
On 02/22/2018 07:06 PM, Heinrich Schuchardt wrote:
> On 02/22/2018 03:20 PM, Marek Vasut wrote:
>> On 02/22/2018 01:04 PM, Heinrich Schuchardt wrote:
>>> The USB keyboard driver provides a ring buffer for key strokes.
>>>
>>> Function keys cannot be encoded as single bytes. Instead xterm control
>>> sequences have to be put into the ring buffer.
>>
>> Does it work without xterm or with any other terminal ?
> I use two testing environments:
> 
> - USB keyboard and HDMI monitor. This does not involve xterm.

So how are the "xterm control sequences" interpreted then ?
What happens if you use the U-Boot menu, does this work in there too?

> - Connection from Linux via serial cable. Linux screen or minicom
>   transfer xterm escape sequences when typing special keys.

Did you try this ie. on kms console , outside of X11 ?

> My target is calling iPXE and Grub as EFI applications. For navigation
> in Grub we need at least up, down, left, right, delete and F10. In
> lib/efi_loader/efi_console.c xterm escape sequences are translated to
> EFI scan codes.

> Before the patch series the U-Boot USB keyboard driver signals up, down,
> left and right as non-standard character codes 0x6, 0x2, 0xe, 0x10.
> F1-F12, Insert, Delete, Home, End, Page Up, and Page Down are not
> supported.
> 
> Function cread_line() (in common/cli_readline.c) interprets both xterm
> escape sequences and non-standard control characters provided by the USB
> keyboard driver.

Wait, are those xterm or vt100 sequences ?

> JinHua Luo's patch
> Add readline cmdline-editing extension
> 501090aaa67b6072ebe8b721c8328d32be607660
> which introduced command line editing unfortunately does not describe
> why it chose CTRL+B, CTRL+F, CTRL+N, and CTRL+P for navigation. These
> codes are not documented in any README.
> 
>>
>>> This preparatory patch changes function usb_kbd_put_queue() to allow
>>> adding
>>> multiple characters at once. If the buffer cannot accommodate the whole
>>> sequence, it is rejected completely.
>>>
>>> Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
>>> ---
>>>   common/usb_kbd.c | 42 +++++++++++++++++++++++++-----------------
>>>   1 file changed, 25 insertions(+), 17 deletions(-)
>>>
>>> diff --git a/common/usb_kbd.c b/common/usb_kbd.c
>>> index 8cbdba6ac2..706cc350a6 100644
>>> --- a/common/usb_kbd.c
>>> +++ b/common/usb_kbd.c
>>> @@ -125,24 +125,32 @@ extern int __maybe_unused net_busy_flag;
>>>   /* The period of time between two calls of usb_kbd_testc(). */
>>>   static unsigned long __maybe_unused kbd_testc_tms;
>>>   -/* Puts character in the queue and sets up the in and out pointer. */
>>> -static void usb_kbd_put_queue(struct usb_kbd_pdata *data, char c)
>>> +/*
>>> + * Put characters into ring buffer.
>>> + *
>>> + * @data:    private data
>>> + * @buf        buffer with data to be queued
>>> + * @count:    number of characters to be queued
>>> + */
>>> +static void usb_kbd_put_queue(struct usb_kbd_pdata *data,
>>> +                  uint8_t *buf, int count)
>>>   {
>>> -    if (data->usb_in_pointer == USB_KBD_BUFFER_LEN - 1) {
>>> -        /* Check for buffer full. */
>>> -        if (data->usb_out_pointer == 0)
>>> -            return;
>>> -
>>> -        data->usb_in_pointer = 0;
>>> -    } else {
>>> -        /* Check for buffer full. */
>>> -        if (data->usb_in_pointer == data->usb_out_pointer - 1)
>>> -            return;
>>> -
>>> -        data->usb_in_pointer++;
>>> +    int i, used;
>>> +
>>> +    /* Check if buffer holds at least 'count' free slots */
>>> +    used = data->usb_in_pointer - data->usb_out_pointer;
>>> +    if (used < 0)
>>> +        used += USB_KBD_BUFFER_LEN;
>>> +    if (used + count >= USB_KBD_BUFFER_LEN)
>>> +        return;
>>> +
>>> +    /* Copy to buffer */
>>> +    for (i = 0; i < count; ++i) {
>>> +        ++data->usb_in_pointer;
>>> +        if (data->usb_in_pointer == USB_KBD_BUFFER_LEN)
>>> +            data->usb_in_pointer = 0;
>>> +        data->usb_kbd_buffer[data->usb_in_pointer] = buf[i];
>>
>> memcpy() ?
> 
> Typically we copy only one byte. But escape sequences have maximum
> length are 8 bytes (e.g. CTRL+F8).
> 
> We have to consider the case with wrap around. This would require two
> memcpy() calls.
> 
> The coding would neither get faster in the average nor less complex
> using memcpy(). So let's keep it as it is.

I suspect this block of code needs cleanup .
Heinrich Schuchardt Feb. 22, 2018, 8:53 p.m. UTC | #4
On 02/22/2018 08:55 PM, Marek Vasut wrote:
> On 02/22/2018 07:06 PM, Heinrich Schuchardt wrote:
>> On 02/22/2018 03:20 PM, Marek Vasut wrote:
>>> On 02/22/2018 01:04 PM, Heinrich Schuchardt wrote:
>>>> The USB keyboard driver provides a ring buffer for key strokes.
>>>>
>>>> Function keys cannot be encoded as single bytes. Instead xterm control
>>>> sequences have to be put into the ring buffer.
>>>
>>> Does it work without xterm or with any other terminal ?
>> I use two testing environments:
>>
>> - USB keyboard and HDMI monitor. This does not involve xterm.
> 
> So how are the "xterm control sequences" interpreted then?

I already pointed you to U-Boot function cread_line().
Here only the sequences for left, right, up, and down are used.

When starting an EFI application the xterm escape sequences are
translated to EFI scan codes. See lib/efi_loader/efi_console.c

> What happens if you use the U-Boot menu, does this work in there too?

Function bootmenu_loop() only looks for
ESC [ A and
ESC [ B

So without the patch series you are not able to navigate inside the 
U-Boot menu using a USB keyboard.

> 
>> - Connection from Linux via serial cable. Linux screen or minicom
>>    transfer xterm escape sequences when typing special keys.
> 
> Did you try this ie. on kms console , outside of X11 ?

I never heard of a kms console.

If I boot into the plain Linux console (i.e. without X11), key 
pressesare still provided as xterm escape sequences.

> 
>> My target is calling iPXE and Grub as EFI applications. For navigation
>> in Grub we need at least up, down, left, right, delete and F10. In
>> lib/efi_loader/efi_console.c xterm escape sequences are translated to
>> EFI scan codes.
> 
>> Before the patch series the U-Boot USB keyboard driver signals up, down,
>> left and right as non-standard character codes 0x6, 0x2, 0xe, 0x10.
>> F1-F12, Insert, Delete, Home, End, Page Up, and Page Down are not
>> supported.
>>
>> Function cread_line() (in common/cli_readline.c) interprets both xterm
>> escape sequences and non-standard control characters provided by the USB
>> keyboard driver.
> 
> Wait, are those xterm or vt100 sequences ?

VT100 largely overlaps with xterm. See
https://invisible-island.net/xterm/ctlseqs/ctlseqs.pdf

> 
>> JinHua Luo's patch
>> Add readline cmdline-editing extension
>> 501090aaa67b6072ebe8b721c8328d32be607660
>> which introduced command line editing unfortunately does not describe
>> why it chose CTRL+B, CTRL+F, CTRL+N, and CTRL+P for navigation. These
>> codes are not documented in any README.
>>
>>>
>>>> This preparatory patch changes function usb_kbd_put_queue() to allow
>>>> adding
>>>> multiple characters at once. If the buffer cannot accommodate the whole
>>>> sequence, it is rejected completely.
>>>>
>>>> Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
>>>> ---
>>>>    common/usb_kbd.c | 42 +++++++++++++++++++++++++-----------------
>>>>    1 file changed, 25 insertions(+), 17 deletions(-)
>>>>
>>>> diff --git a/common/usb_kbd.c b/common/usb_kbd.c
>>>> index 8cbdba6ac2..706cc350a6 100644
>>>> --- a/common/usb_kbd.c
>>>> +++ b/common/usb_kbd.c
>>>> @@ -125,24 +125,32 @@ extern int __maybe_unused net_busy_flag;
>>>>    /* The period of time between two calls of usb_kbd_testc(). */
>>>>    static unsigned long __maybe_unused kbd_testc_tms;
>>>>    -/* Puts character in the queue and sets up the in and out pointer. */
>>>> -static void usb_kbd_put_queue(struct usb_kbd_pdata *data, char c)
>>>> +/*
>>>> + * Put characters into ring buffer.
>>>> + *
>>>> + * @data:    private data
>>>> + * @buf        buffer with data to be queued
>>>> + * @count:    number of characters to be queued
>>>> + */
>>>> +static void usb_kbd_put_queue(struct usb_kbd_pdata *data,
>>>> +                  uint8_t *buf, int count)
>>>>    {
>>>> -    if (data->usb_in_pointer == USB_KBD_BUFFER_LEN - 1) {
>>>> -        /* Check for buffer full. */
>>>> -        if (data->usb_out_pointer == 0)
>>>> -            return;
>>>> -
>>>> -        data->usb_in_pointer = 0;
>>>> -    } else {
>>>> -        /* Check for buffer full. */
>>>> -        if (data->usb_in_pointer == data->usb_out_pointer - 1)
>>>> -            return;
>>>> -
>>>> -        data->usb_in_pointer++;
>>>> +    int i, used;
>>>> +
>>>> +    /* Check if buffer holds at least 'count' free slots */
>>>> +    used = data->usb_in_pointer - data->usb_out_pointer;
>>>> +    if (used < 0)
>>>> +        used += USB_KBD_BUFFER_LEN;
>>>> +    if (used + count >= USB_KBD_BUFFER_LEN)
>>>> +        return;
>>>> +
>>>> +    /* Copy to buffer */
>>>> +    for (i = 0; i < count; ++i) {
>>>> +        ++data->usb_in_pointer;
>>>> +        if (data->usb_in_pointer == USB_KBD_BUFFER_LEN)
>>>> +            data->usb_in_pointer = 0;
>>>> +        data->usb_kbd_buffer[data->usb_in_pointer] = buf[i];
>>>
>>> memcpy() ?
>>
>> Typically we copy only one byte. But escape sequences have a maximum
>> length of 8 bytes (e.g. CTRL+F8).
>>
>> We have to consider the case with wrap around. This would require two
>> memcpy() calls.
>>
>> The coding would neither get faster in the average nor less complex
>> using memcpy(). So let's keep it as it is.
> 
> I suspect this block of code needs cleanup .
> 

Could you, please, give some indication of what you dislike.

Regards

Heinrich
Marek Vasut Feb. 22, 2018, 11:02 p.m. UTC | #5
On 02/22/2018 09:53 PM, Heinrich Schuchardt wrote:
> On 02/22/2018 08:55 PM, Marek Vasut wrote:
>> On 02/22/2018 07:06 PM, Heinrich Schuchardt wrote:
>>> On 02/22/2018 03:20 PM, Marek Vasut wrote:
>>>> On 02/22/2018 01:04 PM, Heinrich Schuchardt wrote:
>>>>> The USB keyboard driver provides a ring buffer for key strokes.
>>>>>
>>>>> Function keys cannot be encoded as single bytes. Instead xterm control
>>>>> sequences have to be put into the ring buffer.
>>>>
>>>> Does it work without xterm or with any other terminal ?
>>> I use two testing environments:
>>>
>>> - USB keyboard and HDMI monitor. This does not involve xterm.
>>
>> So how are the "xterm control sequences" interpreted then?
> 
> I already pointed you to U-Boot function cread_line().
> Here only the sequences for left, right, up, and down are used.
> 
> When starting an EFI application the xterm escape sequences are
> translated to EFI scan codes. See lib/efi_loader/efi_console.c

So this is only usable if you have display connected to the board ?

>> What happens if you use the U-Boot menu, does this work in there too?
> 
> Function bootmenu_loop() only looks for
> ESC [ A and
> ESC [ B
> 
> So without the patch series you are not able to navigate inside the
> U-Boot menu using a USB keyboard.

Ha

>>> - Connection from Linux via serial cable. Linux screen or minicom
>>>    transfer xterm escape sequences when typing special keys.
>>
>> Did you try this ie. on kms console , outside of X11 ?
> 
> I never heard of a kms console.
> 
> If I boot into the plain Linux console (i.e. without X11), key
> pressesare still provided as xterm escape sequences.

But there is no xterm ?

>>> My target is calling iPXE and Grub as EFI applications. For navigation
>>> in Grub we need at least up, down, left, right, delete and F10. In
>>> lib/efi_loader/efi_console.c xterm escape sequences are translated to
>>> EFI scan codes.
>>
>>> Before the patch series the U-Boot USB keyboard driver signals up, down,
>>> left and right as non-standard character codes 0x6, 0x2, 0xe, 0x10.
>>> F1-F12, Insert, Delete, Home, End, Page Up, and Page Down are not
>>> supported.
>>>
>>> Function cread_line() (in common/cli_readline.c) interprets both xterm
>>> escape sequences and non-standard control characters provided by the USB
>>> keyboard driver.
>>
>> Wait, are those xterm or vt100 sequences ?
> 
> VT100 largely overlaps with xterm. See
> https://invisible-island.net/xterm/ctlseqs/ctlseqs.pdf

So vt100 , OK.

>>> JinHua Luo's patch
>>> Add readline cmdline-editing extension
>>> 501090aaa67b6072ebe8b721c8328d32be607660
>>> which introduced command line editing unfortunately does not describe
>>> why it chose CTRL+B, CTRL+F, CTRL+N, and CTRL+P for navigation. These
>>> codes are not documented in any README.
>>>
>>>>
>>>>> This preparatory patch changes function usb_kbd_put_queue() to allow
>>>>> adding
>>>>> multiple characters at once. If the buffer cannot accommodate the
>>>>> whole
>>>>> sequence, it is rejected completely.
>>>>>
>>>>> Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
>>>>> ---
>>>>>    common/usb_kbd.c | 42 +++++++++++++++++++++++++-----------------
>>>>>    1 file changed, 25 insertions(+), 17 deletions(-)
>>>>>
>>>>> diff --git a/common/usb_kbd.c b/common/usb_kbd.c
>>>>> index 8cbdba6ac2..706cc350a6 100644
>>>>> --- a/common/usb_kbd.c
>>>>> +++ b/common/usb_kbd.c
>>>>> @@ -125,24 +125,32 @@ extern int __maybe_unused net_busy_flag;
>>>>>    /* The period of time between two calls of usb_kbd_testc(). */
>>>>>    static unsigned long __maybe_unused kbd_testc_tms;
>>>>>    -/* Puts character in the queue and sets up the in and out
>>>>> pointer. */
>>>>> -static void usb_kbd_put_queue(struct usb_kbd_pdata *data, char c)
>>>>> +/*
>>>>> + * Put characters into ring buffer.
>>>>> + *
>>>>> + * @data:    private data
>>>>> + * @buf        buffer with data to be queued
>>>>> + * @count:    number of characters to be queued
>>>>> + */
>>>>> +static void usb_kbd_put_queue(struct usb_kbd_pdata *data,
>>>>> +                  uint8_t *buf, int count)
>>>>>    {
>>>>> -    if (data->usb_in_pointer == USB_KBD_BUFFER_LEN - 1) {
>>>>> -        /* Check for buffer full. */
>>>>> -        if (data->usb_out_pointer == 0)
>>>>> -            return;
>>>>> -
>>>>> -        data->usb_in_pointer = 0;
>>>>> -    } else {
>>>>> -        /* Check for buffer full. */
>>>>> -        if (data->usb_in_pointer == data->usb_out_pointer - 1)
>>>>> -            return;
>>>>> -
>>>>> -        data->usb_in_pointer++;
>>>>> +    int i, used;
>>>>> +
>>>>> +    /* Check if buffer holds at least 'count' free slots */
>>>>> +    used = data->usb_in_pointer - data->usb_out_pointer;
>>>>> +    if (used < 0)
>>>>> +        used += USB_KBD_BUFFER_LEN;
>>>>> +    if (used + count >= USB_KBD_BUFFER_LEN)
>>>>> +        return;
>>>>> +
>>>>> +    /* Copy to buffer */
>>>>> +    for (i = 0; i < count; ++i) {
>>>>> +        ++data->usb_in_pointer;
>>>>> +        if (data->usb_in_pointer == USB_KBD_BUFFER_LEN)
>>>>> +            data->usb_in_pointer = 0;
>>>>> +        data->usb_kbd_buffer[data->usb_in_pointer] = buf[i];
>>>>
>>>> memcpy() ?
>>>
>>> Typically we copy only one byte. But escape sequences have a maximum
>>> length of 8 bytes (e.g. CTRL+F8).
>>>
>>> We have to consider the case with wrap around. This would require two
>>> memcpy() calls.
>>>
>>> The coding would neither get faster in the average nor less complex
>>> using memcpy(). So let's keep it as it is.
>>
>> I suspect this block of code needs cleanup .
>>
> 
> Could you, please, give some indication of what you dislike.

At least the part which looks like ad-hoc implementation of memcpy() ,
any other cleanups are welcome.
Heinrich Schuchardt Feb. 23, 2018, 5:50 a.m. UTC | #6
On 02/23/2018 12:02 AM, Marek Vasut wrote:
> On 02/22/2018 09:53 PM, Heinrich Schuchardt wrote:
>> On 02/22/2018 08:55 PM, Marek Vasut wrote:
>>> On 02/22/2018 07:06 PM, Heinrich Schuchardt wrote:
>>>> On 02/22/2018 03:20 PM, Marek Vasut wrote:
>>>>> On 02/22/2018 01:04 PM, Heinrich Schuchardt wrote:
>>>>>> The USB keyboard driver provides a ring buffer for key strokes.
>>>>>>
>>>>>> Function keys cannot be encoded as single bytes. Instead xterm control
>>>>>> sequences have to be put into the ring buffer.
>>>>>
>>>>> Does it work without xterm or with any other terminal ?
>>>> I use two testing environments:
>>>>
>>>> - USB keyboard and HDMI monitor. This does not involve xterm.
>>>
>>> So how are the "xterm control sequences" interpreted then?
>>
>> I already pointed you to U-Boot function cread_line().
>> Here only the sequences for left, right, up, and down are used.
>>
>> When starting an EFI application the xterm escape sequences are
>> translated to EFI scan codes. See lib/efi_loader/efi_console.c
> 
> So this is only usable if you have display connected to the board ?

Why? We are talking about input.

Neither local nor remote display is needed to hit the F10 key on a USB 
keyboard.

> 
>>> What happens if you use the U-Boot menu, does this work in there too?
>>
>> Function bootmenu_loop() only looks for
>> ESC [ A and
>> ESC [ B
>>
>> So without the patch series you are not able to navigate inside the
>> U-Boot menu using a USB keyboard.
> 
> Ha
> 
>>>> - Connection from Linux via serial cable. Linux screen or minicom
>>>>     transfer xterm escape sequences when typing special keys.
>>>
>>> Did you try this ie. on kms console , outside of X11 ?
>>
>> I never heard of a kms console.
>>
>> If I boot into the plain Linux console (i.e. without X11), key
>> pressesare still provided as xterm escape sequences.
> 
> But there is no xterm ?
> 
>>>> My target is calling iPXE and Grub as EFI applications. For navigation
>>>> in Grub we need at least up, down, left, right, delete and F10. In
>>>> lib/efi_loader/efi_console.c xterm escape sequences are translated to
>>>> EFI scan codes.
>>>
>>>> Before the patch series the U-Boot USB keyboard driver signals up, down,
>>>> left and right as non-standard character codes 0x6, 0x2, 0xe, 0x10.
>>>> F1-F12, Insert, Delete, Home, End, Page Up, and Page Down are not
>>>> supported.
>>>>
>>>> Function cread_line() (in common/cli_readline.c) interprets both xterm
>>>> escape sequences and non-standard control characters provided by the USB
>>>> keyboard driver.
>>>
>>> Wait, are those xterm or vt100 sequences ?
>>
>> VT100 largely overlaps with xterm. See
>> https://invisible-island.net/xterm/ctlseqs/ctlseqs.pdf
> 
> So vt100 , OK.
> 
>>>> JinHua Luo's patch
>>>> Add readline cmdline-editing extension
>>>> 501090aaa67b6072ebe8b721c8328d32be607660
>>>> which introduced command line editing unfortunately does not describe
>>>> why it chose CTRL+B, CTRL+F, CTRL+N, and CTRL+P for navigation. These
>>>> codes are not documented in any README.
>>>>
>>>>>
>>>>>> This preparatory patch changes function usb_kbd_put_queue() to allow
>>>>>> adding
>>>>>> multiple characters at once. If the buffer cannot accommodate the
>>>>>> whole
>>>>>> sequence, it is rejected completely.
>>>>>>
>>>>>> Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
>>>>>> ---
>>>>>>     common/usb_kbd.c | 42 +++++++++++++++++++++++++-----------------
>>>>>>     1 file changed, 25 insertions(+), 17 deletions(-)
>>>>>>
>>>>>> diff --git a/common/usb_kbd.c b/common/usb_kbd.c
>>>>>> index 8cbdba6ac2..706cc350a6 100644
>>>>>> --- a/common/usb_kbd.c
>>>>>> +++ b/common/usb_kbd.c
>>>>>> @@ -125,24 +125,32 @@ extern int __maybe_unused net_busy_flag;
>>>>>>     /* The period of time between two calls of usb_kbd_testc(). */
>>>>>>     static unsigned long __maybe_unused kbd_testc_tms;
>>>>>>     -/* Puts character in the queue and sets up the in and out
>>>>>> pointer. */
>>>>>> -static void usb_kbd_put_queue(struct usb_kbd_pdata *data, char c)
>>>>>> +/*
>>>>>> + * Put characters into ring buffer.
>>>>>> + *
>>>>>> + * @data:    private data
>>>>>> + * @buf        buffer with data to be queued
>>>>>> + * @count:    number of characters to be queued
>>>>>> + */
>>>>>> +static void usb_kbd_put_queue(struct usb_kbd_pdata *data,
>>>>>> +                  uint8_t *buf, int count)
>>>>>>     {
>>>>>> -    if (data->usb_in_pointer == USB_KBD_BUFFER_LEN - 1) {
>>>>>> -        /* Check for buffer full. */
>>>>>> -        if (data->usb_out_pointer == 0)
>>>>>> -            return;
>>>>>> -
>>>>>> -        data->usb_in_pointer = 0;
>>>>>> -    } else {
>>>>>> -        /* Check for buffer full. */
>>>>>> -        if (data->usb_in_pointer == data->usb_out_pointer - 1)
>>>>>> -            return;
>>>>>> -
>>>>>> -        data->usb_in_pointer++;
>>>>>> +    int i, used;
>>>>>> +
>>>>>> +    /* Check if buffer holds at least 'count' free slots */
>>>>>> +    used = data->usb_in_pointer - data->usb_out_pointer;
>>>>>> +    if (used < 0)
>>>>>> +        used += USB_KBD_BUFFER_LEN;
>>>>>> +    if (used + count >= USB_KBD_BUFFER_LEN)
>>>>>> +        return;
>>>>>> +
>>>>>> +    /* Copy to buffer */
>>>>>> +    for (i = 0; i < count; ++i) {
>>>>>> +        ++data->usb_in_pointer;
>>>>>> +        if (data->usb_in_pointer == USB_KBD_BUFFER_LEN)
>>>>>> +            data->usb_in_pointer = 0;
>>>>>> +        data->usb_kbd_buffer[data->usb_in_pointer] = buf[i];
>>>>>
>>>>> memcpy() ?
>>>>
>>>> Typically we copy only one byte. But escape sequences have a maximum
>>>> length of 8 bytes (e.g. CTRL+F8).
>>>>
>>>> We have to consider the case with wrap around. This would require two
>>>> memcpy() calls.
>>>>
>>>> The coding would neither get faster in the average nor less complex
>>>> using memcpy(). So let's keep it as it is.
>>>
>>> I suspect this block of code needs cleanup .
>>>
>>
>> Could you, please, give some indication of what you dislike.
> 
> At least the part which looks like ad-hoc implementation of memcpy() ,
> any other cleanups are welcome.
> 

Do you really want that ugly monster below for typically copying a 
single byte?

As said it is slower, has more lines, and gives a larger executable.

int remaining;

/* Copy to buffer */
remaining = data->usb_in_pointer + count - USB_KBD_BUFFER_LEN;
if (remaining < 0)
	remaining = 0;
memcpy(&usb_kbd_buffer[data->usb_in_pointer], buf, count - remaining);
if (remaining)
	memcpy(usb_kbd_buffer, buf + count - remaining, remaining);
data->usb_in_pointer += count;
if (data->usb_in_pointer >= USB_KBD_BUFFER_LEN)
	data->usb_in_pointer -= USB_KBD_BUFFER_LEN;
		
Best regards

Heinrich
Marek Vasut Feb. 23, 2018, 6:04 a.m. UTC | #7
On 02/23/2018 06:50 AM, Heinrich Schuchardt wrote:
[...]
>>> When starting an EFI application the xterm escape sequences are
>>> translated to EFI scan codes. See lib/efi_loader/efi_console.c
>>
>> So this is only usable if you have display connected to the board ?
> 
> Why? We are talking about input.
> 
> Neither local nor remote display is needed to hit the F10 key on a USB
> keyboard.

What confused me was the constant usage of xterm control sequences to
describe terminal control sequences. Now it makes sense.

[...]

>>>>>>> +    /* Copy to buffer */
>>>>>>> +    for (i = 0; i < count; ++i) {
>>>>>>> +        ++data->usb_in_pointer;
>>>>>>> +        if (data->usb_in_pointer == USB_KBD_BUFFER_LEN)
>>>>>>> +            data->usb_in_pointer = 0;
>>>>>>> +        data->usb_kbd_buffer[data->usb_in_pointer] = buf[i];
>>>>>>
>>>>>> memcpy() ?
>>>>>
>>>>> Typically we copy only one byte. But escape sequences have a maximum
>>>>> length of 8 bytes (e.g. CTRL+F8).
>>>>>
>>>>> We have to consider the case with wrap around. This would require two
>>>>> memcpy() calls.
>>>>>
>>>>> The coding would neither get faster in the average nor less complex
>>>>> using memcpy(). So let's keep it as it is.
>>>>
>>>> I suspect this block of code needs cleanup .
>>>>
>>>
>>> Could you, please, give some indication of what you dislike.
>>
>> At least the part which looks like ad-hoc implementation of memcpy() ,
>> any other cleanups are welcome.
>>
> 
> Do you really want that ugly monster below for typically copying a
> single byte?
> 
> As said it is slower, has more lines, and gives a larger executable.
> 
> int remaining;
> 
> /* Copy to buffer */
> remaining = data->usb_in_pointer + count - USB_KBD_BUFFER_LEN;
> if (remaining < 0)
>     remaining = 0;
> memcpy(&usb_kbd_buffer[data->usb_in_pointer], buf, count - remaining);
> if (remaining)
>     memcpy(usb_kbd_buffer, buf + count - remaining, remaining);
> data->usb_in_pointer += count;
> if (data->usb_in_pointer >= USB_KBD_BUFFER_LEN)
>     data->usb_in_pointer -= USB_KBD_BUFFER_LEN;

Can the code be tweaked so it doesn't use the circular buffer, but a
linear one , thus two memcpy()s are not needed ?

The whole usb keyboard code is not nice and could use some cleanup.
Heinrich Schuchardt Feb. 23, 2018, 7:09 a.m. UTC | #8
On 02/23/2018 07:04 AM, Marek Vasut wrote:
> On 02/23/2018 06:50 AM, Heinrich Schuchardt wrote:
> [...]
>>>> When starting an EFI application the xterm escape sequences are
>>>> translated to EFI scan codes. See lib/efi_loader/efi_console.c
>>>
>>> So this is only usable if you have display connected to the board ?
>>
>> Why? We are talking about input.
>>
>> Neither local nor remote display is needed to hit the F10 key on a USB
>> keyboard.
> 
> What confused me was the constant usage of xterm control sequences to
> describe terminal control sequences. Now it makes sense.
> 
> [...]
> 
>>>>>>>> +    /* Copy to buffer */
>>>>>>>> +    for (i = 0; i < count; ++i) {
>>>>>>>> +        ++data->usb_in_pointer;
>>>>>>>> +        if (data->usb_in_pointer == USB_KBD_BUFFER_LEN)
>>>>>>>> +            data->usb_in_pointer = 0;
>>>>>>>> +        data->usb_kbd_buffer[data->usb_in_pointer] = buf[i];
>>>>>>>
>>>>>>> memcpy() ?
>>>>>>
>>>>>> Typically we copy only one byte. But escape sequences have a maximum
>>>>>> length of 8 bytes (e.g. CTRL+F8).
>>>>>>
>>>>>> We have to consider the case with wrap around. This would require two
>>>>>> memcpy() calls.
>>>>>>
>>>>>> The coding would neither get faster in the average nor less complex
>>>>>> using memcpy(). So let's keep it as it is.
>>>>>
>>>>> I suspect this block of code needs cleanup .
>>>>>
>>>>
>>>> Could you, please, give some indication of what you dislike.
>>>
>>> At least the part which looks like ad-hoc implementation of memcpy() ,
>>> any other cleanups are welcome.
>>>
>>
>> Do you really want that ugly monster below for typically copying a
>> single byte?
>>
>> As said it is slower, has more lines, and gives a larger executable.
>>
>> int remaining;
>>
>> /* Copy to buffer */
>> remaining = data->usb_in_pointer + count - USB_KBD_BUFFER_LEN;
>> if (remaining < 0)
>>      remaining = 0;
>> memcpy(&usb_kbd_buffer[data->usb_in_pointer], buf, count - remaining);
>> if (remaining)
>>      memcpy(usb_kbd_buffer, buf + count - remaining, remaining);
>> data->usb_in_pointer += count;
>> if (data->usb_in_pointer >= USB_KBD_BUFFER_LEN)
>>      data->usb_in_pointer -= USB_KBD_BUFFER_LEN;
> 
> Can the code be tweaked so it doesn't use the circular buffer, but a
> linear one , thus two memcpy()s are not needed ?

This would require copying the whole buffer with memcpy() when 
withdrawing a byte.

Somehow we tend to reinvent the wheel. Let's use lib/circbuf.c here.

Regards

Heinrich

> 
> The whole usb keyboard code is not nice and could use some cleanup.
>
diff mbox series

Patch

diff --git a/common/usb_kbd.c b/common/usb_kbd.c
index 8cbdba6ac2..706cc350a6 100644
--- a/common/usb_kbd.c
+++ b/common/usb_kbd.c
@@ -125,24 +125,32 @@  extern int __maybe_unused net_busy_flag;
 /* The period of time between two calls of usb_kbd_testc(). */
 static unsigned long __maybe_unused kbd_testc_tms;
 
-/* Puts character in the queue and sets up the in and out pointer. */
-static void usb_kbd_put_queue(struct usb_kbd_pdata *data, char c)
+/*
+ * Put characters into ring buffer.
+ *
+ * @data:	private data
+ * @buf		buffer with data to be queued
+ * @count:	number of characters to be queued
+ */
+static void usb_kbd_put_queue(struct usb_kbd_pdata *data,
+			      uint8_t *buf, int count)
 {
-	if (data->usb_in_pointer == USB_KBD_BUFFER_LEN - 1) {
-		/* Check for buffer full. */
-		if (data->usb_out_pointer == 0)
-			return;
-
-		data->usb_in_pointer = 0;
-	} else {
-		/* Check for buffer full. */
-		if (data->usb_in_pointer == data->usb_out_pointer - 1)
-			return;
-
-		data->usb_in_pointer++;
+	int i, used;
+
+	/* Check if buffer holds at least 'count' free slots */
+	used = data->usb_in_pointer - data->usb_out_pointer;
+	if (used < 0)
+		used += USB_KBD_BUFFER_LEN;
+	if (used + count >= USB_KBD_BUFFER_LEN)
+		return;
+
+	/* Copy to buffer */
+	for (i = 0; i < count; ++i) {
+		++data->usb_in_pointer;
+		if (data->usb_in_pointer == USB_KBD_BUFFER_LEN)
+			data->usb_in_pointer = 0;
+		data->usb_kbd_buffer[data->usb_in_pointer] = buf[i];
 	}
-
-	data->usb_kbd_buffer[data->usb_in_pointer] = c;
 }
 
 /*
@@ -237,7 +245,7 @@  static int usb_kbd_translate(struct usb_kbd_pdata *data, unsigned char scancode,
 	/* Report keycode if any */
 	if (keycode) {
 		debug("%c", keycode);
-		usb_kbd_put_queue(data, keycode);
+		usb_kbd_put_queue(data, &keycode, 1);
 	}
 
 	return 0;