Rewrite pmax console-probing code from scratch

as pmax/dev/findcons.c:
 *  Follow the same logic: look for the device the PROM is using.
 *  If it's a framebuffer and we don't have a driver for it, try other
 *  framebuffers in PROM search order.
 *  If no match found, warn user and fall over to serial console.
 *  if no serial console found, go back to PROM.

Rework tc/scc.c attach routine to give cleaner initialization semantics.
Prune out old 'braindamage' code.
This commit is contained in:
jonathan 1998-03-24 08:39:02 +00:00
parent 3172e096d3
commit 1c0730217a
4 changed files with 780 additions and 288 deletions

View File

@ -0,0 +1,496 @@
/* $NetBSD: findcons.c,v 1.1 1998/03/24 08:39:02 jonathan Exp $ */
/*
* Copyright (c) 1998 Jonathan Stone
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Jonathan Stone for
* the NetBSD Project.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: findcons.c,v 1.1 1998/03/24 08:39:02 jonathan Exp $$");
#include <sys/param.h>
#include <sys/systm.h>
#include <dev/cons.h>
#include <sys/device.h>
#include <sys/termios.h>
#include <pmax/pmax/pmaxtype.h>
extern int pmax_boardtype; /* Motherboard type */
/*
* Default consdev, for errors or warnings before
* consinit runs: use the PROM.
*/
struct consdev cd;
#ifndef integrate
#define integrate static inline
#endif
/*
* Kernel configuration dependencies.
*/
#include "pm.h"
#include "cfb.h"
#include "mfb.h"
#include "xcfb.h"
#include "sfb.h"
#include "dc_ds.h"
#include "dc_ioasic.h"
#include "dtop.h"
#include "scc.h"
#include "asc.h"
#include "tc.h"
#include "rasterconsole.h"
#include <dev/tc/tcvar.h> /* find TC fraembuffer device. */
#include <machine/pmioctl.h>
#include <machine/fbio.h> /* framebuffer decls used below */
#include <machine/fbvar.h>
#include <pmax/dev/fbreg.h>
#include <pmax/dev/promiovar.h>
#include <pmax/dev/lk201var.h>
#include <pmax/dev/rconsvar.h>
/* pmax serial interface */
#if (NDC_DS > 0) || (NDC_IOASIC > 0)
#include <machine/dc7085cons.h>
#include <pmax/dev/dc_cons.h>
#include <pmax/dev/dc_ds_cons.h>
#include <pmax/dev/dc_ioasic_cons.h>
#endif
/* MAXINE desktop bus keyboard */
#if NDTOP > 0
#include <pmax/dev/dtopvar.h>
#endif
/* ioasic serial console */
#if NSCC > 0
#include <pmax/tc/sccvar.h>
#endif
/* ds3100 baseboard framebuffer */
#if NPM > 0
#include <pmax/dev/pmvar.h>
#endif
/* maxine baseboard framebuffer */
#if NXCFB > 0
#include <pmax/dev/xcfbvar.h>
#endif
/*
* XXX Major device numbers for possible console devices.
*/
#define DTOPDEV 15
#define DCDEV 16
#define SCCDEV 17
#define RCONSDEV 85
/*
* forward declarations
*/
/*
* device scan functions.
* This would use the autoconfigatin hiearchy, except we need
* to pick a console early in boot before autoconfig or
* malloc are up.
*/
integrate int dc_ds_kbd __P((int prom_slot));
integrate int dc_ioasic_kbd __P((int prom_slot));
integrate int scc_kbd __P((int prom_slot));
integrate int dtop_kbd __P((int prom_slot));
integrate int pm_screen __P((int prom_slot));
integrate int xcfb_screen __P((int prom_slot));
integrate int tc_screen __P((int prom_slot));
integrate int dc_ds_serial __P((int prom_slot));
integrate int dc_ioasic_serial __P((int prom_slot));
integrate int scc_serial __P((int prom_slot));
int find_kbd __P((int prom_slot));
int find_screen __P((int prom_slot));
int find_serial __P((int prom_slot));
void consinit __P((void));
/*
* Keyboard physically present and driver configured on 3100?
*/
int
dc_ds_kbd(kbd_slot)
int kbd_slot;
{
#if NDC_DS > 0
if (pmax_boardtype == DS_PMAX) {
cd.cn_getc = LKgetc;
lk_divert(dcGetc, makedev(DCDEV, DCKBD_PORT));
return 1;
}
#endif
return 0;
}
/*
* Keyboard supported and present on 5000/200?
*/
int
dc_ioasic_kbd(kbd_slot)
int kbd_slot;
{
#if NDC_IOASIC > 0
if (kbd_slot == 7) {
cd.cn_dev = makedev(DCDEV, DCKBD_PORT);
cd.cn_getc = LKgetc;
lk_divert(dcGetc, makedev(DCDEV, DCKBD_PORT));
return 1;
}
#endif
return 0;
}
/*
* Keyboard configured and physically presnt on 3min, 3maxplus?
*/
int
scc_kbd(kbd_slot)
int kbd_slot;
{
#if NSCC > 0
if (kbd_slot == 3) {
cd.cn_dev = makedev(SCCDEV, SCCKBD_PORT);
lk_divert(sccGetc, makedev(SCCDEV, SCCKBD_PORT));
cd.cn_getc = LKgetc;
return 1;
}
#endif /* NSCC */
return 0;
}
/*
* Keyboard physically present and driver configured on MAXINE?
*/
int
dtop_kbd(kbd_slot)
int kbd_slot;
{
if (pmax_boardtype != DS_MAXINE)
return 0;
#if NDTOP > 0
if (kbd_slot == 3) {
cd.cn_getc = dtopKBDGetc;
return 1;
}
#endif
return 0;
}
/*
* Select appropriate keyboard.
*/
int
find_kbd(kbd)
int kbd;
{
switch(pmax_boardtype) {
case DS_PMAX:
return (dc_ds_kbd(kbd));
break;
case DS_3MAX:
return (dc_ioasic_kbd(kbd));
break;
case DS_3MIN: case DS_3MAXPLUS:
/* keyboard on scc? */
return (scc_kbd(kbd));
break;
case DS_MAXINE:
return (dtop_kbd(kbd));
default:
break;
}
/* No keyboard found. */
return (0);
}
/*
* Test if screens configured.
*/
int
pm_screen(crtslot)
int crtslot;
{
#if NPM > 0
if (pminit(0, 0, 1)) {
cd.cn_pri = CN_INTERNAL;
return(1);
}
#endif
return (0);
}
/*
* Look for MAXINE basboard video.
* If selected as console, take it.
*/
int
xcfb_screen(crtslot)
int crtslot;
{
if (pmax_boardtype != DS_MAXINE)
return 0;
#if NXCFB > 0
if (crtslot == 3 && xcfbinit(NULL, NULL, 0, 0)) {
cd.cn_pri = CN_INTERNAL;
return(1);
} else
#endif
return (0);
}
int
tc_screen(crtslot)
int crtslot;
{
#if NTC > 0
if (tc_findconsole(crtslot)) {
return (1);
}
#endif
return 0;
}
/*
* Look for screen.
*/
int
find_screen(crtslot)
int crtslot;
{
switch(pmax_boardtype) {
case DS_PMAX:
if (pm_screen(crtslot))
return (1);
/* no other options on 3100s. */
break;
case DS_MAXINE:
if (xcfb_screen(crtslot))
return (1);
/*FALLTHROUGH*/
case DS_3MAX:
case DS_3MIN:
case DS_3MAXPLUS:
/* TC option video?*/
if (tc_screen(crtslot))
return(1);
break;
default:
break;
}
/* no screen found. */
return (0);
}
int
dc_ds_serial(comslot)
int comslot;
{
#if NDC_DS
if (comslot == 4)
cd.cn_dev = makedev(DCDEV, DCCOMM_PORT);
else
cd.cn_dev = makedev(DCDEV, DCPRINTER_PORT);
return dc_ds_consinit(cd.cn_dev);
#endif
return 0;
}
int
dc_ioasic_serial(comslot)
int comslot;
{
#if NDC_IOASIC
cd.cn_dev = makedev(DCDEV, DCPRINTER_PORT);
return dc_ioasic_consinit(cd.cn_dev);
#else
return 0;
#endif
}
int
scc_serial(comslot)
int comslot;
{
#if NSCC > 0
int dev;
/*
* On the 3min and 3maxplus, the default serial-console
* port is on the chip at the higher address.
* On the MAXINE, there is only serial port, which
* configures at the lower address.
*/
dev = (pmax_boardtype == DS_MAXINE) ? SCCCOMM2_PORT: SCCCOMM3_PORT;
#ifdef notyet /* no boot-time init entrypoint for scc */
cd.cn_dev = makedev(SCCDEV, DCPRINTER_PORT);
return dc_ioasic_consinit(cd.cn_dev);
#else /* !notyet */
printf("Using PROM serial output until serial drivers initialized.\n");
cd.cn_dev = makedev (SCCDEV, dev);
return(1);
#endif /* notyet */
#endif /* NSCC */
return 0;
}
/*
* find a serial console.
*/
int
find_serial(comslot)
int comslot;
{
switch(pmax_boardtype) {
case DS_PMAX:
return (dc_ds_serial(comslot));
break;
case DS_3MAX:
return (dc_ioasic_serial(comslot));
break;
case DS_MAXINE: /* XXX only one serial port */
case DS_3MIN:
case DS_3MAXPLUS:
return (scc_serial(comslot));
break;
default:
break;
}
return (0);
}
/*
* Pick a console.
* Use the same devices as PROM says, if we have a driver.
* if wedont' have a driver for the device the PROM chose,
* pick the highest-priority device according to the Owners Guide rules.
* If no match, stick with the PROM and hope for the best.
*/
void
consinit()
{
int prom_using_screen = 0; /* boolean */
int kbd = 0; /* prom kbd locator */
int crt = 0; /* prom framebuffer locator */
/* Use copy of PROM console until we find something better. */
cd = promcd;
cn_tab = &cd;
/* get PROM's idea of what the console is. */
prom_findcons(&kbd, &crt, &prom_using_screen);
/* if the prom is using a screen, try that. */
if (prom_using_screen) {
if (find_kbd(kbd) && find_screen(crt)) {
#if NRASTERCONSOLE > 0
cd.cn_pri = CN_NORMAL;
rcons_indev(&cd);
return;
#endif /* NRASTERCONSOLE > 0 */
}
/* PROM is using fb console, but we have no driver for it. */
printf("No supported console device in slot %d. ", crt);
printf("Trying serial console.\n");
} else {
/*
* If we found a keyboard and framebuffer, wire it up
* as an rcons device even if it's not the OS console.
*/
}
/* Otherwise, try a serial port as console. */
if (find_serial(kbd)) {
cd.cn_pri = CN_REMOTE;
return;
}
/*
* Nothing worked. Revert to using PROM.
* Maybe some device will usurp the console during
* autoconfiguration.
*/
cd = promcd;
printf("No driver for console device, using prom for console I/O.\n");
return;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: autoconf.c,v 1.27 1998/01/09 17:22:47 drochner Exp $ */
/* $NetBSD: autoconf.c,v 1.28 1998/03/24 08:39:02 jonathan Exp $ */
/*
* Copyright (c) 1988 University of Utah.
@ -43,7 +43,7 @@
*/
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.27 1998/01/09 17:22:47 drochner Exp $");
__KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.28 1998/03/24 08:39:02 jonathan Exp $");
/*
* Setup the system to run on the current machine.
@ -71,8 +71,6 @@ __KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.27 1998/01/09 17:22:47 drochner Exp $
void dumpconf __P((void)); /* XXX */
void xconsinit __P((void)); /* XXX console-init continuation */
#if 0
/*
* XXX system-dependent, should call through a pointer.
@ -140,17 +138,6 @@ configure()
if (config_rootfound("mainbus", "mainbus") == NULL)
panic("no mainbus found");
#if 0
printf("looking for non-PROM console driver\n");
#endif
xconsinit(); /* do kludged-up console init */
#ifdef DEBUG
if (cputype == DS_3MIN)
/*FIXME*/ printf("switched to non-PROM console\n");
#endif
initcpu();
#ifdef DEBUG

View File

@ -1,4 +1,4 @@
/* $NetBSD: machdep.c,v 1.106 1998/03/12 05:46:21 thorpej Exp $ */
/* $NetBSD: machdep.c,v 1.107 1998/03/24 08:39:02 jonathan Exp $ */
/*
* Copyright (c) 1988 University of Utah.
@ -43,7 +43,7 @@
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.106 1998/03/12 05:46:21 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.107 1998/03/24 08:39:02 jonathan Exp $");
/* from: Utah Hdr: machdep.c 1.63 91/04/24 */
@ -110,6 +110,7 @@ __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.106 1998/03/12 05:46:21 thorpej Exp $"
#include <pmax/pmax/pmaxtype.h>
#include <pmax/pmax/trap.h> /* mboard-specific interrupt fns */
#include <pmax/pmax/cons.h>
#include <pmax/dev/promiovar.h> /* prom console I/O vector */
#include "pm.h"
#include "cfb.h"
@ -123,7 +124,7 @@ __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.106 1998/03/12 05:46:21 thorpej Exp $"
extern struct consdev *cn_tab; /* Console I/O table... */
extern struct consdev cd;
/* the following is used externally (sysctl_hw) */
char machine[] = MACHINE; /* from <machine/param.h> */
@ -313,7 +314,7 @@ mach_init(argc, argv, code, cv)
}
/* Use PROM console output until we initialize a console driver. */
cn_tab = &cd;
cn_tab = &promcd;
/* check for direct boot from DS5000 PROM */
if (argc > 0 && strcmp(argv[0], "boot") == 0) {

View File

@ -1,4 +1,4 @@
/* $NetBSD: scc.c,v 1.38 1998/03/24 00:23:56 jonathan Exp $ */
/* $NetBSD: scc.c,v 1.39 1998/03/24 08:39:02 jonathan Exp $ */
/*
* Copyright (c) 1991,1990,1989,1994,1995,1996 Carnegie Mellon University
@ -66,7 +66,7 @@
*/
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: scc.c,v 1.38 1998/03/24 00:23:56 jonathan Exp $");
__KERNEL_RCSID(0, "$NetBSD: scc.c,v 1.39 1998/03/24 08:39:02 jonathan Exp $");
#ifdef alpha
#include "opt_dec_3000_300.h"
@ -151,7 +151,6 @@ extern void ttrstrt __P((void *));
#if NRASTERCONSOLE > 0
#define HAVE_RCONS
#endif
extern int pending_remcons;
#endif
/*
@ -167,30 +166,14 @@ extern int pending_remcons;
#define RASTER_CONSOLE() 1 /* Treat test for cn_screen as true */
#endif
/*
* Is there a framebuffer console device using this serial driver?
* XXX used for ugly special-cased console input that should be redone
* more cleanly.
* Extract unit (scc chip), channel on chip, and dialin/dialout unit.
*/
#ifdef RCONS_BRAINDAMAGE
static inline int
raster_console(void)
{
#if 1
return (cn_tab->cn_pri == CN_NORMAL || cn_tab->cn_pri == CN_INTERNAL);
#else
register int israster =
(cn_tab->cn_pri == CN_NORMAL || cn_tab->cn_pri == CN_INTERNAL);
printf("israster: %d\n", israster);
return israster;
#endif
}
#endif
#define SCCUNIT(dev) (minor(dev) >> 1)
#define SCCUNIT(dev) ((minor(dev) & 0x7ffff) >> 1)
#define SCCLINE(dev) (minor(dev) & 0x1)
#define SCCDIALOUT(x) (minor(x) & 0x80000)
/* QVSS-compatible in-kernel X input event parser, pointer tracker */
void (*sccDivertXInput) __P((int cc)); /* X windows keyboard input routine */
@ -299,7 +282,12 @@ void scc_kbd_init __P((struct scc_softc *sc, dev_t dev));
void scc_mouse_init __P((struct scc_softc *sc, dev_t dev));
void scc_tty_init __P((struct scc_softc *sc, dev_t dev));
static void scc_txintr __P((struct scc_softc *, int, scc_regmap_t *));
static void scc_rxintr __P((struct scc_softc *, int, scc_regmap_t *, int));
inline
static void scc_stintr __P((struct scc_softc *, int, scc_regmap_t *, int));
int sccintr __P((void *));
#ifdef alpha
void scc_alphaintr __P((int));
#endif
@ -466,7 +454,10 @@ sccattach(parent, self, aux)
unit = sc->sc_dv.dv_unit;
#ifdef pmax
sccaddr = (void*)MIPS_PHYS_TO_KSEG1(d->iada_addr);
#endif
#ifdef SPARSE
sccaddr = (void *)TC_DENSE_TO_SPARSE((tc_addr_t)sccaddr);
#endif
@ -475,28 +466,25 @@ sccattach(parent, self, aux)
ioasic_intr_establish(parent, d->iada_cookie, TC_IPL_TTY,
sccintr, (void *)sc);
/* serial console debugging */
#if defined(DEBUG) && defined(HAVE_RCONS) && 0 /*XXX*/
if (CONSOLE_ON_UNIT(unit) && (cn_tab->cn_pri == CN_REMOTE)) {
DELAY(10000);
printf("(attached interrupt, delaying)\n");
#ifdef alpha
/*
* XXX
* If is the mandated remote console, point cn_tab at it now,
* to make later tests for console-ness MI.
*/
if ((cputype == ST_DEC_3000_500 && sc->sc_dv.dv_unit == 1) ||
(cputype == ST_DEC_3000_300 && sc->sc_dv.dv_unit == 0)) {
cn_tab->cn_dev = makedev(SCCDEV, sc->sc_dv.dv_unit * 2);
}
#endif /* defined(DEBUG) && defined(HAVE_RCONS)*/
#endif
/*
* For a remote console, wait a while for previous output to
* complete.
* If this is the console, wait a while for any previous
* output to complete.
*/
#ifdef pmax
if (CONSOLE_ON_UNIT(unit) && (cn_tab->cn_pri == CN_REMOTE))
if (CONSOLE_ON_UNIT(unit))
DELAY(10000);
#endif
#ifdef alpha
if ((cputype == ST_DEC_3000_500 && sc->sc_dv.dv_unit == 1) ||
(cputype == ST_DEC_3000_300 && sc->sc_dv.dv_unit == 0))
DELAY(10000);
#endif
pdp = &sc->scc_pdma[0];
/* init pseudo DMA structures */
@ -511,65 +499,42 @@ sccattach(parent, self, aux)
pdp++;
}
/* What's the warning here? Defaulting to softCAR on line 2? */
sc->scc_softCAR = sc->sc_dv.dv_cfdata->cf_flags | 0x2; /* XXX */
sc->scc_softCAR = sc->sc_dv.dv_cfdata->cf_flags;
/* reset chip, initialize register-copies in softc */
/*
* Reset chip, initialize register-copies in softc.
* XXX if this was console, no more printf()s until after
* scc_tty_init()!
*/
sccreset(sc);
/*
* Special handling for consoles.
*/
#ifdef pmax
if (pending_remcons) {
if (CONSOLE_ON_UNIT(unit)) {
/*
* We were using PROM callbacks for console I/O,
* and we just reset the chip under the console.
* wire up this driver as console ASAP.
*/
/*XXX*/ /* test for correct unit */
DELAY(10000);
/*
* XXX PROM and NetBSD unit numbers swapped
* on kn03, maybe kmin?
* And what about maxine?
*/
if (cn_tab->cn_dev == unit && cputype != DS_MAXINE) {
printf ("\n");
return;
}
/*
* If we are using the PROM serial-console routines
* as console, now is the time to set up the scc
* driver as console.
* Re-wire this unit up as console ASAP.
*/
cn_tab = &scccons;
cn_tab->cn_dev = makedev(SCCDEV,
sc->sc_dv.dv_unit == 0 ? SCCCOMM2_PORT : SCCCOMM3_PORT);
#ifdef notyet
scc_consinit(cn_tab->cn_dev, sccaddr);
#else
scc_tty_init(sc, cn_tab->cn_dev);
#endif
printf(" (In sccattach: cn_dev = 0x%x)", cn_tab->cn_dev);
printf(" (Unit = %d)", unit);
/* Wire carrier for console. */
sc->scc_softCAR |= SCCLINE(cn_tab->cn_dev);
scc_tty_init(sc, cn_tab->cn_dev);
DELAY(20000);
printf(": console");
pending_remcons = 0;
/*
* XXX We should support configurations where the PROM
* console device is a serial console, and a
* framebuffer, keyboard, and mouse are present.
*/
#ifdef BREAKS_X_WITH_REMOTE_CONSOLE
return;
#endif
}
#endif /* pmax */
printf("\n");
/* Wire up any childre, like keyboards or mice. */
#ifdef HAVE_RCONS
/* XXX test below may be too inclusive ? */
if (cputype != DS_MAXINE) {
if (unit == 1) {
scc_kbd_init(sc, makedev(SCCDEV, SCCKBD_PORT));
@ -579,31 +544,6 @@ sccattach(parent, self, aux)
}
#endif /* HAVE_RCONS */
#ifdef alpha
if (SCCUNIT(cn_tab->cn_dev) == unit) {
scc_tty_init(sc,
makedev(SCCDEV, (sc->sc_dv.dv_unit == 0 ?
SCCCOMM2_PORT : SCCCOMM3_PORT)));
}
/*
* XXX
* Unit 1 is the remote console, wire it up now.
*/
if ((cputype == ST_DEC_3000_500 && sc->sc_dv.dv_unit == 1) ||
(cputype == ST_DEC_3000_300 && sc->sc_dv.dv_unit == 0)) {
cn_tab = &scccons;
cn_tab->cn_dev = makedev(SCCDEV, sc->sc_dv.dv_unit * 2);
printf(": console\n");
/* wire carrier for console. */
sc->scc_softCAR |= SCCLINE(cn_tab->cn_dev);
} else
printf("\n");
#else /* pmax */
printf("\n");
#endif /* pmax */
}
@ -778,6 +718,11 @@ sccopen(dev, flag, mode, p)
if (!sc)
return (ENXIO);
#ifdef DEBUG_CARRIER
printf("sccopen: line %d %x, dialout %d\n",
major(dev), minor(dev), SCCDIALOUT(dev));
#endif /* DEBUG_CARRIER */
line = SCCLINE(dev);
if (sc->scc_pdma[line].p_addr == NULL)
return (ENXIO);
@ -789,6 +734,11 @@ sccopen(dev, flag, mode, p)
tp->t_oproc = sccstart;
tp->t_param = sccparam;
tp->t_dev = dev;
/*
* Do the following only for first opens.
*/
s = spltty();
if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) {
ttychars(tp);
#ifndef PORTSELECTOR
@ -806,10 +756,14 @@ sccopen(dev, flag, mode, p)
#endif
(void) sccparam(tp, &tp->t_termios);
ttsetwater(tp);
} else if ((tp->t_state & TS_XCLUDE) && curproc->p_ucred->cr_uid != 0)
return (EBUSY);
}
else if ((tp->t_state & TS_XCLUDE) && curproc->p_ucred->cr_uid != 0) {
error = EBUSY;
splx(s);
goto bad;
}
(void) sccmctl(dev, DML_DTR, DMSET);
s = spltty();
while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) &&
!(tp->t_state & TS_CARR_ON)) {
tp->t_wopen++;
@ -820,19 +774,21 @@ sccopen(dev, flag, mode, p)
break;
}
splx(s);
if (error)
return (error);
goto bad;
error = (*linesw[tp->t_line].l_open)(dev, tp);
#if defined(HAVE_RCONS) && defined(RCONS_BRAINDAMAGE)
/* handle raster console specially */
if (tp == scctty(makedev(SCCDEV,SCCKBD_PORT)) &&
raster_console() && firstopen) {
extern struct tty *fbconstty;
tp->t_winsize = fbconstty->t_winsize;
}
#endif /* old rcons brain-damage */
#ifdef DEBUG_CARRIER
printf("sccopen: ldisc open %d %x, dialout %d sez %d\n",
major(dev), minor(dev), SCCDIALOUT(dev), error);
#endif
if (error)
goto bad;
bad:
return (error);
}
@ -1151,6 +1107,143 @@ cold_sccparam(tp, t, sc)
}
/*
* transmission done interrupts
*/
static void
scc_txintr(sc, chan, regs)
struct scc_softc *sc;
int chan;
scc_regmap_t *regs;
{
register struct tty *tp = sc->scc_tty[chan];
register struct pdma *dp = &sc->scc_pdma[chan];
register int cc;
tp = sc->scc_tty[chan];
dp = &sc->scc_pdma[chan];
if (dp->p_mem < dp->p_end) {
SCC_WRITE_DATA(regs, chan, *dp->p_mem++);
#ifdef pmax /* Alpha handles the 1.6 msec settle time in hardware */
DELAY(2);
#endif
tc_mb();
} else {
tp->t_state &= ~TS_BUSY;
if (tp->t_state & TS_FLUSH)
tp->t_state &= ~TS_FLUSH;
else {
ndflush(&tp->t_outq, dp->p_mem -
(caddr_t) tp->t_outq.c_cf);
dp->p_end = dp->p_mem = tp->t_outq.c_cf;
}
if (tp->t_line)
(*linesw[tp->t_line].l_start)(tp);
else
sccstart(tp);
if (tp->t_outq.c_cc == 0 || !(tp->t_state & TS_BUSY)) {
SCC_READ_REG(regs, chan, SCC_RR15, cc);
cc &= ~ZSWR15_TXUEOM_IE;
SCC_WRITE_REG(regs, chan, SCC_WR15, cc);
cc = sc->scc_wreg[chan].wr1 & ~ZSWR1_TIE;
SCC_WRITE_REG(regs, chan, SCC_WR1, cc);
sc->scc_wreg[chan].wr1 = cc;
tc_mb();
}
}
}
/*
* receive interrupts
*/
static void
scc_rxintr(sc, chan, regs, unit)
struct scc_softc *sc;
int chan;
scc_regmap_t *regs;
int unit;
{
register struct tty *tp = sc->scc_tty[chan];
int cc, rr1 = 0, rr2 = 0; /* XXX */
SCC_READ_DATA(regs, chan, cc);
if (rr2 == SCC_RR2_A_RECV_SPECIAL ||
rr2 == SCC_RR2_B_RECV_SPECIAL) {
SCC_READ_REG(regs, chan, SCC_RR1, rr1);
SCC_WRITE_REG(regs, chan, SCC_RR0, ZSWR0_RESET_ERRORS);
if (rr1 & ZSRR1_DO) {
log(LOG_WARNING, "scc%d,%d: silo overflow\n",
unit >> 1, chan);
}
}
/*
* Keyboard needs special treatment.
*/
if (tp == scctty(makedev(SCCDEV, SCCKBD_PORT))) {
#if defined(DDB) && defined(LK_DO)
if (cc == LK_DO) {
spl0();
Debugger();
return;
}
#endif
#ifdef DEBUG
debugChar = cc;
#endif
if (sccDivertXInput) {
(*sccDivertXInput)(cc);
return;
}
#ifdef HAVE_RCONS
if ((cc = kbdMapChar(cc)) < 0)
return;
rcons_input(0, cc);
#endif
/*
* Now for mousey
*/
} else if (tp == scctty(makedev(SCCDEV, SCCMOUSE_PORT)) &&
sccMouseButtons) {
#ifdef HAVE_RCONS
/*XXX*/
mouseInput(cc);
#endif
return;
}
if (!(tp->t_state & TS_ISOPEN)) {
wakeup((caddr_t)&tp->t_rawq);
#ifdef PORTSELECTOR
if (!(tp->t_state & TS_WOPEN))
#endif
return;
}
if (rr2 == SCC_RR2_A_RECV_SPECIAL ||
rr2 == SCC_RR2_B_RECV_SPECIAL) {
if (rr1 & ZSRR1_PE)
cc |= TTY_PE;
if (rr1 & ZSRR1_FE)
cc |= TTY_FE;
}
(*linesw[tp->t_line].l_rint)(cc, tp);
}
/*
* Modem status interrupts
*/
static void inline
scc_stintr(sc, chan, regs, unit)
struct scc_softc *sc;
int chan;
scc_regmap_t *regs;
int unit;
{
SCC_WRITE_REG(regs, chan, SCC_RR0, ZSWR0_RESET_STATUS);
scc_modem_intr(unit | chan);
}
/*
* Check for interrupts from all devices.
*/
@ -1161,136 +1254,60 @@ sccintr(xxxsc)
register struct scc_softc *sc = (struct scc_softc *)xxxsc;
register int unit = (long)sc->sc_dv.dv_unit;
register scc_regmap_t *regs;
register struct tty *tp;
register struct pdma *dp;
register int cc, chan, rr1, rr2, rr3;
int overrun = 0;
register int rr3;
rr1 = 0; /* shut up gcc -Wall */
regs = (scc_regmap_t *)sc->scc_pdma[0].p_addr;
unit <<= 1;
for (;;) {
SCC_READ_REG(regs, SCC_CHANNEL_B, ZSRR_IVEC, rr2);
rr2 = SCC_RR2_STATUS(rr2);
/* are we done yet ? */
if (rr2 == 6) { /* strange, distinguished value */
SCC_READ_REG(regs, SCC_CHANNEL_A, ZSRR_IPEND, rr3);
if (rr3 == 0)
return 0 ;/* XXX FIXME why ? */
}
SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_RR0, ZSWR0_CLR_INTR);
if ((rr2 == SCC_RR2_A_XMIT_DONE) || (rr2 == SCC_RR2_B_XMIT_DONE)) {
chan = (rr2 == SCC_RR2_A_XMIT_DONE) ?
SCC_CHANNEL_A : SCC_CHANNEL_B;
tp = sc->scc_tty[chan];
dp = &sc->scc_pdma[chan];
if (dp->p_mem < dp->p_end) {
SCC_WRITE_DATA(regs, chan, *dp->p_mem++);
#ifdef pmax /* Alpha handles the 1.6 msec settle time in hardware */
DELAY(2);
#endif
tc_mb();
} else {
tp->t_state &= ~TS_BUSY;
if (tp->t_state & TS_FLUSH)
tp->t_state &= ~TS_FLUSH;
else {
ndflush(&tp->t_outq, dp->p_mem -
(caddr_t) tp->t_outq.c_cf);
dp->p_end = dp->p_mem = tp->t_outq.c_cf;
}
if (tp->t_line)
(*linesw[tp->t_line].l_start)(tp);
else
sccstart(tp);
if (tp->t_outq.c_cc == 0 || !(tp->t_state & TS_BUSY)) {
SCC_READ_REG(regs, chan, SCC_RR15, cc);
cc &= ~ZSWR15_TXUEOM_IE;
SCC_WRITE_REG(regs, chan, SCC_WR15, cc);
cc = sc->scc_wreg[chan].wr1 & ~ZSWR1_TIE;
SCC_WRITE_REG(regs, chan, SCC_WR1, cc);
sc->scc_wreg[chan].wr1 = cc;
tc_mb();
}
}
} else if (rr2 == SCC_RR2_A_RECV_DONE ||
rr2 == SCC_RR2_B_RECV_DONE || rr2 == SCC_RR2_A_RECV_SPECIAL ||
rr2 == SCC_RR2_B_RECV_SPECIAL) {
if (rr2 == SCC_RR2_A_RECV_DONE || rr2 == SCC_RR2_A_RECV_SPECIAL)
chan = SCC_CHANNEL_A;
else
chan = SCC_CHANNEL_B;
tp = sc->scc_tty[chan];
SCC_READ_DATA(regs, chan, cc);
if (rr2 == SCC_RR2_A_RECV_SPECIAL ||
rr2 == SCC_RR2_B_RECV_SPECIAL) {
SCC_READ_REG(regs, chan, SCC_RR1, rr1);
SCC_WRITE_REG(regs, chan, SCC_RR0, ZSWR0_RESET_ERRORS);
if ((rr1 & ZSRR1_DO) && overrun == 0) {
log(LOG_WARNING, "scc%d,%d: silo overflow\n",
unit >> 1, chan);
overrun = 1;
}
/* Note: only channel A has an RR3 */
SCC_READ_REG(regs, SCC_CHANNEL_A, ZSRR_IPEND, rr3);
/*
* Clear interrupt first to avoid a race condition.
* If a new interrupt condition happens while we are
* servicing this one, we will get another interrupt
* shortly. We can NOT just sit here in a loop, or
* we will cause horrible latency for other devices
* on this interrupt level (i.e. sun3x floppy disk).
*/
/*
* At elast some, maybe all DECstation chips have modem
* leads crosswired: the data comes in one channel and the
* bulkead modem signals for that port are wired to the
* _other_ channel of the chip. Yes, really.
* This code cannot get that right.
*/
/* First look at channel A. */
if (rr3 & (ZSRR3_IP_A_RX | ZSRR3_IP_A_TX | ZSRR3_IP_A_STAT)) {
SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_RR0, ZSWR0_CLR_INTR);
if (rr3 & ZSRR3_IP_A_RX)
scc_rxintr(sc, SCC_CHANNEL_A, regs, unit);
if (rr3 & ZSRR3_IP_A_STAT) {
/* XXX swapped channels */
scc_stintr(sc, SCC_CHANNEL_A, regs, unit);
}
/*
* Keyboard needs special treatment.
*/
if (tp == scctty(makedev(SCCDEV, SCCKBD_PORT))) {
#if defined(DDB) && defined(LK_DO)
if (cc == LK_DO) {
spl0();
Debugger();
return -1;
}
#endif
#ifdef DEBUG
debugChar = cc;
#endif
if (sccDivertXInput) {
(*sccDivertXInput)(cc);
continue;
}
#ifdef HAVE_RCONS
if ((cc = kbdMapChar(cc)) < 0)
continue;
rcons_input(0, cc);
#endif
/*
* Now for mousey
*/
} else if (tp == scctty(makedev(SCCDEV, SCCMOUSE_PORT)) &&
sccMouseButtons) {
#ifdef HAVE_RCONS
/*XXX*/
mouseInput(cc);
#endif
continue;
}
if (!(tp->t_state & TS_ISOPEN)) {
wakeup((caddr_t)&tp->t_rawq);
#ifdef PORTSELECTOR
if (tp->t_wopen == 0)
#endif
continue;
}
if (rr2 == SCC_RR2_A_RECV_SPECIAL ||
rr2 == SCC_RR2_B_RECV_SPECIAL) {
if (rr1 & ZSRR1_PE)
cc |= TTY_PE;
if (rr1 & ZSRR1_FE)
cc |= TTY_FE;
}
(*linesw[tp->t_line].l_rint)(cc, tp);
} else if ((rr2 == SCC_RR2_A_EXT_STATUS) || (rr2 == SCC_RR2_B_EXT_STATUS)) {
chan = (rr2 == SCC_RR2_A_EXT_STATUS) ?
SCC_CHANNEL_A : SCC_CHANNEL_B;
SCC_WRITE_REG(regs, chan, SCC_RR0, ZSWR0_RESET_STATUS);
scc_modem_intr(unit | chan);
}
if (rr3 & ZSRR3_IP_A_TX)
scc_txintr(sc, SCC_CHANNEL_A, regs);
}
/* Now look at channel B. */
if (rr3 & (ZSRR3_IP_B_RX | ZSRR3_IP_B_TX | ZSRR3_IP_B_STAT)) {
SCC_WRITE_REG(regs, SCC_CHANNEL_B, SCC_RR0, ZSWR0_CLR_INTR);
if (rr3 & ZSRR3_IP_B_RX)
scc_rxintr(sc, SCC_CHANNEL_B, regs, unit);
if (rr3 & ZSRR3_IP_B_STAT) {
/* XXX swapped channels */
scc_stintr(sc, SCC_CHANNEL_B, regs, unit);
}
if (rr3 & ZSRR3_IP_B_TX)
scc_txintr(sc, SCC_CHANNEL_B, regs);
}
return 1;
}
void
@ -1320,28 +1337,6 @@ sccstart(tp)
if (tp->t_outq.c_cc == 0)
goto out;
#ifdef RCONS_BRAINDAMAGE
/* handle console specially */
/* XXX raster console output via serial port! */
if (tp == scctty(makedev(SCCDEV,SCCKBD_PORT)) && raster_console()) {
while (tp->t_outq.c_cc > 0) {
cc = getc(&tp->t_outq) & 0x7f;
cnputc(cc);
}
/*
* After we flush the output queue we may need to wake
* up the process that made the output.
*/
if (tp->t_outq.c_cc <= tp->t_lowat) {
if (tp->t_state & TS_ASLEEP) {
tp->t_state &= ~TS_ASLEEP;
wakeup((caddr_t)&tp->t_outq);
}
selwakeup(&tp->t_wsel);
}
goto out;
}
#endif
cc = ndqb(&tp->t_outq, 0);
tp->t_state |= TS_BUSY;
@ -1478,11 +1473,24 @@ scc_modem_intr(dev)
sc = scc_cd.cd_devs[SCCUNIT(dev)];
tp = sc->scc_tty[chan];
regs = (scc_regmap_t *)sc->scc_pdma[chan].p_addr;
if (chan == SCC_CHANNEL_A)
return;
s = spltty();
if (chan == SCC_CHANNEL_A) {
#ifdef DEBUG_CARRIER
printf("scc_modem_intr: line %d,%d nomodem!\n",
SCCUNIT(dev), SCCLINE(dev));
#endif
return;
}
s = spltty();
SCC_READ_REG_ZERO(regs, chan, value);
#ifdef DEBUG_CARRIER
printf("scc_modem_intr: line %d,%d carrier %d softcar %d\n",
SCCUNIT(dev), SCCLINE(dev), value & ZSRR0_DCD,
sc->scc_softCAR & (1 << chan));
#endif
if (sc->scc_softCAR & (1 << chan))
car = 1;
else {
@ -1503,10 +1511,10 @@ scc_modem_intr(dev)
/*
* The pmax driver follows carrier-detect. The Alpha does not.
* On pmax, ignore hups on a console tty.
* On alpha, a no-op, for historical reasons. XXXXXX
* On alpha, a no-op, for historical reasons.
*/
#ifdef pmax
if (!CONSOLE_ON_UNIT(sc->sc_dv.dv_unit) && !pending_remcons) {
if (!CONSOLE_ON_UNIT(sc->sc_dv.dv_unit)) {
if (car) {
/* carrier present */
if (!(tp->t_state & TS_CARR_ON))