/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1986
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:wterm.c 12.0$ */
/* $ACIS:wterm.c 12.0$ */
/* $Source: /ibm/acis/usr/sys/standca/RCS/wterm.c,v $ */

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

#include "sari.h"
#include "com.h"
#include <ctype.h>
#include "init.h"
#include "sa.h"


#define ESC 033
#define ALT 0x80		       /* alt key pressed */
#define ESC_FLAG 0x100		       /* send esc + character */

#define POST_START	0x800	       /* location of POST */
#define POST_END	0x1000	       /* end of POST */

#define COM_BASE	0x00		/* define IO base for com ports */
#ifdef	ATR
#define PC_INT_MASKREG	0x21		/* PC interrupt mask register port */
#endif	ATR

int debug;
int baud_rate = 9600;
#define NOT_PRESENT 0xff	       /* value returned if no hardware there */
struct asydevice *com_addr = (struct asydevice *)(COM_BASE + COM1);
 /* default device */

struct asydevice *com_addrs[] = {
	(struct asydevice *)(COM_BASE + PC_COM1),
	(struct asydevice *)(COM_BASE + PC_COM2),
	(struct asydevice *)(COM_BASE + QUAD_COM1),
	(struct asydevice *)(COM_BASE + QUAD_COM2),
	(struct asydevice *)(COM_BASE + QUAD_COM3),
	(struct asydevice *)(COM_BASE + QUAD_COM4),
	0, 0, 0, 0
};				       /* leave some room for extras */

main(argc, argv)
	char **argv;
{
	register int c;
	register int i;
	struct asydevice *old_com = com_addr;
/*
 * basic terminal emulator - first test to see if we have a character
 * from the host, then check to see if we have one from the keyboard.
 */


#ifdef ATR
	OUT(PC_INT_MASKREG, (IN(PC_INT_MASKREG) | 0x02)); /* mask PC keyboard */
#endif ATR

	if (argc > 1)
		baud_rate = atoi(argv[1]);
	if (argc > 2)
		com_addr = (struct asydevice *)(COM_BASE + (atox(argv[2]) & 0xffff));
	printf("term: %s\n", rcsid);
	if (!init_host(baud_rate)) {
		if (argc >= 3)
			return;	       /* don't try any more */
		for (i = 0; com_addr = com_addrs[i]; ++i)
			if (com_addr != old_com)
				if (init_host(baud_rate))
					break;
		if (com_addr == 0) {
			com_addr = old_com;
			return;	       /* no point in continuing */
		}
	}
	printf("baud rate=%d; serial adapter=%x\n", baud_rate, com_addr);
	for (;;) {
		if ((c = _get_host()) >= 0) {
			if (c == ESC)
				download(c);
			else
				_putchar(c);
		}
		if ((c = get_keyboard()) >= 0) {
			switch (c) {
			case ALT + 'a':
				return;
			case ALT + 'b':
				send_break();
				break;
			case ALT + 'd':
				debugger();
				break;
			default:
				if (c & ESC_FLAG) {
					send_host(ESC);
					c &= ~ESC_FLAG;
				} else if (c & ALT)
					send_host(ESC);
				send_host(c);
				break;
			}
		}
	}
}


char prefix[] = {
	ESC, '[', '5', 'i', 0
};

