diff --git a/sys/alpha/tlsb/zs_tlsb.c b/sys/alpha/tlsb/zs_tlsb.c index 2edf72f0660d..e14fa837e238 100644 --- a/sys/alpha/tlsb/zs_tlsb.c +++ b/sys/alpha/tlsb/zs_tlsb.c @@ -26,8 +26,8 @@ * $FreeBSD$ */ /* - * This driver is a hopeless hack to get the SimOS console working. A real - * driver would use the zs driver source from NetBSD. + * This driver is a somewhat hack. A real driver might use the zs driver + * source from NetBSD, except that it's no real winner either. */ #include "opt_ddb.h" @@ -45,7 +45,7 @@ #include #include -#include /* XXX */ +#include #include #include @@ -55,12 +55,14 @@ static int zsc_get_channel(device_t dev); static caddr_t zsc_get_base(device_t dev); struct zs_softc { - struct tty tty; + struct tty * tp; + device_t dev; int channel; caddr_t base; + struct callout_handle zst; }; #define ZS_SOFTC(unit) \ - ((struct zs_softc*)devclass_get_softc(zs_devclass, (unit))) + ((struct zs_softc *) devclass_get_softc(zs_devclass, (unit))) static d_open_t zsopen; static d_close_t zsclose; @@ -92,16 +94,6 @@ static void zsstop __P((struct tty *tp, int flag)); * Helpers for console support. */ -int zs_cngetc __P((dev_t)); -void zs_cnputc __P((dev_t, int)); - -struct consdev zs_cons = { - NULL, NULL, NULL, zs_cngetc, NULL, zs_cnputc, NULL, NULL, 0, CN_NORMAL -}; - -static caddr_t zs_console_addr; -static int zs_console; - static int zs_probe(device_t); static int zs_attach(device_t); @@ -119,6 +111,10 @@ static driver_t zs_driver = { "zs", zs_methods, sizeof (struct zs_softc), }; +static void zs_poll_intr __P((void *)); +static int zspolltime; + + static int zs_probe(device_t dev) { @@ -129,129 +125,159 @@ static int zs_attach(device_t dev) { struct zs_softc *sc = device_get_softc(dev); - + sc->dev = dev; sc->channel = zsc_get_channel(dev); sc->base = zsc_get_base(dev); - + make_dev(&zs_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, + "zs%d", device_get_unit(dev)); return 0; } static caddr_t zs_statusreg(caddr_t base, int chan) { - if (chan == 0) - return base + ZSC_CHANNELA + ZSC_STATUS; - if (chan == 1) - return base + ZSC_CHANNELB + ZSC_STATUS; - panic("zs_statusreg: bogus channel"); + if (chan == 0) + return base + ZSC_CHANNELA + ZSC_STATUS; + if (chan == 1) + return base + ZSC_CHANNELB + ZSC_STATUS; + panic("zs_statusreg: bogus channel"); } static caddr_t zs_datareg(caddr_t base, int chan) { - if (chan == 0) - return base + ZSC_CHANNELA + ZSC_DATA; - if (chan == 1) - return base + ZSC_CHANNELB + ZSC_DATA; - panic("zs_statusreg: bogus channel"); + if (chan == 0) + return base + ZSC_CHANNELA + ZSC_DATA; + if (chan == 1) + return base + ZSC_CHANNELB + ZSC_DATA; + panic("zs_statusreg: bogus channel"); } static int zs_get_status(caddr_t base, int chan) { - return *(u_int32_t*) zs_statusreg(base, chan) & 0xff; + return *(u_int32_t*) zs_statusreg(base, chan) & 0xff; } +#ifdef IF_RR3_WORKED static void zs_put_status(caddr_t base, int chan, int v) { - *(u_int32_t*) zs_statusreg(base, chan) = v; - alpha_mb(); + *(u_int32_t*) zs_statusreg(base, chan) = v; + alpha_mb(); } static int zs_get_rr3(caddr_t base, int chan) { - if (chan != 0) - panic("zs_get_rr3: bad channel"); - zs_put_status(base, chan, 3); - return zs_get_status(base, chan); + if (chan != 0) + panic("zs_get_rr3: bad channel"); + zs_put_status(base, chan, 3); + return zs_get_status(base, chan); } +#endif static int zs_get_data(caddr_t base, int chan) { - return *(u_int32_t*) zs_datareg(base, chan) & 0xff; + return *(u_int32_t*) zs_datareg(base, chan) & 0xff; } static void zs_put_data(caddr_t base, int chan, int v) { - *(u_int32_t*) zs_datareg(base, chan) = v; - alpha_mb(); + *(u_int32_t*) zs_datareg(base, chan) = v; + alpha_mb(); } static int zs_getc(caddr_t base, int chan) { - while (!(zs_get_status(base, chan) & 1)) - DELAY(5); - return zs_get_data(base, chan); + while (!(zs_get_status(base, chan) & 1)) + DELAY(5); + return zs_get_data(base, chan); +} + +static int +zs_maygetc(caddr_t base, int chan) +{ + if (zs_get_status(base, chan) & 1) + return zs_get_data(base, chan); + else + return (-1); } static void zs_putc(caddr_t base, int chan, int c) { - while (!(zs_get_status(base, chan) & 4)) - DELAY(5); - zs_put_data(base, chan, c); + while (!(zs_get_status(base, chan) & 4)) + DELAY(5); + zs_put_data(base, chan, c); } +/* + * Console support + */ +int zs_cngetc __P((dev_t)); +int zs_cncheckc __P((dev_t)); +void zs_cnputc __P((dev_t, int)); + +static caddr_t zs_console_addr; +CONS_DRIVER(zs, NULL, NULL, NULL, zs_cngetc, zs_cncheckc, zs_cnputc, NULL); + int zs_cnattach(vm_offset_t base, vm_offset_t offset) { - zs_console_addr = (caddr_t) ALPHA_PHYS_TO_K0SEG(base + offset); - zs_console = 1; + /* should really bet part of ivars */ + zs_console_addr = (caddr_t) ALPHA_PHYS_TO_K0SEG(base + offset); - zs_cons.cn_dev = makedev(CDEV_MAJOR, 0); - cn_tab = &zs_cons; - return 0; + zs_consdev.cn_dev = makedev(CDEV_MAJOR, 0); + zs_consdev.cn_pri = CN_NORMAL; + cn_tab = &zs_consdev; + make_dev(&zs_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "zs0"); + return (0); } int zs_cngetc(dev_t dev) { - int s = spltty(); - int c = zs_getc(zs_console_addr, minor(dev)); - splx(s); - return c; + int s = spltty(); + int c = zs_getc(zs_console_addr, minor(dev)); + splx(s); + return c; +} + +int +zs_cncheckc(dev_t dev) +{ + int s = spltty(); + int c = zs_maygetc(zs_console_addr, minor(dev)); + splx(s); + return c; } void zs_cnputc(dev_t dev, int c) { - int s = spltty(); - zs_putc(zs_console_addr, minor(dev), c); - splx(s); + int s = spltty(); + zs_putc(zs_console_addr, minor(dev), c); + splx(s); } static int zsopen(dev_t dev, int flag, int mode, struct proc *p) { - struct zs_softc* sc = ZS_SOFTC(minor(dev)); + struct zs_softc *sc = ZS_SOFTC(minor(dev)); struct tty *tp; + int error = 0, setuptimeout = 0; int s; - int error = 0; if (!sc) return ENXIO; s = spltty(); - - tp = &sc->tty; - dev->si_tty = tp; - + tp = sc->tp = dev->si_tty = ttymalloc(sc->tp); tp->t_oproc = zsstart; tp->t_param = zsparam; tp->t_stop = zsstop; @@ -265,8 +291,8 @@ zsopen(dev_t dev, int flag, int mode, struct proc *p) tp->t_lflag = TTYDEF_LFLAG; tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; ttsetwater(tp); - } else if (tp->t_state & TS_XCLUDE && - suser(p)) { + setuptimeout = 1; + } else if ((tp->t_state & TS_XCLUDE) && suser(p)) { splx(s); return EBUSY; } @@ -275,49 +301,74 @@ zsopen(dev_t dev, int flag, int mode, struct proc *p) error = (*linesw[tp->t_line].l_open)(dev, tp); - return error; + if (error == 0 && setuptimeout) { + zspolltime = hz / 50; + if (zspolltime < 1) + zspolltime = 1; + /* XXX we're not set up to do interrupts yet */ + sc->zst = timeout(zs_poll_intr, sc, zspolltime); + } + + return (error); } static int zsclose(dev_t dev, int flag, int mode, struct proc *p) { - struct tty *tp = &ZS_SOFTC(minor(dev))->tty; + struct zs_softc *sc = ZS_SOFTC(minor(dev)); + struct tty *tp; + int s; + if (sc == NULL) + return (ENXIO); + + tp = sc->tp; + + s = spltty(); + untimeout(zs_poll_intr, sc, sc->zst); (*linesw[tp->t_line].l_close)(tp, flag); ttyclose(tp); - return 0; + splx(s); + + return (0); } static int zsioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) { - struct tty *tp = &ZS_SOFTC(minor(dev))->tty; + struct zs_softc *sc = ZS_SOFTC(minor(dev)); + struct tty *tp; int error; - error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); - if (error != ENOIOCTL) - return error; - error = ttioctl(tp, cmd, data, flag); - if (error != ENOIOCTL) - return error; + if (sc == NULL) + return (ENXIO); - return ENOTTY; + tp = ZS_SOFTC(minor(dev))->tp; + + error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); + + if (error != ENOIOCTL) + return (error); + + error = ttioctl(tp, cmd, data, flag); + + if (error != ENOIOCTL) + return (error); + else + return (ENOTTY); } static int zsparam(struct tty *tp, struct termios *t) { - - return 0; + return (0); } static void zsstart(struct tty *tp) { - struct zs_softc* sc = (struct zs_softc*) tp; - int s; - - s = spltty(); + struct zs_softc *sc = ZS_SOFTC(minor(tp->t_dev)); + int s = spltty(); if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { ttwwakeup(tp); @@ -340,9 +391,7 @@ zsstart(struct tty *tp) static void zsstop(struct tty *tp, int flag) { - int s; - - s = spltty(); + int s = spltty(); if (tp->t_state & TS_BUSY) if ((tp->t_state & TS_TTSTOP) == 0) tp->t_state |= TS_FLUSH; @@ -357,16 +406,15 @@ DRIVER_MODULE(zs, zsc, zs_driver, zs_devclass, 0, 0); struct zsc_softc { caddr_t base; - struct zs_softc* sc_a; - struct zs_softc* sc_b; + struct zs_softc *sc_a; + struct zs_softc *sc_b; void *intr; }; +static driver_intr_t zsc_tlsb_intr; static int zsc_tlsb_probe(device_t dev); static int zsc_tlsb_attach(device_t dev); static int zsc_tlsb_print_child(device_t dev, device_t child); -static driver_intr_t zsc_tlsb_intr; - static device_method_t zsc_tlsb_methods[] = { /* Device interface */ @@ -386,9 +434,7 @@ static device_method_t zsc_tlsb_methods[] = { }; static driver_t zsc_tlsb_driver = { - "zsc", - zsc_tlsb_methods, - sizeof(struct zsc_softc), + "zsc", zsc_tlsb_methods, sizeof(struct zsc_softc), }; static int @@ -401,48 +447,47 @@ static caddr_t zsc_get_base(device_t dev) { device_t bus = device_get_parent(dev); - struct zsc_softc* sc = device_get_softc(bus); + struct zsc_softc *sc = device_get_softc(bus); return sc->base; } static int zsc_tlsb_probe(device_t dev) { - struct zsc_softc* sc = device_get_softc(dev); + static int zs_unit = 0; + struct zsc_softc *sc = device_get_softc(dev); device_set_desc(dev, "Z8530 uart"); - - sc->base = (caddr_t) ALPHA_PHYS_TO_K0SEG(TLSB_GBUS_BASE - + gbus_get_offset(dev)); - + sc->base = (caddr_t) + ALPHA_PHYS_TO_K0SEG(TLSB_GBUS_BASE + gbus_get_offset(dev)); /* * Add channel A and channel B */ - device_add_child(dev, "zs", 0); - device_add_child(dev, "zs", 1); - - return 0; + device_add_child(dev, "zs", zs_unit++); + device_add_child(dev, "zs", zs_unit++); + return (0); } static int zsc_tlsb_attach(device_t dev) { - struct zsc_softc* sc = device_get_softc(dev); + static int once = 1; + struct zsc_softc *sc = device_get_softc(dev); device_t parent = device_get_parent(dev); - cdevsw_add(&zs_cdevsw); - + if (once) { + once = 0; + cdevsw_add(&zs_cdevsw); + } bus_generic_attach(dev); - + /* XXX */ - sc->sc_a = ZS_SOFTC(0); - sc->sc_b = ZS_SOFTC(1); + sc->sc_a = ZS_SOFTC(device_get_unit(dev)); + sc->sc_b = ZS_SOFTC(device_get_unit(dev)+1); /* XXX should use resource argument to communicate vector */ return BUS_SETUP_INTR(parent, dev, NULL, INTR_TYPE_TTY, - zsc_tlsb_intr, sc, &sc->intr); - - return 0; + zsc_tlsb_intr, sc, &sc->intr); } static int @@ -458,14 +503,34 @@ zsc_tlsb_print_child(device_t bus, device_t dev) } static void -zsc_tlsb_intr(void* arg) +zs_poll_intr(void *arg) { - struct zsc_softc* sc = arg; - caddr_t base = sc->base; + struct zs_softc *sc = arg; + int s = spltty(); + zsc_tlsb_intr(device_get_softc(device_get_parent(sc->dev))); + sc->zst = timeout(zs_poll_intr, sc, zspolltime); + splx(s); +} + +static void +zsc_tlsb_intr(void *arg) +{ + struct zsc_softc *sc = arg; + caddr_t base = sc->base; + int rr3; + + if (base == NULL) + panic("null base in zsc_tlsb_intr"); + + +#ifdef IF_RR3_WORKED + rr3 = zs_get_rr3(base, 0); +#else + rr3 = 0x20; +#endif - int rr3 = zs_get_rr3(base, 0); if (rr3 & 0x20) { - struct tty* tp = &sc->sc_a->tty; + struct tty *tp = sc->sc_a->tp; int c; while (zs_get_status(base, 0) & 1) { @@ -474,13 +539,13 @@ zsc_tlsb_intr(void* arg) if (c == CTRL('\\')) Debugger("manual escape to debugger"); #endif - if (tp->t_state & TS_ISOPEN) + if (tp && (tp->t_state & TS_ISOPEN)) (*linesw[tp->t_line].l_rint)(c, tp); DELAY(5); } } if (rr3 & 0x04) { - struct tty* tp = &sc->sc_b->tty; + struct tty *tp = sc->sc_b->tp; int c; while (zs_get_status(base, 1) & 1) { @@ -489,11 +554,10 @@ zsc_tlsb_intr(void* arg) if (c == CTRL('\\')) Debugger("manual escape to debugger"); #endif - if (tp->t_state & TS_ISOPEN) + if (tp && (tp->t_state & TS_ISOPEN)) (*linesw[tp->t_line].l_rint)(c, tp); DELAY(5); } } } - DRIVER_MODULE(zsc, gbus, zsc_tlsb_driver, zsc_devclass, 0, 0);