]> git.sur5r.net Git - u-boot/blobdiff - drivers/input/i8042.c
Merge branch 'master' of git://git.denx.de/u-boot-sunxi
[u-boot] / drivers / input / i8042.c
index 8a1e22e8df4b9f97ac1b7e3f1e3d43f1ac3abf66..5678f8e3cfb1b98e41e881b81692d33a6bc7d50e 100644 (file)
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * (C) Copyright 2002 ELTEC Elektronik AG
  * Frank Gottschling <fgottschling@eltec.de>
- *
- * SPDX-License-Identifier:    GPL-2.0+ 
  */
 
 /* i8042.c - Intel 8042 keyboard driver routines */
 
-/* includes */
-
 #include <common.h>
-#include <linux/compiler.h>
-
-#ifdef CONFIG_USE_CPCIDVI
-extern u8 gt_cpcidvi_in8(u32 offset);
-extern void gt_cpcidvi_out8(u32 offset, u8 data);
-
-#define in8(a)    gt_cpcidvi_in8(a)
-#define out8(a, b) gt_cpcidvi_out8(a, b)
-#endif
-
+#include <dm.h>
+#include <errno.h>
 #include <i8042.h>
+#include <input.h>
+#include <keyboard.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
 
 /* defines */
+#define in8(p)         inb(p)
+#define out8(p, v)     outb(v, p)
 
-#ifdef CONFIG_CONSOLE_CURSOR
-extern void console_cursor(int state);
-static int blinkCount = CONFIG_SYS_CONSOLE_BLINK_COUNT;
-static int cursor_state;
-#endif
+enum {
+       QUIRK_DUP_POR   = 1 << 0,
+};
 
 /* locals */
