diff options
| author | Stefan Roese <sr@denx.de> | 2007-12-11 11:34:54 +0100 | 
|---|---|---|
| committer | Stefan Roese <sr@denx.de> | 2007-12-11 11:34:54 +0100 | 
| commit | 9caeaadf508cd0e11ac5dfc56ab0f72e3b89a105 (patch) | |
| tree | 1afcc9c20c04e19870ab5e2996104877695c54a3 /drivers/input/ps2mult.c | |
| parent | 7cfc12a7dcfdb350e2ab76db4dafcc30f7e77c2b (diff) | |
| parent | 41be969f4957115ed7b1fe8b890bfaee99d7a7a2 (diff) | |
| download | olio-uboot-2014.01-9caeaadf508cd0e11ac5dfc56ab0f72e3b89a105.tar.xz olio-uboot-2014.01-9caeaadf508cd0e11ac5dfc56ab0f72e3b89a105.zip | |
Merge commit 'u-boot/master' into for-1.3.1
Conflicts:
	drivers/rtc/Makefile
Diffstat (limited to 'drivers/input/ps2mult.c')
| -rw-r--r-- | drivers/input/ps2mult.c | 466 | 
1 files changed, 466 insertions, 0 deletions
| diff --git a/drivers/input/ps2mult.c b/drivers/input/ps2mult.c new file mode 100644 index 000000000..9515a0fbf --- /dev/null +++ b/drivers/input/ps2mult.c @@ -0,0 +1,466 @@ +/*********************************************************************** + * + * (C) Copyright 2004 + * DENX Software Engineering + * Wolfgang Denk, wd@denx.de + * All rights reserved. + * + * 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> + +#ifdef CONFIG_PS2MULT + +#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; +} + +#endif /* CONFIG_PS2MULT */ |