/*
 * Copyright (c) 2007, 2008 University of Tsukuba
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of the University of Tsukuba nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
/*
 * Copyright (c) 2012-2013 Yuichi Watanabe
 */

#include <core/printf.h>
#include <core/initfunc.h>
#include "current.h"
#include "io_io.h"
#include "panic.h"
#include "vm.h"

/* #define IOHOOK_DEBUG */
#ifdef IOHOOK_DEBUG
#define IOHOOK_DBG(...)						\
	do {							\
		printf("IOHOOK: " __VA_ARGS__);			\
	} while (0)
#else
#define IOHOOK_DBG(...)
#endif

#ifdef DEBUG_IO_MONITOR
static int
kbdio_monitor (iotype_t type, ioport_t port, void *data)
{
	if (type == IOTYPE_INB)
		printf ("IO Monitor test: INB PORT=0x60 DATA=0x%X\n", *(u8 *)data);
	return 0; /* pass */
}
#endif

#ifdef DEBUG_IO0x20_MONITOR
#include "vramwrite.h"
static void
io0x20_monitor (iotype_t type, ioport_t port, void *data)
{
	do_io_pass (type, port, data);
	if (type == IOTYPE_OUTB) {
		vramwrite_save_and_move_cursor (56, 23);
		printf ("OUT0x20,0x%02X", *(u8 *)data);
		vramwrite_restore_cursor ();
	}
	return /* no pass */
}
#endif

#if defined (F11PANIC) || defined (F12MSG)
#include "keyboard.h"
static int
kbdio_dbg_monitor (iotype_t type, ioport_t port, void *data)
{
	static int led = 0;
	static u8 lk = 0;

	if (type == IOTYPE_INB) {
		switch (*(u8 *)data) {
		case 0x57 | 0x80: /* F11 */
			if (lk == 0x57) {
#ifdef F11PANIC
				if (config.vmm.f11panic)
					panic ("F11 pressed.");
#endif
			}
			break;
		case 0x58 | 0x80: /* F12 */
			if (lk == 0x58) {
#if defined(F12MSG)
				if (config.vmm.f12msg) {
					led ^= LED_CAPSLOCK_BIT |
						LED_NUMLOCK_BIT;
					setkbdled (led);
					printf ("F12 pressed.\n");
				}
#endif /* defined(F12MSG) */
			}
			break;
		}
		lk = *(u8 *)data;
	}
	return 0; /* pass */
}
#endif

static int
kbdcmd_monitor(iotype_t type, ioport_t port, void *data)
{
	u8 data_u8;

	IOHOOK_DBG("type %u port 0x%x\n", type, port);
	if (type == IOTYPE_OUTB) {
		data_u8 = *(u8 *)data;

		if (data_u8 == 0xfe) { /* reset machine */
			if (vm_reset() == VMMERR_SUCCESS) {
				return 1; /* emulated */
			}
			if (vm_get_id() != 0) {
				printf("Ignored a request to reboot by %s\n",
				       vm_get_name());
			}
		}
	}

	if (vm_get_id() == 0) {
		return 0; /* pass */
	} else {
		return 1; /* emulated */
	}
}

static void
setiohooks (void)
{
#ifdef DEBUG_IO_MONITOR
	set_iofunc (0x60, kbdio_monitor);
#endif
#ifdef DEBUG_IO0x20_MONITOR
	set_iofunc (0x20, io0x20_monitor);
#endif
#if defined (F11PANIC) || defined (F12MSG)
	if (config.vmm.f11panic || config.vmm.f12msg)
		set_iofunc (0x60, kbdio_dbg_monitor);
#endif

	set_iofunc(0x64, kbdcmd_monitor);
}

INITFUNC ("setupvm1", setiohooks);