-
-static int  kbd_input   = -1;          /* no input yet */
-static int  kbd_mapping         = KBD_US;      /* default US keyboard */
-static int  kbd_flags   = NORMAL;      /* after reset */
-static int  kbd_state;                 /* unshift code */
-
-static void kbd_conv_char(unsigned char scan_code);
-static void kbd_led_set(void);
-static void kbd_normal(unsigned char scan_code);
-static void kbd_shift(unsigned char scan_code);
-static void kbd_ctrl(unsigned char scan_code);
-static void kbd_num(unsigned char scan_code);
-static void kbd_caps(unsigned char scan_code);
-static void kbd_scroll(unsigned char scan_code);
-static void kbd_alt(unsigned char scan_code);
-static int  kbd_input_empty(void);
-static int  kbd_reset(void);
-
-static unsigned char kbd_fct_map[144] = {
-       /* kbd_fct_map table for scan code */
-        0,  AS,  AS,  AS,  AS,  AS,  AS,  AS, /* scan  0- 7 */
-       AS,  AS,  AS,  AS,  AS,  AS,  AS,  AS, /* scan  8- F */
-       AS,  AS,  AS,  AS,  AS,  AS,  AS,  AS, /* scan 10-17 */
-       AS,  AS,  AS,  AS,  AS,  CN,  AS,  AS, /* scan 18-1F */
-       AS,  AS,  AS,  AS,  AS,  AS,  AS,  AS, /* scan 20-27 */
-       AS,  AS,  SH,  AS,  AS,  AS,  AS,  AS, /* scan 28-2F */
-       AS,  AS,  AS,  AS,  AS,  AS,  SH,  AS, /* scan 30-37 */
-       AS,  AS,  CP,   0,   0,   0,   0,   0, /* scan 38-3F */
-        0,   0,   0,   0,   0,  NM,  ST,  ES, /* scan 40-47 */
-       ES,  ES,  ES,  ES,  ES,  ES,  ES,  ES, /* scan 48-4F */
-       ES,  ES,  ES,  ES,   0,   0,  AS,   0, /* scan 50-57 */
-        0,   0,   0,   0,   0,   0,   0,   0, /* scan 58-5F */
-        0,   0,   0,   0,   0,   0,   0,   0, /* scan 60-67 */
-        0,   0,   0,   0,   0,   0,   0,   0, /* scan 68-6F */
-       AS,   0,   0,  AS,   0,   0,  AS,   0, /* scan 70-77 */
-        0,  AS,   0,   0,   0,  AS,   0,   0, /* scan 78-7F */
-       AS,  CN,  AS,  AS,  AK,  ST,  EX,  EX, /* enhanced */
-       AS,  EX,  EX,  AS,  EX,  AS,  EX,  EX  /* enhanced */
-       };
-
-static unsigned char kbd_key_map[2][5][144] = {
-       { /* US keyboard */
-       { /* unshift code */
-          0, 0x1b,  '1',  '2',  '3',  '4',  '5',  '6', /* scan  0- 7 */
-        '7',  '8',  '9',  '0',  '-',  '=', 0x08, '\t', /* scan  8- F */
-        'q',  'w',  'e',  'r',  't',  'y',  'u',  'i', /* scan 10-17 */
-        'o',  'p',  '[',  ']', '\r',   CN,  'a',  's', /* scan 18-1F */
-        'd',  'f',  'g',  'h',  'j',  'k',  'l',  ';', /* scan 20-27 */
-       '\'',  '`',   SH, '\\',  'z',  'x',  'c',  'v', /* scan 28-2F */
-        'b',  'n',  'm',  ',',  '.',  '/',   SH,  '*', /* scan 30-37 */
-        ' ',  ' ',   CP,    0,    0,    0,    0,    0, /* scan 38-3F */
-          0,    0,    0,    0,    0,   NM,   ST,  '7', /* scan 40-47 */
-        '8',  '9',  '-',  '4',  '5',  '6',  '+',  '1', /* scan 48-4F */
-        '2',  '3',  '0',  '.',    0,    0,    0,    0, /* scan 50-57 */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 58-5F */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 60-67 */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 68-6F */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 70-77 */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 78-7F */
-       '\r',   CN,  '/',  '*',  ' ',   ST,  'F',  'A', /* extended */
-          0,  'D',  'C',    0,  'B',    0,  '@',  'P'  /* extended */
-       },
-       { /* shift code */
-          0, 0x1b,  '!',  '@',  '#',  '$',  '%',  '^', /* scan  0- 7 */
-        '&',  '*',  '(',  ')',  '_',  '+', 0x08, '\t', /* scan  8- F */
-        'Q',  'W',  'E',  'R',  'T',  'Y',  'U',  'I', /* scan 10-17 */
-        'O',  'P',  '{',  '}', '\r',   CN,  'A',  'S', /* scan 18-1F */
-        'D',  'F',  'G',  'H',  'J',  'K',  'L',  ':', /* scan 20-27 */
-        '"',  '~',   SH,  '|',  'Z',  'X',  'C',  'V', /* scan 28-2F */
-        'B',  'N',  'M',  '<',  '>',  '?',   SH,  '*', /* scan 30-37 */
-        ' ',  ' ',   CP,    0,    0,    0,    0,    0, /* scan 38-3F */
-          0,    0,    0,    0,    0,   NM,   ST,  '7', /* scan 40-47 */
-        '8',  '9',  '-',  '4',  '5',  '6',  '+',  '1', /* scan 48-4F */
-        '2',  '3',  '0',  '.',    0,    0,    0,    0, /* scan 50-57 */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 58-5F */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 60-67 */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 68-6F */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 70-77 */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 78-7F */
-       '\r',   CN,  '/',  '*',  ' ',   ST,  'F',  'A', /* extended */
-          0,  'D',  'C',    0,  'B',    0,  '@',  'P'  /* extended */
-       },
-       { /* control code */
-       0xff, 0x1b, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, /* scan  0- 7 */
-       0x1e, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, '\t', /* scan  8- F */
-       0x11, 0x17, 0x05, 0x12, 0x14, 0x19, 0x15, 0x09, /* scan 10-17 */
-       0x0f, 0x10, 0x1b, 0x1d, '\r',   CN, 0x01, 0x13, /* scan 18-1F */
-       0x04, 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0c, 0xff, /* scan 20-27 */
-       0xff, 0x1c,   SH, 0xff, 0x1a, 0x18, 0x03, 0x16, /* scan 28-2F */
-       0x02, 0x0e, 0x0d, 0xff, 0xff, 0xff,   SH, 0xff, /* scan 30-37 */
-       0xff, 0xff,   CP, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 38-3F */
-       0xff, 0xff, 0xff, 0xff, 0xff,   NM,   ST, 0xff, /* scan 40-47 */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 48-4F */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 50-57 */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 58-5F */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 60-67 */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 68-6F */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 70-77 */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 78-7F */
-       '\r',   CN,  '/',  '*',  ' ',   ST, 0xff, 0xff, /* extended */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff  /* extended */
-       },
-       { /* non numeric code */
-          0, 0x1b,  '1',  '2',  '3',  '4',  '5',  '6', /* scan  0- 7 */
-        '7',  '8',  '9',  '0',  '-',  '=', 0x08, '\t', /* scan  8- F */
-        'q',  'w',  'e',  'r',  't',  'y',  'u',  'i', /* scan 10-17 */
-        'o',  'p',  '[',  ']', '\r',   CN,  'a',  's', /* scan 18-1F */
-        'd',  'f',  'g',  'h',  'j',  'k',  'l',  ';', /* scan 20-27 */
-       '\'',  '`',   SH, '\\',  'z',  'x',  'c',  'v', /* scan 28-2F */
-        'b',  'n',  'm',  ',',  '.',  '/',   SH,  '*', /* scan 30-37 */
-        ' ',  ' ',   CP,    0,    0,    0,    0,    0, /* scan 38-3F */
-          0,    0,    0,    0,    0,   NM,   ST,  'w', /* scan 40-47 */
-        'x',  'y',  'l',  't',  'u',  'v',  'm',  'q', /* scan 48-4F */
-        'r',  's',  'p',  'n',    0,    0,    0,    0, /* scan 50-57 */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 58-5F */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 60-67 */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 68-6F */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 70-77 */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 78-7F */
-       '\r',   CN,  '/',  '*',  ' ',   ST,  'F',  'A', /* extended */
-          0,  'D',  'C',    0,  'B',    0,  '@',  'P'  /* extended */
-       },
-       { /* right alt mode - not used in US keyboard */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan  0 - 7 */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 8 - F */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 10 -17 */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 18 -1F */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 20 -27 */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 28 -2F */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 30 -37 */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 38 -3F */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 40 -47 */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 48 -4F */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 50 -57 */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 58 -5F */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 60 -67 */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 68 -6F */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 70 -77 */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 78 -7F */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* extended */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff  /* extended */
-       }
-       },
-       { /* german keyboard */
-       { /* unshift code */
-          0, 0x1b,  '1',  '2',  '3',  '4',  '5',  '6', /* scan  0- 7 */
-        '7',  '8',  '9',  '0', 0xe1, '\'', 0x08, '\t', /* scan  8- F */
-        'q',  'w',  'e',  'r',  't',  'z',  'u',  'i', /* scan 10-17 */
-        'o',  'p', 0x81,  '+', '\r',   CN,  'a',  's', /* scan 18-1F */
-        'd',  'f',  'g',  'h',  'j',  'k',  'l', 0x94, /* scan 20-27 */
-       0x84,  '^',   SH,  '#',  'y',  'x',  'c',  'v', /* scan 28-2F */
-        'b',  'n',  'm',  ',',  '.',  '-',   SH,  '*', /* scan 30-37 */
-        ' ',  ' ',   CP,    0,    0,    0,    0,    0, /* scan 38-3F */
-          0,    0,    0,    0,    0,   NM,   ST,  '7', /* scan 40-47 */
-        '8',  '9',  '-',  '4',  '5',  '6',  '+',  '1', /* scan 48-4F */
-        '2',  '3',  '0',  ',',    0,    0,  '<',    0, /* scan 50-57 */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 58-5F */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 60-67 */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 68-6F */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 70-77 */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 78-7F */
-       '\r',   CN,  '/',  '*',  ' ',   ST,  'F',  'A', /* extended */
-          0,  'D',  'C',    0,  'B',    0,  '@',  'P'  /* extended */
-       },
-       { /* shift code */
-          0, 0x1b,  '!',  '"', 0x15,  '$',  '%',  '&', /* scan  0- 7 */
-        '/',  '(',  ')',  '=',  '?',  '`', 0x08, '\t', /* scan  8- F */
-        'Q',  'W',  'E',  'R',  'T',  'Z',  'U',  'I', /* scan 10-17 */
-        'O',  'P', 0x9a,  '*', '\r',   CN,  'A',  'S', /* scan 18-1F */
-        'D',  'F',  'G',  'H',  'J',  'K',  'L', 0x99, /* scan 20-27 */
-       0x8e, 0xf8,   SH, '\'',  'Y',  'X',  'C',  'V', /* scan 28-2F */
-        'B',  'N',  'M',  ';',  ':',  '_',   SH,  '*', /* scan 30-37 */
-        ' ',  ' ',   CP,    0,    0,    0,    0,    0, /* scan 38-3F */
-          0,    0,    0,    0,    0,   NM,   ST,  '7', /* scan 40-47 */
-        '8',  '9',  '-',  '4',  '5',  '6',  '+',  '1', /* scan 48-4F */
-        '2',  '3',  '0',  ',',    0,    0,  '>',    0, /* scan 50-57 */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 58-5F */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 60-67 */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 68-6F */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 70-77 */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 78-7F */
-       '\r',   CN,  '/',  '*',  ' ',   ST,  'F',  'A', /* extended */
-          0,  'D',  'C',    0,  'B',    0,  '@',  'P'  /* extended */
-       },
-       { /* control code */
-       0xff, 0x1b, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, /* scan  0- 7 */
-       0x1e, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, '\t', /* scan  8- F */
-       0x11, 0x17, 0x05, 0x12, 0x14, 0x19, 0x15, 0x09, /* scan 10-17 */
-       0x0f, 0x10, 0x1b, 0x1d, '\r',   CN, 0x01, 0x13, /* scan 18-1F */
-       0x04, 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0c, 0xff, /* scan 20-27 */
-       0xff, 0x1c,   SH, 0xff, 0x1a, 0x18, 0x03, 0x16, /* scan 28-2F */
-       0x02, 0x0e, 0x0d, 0xff, 0xff, 0xff,   SH, 0xff, /* scan 30-37 */
-       0xff, 0xff,   CP, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 38-3F */
-       0xff, 0xff, 0xff, 0xff, 0xff,   NM,   ST, 0xff, /* scan 40-47 */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 48-4F */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 50-57 */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 58-5F */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 60-67 */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 68-6F */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 70-77 */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 78-7F */
-       '\r',   CN,  '/',  '*',  ' ',   ST, 0xff, 0xff, /* extended */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff  /* extended */
-       },
-       { /* non numeric code */
-          0, 0x1b,  '1',  '2',  '3',  '4',  '5',  '6', /* scan  0- 7 */
-        '7',  '8',  '9',  '0', 0xe1, '\'', 0x08, '\t', /* scan  8- F */
-        'q',  'w',  'e',  'r',  't',  'z',  'u',  'i', /* scan 10-17 */
-        'o',  'p', 0x81,  '+', '\r',   CN,  'a',  's', /* scan 18-1F */
-        'd',  'f',  'g',  'h',  'j',  'k',  'l', 0x94, /* scan 20-27 */
-       0x84,  '^',   SH,    0,  'y',  'x',  'c',  'v', /* scan 28-2F */
-        'b',  'n',  'm',  ',',  '.',  '-',   SH,  '*', /* scan 30-37 */
-        ' ',  ' ',   CP,    0,    0,    0,    0,    0, /* scan 38-3F */
-          0,    0,    0,    0,    0,   NM,   ST,  'w', /* scan 40-47 */
-        'x',  'y',  'l',  't',  'u',  'v',  'm',  'q', /* scan 48-4F */
-        'r',  's',  'p',  'n',    0,    0,  '<',    0, /* scan 50-57 */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 58-5F */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 60-67 */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 68-6F */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 70-77 */
-          0,    0,    0,    0,    0,    0,    0,    0, /* scan 78-7F */
-       '\r',   CN,  '/',  '*',  ' ',   ST,  'F',  'A', /* extended */
-          0,  'D',  'C',    0,  'B',    0,  '@',  'P'  /* extended */
-       },
-       { /* Right alt mode - is used in German keyboard */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan  0 - 7 */
-        '{',  '[',  ']',  '}', '\\', 0xff, 0xff, 0xff, /* scan  8 - F */
-        '@', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 10 -17 */
-       0xff, 0xff, 0xff,  '~', 0xff, 0xff, 0xff, 0xff, /* scan 18 -1F */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 20 -27 */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 28 -2F */
-       0xff, 0xff, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 30 -37 */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 38 -3F */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 40 -47 */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 48 -4F */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  '|', 0xff, /* scan 50 -57 */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 58 -5F */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 60 -67 */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 68 -6F */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 70 -77 */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 78 -7F */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* extended */
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff  /* extended */
-       }
-       }
-       };
+struct i8042_kbd_priv {
+       bool extended;  /* true if an extended keycode is expected next */
+       int quirks;     /* quirks that we support */
+};
 
 static unsigned char ext_key_map[] = {
        0x1c, /* keypad enter */
@@ -298,409 +50,304 @@ static unsigned char ext_key_map[] = {
        0x00  /* map end */
        };
 
-/******************************************************************************/
-
-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 __weak board_i8042_skip(void)
-{
-       /* As default, don't skip */
-       return 0;
-}
-
-void i8042_flush(void)
+static int kbd_input_empty(void)
 {
-       int timeout;
+       int kbd_timeout = KBD_TIMEOUT * 1000;
 
-       /*
-        * 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--;
-               }
+       while ((in8(I8042_STS_REG) & STATUS_IBF) && kbd_timeout--)
+               udelay(1);
 
-               /* Try to pull next byte if not timeout. */
-               if (in8(I8042_STATUS_REG) & 0x01)
-                       in8(I8042_DATA_REG);
-               else
-                       break;
-       }
+       return kbd_timeout != -1;
 }
 
-int i8042_disable(void)
+static int kbd_output_full(void)
 {
-       if (kbd_input_empty() == 0)
-               return -1;
-
-       /* Disable keyboard */
-       out8(I8042_COMMAND_REG, 0xad);
+       int kbd_timeout = KBD_TIMEOUT * 1000;
 
-       if (kbd_input_empty() == 0)
-               return -1;
+       while (((in8(I8042_STS_REG) & STATUS_OBF) == 0) && kbd_timeout--)
+               udelay(1);
 
-       return 0;
+       return kbd_timeout != -1;
 }
 
-
-/*******************************************************************************
+/**
+ * check_leds() - Check the keyboard LEDs and update them it needed
  *
- * i8042_kbd_init - reset keyboard and init state flags
+ * @ret:       Value to return
+ * @return value of @ret
  */
-int i8042_kbd_init(void)
+static int i8042_kbd_update_leds(struct udevice *dev, int leds)
 {
-       int keymap, try;
-       char *penv;
-
-       if (!kbd_controller_present() || board_i8042_skip())
-               return -1;
-
-#ifdef CONFIG_USE_CPCIDVI
-       penv = getenv("console");
-       if (penv != NULL) {
-               if (strncmp(penv, "serial", 7) == 0)
-                       return -1;
-       }
-#endif
-       /* Init keyboard device (default US layout) */
-       keymap = KBD_US;
-       penv = getenv("keymap");
-       if (penv != NULL) {
-               if (strncmp(penv, "de", 3) == 0)
-                       keymap = KBD_GER;
-       }
+       kbd_input_empty();
+       out8(I8042_DATA_REG, CMD_SET_KBD_LED);
+       kbd_input_empty();
+       out8(I8042_DATA_REG, leds & 0x7);
 
-       for (try = 0; try < KBD_RESET_TRIES; try++) {
-               if (kbd_reset() == 0) {
-                       kbd_mapping = keymap;
-                       kbd_flags   = NORMAL;
-                       kbd_state   = 0;
-                       kbd_led_set();
-                       return 0;
-               }
-       }
-       return -1;
+       return 0;
 }
 
