/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1987,1988
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */

/* $Header:mouse.c 12.0$ */
/* $ACIS:mouse.c 12.0$ */
/* $Source: /ibm/acis/usr/sys/pc_code/RCS/mouse.c,v $ */

#ifndef lint
static char *rcsid = "$Header:mouse.c 12.0$";
#endif



#define MSFUNCTION   0xc2;
#define BIOS_SYSSERV 0x15

#define MSCMD_SWITCH  0x00
#define MSOPT_ENABLE  0x01
#define MSOPT_DISABLE 0x00

#define MSCMD_RESET   0x01

#define MSCMD_SETRATE 0x02
#define MSOPT_10RPS   0x00
#define MSOPT_20RPS   0x01
#define MSOPT_40RPS   0x02
#define MSOPT_60RPS   0x03
#define MSOPT_80RPS   0x04
#define MSOPT_100RPS  0x05
#define MSOPT_200RPS  0x06

#define MSCMD_SETRES  0x03
#define MSOPT_1CMP    0x00
#define MSOPT_2CMP    0x01
#define MSOPT_4CMP    0x02
#define MSOPT_8CMP    0x03

#define MSCMD_GETDEV  0x04

#define MSCMD_SETDPS  0x05
#define MSOPT_1BDPS   0x01
#define MSOPT_2BDPS   0x02
#define MSOPT_3BDPS   0x03
#define MSOPT_4BDPS   0x04
#define MSOPT_5BDPS   0x05
#define MSOPT_6BDPS   0x06
#define MSOPT_7BDPS   0x07
#define MSOPT_8BDPS   0x08

#define MSCMD_EXTEND  0x06
#define MSOPT_STATUS  0x00
#define MSOPT_1TO1    0x01
#define MSOPT_2TO1    0x02

#define MSCMD_FARCALL 0x07



#include <sys\types.h>
#include <dos.h>
#include "pcparam.h"
#include "rb.h"
#include "bios.h"
#include "vars.h"

extern void far msint();
u_short         msstatus, msx, msy;

struct msdata   msdata = {0};
struct msqueue  msqueue = {0};


/*****************************************************************
 * mouseint - Interrupt Routine for the Mouse Driver.
 *
 *    This routine can be call from 2 places:
 *
 *        msint() in the file as.asm. This is the FLIH for
 *        the mouse driver. When we are called from this
 *        routine there is data available from the mouse.
 *        The data has been placed into the global variables
 *        msstatus, msx, and msy. We simply copy the data
 *        into the report[] array of the msdata structure
 *        then interrupt Unix via rompint3(3,).
 *
 *        mscmd() in this file. This is the interface used
 *        by the Unix mouse driver to send commands to the
 *        PS/2 code. Commands are acknowledged to Unix by
 *        setting the msdata.type field to 1.
 *
 *   Paramaters:
 *       cmdresp - Indicates where called from:
 *                       0 - Called from interrupt level
 *                       1 - Called from mscmd()
 *
 *       rtncode - Only valid when cmdresp == 1
 *                 Contains BIOS return code for operation.
 *
 */

mouseint(cmdresp, rtncode)
	u_short         cmdresp;
	u_short         rtncode;
{
	struct msdata   msbuff;
	register struct msdata *ms = &msbuff;
	register char  *msreport = (char *) ms->report;
	struct msqueue *msqp = &msqueue;
	int             i = 0;



	if (cmdresp)
	{
		ms->type = 1;
		ms->exit_stat = (rtncode >> 15);
		ms->error = LOBYTE(rtncode);
	} else
		ms->type = 0;

	*msreport++ = LOBYTE(msstatus);
	*msreport++ = LOBYTE(msx);
	*msreport = LOBYTE(msy);
	ms->status = 1;

	if (msdata.status)
	{
		msdqueue(ms);
		return;
	}
	if (msqp->head != msqp->tail)
	{
		msdqueue(ms);
		i = msqp->head;
		ms = &msqp->buff[i];
		i = (i + 1) % MAXMSBUFF;
		msqp->head = i;
	}
	msforward(ms);
}

msforward(mssrcp)
	struct msdata  *mssrcp;
{
	register struct msdata *msdestp = &msdata;

	memcpy((char *) msdestp, (char *) mssrcp, sizeof(struct msdata));
	rompint3(3,FAKEPOLL(MSIRQ), 0, 0, screen_cbcb);

}


msdqueue(mssrcp)
	struct msdata  *mssrcp;
{
	register struct msdata *msdestp;
	register struct msqueue *msq = &msqueue;
	register int    i;

	i = msq->tail;
	msdestp = &msq->buff[i];;
	memcpy((char *) msdestp, (char *) mssrcp, sizeof(struct msdata));
	i = (i + 1) % MAXMSBUFF;
	if (i != msq->head)
		msq->tail = i;

}



