diff options
Diffstat (limited to 'sys/arch/hp300/dev/dcm.c')
-rw-r--r-- | sys/arch/hp300/dev/dcm.c | 194 |
1 files changed, 106 insertions, 88 deletions
diff --git a/sys/arch/hp300/dev/dcm.c b/sys/arch/hp300/dev/dcm.c index 11f424db983..12202b9c4cf 100644 --- a/sys/arch/hp300/dev/dcm.c +++ b/sys/arch/hp300/dev/dcm.c @@ -1,4 +1,4 @@ -/* $NetBSD: dcm.c,v 1.20 1995/12/02 18:18:50 thorpej Exp $ */ +/* $NetBSD: dcm.c,v 1.22 1995/12/31 00:27:21 thorpej Exp $ */ /* * Copyright (c) 1995 Jason R. Thorpe. All rights reserved. @@ -68,6 +68,8 @@ #include <machine/cpu.h> +#include <dev/cons.h> + #include <hp300/dev/device.h> #include <hp300/dev/dcmreg.h> #include <hp300/hp300/isr.h> @@ -122,14 +124,18 @@ struct dcmischeme { }; /* - * Console support + * Stuff for DCM console support. This could probably be done a little + * better. */ +static struct dcmdevice *dcm_cn = NULL; /* pointer to hardware */ +static int dcm_lastcnpri = CN_DEAD; /* XXX last priority */ +static int dcmconsinit; /* has been initialized */ #ifdef DCMCONSOLE -int dcmconsole = DCMCONSOLE; +static int dcmconsole = DCMCONSOLE; #else -int dcmconsole = -1; +static int dcmconsole = -1; #endif -int dcmconsinit; + int dcmdefaultrate = DEFAULT_BAUD_RATE; int dcmconbrdbusy = 0; int dcmmajor; @@ -214,7 +220,11 @@ static char iconv[16] = { MI_RI|MI_CD|MI_CTS|MI_DM }; -#define NDCMPORT 4 /* XXX what about 8-port cards? */ +/* + * Note that 8-port boards appear as 2 4-port boards at consecutive + * select codes. + */ +#define NDCMPORT 4 struct dcm_softc { struct hp_device *sc_hd; /* device info */ @@ -228,7 +238,6 @@ struct dcm_softc { /* * Mask of soft-carrier bits in config flags. - * XXX What about 8-port cards? */ #define DCM_SOFTCAR 0x0000000f @@ -246,6 +255,8 @@ struct dcm_softc { #endif } dcm_softc[NDCM]; +void dcminit __P((struct dcmdevice *, int, int)); + int dcmmatch(hd) register struct hp_device *hd; @@ -374,7 +385,8 @@ dcmattach(hd) * by the corresponding code in dcmcnprobe. */ else { - (void) dcminit(kgdb_dev, kgdb_rate); + dcminit(dcm, DCMPORT(DCMUNIT(kgdb_dev)), + kgdb_rate); if (kgdb_debug_init) { printf("%s port %d: ", sc->sc_hd->hp_xname, DCMPORT(DCMUNIT(kgdb_dev))); @@ -428,7 +440,7 @@ dcmopen(dev, flag, mode, p) * The card might be left in an inconsistent state * if the card memory is read inadvertently. */ - dcminit(dev, dcmdefaultrate); + dcminit(sc->sc_dcm, port, dcmdefaultrate); tp->t_state |= TS_WOPEN; ttychars(tp); @@ -1325,16 +1337,50 @@ dcmsetischeme(brd, flags) SEM_UNLOCK(dcm); } +void +dcminit(dcm, port, rate) + struct dcmdevice *dcm; + int port, rate; +{ + int s, mode; + + mode = LC_8BITS | LC_1STOP; + + s = splhigh(); + + /* + * Wait for transmitter buffer to empty. + */ + while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) + DELAY(DCM_USPERCH(rate)); + + /* + * Make changes known to hardware. + */ + dcm->dcm_data[port].dcm_baud = ttspeedtab(rate, dcmspeedtab); + dcm->dcm_data[port].dcm_conf = mode; + SEM_LOCK(dcm); + dcm->dcm_cmdtab[port].dcm_data |= CT_CON; + dcm->dcm_cr |= (1 << port); + SEM_UNLOCK(dcm); + + /* + * Delay for config change to take place. Weighted by baud. + * XXX why do we do this? + */ + DELAY(16 * DCM_USPERCH(rate)); + splx(s); +} + /* * Following are all routines needed for DCM to act as console */ -#include <dev/cons.h> void dcmcnprobe(cp) struct consdev *cp; { - struct dcm_softc *sc; + struct dcm_softc *sc; /* XXX thorpej */ struct dcmdevice *dcm; struct hp_hw *hw; int unit; @@ -1345,6 +1391,7 @@ dcmcnprobe(cp) break; /* + * XXX FIX ME! * Implicitly assigns the lowest select code DCM card found to be * logical unit 0 (actually CONUNIT). If your config file does * anything different, you're screwed. @@ -1358,8 +1405,7 @@ dcmcnprobe(cp) } unit = CONUNIT; - sc = &dcm_softc[DCMBOARD(CONUNIT)]; - dcm = sc->sc_dcm = (struct dcmdevice *)hw->hw_kva; + dcm = (struct dcmdevice *)hw->hw_kva; /* initialize required fields */ cp->cn_dev = makedev(dcmmajor, unit); @@ -1382,6 +1428,17 @@ dcmcnprobe(cp) */ if (dcmconsole == unit) cp->cn_pri = CN_REMOTE; + + /* + * If our priority is higher than the currently-remembered + * DCM, stash our priority and address, for the benefit of + * dcmcninit(). + */ + if (cp->cn_pri > dcm_lastcnpri) { + dcm_lastcnpri = cp->cn_pri; + dcm_cn = dcm; + } + #ifdef KGDB_CHEAT /* * This doesn't currently work, at least not with ite consoles; @@ -1389,7 +1446,7 @@ dcmcnprobe(cp) */ if (major(kgdb_dev) == dcmmajor && DCMBOARD(DCMUNIT(kgdb_dev)) == DCMBOARD(unit)) { - (void) dcminit(kgdb_dev, kgdb_rate); + dcminit(dcm_cn, DCMPORT(DCMUNIT(kgdb_dev)), kgdb_rate); if (kgdb_debug_init) { /* * We assume that console is ready for us... @@ -1408,77 +1465,37 @@ void dcmcninit(cp) struct consdev *cp; { + int unit = DCMUNIT(cp->cn_dev); + int port = DCMPORT(unit); - dcminit(cp->cn_dev, dcmdefaultrate); + dcminit(dcm_cn, port, dcmdefaultrate); dcmconsinit = 1; dcmconsole = DCMUNIT(cp->cn_dev); } -dcminit(dev, rate) - dev_t dev; - int rate; -{ - struct dcm_softc *sc; - struct dcmdevice *dcm; - int s, mode, unit, board, port; - - unit = DCMUNIT(dev); - board = DCMBOARD(unit); - port = DCMPORT(unit); - - sc = &dcm_softc[board]; - dcm = sc->sc_dcm; - - mode = LC_8BITS | LC_1STOP; - - s = splhigh(); - - /* - * Wait for transmitter buffer to empty. - */ - while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) - DELAY(DCM_USPERCH(rate)); - - /* - * Make changes known to hardware. - */ - dcm->dcm_data[port].dcm_baud = ttspeedtab(rate, dcmspeedtab); - dcm->dcm_data[port].dcm_conf = mode; - SEM_LOCK(dcm); - dcm->dcm_cmdtab[port].dcm_data |= CT_CON; - dcm->dcm_cr |= (1 << port); - SEM_UNLOCK(dcm); - - /* - * Delay for config change to take place. Weighted by baud. - * XXX why do we do this? - */ - DELAY(16 * DCM_USPERCH(rate)); - splx(s); -} - int dcmcngetc(dev) dev_t dev; { - struct dcm_softc *sc; - struct dcmdevice *dcm; struct dcmrfifo *fifo; struct dcmpreg *pp; u_int head; - int s, c, stat, unit, board, port; + int s, c, stat, unit, port; unit = DCMUNIT(dev); - board = DCMBOARD(unit); port = DCMPORT(unit); - sc = &dcm_softc[board]; - dcm = sc->sc_dcm; - pp = dcm_preg(dcm, port); + /* + * NOTE: This assumes that unit == dcmconsole. If it doesn't, + * well, you lose. (It's also extremely unlikely that will ever + * not be the case.) + */ + + pp = dcm_preg(dcm_cn, port); s = splhigh(); head = pp->r_head & RX_MASK; - fifo = &dcm->dcm_rfifos[3-port][head>>1]; + fifo = &dcm_cn->dcm_rfifos[3-port][head>>1]; while (head == (pp->r_tail & RX_MASK)) ; /* @@ -1486,10 +1503,10 @@ dcmcngetc(dev) * interrupt through in case some other port on the board was * busy. Otherwise we must clear the interrupt. */ - SEM_LOCK(dcm); - if ((dcm->dcm_ic & IC_IE) == 0) - stat = dcm->dcm_iir; - SEM_UNLOCK(dcm); + SEM_LOCK(dcm_cn); + if ((dcm_cn->dcm_ic & IC_IE) == 0) + stat = dcm_cn->dcm_iir; + SEM_UNLOCK(dcm_cn); c = fifo->data_char; stat = fifo->data_stat; pp->r_head = (head + 2) & RX_MASK; @@ -1505,37 +1522,38 @@ dcmcnputc(dev, c) dev_t dev; int c; { - struct dcm_softc *sc; - struct dcmdevice *dcm; struct dcmpreg *pp; unsigned tail; - int s, unit, board, port, stat; + int s, unit, port, stat; unit = DCMUNIT(dev); - board = DCMBOARD(unit); port = DCMPORT(unit); - sc = &dcm_softc[board]; - dcm = sc->sc_dcm; - pp = dcm_preg(dcm, port); + /* + * NOTE: This assumes that unit == dcmconsole. If it doesn't, + * well, you lose. (It's also extremely unlikely that will ever + * not be the case.) + */ + + pp = dcm_preg(dcm_cn, port); s = splhigh(); #ifdef KGDB if (dev != kgdb_dev) #endif if (dcmconsinit == 0) { - (void) dcminit(dev, dcmdefaultrate); + dcminit(dcm_cn, port, dcmdefaultrate); dcmconsinit = 1; } tail = pp->t_tail & TX_MASK; while (tail != (pp->t_head & TX_MASK)) ; - dcm->dcm_tfifos[3-port][tail].data_char = c; + dcm_cn->dcm_tfifos[3-port][tail].data_char = c; pp->t_tail = tail = (tail + 1) & TX_MASK; - SEM_LOCK(dcm); - dcm->dcm_cmdtab[port].dcm_data |= CT_TX; - dcm->dcm_cr |= (1 << port); - SEM_UNLOCK(dcm); + SEM_LOCK(dcm_cn); + dcm_cn->dcm_cmdtab[port].dcm_data |= CT_TX; + dcm_cn->dcm_cr |= (1 << port); + SEM_UNLOCK(dcm_cn); while (tail != (pp->t_head & TX_MASK)) ; /* @@ -1543,11 +1561,11 @@ dcmcnputc(dev, c) * interrupt through in case some other port on the board * was busy. Otherwise we must clear the interrupt. */ - if ((dcm->dcm_ic & IC_IE) == 0) { - SEM_LOCK(dcm); - stat = dcm->dcm_iir; - SEM_UNLOCK(dcm); + if ((dcm_cn->dcm_ic & IC_IE) == 0) { + SEM_LOCK(dcm_cn); + stat = dcm_cn->dcm_iir; + SEM_UNLOCK(dcm_cn); } splx(s); } -#endif +#endif /* NDCM > 0 */ |