/*
 * \brief  Keyboard manager
 * \author Markus Partheymueller
 * \date   2012-07-31
 */

/*
 * Copyright (C) 2012 Intel Corporation
 * Copyright (C) 2013 Genode Labs GmbH
 *
 * This file is distributed under the terms of the GNU General Public License
 * version 2.
 *
 * The code is partially based on the Vancouver VMM, which is distributed
 * under the terms of the GNU General Public License version 2.
 *
 * Modifications by Intel Corporation are contributed under the terms and
 * conditions of the GNU General Public License version 2.
 */

/* local includes */
#include "keyboard.h"

/* vancouver generic keyboard helper */
#include <host/keyboard.h>
#include <nul/vcpu.h>


Vancouver_keyboard::Vancouver_keyboard(Synced_motherboard &mb)
: _motherboard(mb), _flags(0) { }


void Vancouver_keyboard::handle_keycode_press(unsigned keycode)
{
	unsigned orig_keycode = keycode;

	switch (keycode) {

	/* modifiers */
	case Input::KEY_LEFTSHIFT:  _flags |= KBFLAG_LSHIFT; keycode = 0x12; break;
	case Input::KEY_RIGHTSHIFT: _flags |= KBFLAG_RSHIFT; keycode = 0x59; break;
	case Input::KEY_LEFTALT:    _flags |= KBFLAG_LALT;   keycode = 0x11; break;
	case Input::KEY_RIGHTALT:   _flags |= KBFLAG_RALT;   keycode = 0x11; break;
	case Input::KEY_LEFTCTRL:   _flags |= KBFLAG_LCTRL;  keycode = 0x14; break;
	case Input::KEY_RIGHTCTRL:  _flags |= KBFLAG_RCTRL;  keycode = 0x14; break;
	case Input::KEY_LEFTMETA:   _flags |= KBFLAG_LWIN;   keycode = 0x1f; return;
	case Input::KEY_RIGHTMETA:  _flags |= KBFLAG_RWIN;   keycode = 0x27; return;

	case Input::KEY_KPSLASH:    _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x35); break;
	case Input::KEY_KPENTER:    _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x1c); break;
	case Input::KEY_F11:        _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x57); break;
	case Input::KEY_F12:        _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x58); break;
	case Input::KEY_INSERT:     _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x52); break;
	case Input::KEY_DELETE:     _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x53); break;
	case Input::KEY_HOME:       _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x47); break;
	case Input::KEY_END:        _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x4f); break;
	case Input::KEY_PAGEUP:     _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x49); break;
	case Input::KEY_PAGEDOWN:   _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x51); break;
	case Input::KEY_LEFT:       _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x4b); break;
	case Input::KEY_RIGHT:      _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x4d); break;
	case Input::KEY_UP:         _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x48); break;
	case Input::KEY_DOWN:       _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x50); break;

	/* up to 0x53, the Genode key codes correspond to scan code set 1 */
	default:
		if (keycode <= 0x53) {
			keycode = GenericKeyboard::translate_sc1_to_sc2(keycode);
			break;
		} else return;
	}

	MessageInput msg(0x10000, _flags | keycode);

	/* debug */
	if ((_flags & KBFLAG_LWIN) && orig_keycode == Input::KEY_INSERT) {
		Logging::printf("DEBUG key\n");

		/* we send an empty event */
		CpuEvent msg(VCpu::EVENT_DEBUG);
		for (VCpu *vcpu = _motherboard()->last_vcpu; vcpu; vcpu=vcpu->get_last())
			vcpu->bus_event.send(msg);
	}

	/* reset */
	else if ((_flags & KBFLAG_LWIN) && orig_keycode == Input::KEY_END) {
		Logging::printf("Reset VM\n");
		MessageLegacy msg2(MessageLegacy::RESET, 0);
		_motherboard()->bus_legacy.send_fifo(msg2);
	}

	else _motherboard()->bus_input.send(msg);

	_flags &= ~(KBFLAG_EXTEND0 | KBFLAG_RELEASE | KBFLAG_EXTEND1);
}


void Vancouver_keyboard::handle_keycode_release(unsigned keycode)
{
	_flags |= KBFLAG_RELEASE;

	switch (keycode) {

	/* modifiers */
	case Input::KEY_LEFTSHIFT:  _flags |= KBFLAG_LSHIFT; keycode = 0x12; break;
	case Input::KEY_RIGHTSHIFT: _flags |= KBFLAG_RSHIFT; keycode = 0x59; break;
	case Input::KEY_LEFTALT:    _flags |= KBFLAG_LALT;   keycode = 0x11; break;
	case Input::KEY_RIGHTALT:   _flags |= KBFLAG_RALT;   keycode = 0x11; break;
	case Input::KEY_LEFTCTRL:   _flags |= KBFLAG_LCTRL;  keycode = 0x14; break;
	case Input::KEY_RIGHTCTRL:  _flags |= KBFLAG_RCTRL;  keycode = 0x14; break;
	case Input::KEY_LEFTMETA:   _flags |= KBFLAG_LWIN;   keycode = 0x1f; break;
	case Input::KEY_RIGHTMETA:  _flags |= KBFLAG_RWIN;   keycode = 0x27; break;

	case Input::KEY_KPSLASH:    _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x35); break;
	case Input::KEY_KPENTER:    _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x1c); break;
	case Input::KEY_F11:        _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x57); break;
	case Input::KEY_F12:        _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x58); break;
	case Input::KEY_INSERT:     _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x52); break;
	case Input::KEY_DELETE:     _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x53); break;
	case Input::KEY_HOME:       _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x47); break;
	case Input::KEY_END:        _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x4f); break;
	case Input::KEY_PAGEUP:     _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x49); break;
	case Input::KEY_PAGEDOWN:   _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x51); break;
	case Input::KEY_LEFT:       _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x4b); break;
	case Input::KEY_RIGHT:      _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x4d); break;
	case Input::KEY_UP:         _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x48); break;
	case Input::KEY_DOWN:       _flags |= KBFLAG_EXTEND0;
		keycode = GenericKeyboard::translate_sc1_to_sc2(0x50); break;

	/* up to 0x53, the Genode key codes correspond to scan code set 1 */
	default:
		if (keycode <= 0x53) {
			keycode = GenericKeyboard::translate_sc1_to_sc2(keycode);
			break;
		} else return;
	}

	MessageInput msg(0x10000, _flags | keycode);
	_motherboard()->bus_input.send(msg);

	_flags &= ~(KBFLAG_EXTEND0 | KBFLAG_RELEASE | KBFLAG_EXTEND1);
}