-
-/*******************************************************************************
- *
- * i8042_tstc - test if keyboard input is available
- *             option: cursor blinking if called in a loop
- */
-int i8042_tstc(void)
+static int kbd_write(int reg, int value)
 {
-       unsigned char scan_code = 0;
-
-#ifdef CONFIG_CONSOLE_CURSOR
-       if (--blinkCount == 0) {
-               cursor_state ^= 1;
-               console_cursor(cursor_state);
-               blinkCount = CONFIG_SYS_CONSOLE_BLINK_COUNT;
-               udelay(10);
-       }
-#endif
-
-       if ((in8(I8042_STATUS_REG) & 0x01) == 0) {
-               return 0;
-       } else {
-               scan_code = in8(I8042_DATA_REG);
-               if (scan_code == 0xfa)
-                       return 0;
-
-               kbd_conv_char(scan_code);
+       if (!kbd_input_empty())
+               return -1;
+       out8(reg, value);
 
-               if (kbd_input != -1)
-                       return 1;
-       }
        return 0;
 }
 
-
-/*******************************************************************************
- *
- * i8042_getc - wait till keyboard input is available
- *             option: turn on/off cursor while waiting
- */
-int i8042_getc(void)
+static int kbd_read(int reg)
 {
-       int ret_chr;
-       unsigned char scan_code;
-
-       while (kbd_input == -1) {
-               while ((in8(I8042_STATUS_REG) & 0x01) == 0) {
-#ifdef CONFIG_CONSOLE_CURSOR
-                       if (--blinkCount == 0) {
-                               cursor_state ^= 1;
-                               console_cursor(cursor_state);
-                               blinkCount = CONFIG_SYS_CONSOLE_BLINK_COUNT;
-                       }
-                       udelay(10);
-#endif
-               }
-               scan_code = in8(I8042_DATA_REG);
-               if (scan_code != 0xfa)
-                       kbd_conv_char (scan_code);
-       }
-       ret_chr = kbd_input;
-       kbd_input = -1;
-       return ret_chr;
-}
-
+       if (!kbd_output_full())
+               return -1;
 
-/******************************************************************************/
+       return in8(reg);
+}
 
-static void kbd_conv_char(unsigned char scan_code)
+static int kbd_cmd_read(int cmd)
 {
-       if (scan_code == 0xe0) {
-               kbd_flags |= EXT;
-               return;
-       }
-
-       /* if high bit of scan_code, set break flag */
-       if (scan_code & 0x80)
-               kbd_flags |=  BRK;
-       else
-               kbd_flags &= ~BRK;
-
-       if ((scan_code == 0xe1) || (kbd_flags & E1)) {
-               if (scan_code == 0xe1) {
-                       kbd_flags ^= BRK;    /* reset the break flag */
-                       kbd_flags ^= E1;     /* bitwise EXOR with E1 flag */
-               }
-               return;
-       }
-
-       scan_code &= 0x7f;
-
-       if (kbd_flags & EXT) {
-               int i;
-
-               kbd_flags ^= EXT;
-               for (i = 0; ext_key_map[i]; i++) {
-                       if (ext_key_map[i] == scan_code) {
-                               scan_code = 0x80 + i;
-                               break;
-                       }
-               }
-               /* not found ? */
-               if (!ext_key_map[i])
-                       return;
-       }
+       if (kbd_write(I8042_CMD_REG, cmd))
+               return -1;
 
-       switch (kbd_fct_map[scan_code]) {
-       case AS:
-               kbd_normal(scan_code);
-               break;
-       case SH:
-               kbd_shift(scan_code);
-               break;
-       case CN:
-               kbd_ctrl(scan_code);
-               break;
-       case NM:
-               kbd_num(scan_code);
-               break;
-       case CP:
-               kbd_caps(scan_code);
-               break;
-       case ST:
-               kbd_scroll(scan_code);
-               break;
-       case AK:
-               kbd_alt(scan_code);
-               break;
-       }
-       return;
+       return kbd_read(I8042_DATA_REG);
 }
 
