#include <stdlib.h>
#include <string.h>
#include <dos.h>
#include <malloc.h>
#define FAR far
#include <os386.h>
#include <errno.h>
#include "shared.h"
#include "funcdef.h"

extern struct real_data near shared;

static int far p_rpc();

int near taskid;

char rpc_name[] = "GLUE.EXE";

typedef unsigned long u_long;
typedef unsigned short u_short;
typedef unsigned char u_char;

void
main(argc, argv)
int argc;
char **argv;
{
	int ret;
	u_char far *psp = (u_char far *)((u_long)_psp << 16);
	struct {
		u_short len;
		char str[128];
	} comline;
	char far *env, far *myname;

	OS386_Use_Bound_Kernel(1);
	if (OS386_Init_Machine(M_COLD)) {
		dfputs("Init Machine failed\r\n");
		exit(1);
	}
	comline.len = psp[0x80];
	/* Copy return character too. */
	_fmemcpy(comline.str, &psp[0x81], comline.len + 1);
	/* find environ */
	env = (char far *)((u_long)*(u_short far *)&psp[0x2c] << 16);
	/* find my name */
	myname = env;
	do {
	    /* find a zero */
	    while (*myname++)
		;
	} while (*myname++);
	myname += 2;
	if (OS386_Create_Task(myname, (long)0, &comline, env, &taskid)) {
		dfputs("Create Task failed\r\n");
		exit(1);
	}
	OS386_Declare_RPC(rpc_name, 0, p_rpc);
	ret = OS386_Task_Control(taskid, T_GO);

	/* X is running at this point. */

	OS386_Delete_RPC(rpc_name);
	if (ret != R_EXIT) {
		dump_regs(taskid, ret);
	}
	ret = OS386_Get_Exit_Code();
	OS386_Exit_Loader();
	exit(ret);
}

static void (_interrupt _far *oldkbd)() = 0;
extern void _interrupt _far kbd_int();
extern void _interrupt _far err_handler();

static int far
p_rpc(buf, size)
short far *buf;
int size;
{
    switch (buf[0]) {
	case FUNC_INIT:
	    buf[0] = 0;		/* status */
	    buf[1] = 0;		/* pad */
	    buf[2] = (short)&shared;	/* offset */
	    buf[3] = (short)((long)(char far *)&shared >> 16);
	    return 8;
	case FUNC_SHUTDOWN:
	    mouse_shutdown();
	    kbd_shutdown();
	    break;
	case FUNC_KBD_INIT:
	    /* kbd_init -- set the keyboard interrupt routine
	     * and initialize the keyboard input buffer. */
	    shared.flags |= KBD_OPEN;
	    shared.kbd_start = 0;
	    shared.kbd_end = 0;

	    /* Get old keyboard vector. */
	    if (!oldkbd)
		oldkbd = _dos_getvect(0x09);
	    /* Set the new one. */
	    _dos_setvect(0x09, kbd_int);
	    break;
	case FUNC_KBD_SHUT:
	    kbd_shutdown();
	    break;
	case FUNC_KBD_COM:
	    kbd_command((char)buf[1]);
	    break;
	case FUNC_KBD_COUNTRY:
	    buf[0] = kbd_country();
	    return 2;
	case FUNC_MOUSE_INIT:
	    mouse_init(buf[1]);
	    break;
	case FUNC_MOUSE_SHUT:
	    mouse_shutdown();
	    break;
	case FUNC_VESA_INIT:
	    vesa_init(buf);
	    return 4;
	case FUNC_HARDERR:
	    _dos_setvect(0x24, err_handler);
	    break;
    }
    return 0;
}

void
_nullcheck()
{
}

void
kbd_shutdown()
{
    shared.flags &= ~KBD_OPEN;
    if (oldkbd) {
	_dos_setvect(0x09, oldkbd);
	oldkbd = 0;
    }
}

void
vesa_init(buf)
short _far *buf;
{
    union REGS regs;
    struct SREGS sregs;
    char vesa_buf[256];

    regs.x.ax = 0x4f01;
    regs.x.cx = buf[1];
    regs.x.di = (short)vesa_buf;
    sregs.es = (short)((long)(char _far *)vesa_buf >> 16);
    int86x(0x10, &regs, &regs, &sregs);
    if (regs.h.al != 0x4f) {
	buf[0] = 1;
	return;
    }
    if (regs.h.ah != 0) {
	buf[0] = 2;
	return;
    }
    buf[0] = 0;
    buf[1] = *(short *)&vesa_buf[4];
}

#ifdef notdef
static void _far
err_handler()
{
    _hardresume(_HARDERR_FAIL);
}
#endif
