/*
 * Copyright (c) 1992, 1993, 1996
 *	Berkeley Software Design, Inc.  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. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by Berkeley Software
 *	Design, Inc.
 *
 * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``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 Berkeley Software Design, Inc. 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.
 *
 *	BSDI int33.c,v 2.2 1996/04/08 19:32:54 bostic Exp
 */

#include "doscmd.h"
#include "mouse.h"

mouse_t mouse_status;
u_char *mouse_area = 0;
int nmice = 0;

void mouse_probe() { }

void
int33(struct sigcontext *sc)
{
    	u_long vec;
	u_short mask;
    	void *addr;
	int i;

	if (!nmice) {
		sc->sc_eflags |= PSL_C;	/* We don't support a mouse */
		return;
	}

printf("Mouse: %02x\n", GET16(sc->sc_eax));
	switch (GET16(sc->sc_eax)) {
	case 0x00:	/* Reset Mouse */
printf("Installing mouse driver\n");
		SET16(sc->sc_eax, 0xffff);	/* Mouse installed */
		SET16(sc->sc_ebx, 2);		/* Number of mouse buttons */
    	    	memset(&mouse_status, 0, sizeof(mouse_status));
		mouse_status.installed = 1;
		mouse_status.hardcursor = 1;
		mouse_status.end = 16;
		mouse_status.hmickey = 8;
		mouse_status.vmickey = 16;
		mouse_status.doubling = 100;
		mouse_status.init = -1;
		mouse_status.range.w = 8 * 80;
		mouse_status.range.h = 16 * 25;
		break;
	case 0x01:	/* Display Mouse Cursor */
		if ((mouse_status.init += 1) == 0) {
		    mouse_status.show = 1;
		}
		break;
	case 0x02:	/* Hide Mouse Cursor */
		if (mouse_status.init == 0)
		    mouse_status.show = 0;
		mouse_status.init -= 1;
		break;
	case 0x03:	/* Get cursor position/button status */
		mouse_probe();
		SET16(sc->sc_ecx, mouse_status.x);
		SET16(sc->sc_edx, mouse_status.y);
		SET16(sc->sc_ebx, mouse_status.buttons);
		break;
	case 0x04:	/* Move mouse cursor */
		/* mouse_move(GET16(sc->sc_ecx), GET16(sc->sc_edx)); */
		break;
	case 0x05:	/* Determine number of times mouse button was active */
		i = GET16(sc->sc_ebx) & 3;
		if (i == 3)
		    i = 1;

		SET16(sc->sc_ebx, mouse_status.downs[i]);
		mouse_status.downs[i] = 0;
		SET16(sc->sc_eax, mouse_status.buttons);
		SET16(sc->sc_ecx, mouse_status.x);	/* Not quite right */
		SET16(sc->sc_edx, mouse_status.y);	/* Not quite right */
		break;
	case 0x06:	/* Determine number of times mouse button was relsd */
		i = GET16(sc->sc_ebx) & 3;
		if (i == 3)
		    i = 1;

		SET16(sc->sc_ebx, mouse_status.ups[i]);
		mouse_status.ups[i] = 0;
		SET16(sc->sc_eax, mouse_status.buttons);
		SET16(sc->sc_ecx, mouse_status.x);	/* Not quite right */
		SET16(sc->sc_edx, mouse_status.y);	/* Not quite right */
		break;
	case 0x07:	/* Set min/max horizontal cursor position */
		mouse_status.range.x = GET16(sc->sc_ecx);
		mouse_status.range.w = GET16(sc->sc_edx) - GET16(sc->sc_ecx);
		break;
	case 0x08:	/* Set min/max vertical cursor position */
		mouse_status.range.y = GET16(sc->sc_ecx);
		mouse_status.range.h = GET16(sc->sc_edx) - GET16(sc->sc_ecx);
	case 0x09:	/* Set graphics cursor block */
		/* BX,CX is hot spot, ES:DX is data. */
		break;
	case 0x0a:	/* Set Text Cursor */
		mouse_status.hardcursor = GET16(sc->sc_ebx) ? 1 : 0;
		mouse_status.start = GET16(sc->sc_ecx);
		mouse_status.end = GET16(sc->sc_ecx);
		break;
	case 0x0b:	/* Read Mouse Motion Counters */
		mouse_probe();
		SET16(sc->sc_ecx, mouse_status.x - mouse_status.lastx);
		SET16(sc->sc_edx, mouse_status.y - mouse_status.lasty);
		mouse_status.lastx - mouse_status.x;
		mouse_status.lasty - mouse_status.y;
		break;
	case 0x0c:	/* Set event handler */
		mouse_status.mask = GET16(sc->sc_ecx);
		mouse_status.handler = GETVEC(sc->sc_es, sc->sc_edx);
		break;
	case 0x0d:	/* Enable light pen */
	case 0x0e:	/* Disable light pen */
		break;
	case 0x0f:	/* Set cursor speed */
		mouse_status.hmickey = GET16(sc->sc_ecx);
		mouse_status.vmickey = GET16(sc->sc_edx);
		break;
	case 0x10:	/* Exclusive area */
		mouse_status.exclude.x = GET16(sc->sc_ecx);
		mouse_status.exclude.y = GET16(sc->sc_edx);
		mouse_status.exclude.w = GET16(sc->sc_esi) - GET16(sc->sc_ecx);
		mouse_status.exclude.h = GET16(sc->sc_edi) - GET16(sc->sc_edx);
		break;
	case 0x13:	/* Set maximum for mouse speed doubling */
		break;
	case 0x14:	/* Exchange event handlers */
		mask = mouse_status.mask;
		vec = mouse_status.handler;

		mouse_status.mask = GET16(sc->sc_ecx);
		mouse_status.handler = GETVEC(sc->sc_es, sc->sc_edx);
    	    	SET16(sc->sc_ecx, mask);
		PUTVEC(sc->sc_es, sc->sc_edx, vec);
		break;
    	case 0x15:	/* Determine mouse status buffer size */
		SET16(sc->sc_ebx, sizeof(mouse_status));
		break;
	case 0x16:	/* Store mouse buffer */
		memcpy((char *)GETPTR(sc->sc_es, sc->sc_edx), &mouse_status,
		       sizeof(mouse_status));
		break;
	case 0x17:	/* Restore mouse buffer */
		memcpy(&mouse_status, (char *)GETPTR(sc->sc_es, sc->sc_edx),
		       sizeof(mouse_status));
		break;
	case 0x18:	/* Install alternate handler */
		mask = GET16(sc->sc_ecx) & 0xff;
		if ((GET16(sc->sc_ecx) & 0xe0) == 0x00 ||
		    mask == mouse_status.altmask[0] ||
		    mask == mouse_status.altmask[1] ||
		    mask == mouse_status.altmask[2] ||
		    (mouse_status.altmask[i = 0] &&
		     mouse_status.altmask[i = 1] &&
		     mouse_status.altmask[i = 2])) {
			SET16(sc->sc_eax, 0xffff);
			break;
		}
    	    	mouse_status.altmask[i] = GET16(sc->sc_ecx);
    	    	mouse_status.althandler[i] = GETVEC(sc->sc_es, sc->sc_edx);
		break;
	case 0x19:	/* Determine address of alternate event handler */
		mask = GET16(sc->sc_ecx) & 0xff;
    	    	if (mask == mouse_status.altmask[0])
			vec = mouse_status.althandler[0];
    	    	else if (mask == mouse_status.altmask[1])
			vec = mouse_status.althandler[1];
    	    	else if (mask == mouse_status.altmask[2])
			vec = mouse_status.althandler[2];
		else
			SET16(sc->sc_ecx, 0);
		PUTVEC(sc->sc_es, sc->sc_edx, vec);
		break;
	case 0x1a:	/* set mouse sensitivity */
		mouse_status.hmickey = GET16(sc->sc_ebx);
		mouse_status.vmickey = GET16(sc->sc_ecx);
		mouse_status.doubling = GET16(sc->sc_edx);
		break;
	case 0x1b:	/* set mouse sensitivity */
		SET16(sc->sc_ebx, mouse_status.hmickey);
		SET16(sc->sc_ecx, mouse_status.vmickey);
		SET16(sc->sc_edx, mouse_status.doubling);
		break;
    	case 0x1c:	/* set mouse hardware rate */
		break;
	case 0x1d:	/* set display page */
		break;
	case 0x1e:	/* get display page */
		SET16(sc->sc_ebx, 0);	/* Always on display page 0 */
		break;
	case 0x1f:	/* Disable mouse driver */
		if (mouse_status.installed) {
			PUTVEC(sc->sc_es, sc->sc_edx, mouse_status.handler);
			mouse_status.installed = 0;
    	    	} else {
		    	SET16(sc->sc_eax, 0xffff);
		}
		break;
	case 0x20:	/* Enable mouse driver */
		mouse_status.installed = 1;
		break;
	case 0x21:	/* Reset mouse driver */
		if (mouse_status.installed) {
			mouse_status.show = 0;
			mouse_status.handler = 0;
			mouse_status.mask = 0;
			mouse_status.cursor = 0;
		} else
		    	SET16(sc->sc_eax, 0xffff);
		break;
	case 0x22:	/* Specified language for mouse messages */
		break;
	case 0x23:	/* Get language number */
		SET16(sc->sc_ebx, 0);	/* Always return english */
		break;
	case 0x24:	/* Get mouse type */
		SET16(sc->sc_ecx, 0x0400);		/* PS/2 style mouse */
		SET16(sc->sc_ebx, 0x0600 + 24);	/* Version 6.24 */
		break;
	default:
		sc->sc_eflags |= PSL_C;
		break;
	}
}

void
mouse_init(void)
{
	u_long vec;

	vec = insert_softint_trampoline();
	ivec[0x33] = vec;
	register_callback(vec, int33, "int 33");

	mouse_area[1] = 24;
}
