
/*
 * tty3200.c: version 3.3 of 6/4/85
 *
 *  tty3200.c -- VIOS terminal handler for 3210 Rev-A
 *  copyright (c) American Information Systems Corporation
 *	Daniel Steinberg	November, 1984
 */
#ifdef SCCS
static char *sccsid = "@(#)tty3200.c	3.3";
#endif

#include "vinc/viosconf.h"
#include "vinc/abusflags.h"
#include "vinc/viostatus.h"
#include "vinc/devices.h"
#include "vinc/ascii.h"


#ifdef DEBUG3
#undef DEBUG3
#endif


/* define structures that point to CSRS */

static uart_controller *csrs[UARTS] =	/* uart CSRS */

#ifdef REV_2A /****************** CPU REVISION-2A **********************/
		{
		(uart_controller*) UART0,
		(uart_controller*) UART1,
		(uart_controller*) UART2,
		(uart_controller*) UART3
		};

static duart_controller *duarts[UARTS] =	/* duart CSRS */
		{
		(duart_controller*) UARTA,
		(duart_controller*) UARTA,
		(duart_controller*) UARTB,
		(duart_controller*) UARTB
		};

#endif /************************* CPU REVISION-2A **********************/

inp_i (tty)
    int tty;

/* inp_i (tty)
 *	in:	tty		Uart number of interrupting device
 *	return:	(NONE)
 *	thrown:	(NONE)
 *
 *	Reads the input character and status from the uart and calls
 *	the input interrupt handler (inp_interrupt()) in aistty.c.
 *
 *	If there was a data overrun, the current character is thrown away
 *	and OVERRUN is flagged to the interrupt handler.
 *
 *	If there was a framing error, BREAK is flagged to the interrupt handler.
 */
{
    register unsigned chr;
    register UB8 stat;

#ifdef REV_2A /****************** CPU REVISION-2A **********************/
    stat = csrs[tty]->stat.c;		/* Read the status */
    chr = csrs[tty]->idata.c;		/* Read the character from the uart */
#endif /************************* CPU REVISION-2A **********************/

    /* if error or a char is in the uart */
    if (stat & (U_RXRDY | U_OVERRUN | U_FRAME | U_BREAK))
	{
	if (stat & U_OVERRUN)		/* if data overrun */
	    chr = (unsigned) OVERRUN;
	if (stat & (U_BREAK | U_FRAME))		/* if framing error */
	    chr = (unsigned) BREAK;

	if ((int) chr LT 0)
#ifdef REV_2A /****************** CPU REVISION-2A **********************/
	    csrs[tty]->cmd.c = U_ERRESET;		/* clear error flag */
#endif /************************* CPU REVISION-2A **********************/

	inp_interrupt (chr, ttypdds[tty]);
	} /*if-RXRDY*/
}

outqio (chr, tty)
    int chr;
    int tty;
{
    register uart_controller *csr;
#ifdef REV_2A /****************** CPU REVISION-2A **********************/
    register duart_controller *dcsr;

    dcsr = duarts[tty];		/* set duart csr address */
#endif /************************* CPU REVISION-2A **********************/

    csr = csrs[tty];		/* set uart csr address */

#ifdef DEBUG3   /*************************************************************/
    if ( NOT (csr->stat.c & U_TXRDY) ) 	   /* If uart is busy...error */
	error("Uart at %x not ready at outqio()", csr);
#endif /* DEBUG3 *************************************************************/

    csr->odata.c = (UB8) chr;		/* send out the character */

#ifdef REV_2A /****************** CPU REVISION-2A **********************/
    dcsr->imr.c = (UB8)
	(duart_imr[tty/2] |= ( (tty%2) ? U_BTXRDYINT : U_ATXRDYINT ));
#endif /************************* CPU REVISION-2A **********************/
}

#ifdef REV_2A /****************** CPU REVISION-2A **********************/

uart_a ()

/* uart_a () - Interrupt handler for duart-A
 *	return:	(NONE)
 *	thrown:	(NONE)
 *
 *	Calls the duart interrupt handler (duart_int(), below).
 */
{
    duart_int(UARTA, 0);	/* Duart-A first uart is number 0 */
}

uart_b ()

/* uart_b () - Interrupt handler for duart-B
 *	return:	(NONE)
 *	thrown:	(NONE)
 *
 *	Calls the duart interrupt handler (duart_int(), below).
 */
{
    duart_int(UARTB, 2);	/* Duart-B first uart is number 2 */
}


duart_int (du, ubase)
    duart_controller *du;
    int ubase;