+static int kbd_cmd_write(int cmd, int data)
+{
+       if (kbd_write(I8042_CMD_REG, cmd))
+               return -1;
 
-/******************************************************************************/
+       return kbd_write(I8042_DATA_REG, data);
+}
 
-static void kbd_normal(unsigned char scan_code)
+static int kbd_reset(int quirk)
 {
-       unsigned char chr;
+       int config;
 
-       if ((kbd_flags & BRK) == NORMAL) {
-               chr = kbd_key_map[kbd_mapping][kbd_state][scan_code];
-               if ((chr == 0xff) || (chr == 0x00))
-                       return;
+       /* controller self test */
+       if (kbd_cmd_read(CMD_SELF_TEST) != KBC_TEST_OK)
+               goto err;
 
-               /* if caps lock convert upper to lower */
-               if (((kbd_flags & CAPS) == CAPS) &&
-                               (chr >= 'a' && chr <= 'z')) {
-                       chr -= 'a' - 'A';
-               }
-               kbd_input = chr;
-       }
-}
+       /* keyboard reset */
+       if (kbd_write(I8042_DATA_REG, CMD_RESET_KBD) ||
+           kbd_read(I8042_DATA_REG) != KBD_ACK ||
+           kbd_read(I8042_DATA_REG) != KBD_POR)
+               goto err;
 
+       if (kbd_write(I8042_DATA_REG, CMD_DRAIN_OUTPUT) ||
+           kbd_read(I8042_DATA_REG) != KBD_ACK)
+               goto err;
 
-/******************************************************************************/
+       /* set AT translation and disable irq */
+       config = kbd_cmd_read(CMD_RD_CONFIG);
+       if (config == -1)
+               goto err;
 
-static void kbd_shift(unsigned char scan_code)
-{
-       if ((kbd_flags & BRK) == BRK) {
-               kbd_state = AS;
-               kbd_flags &= (~SHIFT);
-       } else {
-               kbd_state = SH;
-               kbd_flags |= SHIFT;
-       }
-}
+       /* Sometimes get a second byte */
+       else if ((quirk & QUIRK_DUP_POR) && config == KBD_POR)
+               config = kbd_cmd_read(CMD_RD_CONFIG);
 
+       config |= CONFIG_AT_TRANS;
+       config &= ~(CONFIG_KIRQ_EN | CONFIG_MIRQ_EN);
+       if (kbd_cmd_write(CMD_WR_CONFIG, config))
+               goto err;
 
