mirror of
https://github.com/Ysurac/openmptcprouter.git
synced 2025-03-09 15:40:20 +00:00
Kernel 5.4 RUTX support
This commit is contained in:
parent
839fcf1cab
commit
cfce9f52b2
7376 changed files with 3902 additions and 546 deletions
53
common/package/boot/uboot-ipq40xx/src/drivers/input/Makefile
Normal file
53
common/package/boot/uboot-ipq40xx/src/drivers/input/Makefile
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
#
|
||||
# (C) Copyright 2000-2007
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
#
|
||||
# See file CREDITS for list of people who contributed to this
|
||||
# project.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; either version 2 of
|
||||
# the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
# MA 02111-1307 USA
|
||||
#
|
||||
|
||||
include $(TOPDIR)/config.mk
|
||||
|
||||
LIB := $(obj)libinput.o
|
||||
|
||||
COBJS-$(CONFIG_I8042_KBD) += i8042.o
|
||||
COBJS-$(CONFIG_TEGRA2_KEYBOARD) += tegra-kbc.o
|
||||
ifdef CONFIG_PS2KBD
|
||||
COBJS-y += keyboard.o pc_keyb.o
|
||||
COBJS-$(CONFIG_PS2MULT) += ps2mult.o ps2ser.o
|
||||
endif
|
||||
COBJS-y += input.o
|
||||
COBJS-$(CONFIG_OF_CONTROL) += key_matrix.o
|
||||
|
||||
COBJS := $(COBJS-y)
|
||||
SRCS := $(COBJS:.o=.c)
|
||||
OBJS := $(addprefix $(obj),$(COBJS))
|
||||
|
||||
all: $(LIB)
|
||||
|
||||
$(LIB): $(obj).depend $(OBJS)
|
||||
$(call cmd_link_o_target, $(OBJS))
|
||||
|
||||
#########################################################################
|
||||
|
||||
# defines $(obj).depend target
|
||||
include $(SRCTREE)/rules.mk
|
||||
|
||||
sinclude $(obj).depend
|
||||
|
||||
#########################################################################
|
||||
654
common/package/boot/uboot-ipq40xx/src/drivers/input/i8042.c
Normal file
654
common/package/boot/uboot-ipq40xx/src/drivers/input/i8042.c
Normal file
|
|
@ -0,0 +1,654 @@
|
|||
/*
|
||||
* (C) Copyright 2002 ELTEC Elektronik AG
|
||||
* Frank Gottschling <fgottschling@eltec.de>
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* i8042.c - Intel 8042 keyboard driver routines */
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <common.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 <i8042.h>
|
||||
|
||||
/* defines */
|
||||
|
||||
#ifdef CONFIG_CONSOLE_CURSOR
|
||||
extern void console_cursor(int state);
|
||||
static int blinkCount = CONFIG_SYS_CONSOLE_BLINK_COUNT;
|
||||
static int cursor_state;
|
||||
#endif
|
||||
|
||||
/* 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 */
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static unsigned char ext_key_map[] = {
|
||||
0x1c, /* keypad enter */
|
||||
0x1d, /* right control */
|
||||
0x35, /* keypad slash */
|
||||
0x37, /* print screen */
|
||||
0x38, /* right alt */
|
||||
0x46, /* break */
|
||||
0x47, /* editpad home */
|
||||
0x48, /* editpad up */
|
||||
0x49, /* editpad pgup */
|
||||
0x4b, /* editpad left */
|
||||
0x4d, /* editpad right */
|
||||
0x4f, /* editpad end */
|
||||
0x50, /* editpad dn */
|
||||
0x51, /* editpad pgdn */
|
||||
0x52, /* editpad ins */
|
||||
0x53, /* editpad del */
|
||||
0x00 /* map end */
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int kbd_controller_present(void)
|
||||
{
|
||||
return in8(I8042_STATUS_REG) != 0xff;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* i8042_kbd_init - reset keyboard and init state flags
|
||||
*/
|
||||
int i8042_kbd_init(void)
|
||||
{
|
||||
int keymap, try;
|
||||
char *penv;
|
||||
|
||||
if (!kbd_controller_present())
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* i8042_tstc - test if keyboard input is available
|
||||
* option: cursor blinking if called in a loop
|
||||
*/
|
||||
int i8042_tstc(void)
|
||||
{
|
||||
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 != -1)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* i8042_getc - wait till keyboard input is available
|
||||
* option: turn on/off cursor while waiting
|
||||
*/
|
||||
int i8042_getc(void)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void kbd_conv_char(unsigned char scan_code)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void kbd_normal(unsigned char scan_code)
|
||||
{
|
||||
unsigned char chr;
|
||||
|
||||
if ((kbd_flags & BRK) == NORMAL) {
|
||||
chr = kbd_key_map[kbd_mapping][kbd_state][scan_code];
|
||||
if ((chr == 0xff) || (chr == 0x00))
|
||||
return;
|
||||
|
||||
/* if caps lock convert upper to lower */
|
||||
if (((kbd_flags & CAPS) == CAPS) &&
|
||||
(chr >= 'a' && chr <= 'z')) {
|
||||
chr -= 'a' - 'A';
|
||||
}
|
||||
kbd_input = chr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void kbd_caps(unsigned char scan_code)
|
||||
{
|
||||
if ((kbd_flags & BRK) == NORMAL) {
|
||||
kbd_flags ^= CAPS;
|
||||
kbd_led_set(); /* update keyboard LED */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void kbd_num(unsigned char scan_code)
|
||||
{
|
||||
if ((kbd_flags & BRK) == NORMAL) {
|
||||
kbd_flags ^= NUM;
|
||||
kbd_state = (kbd_flags & NUM) ? AS : NM;
|
||||
kbd_led_set(); /* update keyboard LED */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
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;
|
||||
else
|
||||
kbd_input = 0x11;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void kbd_alt(unsigned char scan_code)
|
||||
{
|
||||
if ((kbd_flags & BRK) == BRK) {
|
||||
kbd_state = AS;
|
||||
kbd_flags &= (~ALT);
|
||||
} else {
|
||||
kbd_state = AK;
|
||||
kbd_flags &= ALT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
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 */
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int kbd_input_empty(void)
|
||||
{
|
||||
int kbdTimeout = KBD_TIMEOUT;
|
||||
|
||||
/* wait for input buf empty */
|
||||
while ((in8(I8042_STATUS_REG) & 0x02) && kbdTimeout--)
|
||||
udelay(1000);
|
||||
|
||||
return kbdTimeout != -1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int kbd_reset(void)
|
||||
{
|
||||
if (kbd_input_empty() == 0)
|
||||
return -1;
|
||||
|
||||
out8(I8042_DATA_REG, 0xff);
|
||||
|
||||
udelay(250000);
|
||||
|
||||
if (kbd_input_empty() == 0)
|
||||
return -1;
|
||||
|
||||
#ifdef CONFIG_USE_CPCIDVI
|
||||
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;
|
||||
|
||||
out8(I8042_COMMAND_REG, 0xae);
|
||||
|
||||
if (kbd_input_empty() == 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
430
common/package/boot/uboot-ipq40xx/src/drivers/input/input.c
Normal file
430
common/package/boot/uboot-ipq40xx/src/drivers/input/input.c
Normal file
|
|
@ -0,0 +1,430 @@
|
|||
/*
|
||||
* Translate key codes into ASCII
|
||||
*
|
||||
* Copyright (c) 2011 The Chromium OS Authors.
|
||||
* (C) Copyright 2004 DENX Software Engineering, Wolfgang Denk, wd@denx.de
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <stdio_dev.h>
|
||||
#include <input.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
enum {
|
||||
/* These correspond to the lights on the keyboard */
|
||||
FLAG_NUM_LOCK = 1 << 0,
|
||||
FLAG_CAPS_LOCK = 1 << 1,
|
||||
FLAG_SCROLL_LOCK = 1 << 2,
|
||||
|
||||
/* Special flag ORed with key code to indicate release */
|
||||
KEY_RELEASE = 1 << 15,
|
||||
KEY_MASK = 0xfff,
|
||||
};
|
||||
|
||||
/*
|
||||
* These takes map key codes to ASCII. 0xff means no key, or special key.
|
||||
* Three tables are provided - one for plain keys, one for when the shift
|
||||
* 'modifier' key is pressed and one for when the ctrl modifier key is
|
||||
* pressed.
|
||||
*/
|
||||
static const uchar kbd_plain_xlate[] = {
|
||||
0xff, 0x1b, '1', '2', '3', '4', '5', '6',
|
||||
'7', '8', '9', '0', '-', '=', '\b', '\t', /* 0x00 - 0x0f */
|
||||
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
|
||||
'o', 'p', '[', ']', '\r', 0xff, 'a', 's', /* 0x10 - 0x1f */
|
||||
'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
|
||||
'\'', '`', 0xff, '\\', 'z', 'x', 'c', 'v', /* 0x20 - 0x2f */
|
||||
'b', 'n', 'm', ',' , '.', '/', 0xff, 0xff, 0xff,
|
||||
' ', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30 - 0x3f */
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, '7',
|
||||
'8', '9', '-', '4', '5', '6', '+', '1', /* 0x40 - 0x4f */
|
||||
'2', '3', '0', '.', 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50 - 0x5F */
|
||||
'\r', 0xff, 0xff
|
||||
};
|
||||
|
||||
static unsigned char kbd_shift_xlate[] = {
|
||||
0xff, 0x1b, '!', '@', '#', '$', '%', '^',
|
||||
'&', '*', '(', ')', '_', '+', '\b', '\t', /* 0x00 - 0x0f */
|
||||
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
|
||||
'O', 'P', '{', '}', '\r', 0xff, 'A', 'S', /* 0x10 - 0x1f */
|
||||
'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
|
||||
'"', '~', 0xff, '|', 'Z', 'X', 'C', 'V', /* 0x20 - 0x2f */
|
||||
'B', 'N', 'M', '<', '>', '?', 0xff, 0xff, 0xff,
|
||||
' ', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30 - 0x3f */
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, '7',
|
||||
'8', '9', '-', '4', '5', '6', '+', '1', /* 0x40 - 0x4f */
|
||||
'2', '3', '0', '.', 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50 - 0x5F */
|
||||
'\r', 0xff, 0xff
|
||||
};
|
||||
|
||||
static unsigned char kbd_ctrl_xlate[] = {
|
||||
0xff, 0x1b, '1', 0x00, '3', '4', '5', 0x1E,
|
||||
'7', '8', '9', '0', 0x1F, '=', '\b', '\t', /* 0x00 - 0x0f */
|
||||
0x11, 0x17, 0x05, 0x12, 0x14, 0x18, 0x15, 0x09,
|
||||
0x0f, 0x10, 0x1b, 0x1d, '\n', 0xff, 0x01, 0x13, /* 0x10 - 0x1f */
|
||||
0x04, 0x06, 0x08, 0x09, 0x0a, 0x0b, 0x0c, ';',
|
||||
'\'', '~', 0x00, 0x1c, 0x1a, 0x18, 0x03, 0x16, /* 0x20 - 0x2f */
|
||||
0x02, 0x0e, 0x0d, '<', '>', '?', 0xff, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30 - 0x3f */
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, '7',
|
||||
'8', '9', '-', '4', '5', '6', '+', '1', /* 0x40 - 0x4f */
|
||||
'2', '3', '0', '.', 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50 - 0x5F */
|
||||
'\r', 0xff, 0xff
|
||||
};
|
||||
|
||||
|
||||
int input_queue_ascii(struct input_config *config, int ch)
|
||||
{
|
||||
if (config->fifo_in + 1 == INPUT_BUFFER_LEN) {
|
||||
if (!config->fifo_out)
|
||||
return -1; /* buffer full */
|
||||
else
|
||||
config->fifo_in = 0;
|
||||
} else {
|
||||
if (config->fifo_in + 1 == config->fifo_out)
|
||||
return -1; /* buffer full */
|
||||
config->fifo_in++;
|
||||
}
|
||||
config->fifo[config->fifo_in] = (uchar)ch;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int input_tstc(struct input_config *config)
|
||||
{
|
||||
if (config->fifo_in == config->fifo_out && config->read_keys) {
|
||||
if (!(*config->read_keys)(config))
|
||||
return 0;
|
||||
}
|
||||
return config->fifo_in != config->fifo_out;
|
||||
}
|
||||
|
||||
int input_getc(struct input_config *config)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
while (config->fifo_in == config->fifo_out) {
|
||||
if (config->read_keys)
|
||||
err = (*config->read_keys)(config);
|
||||
if (err)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (++config->fifo_out == INPUT_BUFFER_LEN)
|
||||
config->fifo_out = 0;
|
||||
|
||||
return config->fifo[config->fifo_out];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a modifier/special key press or release and decide which key
|
||||
* translation array should be used as a result.
|
||||
*
|
||||
* TODO: Should keep track of modifier press/release
|
||||
*
|
||||
* @param config Input state
|
||||
* @param key Key code to process
|
||||
* @param release 0 if a press, 1 if a release
|
||||
* @return pointer to keycode->ascii translation table that should be used
|
||||
*/
|
||||
static struct input_key_xlate *process_modifier(struct input_config *config,
|
||||
int key, int release)
|
||||
{
|
||||
struct input_key_xlate *table;
|
||||
int flip = -1;
|
||||
int i;
|
||||
|
||||
/* Start with the main table, and see what modifiers change it */
|
||||
assert(config->num_tables > 0);
|
||||
table = &config->table[0];
|
||||
for (i = 1; i < config->num_tables; i++) {
|
||||
struct input_key_xlate *tab = &config->table[i];
|
||||
|
||||
if (key == tab->left_keycode || key == tab->right_keycode)
|
||||
table = tab;
|
||||
}
|
||||
|
||||
/* Handle the lighted keys */
|
||||
if (!release) {
|
||||
switch (key) {
|
||||
case KEY_SCROLLLOCK:
|
||||
flip = FLAG_SCROLL_LOCK;
|
||||
break;
|
||||
case KEY_NUMLOCK:
|
||||
flip = FLAG_NUM_LOCK;
|
||||
break;
|
||||
case KEY_CAPSLOCK:
|
||||
flip = FLAG_CAPS_LOCK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (flip != -1) {
|
||||
int leds = 0;
|
||||
|
||||
config->leds ^= flip;
|
||||
if (config->flags & FLAG_NUM_LOCK)
|
||||
leds |= INPUT_LED_NUM;
|
||||
if (config->flags & FLAG_CAPS_LOCK)
|
||||
leds |= INPUT_LED_CAPS;
|
||||
if (config->flags & FLAG_SCROLL_LOCK)
|
||||
leds |= INPUT_LED_SCROLL;
|
||||
config->leds = leds;
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search an int array for a key value
|
||||
*
|
||||
* @param array Array to search
|
||||
* @param count Number of elements in array
|
||||
* @param key Key value to find
|
||||
* @return element where value was first found, -1 if none
|
||||
*/
|
||||
static int array_search(int *array, int count, int key)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (array[i] == key)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort an array so that those elements that exist in the ordering are
|
||||
* first in the array, and in the same order as the ordering. The algorithm
|
||||
* is O(count * ocount) and designed for small arrays.
|
||||
*
|
||||
* TODO: Move this to common / lib?
|
||||
*
|
||||
* @param dest Array with elements to sort, also destination array
|
||||
* @param count Number of elements to sort
|
||||
* @param order Array containing ordering elements
|
||||
* @param ocount Number of ordering elements
|
||||
* @return number of elements in dest that are in order (these will be at the
|
||||
* start of dest).
|
||||
*/
|
||||
static int sort_array_by_ordering(int *dest, int count, int *order,
|
||||
int ocount)
|
||||
{
|
||||
int temp[count];
|
||||
int dest_count;
|
||||
int same; /* number of elements which are the same */
|
||||
int i;
|
||||
|
||||
/* setup output items, copy items to be sorted into our temp area */
|
||||
memcpy(temp, dest, count * sizeof(*dest));
|
||||
dest_count = 0;
|
||||
|
||||
/* work through the ordering, move over the elements we agree on */
|
||||
for (i = 0; i < ocount; i++) {
|
||||
if (array_search(temp, count, order[i]) != -1)
|
||||
dest[dest_count++] = order[i];
|
||||
}
|
||||
same = dest_count;
|
||||
|
||||
/* now move over the elements that are not in the ordering */
|
||||
for (i = 0; i < count; i++) {
|
||||
if (array_search(order, ocount, temp[i]) == -1)
|
||||
dest[dest_count++] = temp[i];
|
||||
}
|
||||
assert(dest_count == count);
|
||||
return same;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a list of key codes against the previous key scan
|
||||
*
|
||||
* Given a list of new key codes, we check how many of these are the same
|
||||
* as last time.
|
||||
*
|
||||
* @param config Input state
|
||||
* @param keycode List of key codes to examine
|
||||
* @param num_keycodes Number of key codes
|
||||
* @param same Returns number of key codes which are the same
|
||||
*/
|
||||
static int input_check_keycodes(struct input_config *config,
|
||||
int keycode[], int num_keycodes, int *same)
|
||||
{
|
||||
/* Select the 'plain' xlate table to start with */
|
||||
if (!config->num_tables) {
|
||||
debug("%s: No xlate tables: cannot decode keys\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* sort the keycodes into the same order as the previous ones */
|
||||
*same = sort_array_by_ordering(keycode, num_keycodes,
|
||||
config->prev_keycodes, config->num_prev_keycodes);
|
||||
|
||||
memcpy(config->prev_keycodes, keycode, num_keycodes * sizeof(int));
|
||||
config->num_prev_keycodes = num_keycodes;
|
||||
|
||||
return *same != num_keycodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* Characters which were seen last time do not generate fresh ASCII output.
|
||||
*
|
||||
* @param config Input state
|
||||
* @param keycode List of key codes to examine
|
||||
* @param num_keycodes Number of key codes
|
||||
* @param same Number of key codes which are the same
|
||||
*/
|
||||
static int input_keycodes_to_ascii(struct input_config *config,
|
||||
int keycode[], int num_keycodes, char output_ch[], int same)
|
||||
{
|
||||
struct input_key_xlate *table;
|
||||
int ch_count;
|
||||
int i;
|
||||
|
||||
table = &config->table[0];
|
||||
|
||||
/* deal with modifiers first */
|
||||
for (i = 0; i < num_keycodes; i++) {
|
||||
int key = keycode[i] & KEY_MASK;
|
||||
|
||||
if (key >= table->num_entries || table->xlate[key] == 0xff) {
|
||||
table = process_modifier(config, key,
|
||||
keycode[i] & KEY_RELEASE);
|
||||
}
|
||||
}
|
||||
|
||||
/* now find normal keys */
|
||||
for (i = ch_count = 0; i < num_keycodes; i++) {
|
||||
int key = keycode[i];
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* ok, so return keys */
|
||||
return ch_count;
|
||||
}
|
||||
|
||||
int input_send_keycodes(struct input_config *config,
|
||||
int keycode[], int num_keycodes)
|
||||
{
|
||||
char ch[num_keycodes];
|
||||
int count, i, same = 0;
|
||||
int is_repeat = 0;
|
||||
unsigned delay_ms;
|
||||
|
||||
config->modifiers = 0;
|
||||
if (!input_check_keycodes(config, keycode, num_keycodes, &same)) {
|
||||
/*
|
||||
* Same as last time - is it time for another repeat?
|
||||
* TODO(sjg@chromium.org) We drop repeats here and since
|
||||
* the caller may not call in again for a while, our
|
||||
* auto-repeat speed is not quite correct. We should
|
||||
* insert another character if we later realise that we
|
||||
* have missed a repeat slot.
|
||||
*/
|
||||
is_repeat = (int)get_timer(config->next_repeat_ms) >= 0;
|
||||
if (!is_repeat)
|
||||
return 0;
|
||||
}
|
||||
|
||||
count = input_keycodes_to_ascii(config, keycode, num_keycodes,
|
||||
ch, is_repeat ? 0 : same);
|
||||
for (i = 0; i < count; i++)
|
||||
input_queue_ascii(config, ch[i]);
|
||||
delay_ms = is_repeat ?
|
||||
config->repeat_rate_ms :
|
||||
config->repeat_delay_ms;
|
||||
|
||||
config->next_repeat_ms = get_timer(0) + delay_ms;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int input_add_table(struct input_config *config, int left_keycode,
|
||||
int right_keycode, const uchar *xlate, int num_entries)
|
||||
{
|
||||
struct input_key_xlate *table;
|
||||
|
||||
if (config->num_tables == INPUT_MAX_MODIFIERS) {
|
||||
debug("%s: Too many modifier tables\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
table = &config->table[config->num_tables++];
|
||||
table->left_keycode = left_keycode;
|
||||
table->right_keycode = right_keycode;
|
||||
table->xlate = xlate;
|
||||
table->num_entries = num_entries;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int input_init(struct input_config *config, int leds, int repeat_delay_ms,
|
||||
int repeat_rate_ms)
|
||||
{
|
||||
memset(config, '\0', sizeof(*config));
|
||||
config->leds = leds;
|
||||
config->repeat_delay_ms = repeat_delay_ms;
|
||||
config->repeat_rate_ms = repeat_rate_ms;
|
||||
if (input_add_table(config, -1, -1,
|
||||
kbd_plain_xlate, ARRAY_SIZE(kbd_plain_xlate)) ||
|
||||
input_add_table(config, KEY_LEFTSHIFT, KEY_RIGHTSHIFT,
|
||||
kbd_shift_xlate, ARRAY_SIZE(kbd_shift_xlate)) ||
|
||||
input_add_table(config, KEY_LEFTCTRL, KEY_RIGHTCTRL,
|
||||
kbd_ctrl_xlate, ARRAY_SIZE(kbd_ctrl_xlate))) {
|
||||
debug("%s: Could not add modifier tables\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int input_stdio_register(struct stdio_dev *dev)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = stdio_register(dev);
|
||||
|
||||
/* check if this is the standard input device */
|
||||
if (!error && strcmp(getenv("stdin"), dev->name) == 0) {
|
||||
/* reassign the console */
|
||||
if (OVERWRITE_CONSOLE ||
|
||||
console_assign(stdin, dev->name))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
208
common/package/boot/uboot-ipq40xx/src/drivers/input/key_matrix.c
Normal file
208
common/package/boot/uboot-ipq40xx/src/drivers/input/key_matrix.c
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* Manage Keyboard Matrices
|
||||
*
|
||||
* Copyright (c) 2012 The Chromium OS Authors.
|
||||
* (C) Copyright 2004 DENX Software Engineering, Wolfgang Denk, wd@denx.de
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <fdtdec.h>
|
||||
#include <key_matrix.h>
|
||||
#include <malloc.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
/**
|
||||
* Determine if the current keypress configuration can cause key ghosting
|
||||
*
|
||||
* We figure this out by seeing if we have two or more keys in the same
|
||||
* column, as well as two or more keys in the same row.
|
||||
*
|
||||
* @param config Keyboard matrix config
|
||||
* @param keys List of keys to check
|
||||
* @param valid Number of valid keypresses to check
|
||||
* @return 0 if no ghosting is possible, 1 if it is
|
||||
*/
|
||||
static int has_ghosting(struct key_matrix *config, struct key_matrix_key *keys,
|
||||
int valid)
|
||||
{
|
||||
int key_in_same_col = 0, key_in_same_row = 0;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < valid; i++) {
|
||||
/*
|
||||
* Find 2 keys such that one key is in the same row
|
||||
* and the other is in the same column as the i-th key.
|
||||
*/
|
||||
for (j = i + 1; j < valid; j++) {
|
||||
if (keys[j].col == keys[i].col)
|
||||
key_in_same_col = 1;
|
||||
if (keys[j].row == keys[i].row)
|
||||
key_in_same_row = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (key_in_same_col && key_in_same_row)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int key_matrix_decode(struct key_matrix *config, struct key_matrix_key keys[],
|
||||
int num_keys, int keycode[], int max_keycodes)
|
||||
{
|
||||
const u8 *keymap;
|
||||
int valid, upto;
|
||||
int pos;
|
||||
|
||||
debug("%s: num_keys = %d\n", __func__, num_keys);
|
||||
keymap = config->plain_keycode;
|
||||
for (valid = upto = 0; upto < num_keys; upto++) {
|
||||
struct key_matrix_key *key = &keys[upto];
|
||||
|
||||
debug(" valid=%d, row=%d, col=%d\n", key->valid, key->row,
|
||||
key->col);
|
||||
if (!key->valid)
|
||||
continue;
|
||||
pos = key->row * config->num_cols + key->col;
|
||||
if (config->fn_keycode && pos == config->fn_pos)
|
||||
keymap = config->fn_keycode;
|
||||
|
||||
/* Convert the (row, col) values into a keycode */
|
||||
if (valid < max_keycodes)
|
||||
keycode[valid++] = keymap[pos];
|
||||
debug(" keycode=%d\n", keymap[pos]);
|
||||
}
|
||||
|
||||
/* For a ghost key config, ignore the keypresses for this iteration. */
|
||||
if (valid >= 3 && has_ghosting(config, keys, valid)) {
|
||||
valid = 0;
|
||||
debug(" ghosting detected!\n");
|
||||
}
|
||||
debug(" %d valid keycodes found\n", valid);
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new keycode map from some provided data
|
||||
*
|
||||
* This decodes a keycode map in the format used by the fdt, which is one
|
||||
* word per entry, with the row, col and keycode encoded in that word.
|
||||
*
|
||||
* We create a (row x col) size byte array with each entry containing the
|
||||
* keycode for that (row, col). We also search for map_keycode and return
|
||||
* its position if found (this is used for finding the Fn key).
|
||||
*
|
||||
* @param config Key matrix dimensions structure
|
||||
* @param data Keycode data
|
||||
* @param len Number of entries in keycode table
|
||||
* @param map_keycode Key code to find in the map
|
||||
* @param pos Returns position of map_keycode, if found, else -1
|
||||
* @return map Pointer to allocated map
|
||||
*/
|
||||
static uchar *create_keymap(struct key_matrix *config, u32 *data, int len,
|
||||
int map_keycode, int *pos)
|
||||
{
|
||||
uchar *map;
|
||||
|
||||
if (pos)
|
||||
*pos = -1;
|
||||
map = (uchar *)calloc(1, config->key_count);
|
||||
if (!map) {
|
||||
debug("%s: failed to malloc %d bytes\n", __func__,
|
||||
config->key_count);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (; len >= sizeof(u32); data++, len -= 4) {
|
||||
u32 tmp = fdt32_to_cpu(*data);
|
||||
int key_code, row, col;
|
||||
int entry;
|
||||
|
||||
row = (tmp >> 24) & 0xff;
|
||||
col = (tmp >> 16) & 0xff;
|
||||
key_code = tmp & 0xffff;
|
||||
entry = row * config->num_cols + col;
|
||||
map[entry] = key_code;
|
||||
if (pos && map_keycode == key_code)
|
||||
*pos = entry;
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
int key_matrix_decode_fdt(struct key_matrix *config, const void *blob,
|
||||
int node)
|
||||
{
|
||||
const struct fdt_property *prop;
|
||||
int offset;
|
||||
|
||||
/* Check each property name for ones that we understand */
|
||||
for (offset = fdt_first_property_offset(blob, node);
|
||||
offset > 0;
|
||||
offset = fdt_next_property_offset(blob, offset)) {
|
||||
const char *name;
|
||||
int len;
|
||||
|
||||
prop = fdt_get_property_by_offset(blob, offset, NULL);
|
||||
name = fdt_string(blob, fdt32_to_cpu(prop->nameoff));
|
||||
len = strlen(name);
|
||||
|
||||
/* Name needs to match "1,<type>keymap" */
|
||||
debug("%s: property '%s'\n", __func__, name);
|
||||
if (strncmp(name, "1,", 2) || len < 8 ||
|
||||
strcmp(name + len - 6, "keymap"))
|
||||
continue;
|
||||
|
||||
len -= 8;
|
||||
if (len == 0) {
|
||||
config->plain_keycode = create_keymap(config,
|
||||
(u32 *)prop->data, fdt32_to_cpu(prop->len),
|
||||
KEY_FN, &config->fn_pos);
|
||||
} else if (0 == strncmp(name + 2, "fn-", len)) {
|
||||
config->fn_keycode = create_keymap(config,
|
||||
(u32 *)prop->data, fdt32_to_cpu(prop->len),
|
||||
-1, NULL);
|
||||
} else {
|
||||
debug("%s: unrecognised property '%s'\n", __func__,
|
||||
name);
|
||||
}
|
||||
}
|
||||
debug("%s: Decoded key maps %p, %p from fdt\n", __func__,
|
||||
config->plain_keycode, config->fn_keycode);
|
||||
|
||||
if (!config->plain_keycode) {
|
||||
debug("%s: cannot find keycode-plain map\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int key_matrix_init(struct key_matrix *config, int rows, int cols)
|
||||
{
|
||||
memset(config, '\0', sizeof(*config));
|
||||
config->num_rows = rows;
|
||||
config->num_cols = cols;
|
||||
config->key_count = rows * cols;
|
||||
assert(config->key_count > 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
300
common/package/boot/uboot-ipq40xx/src/drivers/input/keyboard.c
Normal file
300
common/package/boot/uboot-ipq40xx/src/drivers/input/keyboard.c
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
/***********************************************************************
|
||||
*
|
||||
* (C) Copyright 2004
|
||||
* DENX Software Engineering
|
||||
* Wolfgang Denk, wd@denx.de
|
||||
*
|
||||
* Keyboard driver
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
#include <stdio_dev.h>
|
||||
#include <keyboard.h>
|
||||
|
||||
#undef KBG_DEBUG
|
||||
|
||||
#ifdef KBG_DEBUG
|
||||
#define PRINTF(fmt,args...) printf (fmt ,##args)
|
||||
#else
|
||||
#define PRINTF(fmt,args...)
|
||||
#endif
|
||||
|
||||
|
||||
#define DEVNAME "kbd"
|
||||
|
||||
#define LED_SCR 0x01 /* scroll lock led */
|
||||
#define LED_CAP 0x04 /* caps lock led */
|
||||
#define LED_NUM 0x02 /* num lock led */
|
||||
|
||||
#define KBD_BUFFER_LEN 0x20 /* size of the keyboardbuffer */
|
||||
|
||||
#if defined(CONFIG_MPC5xxx) || defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555)
|
||||
int ps2ser_check(void);
|
||||
#endif
|
||||
|
||||
static volatile char kbd_buffer[KBD_BUFFER_LEN];
|
||||
static volatile int in_pointer = 0;
|
||||
static volatile int out_pointer = 0;
|
||||
|
||||
static unsigned char leds = 0;
|
||||
static unsigned char num_lock = 0;
|
||||
static unsigned char caps_lock = 0;
|
||||
static unsigned char scroll_lock = 0;
|
||||
static unsigned char shift = 0;
|
||||
static unsigned char ctrl = 0;
|
||||
static unsigned char alt = 0;
|
||||
static unsigned char e0 = 0;
|
||||
|
||||
/******************************************************************
|
||||
* Queue handling
|
||||
******************************************************************/
|
||||
|
||||
/* puts character in the queue and sets up the in and out pointer */
|
||||
static void kbd_put_queue(char data)
|
||||
{
|
||||
if((in_pointer+1)==KBD_BUFFER_LEN) {
|
||||
if(out_pointer==0) {
|
||||
return; /* buffer full */
|
||||
} else{
|
||||
in_pointer=0;
|
||||
}
|
||||
} else {
|
||||
if((in_pointer+1)==out_pointer)
|
||||
return; /* buffer full */
|
||||
in_pointer++;
|
||||
}
|
||||
kbd_buffer[in_pointer]=data;
|
||||
return;
|
||||
}
|
||||
|
||||
/* test if a character is in the queue */
|
||||
static int kbd_testc(void)
|
||||
{
|
||||
#if defined(CONFIG_MPC5xxx) || defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555)
|
||||
/* no ISR is used, so received chars must be polled */
|
||||
ps2ser_check();
|
||||
#endif
|
||||
if(in_pointer==out_pointer)
|
||||
return(0); /* no data */
|
||||
else
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* gets the character from the queue */
|
||||
static int kbd_getc(void)
|
||||
{
|
||||
char c;
|
||||
while(in_pointer==out_pointer) {
|
||||
#if defined(CONFIG_MPC5xxx) || defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555)
|
||||
/* no ISR is used, so received chars must be polled */
|
||||
ps2ser_check();
|
||||
#endif
|
||||
;}
|
||||
if((out_pointer+1)==KBD_BUFFER_LEN)
|
||||
out_pointer=0;
|
||||
else
|
||||
out_pointer++;
|
||||
c=kbd_buffer[out_pointer];
|
||||
return (int)c;
|
||||
|
||||
}
|
||||
|
||||
/* Simple translation table for the keys */
|
||||
|
||||
static unsigned char kbd_plain_xlate[] = {
|
||||
0xff,0x1b, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=','\b','\t', /* 0x00 - 0x0f */
|
||||
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']','\r',0xff, 'a', 's', /* 0x10 - 0x1f */
|
||||
'd', 'f', 'g', 'h', 'j', 'k', 'l', ';','\'', '`',0xff,'\\', 'z', 'x', 'c', 'v', /* 0x20 - 0x2f */
|
||||
'b', 'n', 'm', ',', '.', '/',0xff,0xff,0xff, ' ',0xff,0xff,0xff,0xff,0xff,0xff, /* 0x30 - 0x3f */
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1', /* 0x40 - 0x4f */
|
||||
'2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0x50 - 0x5F */
|
||||
'\r',0xff,0xff
|
||||
};
|
||||
|
||||
static unsigned char kbd_shift_xlate[] = {
|
||||
0xff,0x1b, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+','\b','\t', /* 0x00 - 0x0f */
|
||||
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}','\r',0xff, 'A', 'S', /* 0x10 - 0x1f */
|
||||
'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~',0xff, '|', 'Z', 'X', 'C', 'V', /* 0x20 - 0x2f */
|
||||
'B', 'N', 'M', '<', '>', '?',0xff,0xff,0xff, ' ',0xff,0xff,0xff,0xff,0xff,0xff, /* 0x30 - 0x3f */
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1', /* 0x40 - 0x4f */
|
||||
'2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0x50 - 0x5F */
|
||||
'\r',0xff,0xff
|
||||
};
|
||||
|
||||
static unsigned char kbd_ctrl_xlate[] = {
|
||||
0xff,0x1b, '1',0x00, '3', '4', '5',0x1E, '7', '8', '9', '0',0x1F, '=','\b','\t', /* 0x00 - 0x0f */
|
||||
0x11,0x17,0x05,0x12,0x14,0x18,0x15,0x09,0x0f,0x10,0x1b,0x1d,'\n',0xff,0x01,0x13, /* 0x10 - 0x1f */
|
||||
0x04,0x06,0x08,0x09,0x0a,0x0b,0x0c, ';','\'', '~',0x00,0x1c,0x1a,0x18,0x03,0x16, /* 0x20 - 0x2f */
|
||||
0x02,0x0e,0x0d, '<', '>', '?',0xff,0xff,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xff, /* 0x30 - 0x3f */
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1', /* 0x40 - 0x4f */
|
||||
'2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0x50 - 0x5F */
|
||||
'\r',0xff,0xff
|
||||
};
|
||||
|
||||
|
||||
void handle_scancode(unsigned char scancode)
|
||||
{
|
||||
unsigned char keycode;
|
||||
|
||||
/* Convert scancode to keycode */
|
||||
PRINTF("scancode %x\n",scancode);
|
||||
if(scancode==0xe0) {
|
||||
e0=1; /* special charakters */
|
||||
return;
|
||||
}
|
||||
if(e0==1) {
|
||||
e0=0; /* delete flag */
|
||||
if(!( ((scancode&0x7F)==0x38)|| /* the right ctrl key */
|
||||
((scancode&0x7F)==0x1D)|| /* the right alt key */
|
||||
((scancode&0x7F)==0x35)|| /* the right '/' key */
|
||||
((scancode&0x7F)==0x1C) )) /* the right enter key */
|
||||
/* we swallow unknown e0 codes */
|
||||
return;
|
||||
}
|
||||
/* special cntrl keys */
|
||||
switch(scancode) {
|
||||
case 0x2A:
|
||||
case 0x36: /* shift pressed */
|
||||
shift=1;
|
||||
return; /* do nothing else */
|
||||
case 0xAA:
|
||||
case 0xB6: /* shift released */
|
||||
shift=0;
|
||||
return; /* do nothing else */
|
||||
case 0x38: /* alt pressed */
|
||||
alt=1;
|
||||
return; /* do nothing else */
|
||||
case 0xB8: /* alt released */
|
||||
alt=0;
|
||||
return; /* do nothing else */
|
||||
case 0x1d: /* ctrl pressed */
|
||||
ctrl=1;
|
||||
return; /* do nothing else */
|
||||
case 0x9d: /* ctrl released */
|
||||
ctrl=0;
|
||||
return; /* do nothing else */
|
||||
case 0x46: /* scrollock pressed */
|
||||
scroll_lock=~scroll_lock;
|
||||
if(scroll_lock==0)
|
||||
leds&=~LED_SCR; /* switch LED off */
|
||||
else
|
||||
leds|=LED_SCR; /* switch on LED */
|
||||
pckbd_leds(leds);
|
||||
return; /* do nothing else */
|
||||
case 0x3A: /* capslock pressed */
|
||||
caps_lock=~caps_lock;
|
||||
if(caps_lock==0)
|
||||
leds&=~LED_CAP; /* switch caps_lock off */
|
||||
else
|
||||
leds|=LED_CAP; /* switch on LED */
|
||||
pckbd_leds(leds);
|
||||
return;
|
||||
case 0x45: /* numlock pressed */
|
||||
num_lock=~num_lock;
|
||||
if(num_lock==0)
|
||||
leds&=~LED_NUM; /* switch LED off */
|
||||
else
|
||||
leds|=LED_NUM; /* switch on LED */
|
||||
pckbd_leds(leds);
|
||||
return;
|
||||
case 0xC6: /* scroll lock released */
|
||||
case 0xC5: /* num lock released */
|
||||
case 0xBA: /* caps lock released */
|
||||
return; /* just swallow */
|
||||
}
|
||||
#if 1
|
||||
if((scancode&0x80)==0x80) /* key released */
|
||||
return;
|
||||
#else
|
||||
if((scancode&0x80)==0x00) /* key pressed */
|
||||
return;
|
||||
scancode &= ~0x80;
|
||||
#endif
|
||||
/* now, decide which table we need */
|
||||
if(scancode > (sizeof(kbd_plain_xlate)/sizeof(kbd_plain_xlate[0]))) { /* scancode not in list */
|
||||
PRINTF("unkown scancode %X\n",scancode);
|
||||
return; /* swallow it */
|
||||
}
|
||||
/* setup plain code first */
|
||||
keycode=kbd_plain_xlate[scancode];
|
||||
if(caps_lock==1) { /* caps_lock is pressed, overwrite plain code */
|
||||
if(scancode > (sizeof(kbd_shift_xlate)/sizeof(kbd_shift_xlate[0]))) { /* scancode not in list */
|
||||
PRINTF("unkown caps-locked scancode %X\n",scancode);
|
||||
return; /* swallow it */
|
||||
}
|
||||
keycode=kbd_shift_xlate[scancode];
|
||||
if(keycode<'A') { /* we only want the alphas capital */
|
||||
keycode=kbd_plain_xlate[scancode];
|
||||
}
|
||||
}
|
||||
if(shift==1) { /* shift overwrites caps_lock */
|
||||
if(scancode > (sizeof(kbd_shift_xlate)/sizeof(kbd_shift_xlate[0]))) { /* scancode not in list */
|
||||
PRINTF("unkown shifted scancode %X\n",scancode);
|
||||
return; /* swallow it */
|
||||
}
|
||||
keycode=kbd_shift_xlate[scancode];
|
||||
}
|
||||
if(ctrl==1) { /* ctrl overwrites caps_lock and shift */
|
||||
if(scancode > (sizeof(kbd_ctrl_xlate)/sizeof(kbd_ctrl_xlate[0]))) { /* scancode not in list */
|
||||
PRINTF("unkown ctrl scancode %X\n",scancode);
|
||||
return; /* swallow it */
|
||||
}
|
||||
keycode=kbd_ctrl_xlate[scancode];
|
||||
}
|
||||
/* check if valid keycode */
|
||||
if(keycode==0xff) {
|
||||
PRINTF("unkown scancode %X\n",scancode);
|
||||
return; /* swallow unknown codes */
|
||||
}
|
||||
|
||||
kbd_put_queue(keycode);
|
||||
PRINTF("%x\n",keycode);
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* Init
|
||||
******************************************************************/
|
||||
|
||||
#ifdef CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE
|
||||
extern int overwrite_console (void);
|
||||
#define OVERWRITE_CONSOLE overwrite_console ()
|
||||
#else
|
||||
#define OVERWRITE_CONSOLE 0
|
||||
#endif /* CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE */
|
||||
|
||||
int kbd_init (void)
|
||||
{
|
||||
int error;
|
||||
struct stdio_dev kbddev ;
|
||||
char *stdinname = getenv ("stdin");
|
||||
|
||||
if(kbd_init_hw()==-1)
|
||||
return -1;
|
||||
memset (&kbddev, 0, sizeof(kbddev));
|
||||
strcpy(kbddev.name, DEVNAME);
|
||||
kbddev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
|
||||
kbddev.putc = NULL ;
|
||||
kbddev.puts = NULL ;
|
||||
kbddev.getc = kbd_getc ;
|
||||
kbddev.tstc = kbd_testc ;
|
||||
|
||||
error = stdio_register (&kbddev);
|
||||
if(error==0) {
|
||||
/* check if this is the standard input device */
|
||||
if(strcmp(stdinname,DEVNAME)==0) {
|
||||
/* reassign the console */
|
||||
if(OVERWRITE_CONSOLE) {
|
||||
return 1;
|
||||
}
|
||||
error=console_assign(stdin,DEVNAME);
|
||||
if(error==0)
|
||||
return 1;
|
||||
else
|
||||
return error;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
251
common/package/boot/uboot-ipq40xx/src/drivers/input/pc_keyb.c
Normal file
251
common/package/boot/uboot-ipq40xx/src/drivers/input/pc_keyb.c
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
/***********************************************************************
|
||||
*
|
||||
* (C) Copyright 2004
|
||||
* DENX Software Engineering
|
||||
* Wolfgang Denk, wd@denx.de
|
||||
*
|
||||
* PS/2 keyboard driver
|
||||
*
|
||||
* Originally from linux source (drivers/char/pc_keyb.c)
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
#include <keyboard.h>
|
||||
#include <pc_keyb.h>
|
||||
|
||||
#undef KBG_DEBUG
|
||||
|
||||
#ifdef KBG_DEBUG
|
||||
#define PRINTF(fmt,args...) printf (fmt ,##args)
|
||||
#else
|
||||
#define PRINTF(fmt,args...)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* This reads the keyboard status port, and does the
|
||||
* appropriate action.
|
||||
*
|
||||
*/
|
||||
static unsigned char handle_kbd_event(void)
|
||||
{
|
||||
unsigned char status = kbd_read_status();
|
||||
unsigned int work = 10000;
|
||||
|
||||
while ((--work > 0) && (status & KBD_STAT_OBF)) {
|
||||
unsigned char scancode;
|
||||
|
||||
scancode = kbd_read_input();
|
||||
|
||||
/* Error bytes must be ignored to make the
|
||||
Synaptics touchpads compaq use work */
|
||||
/* Ignore error bytes */
|
||||
if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR))) {
|
||||
if (status & KBD_STAT_MOUSE_OBF)
|
||||
; /* not supported: handle_mouse_event(scancode); */
|
||||
else
|
||||
handle_scancode(scancode);
|
||||
}
|
||||
status = kbd_read_status();
|
||||
}
|
||||
if (!work)
|
||||
PRINTF("pc_keyb: controller jammed (0x%02X).\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static int kbd_read_data(void)
|
||||
{
|
||||
int val;
|
||||
unsigned char status;
|
||||
|
||||
val = -1;
|
||||
status = kbd_read_status();
|
||||
if (status & KBD_STAT_OBF) {
|
||||
val = kbd_read_input();
|
||||
if (status & (KBD_STAT_GTO | KBD_STAT_PERR))
|
||||
val = -2;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static int kbd_wait_for_input(void)
|
||||
{
|
||||
unsigned long timeout;
|
||||
int val;
|
||||
|
||||
timeout = KBD_TIMEOUT;
|
||||
val=kbd_read_data();
|
||||
while(val < 0) {
|
||||
if(timeout--==0)
|
||||
return -1;
|
||||
udelay(1000);
|
||||
val=kbd_read_data();
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
static int kb_wait(void)
|
||||
{
|
||||
unsigned long timeout = KBC_TIMEOUT * 10;
|
||||
|
||||
do {
|
||||
unsigned char status = handle_kbd_event();
|
||||
if (!(status & KBD_STAT_IBF))
|
||||
return 0; /* ok */
|
||||
udelay(1000);
|
||||
timeout--;
|
||||
} while (timeout);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void kbd_write_command_w(int data)
|
||||
{
|
||||
if(kb_wait())
|
||||
PRINTF("timeout in kbd_write_command_w\n");
|
||||
kbd_write_command(data);
|
||||
}
|
||||
|
||||
static void kbd_write_output_w(int data)
|
||||
{
|
||||
if(kb_wait())
|
||||
PRINTF("timeout in kbd_write_output_w\n");
|
||||
kbd_write_output(data);
|
||||
}
|
||||
|
||||
static void kbd_send_data(unsigned char data)
|
||||
{
|
||||
kbd_write_output_w(data);
|
||||
kbd_wait_for_input();
|
||||
}
|
||||
|
||||
|
||||
static char * kbd_initialize(void)
|
||||
{
|
||||
int status;
|
||||
|
||||
/*
|
||||
* Test the keyboard interface.
|
||||
* This seems to be the only way to get it going.
|
||||
* If the test is successful a x55 is placed in the input buffer.
|
||||
*/
|
||||
kbd_write_command_w(KBD_CCMD_SELF_TEST);
|
||||
if (kbd_wait_for_input() != 0x55)
|
||||
return "Kbd: failed self test";
|
||||
/*
|
||||
* Perform a keyboard interface test. This causes the controller
|
||||
* to test the keyboard clock and data lines. The results of the
|
||||
* test are placed in the input buffer.
|
||||
*/
|
||||
kbd_write_command_w(KBD_CCMD_KBD_TEST);
|
||||
if (kbd_wait_for_input() != 0x00)
|
||||
return "Kbd: interface failed self test";
|
||||
/*
|
||||
* Enable the keyboard by allowing the keyboard clock to run.
|
||||
*/
|
||||
kbd_write_command_w(KBD_CCMD_KBD_ENABLE);
|
||||
|
||||
/*
|
||||
* Reset keyboard. If the read times out
|
||||
* then the assumption is that no keyboard is
|
||||
* plugged into the machine.
|
||||
* This defaults the keyboard to scan-code set 2.
|
||||
*
|
||||
* Set up to try again if the keyboard asks for RESEND.
|
||||
*/
|
||||
do {
|
||||
kbd_write_output_w(KBD_CMD_RESET);
|
||||
status = kbd_wait_for_input();
|
||||
if (status == KBD_REPLY_ACK)
|
||||
break;
|
||||
if (status != KBD_REPLY_RESEND) {
|
||||
PRINTF("status: %X\n",status);
|
||||
return "Kbd: reset failed, no ACK";
|
||||
}
|
||||
} while (1);
|
||||
if (kbd_wait_for_input() != KBD_REPLY_POR)
|
||||
return "Kbd: reset failed, no POR";
|
||||
|
||||
/*
|
||||
* Set keyboard controller mode. During this, the keyboard should be
|
||||
* in the disabled state.
|
||||
*
|
||||
* Set up to try again if the keyboard asks for RESEND.
|
||||
*/
|
||||
do {
|
||||
kbd_write_output_w(KBD_CMD_DISABLE);
|
||||
status = kbd_wait_for_input();
|
||||
if (status == KBD_REPLY_ACK)
|
||||
break;
|
||||
if (status != KBD_REPLY_RESEND)
|
||||
return "Kbd: disable keyboard: no ACK";
|
||||
} while (1);
|
||||
|
||||
kbd_write_command_w(KBD_CCMD_WRITE_MODE);
|
||||
kbd_write_output_w(KBD_MODE_KBD_INT
|
||||
| KBD_MODE_SYS
|
||||
| KBD_MODE_DISABLE_MOUSE
|
||||
| KBD_MODE_KCC);
|
||||
|
||||
/* AMCC powerpc portables need this to use scan-code set 1 -- Cort */
|
||||
kbd_write_command_w(KBD_CCMD_READ_MODE);
|
||||
if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
|
||||
/*
|
||||
* If the controller does not support conversion,
|
||||
* Set the keyboard to scan-code set 1.
|
||||
*/
|
||||
kbd_write_output_w(0xF0);
|
||||
kbd_wait_for_input();
|
||||
kbd_write_output_w(0x01);
|
||||
kbd_wait_for_input();
|
||||
}
|
||||
kbd_write_output_w(KBD_CMD_ENABLE);
|
||||
if (kbd_wait_for_input() != KBD_REPLY_ACK)
|
||||
return "Kbd: enable keyboard: no ACK";
|
||||
|
||||
/*
|
||||
* Finally, set the typematic rate to maximum.
|
||||
*/
|
||||
kbd_write_output_w(KBD_CMD_SET_RATE);
|
||||
if (kbd_wait_for_input() != KBD_REPLY_ACK)
|
||||
return "Kbd: Set rate: no ACK";
|
||||
kbd_write_output_w(0x00);
|
||||
if (kbd_wait_for_input() != KBD_REPLY_ACK)
|
||||
return "Kbd: Set rate: no ACK";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void kbd_interrupt(void *dev_id)
|
||||
{
|
||||
handle_kbd_event();
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* Init
|
||||
******************************************************************/
|
||||
|
||||
int kbd_init_hw(void)
|
||||
{
|
||||
char* result;
|
||||
|
||||
kbd_request_region();
|
||||
|
||||
result=kbd_initialize();
|
||||
if (result==NULL) {
|
||||
PRINTF("AT Keyboard initialized\n");
|
||||
kbd_request_irq(kbd_interrupt);
|
||||
return (1);
|
||||
} else {
|
||||
printf("%s\n",result);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
void pckbd_leds(unsigned char leds)
|
||||
{
|
||||
kbd_send_data(KBD_CMD_SET_LEDS);
|
||||
kbd_send_data(leds);
|
||||
}
|
||||
461
common/package/boot/uboot-ipq40xx/src/drivers/input/ps2mult.c
Normal file
461
common/package/boot/uboot-ipq40xx/src/drivers/input/ps2mult.c
Normal file
|
|
@ -0,0 +1,461 @@
|
|||
/***********************************************************************
|
||||
*
|
||||
* (C) Copyright 2004
|
||||
* DENX Software Engineering
|
||||
* Wolfgang Denk, wd@denx.de
|
||||
*
|
||||
* PS/2 multiplexer driver
|
||||
*
|
||||
* Originally from linux source (drivers/char/ps2mult.c)
|
||||
*
|
||||
* Uses simple serial driver (ps2ser.c) to access the multiplexer
|
||||
* Used by PS/2 keyboard driver (pc_keyb.c)
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
#include <pc_keyb.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <ps2mult.h>
|
||||
|
||||
/* #define DEBUG_MULT */
|
||||
/* #define DEBUG_KEYB */
|
||||
|
||||
#define KBD_STAT_DEFAULT (KBD_STAT_SELFTEST | KBD_STAT_UNLOCKED)
|
||||
|
||||
#define PRINTF(format, args...) printf("ps2mult.c: " format, ## args)
|
||||
|
||||
#ifdef DEBUG_MULT
|
||||
#define PRINTF_MULT(format, args...) printf("PS2MULT: " format, ## args)
|
||||
#else
|
||||
#define PRINTF_MULT(format, args...)
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_KEYB
|
||||
#define PRINTF_KEYB(format, args...) printf("KEYB: " format, ## args)
|
||||
#else
|
||||
#define PRINTF_KEYB(format, args...)
|
||||
#endif
|
||||
|
||||
|
||||
static ulong start_time;
|
||||
static int init_done = 0;
|
||||
|
||||
static int received_escape = 0;
|
||||
static int received_bsync = 0;
|
||||
static int received_selector = 0;
|
||||
|
||||
static int kbd_command_active = 0;
|
||||
static int mouse_command_active = 0;
|
||||
static int ctl_command_active = 0;
|
||||
|
||||
static u_char command_byte = 0;
|
||||
|
||||
static void (*keyb_handler)(void *dev_id);
|
||||
|
||||
static u_char ps2mult_buf [PS2BUF_SIZE];
|
||||
static atomic_t ps2mult_buf_cnt;
|
||||
static int ps2mult_buf_in_idx;
|
||||
static int ps2mult_buf_out_idx;
|
||||
|
||||
static u_char ps2mult_buf_status [PS2BUF_SIZE];
|
||||
|
||||
#ifndef CONFIG_BOARD_EARLY_INIT_R
|
||||
#error #define CONFIG_BOARD_EARLY_INIT_R and call ps2mult_early_init() in board_early_init_r()
|
||||
#endif
|
||||
void ps2mult_early_init (void)
|
||||
{
|
||||
start_time = get_timer(0);
|
||||
}
|
||||
|
||||
static void ps2mult_send_byte(u_char byte, u_char sel)
|
||||
{
|
||||
ps2ser_putc(sel);
|
||||
|
||||
if (sel == PS2MULT_KB_SELECTOR) {
|
||||
PRINTF_MULT("0x%02x send KEYBOARD\n", byte);
|
||||
kbd_command_active = 1;
|
||||
} else {
|
||||
PRINTF_MULT("0x%02x send MOUSE\n", byte);
|
||||
mouse_command_active = 1;
|
||||
}
|
||||
|
||||
switch (byte) {
|
||||
case PS2MULT_ESCAPE:
|
||||
case PS2MULT_BSYNC:
|
||||
case PS2MULT_KB_SELECTOR:
|
||||
case PS2MULT_MS_SELECTOR:
|
||||
case PS2MULT_SESSION_START:
|
||||
case PS2MULT_SESSION_END:
|
||||
ps2ser_putc(PS2MULT_ESCAPE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ps2ser_putc(byte);
|
||||
}
|
||||
|
||||
static void ps2mult_receive_byte(u_char byte, u_char sel)
|
||||
{
|
||||
u_char status = KBD_STAT_DEFAULT;
|
||||
|
||||
#if 1 /* Ignore mouse in U-Boot */
|
||||
if (sel == PS2MULT_MS_SELECTOR) return;
|
||||
#endif
|
||||
|
||||
if (sel == PS2MULT_KB_SELECTOR) {
|
||||
if (kbd_command_active) {
|
||||
if (!received_bsync) {
|
||||
PRINTF_MULT("0x%02x lost KEYBOARD !!!\n", byte);
|
||||
return;
|
||||
} else {
|
||||
kbd_command_active = 0;
|
||||
received_bsync = 0;
|
||||
}
|
||||
}
|
||||
PRINTF_MULT("0x%02x receive KEYBOARD\n", byte);
|
||||
status |= KBD_STAT_IBF | KBD_STAT_OBF;
|
||||
} else {
|
||||
if (mouse_command_active) {
|
||||
if (!received_bsync) {
|
||||
PRINTF_MULT("0x%02x lost MOUSE !!!\n", byte);
|
||||
return;
|
||||
} else {
|
||||
mouse_command_active = 0;
|
||||
received_bsync = 0;
|
||||
}
|
||||
}
|
||||
PRINTF_MULT("0x%02x receive MOUSE\n", byte);
|
||||
status |= KBD_STAT_IBF | KBD_STAT_OBF | KBD_STAT_MOUSE_OBF;
|
||||
}
|
||||
|
||||
if (atomic_read(&ps2mult_buf_cnt) < PS2BUF_SIZE) {
|
||||
ps2mult_buf_status[ps2mult_buf_in_idx] = status;
|
||||
ps2mult_buf[ps2mult_buf_in_idx++] = byte;
|
||||
ps2mult_buf_in_idx &= (PS2BUF_SIZE - 1);
|
||||
atomic_inc(&ps2mult_buf_cnt);
|
||||
} else {
|
||||
PRINTF("buffer overflow\n");
|
||||
}
|
||||
|
||||
if (received_bsync) {
|
||||
PRINTF("unexpected BSYNC\n");
|
||||
received_bsync = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ps2mult_callback (int in_cnt)
|
||||
{
|
||||
int i;
|
||||
u_char byte;
|
||||
static int keyb_handler_active = 0;
|
||||
|
||||
if (!init_done) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < in_cnt; i ++) {
|
||||
byte = ps2ser_getc();
|
||||
|
||||
if (received_escape) {
|
||||
ps2mult_receive_byte(byte, received_selector);
|
||||
received_escape = 0;
|
||||
} else switch (byte) {
|
||||
case PS2MULT_ESCAPE:
|
||||
PRINTF_MULT("ESCAPE receive\n");
|
||||
received_escape = 1;
|
||||
break;
|
||||
|
||||
case PS2MULT_BSYNC:
|
||||
PRINTF_MULT("BSYNC receive\n");
|
||||
received_bsync = 1;
|
||||
break;
|
||||
|
||||
case PS2MULT_KB_SELECTOR:
|
||||
case PS2MULT_MS_SELECTOR:
|
||||
PRINTF_MULT("%s receive\n",
|
||||
byte == PS2MULT_KB_SELECTOR ? "KB_SEL" : "MS_SEL");
|
||||
received_selector = byte;
|
||||
break;
|
||||
|
||||
case PS2MULT_SESSION_START:
|
||||
case PS2MULT_SESSION_END:
|
||||
PRINTF_MULT("%s receive\n",
|
||||
byte == PS2MULT_SESSION_START ?
|
||||
"SESSION_START" : "SESSION_END");
|
||||
break;
|
||||
|
||||
default:
|
||||
ps2mult_receive_byte(byte, received_selector);
|
||||
}
|
||||
}
|
||||
|
||||
if (keyb_handler && !keyb_handler_active &&
|
||||
atomic_read(&ps2mult_buf_cnt)) {
|
||||
keyb_handler_active = 1;
|
||||
keyb_handler(NULL);
|
||||
keyb_handler_active = 0;
|
||||
}
|
||||
}
|
||||
|
||||
u_char ps2mult_read_status(void)
|
||||
{
|
||||
u_char byte;
|
||||
|
||||
if (atomic_read(&ps2mult_buf_cnt) == 0) {
|
||||
ps2ser_check();
|
||||
}
|
||||
|
||||
if (atomic_read(&ps2mult_buf_cnt)) {
|
||||
byte = ps2mult_buf_status[ps2mult_buf_out_idx];
|
||||
} else {
|
||||
byte = KBD_STAT_DEFAULT;
|
||||
}
|
||||
PRINTF_KEYB("read_status()=0x%02x\n", byte);
|
||||
return byte;
|
||||
}
|
||||
|
||||
u_char ps2mult_read_input(void)
|
||||
{
|
||||
u_char byte = 0;
|
||||
|
||||
if (atomic_read(&ps2mult_buf_cnt) == 0) {
|
||||
ps2ser_check();
|
||||
}
|
||||
|
||||
if (atomic_read(&ps2mult_buf_cnt)) {
|
||||
byte = ps2mult_buf[ps2mult_buf_out_idx++];
|
||||
ps2mult_buf_out_idx &= (PS2BUF_SIZE - 1);
|
||||
atomic_dec(&ps2mult_buf_cnt);
|
||||
}
|
||||
PRINTF_KEYB("read_input()=0x%02x\n", byte);
|
||||
return byte;
|
||||
}
|
||||
|
||||
void ps2mult_write_output(u_char val)
|
||||
{
|
||||
int i;
|
||||
|
||||
PRINTF_KEYB("write_output(0x%02x)\n", val);
|
||||
|
||||
for (i = 0; i < KBD_TIMEOUT; i++) {
|
||||
if (!kbd_command_active && !mouse_command_active) {
|
||||
break;
|
||||
}
|
||||
udelay(1000);
|
||||
ps2ser_check();
|
||||
}
|
||||
|
||||
if (kbd_command_active) {
|
||||
PRINTF("keyboard command not acknoledged\n");
|
||||
kbd_command_active = 0;
|
||||
}
|
||||
|
||||
if (mouse_command_active) {
|
||||
PRINTF("mouse command not acknoledged\n");
|
||||
mouse_command_active = 0;
|
||||
}
|
||||
|
||||
if (ctl_command_active) {
|
||||
switch (ctl_command_active) {
|
||||
case KBD_CCMD_WRITE_MODE:
|
||||
/* Scan code conversion not supported */
|
||||
command_byte = val & ~KBD_MODE_KCC;
|
||||
break;
|
||||
|
||||
case KBD_CCMD_WRITE_AUX_OBUF:
|
||||
ps2mult_receive_byte(val, PS2MULT_MS_SELECTOR);
|
||||
break;
|
||||
|
||||
case KBD_CCMD_WRITE_MOUSE:
|
||||
ps2mult_send_byte(val, PS2MULT_MS_SELECTOR);
|
||||
break;
|
||||
|
||||
default:
|
||||
PRINTF("invalid controller command\n");
|
||||
break;
|
||||
}
|
||||
|
||||
ctl_command_active = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
ps2mult_send_byte(val, PS2MULT_KB_SELECTOR);
|
||||
}
|
||||
|
||||
void ps2mult_write_command(u_char val)
|
||||
{
|
||||
ctl_command_active = 0;
|
||||
|
||||
PRINTF_KEYB("write_command(0x%02x)\n", val);
|
||||
|
||||
switch (val) {
|
||||
case KBD_CCMD_READ_MODE:
|
||||
ps2mult_receive_byte(command_byte, PS2MULT_KB_SELECTOR);
|
||||
break;
|
||||
|
||||
case KBD_CCMD_WRITE_MODE:
|
||||
ctl_command_active = val;
|
||||
break;
|
||||
|
||||
case KBD_CCMD_MOUSE_DISABLE:
|
||||
break;
|
||||
|
||||
case KBD_CCMD_MOUSE_ENABLE:
|
||||
break;
|
||||
|
||||
case KBD_CCMD_SELF_TEST:
|
||||
ps2mult_receive_byte(0x55, PS2MULT_KB_SELECTOR);
|
||||
break;
|
||||
|
||||
case KBD_CCMD_KBD_TEST:
|
||||
ps2mult_receive_byte(0x00, PS2MULT_KB_SELECTOR);
|
||||
break;
|
||||
|
||||
case KBD_CCMD_KBD_DISABLE:
|
||||
break;
|
||||
|
||||
case KBD_CCMD_KBD_ENABLE:
|
||||
break;
|
||||
|
||||
case KBD_CCMD_WRITE_AUX_OBUF:
|
||||
ctl_command_active = val;
|
||||
break;
|
||||
|
||||
case KBD_CCMD_WRITE_MOUSE:
|
||||
ctl_command_active = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
PRINTF("invalid controller command\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int ps2mult_getc_w (void)
|
||||
{
|
||||
int res = -1;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < KBD_TIMEOUT; i++) {
|
||||
if (ps2ser_check()) {
|
||||
res = ps2ser_getc();
|
||||
break;
|
||||
}
|
||||
udelay(1000);
|
||||
}
|
||||
|
||||
switch (res) {
|
||||
case PS2MULT_KB_SELECTOR:
|
||||
case PS2MULT_MS_SELECTOR:
|
||||
received_selector = res;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int ps2mult_init (void)
|
||||
{
|
||||
int byte;
|
||||
int kbd_found = 0;
|
||||
int mouse_found = 0;
|
||||
|
||||
while (get_timer(start_time) < CONFIG_PS2MULT_DELAY);
|
||||
|
||||
ps2ser_init();
|
||||
|
||||
ps2ser_putc(PS2MULT_SESSION_START);
|
||||
|
||||
ps2ser_putc(PS2MULT_KB_SELECTOR);
|
||||
ps2ser_putc(KBD_CMD_RESET);
|
||||
|
||||
do {
|
||||
byte = ps2mult_getc_w();
|
||||
} while (byte >= 0 && byte != KBD_REPLY_ACK);
|
||||
|
||||
if (byte == KBD_REPLY_ACK) {
|
||||
byte = ps2mult_getc_w();
|
||||
if (byte == 0xaa) {
|
||||
kbd_found = 1;
|
||||
puts("keyboard");
|
||||
}
|
||||
}
|
||||
|
||||
if (!kbd_found) {
|
||||
while (byte >= 0) {
|
||||
byte = ps2mult_getc_w();
|
||||
}
|
||||
}
|
||||
|
||||
#if 1 /* detect mouse */
|
||||
ps2ser_putc(PS2MULT_MS_SELECTOR);
|
||||
ps2ser_putc(AUX_RESET);
|
||||
|
||||
do {
|
||||
byte = ps2mult_getc_w();
|
||||
} while (byte >= 0 && byte != AUX_ACK);
|
||||
|
||||
if (byte == AUX_ACK) {
|
||||
byte = ps2mult_getc_w();
|
||||
if (byte == 0xaa) {
|
||||
byte = ps2mult_getc_w();
|
||||
if (byte == 0x00) {
|
||||
mouse_found = 1;
|
||||
puts(", mouse");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!mouse_found) {
|
||||
while (byte >= 0) {
|
||||
byte = ps2mult_getc_w();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mouse_found || kbd_found) {
|
||||
if (!received_selector) {
|
||||
if (mouse_found) {
|
||||
received_selector = PS2MULT_MS_SELECTOR;
|
||||
} else {
|
||||
received_selector = PS2MULT_KB_SELECTOR;
|
||||
}
|
||||
}
|
||||
|
||||
init_done = 1;
|
||||
} else {
|
||||
puts("No device found");
|
||||
}
|
||||
|
||||
puts("\n");
|
||||
|
||||
#if 0 /* for testing */
|
||||
{
|
||||
int i;
|
||||
u_char key[] = {
|
||||
0x1f, 0x12, 0x14, 0x12, 0x31, 0x2f, 0x39, /* setenv */
|
||||
0x1f, 0x14, 0x20, 0x17, 0x31, 0x39, /* stdin */
|
||||
0x1f, 0x12, 0x13, 0x17, 0x1e, 0x26, 0x1c, /* serial */
|
||||
};
|
||||
|
||||
for (i = 0; i < sizeof (key); i++) {
|
||||
ps2mult_receive_byte (key[i], PS2MULT_KB_SELECTOR);
|
||||
ps2mult_receive_byte (key[i] | 0x80, PS2MULT_KB_SELECTOR);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return init_done ? 0 : -1;
|
||||
}
|
||||
|
||||
int ps2mult_request_irq(void (*handler)(void *))
|
||||
{
|
||||
keyb_handler = handler;
|
||||
|
||||
return 0;
|
||||
}
|
||||
241
common/package/boot/uboot-ipq40xx/src/drivers/input/ps2ser.c
Normal file
241
common/package/boot/uboot-ipq40xx/src/drivers/input/ps2ser.c
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
/***********************************************************************
|
||||
*
|
||||
* (C) Copyright 2004-2009
|
||||
* DENX Software Engineering
|
||||
* Wolfgang Denk, wd@denx.de
|
||||
*
|
||||
* Simple 16550A serial driver
|
||||
*
|
||||
* Originally from linux source (drivers/char/ps2ser.c)
|
||||
*
|
||||
* Used by the PS/2 multiplexer driver (ps2mult.c)
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <ps2mult.h>
|
||||
/* This is needed for ns16550.h */
|
||||
#ifndef CONFIG_SYS_NS16550_REG_SIZE
|
||||
#define CONFIG_SYS_NS16550_REG_SIZE 1
|
||||
#endif
|
||||
#include <ns16550.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/* #define DEBUG */
|
||||
|
||||
#define PS2SER_BAUD 57600
|
||||
|
||||
#ifdef CONFIG_MPC5xxx
|
||||
#if CONFIG_PS2SERIAL == 1
|
||||
#define PSC_BASE MPC5XXX_PSC1
|
||||
#elif CONFIG_PS2SERIAL == 2
|
||||
#define PSC_BASE MPC5XXX_PSC2
|
||||
#elif CONFIG_PS2SERIAL == 3
|
||||
#define PSC_BASE MPC5XXX_PSC3
|
||||
#elif CONFIG_PS2SERIAL == 4
|
||||
#define PSC_BASE MPC5XXX_PSC4
|
||||
#elif CONFIG_PS2SERIAL == 5
|
||||
#define PSC_BASE MPC5XXX_PSC5
|
||||
#elif CONFIG_PS2SERIAL == 6
|
||||
#define PSC_BASE MPC5XXX_PSC6
|
||||
#else
|
||||
#error CONFIG_PS2SERIAL must be in 1 ... 6
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#if CONFIG_PS2SERIAL == 1
|
||||
#define COM_BASE (CONFIG_SYS_CCSRBAR+0x4500)
|
||||
#elif CONFIG_PS2SERIAL == 2
|
||||
#define COM_BASE (CONFIG_SYS_CCSRBAR+0x4600)
|
||||
#else
|
||||
#error CONFIG_PS2SERIAL must be in 1 ... 2
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_MPC5xxx / other */
|
||||
|
||||
static int ps2ser_getc_hw(void);
|
||||
static void ps2ser_interrupt(void *dev_id);
|
||||
|
||||
extern struct serial_state rs_table[]; /* in serial.c */
|
||||
|
||||
static u_char ps2buf[PS2BUF_SIZE];
|
||||
static atomic_t ps2buf_cnt;
|
||||
static int ps2buf_in_idx;
|
||||
static int ps2buf_out_idx;
|
||||
|
||||
#ifdef CONFIG_MPC5xxx
|
||||
int ps2ser_init(void)
|
||||
{
|
||||
volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
|
||||
unsigned long baseclk;
|
||||
int div;
|
||||
|
||||
/* reset PSC */
|
||||
psc->command = PSC_SEL_MODE_REG_1;
|
||||
|
||||
/* select clock sources */
|
||||
psc->psc_clock_select = 0;
|
||||
baseclk = (gd->ipb_clk + 16) / 32;
|
||||
|
||||
/* switch to UART mode */
|
||||
psc->sicr = 0;
|
||||
|
||||
/* configure parity, bit length and so on */
|
||||
psc->mode = PSC_MODE_8_BITS | PSC_MODE_PARNONE;
|
||||
psc->mode = PSC_MODE_ONE_STOP;
|
||||
|
||||
/* set up UART divisor */
|
||||
div = (baseclk + (PS2SER_BAUD/2)) / PS2SER_BAUD;
|
||||
psc->ctur = (div >> 8) & 0xff;
|
||||
psc->ctlr = div & 0xff;
|
||||
|
||||
/* disable all interrupts */
|
||||
psc->psc_imr = 0;
|
||||
|
||||
/* reset and enable Rx/Tx */
|
||||
psc->command = PSC_RST_RX;
|
||||
psc->command = PSC_RST_TX;
|
||||
psc->command = PSC_RX_ENABLE | PSC_TX_ENABLE;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int ps2ser_init(void)
|
||||
{
|
||||
NS16550_t com_port = (NS16550_t)COM_BASE;
|
||||
|
||||
com_port->ier = 0x00;
|
||||
com_port->lcr = UART_LCR_BKSE | UART_LCR_8N1;
|
||||
com_port->dll = (CONFIG_SYS_NS16550_CLK / 16 / PS2SER_BAUD) & 0xff;
|
||||
com_port->dlm = ((CONFIG_SYS_NS16550_CLK / 16 / PS2SER_BAUD) >> 8) & 0xff;
|
||||
com_port->lcr = UART_LCR_8N1;
|
||||
com_port->mcr = (UART_MCR_DTR | UART_MCR_RTS);
|
||||
com_port->fcr = (UART_FCR_FIFO_EN | UART_FCR_RXSR | UART_FCR_TXSR);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MPC5xxx / other */
|
||||
|
||||
void ps2ser_putc(int chr)
|
||||
{
|
||||
#ifdef CONFIG_MPC5xxx
|
||||
volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
|
||||
#else
|
||||
NS16550_t com_port = (NS16550_t)COM_BASE;
|
||||
#endif
|
||||
debug(">>>> 0x%02x\n", chr);
|
||||
|
||||
#ifdef CONFIG_MPC5xxx
|
||||
while (!(psc->psc_status & PSC_SR_TXRDY));
|
||||
|
||||
psc->psc_buffer_8 = chr;
|
||||
#else
|
||||
while ((com_port->lsr & UART_LSR_THRE) == 0);
|
||||
com_port->thr = chr;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int ps2ser_getc_hw(void)
|
||||
{
|
||||
#ifdef CONFIG_MPC5xxx
|
||||
volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
|
||||
#else
|
||||
NS16550_t com_port = (NS16550_t)COM_BASE;
|
||||
#endif
|
||||
int res = -1;
|
||||
|
||||
#ifdef CONFIG_MPC5xxx
|
||||
if (psc->psc_status & PSC_SR_RXRDY) {
|
||||
res = (psc->psc_buffer_8);
|
||||
}
|
||||
#else
|
||||
if (com_port->lsr & UART_LSR_DR) {
|
||||
res = com_port->rbr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int ps2ser_getc(void)
|
||||
{
|
||||
volatile int chr;
|
||||
int flags;
|
||||
|
||||
debug("<< ");
|
||||
|
||||
flags = disable_interrupts();
|
||||
|
||||
do {
|
||||
if (atomic_read(&ps2buf_cnt) != 0) {
|
||||
chr = ps2buf[ps2buf_out_idx++];
|
||||
ps2buf_out_idx &= (PS2BUF_SIZE - 1);
|
||||
atomic_dec(&ps2buf_cnt);
|
||||
} else {
|
||||
chr = ps2ser_getc_hw();
|
||||
}
|
||||
}
|
||||
while (chr < 0);
|
||||
|
||||
if (flags)
|
||||
enable_interrupts();
|
||||
|
||||
debug("0x%02x\n", chr);
|
||||
|
||||
return chr;
|
||||
}
|
||||
|
||||
int ps2ser_check(void)
|
||||
{
|
||||
int flags;
|
||||
|
||||
flags = disable_interrupts();
|
||||
ps2ser_interrupt(NULL);
|
||||
if (flags) enable_interrupts();
|
||||
|
||||
return atomic_read(&ps2buf_cnt);
|
||||
}
|
||||
|
||||
static void ps2ser_interrupt(void *dev_id)
|
||||
{
|
||||
#ifdef CONFIG_MPC5xxx
|
||||
volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
|
||||
#else
|
||||
NS16550_t com_port = (NS16550_t)COM_BASE;
|
||||
#endif
|
||||
int chr;
|
||||
int status;
|
||||
|
||||
do {
|
||||
chr = ps2ser_getc_hw();
|
||||
#ifdef CONFIG_MPC5xxx
|
||||
status = psc->psc_status;
|
||||
#else
|
||||
status = com_port->lsr;
|
||||
#endif
|
||||
if (chr < 0) continue;
|
||||
|
||||
if (atomic_read(&ps2buf_cnt) < PS2BUF_SIZE) {
|
||||
ps2buf[ps2buf_in_idx++] = chr;
|
||||
ps2buf_in_idx &= (PS2BUF_SIZE - 1);
|
||||
atomic_inc(&ps2buf_cnt);
|
||||
} else {
|
||||
printf ("ps2ser.c: buffer overflow\n");
|
||||
}
|
||||
#ifdef CONFIG_MPC5xxx
|
||||
} while (status & PSC_SR_RXRDY);
|
||||
#else
|
||||
} while (status & UART_LSR_DR);
|
||||
#endif
|
||||
if (atomic_read(&ps2buf_cnt)) {
|
||||
ps2mult_callback(atomic_read(&ps2buf_cnt));
|
||||
}
|
||||
}
|
||||
375
common/package/boot/uboot-ipq40xx/src/drivers/input/tegra-kbc.c
Normal file
375
common/package/boot/uboot-ipq40xx/src/drivers/input/tegra-kbc.c
Normal file
|
|
@ -0,0 +1,375 @@
|
|||
/*
|
||||
* (C) Copyright 2011
|
||||
* NVIDIA Corporation <www.nvidia.com>
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <fdtdec.h>
|
||||
#include <input.h>
|
||||
#include <key_matrix.h>
|
||||
#include <stdio_dev.h>
|
||||
#include <tegra-kbc.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/funcmux.h>
|
||||
#include <asm/arch/timer.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
enum {
|
||||
KBC_MAX_GPIO = 24,
|
||||
KBC_MAX_KPENT = 8, /* size of keypress entry queue */
|
||||
};
|
||||
|
||||
#define KBC_FIFO_TH_CNT_SHIFT 14
|
||||
#define KBC_DEBOUNCE_CNT_SHIFT 4
|
||||
#define KBC_CONTROL_FIFO_CNT_INT_EN (1 << 3)
|
||||
#define KBC_CONTROL_KBC_EN (1 << 0)
|
||||
#define KBC_INT_FIFO_CNT_INT_STATUS (1 << 2)
|
||||
#define KBC_KPENT_VALID (1 << 7)
|
||||
#define KBC_ST_STATUS (1 << 3)
|
||||
|
||||
enum {
|
||||
KBC_DEBOUNCE_COUNT = 2,
|
||||
KBC_REPEAT_RATE_MS = 30,
|
||||
KBC_REPEAT_DELAY_MS = 240,
|
||||
KBC_CLOCK_KHZ = 32, /* Keyboard uses a 32KHz clock */
|
||||
};
|
||||
|
||||
/* keyboard controller config and state */
|
||||
static struct keyb {
|
||||
struct input_config input; /* The input layer */
|
||||
struct key_matrix matrix; /* The key matrix layer */
|
||||
|
||||
struct kbc_tegra *kbc; /* tegra keyboard controller */
|
||||
unsigned char inited; /* 1 if keyboard has been inited */
|
||||
unsigned char first_scan; /* 1 if this is our first key scan */
|
||||
|
||||
/*
|
||||
* After init we must wait a short time before polling the keyboard.
|
||||
* This gives the tegra keyboard controller time to react after reset
|
||||
* and lets us grab keys pressed during reset.
|
||||
*/
|
||||
unsigned int init_dly_ms; /* Delay before we can read keyboard */
|
||||
unsigned int start_time_ms; /* Time that we inited (in ms) */
|
||||
unsigned int last_poll_ms; /* Time we should last polled */
|
||||
unsigned int next_repeat_ms; /* Next time we repeat a key */
|
||||
} config;
|
||||
|
||||
/**
|
||||
* reads the keyboard fifo for current keypresses
|
||||
*
|
||||
* @param config Keyboard config
|
||||
* @param fifo Place to put fifo results
|
||||
* @param max_keycodes Maximum number of key codes to put in the fifo
|
||||
* @return number of items put into fifo
|
||||
*/
|
||||
static int tegra_kbc_find_keys(struct keyb *config, int *fifo,
|
||||
int max_keycodes)
|
||||
{
|
||||
struct key_matrix_key keys[KBC_MAX_KPENT], *key;
|
||||
u32 kp_ent = 0;
|
||||
int i;
|
||||
|
||||
for (key = keys, i = 0; i < KBC_MAX_KPENT; i++, key++) {
|
||||
/* Get next word */
|
||||
if (!(i & 3))
|
||||
kp_ent = readl(&config->kbc->kp_ent[i / 4]);
|
||||
|
||||
key->valid = (kp_ent & KBC_KPENT_VALID) != 0;
|
||||
key->row = (kp_ent >> 3) & 0xf;
|
||||
key->col = kp_ent & 0x7;
|
||||
|
||||
/* Shift to get next entry */
|
||||
kp_ent >>= 8;
|
||||
}
|
||||
return key_matrix_decode(&config->matrix, keys, KBC_MAX_KPENT, fifo,
|
||||
max_keycodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process all the keypress sequences in fifo and send key codes
|
||||
*
|
||||
* The fifo contains zero or more keypress sets. Each set
|
||||
* consists of from 1-8 keycodes, representing the keycodes which
|
||||
* were simultaneously pressed during that scan.
|
||||
*
|
||||
* This function works through each set and generates ASCII characters
|
||||
* for each. Not that one set may produce more than one ASCII characters -
|
||||
* for example holding down 'd' and 'f' at the same time will generate
|
||||
* two ASCII characters.
|
||||
*
|
||||
* Note: if fifo_cnt is 0, we will tell the input layer that no keys are
|
||||
* pressed.
|
||||
*
|
||||
* @param config Keyboard config
|
||||
* @param fifo_cnt Number of entries in the keyboard fifo
|
||||
*/
|
||||
static void process_fifo(struct keyb *config, int fifo_cnt)
|
||||
{
|
||||
int fifo[KBC_MAX_KPENT];
|
||||
int cnt = 0;
|
||||
|
||||
/* Always call input_send_keycodes() at least once */
|
||||
do {
|
||||
if (fifo_cnt)
|
||||
cnt = tegra_kbc_find_keys(config, fifo, KBC_MAX_KPENT);
|
||||
|
||||
input_send_keycodes(&config->input, fifo, cnt);
|
||||
} while (--fifo_cnt > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the keyboard controller and emit ASCII characters for any keys that
|
||||
* are pressed.
|
||||
*
|
||||
* @param config Keyboard config
|
||||
*/
|
||||
static void check_for_keys(struct keyb *config)
|
||||
{
|
||||
int fifo_cnt;
|
||||
|
||||
if (!config->first_scan &&
|
||||
get_timer(config->last_poll_ms) < KBC_REPEAT_RATE_MS)
|
||||
return;
|
||||
config->last_poll_ms = get_timer(0);
|
||||
config->first_scan = 0;
|
||||
|
||||
/*
|
||||
* Once we get here we know the keyboard has been scanned. So if there
|
||||
* scan waiting for us, we know that nothing is held down.
|
||||
*/
|
||||
fifo_cnt = (readl(&config->kbc->interrupt) >> 4) & 0xf;
|
||||
process_fifo(config, fifo_cnt);
|
||||
}
|
||||
|
||||
/**
|
||||
* In order to detect keys pressed on boot, wait for the hardware to
|
||||
* complete scanning the keys. This includes time to transition from
|
||||
* Wkup mode to Continous polling mode and the repoll time. We can
|
||||
* deduct the time that's already elapsed.
|
||||
*
|
||||
* @param config Keyboard config
|
||||
*/
|
||||
static void kbd_wait_for_fifo_init(struct keyb *config)
|
||||
{
|
||||
if (!config->inited) {
|
||||
unsigned long elapsed_time;
|
||||
long delay_ms;
|
||||
|
||||
elapsed_time = get_timer(config->start_time_ms);
|
||||
delay_ms = config->init_dly_ms - elapsed_time;
|
||||
if (delay_ms > 0) {
|
||||
udelay(delay_ms * 1000);
|
||||
debug("%s: delay %ldms\n", __func__, delay_ms);
|
||||
}
|
||||
|
||||
config->inited = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the tegra keyboard, and send any keys that are pressed.
|
||||
*
|
||||
* This is called by input_tstc() and input_getc() when they need more
|
||||
* characters
|
||||
*
|
||||
* @param input Input configuration
|
||||
* @return 1, to indicate that we have something to look at
|
||||
*/
|
||||
int tegra_kbc_check(struct input_config *input)
|
||||
{
|
||||
kbd_wait_for_fifo_init(&config);
|
||||
check_for_keys(&config);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if keys are available to be read
|
||||
*
|
||||
* @return 0 if no keys available, 1 if keys are available
|
||||
*/
|
||||
static int kbd_tstc(void)
|
||||
{
|
||||
/* Just get input to do this for us */
|
||||
return input_tstc(&config.input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a key
|
||||
*
|
||||
* TODO: U-Boot wants 0 for no key, but Ctrl-@ is a valid key...
|
||||
*
|
||||
* @return ASCII key code, or 0 if no key, or -1 if error
|
||||
*/
|
||||
static int kbd_getc(void)
|
||||
{
|
||||
/* Just get input to do this for us */
|
||||
return input_getc(&config.input);
|
||||
}
|
||||
|
||||
/* configures keyboard GPIO registers to use the rows and columns */
|
||||
static void config_kbc_gpio(struct kbc_tegra *kbc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < KBC_MAX_GPIO; i++) {
|
||||
u32 row_cfg, col_cfg;
|
||||
u32 r_shift = 5 * (i % 6);
|
||||
u32 c_shift = 4 * (i % 8);
|
||||
u32 r_mask = 0x1f << r_shift;
|
||||
u32 c_mask = 0xf << c_shift;
|
||||
u32 r_offs = i / 6;
|
||||
u32 c_offs = i / 8;
|
||||
|
||||
row_cfg = readl(&kbc->row_cfg[r_offs]);
|
||||
col_cfg = readl(&kbc->col_cfg[c_offs]);
|
||||
|
||||
row_cfg &= ~r_mask;
|
||||
col_cfg &= ~c_mask;
|
||||
|
||||
if (i < config.matrix.num_rows) {
|
||||
row_cfg |= ((i << 1) | 1) << r_shift;
|
||||
} else {
|
||||
col_cfg |= (((i - config.matrix.num_rows) << 1) | 1)
|
||||
<< c_shift;
|
||||
}
|
||||
|
||||
writel(row_cfg, &kbc->row_cfg[r_offs]);
|
||||
writel(col_cfg, &kbc->col_cfg[c_offs]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start up the keyboard device
|
||||
*/
|
||||
static void tegra_kbc_open(void)
|
||||
{
|
||||
struct kbc_tegra *kbc = config.kbc;
|
||||
unsigned int scan_period;
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
* We will scan at twice the keyboard repeat rate, so that there is
|
||||
* always a scan ready when we check it in check_for_keys().
|
||||
*/
|
||||
scan_period = KBC_REPEAT_RATE_MS / 2;
|
||||
writel(scan_period * KBC_CLOCK_KHZ, &kbc->rpt_dly);
|
||||
writel(scan_period * KBC_CLOCK_KHZ, &kbc->init_dly);
|
||||
/*
|
||||
* Before reading from the keyboard we must wait for the init_dly
|
||||
* plus the rpt_delay, plus 2ms for the row scan time.
|
||||
*/
|
||||
config.init_dly_ms = scan_period * 2 + 2;
|
||||
|
||||
val = KBC_DEBOUNCE_COUNT << KBC_DEBOUNCE_CNT_SHIFT;
|
||||
val |= 1 << KBC_FIFO_TH_CNT_SHIFT; /* fifo interrupt threshold */
|
||||
val |= KBC_CONTROL_KBC_EN; /* enable */
|
||||
writel(val, &kbc->control);
|
||||
|
||||
config.start_time_ms = get_timer(0);
|
||||
config.last_poll_ms = config.next_repeat_ms = get_timer(0);
|
||||
config.first_scan = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the tegra 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 init_tegra_keyboard(void)
|
||||
{
|
||||
#ifdef CONFIG_OF_CONTROL
|
||||
int node;
|
||||
|
||||
node = fdtdec_next_compatible(gd->fdt_blob, 0,
|
||||
COMPAT_NVIDIA_TEGRA20_KBC);
|
||||
if (node < 0) {
|
||||
debug("%s: cannot locate keyboard node\n", __func__);
|
||||
return node;
|
||||
}
|
||||
config.kbc = (struct kbc_tegra *)fdtdec_get_addr(gd->fdt_blob,
|
||||
node, "reg");
|
||||
if ((fdt_addr_t)config.kbc == FDT_ADDR_T_NONE) {
|
||||
debug("%s: No keyboard register found\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Decode the keyboard matrix information (16 rows, 8 columns) */
|
||||
if (key_matrix_init(&config.matrix, 16, 8)) {
|
||||
debug("%s: Could not init key matrix\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
if (key_matrix_decode_fdt(&config.matrix, gd->fdt_blob, node)) {
|
||||
debug("%s: Could not decode key matrix from fdt\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
if (config.matrix.fn_keycode) {
|
||||
if (input_add_table(&config.input, KEY_FN, -1,
|
||||
config.matrix.fn_keycode,
|
||||
config.matrix.key_count))
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
#error "Tegra keyboard driver requires FDT definitions"
|
||||
#endif
|
||||
|
||||
/* Set up pin mux and enable the clock */
|
||||
funcmux_select(PERIPH_ID_KBC, FUNCMUX_DEFAULT);
|
||||
clock_enable(PERIPH_ID_KBC);
|
||||
config_kbc_gpio(config.kbc);
|
||||
|
||||
tegra_kbc_open();
|
||||
debug("%s: Tegra keyboard ready\n", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drv_keyboard_init(void)
|
||||
{
|
||||
struct stdio_dev dev;
|
||||
|
||||
if (input_init(&config.input, 0, KBC_REPEAT_DELAY_MS,
|
||||
KBC_REPEAT_RATE_MS)) {
|
||||
debug("%s: Cannot set up input\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
config.input.read_keys = tegra_kbc_check;
|
||||
|
||||
memset(&dev, '\0', sizeof(dev));
|
||||
strcpy(dev.name, "tegra-kbc");
|
||||
dev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
|
||||
dev.getc = kbd_getc;
|
||||
dev.tstc = kbd_tstc;
|
||||
dev.start = init_tegra_keyboard;
|
||||
|
||||
/* Register the device. init_tegra_keyboard() will be called soon */
|
||||
return input_stdio_register(&dev);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue