From 41fb5989fe61640e07ff305bd544c2e2dfd452da Mon Sep 17 00:00:00 2001 From: pk Date: Sun, 19 Mar 2000 13:22:14 +0000 Subject: [PATCH] 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. --- sys/arch/sparc/dev/kd.c | 466 +++++++++++++++++++++++++--------------- sys/arch/sparc/dev/zs.c | 399 ++++++++++++---------------------- 2 files changed, 421 insertions(+), 444 deletions(-) diff --git a/sys/arch/sparc/dev/kd.c b/sys/arch/sparc/dev/kd.c index 8f314e882a61..5d2421706532 100644 --- a/sys/arch/sparc/dev/kd.c +++ b/sys/arch/sparc/dev/kd.c @@ -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 #include #include +#include #include #include #include @@ -68,14 +69,14 @@ #include #endif - #include -#include #include +#include +#include +#include + 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 +} diff --git a/sys/arch/sparc/dev/zs.c b/sys/arch/sparc/dev/zs.c index 3a211c64c305..03f0596f7d29 100644 --- a/sys/arch/sparc/dev/zs.c +++ b/sys/arch/sparc/dev/zs.c @@ -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); } /*