155107Storek /* 255107Storek * Copyright (c) 1992 The Regents of the University of California. 355107Storek * All rights reserved. 455107Storek * 555107Storek * This software was developed by the Computer Systems Engineering group 655107Storek * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 755107Storek * contributed to Berkeley. 855107Storek * 9*55499Sbostic * All advertising materials mentioning features or use of this software 10*55499Sbostic * must display the following acknowledgement: 11*55499Sbostic * This product includes software developed by the University of 12*55499Sbostic * California, Lawrence Berkeley Laboratories. 13*55499Sbostic * 1455107Storek * %sccs.include.redist.c% 1555107Storek * 16*55499Sbostic * @(#)zs.c 7.2 (Berkeley) 07/21/92 1755107Storek * 1855107Storek * from: $Header: zs.c,v 1.24 92/06/30 02:24:21 torek Exp $ 1955107Storek */ 2055107Storek 2155107Storek /* 2255107Storek * Zilog Z8530 (ZSCC) driver. 2355107Storek * 2455107Storek * Runs two tty ports (ttya and ttyb) on zs0, 2555107Storek * and runs a keyboard and mouse on zs1. 2655107Storek * 2755107Storek * This driver knows far too much about chip to usage mappings. 2855107Storek */ 2955107Storek #define NZS 2 /* XXX */ 3055107Storek 3155107Storek #include "sys/param.h" 3255107Storek #include "sys/proc.h" 3355107Storek #include "sys/device.h" 3455107Storek #include "sys/conf.h" 3555107Storek #include "sys/file.h" 3655107Storek #include "sys/ioctl.h" 3755107Storek #include "sys/tty.h" 3855107Storek #include "sys/time.h" 3955107Storek #include "sys/kernel.h" 4055107Storek #include "sys/syslog.h" 4155107Storek 4255107Storek #include "machine/autoconf.h" 4355107Storek #include "machine/cpu.h" 4455107Storek 4555107Storek #include "kbd.h" 4655107Storek #include "zsreg.h" 4755107Storek #include "zsvar.h" 4855107Storek 4955107Storek #ifdef KGDB 5055107Storek #include "machine/remote-sl.h" 5155107Storek #endif 5255107Storek 5355107Storek #define ZSMAJOR 12 /* XXX */ 5455107Storek 5555107Storek #define ZS_KBD 2 /* XXX */ 5655107Storek #define ZS_MOUSE 3 /* XXX */ 5755107Storek 5855107Storek /* the magic number below was stolen from the Sprite source. */ 5955107Storek #define PCLK (19660800/4) /* PCLK pin input clock rate */ 6055107Storek 6155107Storek /* 6255107Storek * Select software interrupt bit based on TTY ipl. 6355107Storek */ 6455107Storek #if PIL_TTY == 1 6555107Storek # define IE_ZSSOFT IE_L1 6655107Storek #elif PIL_TTY == 4 6755107Storek # define IE_ZSSOFT IE_L4 6855107Storek #elif PIL_TTY == 6 6955107Storek # define IE_ZSSOFT IE_L6 7055107Storek #else 7155107Storek # error "no suitable software interrupt bit" 7255107Storek #endif 7355107Storek 7455107Storek /* 7555107Storek * Software state per found chip. This would be called `zs_softc', 7655107Storek * but the previous driver had a rather different zs_softc.... 7755107Storek */ 7855107Storek struct zsinfo { 7955107Storek struct device zi_dev; /* base device */ 8055107Storek volatile struct zsdevice *zi_zs;/* chip registers */ 8155107Storek struct zs_chanstate zi_cs[2]; /* channel A and B software state */ 8255107Storek }; 8355107Storek 8455107Storek struct tty zs_tty[NZS * 2]; /* XXX should be dynamic */ 8555107Storek 8655107Storek /* Definition of the driver for autoconfig. */ 8755107Storek static int zsmatch(struct device *, struct cfdata *, void *); 8855107Storek static void zsattach(struct device *, struct device *, void *); 8955107Storek struct cfdriver zscd = 9055107Storek { NULL, "zs", zsmatch, zsattach, DV_TTY, sizeof(struct zsinfo) }; 9155107Storek 9255107Storek /* Interrupt handlers. */ 9355107Storek static int zshard(void *); 9455107Storek static struct intrhand levelhard = { zshard }; 9555107Storek static int zssoft(void *); 9655107Storek static struct intrhand levelsoft = { zssoft }; 9755107Storek 9855107Storek struct zs_chanstate *zslist; 9955107Storek 10055107Storek /* Routines called from other code. */ 10155107Storek static void zsiopen(struct tty *); 10255107Storek static void zsiclose(struct tty *); 10355107Storek static void zsstart(struct tty *); 10455107Storek static void zsstop(struct tty *, int); 10555107Storek static int zsparam(struct tty *, struct termios *); 10655107Storek 10755107Storek /* Routines purely local to this driver. */ 10855107Storek static int zs_getspeed(volatile struct zschan *); 10955107Storek static void zs_reset(volatile struct zschan *, int, int); 11055107Storek static void zs_modem(struct zs_chanstate *, int); 11155107Storek static void zs_loadchannelregs(volatile struct zschan *, u_char *); 11255107Storek 11355107Storek /* Console stuff. */ 11455107Storek static struct tty *zs_ctty; /* console `struct tty *' */ 11555107Storek static int zs_consin = -1, zs_consout = -1; 11655107Storek static int zscnputc(int); /* console putc function */ 11755107Storek static volatile struct zschan *zs_conschan; 11855107Storek static struct tty *zs_checkcons(struct zsinfo *, int, struct zs_chanstate *); 11955107Storek 12055107Storek #ifdef KGDB 12155107Storek /* KGDB stuff. Must reboot to change zs_kgdbunit. */ 12255107Storek extern int kgdb_dev, kgdb_rate; 12355107Storek static int zs_kgdb_savedspeed; 12455107Storek static void zs_checkkgdb(int, struct zs_chanstate *, struct tty *); 12555107Storek #endif 12655107Storek 12755107Storek extern volatile struct zsdevice *findzs(int); 12855107Storek static volatile struct zsdevice *zsaddr[NZS]; /* XXX, but saves work */ 12955107Storek 13055107Storek /* 13155107Storek * Console keyboard L1-A processing is done in the hardware interrupt code, 13255107Storek * so we need to duplicate some of the console keyboard decode state. (We 13355107Storek * must not use the regular state as the hardware code keeps ahead of the 13455107Storek * software state: the software state tracks the most recent ring input but 13555107Storek * the hardware state tracks the most recent ZSCC input.) See also kbd.h. 13655107Storek */ 13755107Storek static struct conk_state { /* console keyboard state */ 13855107Storek char conk_id; /* true => ID coming up (console only) */ 13955107Storek char conk_l1; /* true => L1 pressed (console only) */ 14055107Storek } zsconk_state; 14155107Storek 14255107Storek /* 14355107Storek * Match slave number to zs unit number, so that misconfiguration will 14455107Storek * not set up the keyboard as ttya, etc. 14555107Storek */ 14655107Storek static int 14755107Storek zsmatch(struct device *parent, struct cfdata *cf, void *aux) 14855107Storek { 14955107Storek struct romaux *ra = aux; 15055107Storek 15155107Storek return (getpropint(ra->ra_node, "slave", -2) == cf->cf_unit); 15255107Storek } 15355107Storek 15455107Storek /* 15555107Storek * Attach a found zs. 15655107Storek * 15755107Storek * USE ROM PROPERTIES port-a-ignore-cd AND port-b-ignore-cd FOR 15855107Storek * SOFT CARRIER, AND keyboard PROPERTY FOR KEYBOARD/MOUSE? 15955107Storek */ 16055107Storek static void 16155107Storek zsattach(struct device *parent, struct device *dev, void *aux) 16255107Storek { 16355107Storek register int zs = dev->dv_unit, unit; 16455107Storek register struct zsinfo *zi; 16555107Storek register struct zs_chanstate *cs; 16655107Storek register volatile struct zsdevice *addr; 16755107Storek register struct tty *tp, *ctp; 16855107Storek register struct romaux *ra = aux; 16955107Storek int pri, softcar; 17055107Storek static int didintr, prevpri; 17155107Storek 17255107Storek if ((addr = zsaddr[zs]) == NULL) 17355107Storek addr = zsaddr[zs] = findzs(zs); 17455107Storek if ((void *)addr != ra->ra_vaddr) 17555107Storek panic("zsattach"); 17655107Storek if (ra->ra_nintr != 1) { 17755107Storek printf(": expected 1 interrupt, got %d\n", ra->ra_nintr); 17855107Storek return; 17955107Storek } 18055107Storek pri = ra->ra_intr[0].int_pri; 18155107Storek printf(" pri %d, softpri %d\n", pri, PIL_TTY); 18255107Storek if (!didintr) { 18355107Storek didintr = 1; 18455107Storek prevpri = pri; 18555107Storek intr_establish(pri, &levelhard); 18655107Storek intr_establish(PIL_TTY, &levelsoft); 18755107Storek } else if (pri != prevpri) 18855107Storek panic("broken zs interrupt scheme"); 18955107Storek zi = (struct zsinfo *)dev; 19055107Storek zi->zi_zs = addr; 19155107Storek unit = zs * 2; 19255107Storek cs = zi->zi_cs; 19355107Storek tp = &zs_tty[unit]; 19455107Storek 19555107Storek if (unit == 0) { 19655107Storek /* Get software carrier flags from options node in OPENPROM. */ 19755107Storek extern int optionsnode; 19855107Storek 19955107Storek softcar = 0; 20055107Storek if (*getpropstring(optionsnode, "ttya-ignore-cd") == 't') 20155107Storek softcar |= 1; 20255107Storek if (*getpropstring(optionsnode, "ttyb-ignore-cd") == 't') 20355107Storek softcar |= 2; 20455107Storek } else 20555107Storek softcar = dev->dv_cfdata->cf_flags; 20655107Storek 20755107Storek /* link into interrupt list with order (A,B) (B=A+1) */ 20855107Storek cs[0].cs_next = &cs[1]; 20955107Storek cs[1].cs_next = zslist; 21055107Storek zslist = cs; 21155107Storek 21255107Storek cs->cs_unit = unit; 21355107Storek cs->cs_speed = zs_getspeed(&addr->zs_chan[CHAN_A]); 21455107Storek cs->cs_softcar = softcar & 1; 21555107Storek cs->cs_zc = &addr->zs_chan[CHAN_A]; 21655107Storek tp->t_dev = makedev(ZSMAJOR, unit); 21755107Storek tp->t_oproc = zsstart; 21855107Storek tp->t_param = zsparam; 21955107Storek tp->t_stop = zsstop; 22055107Storek if ((ctp = zs_checkcons(zi, unit, cs)) != NULL) 22155107Storek tp = ctp; 22255107Storek cs->cs_ttyp = tp; 22355107Storek #ifdef KGDB 22455107Storek if (ctp == NULL) 22555107Storek zs_checkkgdb(unit, cs, tp); 22655107Storek else 22755107Storek #endif 22855107Storek zs_reset(&addr->zs_chan[CHAN_A], 0, cs->cs_speed); 22955107Storek if (unit == ZS_KBD) { 23055107Storek /* 23155107Storek * Keyboard: tell /dev/kbd driver how to talk to us. 23255107Storek */ 23355107Storek tp->t_ispeed = tp->t_ospeed = cs->cs_speed; 23455107Storek tp->t_cflag = CS8; 23555107Storek kbd_serial(tp, zsiopen, zsiclose); 23655107Storek cs->cs_conk = 1; /* do L1-A processing */ 23755107Storek } 23855107Storek unit++; 23955107Storek cs++; 24055107Storek tp++; 24155107Storek cs->cs_unit = unit; 24255107Storek cs->cs_speed = zs_getspeed(&addr->zs_chan[CHAN_B]); 24355107Storek cs->cs_softcar = softcar & 2; 24455107Storek cs->cs_zc = &addr->zs_chan[CHAN_B]; 24555107Storek tp->t_dev = makedev(ZSMAJOR, unit); 24655107Storek tp->t_oproc = zsstart; 24755107Storek tp->t_param = zsparam; 24855107Storek tp->t_stop = zsstop; 24955107Storek if ((ctp = zs_checkcons(zi, unit, cs)) != NULL) 25055107Storek tp = ctp; 25155107Storek cs->cs_ttyp = tp; 25255107Storek #ifdef KGDB 25355107Storek if (ctp == NULL) 25455107Storek zs_checkkgdb(unit, cs, tp); 25555107Storek else 25655107Storek #endif 25755107Storek zs_reset(&addr->zs_chan[CHAN_B], 0, cs->cs_speed); 25855107Storek if (unit == ZS_MOUSE) { 25955107Storek /* 26055107Storek * Mouse: tell /dev/mouse driver how to talk to us. 26155107Storek */ 26255107Storek tp->t_ispeed = tp->t_ospeed = cs->cs_speed; 26355107Storek tp->t_cflag = CS8; 26455107Storek ms_serial(tp, zsiopen, zsiclose); 26555107Storek } 26655107Storek } 26755107Storek 26855107Storek /* 26955107Storek * Put a channel in a known state. Interrupts may be left disabled 27055107Storek * or enabled, as desired. 27155107Storek */ 27255107Storek static void 27355107Storek zs_reset(zc, inten, speed) 27455107Storek volatile struct zschan *zc; 27555107Storek int inten, speed; 27655107Storek { 27755107Storek int tconst; 27855107Storek static u_char reg[16] = { 27955107Storek 0, 28055107Storek 0, 28155107Storek 0, 28255107Storek ZSWR3_RX_8 | ZSWR3_RX_ENABLE, 28355107Storek ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP, 28455107Storek ZSWR5_TX_8 | ZSWR5_TX_ENABLE, 28555107Storek 0, 28655107Storek 0, 28755107Storek 0, 28855107Storek 0, 28955107Storek ZSWR10_NRZ, 29055107Storek ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD, 29155107Storek 0, 29255107Storek 0, 29355107Storek ZSWR14_BAUD_FROM_PCLK | ZSWR14_BAUD_ENA, 29455107Storek ZSWR15_BREAK_IE | ZSWR15_DCD_IE, 29555107Storek }; 29655107Storek 29755107Storek reg[9] = inten ? ZSWR9_MASTER_IE | ZSWR9_NO_VECTOR : ZSWR9_NO_VECTOR; 29855107Storek tconst = BPS_TO_TCONST(PCLK / 16, speed); 29955107Storek reg[12] = tconst; 30055107Storek reg[13] = tconst >> 8; 30155107Storek zs_loadchannelregs(zc, reg); 30255107Storek } 30355107Storek 30455107Storek /* 30555107Storek * Declare the given tty (which is in fact &cons) as a console input 30655107Storek * or output. This happens before the zs chip is attached; the hookup 30755107Storek * is finished later, in zs_setcons() below. 30855107Storek * 30955107Storek * This is used only for ports a and b. The console keyboard is decoded 31055107Storek * independently (we always send unit-2 input to /dev/kbd, which will 31155107Storek * direct it to /dev/console if appropriate). 31255107Storek */ 31355107Storek void 31455107Storek zsconsole(tp, unit, out) 31555107Storek register struct tty *tp; 31655107Storek register int unit; 31755107Storek int out; 31855107Storek { 31955107Storek extern int (*v_putc)(); 32055107Storek int zs; 32155107Storek volatile struct zsdevice *addr; 32255107Storek 32355107Storek if (unit >= ZS_KBD) 32455107Storek panic("zsconsole"); 32555107Storek if (out) { 32655107Storek zs_consout = unit; 32755107Storek zs = unit >> 1; 32855107Storek if ((addr = zsaddr[zs]) == NULL) 32955107Storek addr = zsaddr[zs] = findzs(zs); 33055107Storek zs_conschan = (unit & 1) == 0 ? &addr->zs_chan[CHAN_A] : 33155107Storek &addr->zs_chan[CHAN_B]; 33255107Storek v_putc = zscnputc; 33355107Storek } else 33455107Storek zs_consin = unit; 33555107Storek zs_ctty = tp; 33655107Storek } 33755107Storek 33855107Storek /* 33955107Storek * Polled console output putchar. 34055107Storek */ 34155107Storek static int 34255107Storek zscnputc(c) 34355107Storek int c; 34455107Storek { 34555107Storek register volatile struct zschan *zc = zs_conschan; 34655107Storek register int s; 34755107Storek 34855107Storek /* 34955107Storek * Must block output interrupts (i.e., raise to >= splzs) without 35055107Storek * lowering current ipl. Need a better way. 35155107Storek */ 35255107Storek s = splhigh(); 35355107Storek #ifdef sun4c /* XXX */ 35455107Storek if (s <= (12 << 8)) 35555107Storek (void) splzs(); 35655107Storek #endif 35755107Storek while ((zc->zc_csr & ZSRR0_TX_READY) == 0) 35855107Storek continue; 35955107Storek zc->zc_data = c; 36055107Storek splx(s); 36155107Storek } 36255107Storek 36355107Storek /* 36455107Storek * Set up the given unit as console input, output, both, or neither, as 36555107Storek * needed. Return console tty if it is to receive console input. 36655107Storek */ 36755107Storek static struct tty * 36855107Storek zs_checkcons(struct zsinfo *zi, int unit, struct zs_chanstate *cs) 36955107Storek { 37055107Storek register struct tty *tp; 37155107Storek char *i, *o; 37255107Storek 37355107Storek if ((tp = zs_ctty) == NULL) 37455107Storek return (0); 37555107Storek i = zs_consin == unit ? "input" : NULL; 37655107Storek o = zs_consout == unit ? "output" : NULL; 37755107Storek if (i == NULL && o == NULL) 37855107Storek return (0); 37955107Storek 38055107Storek /* rewire the minor device (gack) */ 38155107Storek tp->t_dev = makedev(major(tp->t_dev), unit); 38255107Storek 38355107Storek /* 38455107Storek * Rewire input and/or output. Note that baud rate reflects 38555107Storek * input settings, not output settings, but we can do no better 38655107Storek * if the console is split across two ports. 38755107Storek */ 38855107Storek if (i) { 38955107Storek tp->t_param = zsparam; 39055107Storek tp->t_ispeed = tp->t_ospeed = cs->cs_speed; 39155107Storek tp->t_cflag = CS8; 39255107Storek ttsetwater(tp); 39355107Storek } 39455107Storek if (o) { 39555107Storek tp->t_oproc = zsstart; 39655107Storek tp->t_stop = zsstop; 39755107Storek } 39855107Storek printf("%s%c: console %s\n", 39955107Storek zi->zi_dev.dv_xname, (unit & 1) + 'a', i ? (o ? "i/o" : i) : o); 40055107Storek cs->cs_consio = 1; 40155107Storek cs->cs_brkabort = 1; 40255107Storek return (i ? tp : NULL); 40355107Storek } 40455107Storek 40555107Storek #ifdef KGDB 40655107Storek /* 40755107Storek * The kgdb zs port, if any, was altered at boot time (see zs_kgdb_init). 40855107Storek * Pick up the current speed and character size and restore the original 40955107Storek * speed. 41055107Storek */ 41155107Storek static void 41255107Storek zs_checkkgdb(int unit, struct zs_chanstate *cs, struct tty *tp) 41355107Storek { 41455107Storek 41555107Storek if (kgdb_dev == makedev(ZSMAJOR, unit)) { 41655107Storek tp->t_ispeed = tp->t_ospeed = kgdb_rate; 41755107Storek tp->t_cflag = CS8; 41855107Storek cs->cs_kgdb = 1; 41955107Storek cs->cs_speed = zs_kgdb_savedspeed; 42055107Storek (void) zsparam(tp, &tp->t_termios); 42155107Storek } 42255107Storek } 42355107Storek #endif 42455107Storek 42555107Storek /* 42655107Storek * Compute the current baud rate given a ZSCC channel. 42755107Storek */ 42855107Storek static int 42955107Storek zs_getspeed(zc) 43055107Storek register volatile struct zschan *zc; 43155107Storek { 43255107Storek register int tconst; 43355107Storek 43455107Storek tconst = ZS_READ(zc, 12); 43555107Storek tconst |= ZS_READ(zc, 13) << 8; 43655107Storek return (TCONST_TO_BPS(PCLK / 16, tconst)); 43755107Storek } 43855107Storek 43955107Storek 44055107Storek /* 44155107Storek * Do an internal open. 44255107Storek */ 44355107Storek static void 44455107Storek zsiopen(struct tty *tp) 44555107Storek { 44655107Storek 44755107Storek (void) zsparam(tp, &tp->t_termios); 44855107Storek ttsetwater(tp); 44955107Storek tp->t_state = TS_ISOPEN | TS_CARR_ON; 45055107Storek } 45155107Storek 45255107Storek /* 45355107Storek * Do an internal close. Eventually we should shut off the chip when both 45455107Storek * ports on it are closed. 45555107Storek */ 45655107Storek static void 45755107Storek zsiclose(struct tty *tp) 45855107Storek { 45955107Storek 46055107Storek ttylclose(tp, 0); /* ??? */ 46155107Storek ttyclose(tp); /* ??? */ 46255107Storek tp->t_state = 0; 46355107Storek } 46455107Storek 46555107Storek 46655107Storek /* 46755107Storek * Open a zs serial port. This interface may not be used to open 46855107Storek * the keyboard and mouse ports. (XXX) 46955107Storek */ 47055107Storek int 47155107Storek zsopen(dev_t dev, int flags, int mode, struct proc *p) 47255107Storek { 47355107Storek register struct tty *tp; 47455107Storek register struct zs_chanstate *cs; 47555107Storek struct zsinfo *zi; 47655107Storek int unit = minor(dev), zs = unit >> 1, error, s; 47755107Storek 47855107Storek if (zs >= zscd.cd_ndevs || (zi = zscd.cd_devs[zs]) == NULL || 47955107Storek unit == ZS_KBD || unit == ZS_MOUSE) 48055107Storek return (ENXIO); 48155107Storek cs = &zi->zi_cs[unit & 1]; 48255107Storek if (cs->cs_consio) 48355107Storek return (ENXIO); /* ??? */ 48455107Storek tp = cs->cs_ttyp; 48555107Storek s = spltty(); 48655107Storek if ((tp->t_state & TS_ISOPEN) == 0) { 48755107Storek ttychars(tp); 48855107Storek if (tp->t_ispeed == 0) { 48955107Storek tp->t_iflag = TTYDEF_IFLAG; 49055107Storek tp->t_oflag = TTYDEF_OFLAG; 49155107Storek tp->t_cflag = TTYDEF_CFLAG; 49255107Storek tp->t_lflag = TTYDEF_LFLAG; 49355107Storek tp->t_ispeed = tp->t_ospeed = cs->cs_speed; 49455107Storek } 49555107Storek (void) zsparam(tp, &tp->t_termios); 49655107Storek ttsetwater(tp); 49755107Storek } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { 49855107Storek splx(s); 49955107Storek return (EBUSY); 50055107Storek } 50155107Storek error = 0; 50255107Storek for (;;) { 50355107Storek /* loop, turning on the device, until carrier present */ 50455107Storek zs_modem(cs, 1); 50555107Storek if (cs->cs_softcar) 50655107Storek tp->t_state |= TS_CARR_ON; 50755107Storek if (flags & O_NONBLOCK || tp->t_cflag & CLOCAL || 50855107Storek tp->t_state & TS_CARR_ON) 50955107Storek break; 51055107Storek tp->t_state |= TS_WOPEN; 51155107Storek if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 51255107Storek ttopen, 0)) 51355107Storek break; 51455107Storek } 51555107Storek splx(s); 51655107Storek if (error == 0) 51755107Storek error = (*linesw[tp->t_line].l_open)(dev, tp); 51855107Storek if (error) 51955107Storek zs_modem(cs, 0); 52055107Storek return (error); 52155107Storek } 52255107Storek 52355107Storek /* 52455107Storek * Close a zs serial port. 52555107Storek */ 52655107Storek int 52755107Storek zsclose(dev_t dev, int flags, int mode, struct proc *p) 52855107Storek { 52955107Storek register struct zs_chanstate *cs; 53055107Storek register struct tty *tp; 53155107Storek struct zsinfo *zi; 53255107Storek int unit = minor(dev), s; 53355107Storek 53455107Storek zi = zscd.cd_devs[unit >> 1]; 53555107Storek cs = &zi->zi_cs[unit & 1]; 53655107Storek tp = cs->cs_ttyp; 53755107Storek (*linesw[tp->t_line].l_close)(tp, flags); 53855107Storek if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN || 53955107Storek (tp->t_state & TS_ISOPEN) == 0) { 54055107Storek zs_modem(cs, 0); 54155107Storek /* hold low for 1 second */ 54255107Storek (void) tsleep((caddr_t)cs, TTIPRI, ttclos, hz); 54355107Storek } 54455107Storek ttyclose(tp); 54555107Storek #ifdef KGDB 54655107Storek /* Reset the speed if we're doing kgdb on this port */ 54755107Storek if (cs->cs_kgdb) { 54855107Storek tp->t_ispeed = tp->t_ospeed = kgdb_rate; 54955107Storek (void) zsparam(tp, &tp->t_termios); 55055107Storek } 55155107Storek #endif 55255107Storek return (0); 55355107Storek } 55455107Storek 55555107Storek /* 55655107Storek * Read/write zs serial port. 55755107Storek */ 55855107Storek int 55955107Storek zsread(dev_t dev, struct uio *uio, int flags) 56055107Storek { 56155107Storek register struct tty *tp = &zs_tty[minor(dev)]; 56255107Storek 56355107Storek return (linesw[tp->t_line].l_read(tp, uio, flags)); 56455107Storek } 56555107Storek 56655107Storek int 56755107Storek zswrite(dev_t dev, struct uio *uio, int flags) 56855107Storek { 56955107Storek register struct tty *tp = &zs_tty[minor(dev)]; 57055107Storek 57155107Storek return (linesw[tp->t_line].l_write(tp, uio, flags)); 57255107Storek } 57355107Storek 57455107Storek /* 57555107Storek * ZS hardware interrupt. Scan all ZS channels. NB: we know here that 57655107Storek * channels are kept in (A,B) pairs. 57755107Storek * 57855107Storek * Do just a little, then get out; set a software interrupt if more 57955107Storek * work is needed. 58055107Storek * 58155107Storek * We deliberately ignore the vectoring Zilog gives us, and match up 58255107Storek * only the number of `reset interrupt under service' operations, not 58355107Storek * the order. 58455107Storek */ 58555107Storek /* ARGSUSED */ 58655107Storek int 58755107Storek zshard(void *intrarg) 58855107Storek { 58955107Storek register struct zs_chanstate *a; 59055107Storek #define b (a + 1) 59155107Storek register int rr3, intflags = 0; 59255107Storek static int zsrint(struct zs_chanstate *); 59355107Storek static int zsxint(struct zs_chanstate *); 59455107Storek static int zssint(struct zs_chanstate *); 59555107Storek 59655107Storek for (a = zslist; a != NULL; a = b->cs_next) { 59755107Storek rr3 = ZS_READ(a->cs_zc, 3); 59855107Storek if (rr3 == 0) 59955107Storek continue; 60055107Storek intflags |= 2; /* took an interrupt */ 60155107Storek if (rr3 & ZSRR3_IP_A_RX) 60255107Storek intflags |= zsrint(a); 60355107Storek if (rr3 & ZSRR3_IP_B_RX) 60455107Storek intflags |= zsrint(b); 60555107Storek if (rr3 & ZSRR3_IP_A_TX) 60655107Storek intflags |= zsxint(a); 60755107Storek if (rr3 & ZSRR3_IP_B_TX) 60855107Storek intflags |= zsxint(b); 60955107Storek if (rr3 & ZSRR3_IP_A_STAT) 61055107Storek intflags |= zssint(a); 61155107Storek if (rr3 & ZSRR3_IP_B_STAT) 61255107Storek intflags |= zssint(b); 61355107Storek } 61455107Storek #undef b 61555107Storek if (intflags & 1) { 61655107Storek #if sun4c /* XXX -- but this will go away when zshard moves to locore.s */ 61755107Storek struct clockframe *p = intrarg; 61855107Storek 61955107Storek if ((p->psr & PSR_PIL) < (PIL_TTY << 8)) { 62055107Storek (void) spltty(); 62155107Storek return (zssoft(intrarg)); 62255107Storek } 62355107Storek #endif 62455107Storek ienab_bis(IE_ZSSOFT); 62555107Storek } 62655107Storek return (intflags & 2); 62755107Storek } 62855107Storek 62955107Storek static int 63055107Storek zsrint(register struct zs_chanstate *cs) 63155107Storek { 63255107Storek register volatile struct zschan *zc = cs->cs_zc; 63355107Storek register int c = zc->zc_data, i; 63455107Storek 63555107Storek 63655107Storek if (cs->cs_conk) { 63755107Storek register struct conk_state *conk = &zsconk_state; 63855107Storek 63955107Storek /* 64055107Storek * Check here for console abort function, so that we 64155107Storek * can abort even when interrupts are locking up the 64255107Storek * machine. 64355107Storek */ 64455107Storek if (c == KBD_RESET) { 64555107Storek conk->conk_id = 1; /* ignore next byte */ 64655107Storek conk->conk_l1 = 0; 64755107Storek } else if (conk->conk_id) 64855107Storek conk->conk_id = 0; /* stop ignoring bytes */ 64955107Storek else if (c == KBD_L1) 65055107Storek conk->conk_l1 = 1; /* L1 went down */ 65155107Storek else if (c == (KBD_L1|KBD_UP)) 65255107Storek conk->conk_l1 = 0; /* L1 went up */ 65355107Storek else if (c == KBD_A && conk->conk_l1) { 65455107Storek zsabort(); 65555107Storek conk->conk_l1 = 0; /* we never see the up */ 65655107Storek goto clearit; /* eat the A after L1-A */ 65755107Storek } 65855107Storek } 65955107Storek #ifdef KGDB 66055107Storek if (c == FRAME_START && cs->cs_kgdb && 66155107Storek (cs->cs_ttyp->t_state & TS_ISOPEN) == 0) { 66255107Storek zskgdb(cs->cs_unit); 66355107Storek goto clearit; 66455107Storek } 66555107Storek #endif 66655107Storek /* store receive character and status into ring */ 66755107Storek i = cs->cs_rbput; 66855107Storek cs->cs_rbput = i + 1; 66955107Storek c <<= 8; 67055107Storek c |= ZS_READ(zc, 1); 67155107Storek cs->cs_rbuf[i & ZLRB_RING_MASK] = c; 67255107Storek 67355107Storek /* clear receive error & interrupt condition */ 67455107Storek zc->zc_csr = ZSWR0_RESET_ERRORS; 67555107Storek zc->zc_csr = ZSWR0_CLR_INTR; 67655107Storek return (1); 67755107Storek 67855107Storek clearit: 67955107Storek zc->zc_csr = ZSWR0_RESET_ERRORS; 68055107Storek zc->zc_csr = ZSWR0_CLR_INTR; 68155107Storek return (0); 68255107Storek } 68355107Storek 68455107Storek static int 68555107Storek zsxint(register struct zs_chanstate *cs) 68655107Storek { 68755107Storek register volatile struct zschan *zc = cs->cs_zc; 68855107Storek register int c, i = cs->cs_tbc; 68955107Storek 69055107Storek if (i == 0) { 69155107Storek zc->zc_csr = ZSWR0_RESET_TXINT; 69255107Storek zc->zc_csr = ZSWR0_CLR_INTR; 69355107Storek cs->cs_txint = 1; 69455107Storek return (1); 69555107Storek } 69655107Storek cs->cs_tbc = i - 1; 69755107Storek zc->zc_data = *cs->cs_tba++; 69855107Storek zc->zc_csr = ZSWR0_CLR_INTR; 69955107Storek return (0); 70055107Storek } 70155107Storek 70255107Storek static int 70355107Storek zssint(register struct zs_chanstate *cs) 70455107Storek { 70555107Storek register volatile struct zschan *zc = cs->cs_zc; 70655107Storek register int i; 70755107Storek 70855107Storek i = zc->zc_csr; 70955107Storek zc->zc_csr = ZSWR0_RESET_STATUS; 71055107Storek zc->zc_csr = ZSWR0_CLR_INTR; 71155107Storek if ((i & ZSRR0_BREAK) && cs->cs_brkabort) 71255107Storek zsabort(); 71355107Storek else if (! cs->cs_softcar) { 71455107Storek cs->cs_rr0 = i | 0x100; 71555107Storek return (1); 71655107Storek } 71755107Storek return (0); 71855107Storek } 71955107Storek 72055107Storek zsabort() 72155107Storek { 72255107Storek 72355107Storek printf("stopping on keyboard abort\n"); 72455107Storek callrom(); 72555107Storek } 72655107Storek 72755107Storek #ifdef KGDB 72855107Storek /* 72955107Storek * KGDB framing character received: enter kernel debugger. This probably 73055107Storek * should time out after a few seconds to avoid hanging on spurious input. 73155107Storek */ 73255107Storek zskgdb(int unit) 73355107Storek { 73455107Storek 73555107Storek printf("zs%d%c: kgdb interrupt\n", unit >> 1, (unit & 1) + 'a'); 73655107Storek kgdb_connect(1); 73755107Storek } 73855107Storek #endif 73955107Storek 74055107Storek /* 74155107Storek * Print out a ring or fifo overrun error message. 74255107Storek */ 74355107Storek static void 74455107Storek zsoverrun(int unit, long *ptime, char *what) 74555107Storek { 74655107Storek 74755107Storek if (*ptime != time.tv_sec) { 74855107Storek *ptime = time.tv_sec; 74955107Storek log(LOG_WARNING, "zs%d%c: input %s overrun\n", unit >> 1, 75055107Storek (unit & 1) + 'a', what); 75155107Storek } 75255107Storek } 75355107Storek 75455107Storek /* 75555107Storek * ZS software interrupt. Scan both ZS chips. 75655107Storek */ 75755107Storek int 75855107Storek zssoft(void *arg) 75955107Storek { 76055107Storek register struct zs_chanstate *cs; 76155107Storek register volatile struct zschan *zc; 76255107Storek register struct tty *tp; 76355107Storek register int get, n, c, cc, rr0, txint, unit, s; 76455107Storek 76555107Storek for (cs = zslist; cs; cs = cs->cs_next) { 76655107Storek unit = cs->cs_unit; 76755107Storek zc = cs->cs_zc; 76855107Storek tp = cs->cs_ttyp; 76955107Storek /* 77055107Storek * Scan receive ring. This involves calling ttyinput(), 77155107Storek * which is quite slow, so we loop until we have caught 77255107Storek * up with the receiver. (XXX should test effectiveness) 77355107Storek * If we are not interested, discard the input right away. 77455107Storek * 77555107Storek * XXX this will have to be broken up so that we can get 77655107Storek * ^S stops out reasonably quickly.... 77755107Storek */ 77855107Storek for (;;) { 77955107Storek n = cs->cs_rbput; /* atomic */ 78055107Storek get = cs->cs_rbget; 78155107Storek if (get == n) 78255107Storek break; 78355107Storek /* 78455107Storek * Compute the number of characters in the receive 78555107Storek * ring; drain them. If the count is overlarge, we 78655107Storek * lost some receive data, and must advance to the 78755107Storek * first still-extant character. It may get 78855107Storek * overwritten if more data are arriving, but this 78955107Storek * is too expensive to check and gains nothing (we 79055107Storek * already lost out; all we can do at this point is 79155107Storek * trade one kind of loss for another). 79255107Storek * 79355107Storek * XXX should do flow control if ring is 79455107Storek * getting full ... needs more thought; will 79555107Storek * require locking against zshard(). 79655107Storek */ 79755107Storek n -= get; 79855107Storek if (n > ZLRB_RING_SIZE) { 79955107Storek zsoverrun(unit, &cs->cs_rotime, "ring"); 80055107Storek get += n - ZLRB_RING_SIZE; 80155107Storek n = ZLRB_RING_SIZE; 80255107Storek } 80355107Storek while (--n >= 0) { 80455107Storek /* race to keep ahead of incoming data */ 80555107Storek c = cs->cs_rbuf[get++ & ZLRB_RING_MASK]; 80655107Storek if (c & ZSRR1_DO) 80755107Storek zsoverrun(unit, &cs->cs_fotime, "fifo"); 80855107Storek cc = c >> 8; 80955107Storek if (c & ZSRR1_FE) 81055107Storek cc |= TTY_FE; 81155107Storek if (c & ZSRR1_PE) 81255107Storek cc |= TTY_PE; 81355107Storek /* 81455107Storek * this should be done through 81555107Storek * bstreams XXX gag choke 81655107Storek */ 81755107Storek if (unit == ZS_KBD) 81855107Storek kbd_rint(cc); 81955107Storek else if (unit == ZS_MOUSE) 82055107Storek ms_rint(cc); 82155107Storek else 82255107Storek (*linesw[tp->t_line].l_rint)(cc, tp); 82355107Storek } 82455107Storek cs->cs_rbget = get; 82555107Storek } 82655107Storek check_xmit: 82755107Storek /* 82855107Storek * Atomically get and clear transmit and status change 82955107Storek * interrupts. 83055107Storek */ 83155107Storek s = splzs(); 83255107Storek txint = cs->cs_txint; 83355107Storek rr0 = cs->cs_rr0; 83455107Storek if (txint) 83555107Storek cs->cs_txint = 0; 83655107Storek if (rr0 & 0x100) 83755107Storek cs->cs_rr0 = rr0 & 255; 83855107Storek splx(s); 83955107Storek 84055107Storek /* 84155107Storek * Check for status changes. If carrier has changed, 84255107Storek * and we want CTS output flow control, we have to fiddle 84355107Storek * the HFC bit (see zsparam). If carrier is gone, and 84455107Storek * linesw l_modem returns 0, drop DTR. 84555107Storek */ 84655107Storek if (rr0 & 0x100) { 84755107Storek if (rr0 & ZSRR0_DCD) { 84855107Storek (void) splzs(); 84955107Storek if (tp->t_cflag & CCTS_OFLOW && 85055107Storek (cs->cs_creg[3] & ZSWR3_HFC) == 0) { 85155107Storek cs->cs_creg[3] |= ZSWR3_HFC; 85255107Storek ZS_WRITE(zc, 3, cs->cs_creg[3]); 85355107Storek } 85455107Storek splx(s); 85555107Storek (void) (*linesw[tp->t_line].l_modem)(tp, 1); 85655107Storek } else { 85755107Storek (void) splzs(); 85855107Storek if (cs->cs_creg[3] & ZSWR3_HFC) { 85955107Storek cs->cs_creg[3] &= ~ZSWR3_HFC; 86055107Storek ZS_WRITE(zc, 3, cs->cs_creg[3]); 86155107Storek } 86255107Storek splx(s); 86355107Storek if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) 86455107Storek zs_modem(cs, 0); 86555107Storek } 86655107Storek } 86755107Storek 86855107Storek if (txint) { 86955107Storek /* 87055107Storek * Transmit done: change registers and resume 87155107Storek * or clear BUSY. 87255107Storek */ 87355107Storek if (cs->cs_heldchange) { 87455107Storek s = splzs(); 87555107Storek if ((rr0 & ZSRR0_DCD) == 0) 87655107Storek cs->cs_preg[3] &= ~ZSWR3_HFC; 87755107Storek bcopy((caddr_t)cs->cs_preg, 87855107Storek (caddr_t)cs->cs_creg, 16); 87955107Storek zs_loadchannelregs(cs->cs_zc, cs->cs_creg); 88055107Storek splx(s); 88155107Storek cs->cs_heldchange = 0; 88255107Storek if (cs->cs_heldtbc && 88355107Storek (tp->t_state & TS_TTSTOP) == 0) { 88455107Storek cs->cs_tbc = cs->cs_heldtbc - 1; 88555107Storek zc->zc_data = *cs->cs_tba++; 88655107Storek continue; 88755107Storek } 88855107Storek } 88955107Storek tp->t_state &= ~TS_BUSY; 89055107Storek if (tp->t_state & TS_FLUSH) 89155107Storek tp->t_state &= ~TS_FLUSH; 89255107Storek else 89355107Storek ndflush(&tp->t_outq, 89455107Storek cs->cs_tba - tp->t_outq.c_cf); 89555107Storek (*linesw[tp->t_line].l_start)(tp); 89655107Storek } 89755107Storek } 89855107Storek return (1); 89955107Storek } 90055107Storek 90155107Storek int 90255107Storek zsioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) 90355107Storek { 90455107Storek int unit = minor(dev); 90555107Storek struct zsinfo *zi = zscd.cd_devs[unit >> 1]; 90655107Storek register struct tty *tp = zi->zi_cs[unit & 1].cs_ttyp; 90755107Storek register int error; 90855107Storek 90955107Storek error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 91055107Storek if (error >= 0) 91155107Storek return (error); 91255107Storek error = ttioctl(tp, cmd, data, flag); 91355107Storek if (error >= 0) 91455107Storek return (error); 91555107Storek 91655107Storek switch (cmd) { 91755107Storek 91855107Storek case TIOCSBRK: 91955107Storek /* FINISH ME ... need implicit TIOCCBRK in zsclose as well */ 92055107Storek 92155107Storek case TIOCCBRK: 92255107Storek 92355107Storek case TIOCSDTR: 92455107Storek 92555107Storek case TIOCCDTR: 92655107Storek 92755107Storek case TIOCMSET: 92855107Storek 92955107Storek case TIOCMBIS: 93055107Storek 93155107Storek case TIOCMBIC: 93255107Storek 93355107Storek case TIOCMGET: 93455107Storek 93555107Storek default: 93655107Storek return (ENOTTY); 93755107Storek } 93855107Storek return (0); 93955107Storek } 94055107Storek 94155107Storek /* 94255107Storek * Start or restart transmission. 94355107Storek */ 94455107Storek static void 94555107Storek zsstart(register struct tty *tp) 94655107Storek { 94755107Storek register struct zs_chanstate *cs; 94855107Storek register int s, nch; 94955107Storek int unit = minor(tp->t_dev); 95055107Storek struct zsinfo *zi = zscd.cd_devs[unit >> 1]; 95155107Storek 95255107Storek cs = &zi->zi_cs[unit & 1]; 95355107Storek s = spltty(); 95455107Storek 95555107Storek /* 95655107Storek * If currently active or delaying, no need to do anything. 95755107Storek */ 95855107Storek if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) 95955107Storek goto out; 96055107Storek 96155107Storek /* 96255107Storek * If there are sleepers, and output has drained below low 96355107Storek * water mark, awaken. 96455107Storek */ 96555107Storek if (tp->t_outq.c_cc <= tp->t_lowat) { 96655107Storek if (tp->t_state & TS_ASLEEP) { 96755107Storek tp->t_state &= ~TS_ASLEEP; 96855107Storek wakeup((caddr_t)&tp->t_outq); 96955107Storek } 97055107Storek selwakeup(&tp->t_wsel); 97155107Storek } 97255107Storek 97355107Storek nch = ndqb(&tp->t_outq, 0); /* XXX */ 97455107Storek if (nch) { 97555107Storek register char *p = tp->t_outq.c_cf; 97655107Storek 97755107Storek /* mark busy, enable tx done interrupts, & send first byte */ 97855107Storek tp->t_state |= TS_BUSY; 97955107Storek (void) splzs(); 98055107Storek cs->cs_preg[1] |= ZSWR1_TIE; 98155107Storek cs->cs_creg[1] |= ZSWR1_TIE; 98255107Storek ZS_WRITE(cs->cs_zc, 1, cs->cs_creg[1]); 98355107Storek cs->cs_zc->zc_data = *p; 98455107Storek cs->cs_tba = p + 1; 98555107Storek cs->cs_tbc = nch - 1; 98655107Storek } else { 98755107Storek /* 98855107Storek * Nothing to send, turn off transmit done interrupts. 98955107Storek * This is useful if something is doing polled output. 99055107Storek */ 99155107Storek (void) splzs(); 99255107Storek cs->cs_preg[1] &= ~ZSWR1_TIE; 99355107Storek cs->cs_creg[1] &= ~ZSWR1_TIE; 99455107Storek ZS_WRITE(cs->cs_zc, 1, cs->cs_creg[1]); 99555107Storek } 99655107Storek out: 99755107Storek splx(s); 99855107Storek } 99955107Storek 100055107Storek /* 100155107Storek * Stop output, e.g., for ^S or output flush. 100255107Storek */ 100355107Storek static void 100455107Storek zsstop(register struct tty *tp, int flag) 100555107Storek { 100655107Storek register struct zs_chanstate *cs; 100755107Storek register int s, unit = minor(tp->t_dev); 100855107Storek struct zsinfo *zi = zscd.cd_devs[unit >> 1]; 100955107Storek 101055107Storek cs = &zi->zi_cs[unit & 1]; 101155107Storek s = splzs(); 101255107Storek if (tp->t_state & TS_BUSY) { 101355107Storek /* 101455107Storek * Device is transmitting; must stop it. 101555107Storek */ 101655107Storek cs->cs_tbc = 0; 101755107Storek if ((tp->t_state & TS_TTSTOP) == 0) 101855107Storek tp->t_state |= TS_FLUSH; 101955107Storek } 102055107Storek splx(s); 102155107Storek } 102255107Storek 102355107Storek /* 102455107Storek * Set ZS tty parameters from termios. 102555107Storek * 102655107Storek * This routine makes use of the fact that only registers 102755107Storek * 1, 3, 4, 5, 9, 10, 11, 12, 13, 14, and 15 are written. 102855107Storek */ 102955107Storek static int 103055107Storek zsparam(register struct tty *tp, register struct termios *t) 103155107Storek { 103255107Storek int unit = minor(tp->t_dev); 103355107Storek struct zsinfo *zi = zscd.cd_devs[unit >> 1]; 103455107Storek register struct zs_chanstate *cs = &zi->zi_cs[unit & 1]; 103555107Storek register int tmp, tmp5, cflag, s; 103655107Storek 103755107Storek /* 103855107Storek * Because PCLK is only run at 4.9 MHz, the fastest we 103955107Storek * can go is 51200 baud (this corresponds to TC=1). 104055107Storek * This is somewhat unfortunate as there is no real 104155107Storek * reason we should not be able to handle higher rates. 104255107Storek */ 104355107Storek tmp = t->c_ospeed; 104455107Storek if (tmp < 0 || (t->c_ispeed && t->c_ispeed != tmp)) 104555107Storek return (EINVAL); 104655107Storek if (tmp == 0) { 104755107Storek /* stty 0 => drop DTR and RTS */ 104855107Storek zs_modem(cs, 0); 104955107Storek return (0); 105055107Storek } 105155107Storek tmp = BPS_TO_TCONST(PCLK / 16, tmp); 105255107Storek if (tmp < 2) 105355107Storek return (EINVAL); 105455107Storek 105555107Storek cflag = t->c_cflag; 105655107Storek tp->t_ispeed = tp->t_ospeed = TCONST_TO_BPS(PCLK / 16, tmp); 105755107Storek tp->t_cflag = cflag; 105855107Storek 105955107Storek /* 106055107Storek * Block interrupts so that state will not 106155107Storek * be altered until we are done setting it up. 106255107Storek */ 106355107Storek s = splzs(); 106455107Storek cs->cs_preg[12] = tmp; 106555107Storek cs->cs_preg[13] = tmp >> 8; 106655107Storek cs->cs_preg[1] = ZSWR1_RIE | ZSWR1_TIE | ZSWR1_SIE; 106755107Storek switch (cflag & CSIZE) { 106855107Storek case CS5: 106955107Storek tmp = ZSWR3_RX_5; 107055107Storek tmp5 = ZSWR5_TX_5; 107155107Storek break; 107255107Storek case CS6: 107355107Storek tmp = ZSWR3_RX_6; 107455107Storek tmp5 = ZSWR5_TX_6; 107555107Storek break; 107655107Storek case CS7: 107755107Storek tmp = ZSWR3_RX_7; 107855107Storek tmp5 = ZSWR5_TX_7; 107955107Storek break; 108055107Storek case CS8: 108155107Storek default: 108255107Storek tmp = ZSWR3_RX_8; 108355107Storek tmp5 = ZSWR5_TX_8; 108455107Storek break; 108555107Storek } 108655107Storek 108755107Storek /* 108855107Storek * Output hardware flow control on the chip is horrendous: if 108955107Storek * carrier detect drops, the receiver is disabled. Hence we 109055107Storek * can only do this when the carrier is on. 109155107Storek */ 109255107Storek if (cflag & CCTS_OFLOW && cs->cs_zc->zc_csr & ZSRR0_DCD) 109355107Storek tmp |= ZSWR3_HFC | ZSWR3_RX_ENABLE; 109455107Storek else 109555107Storek tmp |= ZSWR3_RX_ENABLE; 109655107Storek cs->cs_preg[3] = tmp; 109755107Storek cs->cs_preg[5] = tmp5 | ZSWR5_TX_ENABLE | ZSWR5_DTR | ZSWR5_RTS; 109855107Storek 109955107Storek tmp = ZSWR4_CLK_X16 | (cflag & CSTOPB ? ZSWR4_TWOSB : ZSWR4_ONESB); 110055107Storek if ((cflag & PARODD) == 0) 110155107Storek tmp |= ZSWR4_EVENP; 110255107Storek if (cflag & PARENB) 110355107Storek tmp |= ZSWR4_PARENB; 110455107Storek cs->cs_preg[4] = tmp; 110555107Storek cs->cs_preg[9] = ZSWR9_MASTER_IE | ZSWR9_NO_VECTOR; 110655107Storek cs->cs_preg[10] = ZSWR10_NRZ; 110755107Storek cs->cs_preg[11] = ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD; 110855107Storek cs->cs_preg[14] = ZSWR14_BAUD_FROM_PCLK | ZSWR14_BAUD_ENA; 110955107Storek cs->cs_preg[15] = ZSWR15_BREAK_IE | ZSWR15_DCD_IE; 111055107Storek 111155107Storek /* 111255107Storek * If nothing is being transmitted, set up new current values, 111355107Storek * else mark them as pending. 111455107Storek */ 111555107Storek if (cs->cs_heldchange == 0) { 111655107Storek if (cs->cs_ttyp->t_state & TS_BUSY) { 111755107Storek cs->cs_heldtbc = cs->cs_tbc; 111855107Storek cs->cs_tbc = 0; 111955107Storek cs->cs_heldchange = 1; 112055107Storek } else { 112155107Storek bcopy((caddr_t)cs->cs_preg, (caddr_t)cs->cs_creg, 16); 112255107Storek zs_loadchannelregs(cs->cs_zc, cs->cs_creg); 112355107Storek } 112455107Storek } 112555107Storek splx(s); 112655107Storek return (0); 112755107Storek } 112855107Storek 112955107Storek /* 113055107Storek * Raise or lower modem control (DTR/RTS) signals. If a character is 113155107Storek * in transmission, the change is deferred. 113255107Storek */ 113355107Storek static void 113455107Storek zs_modem(struct zs_chanstate *cs, int onoff) 113555107Storek { 113655107Storek int s, bis, and; 113755107Storek 113855107Storek if (onoff) { 113955107Storek bis = ZSWR5_DTR | ZSWR5_RTS; 114055107Storek and = ~0; 114155107Storek } else { 114255107Storek bis = 0; 114355107Storek and = ~(ZSWR5_DTR | ZSWR5_RTS); 114455107Storek } 114555107Storek s = splzs(); 114655107Storek cs->cs_preg[5] = (cs->cs_preg[5] | bis) & and; 114755107Storek if (cs->cs_heldchange == 0) { 114855107Storek if (cs->cs_ttyp->t_state & TS_BUSY) { 114955107Storek cs->cs_heldtbc = cs->cs_tbc; 115055107Storek cs->cs_tbc = 0; 115155107Storek cs->cs_heldchange = 1; 115255107Storek } else { 115355107Storek cs->cs_creg[5] = (cs->cs_creg[5] | bis) & and; 115455107Storek ZS_WRITE(cs->cs_zc, 5, cs->cs_creg[5]); 115555107Storek } 115655107Storek } 115755107Storek splx(s); 115855107Storek } 115955107Storek 116055107Storek /* 116155107Storek * Write the given register set to the given zs channel in the proper order. 116255107Storek * The channel must not be transmitting at the time. The receiver will 116355107Storek * be disabled for the time it takes to write all the registers. 116455107Storek */ 116555107Storek static void 116655107Storek zs_loadchannelregs(volatile struct zschan *zc, u_char *reg) 116755107Storek { 116855107Storek int i; 116955107Storek 117055107Storek zc->zc_csr = ZSM_RESET_ERR; /* reset error condition */ 117155107Storek i = zc->zc_data; /* drain fifo */ 117255107Storek i = zc->zc_data; 117355107Storek i = zc->zc_data; 117455107Storek ZS_WRITE(zc, 4, reg[4]); 117555107Storek ZS_WRITE(zc, 10, reg[10]); 117655107Storek ZS_WRITE(zc, 3, reg[3] & ~ZSWR3_RX_ENABLE); 117755107Storek ZS_WRITE(zc, 5, reg[5] & ~ZSWR5_TX_ENABLE); 117855107Storek ZS_WRITE(zc, 1, reg[1]); 117955107Storek ZS_WRITE(zc, 9, reg[9]); 118055107Storek ZS_WRITE(zc, 11, reg[11]); 118155107Storek ZS_WRITE(zc, 12, reg[12]); 118255107Storek ZS_WRITE(zc, 13, reg[13]); 118355107Storek ZS_WRITE(zc, 14, reg[14]); 118455107Storek ZS_WRITE(zc, 15, reg[15]); 118555107Storek ZS_WRITE(zc, 3, reg[3]); 118655107Storek ZS_WRITE(zc, 5, reg[5]); 118755107Storek } 118855107Storek 118955107Storek #ifdef KGDB 119055107Storek /* 119155107Storek * Get a character from the given kgdb channel. Called at splhigh(). 119255107Storek */ 119355107Storek static int 119455107Storek zs_kgdb_getc(void *arg) 119555107Storek { 119655107Storek register volatile struct zschan *zc = (volatile struct zschan *)arg; 119755107Storek 119855107Storek while ((zc->zc_csr & ZSRR0_RX_READY) == 0) 119955107Storek continue; 120055107Storek return (zc->zc_data); 120155107Storek } 120255107Storek 120355107Storek /* 120455107Storek * Put a character to the given kgdb channel. Called at splhigh(). 120555107Storek */ 120655107Storek static void 120755107Storek zs_kgdb_putc(void *arg, int c) 120855107Storek { 120955107Storek register volatile struct zschan *zc = (volatile struct zschan *)arg; 121055107Storek 121155107Storek while ((zc->zc_csr & ZSRR0_TX_READY) == 0) 121255107Storek continue; 121355107Storek zc->zc_data = c; 121455107Storek } 121555107Storek 121655107Storek /* 121755107Storek * Set up for kgdb; called at boot time before configuration. 121855107Storek * KGDB interrupts will be enabled later when zs0 is configured. 121955107Storek */ 122055107Storek void 122155107Storek zs_kgdb_init() 122255107Storek { 122355107Storek volatile struct zsdevice *addr; 122455107Storek volatile struct zschan *zc; 122555107Storek int unit, zs; 122655107Storek 122755107Storek if (major(kgdb_dev) != ZSMAJOR) 122855107Storek return; 122955107Storek unit = minor(kgdb_dev); 123055107Storek /* 123155107Storek * Unit must be 0 or 1 (zs0). 123255107Storek */ 123355107Storek if ((unsigned)unit >= ZS_KBD) { 123455107Storek printf("zs_kgdb_init: bad minor dev %d\n", unit); 123555107Storek return; 123655107Storek } 123755107Storek zs = unit >> 1; 123855107Storek if ((addr = zsaddr[zs]) == NULL) 123955107Storek addr = zsaddr[zs] = findzs(zs); 124055107Storek unit &= 1; 124155107Storek zc = unit == 0 ? &addr->zs_chan[CHAN_A] : &addr->zs_chan[CHAN_B]; 124255107Storek zs_kgdb_savedspeed = zs_getspeed(zc); 124355107Storek printf("zs_kgdb_init: attaching zs%d%c at %d baud\n", 124455107Storek zs, unit + 'a', kgdb_rate); 124555107Storek zs_reset(zc, 1, kgdb_rate); 124655107Storek kgdb_attach(zs_kgdb_getc, zs_kgdb_putc, (void *)zc); 124755107Storek } 124855107Storek #endif /* KGDB */ 1249