/* Console device driver for the uVAX. */

#include <types.h>
#include <sys.h>
#include <sysext.h>
#include <itp.h>

/* Console use of device flags. */
#define D_XOFF D_DV1		/* In XOFF state */

iorb *con_iiob;

/* Initialize console. */
con_rup(devp)
reg dct *devp;
{
    con_rinten();
    devp->d_flg = D_INI;
}

con_tup(devp)
reg dct *devp;
{
    con_tintdis();
    devp->d_flg = D_INI;
    devp->d_rc = 0;
    con_iiob = (iorb *)mem_alloc(sizeof(iorb) + 128);
    con_iiob->i_addr = (byte *)(con_iiob + 1);
    con_iiob->i_breq = 128;
    con_iiob->i_bxfr = 0;
    con_iiob->i_devp = devp;
}

/* Output transfer initialization routine */
con_out(devp)
dct *devp;
{
    con_tinten();
}

/* Receive interrupt handler */
con_rint(devp)
dct *devp;
{
    reg int c;
    void con_input();

    c = con_recv();
    if ((c&~0x80) == 26)	/* ^Z */
      asm("bispsw $0x10");	/*   cause trace trap */
    else if ((c&~0x80) == 19) {	/* ^S (XOFF) */
	devp->d_lnk->d_flg |= D_XOFF;
    }
    else if ((c&~0x80) == 17) {	/* ^Q (XON) */
	devp = devp->d_lnk;
	devp->d_flg &= ~D_XOFF;
	if (devp->d_qhd)
	  con_out(devp);
    }
    else {
	if ((devp->d_lnk->d_flg & D_XOFF) != 0) {
	    devp = devp->d_lnk;
	    devp->d_flg &= ~D_XOFF;
	    if (devp->d_qhd)
	      con_out(devp);
	}
	addtsk(syshnd, 200, con_input, c);
    }
}

static byte newline[] = {'\r' ,'\n' };
static byte clear[] = {'\033', 'H', '\033', 'J' };

/* Transmit interrupt handler */
con_tint(devp)
reg dct *devp;
{
    if (devp->d_rc) {
	con_send(*devp->d_rfnt++);
	devp->d_rc--;
	return;
    }

    if (devp->d_breq) {
	if ((devp->d_flg & D_XOFF) != 0) {
	    con_tintdis();
	    return;
	}
	switch ((char)(*devp->d_addr)) {
	case '\n':
	    devp->d_rfnt = newline;
	    devp->d_rc = sizeof(newline);
	    break;
	case TDCLR:
	    devp->d_rfnt = clear;
	    devp->d_rc = sizeof(clear);
	    break;
	default:
	    con_send(*devp->d_addr++);
	    devp->d_breq--;
	    return;
	}
	con_send(*devp->d_rfnt++);
	devp->d_rc--;
	devp->d_addr++;
	devp->d_breq--;
    }
    else {
	con_tintdis();
	iocmr(devp);
    }
}

con_input(c)
char c;
{
    opcon_input(con_iiob->i_devp, con_iiob, c);
}