-/******************************************************************************/
+       /* enable keyboard */
+       if (kbd_write(I8042_CMD_REG, CMD_KBD_EN) ||
+           !kbd_input_empty())
+               goto err;
 
-static void kbd_ctrl(unsigned char scan_code)
-{
-       if ((kbd_flags & BRK) == BRK) {
-               kbd_state = AS;
-               kbd_flags &= (~CTRL);
-       } else {
-               kbd_state = CN;
-               kbd_flags |= CTRL;
-       }
+       return 0;
+err:
+       debug("%s: Keyboard failure\n", __func__);
+       return -1;
 }
 
-
-/******************************************************************************/
-
-static void kbd_caps(unsigned char scan_code)
+static int kbd_controller_present(void)
 {
-       if ((kbd_flags & BRK) == NORMAL) {
-               kbd_flags ^= CAPS;
-               kbd_led_set();    /* update keyboard LED */
-       }
+       return in8(I8042_STS_REG) != 0xff;
 }
 
-
-/******************************************************************************/
-
-static void kbd_num(unsigned char scan_code)
+/*
+ * Implement a weak default function for boards that optionally
+ * need to skip the i8042 initialization.
+ *
+ * TODO(sjg@chromium.org): Use device tree for this?
+ */
+int __weak board_i8042_skip(void)
 {
-       if ((kbd_flags & BRK) == NORMAL) {
-               kbd_flags ^= NUM;
-               kbd_state = (kbd_flags & NUM) ? AS : NM;
-               kbd_led_set();    /* update keyboard LED */
-       }
+       /* As default, don't skip */
+       return 0;
 }
 
+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_STS_REG) & STATUS_OBF)) {
+                       udelay(1);
+                       timeout--;
+               }
 
-static void kbd_scroll(unsigned char scan_code)
-{
-       if ((kbd_flags & BRK) == NORMAL) {
-               kbd_flags ^= STP;
-               kbd_led_set();    /* update keyboard LED */
-               if (kbd_flags & STP)
-                       kbd_input = 0x13;
+               /* Try to pull next byte if not timeout */
+               if (in8(I8042_STS_REG) & STATUS_OBF)
+                       in8(I8042_DATA_REG);
                else
-                       kbd_input = 0x11;
+                       break;
        }
 }
 
-/******************************************************************************/
-
-static void kbd_alt(unsigned char scan_code)
+int i8042_disable(void)
 {
-       if ((kbd_flags & BRK) == BRK) {
-               kbd_state = AS;
-               kbd_flags &= (~ALT);
-       } else {
-               kbd_state = AK;
-               kbd_flags &= ALT;
-       }
-}
+       if (kbd_input_empty() == 0)
+               return -1;
 
+       /* Disable keyboard */
+       out8(I8042_CMD_REG, CMD_KBD_DIS);
 
-/******************************************************************************/
+       if (kbd_input_empty() == 0)
+               return -1;
 
-static void kbd_led_set(void)
-{
-       kbd_input_empty();
-       out8(I8042_DATA_REG, 0xed);    /* SET LED command */
-       kbd_input_empty();
-       out8(I8042_DATA_REG, (kbd_flags & 0x7));    /* LED bits only */
+       return 0;
 }
 
-
-/******************************************************************************/
-
-static int kbd_input_empty(void)
+static int i8042_kbd_check(struct input_config *input)
 {
-       int kbdTimeout = KBD_TIMEOUT * 1000;
-
-       while ((in8(I8042_STATUS_REG) & I8042_STATUS_IN_DATA) && kbdTimeout--)
-               udelay(1);
+       struct i8042_kbd_priv *priv = dev_get_priv(input->dev);
 
-       return kbdTimeout != -1;
-}
-
-/******************************************************************************/
-
-static int wait_until_kbd_output_full(void)
-{
-       int kbdTimeout = KBD_TIMEOUT * 1000;
+       if ((in8(I8042_STS_REG) & STATUS_OBF) == 0) {
+               return 0;
+       } else {
+               bool release = false;
+               int scan_code;
+               int i;
 
-       while (((in8(I8042_STATUS_REG) & 0x01) == 0) && kbdTimeout--)
-               udelay(1);
+               scan_code = in8(I8042_DATA_REG);
+               if (scan_code == 0xfa) {
+                       return 0;
+               } else if (scan_code == 0xe0) {
+                       priv->extended = true;
+                       return 0;
+               }
+               if (scan_code & 0x80) {
+                       scan_code &= 0x7f;
+                       release = true;
+               }
+               if (priv->extended) {
+                       priv->extended = false;
+                       for (i = 0; ext_key_map[i]; i++) {
+                               if (ext_key_map[i] == scan_code) {
+                                       scan_code = 0x60 + i;
+                                       break;
+                               }
+                       }
+                       /* not found ? */
+                       if (!ext_key_map[i])
+                               return 0;
+               }
 
-       return kbdTimeout != -1;
+               input_add_keycode(input, scan_code, release);
+               return 1;
+       }
 }
 