int msinit()
{
	int             rval;

#ifdef DEBUG
	int             ldebug = (*dbugptr & MSDEBUG);
#endif

	rval = mousecmd(MSCMD_SETDPS, MSOPT_3BDPS);
	if (rval < 0)
	{
		DEBUGF(ldebug, printf("MOUSE RESET FAILED, Error Code = %#x\n",
				      rval));
		return (-1);
	}
	DEBUGF(ldebug, printf("MOUSE RESET PASSED\n"));


	rval = mousecmd(MSCMD_FARCALL, 0);
	if (rval < 0)
	{
		DEBUGF(ldebug, printf("FAR CALL NOT INSTALLED, Error Code = %#x\n",
				      rval));
		return (-1);
	}
	DEBUGF(ldebug, printf("MOUSE FAR CALL INSTALLED\n"));

#ifdef DEBUG
	if (ldebug)
	{
		rval = mousecmd(MSCMD_SWITCH, MSOPT_ENABLE);
		if (rval < 0)
		{
			DEBUGF(ldebug, printf("CAN'T ENABLE THE MOUSE, Error Code = %#x\n",
					      rval));
			return (-1);
		}
	}
	DEBUGF(ldebug, printf("MOUSE ENABLED\n"));
#endif /* DEBUG */

	return (0);
}


int mscmd(pcplqe)
	pcplqaddr_t     pcplqe;
{
	struct pcms_cmd mscmd;
	register struct pcms_cmd *mspl = &mscmd;
	u_long          unixaddr;
	char far       *pcaddr;
	int             rc;

#ifdef DEBUG
	int             ldebug = (*dbugptr & MSDEBUG);
#endif /* DEBUG */

	/*
	 * First read the pcms_cmd structure down from Unix 
	 */


	/*
	 * Zero out our local copy of the structure 
	 */
	memset((char *) mspl, 0, sizeof(struct pcms_cmd));

	pcaddr = (char far *) mspl;
	unixaddr = (u_long) pcplqe->unix_cb;

	DEBUGF(ldebug, printf("mscmd: pcplqe = %#lx\n", (u_long) pcplqe));
	DEBUGF(ldebug, printf("mscmd: Copy the pcms_cmd from Unix"));

	rc = movein(unixaddr, pcaddr, sizeof(struct pcms_cmd));

	if (rc < 0)
	{
		printf("pc_code: Can't read pcms_cmd structure from Unix\n");
		return (rc);
	}
	rc = mousecmd(mspl->cmd, mspl->param);

#ifdef DEBUG
	if (rc < 0)
		DEBUGF(ldebug, printf("mscmd: Command Failed!, BIOS ERROR CODE = %#x\n", rc & 0xff));
#endif /* DEBUG */

	mouseint(1, rc);

}



static int
mousecmd(cmd, opt)
	u_short         cmd;
	u_short         opt;
{
	struct SREGS    segregs;
	union REGS      inregs, outregs;
	register union REGS *iregs = &inregs;
	register union REGS *oregs = &outregs;
	char far       *pf = (char far *) msint;
	int             rval = -1;
	int             valid_cmd = 0;

#ifdef DEBUG
	int             ldebug = (*dbugptr & MSDEBUG);
#endif

	DEBUGF(ldebug, printf("mousecmd: cmd = %#x, opt = %#x\n", cmd, opt));

	switch (cmd)
	{
	case MSCMD_SWITCH:
	case MSCMD_RESET:
	case MSCMD_SETRATE:
	case MSCMD_SETRES:
	case MSCMD_GETDEV:
	case MSCMD_SETDPS:
	case MSCMD_EXTEND:
		valid_cmd = 1;
		iregs->h.bh = LOBYTE(opt);
		break;

	case MSCMD_FARCALL:
		valid_cmd = 1;
		iregs->x.bx = FP_OFF(pf);
		segregs.es = FP_SEG(pf);
		break;

	default:
		break;
	}

	if (valid_cmd)
	{
		iregs->h.ah = MSFUNCTION;
		iregs->h.al = LOBYTE(cmd);
		int86x(BIOS_SYSSERV, iregs, oregs, &segregs);
		if (oregs->x.cflag)
		{
			if (oregs->h.ah == 0x04)
				oregs->h.ah -= 1;
			rval = (0x8000 | oregs->h.ah);
		} else
		{
			rval = 0;
			switch (cmd)
			{
			case MSCMD_RESET:
				msstatus = oregs->h.bl;	/* Completion Code */
				msx = oregs->h.bh;	/* Device ID       */
				DEBUGF(ldebug, printf("mousecmd: RESET code = %#x id = %#x\n",
						      msstatus, msx));
				break;


			case MSCMD_GETDEV:
				msstatus = oregs->h.bh;	/* Device ID */
				DEBUGF(ldebug, printf("mousecmd: GETDEV id = %#x\n", msstatus));
				break;

			case MSCMD_EXTEND:
				if (opt == MSOPT_STATUS)
				{
					msstatus = oregs->h.bl;	/* Status Byte 1       */
					msx = oregs->h.cl;	/* Current Resolution  */
					msy = oregs->h.dl;	/* Current Sample Rate */
#ifdef DEBUG
					if (ldebug)
						printf("mousecmd: stat = %#x, res = %#x, srate = %#x\n",
						       msstatus, msx, msy);
#endif /* DEBUG */
				}	/* End if(opt == .... */
				break;
			}	/* End switch(cmd) */
		}		/* End else */
	}			/* End if(vaild_cmd) */
	return (rval);
}
