input: Use finer grain udelays while waitng for the i8042 keyboard buffer to empty
PATCH 1/5 input: Use finer grain udelays while waitng for the i8042 keyboard buffer to empty
From: Gabe Black <[email protected]>
On x86, the i8042 keyboard controller driver frequently waits for the keyboard input buffer to be empty to make sure the controller has had a chance to process the data it was given. The way the delay loop was structured, if the controller hadn't cleared the corresponding status bit immediately, it would wait 1ms before checking again. If the keyboard responded quickly but not instantly, the driver would still wait a full 1ms when perhaps 1us would have been sufficient. Because udelay is a busy wait anyway, this change decreases the delay between checks to 1us.
Also, this change gets rid of a hardcoded 250ms delay.
On Stumpy, this saves 100-150ms during boot.
--- drivers/input/i8042.c | 7 ++----- 1 files changed, 2 insertions(+), 5 deletions(-)
drivers/input/i8042.c +2 -5
@@ -607,11 +607,10 @@ static void kbd_led_set(void)static int kbd_input_empty (void ) { -int kbdTimeout =KBD_TIMEOUT ; +int kbdTimeout =KBD_TIMEOUT *1000 ; -/* wait for input buf empty */ while ((in8 (I8042_STATUS_REG ) &0x02 ) && kbdTimeout--) -udelay (1000 ); +udelay (1 );return kbdTimeout !=-1 ; }
@@ -625,8 +624,6 @@ static int kbd_reset(void)out8 (I8042_DATA_REG ,0xff ); -udelay (250000 ); -if (kbd_input_empty () ==0 )return -1 ;
Signature · 1 line
1.7.7.3
PATCH 2/5 input: Provide a board specific mechanism to decide whether to skip i8042 init
From: Gabe Black <[email protected]>
This change adds a board overridable function which can be used to decide whether or not to initialize the i8042 keyboard controller. On systems where it isn't actually connected to anything, this can save a significant amount of boot time.
On Stumpy, this saves about 200ms on boot.
--- drivers/input/i8042.c | 13 ++++++++++++- 1 files changed, 12 insertions(+), 1 deletions(-)
drivers/input/i8042.c +12 -1
@@ -320,6 +320,17 @@ static int kbd_controller_present(void)return in8 (I8042_STATUS_REG ) !=0xff ; } +/* +* Implement a weak default function for boards that optionally +* need to skip the i8042 initialization. +*/ +int __board_i8042_skip (void ) +{ +/* As default, don't skip */ +return 0 ; +} +int board_i8042_skip (void ) __attribute__((weak,alias ("__board_i8042_skip" ))); +/******************************************************************************* * * i8042_kbd_init - reset keyboard and init state flags
@@ -329,7 +340,7 @@ int i8042_kbd_init(void)int keymap, try;char *penv; -if (!kbd_controller_present ()) +if (!kbd_controller_present () ||board_i8042_skip ())return -1 ;#ifdef CONFIG_USE_CPCIDVI
Signature · 1 line
1.7.7.3
PATCH 2/5 input: Provide a board specific mechanism to decide whether to skip i8042 init
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Quoted 19 lines · Simon Glass
From: Gabe Black <[email protected]>
This change adds a board overridable function which can be used to decide whether or not to initialize the i8042 keyboard controller. On systems where it isn't actually connected to anything, this can save a significant amount of boot time.
On Stumpy, this saves about 200ms on boot.
Signed-off-by Gabe Black <[email protected]> Signed-off-by:Simon Glass <[email protected]> ---
drivers/input/i8042.c| 13
++++++++++++- 1 files changed, 12 insertions(+), 1 deletions(-)drivers/input/i8042.c index renamed from drivers/input/i8042.c +0
-099254e4..cae2d0a 100644 ---
a/drivers/input/i8042.c+++b/drivers/input/i8042.c@@ -320,6 +320,17 @@ static intkbd_controller_present(void)returnin8(I8042_STATUS_REG)!=0xff; }
Quoted 5 lines
+/* + * Implement a weak default function for boards that optionally + * need to skip the i8042 initialization. + */ +int
__board_i8042_skip(void)+{ + /* As default, don't skip */ + return
0; +} +intboard_i8042_skip(void)__attribute__((weak, alias("__board_i8042_skip")));
Please add <linux/compiler.h> and use __weak directly, thanks.
- --
Tom
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://www.enigmail.net/
iQIcBAEBAgAGBQJQeD/QAAoJENk4IS6UOR1WVMsP/RJTlWaTvF56K6H75WbjK7l5 xE7zeAeCS4gbM1CS0fEv1X4296L7oWUUUkw73gwSEAxd2CxOj96HrhJI0WQIqZ/a m6ysfwswzY92oqXJGxnWnLiZzd0JUR/QHZAM7U0tX1yHFsYrycEtuq+JvfMm5BU7 1ozqrN0SoFPa8ZBq0GpnXhDsGdMApucDBkbDv3cgHTYPkOlfh3gLpbz/dkWKxrCv NBwKvZgVMtEPf9hZf5CLuB2ghfWIRyP50Bf99nKhV+gdLGtrEbboHkMMXEc2Z1ex foEMqpmSiMVd9yMRqVEIM3sWwnapqAZVn3wQLoq5Kz+YGS/9e0c9t95ck+CmndiM kJmrx/LZ/XSGzjLrKC3MWLWC/KUS2hHqj4AfYUf1kL5lPuHM24c+oSRfOjogkaqR bMJZ9ii/kYcQJry/dAYTjFyEa120X48y46e2bNcMhWVZh48A6VpJkFILb1Ga4tEo ss+hMBX/tiMNp8eoOR7y1n+A+94r3ABKUrLapjfVKg+qXeufrMyotBVfPY35hWnP qLNVlPpdEF7nP1Wt22OB9s6bBcI6dCrNuL75Ym6wJ3DYnpqU8Y8f3HihwL7cBy7F o1Zpo0bzazNfy722IYphWu0O3hihIQ11fRpAndVemUzjaXP/kKxaVhiDCj28xHup 9zGuTm7SW/liJTXp4cc8
=5tNx
-----END PGP SIGNATURE-----
PATCH 2/5 input: Provide a board specific mechanism to decide whether to skip i8042 init
Hi Tom,
Quoted 23 lines · Tom Rini
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1Quoted 19 lines · Simon Glass
From: Gabe Black <[email protected]>
This change adds a board overridable function which can be used to decide whether or not to initialize the i8042 keyboard controller. On systems where it isn't actually connected to anything, this can save a significant amount of boot time.
On Stumpy, this saves about 200ms on boot.
Signed-off-by Gabe Black <[email protected]> Signed-off-by:Simon Glass <[email protected]> ---
drivers/input/i8042.c| 13
++++++++++++- 1 files changed, 12 insertions(+), 1 deletions(-)drivers/input/i8042.c index renamed from drivers/input/i8042.c +0
-099254e4..cae2d0a 100644 ---
a/drivers/input/i8042.c+++b/drivers/input/i8042.c@@ -320,6 +320,17 @@ static intkbd_controller_present(void)returnin8(I8042_STATUS_REG)!=0xff; }
Quoted 7 lines
Quoted 5 lines
+/* + * Implement a weak default function for boards that optionally + * need to skip the i8042 initialization. + */ +int
__board_i8042_skip(void)+{ + /* As default, don't skip */ + return 0; +} +intboard_i8042_skip(void)__attribute__((weak, alias("__board_i8042_skip")));Please add <
linux/compiler.h> and use__weakdirectly, thanks.
Yes will do,
Quoted 7 lines
- --
Tom
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://www.enigmail.net/
Quoted 14 lines
iQIcBAEBAgAGBQJQeD/QAAoJENk4IS6UOR1WVMsP/RJTlWaTvF56K6H75WbjK7l5 xE7zeAeCS4gbM1CS0fEv1X4296L7oWUUUkw73gwSEAxd2CxOj96HrhJI0WQIqZ/a m6ysfwswzY92oqXJGxnWnLiZzd0JUR/QHZAM7U0tX1yHFsYrycEtuq+JvfMm5BU7 1ozqrN0SoFPa8ZBq0GpnXhDsGdMApucDBkbDv3cgHTYPkOlfh3gLpbz/dkWKxrCv NBwKvZgVMtEPf9hZf5CLuB2ghfWIRyP50Bf99nKhV+gdLGtrEbboHkMMXEc2Z1ex foEMqpmSiMVd9yMRqVEIM3sWwnapqAZVn3wQLoq5Kz+YGS/9e0c9t95ck+CmndiM kJmrx/LZ/XSGzjLrKC3MWLWC/KUS2hHqj4AfYUf1kL5lPuHM24c+oSRfOjogkaqR bMJZ9ii/kYcQJry/dAYTjFyEa120X48y46e2bNcMhWVZh48A6VpJkFILb1Ga4tEo ss+hMBX/tiMNp8eoOR7y1n+A+94r3ABKUrLapjfVKg+qXeufrMyotBVfPY35hWnP qLNVlPpdEF7nP1Wt22OB9s6bBcI6dCrNuL75Ym6wJ3DYnpqU8Y8f3HihwL7cBy7F o1Zpo0bzazNfy722IYphWu0O3hihIQ11fRpAndVemUzjaXP/kKxaVhiDCj28xHup 9zGuTm7SW/liJTXp4cc8
=5tNx
-----END PGP SIGNATURE-----
Regards,
Simon
PATCH 3/5 input: i8042: Provide feature to disable keyboard before booting kernel
In reply to Simon GlassFrom: Louis Yung-Chieh Lo <[email protected]>
The BIOS leaves the keyboard enabled during boot time so that any keystroke would interfere kernel driver initialization.
Add a way to disable the keyboard to make sure no scancode will be generated during the boot time. Note that the keyboard will be re-enabled again after the kernel driver is up.
This code can be called from the board functions.
--- drivers/input/i8042.c | 38 ++++++++++++++++++++++++++++++++++++++ include/i8042.h | 13 +++++++++++++ 2 files changed, 51 insertions(+), 0 deletions(-)
drivers/input/i8042.c +38 -0
@@ -331,6 +331,44 @@ int __board_i8042_skip(void) }int board_i8042_skip (void ) __attribute__((weak,alias ("__board_i8042_skip" ))); +void i8042_flush (void ) +{ +int timeout; + +/* +* The delay is to give the keyboard controller some time to fill the +* next byte. +*/ +while (1 ) { + timeout =100 ;/* wait for no longer than 100us */ +while (timeout >0 && !(in8 (I8042_STATUS_REG ) &0x01 )) { +udelay (1 ); + timeout--; + } + +/* Try to pull next byte if not timeout. */ +if (in8 (I8042_STATUS_REG ) &0x01 ) +in8 (I8042_DATA_REG ); +else +break ; + } +} + +int i8042_disable (void ) +{ +if (kbd_input_empty () ==0 ) +return -1 ; + +/* Disable keyboard */ +out8 (I8042_COMMAND_REG ,0xad ); + +if (kbd_input_empty () ==0 ) +return -1 ; + +return 0 ; +} + +/******************************************************************************* * * i8042_kbd_init - reset keyboard and init state flags
include/i8042.h +13 -0
@@ -69,6 +69,19 @@/* exports */ +/** +* Flush all buffer from keyboard controller to host. +*/ +void i8042_flush (void ); + +/** +* Disables the keyboard so that key strokes no longer generate scancodes to +* the host. +* +* @return 0 if ok, -1 if keyboard input was found while disabling +*/ +int i8042_disable (void ); +int i8042_kbd_init (void );int i8042_tstc (void );int i8042_getc (void );
Signature · 1 line
1.7.7.3
PATCH 4/5 input: Fix i8042 keyboard reset
In reply to Simon GlassFrom: Marc Jones <[email protected]>
The i8042 keyboard reset was not checking the results of the output buffer after the reset command. This can jam up some KBC/keyboards. Also, remove a write to the wrong register and the CONFIG setting around the incorrect write.
--- drivers/input/i8042.c | 32 +++++++++++++++++++++++++++----- 1 files changed, 27 insertions(+), 5 deletions(-)
drivers/input/i8042.c +27 -5
@@ -666,31 +666,53 @@ static int kbd_input_empty(void)/******************************************************************************/ +static int wait_until_kbd_output_full (void ) +{ +int kbdTimeout =KBD_TIMEOUT *1000 ; + +while (((in8 (I8042_STATUS_REG ) &0x01 ) ==0 ) && kbdTimeout--) +udelay (1 ); + +return kbdTimeout !=-1 ; +} + +/******************************************************************************/ +static int kbd_reset (void ) { +/* KB Reset */ if (kbd_input_empty () ==0 )return -1 ;out8 (I8042_DATA_REG ,0xff ); +if (wait_until_kbd_output_full () ==0 ) +return -1 ; + +if (in8 (I8042_DATA_REG ) !=0xfa )/* ACK */ +return -1 ; + +if (wait_until_kbd_output_full () ==0 ) +return -1 ; + +if (in8 (I8042_DATA_REG ) !=0xaa )/* Test Pass*/ +return -1 ; +if (kbd_input_empty () ==0 )return -1 ; -#ifdef CONFIG_USE_CPCIDVI +/* Set KBC mode */ out8 (I8042_COMMAND_REG ,0x60 ); -#else -out8 (I8042_DATA_REG ,0x60 ); -#endif if (kbd_input_empty () ==0 )return -1 ;out8 (I8042_DATA_REG ,0x45 ); -if (kbd_input_empty () ==0 )return -1 ; +/* Enable Keyboard */ out8 (I8042_COMMAND_REG ,0xae );if (kbd_input_empty () ==0 )
Signature · 1 line
1.7.7.3
PATCH 5/5 input: Add ANSI 3.64 escape sequence generation.
In reply to Simon GlassFrom: Hung-Te Lin <[email protected]>
To support Non-ASCII keys (ex, Fn, PgUp/Dn, arrow keys, ...), we need to translate key code into escape sequence.
(Updated by sjg at chromium.org to move away from a function to store keycodes, so we can easily record how many were sent. We now need to return this from input_send_keycodes() so we know whether keys were generated.)
--- drivers/input/input.c | 102 +++++++++++++++++++++++++++++++++++++++++------- include/input.h | 2 + 2 files changed, 89 insertions(+), 15 deletions(-)
drivers/input/input.c +87 -15
@@ -93,6 +93,22 @@ static unsigned char kbd_ctrl_xlate[] = { '\r', 0xff, 0xff }; +/* +* Scan key code to ANSI 3.64 escape sequence table. This table is +* incomplete in that it does not include all possible extra keys. +*/ +static struct { +int kbd_scan_code; +char *escape; +} kbd_to_ansi364[] = { + {KEY_UP ,"\033[A" }, + {KEY_DOWN ,"\033[B" }, + {KEY_RIGHT ,"\033[C" }, + {KEY_LEFT ,"\033[D" }, +}; + +/* Maximum number of output characters that an ANSI sequence expands to */ +#define ANSI_CHAR_MAX 3int input_queue_ascii (struct input_config *config,int ch) {
@@ -289,24 +305,67 @@ static int input_check_keycodes(struct input_config *config, }/** +* Checks and converts a special key code into ANSI 3.64 escape sequence. +* +* @param config Input state +* @param keycode Key code to examine +* @param output_ch Buffer to place output characters into. It should +* be at least ANSI_CHAR_MAX bytes long, to allow for +* an ANSI sequence. +* @param max_chars Maximum number of characters to add to output_ch +* @return number of characters output, if the key was converted, otherwise 0. +* This may be larger than max_chars, in which case the overflow +* characters are not output. +*/ +static int input_keycode_to_ansi364 (struct input_config *config, +int keycode,char output_ch[],int max_chars) +{ +const char *escape; +int ch_count; +int i; + +for (i = ch_count =0 ; i <ARRAY_SIZE (kbd_to_ansi364); i++) { +if (keycode != kbd_to_ansi364[i].kbd_scan_code) +continue ; +for (escape = kbd_to_ansi364[i].escape; *escape; escape++) { +if (ch_count < max_chars) + output_ch[ch_count] = *escape; + ch_count++; + } +return ch_count; + } + +return 0 ; +} + +/** +* Converts and queues a list of key codes in escaped ASCII string form * Convert a list of key codes into ASCII * * You must call input_check_keycodes() before this. It turns the keycode -* list into a list of ASCII characters which are ready to send to the -* input layer. +* list into a list of ASCII characters and sends them to the input layer. * * Characters which were seen last time do not generate fresh ASCII output. +* The output (calls to queue_ascii) may be longer than num_keycodes, if the +* keycode contains special keys that was encoded to longer escaped sequence. * * @param config Input state * @param keycode List of key codes to examine * @param num_keycodes Number of key codes +* @param output_ch Buffer to place output characters into. It should +* be@last ANSI_CHAR_MAX * num_keycodes, to allow for +* ANSI sequences. +* @param max_chars Maximum number of characters to add to output_ch * @param same Number of key codes which are the same +* @return number of characters written into output_ch, or -1 if we would +* exceed max_chars chars. */ static int input_keycodes_to_ascii (struct input_config *config, -int keycode[],int num_keycodes,char output_ch[],int same) +int keycode[],int num_keycodes,char output_ch[], +int max_chars,int same) {struct input_key_xlate *table; -int ch_count; +int ch_count =0 ;int i; table = &config->table[0 ];
@@ -321,19 +380,31 @@ static int input_keycodes_to_ascii(struct input_config *config, } } -/* now find normal keys */ -for (i = ch_count =0 ; i < num_keycodes; i++) { +/* Start conversion by looking for the first new keycode (by same). */ +for (i = same; i < num_keycodes; i++) {int key = keycode[i]; +int ch = (key < table->num_entries) ? table->xlate[key] :0xff ; -if (key < table->num_entries && i >= same) { -int ch = table->xlate[key]; - -/* If a normal key with an ASCII value, add it! */ -if (ch !=0xff ) - output_ch[ch_count++] = (uchar )ch; +/* +* For a normal key (with an ASCII value), add it; otherwise +* translate special key to escape sequence if possible. +*/ +if (ch !=0xff ) { +if (ch_count < max_chars) + output_ch[ch_count] = (uchar )ch; + ch_count++; + }else { + ch_count +=input_keycode_to_ansi364 (config, key, + output_ch, max_chars); } } +if (ch_count > max_chars) { +debug ("%s: Output char buffer overflow size=%d, need=%d\n" , + __func__, max_chars, ch_count); +return -1 ; + } +/* ok, so return keys */ return ch_count; }
@@ -341,7 +412,7 @@ static int input_keycodes_to_ascii(struct input_config *config,int input_send_keycodes (struct input_config *config,int keycode[],int num_keycodes) { -char ch[num_keycodes]; +char ch[num_keycodes *ANSI_CHAR_MAX ];int count, i, same =0 ;int is_repeat =0 ;unsigned delay_ms;
@@ -363,7 +434,7 @@ int input_send_keycodes(struct input_config *config, } count =input_keycodes_to_ascii (config, keycode, num_keycodes, - ch, is_repeat ?0 : same); + ch,sizeof (ch), is_repeat ?0 : same);for (i =0 ; i < count; i++)input_queue_ascii (config, ch[i]); delay_ms = is_repeat ?
@@ -371,7 +442,8 @@ int input_send_keycodes(struct input_config *config, config->repeat_delay_ms; config->next_repeat_ms =get_timer (0 ) + delay_ms; -return 0 ; + +return count; } int input_add_table(struct input_config *config, int left_keycode,
include/input.h +2 -0
@@ -84,6 +84,8 @@ struct stdio_dev;* @param config Input state * @param keycode List of key codes to examine * @param num_keycodes Number of key codes +* @return number of ascii characters sent, or 0 if none, or -1 for an +* internal error */ int input_send_keycodes (struct input_config *config,int keycode[],int count);
Signature · 1 line
1.7.7.3
PATCH 1/5 input: Use finer grain udelays while waitng for the i8042 keyboard buffer to empty
In reply to Simon GlassHi Simon,
drivers/input/i8042.c static void kbd_led_set(void) · line 612
Quoted 13 lines · Simon Glass
drivers/input/i8042.c +1
-2@@ -607,11 +607,10 @@ static void kbd_led_set(void)static int kbd_input_empty (void ) { -int kbdTimeout =KBD_TIMEOUT ; +int kbdTimeout =KBD_TIMEOUT *1000 ; -/* wait for input buf empty */ while ((in8 (I8042_STATUS_REG ) &0x02 ) && kbdTimeout--)
I know this magic number was already here, but later patches introduce even more. Any chance these can be cleaned up as well?
Regards,
Graeme
PATCH 1/5 input: Use finer grain udelays while waitng for the i8042 keyboard buffer to empty
Hi Graeme,
Quoted 15 lines · Graeme Russ
Hi Simon,
Quoted 11 lines · Simon Glass
drivers/input/i8042.c +1
-1@@ -607,11 +607,10 @@ static void kbd_led_set(void)static int kbd_input_empty (void ) { -int kbdTimeout =KBD_TIMEOUT ; +int kbdTimeout =KBD_TIMEOUT *1000 ;
Quoted 5 lines
drivers/input/i8042.c static void kbd_led_set(void) · line 612
Quoted 2 lines
drivers/input/i8042.c +0
-1-/* wait for input buf empty */ while ((in8 (I8042_STATUS_REG ) &0x02 ) && kbdTimeout--)I know this magic number was already here, but later patches introduce even more. Any chance these can be cleaned up as well?
Yes, will do.
Regards,
Simon
Quoted 4 lines
Regards,
Graeme
PATCH 1/5 input: Use finer grain udelays while waitng for the i8042 keyboard buffer to empty
In reply to Simon GlassQuoted 11 lines · Simon Glass
From: Gabe Black <[email protected]>
On x86, the i8042 keyboard controller driver frequently waits for the keyboard input buffer to be empty to make sure the controller has had a chance to process the data it was given. The way the delay loop was structured, if the controller hadn't cleared the corresponding status bit immediately, it would wait 1ms before checking again. If the keyboard responded quickly but not instantly, the driver would still wait a full 1ms when perhaps 1us would have been sufficient. Because udelay is a busy wait anyway, this change decreases the delay between checks to 1us.
Quoted 6 lines
Also, this change gets rid of a hardcoded 250ms delay.
On Stumpy, this saves 100-150ms during boot.
Signed-off-by Gabe Black <[email protected]>Signed-off-by Simon Glass <[email protected]>
This, or more precisely, v2 of 1/5 and 2/5 and v1 of 3, 4 and 5/5 have been applied to u-boot/master, thanks!
Signature · 8 lines
Tom -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: <http://lists.denx.de/pipermail/u-boot/attachments/20121020/9985872b/attachment.pgp>