download(c)
	register int c;
{
	register int i = 0;
	register int j;
	register char *start;
	char buff[100];
	register int nonzero = 0;

	for (j = 0;;) {
		buff[i] = c;
		if (debug)
			printf(" %d=%x ", i, c);
		++i;
		if (c != prefix[i - 1])
			break;
		if (debug)
			printf(" got %x", c);
		DISPLAY(i);
		if (prefix[i] == 0) {
			++j;
			break;
		}
		c = get_host();	       /* get next character */
	}
	if (j == 0) {
		for (j = 0; j < i; ++j)
			putchar(buff[j]);
		return;
	}
	for (i = 0; i < sizeof buff; ++i) {
		c = get_host();
		if (c <= ' ')
			break;
		buff[i] = c;
	}
	buff[i] = 0;
	printf("load");
	if (isxdigit(buff[0]))
		start = (char *)atox(buff);
	else {
		printf(" %s", buff);
		start = (char *)0x10000;
	}
	printf(" at %x ", start);
	put_status(30, "loading    ");
	for (i = 0;;) {
		c = get_host_byte();
		if (c < 0)
			break;
#ifdef ibm032
		if ((int)start >= POST_START && (int)start < POST_END &&
		    (c == 0 || ++nonzero == 0))
			++start;       /* ignore zero bytes */
		else
#endif ibm032
		*start++ = c;
		if ((++i & 0777) == 0)
			sprintf(buff, "%d", i >> 9), put_status(38, buff);
	}
	if (nonzero)
		printf(" [%d non-zero POST bytes]", nonzero);
	printf(" ; loaded %d bytes\n", i);
	put_status(30, "           ");
	DISPLAY(0);
}


get_host_byte()
{
	register int c;

	c = get_host();
	if (c == '\\') {
		c = (get_host() - '0') & 0x0f;
		c = (c << 4) + ((get_host() - '0') & 0x0f);
	} else if (c == ESC)
		c = -1;
	return (c);
}


/*
 * get a character from the host - wait til one arrives.
 * if anything happens on the keyboard then send that character to
 * the host.
 */
get_host()
{
	register int c;

	while ((c = _get_host()) <= 0) {
		if ((c = get_keyboard()) >= 0)
			send_host(c);
	}
	return (c & 0177);
}


/*
 * get a character from the host via a COM1 communication card
 * return -1 if no character available.
 */
_get_host()
{
	register int c;
	register struct asydevice *com = com_addr;

	if (( IN(&com->LSR) & 01) == 0)
		return (-1);
	c = IN(&com->RXB) & 0177;
	return (c);
}


#define CHAR_NORM CHAR_8 + STOP_1 + PARITY_DISABLE

short baud_rates[] = {
	300, 600, 1200, 2400, 4800, 9600, 19200, 0
};

short rates[] = {
	COM_300, COM_600, COM_1200, COM_2400, COM_4800, COM_9600, COM_19200
};

LOCAL init_host(rate)
{
	register int x, n;
	static int baud = COM_9600;
	register struct asydevice *com = com_addr;

	if (IN(&com->LCR) == NOT_PRESENT && IN(&com->RXB) == NOT_PRESENT) {
		printf("no COM card at address %x \n", com);
		return (0);
	}
	for (x = 0; n = baud_rates[x]; ++x)
		if (rate == n) {
			baud = rates[x];
			break;
		}
	if (n == 0)
		printf("warning: unknown baud rate %d\n", rate);
	OUT(&com->LCR, COM_DLAB);	/* enable for output to set baud rate */
	OUT(&com->LSB, (char)baud );	/* set baud rate low */
	OUT(&com->MSB, (char)(baud >> 8));	/* set msb */
	OUT(&com->LCR, CHAR_NORM);	/* 7 bits etc. */
	OUT(&com->IER, 0x00);		/* disable interrupts */
	x = IN(&com->RXB);
	return (1);
}


send_host(c)
	register int c;
{
	register struct asydevice *com = com_addr;

	while ((IN(&com->LSR) & 040) == 0);	/* wait for ready */
	OUT(&com->TXB, (char)c );		/* output the character */
}


short break_delay = 250;	       /* amount of time to delay */
send_break()
{
	register struct asydevice *com = com_addr;

	OUT(&com->LCR, CHAR_NORM + SET_BREAK); /* turn on break */
	delay(break_delay);
	OUT(&com->LCR, CHAR_NORM);	       /* turn off break */
}


asyint()
{
	printf("asyint called\n");
}
