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:
parent
08a1a0f49d
commit
41fb5989fe
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue