|
|
researchv9-SUN3
#ifndef lint
static char sccsid[] = "@(#)zs_common.c 1.1 86/02/03 Copyr 1985 Sun Micro";
#endif
/*
* Copyright (c) 1985 by Sun Microsystems, Inc.
*/
/*
* Sun USART(s) driver - common code for all protocols
*/
#include "zs.h"
#if NZS > 0
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/buf.h"
#include "../machine/enable.h"
#include "../machine/mmu.h"
#include "../machine/cpu.h"
#include "../machine/scb.h"
#include "../machine/fault.h"
/*#include "../sun/consdev.h"*/
#include "../sundev/mbvar.h"
#include "../sundev/zsreg.h"
#include "../sundev/zscom.h"
#include "../sundev/zsvar.h"
#define NZSLINE (2*NZS)
struct zscom zscom[NZSLINE];
struct zscom *zscurr = &zscom[1];
struct zscom *zslast = &zscom[0];
#define ZREADA(n) zszread((struct zscc_device *)((int)zs->zs_addr|4), n)
#define ZREADB(n) zszread((struct zscc_device *)((int)zs->zs_addr&~4), n)
#define ZWRITEA(n, v) zszwrite((struct zscc_device *)((int)zs->zs_addr|4), \
n, v)
#define ZWRITEB(n, v) zszwrite((struct zscc_device *)((int)zs->zs_addr&~4), \
n, v)
/*
* Driver information for auto-configuration stuff.
*/
int zsprobe(), zsattach(), zsintr();
struct mb_device *zs_info[NZS];
struct mb_driver zsdriver = {
zsprobe, 0, zsattach, 0, 0, zsintr,
2 * sizeof(struct zscc_device), "zs", zs_info, 0, 0, 0,
};
int zssoftflags[NZSLINE];
/*ARGSUSED*/
zsprobe(reg, unit)
caddr_t reg;
{
register struct zscc_device *zsaddr = (struct zscc_device *)reg;
struct zscom tmpzs, *zs = &tmpzs;
short speed[2];
register int c, loops;
label_t jb;
/* get in sync with the chip */
if ((c = peekc((char *)&zsaddr->zscc_control)) == -1)
return (0);
/*
* We see if it's a Z8530 by looking at register 15
* which always has two bits as zero. If it's not a
* Z8530 then setting control to 15 will probably set
* those bits. Hack, hack.
*/
if (pokec((char *)&zsaddr->zscc_control, 15)) /* set reg 15 */
return (0);
if ((c = peekc((char *)&zsaddr->zscc_control)) == -1)
return (0);
if (c & 5)
return (0);
/*
* Well, that test wasn't strong enough for the damn UARTs
* on the video board in P2 memory, so here comes some more
* Anywhere in the following process, the non-existent video
* board may decide to give us a parity error, so we use nofault
* to catch any errors from here to the end of the probe routine
*/
zs->zs_addr = zsaddr; /* for zszread/write */
nofault = (label_t *)jb;
if (setjmp(nofault)) {
/* error occurred */
goto error;
}
/*
* we can't trust the drain bit in the uart cause we don't know
* that the uart is really there.
* We need this because trashing the speeds below causes garbage
* to be sent.
*/
loops = 0;
while ((ZREADA(1) & ZSRR1_ALL_SENT) == 0 ||
(ZREADB(1) & ZSRR1_ALL_SENT) == 0 ||
(ZREADA(0) & ZSRR0_TX_READY) == 0 ||
(ZREADB(0) & ZSRR0_TX_READY) == 0) {
DELAY(1000);
if (loops++ > 500)
break;
}
/* must preserve speeds for monitor / console */
speed[0] = ZREADA(12);
speed[0] |= ZREADA(13) << 8;
speed[1] = ZREADB(12);
speed[1] |= ZREADB(13) << 8;
ZWRITEA(12, 17);
ZWRITEA(13, 23);
ZWRITEB(12, 29);
ZWRITEB(13, 37);
if (ZREADA(12) != 17)
goto error;
if (ZREADA(13) != 23)
goto error;
if (ZREADB(12) != 29)
goto error;
if (ZREADB(13) != 37)
goto error;
/* restore original speeds */
ZWRITEA(12, speed[0]);
ZWRITEA(13, speed[0] >> 8);
ZWRITEB(12, speed[1]);
ZWRITEB(13, speed[1] >> 8);
nofault = 0;
return (2 * sizeof (struct zscc_device));
error:
nofault = 0;
return (0);
}
#ifdef sun3
/*
* Base vector numbers for SCC chips
* Each SCC chip requires 8 contiguous even or odd vectors,
* on a multiple of 16 boundary
* E.G., nnnnxxxn where nnnn000n is the base value
*/
short zsvecbase[] = {
144, /* zs0 - 1001xxx0 */
145, /* zs1 - 1001xxx1 */
};
#define NZSVEC (sizeof zsvecbase/sizeof zsvecbase[0])
#endif sun3
zsattach(md)
register struct mb_device *md;
{
register struct zscom *zs = &zscom[md->md_unit*2];
register struct zsops *zso;
register int i, j;
short speed[2];
int loops;
short vector = 0;
#ifdef sun3
/*
* Install the 8 vectors for this SCC chip
*/
if (cpu != CPU_SUN3_50) {
extern int (*zsvectab[NZS][8])();
int (**p)(), (**q)();
if (md->md_unit >= NZSVEC)
panic("zsattach: too many zs units");
vector = zsvecbase[md->md_unit];
p = &scb.scb_user[vector - VEC_MIN];
q = &zsvectab[md->md_unit][0];
for (i = 0; i < 8; i++) {
*p = *q++;
p += 2;
}
}
#endif sun3
stopnmi();
zs->zs_addr = (struct zscc_device *)md->md_addr;
loops = 0;
while ((ZREADA(1) & ZSRR1_ALL_SENT) == 0 ||
(ZREADB(1) & ZSRR1_ALL_SENT) == 0 ||
(ZREADA(0) & ZSRR0_TX_READY) == 0 ||
(ZREADB(0) & ZSRR0_TX_READY) == 0) {
DELAY(1000);
if (loops++ > 500)
break;
}
/* must preserve speeds over reset for monitor */
speed[0] = ZREADA(12);
speed[0] |= ZREADA(13) << 8;
speed[1] = ZREADB(12);
speed[1] |= ZREADB(13) << 8;
ZWRITE(9, ZSWR9_RESET_WORLD); DELAY(10);
zs->zs_wreg[9] = 0;
for (i = 0; i < 2; i++) {
if (i == 0) { /* port A */
zs->zs_addr = (struct zscc_device *)
((int)md->md_addr | 4);
} else { /* port B */
zs++;
zs->zs_addr = (struct zscc_device *)
((int)md->md_addr &~ 4);
zscurr = zs;
}
zs->zs_unit = md->md_unit * 2 + i;
zssoftflags[zs->zs_unit] = (md->md_flags & (1 << i)) ? 1 : 0;
zssoftflags[zs->zs_unit] |= (md->md_flags & ZS_KBDMS);
for (j=0; zs_proto[j]; j++) {
zso = zs_proto[j];
(*zso->zsop_attach)(zs, speed[i]);
}
}
ZWRITE(9, ZSWR9_MASTER_IE + ZSWR9_VECTOR_INCL_STAT);
if (vector)
ZWRITE(2, vector);
DELAY(4000);
startnmi();
zslast = zs;
if (md->md_intpri != 3) {
printf("zs%d: priority %d\n", md->md_unit, md->md_intpri);
panic("bad zs priority");
}
}
/*
* Handle Hardware level 6 interrupts
* These interrupts are locked out only by splzs or spl7,
* not by spl6, so this routine may not use UNIX facilities such
* as wakeup which depend on being able to disable interrupts with spls.
* All communication with the rest of the world is done through the zscom
* structure and the use of level 3 software interrupts.
*
* This routine is only called when the vector indicated by the most
* recently interrupting SCC is a "special receive" interrupt.
* This vector is used BOTH for special receive interrupts and to
* indicate NO interrupt pending. In the no interrupt pending case
* we must poll the other SCCs to find the interrupter.
* Low level assembler code dispatches the other vectors using the zs_vec
* array. This assembler routine is also the code which actually clears
* the interrupt; the argzs argument is a value/return argument which changes
* when a different SCC interrupts.
*/
zslevel6intr(argzs)
struct zscom *argzs; /* NOTE: value/return argument!! */
{
register struct zscom *zs;
register short iinf, unit;
zs = zscurr; /* always channel B */
unit = 0;
for (;;) {
if (zs->zs_addr && ZREADA(3))
break;
zs += 2; /* always channel B */
if (zs > zslast)
zs = &zscom[1];
if (++unit >= NZS)
return;
}
zscurr = zs;
iinf = ZREAD(2); /* get interrupt vector & status */
if (iinf & 8)
zs = zscurr - 1; /* channel A */
else
zs = zscurr; /* channel B */
switch (iinf & 6) {
case 0: /* xmit buffer empty */
(*zs->zs_ops->zsop_txint)(zs);
break;
case 2: /* external/status change */
(*zs->zs_ops->zsop_xsint)(zs);
break;
case 4: /* receive char available */
(*zs->zs_ops->zsop_rxint)(zs);
break;
case 6: /* special receive condition or no interrupt */
(*zs->zs_ops->zsop_srint)(zs);
break;
}
argzs = zs;
#ifdef lint
argzs = argzs;
#endif lint
}
/*
* Install a new ops vector into low level vector routine addresses
*/
zsopinit(zs, zso)
register struct zscom *zs;
register struct zsops *zso;
{
zs->zs_vec[0] = zso->zsop_txint;
zs->zs_vec[1] = zso->zsop_xsint;
zs->zs_vec[2] = zso->zsop_rxint;
switch (cpu) {
#ifdef sun3
case CPU_SUN3_160:
case CPU_SUN3_260:
/* vectored interrupts */
zs->zs_vec[3] = zso->zsop_srint;
break;
#endif sun3
default:
/* non-vectored Sun-2 and Sun-3 50 (Model 25) */
zs->zs_vec[3] = zslevel6intr;
break;
}
zs->zs_ops = zso;
}
/*
* Handle a level 3 interrupt
* This is the routine found by autoconf in the driver structure
*/
zsintr()
{
register struct zscom *zs;
if (clrzssoft()) {
zssoftpend = 0;
for (zs = &zscom[0]; zs <= zslast; zs++) {
if (zs->zs_flags & ZS_NEEDSOFT) {
zs->zs_flags &=~ ZS_NEEDSOFT;
(*zs->zs_ops->zsop_softint)(zs);
}
}
return (1);
}
return (0);
}
/*
* The "null" zs protocol
* Called before the others to initialize things
* and prevent interrupts on unused devices
*/
int zsnull_attach(), zsnull_intr(), zsnull_softint();
struct zsops zsops_null = {
zsnull_attach,
zsnull_intr,
zsnull_intr,
zsnull_intr,
zsnull_intr,
zsnull_softint,
};
zsnull_attach(zs, speed)
register struct zscom *zs;
{
/* make sure ops prt is valid */
zsopinit(zs, &zsops_null);
/*
* Set up the default asynch modes
* so the monitor will still work
*/
ZWRITE(4, ZSWR4_PARITY_EVEN + ZSWR4_1_STOP + ZSWR4_X16_CLK);
ZWRITE(3, ZSWR3_RX_8);
ZWRITE(11, ZSWR11_TXCLK_BAUD + ZSWR11_RXCLK_BAUD);
ZWRITE(12, speed);
ZWRITE(13, speed >> 8);
ZWRITE(14, ZSWR14_BAUD_FROM_PCLK);
ZWRITE(3, ZSWR3_RX_8 + ZSWR3_RX_ENABLE);
ZWRITE(5, ZSWR5_TX_ENABLE + ZSWR5_TX_8 + ZSWR5_RTS + ZSWR5_DTR);
ZWRITE(14, ZSWR14_BAUD_ENA + ZSWR14_BAUD_FROM_PCLK);
zs->zs_addr->zscc_control = ZSWR0_RESET_ERRORS + ZSWR0_RESET_STATUS;
}
zsnull_intr(zs)
register struct zscom *zs;
{
register struct zscc_device *zsaddr = zs->zs_addr;
register short c;
zsaddr->zscc_control = ZSWR0_RESET_TXINT;
DELAY(2);
zsaddr->zscc_control = ZSWR0_RESET_STATUS;
DELAY(2);
c = zsaddr->zscc_data;
#ifdef lint
c = c;
#endif lint
DELAY(2);
zsaddr->zscc_control = ZSWR0_RESET_ERRORS;
}
zsnull_softint(zs)
register struct zscom *zs;
{
printf("zs%d: unexpected soft int\n", zs->zs_unit);
}
#endif NZS > 0
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.