-/******************************************************************************/
-
-static int kbd_reset(void)
+/* i8042_kbd_init - reset keyboard and init state flags */
+static int i8042_start(struct udevice *dev)
 {
-       /* 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;
+       struct keyboard_priv *uc_priv = dev_get_uclass_priv(dev);
+       struct i8042_kbd_priv *priv = dev_get_priv(dev);
+       struct input_config *input = &uc_priv->input;
+       int keymap, try;
+       char *penv;
+       int ret;
 
-       if (kbd_input_empty() == 0)
-               return -1;
+       if (!kbd_controller_present() || board_i8042_skip()) {
+               debug("i8042 keyboard controller is not present\n");
+               return -ENOENT;
+       }
 
-       /* Set KBC mode */
-       out8(I8042_COMMAND_REG, 0x60);
+       /* Init keyboard device (default US layout) */
+       keymap = KBD_US;
+       penv = env_get("keymap");
+       if (penv != NULL) {
+               if (strncmp(penv, "de", 3) == 0)
+                       keymap = KBD_GER;
+       }
 
-       if (kbd_input_empty() == 0)
-               return -1;
+       for (try = 0; kbd_reset(priv->quirks) != 0; try++) {
+               if (try >= KBD_RESET_TRIES)
+                       return -1;
+       }
 
-       out8(I8042_DATA_REG, 0x45);
+       ret = input_add_tables(input, keymap == KBD_GER);
+       if (ret)
+               return ret;
 
-       if (kbd_input_empty() == 0)
-               return -1;
+       i8042_kbd_update_leds(dev, NORMAL);
+       debug("%s: started\n", __func__);
 
-       /* Enable Keyboard */
-       out8(I8042_COMMAND_REG, 0xae);
+       return 0;
+}
 
-       if (kbd_input_empty() == 0)
-               return -1;
+/**
+ * Set up the i8042 keyboard. This is called by the stdio device handler
+ *
+ * We want to do this init when the keyboard is actually used rather than
+ * at start-up, since keyboard input may not currently be selected.
+ *
+ * Once the keyboard starts there will be a period during which we must
+ * wait for the keyboard to init. We do this only when a key is first
+ * read - see kbd_wait_for_fifo_init().
+ *
+ * @return 0 if ok, -ve on error
+ */
+static int i8042_kbd_probe(struct udevice *dev)
+{
+       struct keyboard_priv *uc_priv = dev_get_uclass_priv(dev);
+       struct i8042_kbd_priv *priv = dev_get_priv(dev);
+       struct stdio_dev *sdev = &uc_priv->sdev;
+       struct input_config *input = &uc_priv->input;
+       int ret;
+
+       if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
+                           "intel,duplicate-por"))
+               priv->quirks |= QUIRK_DUP_POR;
+
+       /* Register the device. i8042_start() will be called soon */
+       input->dev = dev;
+       input->read_keys = i8042_kbd_check;
+       input_allow_repeats(input, true);
+       strcpy(sdev->name, "i8042-kbd");
+       ret = input_stdio_register(sdev);
+       if (ret) {
+               debug("%s: input_stdio_register() failed\n", __func__);
+               return ret;
+       }
+       debug("%s: ready\n", __func__);
 
        return 0;
 }
+
+static const struct keyboard_ops i8042_kbd_ops = {
+       .start  = i8042_start,
+       .update_leds    = i8042_kbd_update_leds,
+};
+
+static const struct udevice_id i8042_kbd_ids[] = {
+       { .compatible = "intel,i8042-keyboard" },
+       { }
+};
+
+U_BOOT_DRIVER(i8042_kbd) = {
+       .name   = "i8042_kbd",
+       .id     = UCLASS_KEYBOARD,
+       .of_match = i8042_kbd_ids,
+       .probe = i8042_kbd_probe,
+       .ops    = &i8042_kbd_ops,
+       .priv_auto_alloc_size = sizeof(struct i8042_kbd_priv),
+};