/* duart_int (du, ubase) -- Duart interrupt handler
 *	in:	du		Address of duart to process
 *	in:	ubase		Number of first uart on this duart
 *	return:	(NONE)
 *	thrown:	(NONE)
 *
 *	Process input, then output interrupts on the duart whose
 *	address is 'du'.  Loop until there are no more pending
 *	interrupt conditions (the interrupt should be level-triggered).
 *	The lower-numbered of the uarts is processed first, but the
 *	priority of handling is basically rotating, since all pending
 *	conditions are handled before re-reading the interrupt source.
 */
{
    register unsigned char ibits;
    register int dubase;

    dubase = ubase/2;		/* set index for duart_imr lookup */

    /* while any 'activated' interrupts are pending */
    while ((ibits = du->isr.c & duart_imr[dubase]) NE 0)
	{
	if (ibits & U_ARXRDYINT)	/* input ready on first uart */
	    inp_i(ubase);
	if (ibits & U_BRXRDYINT)	/* input ready on second uart */
	    inp_i(ubase+1);
	if (ibits & U_ATXRDYINT)	/* output ready on first uart */
	    {
	    du->imr.c = (UB8) (duart_imr[dubase] &= ~(U_ATXRDYINT));
	    out_interrupt(ttypdds[ubase]);
	    }
	if (ibits & U_BTXRDYINT)	/* output ready on second uart */
	    {
	    du->imr.c = (UB8) (duart_imr[dubase] &= ~(U_BTXRDYINT));
	    out_interrupt(ttypdds[ubase+1]);
	    }
	}
}


tty_setbaud (tty, ibaud, obaud)
    int tty;
    unsigned ibaud;
    unsigned obaud;

/* tty_setbaud (tty, ibaud, obaud) -- Set the baud rate of a terminal line
 *	in:	tty		Terminal line number
 *	in:	ibaud		Input baud rate code
 *	in:	obaud		Output baud rate code
 *	return:	(NONE)
 *	thrown:	(NONE)
 *
 *	Sets the input and output baud rates of 'tty' according to
 *	'ibaud' and 'obaud'.
 */
{
    register uart_controller *csr;

    csr = csrs[tty];		/* set uart csr address */
    csr->baud.c = (UB8) (obaud | (ibaud << 4));	/* shift receive rate left */
}


tty_dtr (tty, on_off)
    int tty;
    BOOLEAN on_off;

/* tty_dtr (tty, on_off) -- Turn DTR on or off for a terminal line
 *	in:	tty		Terminal line number
 *	in:	on_off		TRUE  - turn DTR on
 *				FALSE - turn DTR off
 *	return:	(NONE)
 *	thrown:	(NONE)
 *
 *	Turns DTR for 'tty' on or off according to 'on_off' flag.
 */
{
    register duart_controller *csr;
    register UB8 dtr;

    csr = (duart_controller*) UART_MAPENABLE;	/* set csr for dtrs */
    dtr = DTR0 << tty;		/* set bit to toggle in uart */

    if (on_off)
	{
	csr->setout.c = dtr;	/* turn on DTR */
	}
    else
	{
	csr->clrout.c = dtr;	/* turn off DTR */
	}
}
#endif /************************* CPU REVISION-2A **********************/

_i_interrupts ()

