Revise console device handling:

* do not require a `zs' driver for console handling
	* run the console on PROM primitives until a device recognises
	  itself as a console device during normal autoconfiguration.
	* allow (keyboard) devices to take over the input channel of
	  the PROM primitive-based console device.

As a result, consinit() is much simplified and does no longer have
to "detect" devices to setup a working console device. This complexity
has moved to individual drivers which interpret the PROM information
after they have attached to decide whether or not to act as a console.
This commit is contained in:
pk 2000-03-19 13:22:14 +00:00
parent 08a1a0f49d
commit 41fb5989fe
2 changed files with 421 additions and 444 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: kd.c,v 1.6 2000/03/06 21:36:11 thorpej Exp $ */
/* $NetBSD: kd.c,v 1.7 2000/03/19 13:22:14 pk Exp $ */
/*-
* Copyright (c) 1996 The NetBSD Foundation, Inc.
@ -37,17 +37,18 @@
*/
/*
* Keyboard/Display device.
* Console driver based on PROM primitives.
*
* This driver exists simply to provide a tty device that
* the indirect console driver can point to.
* The kbd driver sends its input here.
* Output goes to the screen via PROM printf.
* This driver exists to provide a tty device that the indirect
* console driver can point to. It also provides a hook that
* allows another device to serve console input. This will normally
* be a keyboard driver (see sys/dev/sun/kbd.c)
*/
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/ioctl.h>
#include <sys/tty.h>
#include <sys/file.h>
@ -68,14 +69,14 @@
#include <machine/fbvar.h>
#endif
#include <dev/cons.h>
#include <dev/sun/kbd_xlate.h>
#include <sparc/dev/cons.h>
#include <dev/sun/event_var.h>
#include <dev/sun/kbd_xlate.h>
#include <dev/sun/kbdvar.h>
struct tty *fbconstty = 0; /* tty structure for frame buffer console */
int cnrom __P((void));
void cnrint __P((void));
#define KDMAJOR 1
#define PUT_WSIZE 64
@ -84,6 +85,9 @@ struct kd_softc {
struct device kd_dev; /* required first: base device */
struct tty *kd_tty;
int rows, cols;
/* Console input hook */
struct cons_channel *kd_in;
};
/*
@ -91,94 +95,73 @@ struct kd_softc {
* more than one keyboard/display device.
*/
static struct kd_softc kd_softc;
static int kd_is_console;
static int kdparam(struct tty *, struct termios *);
static void kdstart(struct tty *);
static void kd_init __P((struct kd_softc *));
static void kd_cons_input __P((int));
int rom_console_input; /* when set, hardclock calls cnrom() */
int cons_ocount; /* output byte count */
/* Now talking directly to the zs, so this is not needed. */
int
cnrom()
{
return (0);
}
void
cnrint()
{
}
/*
* This is called by kbd_attach()
* XXX - Make this a proper child of kbd?
* Prepare the console tty; called on first open of /dev/console
*/
void
kd_init(unit)
int unit;
{
kd_init(kd)
struct kd_softc *kd;
{
struct tty *tp;
if (unit != 0)
return;
kd = &kd_softc; /* XXX */
tp = ttymalloc();
tp->t_oproc = kdstart;
tp->t_param = kdparam;
tp->t_dev = makedev(KDMAJOR, unit);
#if 1 /* XXX - Why? */
clalloc(&tp->t_rawq, 1024, 1);
clalloc(&tp->t_canq, 1024, 1);
/* output queue doesn't need quoting */
clalloc(&tp->t_outq, 1024, 0);
#endif
tp->t_dev = makedev(KDMAJOR, 0);
tty_attach(tp);
kd->kd_tty = tp;
/*
* get the console struct winsize.
* Get the console struct winsize.
*/
if (kd_is_console) {
fbconstty = tp;
#ifdef RASTERCONSOLE
kd->rows = fbrcons_rows();
kd->cols = fbrcons_cols();
/* If the raster console driver is attached, copy its size */
kd->rows = fbrcons_rows();
kd->cols = fbrcons_cols();
#endif
}
if (CPU_ISSUN4COR4M) {
int i;
char *prop;
/* else, consult the PROM */
switch (prom_version()) {
char *prop;
struct eeprom *ep;
case PROM_OLDMON:
if ((ep = (struct eeprom *)eeprom_va) == NULL)
break;
if (kd->rows == 0)
kd->rows = (u_short)ep->eeTtyRows;
if (kd->cols == 0)
kd->cols = (u_short)ep->eeTtyCols;
break;
case PROM_OBP_V0:
case PROM_OBP_V2:
case PROM_OBP_V3:
case PROM_OPENFIRM:
if (kd->rows == 0 &&
(prop = getpropstring(optionsnode, "screen-#rows"))) {
i = 0;
int i = 0;
while (*prop != '\0')
i = i * 10 + *prop++ - '0';
kd->rows = (unsigned short)i;
}
if (kd->cols == 0 &&
(prop = getpropstring(optionsnode, "screen-#columns"))) {
i = 0;
int i = 0;
while (*prop != '\0')
i = i * 10 + *prop++ - '0';
kd->cols = (unsigned short)i;
}
}
if (CPU_ISSUN4) {
struct eeprom *ep = (struct eeprom *)eeprom_va;
if (ep) {
if (kd->rows == 0)
kd->rows = (u_short)ep->eeTtyRows;
if (kd->cols == 0)
kd->cols = (u_short)ep->eeTtyCols;
}
break;
}
return;
@ -203,20 +186,20 @@ kdopen(dev, flag, mode, p)
struct kd_softc *kd;
int error, s, unit;
struct tty *tp;
static int firstopen = 1;
unit = minor(dev);
if (unit != 0)
return ENXIO;
kd = &kd_softc; /* XXX */
tp = kd->kd_tty;
if ((error = kbd_iopen(unit)) != 0) {
#ifdef DIAGNOSTIC
printf("kd: kbd_iopen, error=%d\n", error);
#endif
return (error);
kd = &kd_softc; /* XXX */
if (firstopen) {
kd_init(kd);
firstopen = 0;
}
tp = kd->kd_tty;
/* It's simpler to do this up here. */
if (((tp->t_state & (TS_ISOPEN | TS_XCLUDE))
== (TS_ISOPEN | TS_XCLUDE))
@ -226,9 +209,16 @@ kdopen(dev, flag, mode, p)
}
s = spltty();
if ((tp->t_state & TS_ISOPEN) == 0) {
/* First open. */
/* Notify the input device that serves us */
struct cons_channel *cc = kd->kd_in;
if (cc != NULL &&
(error = (*cc->cc_iopen)(cc)) != 0) {
return (error);
}
ttychars(tp);
tp->t_iflag = TTYDEF_IFLAG;
tp->t_oflag = TTYDEF_OFLAG;
@ -257,6 +247,7 @@ kdclose(dev, flag, mode, p)
{
struct kd_softc *kd;
struct tty *tp;
struct cons_channel *cc;
kd = &kd_softc; /* XXX */
tp = kd->kd_tty;
@ -267,6 +258,10 @@ kdclose(dev, flag, mode, p)
(*linesw[tp->t_line].l_close)(tp, flag);
ttyclose(tp);
if ((cc = kd->kd_in) != NULL)
(void)(*cc->cc_iclose)(cc->cc_dev);
return (0);
}
@ -359,7 +354,7 @@ kdstart(tp)
struct tty *tp;
{
struct clist *cl;
register int s;
int s;
s = spltty();
if (tp->t_state & (TS_BUSY|TS_TTSTOP|TS_TIMEOUT))
@ -367,26 +362,16 @@ kdstart(tp)
cl = &tp->t_outq;
if (cl->c_cc) {
if (kd_is_console) {
tp->t_state |= TS_BUSY;
if ((s & PSR_PIL) == 0) {
/* called at level zero - update screen now. */
(void) spllowersoftclock();
kd_putfb(tp);
(void) spltty();
tp->t_state &= ~TS_BUSY;
} else {
/* called at interrupt level - do it later */
timeout(kd_later, (void*)tp, 0);
}
tp->t_state |= TS_BUSY;
if ((s & PSR_PIL) == 0) {
/* called at level zero - update screen now. */
(void) spllowersoftclock();
kd_putfb(tp);
(void) spltty();
tp->t_state &= ~TS_BUSY;
} else {
/*
* This driver uses the PROM for writing the screen,
* and that only works if this is the console device.
* If this is not the console, just flush the output.
* Sorry. (In that case, use xdm instead of getty.)
*/
ndflush(cl, cl->c_cc);
/* called at interrupt level - do it later */
timeout(kd_later, (void*)tp, 0);
}
}
if (cl->c_cc <= tp->t_lowat) {
@ -405,11 +390,11 @@ out:
* Called at splsoftclock when requested by kdstart.
*/
static void
kd_later(tpaddr)
void *tpaddr;
kd_later(arg)
void *arg;
{
struct tty *tp = tpaddr;
register int s;
struct tty *tp = arg;
int s;
kd_putfb(tp);
@ -450,7 +435,7 @@ kd_putfb(tp)
* the keyboard driver (dev/sun/kbd.c) at spltty.
*/
void
kd_input(c)
kd_cons_input(c)
int c;
{
struct kd_softc *kd = &kd_softc;
@ -466,97 +451,149 @@ kd_input(c)
(*linesw[tp->t_line].l_rint)(c, tp);
}
void
cons_attach_input(cc)
struct cons_channel *cc;
{
struct kd_softc *kd = &kd_softc;
/****************************************************************
* kd console support
****************************************************************/
kd->kd_in = cc;
cc->cc_upstream = kd_cons_input;
}
/* The debugger gets its own key translation state. */
static struct kbd_state kdcn_state;
static void kdcnprobe __P((struct consdev *));
static void kdcninit __P((struct consdev *));
static int kdcngetc __P((dev_t));
static void kdcnputc __P((dev_t, int));
static void kdcnpollc __P((dev_t, int));
/*
* Default PROM-based console input stream
* Since the PROM does not notify us when data is available on the
* input channel these functions periodically poll the PROM.
*/
static int kd_rom_iopen __P((struct cons_channel *));
static int kd_rom_iclose __P((struct cons_channel *));
static void kd_rom_intr __P((void *));
struct consdev consdev_kd = {
kdcnprobe,
kdcninit,
kdcngetc,
kdcnputc,
kdcnpollc,
static struct cons_channel prom_cons_channel;
int
kd_rom_iopen(cc)
struct cons_channel *cc;
{
/* Poll for ROM input 4 times per second */
timeout(kd_rom_intr, cc, hz/4);
return (0);
}
int
kd_rom_iclose(cc)
struct cons_channel *cc;
{
untimeout(kd_rom_intr, cc);
return (0);
}
/*
* "Interrupt" routine for input through ROM vectors
*/
void
kd_rom_intr(arg)
void *arg;
{
struct cons_channel *cc = arg;
int s, c;
/* Re-schedule */
timeout(kd_rom_intr, arg, hz/4);
s = spltty();
while ((c = prom_peekchar()) >= 0)
(*cc->cc_upstream)(c);
splx(s);
}
/*****************************************************************/
int prom_stdin_node;
int prom_stdout_node;
char prom_stdin_args[16];
char prom_stdout_args[16];
extern void prom_cnprobe __P((struct consdev *));
static void prom_cninit __P((struct consdev *));
static int prom_cngetc __P((dev_t));
static void prom_cnputc __P((dev_t, int));
extern void prom_cnpollc __P((dev_t, int));
/*
* The console is set to this one initially,
* which lets us use the PROM until consinit()
* is called to select a real console.
*/
struct consdev consdev_prom = {
prom_cnprobe,
prom_cninit,
prom_cngetc,
prom_cnputc,
prom_cnpollc,
NULL,
};
/* We never call this. */
static void
kdcnprobe(cn)
/*
* The console table pointer is statically initialized
* to point to the PROM table, so that early calls to printf will work.
*/
struct consdev *cn_tab = &consdev_prom;
void
prom_cnprobe(cn)
struct consdev *cn;
{
}
static void
kdcninit(cn)
prom_cninit(cn)
struct consdev *cn;
{
struct kbd_state *ks = &kdcn_state;
cn->cn_dev = makedev(KDMAJOR, 0);
cn->cn_pri = CN_INTERNAL;
/* This prepares kbd_translate() */
ks->kbd_id = KBD_MIN_TYPE;
kbd_xlate_init(ks);
/* Indicate that it is OK to use the PROM fbwrite */
kd_is_console = 1;
}
void
prom_cnpollc(dev, on)
dev_t dev;
int on;
{
if (on) {
/* Entering debugger. */
#if NFB > 0
fb_unblank();
#endif
} else {
/* Resuming kernel. */
}
}
/*
* PROM console input putchar.
*/
static int
kdcngetc(dev)
prom_cngetc(dev)
dev_t dev;
{
struct kbd_state *ks = &kdcn_state;
int code, class, data, keysym;
int s, c;
for (;;) {
code = zs_getc(zs_conschan);
keysym = kbd_code_to_keysym(ks, code);
class = KEYSYM_CLASS(keysym);
switch (class) {
case KEYSYM_ASCII:
goto out;
case KEYSYM_CLRMOD:
case KEYSYM_SETMOD:
data = (keysym & 0x1F);
/* Only allow ctrl or shift. */
if (data > KBMOD_SHIFT_R)
break;
data = 1 << data;
if (class == KEYSYM_SETMOD)
ks->kbd_modbits |= data;
else
ks->kbd_modbits &= ~data;
break;
case KEYSYM_ALL_UP:
/* No toggle keys here. */
ks->kbd_modbits = 0;
break;
default: /* ignore all other keysyms */
break;
}
}
out:
return (keysym);
s = splhigh();
c = prom_getchar();
splx(s);
return (c);
}
/*
* PROM console output putchar.
*/
static void
kdcnputc(dev, c)
prom_cnputc(dev, c)
dev_t dev;
int c;
{
@ -564,22 +601,93 @@ kdcnputc(dev, c)
prom_putchar(c);
}
static void
kdcnpollc(dev, on)
dev_t dev;
int on;
{
struct kbd_state *ks = &kdcn_state;
if (on) {
/* Entering debugger. */
#if NFB > 0
fb_unblank();
#endif
/* Clear shift keys too. */
ks->kbd_modbits = 0;
} else {
/* Resuming kernel. */
/*****************************************************************/
static void prom_get_device_args __P((const char *, char *, unsigned int));
void
prom_get_device_args(prop, args, sz)
const char *prop;
char *args;
unsigned int sz;
{
char *cp, buffer[128];
cp = getpropstringA(findroot(), (char *)prop, buffer, sizeof buffer);
/*
* Extract device-specific arguments from a PROM device path (if any)
*/
cp = buffer + strlen(buffer);
while (cp >= buffer) {
if (*cp == ':') {
strncpy(args, cp+1, sz);
break;
}
cp--;
}
}
/*
*
*/
void
consinit()
{
int inSource, outSink;
switch (prom_version()) {
case PROM_OLDMON:
case PROM_OBP_V0:
/* The stdio handles identify the device type */
inSource = prom_stdin();
outSink = prom_stdout();
break;
case PROM_OBP_V2:
case PROM_OBP_V3:
case PROM_OPENFIRM:
/* Save PROM arguments for device matching */
prom_get_device_args("stdin-path", prom_stdin_args,
sizeof(prom_stdin_args));
prom_get_device_args("stdout-path", prom_stdout_args,
sizeof(prom_stdout_args));
/*
* Translate the STDIO package instance (`ihandle') -- that
* the PROM has already opened for us -- to a device tree
* node (i.e. a `phandle').
*/
prom_stdin_node = prom_instance_to_package(prom_stdin());
if (prom_stdin_node == 0)
printf("consinit: cannot convert stdin ihandle\n");
prom_stdout_node = prom_instance_to_package(prom_stdout());
if (prom_stdout_node == 0) {
printf("consinit: cannot convert stdout ihandle\n");
break;
}
break;
default:
break;
}
/* Wire up /dev/console */
cn_tab->cn_dev = makedev(KDMAJOR, 0);
cn_tab->cn_pri = CN_INTERNAL;
/* Set up initial PROM input channel for /dev/console */
prom_cons_channel.cc_dev = NULL;
prom_cons_channel.cc_iopen = kd_rom_iopen;
prom_cons_channel.cc_iclose = kd_rom_iclose;
cons_attach_input(&prom_cons_channel);
#ifdef KGDB
zs_kgdb_init(); /* XXX */
#endif
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: zs.c,v 1.75 2000/03/14 21:20:51 jdc Exp $ */
/* $NetBSD: zs.c,v 1.76 2000/03/19 13:22:14 pk Exp $ */
/*-
* Copyright (c) 1996 The NetBSD Foundation, Inc.
@ -125,7 +125,7 @@ struct zsdevice {
};
/* ZS channel used as the console device (if any) */
void *zs_conschan;
void *zs_conschan_get, *zs_conschan_put;
/* Default speed for each channel */
static int zs_defspeed[NZS][2] = {
@ -156,6 +156,20 @@ static u_char zs_init_reg[16] = {
ZSWR15_BREAK_IE,
};
/* Console ops */
static int zscngetc __P((dev_t));
static void zscnputc __P((dev_t, int));
static void zscnpollc __P((dev_t, int));
struct consdev zs_consdev = {
NULL,
NULL,
zscngetc,
zscnputc,
zscnpollc,
NULL,
};
/****************************************************************
* Autoconfig
@ -167,6 +181,7 @@ static int zs_match_obio __P((struct device *, struct cfdata *, void *));
static void zs_attach_mainbus __P((struct device *, struct device *, void *));
static void zs_attach_obio __P((struct device *, struct device *, void *));
static void zs_attach __P((struct zsc_softc *, struct zsdevice *, int));
static int zs_print __P((void *, const char *name));
@ -187,6 +202,9 @@ static struct intrhand levelsoft = { zssoft };
static int zs_get_speed __P((struct zs_chanstate *));
/* Console device support */
static int zs_console_flags __P((int, int, int));
/* Power management hooks */
int zs_enable __P((struct zs_chanstate *));
void zs_disable __P((struct zs_chanstate *));
@ -243,6 +261,8 @@ zs_attach_mainbus(parent, self, aux)
zsc->zsc_bustag = ma->ma_bustag;
zsc->zsc_dmatag = ma->ma_dmatag;
zsc->zsc_promunit = getpropint(ma->ma_node, "slave", -2);
zsc->zsc_node = ma->ma_node;
/*
* For machines with zs on mainbus (all sun4c models), we expect
@ -306,16 +326,19 @@ zs_attach_obio(parent, self, aux)
zsc->zsc_bustag = sa->sa_bustag;
zsc->zsc_dmatag = sa->sa_dmatag;
zsc->zsc_promunit = getpropint(sa->sa_node, "slave", -2);
zsc->zsc_node = sa->sa_node;
zs_attach(zsc, va, sa->sa_pri);
} else {
struct obio4_attach_args *oba = &uoba->uoba_oba4;
bus_space_handle_t bh;
bus_addr_t paddr = oba->oba_paddr;
/*
* As for zs on mainbus, we require a PROM mapping.
*/
if (bus_space_map(oba->oba_bustag,
oba->oba_paddr,
paddr,
sizeof(struct zsdevice),
BUS_SPACE_MAP_LINEAR | OBIO_BUS_MAP_USE_ROM,
&bh) != 0) {
@ -324,6 +347,12 @@ zs_attach_obio(parent, self, aux)
}
zsc->zsc_bustag = oba->oba_bustag;
zsc->zsc_dmatag = oba->oba_dmatag;
/* Find prom unit by physical address */
zsc->zsc_promunit =
(paddr == 0xf1000000) ? 0 :
(paddr == 0xf0000000) ? 1 :
(paddr == 0xe0000000) ? 2 : -2;
zs_attach(zsc, (void *)bh, oba->oba_pri);
}
}
@ -341,7 +370,7 @@ zs_attach(zsc, zsd, pri)
{
struct zsc_attach_args zsc_args;
struct zs_chanstate *cs;
int s, zs_unit, channel;
int s, channel;
static int didintr, prevpri;
if (zsd == NULL) {
@ -354,12 +383,10 @@ zs_attach(zsc, zsd, pri)
/*
* Initialize software state for each channel.
*/
zs_unit = zsc->zsc_dev.dv_unit;
for (channel = 0; channel < 2; channel++) {
volatile struct zschan *zc;
struct zschan *zc;
zsc_args.channel = channel;
zsc_args.hwflags = 0;
cs = &zsc->zsc_cs_store[channel];
zsc->zsc_cs[channel] = cs;
@ -369,8 +396,23 @@ zs_attach(zsc, zsd, pri)
cs->cs_brg_clk = PCLK / 16;
zc = (channel == 0) ? &zsd->zs_chan_a : &zsd->zs_chan_b;
if (zc == zs_conschan)
zsc_args.hwflags |= ZS_HWFLAG_CONSOLE;
zsc_args.hwflags = zs_console_flags(zsc->zsc_promunit,
zsc->zsc_node,
channel);
if (zsc_args.hwflags & ZS_HWFLAG_CONSOLE) {
zsc_args.hwflags |= ZS_HWFLAG_USE_CONSDEV;
zsc_args.consdev = &zs_consdev;
}
if ((zsc_args.hwflags & ZS_HWFLAG_CONSOLE_INPUT) != 0) {
zs_conschan_get = zc;
}
if ((zsc_args.hwflags & ZS_HWFLAG_CONSOLE_OUTPUT) != 0) {
zs_conschan_put = zc;
}
/* Childs need to set cn_dev, etc */
cs->cs_reg_csr = &zc->zc_csr;
cs->cs_reg_data = &zc->zc_data;
@ -383,7 +425,7 @@ zs_attach(zsc, zsd, pri)
if (zsc_args.hwflags & ZS_HWFLAG_CONSOLE)
cs->cs_defspeed = zs_get_speed(cs);
else
cs->cs_defspeed = zs_defspeed[zs_unit][channel];
cs->cs_defspeed = zs_defspeed[zsc->zsc_promunit][channel];
cs->cs_defcflag = zs_def_cflag;
/* Make these correspond to cs_defcflag (-crtscts) */
@ -449,7 +491,7 @@ zs_attach(zsc, zsd, pri)
* lower interrupts just enough to let zs interrupts in.
* This is done after both zs devices are attached.
*/
if (zs_unit == 1) {
if (zsc->zsc_promunit == 1) {
printf("zs1: enabling zs interrupts\n");
(void)splfd(); /* XXX: splzs - 1 */
}
@ -482,11 +524,13 @@ static int
zshard(arg)
void *arg;
{
register struct zsc_softc *zsc;
register int unit, rr3, rval, softreq;
struct zsc_softc *zsc;
int unit, rr3, rval, softreq;
rval = softreq = 0;
for (unit = 0; unit < zs_cd.cd_ndevs; unit++) {
struct zs_chanstate *cs;
zsc = zs_cd.cd_devs[unit];
if (zsc == NULL)
continue;
@ -496,8 +540,10 @@ zshard(arg)
rval |= rr3;
zsc->zsc_intrcnt.ev_count++;
}
softreq |= zsc->zsc_cs[0]->cs_softreq;
softreq |= zsc->zsc_cs[1]->cs_softreq;
if ((cs = zsc->zsc_cs[0]) != NULL)
softreq |= cs->cs_softreq;
if ((cs = zsc->zsc_cs[1]) != NULL)
softreq |= cs->cs_softreq;
}
/* We are at splzs here, so no need to lock. */
@ -520,8 +566,8 @@ static int
zssoft(arg)
void *arg;
{
register struct zsc_softc *zsc;
register int s, unit;
struct zsc_softc *zsc;
int s, unit;
/* This is not the only ISR on this IPL. */
if (zssoftpending == 0)
@ -678,14 +724,15 @@ u_char
zs_read_csr(cs)
struct zs_chanstate *cs;
{
register u_char val;
u_char val;
val = *cs->cs_reg_csr;
ZS_DELAY();
return (val);
}
void zs_write_csr(cs, val)
void
zs_write_csr(cs, val)
struct zs_chanstate *cs;
u_char val;
{
@ -693,10 +740,11 @@ void zs_write_csr(cs, val)
ZS_DELAY();
}
u_char zs_read_data(cs)
u_char
zs_read_data(cs)
struct zs_chanstate *cs;
{
register u_char val;
u_char val;
val = *cs->cs_reg_data;
ZS_DELAY();
@ -725,7 +773,7 @@ void
zs_abort(cs)
struct zs_chanstate *cs;
{
register volatile struct zschan *zc = zs_conschan;
struct zschan *zc = zs_conschan_get;
int rr0;
/* Wait for end of break to avoid PROM abort. */
@ -745,6 +793,9 @@ zs_abort(cs)
#endif
}
static int zs_getc __P((void *arg));
static void zs_putc __P((void *arg, int c));
/*
* Polled input char.
*/
@ -752,8 +803,8 @@ int
zs_getc(arg)
void *arg;
{
register volatile struct zschan *zc = arg;
register int s, c, rr0;
struct zschan *zc = arg;
int s, c, rr0;
s = splhigh();
/* Wait for a character to arrive. */
@ -781,8 +832,8 @@ zs_putc(arg, c)
void *arg;
int c;
{
register volatile struct zschan *zc = arg;
register int s, rr0;
struct zschan *zc = arg;
int s, rr0;
s = splhigh();
@ -808,291 +859,109 @@ zs_putc(arg, c)
}
/*****************************************************************/
static void zscninit __P((struct consdev *));
static int zscngetc __P((dev_t));
static void zscnputc __P((dev_t, int));
/*
* Console table shared by ttya, ttyb
*/
struct consdev consdev_tty = {
nullcnprobe,
zscninit,
zscngetc,
zscnputc,
nullcnpollc,
NULL,
};
static void
zscninit(cn)
struct consdev *cn;
{
}
/*
* Polled console input putchar.
*/
static int
int
zscngetc(dev)
dev_t dev;
{
return (zs_getc(zs_conschan));
return (zs_getc(zs_conschan_get));
}
/*
* Polled console output putchar.
*/
static void
void
zscnputc(dev, c)
dev_t dev;
int c;
{
zs_putc(zs_conschan, c);
zs_putc(zs_conschan_put, c);
}
/*****************************************************************/
static void prom_cninit __P((struct consdev *));
static int prom_cngetc __P((dev_t));
static void prom_cnputc __P((dev_t, int));
/*
* The console is set to this one initially,
* which lets us use the PROM until consinit()
* is called to select a real console.
*/
struct consdev consdev_prom = {
nullcnprobe,
prom_cninit,
prom_cngetc,
prom_cnputc,
nullcnpollc,
};
/*
* The console table pointer is statically initialized
* to point to the PROM (output only) table, so that
* early calls to printf will work.
*/
struct consdev *cn_tab = &consdev_prom;
void
nullcnprobe(cn)
struct consdev *cn;
{
}
static void
prom_cninit(cn)
struct consdev *cn;
{
}
/*
* PROM console input putchar.
* (dummy - this is output only) (WHY?????!)
*/
static int
prom_cngetc(dev)
zscnpollc(dev, on)
dev_t dev;
int on;
{
return (prom_getchar());
/* No action needed */
}
/*
* PROM console output putchar.
*/
static void
prom_cnputc(dev, c)
dev_t dev;
int c;
{
prom_putchar(c);
}
/*****************************************************************/
extern struct consdev consdev_kd;
static char *prom_inSrc_name[] = {
"keyboard/display",
"ttya", "ttyb",
"ttyc", "ttyd" };
static int get_serial_promdev __P((int));
int
get_serial_promdev(io)
int io;
{
char *prop, *cp, buffer[128];
zs_console_flags(promunit, node, channel)
int promunit;
int node;
node = findroot();
prop = (io == 0) ? "stdin-path" : "stdout-path";
cp = getpropstringA(node, prop, buffer, sizeof buffer);
/*
* At this point we assume the device path is in the form
* ....device@x,y:a for ttya and ...device@x,y:b for ttyb, etc.
*/
if (cp[0] != '\0' && cp[1] != '\0') {
while (*cp != '\0')
cp++;
cp -= 2;
} else {
/*
* If don't have at least a 2 character string at cp, then
* we default to using using the string ":a" for ttya.
*/
cp[0] = ':';
cp[1] = 'a';
cp[2] = '\0';
}
if (cp >= buffer) {
/* XXX: only allows tty's a->z, assumes PROMDEV_TTYx contig */
if (cp[0] == ':' && cp[1] >= 'a' && cp[1] <= 'z')
return (PROMDEV_TTYA + (cp[1] - 'a'));
}
printf("Warning: unparseable %s property\n", prop);
return (-1);
}
/*
* This function replaces sys/dev/cninit.c
* Determine which device is the console using
* the PROM "input source" and "output sink".
*/
void
consinit()
int channel;
{
struct zschan *zc;
struct zsdevice *zsd;
struct consdev *cn;
int channel, promzs_unit, zstty_unit;
int inSource, outSink;
int node;
char *devtype;
extern int fbnode;
int cookie, flags = 0;
switch (prom_version()) {
case PROM_OLDMON:
case PROM_OBP_V0:
/* The stdio handles identify the device type */
inSource = prom_stdin();
outSink = prom_stdout();
/*
* Use `promunit' and `channel' to derive the PROM
* stdio handles that correspond to this device.
*/
if (promunit == 0)
cookie = PROMDEV_TTYA + channel;
else if (promunit == 1 && channel == 0)
cookie = PROMDEV_KBD;
else
cookie = -1;
if (cookie == prom_stdin())
flags |= ZS_HWFLAG_CONSOLE_INPUT;
/*
* Prevent the keyboard from matching the output device
* (note that PROMDEV_KBD == PROMDEV_SCREEN == 0!).
*/
if (cookie != PROMDEV_KBD && cookie == prom_stdout())
flags |= ZS_HWFLAG_CONSOLE_OUTPUT;
break;
case PROM_OBP_V2:
case PROM_OBP_V3:
case PROM_OPENFIRM:
/*
* We need to probe the PROM device tree.
*
* Translate the STDIO package instance (`ihandle') -- that
* the PROM has already opened for us -- to a device tree
* node (i.e. a `phandle').
* Match the nodes and device arguments prepared by
* consinit() against our device node and channel.
* (The device argument is the part of the OBP path
* following the colon, as in `/obio/zs@0,100000:a')
*/
if ((node = prom_instance_to_package(prom_stdin())) == 0) {
printf("consinit: cannot convert stdin ihandle\n");
inSource = -1;
goto setup_output;
/* Default to channel 0 if there are no explicit prom args */
cookie = 0;
if (node == prom_stdin_node) {
if (prom_stdin_args[0] != '\0')
/* Translate (a,b) -> (0,1) */
cookie = prom_stdin_args[0] - 'a';
if (channel == cookie)
flags |= ZS_HWFLAG_CONSOLE_INPUT;
}
if (prom_node_has_property(node, "keyboard")) {
inSource = PROMDEV_KBD;
} else if (strcmp(getpropstring(node, "device_type"),
"serial") == 0) {
inSource = get_serial_promdev(0);
} else {
/* not serial, not keyboard. what is it?!? */
inSource = -1;
if (node == prom_stdout_node) {
if (prom_stdout_args[0] != '\0')
/* Translate (a,b) -> (0,1) */
cookie = prom_stdout_args[0] - 'a';
if (channel == cookie)
flags |= ZS_HWFLAG_CONSOLE_OUTPUT;
}
setup_output:
if ((node = prom_instance_to_package(prom_stdout())) == 0) {
printf("consinit: cannot convert stdout ihandle\n");
outSink = -1;
goto setup_console;
}
devtype = getpropstring(node, "device_type");
if (strcmp(devtype, "display") == 0) {
/* frame buffer output */
outSink = PROMDEV_SCREEN;
fbnode = node;
} else if (strcmp(devtype, "serial") == 0) {
outSink = get_serial_promdev(1);
} else {
/* not screen, not serial. Whatzit? */
outSink = -1;
}
break;
default:
inSource = -1;
outSink = -1;
}
setup_console:
if (inSource != outSink) {
printf("cninit: mismatched PROM output selector\n");
printf("inSource=%x; Sink=%x\n", inSource, outSink);
}
switch (inSource) {
default:
printf("cninit: invalid inSource=0x%x\n", inSource);
prom_abort();
inSource = PROMDEV_KBD;
/* fall through */
case 0: /* keyboard/display */
#if NKBD > 0
promzs_unit = 1; /* XXX - config info! */
channel = 0;
cn = &consdev_kd;
/* Set cn_dev, cn_pri in kd.c */
break;
#else /* NKBD */
printf("cninit: kdb/display not configured\n");
callrom();
inSource = PROMDEV_TTYA;
/* fall through */
#endif /* NKBD */
case PROMDEV_TTYA:
case PROMDEV_TTYB:
zstty_unit = inSource - PROMDEV_TTYA;
promzs_unit = 0; /* XXX - config info! */
channel = zstty_unit & 1;
cn = &consdev_tty;
cn->cn_dev = makedev(zs_major, zstty_unit);
cn->cn_pri = CN_REMOTE;
break;
}
/* Now that inSource has been validated, print it. */
printf("console is %s\n", prom_inSrc_name[inSource]);
zsd = findzs(promzs_unit);
if (zsd == NULL) {
printf("cninit: zs not mapped.\n");
return;
}
zc = (channel == 0) ? &zsd->zs_chan_a : &zsd->zs_chan_b;
zs_conschan = zc;
cn_tab = cn;
(*cn->cn_init)(cn);
#ifdef KGDB
zs_kgdb_init();
#endif
prom_printf("zs_console flags: %x\n", flags);
return (flags);
}
/*