/* _i_interrupts ()
 *	return:	(NONE)
 *	thrown:	(NONE)
 *
 *	Establish initial interrupt handling
 */
{
    register int_controller *icu;
    register unsigned eg;

    icu = (int_controller*) INTCTLR;		/* set base address of ICU */

    icu->mctl.c |= (UB8) (I_FRZ | I_COUTD | I_CFRZ);	/* disable controller */
    icu->svct.c = 0x10;			/* set first bank of vectors */
    icu->csrc0.c = icu->csrc1.c = '\0';	/* disable cascading */
    icu->fprt0.c = (UB8) 0;		/* clear first priority */
    icu->ocasn.c = (UB8) 0;		/* no clock output assignment */

    /* Initialize the VIOS system clock */
    icu->cctl.c = (UB8) I_CCON;		/* disable ctrs / concatenate ctrs */
    icu->cictl.c = (UB8) (I_WENH | I_WENL);	/* enable ctr write */
    icu->ciptr.c = (UB8) (TIMER_INT << 4);	/* assign interrupt vector */

    eg = (ICU_FREQ + (CLOCK_HERTZ/2)) / CLOCK_HERTZ;	/* get ctr value */

    icu->lcsv0.c = (UB8) eg;		/* set counter start value */
    icu->lccv0.c = (UB8) eg;		/* set counter current value */
    icu->lcsv1.c = (UB8) (eg >>= 8);	/* and higher order ctr bits */
    icu->lccv1.c = (UB8) eg;
    icu->hcsv0.c = (UB8) (eg >>= 8);
    icu->hccv0.c = (UB8) eg;
    icu->hcsv1.c = (UB8) (eg >>= 8);
    icu->hccv1.c = (UB8) eg;

    icu->cictl.c = (UB8) (I_WENH | I_CIEH);	/* concatenate ctrs */

					/* output port assignments? */

#ifdef REV_2A /****************** CPU REVISION-2A **********************/
    eg = (1 << UA_INT) | (1 << UB_INT);
    icu->eltg0.c |= (UB8) (eg);		/* set uarts level-triggered */
    icu->eltg1.c |= (UB8) (eg >> 8);

    icu->tpl0.c &= (UB8) (~(eg));	/* set uarts low level-triggered */
    icu->tpl1.c &= (UB8) (~(eg >> 8));

    duart_imr[0] = duart_imr[1] = 0;	/* all interrupts are masked */

    eg = (1 << HOST_INIT);		/* set up for Host Bus init ints */
    icu->eltg0.c &= (UB8) (~(eg));	/* set init edge-triggered */
    icu->eltg1.c &= (UB8) (~(eg >> 8));
    icu->tpl0.c &= (UB8) (~(eg));	/* set init falling edge-triggered */
    icu->tpl1.c &= (UB8) (~(eg >> 8));
#endif /************************* CPU REVISION-2A **********************/


    eg = (1 << CSR_I_INT);		/* host writes CSR to interrupt */
    icu->eltg0.c |= (UB8) (eg);	/* set CSR level-triggered */
    icu->eltg1.c |= (UB8) (eg >> 8);

#ifdef REV_2A /****************** CPU REVISION-2A **********************/
    icu->tpl0.c &= (UB8) ~(eg);	/* set CSR low-level-triggered */
    icu->tpl1.c &= (UB8) ~(eg >> 8);
#endif /************************* CPU REVISION-2A **********************/

    icu->imsk0.c = (UB8) (0xFF);	/* disable all interrupts */
    icu->imsk1.c = (UB8) (0xFF);

    icu->ipnd0.c = (UB8) (I_ICLRALL);	/* clear all pending interrupts */
    icu->ipnd1.c = (UB8) (I_ICLRALL);

    icu->mctl.c &= (UB8) ~(I_FRZ | I_COUTD | I_CFRZ);	/* enable controller */

    init_3200();		/* finish interrupt initialization */

#ifdef REV_2A /****************** CPU REVISION-2A **********************/
	/* enable Host Bus Init and DUART interrupts */
	/* (individual uart interrupt sources are masked) */
	eg |= ( (1 << HOST_INIT) | (1 << UA_INT) | (1 << UB_INT) );
#endif /************************* CPU REVISION-2A **********************/

    eg |= (1 << TIMER_INT);		/* enable clock interrupts */
    icu->imsk0.c &= (UB8) (~(eg));	/* enable CSR interrupts */
    icu->imsk1.c &= (UB8) (~(eg >> 8));

    icu->cctl.c |= (UB8) (I_CRUNH | I_CFNPS);	/* start clock */
}

    uart_controller *
initty (pdd, name)
    PDD_PTR pdd;
    register char  *name;

/* initty (pdd, name)
 *	in:	pdd		Physical Device Descriptor bufptr
 *	in:	name		ASCIZ device name (number only) to associate
 *	return:	(uart_controller*)	Unit number of device
 *	thrown:	V_NO_DEVICE	Invalid terminal name
 *
 *	Verifies that AIS:TTY'name' is a valid uart descriptor and, if so:
 *		1) Saves 'pdd' in a descriptor table for interrupt handling.
 *		2) Enables interrupts for that UART.
 *		3) Returns the unit number of the device (formerly CSR addr)
 *			so that handler routines can locate both the duart
 *			and uart csrs.
 *
 *	Throws V_NO_DEVICE if 'name' is not valid.
 */
{
#ifdef REV_2A /****************** CPU REVISION-2A **********************/
    register duart_controller *du;
#endif /************************* CPU REVISION-2A **********************/

    register unsigned enable;
    register int unit;

    unit = *name++ - '0';		/* convert number to binary */

    if (*name NE '\0')
	throw(V_NO_DEVICE);		/* Only one digit tolerated */

    switch (unit)
	{
#ifdef REV_2A /****************** CPU REVISION-2A **********************/
    case 0:
	enable = (U_ARXRDYINT);			/* set bits to set */
	du = (duart_controller*) UARTA;		/* set duart to manipulate */
	break;

    case 1:
	enable = (U_BRXRDYINT);			/* set bits to set */
	du = (duart_controller*) UARTA;		/* set duart to manipulate */
	break;

    case 2:
	enable = (U_ARXRDYINT);			/* set bits to set */
	du = (duart_controller*) UARTB;		/* set duart to manipulate */
	break;

    case 3:
	enable = (U_BRXRDYINT);			/* set bits to set */
	du = (duart_controller*) UARTB;		/* set duart to manipulate */
	break;
#endif /************************* CPU REVISION-2A **********************/

    default:
	throw(V_NO_DEVICE);
	}

#ifdef REV_2A /****************** CPU REVISION-2A **********************/
    du->imr.c = (duart_imr[unit/2] |= enable);	/* enable more ints */
#endif /************************* CPU REVISION-2A **********************/

    ttypdds[unit] = (unsigned*) pdd;	/* save PDD_PTR for this device */

    return((uart_controller*)unit);	/* return unit number */
}
