From: deraadt Date: Tue, 24 Dec 1996 20:31:23 +0000 (+0000) Subject: nearly working driver for wglen serial card X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=33e67c4ccdf923c97a673ff2a3396e2459465a69;p=openbsd nearly working driver for wglen serial card --- diff --git a/sys/arch/mvme68k/dev/wl.c b/sys/arch/mvme68k/dev/wl.c new file mode 100644 index 00000000000..200dac6ad28 --- /dev/null +++ b/sys/arch/mvme68k/dev/wl.c @@ -0,0 +1,1788 @@ +/* $OpenBSD: wl.c,v 1.1 1996/12/24 20:31:23 deraadt Exp $ */ + +/* + * Copyright (c) 1995 Dale Rahn. All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Dale Rahn. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* DMA mode still does not work!!! */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* #include */ +#include +#include +#include +#include +#include +#include "cl.h" + +#include "vmes.h" + +#define splcl() spl4() + +/* min timeout 0xa, what is a good value */ +#define CL_TIMEOUT 0x10 +#define CL_FIFO_MAX 0x10 +#define CL_FIFO_CNT 0xc +#define CL_RX_TIMEOUT 0x10 + +#define CL_RXDMAINT 0x82 +#define CL_TXDMAINT 0x42 +#define CL_TXMASK 0x47 +#define CL_RXMASK 0x87 +#define CL_TXINTR 0x02 +#define CL_RXINTR 0x02 + +#define WLRAMLEN (1 << 16) +struct clboard { + union { + struct clreg clreg; + char xx[256]; + } chips[2]; + union { + u_char base; + char xx[256]; + } sram; + union { + u_char val; + char xx[256]; + } ringstatus; + union { + u_char val; + char xx[256]; + } ringreset; + union { + u_char val; + char xx[256]; + } master; + union { + u_char val; + char xx[256]; + } reset; +}; + + +struct cl_info { + struct tty *tty; + u_char cl_swflags; + u_char cl_softchar; + u_char cl_speed; + u_char cl_parstop; /* parity, stop bits. */ + u_char cl_rxmode; + u_char cl_txmode; + u_char cl_clen; + u_char cl_parity; + u_char transmitting; + u_long txcnt; + u_long rxcnt; + + void *rx[2]; + void *rxp[2]; + void *tx[2]; + void *txp[2]; +}; +#define CLCD_PORTS_PER_CHIP 4 +#define CL_BUFSIZE 256 + +#ifndef DO_MALLOC +/* four (4) buffers per port */ +char cl_dmabuf [2 * CLCD_PORTS_PER_CHIP * CL_BUFSIZE * 4]; +#endif + +struct wlsoftc { + struct device sc_dev; + struct evcnt sc_txintrcnt; + struct evcnt sc_rxintrcnt; + struct evcnt sc_mxintrcnt; + + time_t sc_rotime; /* time of last ring overrun */ + time_t sc_fotime; /* time of last fifo overrun */ + + u_char sc_memv; + void *sc_memvme; + void *sc_memp; + void *sc_memkv; + + struct clreg *cl_reg; + struct cl_info sc_cl[CLCD_PORTS_PER_CHIP]; + struct intrhand sc_ih_e; + struct intrhand sc_ih_m; + struct intrhand sc_ih_t; + struct intrhand sc_ih_r; + struct vme2reg *sc_vme2; + u_char sc_vec; + int sc_flags; +}; +struct { + u_int speed; + u_char divisor; + u_char clock; + u_char rx_timeout; +} cl_clocks[] = { + { 64000, 0x26, 0, 0x01}, + { 56000, 0x2c, 0, 0x01}, + { 38400, 0x40, 0, 0x01}, + { 19200, 0x81, 0, 0x02}, + { 9600, 0x40, 1, 0x04}, + { 7200, 0x56, 1, 0x04}, + { 4800, 0x81, 1, 0x08}, + { 3600, 0xad, 1, 0x08}, + { 2400, 0x40, 2, 0x10}, + { 1200, 0x81, 2, 0x20}, + { 600, 0x40, 3, 0x40}, + { 300, 0x81, 3, 0x80}, + { 150, 0x40, 3, 0x80}, + { 110, 0x58, 4, 0xff}, + { 50, 0xC2, 4, 0xff}, + { 0, 0x00, 0, 0}, +}; + +/* prototypes */ +u_char cl_clkdiv __P((int speed)); +u_char cl_clknum __P((int speed)); +u_char cl_clkrxtimeout __P((int speed)); +void clstart __P((struct tty *tp)); +void cl_unblock __P((struct tty *tp)); +int clccparam __P((struct wlsoftc *sc, struct termios *par, int channel)); + +int clparam __P((struct tty *tp, struct termios *t)); +int cl_mintr __P((struct wlsoftc *sc)); +int cl_txintr __P((struct wlsoftc *sc)); +int cl_rxintr __P((struct wlsoftc *sc)); +void cl_overflow __P((struct wlsoftc *sc, int channel, long *ptime, u_char *msg)); +void cl_parity __P((struct wlsoftc *sc, int channel)); +void cl_frame __P((struct wlsoftc *sc, int channel)); +void cl_break __P(( struct wlsoftc *sc, int channel)); +int clmctl __P((dev_t dev, int bits, int how)); +void cl_dumpport __P((int channel)); + +int wlprobe __P((struct device *parent, void *self, void *aux)); +void wlattach __P((struct device *parent, struct device *self, void *aux)); + +int wlopen __P((dev_t dev, int flag, int mode, struct proc *p)); +int wlclose __P((dev_t dev, int flag, int mode, struct proc *p)); +int wlread __P((dev_t dev, struct uio *uio, int flag)); +int wlwrite __P((dev_t dev, struct uio *uio, int flag)); +int wlioctl __P((dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)); +int wlstop __P((struct tty *tp, int flag)); + +static void cl_initchannel __P((struct wlsoftc *sc, int channel)); +static void clputc __P((struct wlsoftc *sc, int unit, u_char c)); +static u_char clgetc __P((struct wlsoftc *sc, int *channel)); +static void cloutput __P( (struct tty *tp)); + +struct cfattach wl_ca = { + sizeof(struct wlsoftc), wlprobe, wlattach +}; + +struct cfdriver wl_cd = { + NULL, "wl", DV_TTY, 0 +}; + +#define CLCDBUF 80 + +#define CL_UNIT(x) (minor(x) >> 2) +#define CL_CHANNEL(x) (minor(x) & 3) +#define CL_TTY(x) (minor(x)) + +extern int cputyp; + +struct tty * +wltty(dev) + dev_t dev; +{ + int unit = CL_UNIT(dev); + int channel; + struct wlsoftc *sc; + + if (unit >= wl_cd.cd_ndevs || + (sc = (struct wlsoftc *) wl_cd.cd_devs[unit]) == NULL) + return (NULL); + channel = CL_CHANNEL(dev); + return sc->sc_cl[channel].tty; +} + +int +wlprobe(parent, self, aux) + struct device *parent; + void *self; + void *aux; +{ + struct confargs *ca = aux; + struct wlsoftc *sc = self; + struct clreg *cl_reg = (struct clreg *)ca->ca_vaddr; + + if (ca->ca_vec & 0x03) { + printf("%s: bad vector\n", sc->sc_dev.dv_xname); + return (0); + } + return (!badvaddr(&cl_reg->cl_gfrcr, 1)); +} + +void +wlattach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + struct wlsoftc *sc = (struct wlsoftc *)self; + struct confargs *ca = aux; + struct clboard *clb = (struct clboard *)ca->ca_vaddr; + void *p; + int i, j; + + sc->cl_reg = (struct clreg *)&clb->chips[0].clreg; + sc->sc_vme2 = ca->ca_master; + sc->sc_vec = ca->ca_vec; + + sc->sc_memv = 0xa5 + 0; + sc->sc_memvme = (void *)((0xff00 + sc->sc_memv) << 16); + + clb->reset.val = 0xff; /* reset card */ + DELAY(1000); + clb->sram.base = ((u_int)sc->sc_memvme >> 16) & 0xff; + DELAY(1000); + clb->master.val = 0x01; /* enable sram decoder */ + DELAY(1000); + + printf(": va=%x sc=%x slot 0x%02x vmes 0x%08x ", sc->cl_reg, sc, + sc->sc_memv, sc->sc_memvme); + + while (sc->cl_reg->cl_gfrcr == 0x00) + ; + sc->cl_reg->cl_ccr = 0x10; /* reset it */ + while (sc->cl_reg->cl_gfrcr == 0x00) + ; + printf("rev %02x\n", sc->cl_reg->cl_gfrcr); + + /* set up global registers */ + sc->cl_reg->cl_tpr = CL_TIMEOUT; + sc->cl_reg->cl_rpilr = (ca->ca_ipl << 1) | 1; + sc->cl_reg->cl_tpilr = (ca->ca_ipl << 1) | 1; + sc->cl_reg->cl_mpilr = (ca->ca_ipl << 1) | 1; + + sc->sc_memkv = vmemap(((struct vmessoftc *)parent)->sc_vme, + sc->sc_memvme, WLRAMLEN, BUS_VMES); + sc->sc_memp = (void *)kvtop(sc->sc_memkv); + if (sc->sc_memkv == NULL) + printf("%s: got no memory", sc->sc_dev.dv_xname); + else if (badvaddr(sc->sc_memkv, 1)) + printf("%s: cannot tap 0x%08x", sc->sc_dev.dv_xname, sc->sc_memkv); + else { + u_char *x = sc->sc_memkv; + + printf("%s: pa 0x%08x va 0x%08x", sc->sc_dev.dv_xname, + sc->sc_memp, sc->sc_memkv); + printf(" tap"); + x[0] = 0xaa; + x[1] = 0x55; + printf(" 0x%02x 0x%02x", x[0], x[1]); + x[0] = 0x55; + x[1] = 0xaa; + printf(" 0x%02x 0x%02x", x[0], x[1]); + printf(" neato"); + + bzero(x, WLRAMLEN); + printf(" zero\n"); + } + + /* enable interrupts */ + sc->sc_ih_e.ih_fn = cl_rxintr; + sc->sc_ih_e.ih_arg = sc; + sc->sc_ih_e.ih_ipl = ca->ca_ipl; + sc->sc_ih_e.ih_wantframe = 0; + + sc->sc_ih_m.ih_fn = cl_mintr; + sc->sc_ih_m.ih_arg = sc; + sc->sc_ih_m.ih_ipl = ca->ca_ipl; + sc->sc_ih_m.ih_wantframe = 0; + + sc->sc_ih_t.ih_fn = cl_txintr; + sc->sc_ih_t.ih_arg = sc; + sc->sc_ih_t.ih_ipl = ca->ca_ipl; + sc->sc_ih_t.ih_wantframe = 0; + + sc->sc_ih_r.ih_fn = cl_rxintr; + sc->sc_ih_r.ih_arg = sc; + sc->sc_ih_r.ih_ipl = ca->ca_ipl; + sc->sc_ih_r.ih_wantframe = 0; + + vmeintr_establish(ca->ca_vec + 0, &sc->sc_ih_e); + vmeintr_establish(ca->ca_vec + 1, &sc->sc_ih_m); + vmeintr_establish(ca->ca_vec + 2, &sc->sc_ih_t); + vmeintr_establish(ca->ca_vec + 3, &sc->sc_ih_r); + + evcnt_attach(&sc->sc_dev, "intr", &sc->sc_txintrcnt); + evcnt_attach(&sc->sc_dev, "intr", &sc->sc_rxintrcnt); + evcnt_attach(&sc->sc_dev, "intr", &sc->sc_mxintrcnt); + +#if 1 + p = sc->sc_memkv; + for (i = 0; i < CLCD_PORTS_PER_CHIP; i++) { + for (j = 0; j < 2; j++) { + sc->sc_cl[i].rx[j] = p; + sc->sc_cl[i].rxp[j] = (void *)(p - sc->sc_memkv); + printf("%d:%d rx v %x p %x\n", + i, j, sc->sc_cl[i].rx[j], sc->sc_cl[i].rxp[j]); + p += CL_BUFSIZE; + } + for (j = 0; j < 2; j++) { + sc->sc_cl[i].tx[j] = p; + sc->sc_cl[i].txp[j] = (void *)(p - sc->sc_memkv); + printf("%d:%d tx v %x p %x\n", + i, j, sc->sc_cl[i].tx[j], sc->sc_cl[i].txp[j]); + p += CL_BUFSIZE; + } + cl_initchannel(sc, i); + } +#else + sc->sc_cl[0].rx[0] = sc->sc_memkv; + sc->sc_cl[0].rx[1] = (void *)(((int)sc->sc_cl[0].rx[0]) + CL_BUFSIZE); + sc->sc_cl[1].rx[0] = (void *)(((int)sc->sc_cl[0].rx[1]) + CL_BUFSIZE); + sc->sc_cl[1].rx[1] = (void *)(((int)sc->sc_cl[1].rx[0]) + CL_BUFSIZE); + + sc->sc_cl[2].rx[0] = (void *)(((int)sc->sc_cl[1].rx[1]) + CL_BUFSIZE); + sc->sc_cl[2].rx[1] = (void *)(((int)sc->sc_cl[2].rx[0]) + CL_BUFSIZE); + sc->sc_cl[3].rx[0] = (void *)(((int)sc->sc_cl[2].rx[1]) + CL_BUFSIZE); + sc->sc_cl[3].rx[1] = (void *)(((int)sc->sc_cl[3].rx[0]) + CL_BUFSIZE); + + sc->sc_cl[0].tx[0] = (void *)(((int)sc->sc_cl[3].rx[1]) + CL_BUFSIZE); + sc->sc_cl[0].tx[1] = (void *)(((int)sc->sc_cl[0].tx[0]) + CL_BUFSIZE); + sc->sc_cl[1].tx[0] = (void *)(((int)sc->sc_cl[0].tx[1]) + CL_BUFSIZE); + sc->sc_cl[1].tx[1] = (void *)(((int)sc->sc_cl[1].tx[0]) + CL_BUFSIZE); + + sc->sc_cl[2].tx[0] = (void *)(((int)sc->sc_cl[1].tx[1]) + CL_BUFSIZE); + sc->sc_cl[2].tx[1] = (void *)(((int)sc->sc_cl[2].tx[0]) + CL_BUFSIZE); + sc->sc_cl[3].tx[0] = (void *)(((int)sc->sc_cl[2].tx[1]) + CL_BUFSIZE); + sc->sc_cl[3].tx[1] = (void *)(((int)sc->sc_cl[3].tx[0]) + CL_BUFSIZE); + + for (i = 0; i < CLCD_PORTS_PER_CHIP; i++) { + for (j = 0; j < 2 ; j++) { + sc->sc_cl[i].rxp[j] = (void *)(sc->sc_cl[i].rx[j] - + sc->sc_memkv); + sc->sc_cl[i].txp[j] = (void *)(sc->sc_cl[i].tx[j] - + sc->sc_memkv); + printf("cl[%d].rxbuf[%d] %x p %x\n", + i, j, sc->sc_cl[i].rx[j], sc->sc_cl[i].rxp[j]); + printf("cl[%d].txbuf[%d] %x p %x\n", + i, j, sc->sc_cl[i].tx[j], sc->sc_cl[i].txp[j]); + } + cl_initchannel(sc, i); + } +#endif +} + +static void +cl_initchannel(sc, channel) + struct wlsoftc *sc; + int channel; +{ + int s; + struct clreg *cl_reg = sc->cl_reg; + + /* set up option registers */ + sc->sc_cl[channel].tty = NULL; + s = splhigh(); + cl_reg->cl_car = (u_char) channel; + cl_reg->cl_livr = sc->sc_vec; + cl_reg->cl_ier = 0x00; + cl_reg->cl_cmr = 0x02; + cl_reg->cl_cor1 = 0x17; + cl_reg->cl_cor2 = 0x00; + cl_reg->cl_cor3 = 0x02; + cl_reg->cl_cor4 = 0xec; + cl_reg->cl_cor5 = 0xec; + cl_reg->cl_cor6 = 0x00; + cl_reg->cl_cor7 = 0x00; + cl_reg->cl_schr1 = 0x00; + cl_reg->cl_schr2 = 0x00; + cl_reg->cl_schr3 = 0x00; + cl_reg->cl_schr4 = 0x00; + cl_reg->cl_scrl = 0x00; + cl_reg->cl_scrh = 0x00; + cl_reg->cl_lnxt = 0x00; + cl_reg->cl_rbpr = 0x40; /* 9600 */ + cl_reg->cl_rcor = 0x01; + cl_reg->cl_tbpr = 0x40; /* 9600 */ + cl_reg->cl_tcor = 0x01 << 5; + /* console port should be 0x88 already */ + cl_reg->cl_msvr_rts = 0x00; + cl_reg->cl_msvr_dtr = 0x00; + cl_reg->cl_rtprl = CL_RX_TIMEOUT; + cl_reg->cl_rtprh = 0x00; + sc->cl_reg->cl_ccr = 0x20; + while (sc->cl_reg->cl_ccr != 0) + ; + + splx(s); +} + + +int cldefaultrate = TTYDEF_SPEED; + +int clmctl (dev, bits, how) + dev_t dev; + int bits; + int how; +{ + int s; + struct wlsoftc *sc; + /* should only be called with valid device */ + sc = (struct wlsoftc *) wl_cd.cd_devs[CL_UNIT(dev)]; + /* + printf("mctl: dev %x, bits %x, how %x,\n",dev, bits, how); + */ + /* settings are currently ignored */ + s = splcl(); + switch (how) { + case DMSET: + if( bits & TIOCM_RTS) { + sc->cl_reg->cl_msvr_rts = 0x01; + } else { + sc->cl_reg->cl_msvr_rts = 0x00; + } + if( bits & TIOCM_DTR) { + sc->cl_reg->cl_msvr_dtr = 0x02; + } else { + sc->cl_reg->cl_msvr_dtr = 0x00; + } + break; + + case DMBIC: + if( bits & TIOCM_RTS) { + sc->cl_reg->cl_msvr_rts = 0x00; + } + if( bits & TIOCM_DTR) { + sc->cl_reg->cl_msvr_dtr = 0x00; + } + break; + + case DMBIS: + if( bits & TIOCM_RTS) { + sc->cl_reg->cl_msvr_rts = 0x01; + } + if( bits & TIOCM_DTR) { + sc->cl_reg->cl_msvr_dtr = 0x02; + } + break; + + case DMGET: + bits = 0; + + { + u_char msvr; + msvr = sc->cl_reg->cl_msvr_rts; + if( msvr & 0x80) { + bits |= TIOCM_DSR; + } + if( msvr & 0x40) { + bits |= TIOCM_CD; + } + if( msvr & 0x20) { + bits |= TIOCM_CTS; + } + if( msvr & 0x10) { + bits |= TIOCM_DTR; + } + if( msvr & 0x02) { + bits |= TIOCM_DTR; + } + if( msvr & 0x01) { + bits |= TIOCM_RTS; + } + + } + break; + } + (void)splx(s); +#if 0 + bits = 0; + /* proper defaults? */ + bits |= TIOCM_DTR; + bits |= TIOCM_RTS; + bits |= TIOCM_CTS; + bits |= TIOCM_CD; + /* bits |= TIOCM_RI; */ + bits |= TIOCM_DSR; +#endif + + /* + printf("retbits %x\n", bits); + */ + return(bits); +} + +int wlopen (dev, flag, mode, p) + dev_t dev; + int flag; + int mode; + struct proc *p; +{ + int s, unit, channel; + struct cl_info *cl; + struct wlsoftc *sc; + struct tty *tp; + + unit = CL_UNIT(dev); + if (unit >= wl_cd.cd_ndevs || + (sc = (struct wlsoftc *) wl_cd.cd_devs[unit]) == NULL) { + return (ENODEV); + } + channel = CL_CHANNEL(dev); + cl = &sc->sc_cl[channel]; + s = splcl(); + if (cl->tty) { + tp = cl->tty; + } else { + tp = cl->tty = ttymalloc(); + tty_attach(tp); + } + tp->t_oproc = clstart; + tp->t_param = clparam; + tp->t_dev = dev; + + if ((tp->t_state & TS_ISOPEN) == 0) { + tp->t_state |= TS_WOPEN; + ttychars(tp); + if (tp->t_ispeed == 0) { + /* + * only when cleared do we reset to defaults. + */ + tp->t_iflag = TTYDEF_IFLAG; + tp->t_oflag = TTYDEF_OFLAG; + tp->t_lflag = TTYDEF_LFLAG; + tp->t_ispeed = tp->t_ospeed = cldefaultrate; + + tp->t_cflag = TTYDEF_CFLAG; + } + /* + * do these all the time + */ + if (cl->cl_swflags & TIOCFLAG_CLOCAL) + tp->t_cflag |= CLOCAL; + if (cl->cl_swflags & TIOCFLAG_CRTSCTS) + tp->t_cflag |= CRTSCTS; + if (cl->cl_swflags & TIOCFLAG_MDMBUF) + tp->t_cflag |= MDMBUF; + clparam(tp, &tp->t_termios); + ttsetwater(tp); + + (void)clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMSET); +#ifdef XXX + if ((cl->cl_swflags & TIOCFLAG_SOFTCAR) || + (clmctl(dev, 0, DMGET) & TIOCM_CD)) { + tp->t_state |= TS_CARR_ON; + } else { + tp->t_state &= ~TS_CARR_ON; + } +#endif + tp->t_state |= TS_CARR_ON; + { + u_char save = sc->cl_reg->cl_car; + sc->cl_reg->cl_car = channel; + sc->cl_reg->cl_ier = 0x88; +#ifdef CL_DMA_WORKS + { + sc->cl_reg->cl_cmr = + /* CL_TXDMAINT | */ CL_RXDMAINT; + sc->cl_reg->cl_ier = 0xa8; + sc->cl_reg->cl_licr = 0x00; + } + sc->cl_reg->cl_arbadrl = + ((u_long)sc->sc_cl[channel].rxp[0]) & 0xffff; + sc->cl_reg->cl_arbadru = + ((u_long)sc->sc_cl[channel].rxp[0]) >> 16; + sc->cl_reg->cl_brbadrl = + ((u_long)sc->sc_cl[channel].rxp[1]) & 0xffff; + sc->cl_reg->cl_brbadru = + ((u_long)sc->sc_cl[channel].rxp[1]) >> 16; + sc->cl_reg->cl_atbadrl = + ((u_long)sc->sc_cl[channel].txp[0]) & 0xffff; + sc->cl_reg->cl_atbadru = + ((u_long)sc->sc_cl[channel].txp[0]) >> 16; + sc->cl_reg->cl_btbadrl = + ((u_long)sc->sc_cl[channel].txp[1]) & 0xffff; + sc->cl_reg->cl_btbadru = + ((u_long)sc->sc_cl[channel].txp[1]) >> 16; + sc->cl_reg->cl_arbcnt = CL_BUFSIZE; + sc->cl_reg->cl_brbcnt = CL_BUFSIZE; + sc->cl_reg->cl_arbsts = 0x01; + sc->cl_reg->cl_brbsts = 0x01; +if (channel == 2) { /* test one channel now */ + /* shift for tx DMA */ + /* no shift for rx DMA */ +#if 0 + /* tx only */ + sc->cl_reg->cl_licr = (CL_DMAMODE << 4); + sc->cl_reg->cl_cmr = 0x42; +#endif + /* rx only */ + sc->cl_reg->cl_licr = 0x00; + sc->cl_reg->cl_cmr = 0x82; +} + sc->cl_reg->cl_ccr = 0x20; + while (sc->cl_reg->cl_ccr != 0) + ; +#endif /* CL_DMA_WORKS */ + sc->cl_reg->cl_car = save; + } + } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { + splx(s); + return(EBUSY); + } +#ifdef XXX + /* + * if NONBLOCK requested, ignore carrier + */ + if (flag & O_NONBLOCK) + goto done; +#endif + + splx(s); + /* + * Reset the tty pointer, as there could have been a dialout + * use of the tty with a dialin open waiting. + */ + tp->t_dev = dev; +#ifdef DEBUG + cl_dumpport(channel); +#endif + return((*linesw[tp->t_line].l_open)(dev, tp)); +} +int clparam(tp, t) + struct tty *tp; + struct termios *t; +{ + int unit, channel; + struct wlsoftc *sc; + int s; + dev_t dev; + + dev = tp->t_dev; + unit = CL_UNIT(dev); + if (unit >= wl_cd.cd_ndevs || + (sc = (struct wlsoftc *) wl_cd.cd_devs[unit]) == NULL) { + return (ENODEV); + } + channel = CL_CHANNEL(dev); + tp->t_ispeed = t->c_ispeed; + tp->t_ospeed = t->c_ospeed; + tp->t_cflag = t->c_cflag; + clccparam(sc, t, channel); + s = splcl(); + cl_unblock(tp); + splx(s); + return 0; +} + +void cloutput(tp) + struct tty *tp; +{ + int cc, s, unit, cnt; + u_char *tptr; + int channel; + struct wlsoftc *sc; + dev_t dev; + u_char cl_obuffer[CLCDBUF+1]; + + dev = tp->t_dev; + unit = CL_UNIT(dev); + if (unit >= wl_cd.cd_ndevs || + (sc = (struct wlsoftc *) wl_cd.cd_devs[unit]) == NULL) { + return; + } + channel = CL_CHANNEL(dev); + + if ((tp->t_state & TS_ISOPEN) == 0) + return; + + s = splcl(); + cc = tp->t_outq.c_cc; + while (cc > 0) { +/*XXX*/ + cnt = min (CLCDBUF,cc); + cnt = q_to_b(&tp->t_outq, cl_obuffer, cnt); + if (cnt == 0) { + break; + } + for (tptr = cl_obuffer; tptr < &cl_obuffer[cnt]; tptr++) { + clputc(sc, channel, *tptr); + } + cc -= cnt; + } + splx(s); +} + +int wlclose (dev, flag, mode, p) + dev_t dev; + int flag; + int mode; + struct proc *p; +{ + int unit, channel; + struct tty *tp; + struct cl_info *cl; + struct wlsoftc *sc; + int s; + unit = CL_UNIT(dev); + if (unit >= wl_cd.cd_ndevs || + (sc = (struct wlsoftc *) wl_cd.cd_devs[unit]) == NULL) { + return (ENODEV); + } + channel = CL_CHANNEL(dev); + cl = &sc->sc_cl[channel]; + tp = cl->tty; + (*linesw[tp->t_line].l_close)(tp, flag); + + s = splcl(); + + sc->cl_reg->cl_car = channel; + if((tp->t_cflag & HUPCL) != 0) { + sc->cl_reg->cl_msvr_rts = 0x00; + sc->cl_reg->cl_msvr_dtr = 0x00; + sc->cl_reg->cl_ccr = 0x05; + } + + splx(s); + ttyclose(tp); + +#if 0 + cl->tty = NULL; +#endif +#ifdef DEBUG + cl_dumpport(channel); +#endif + + return 0; +} + +int wlread (dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + int unit, channel; + struct tty *tp; + struct cl_info *cl; + struct wlsoftc *sc; + unit = CL_UNIT(dev); + if (unit >= wl_cd.cd_ndevs || + (sc = (struct wlsoftc *) wl_cd.cd_devs[unit]) == NULL) { + return (ENODEV); + } + channel = CL_CHANNEL(dev); + cl = &sc->sc_cl[channel]; + tp = cl->tty; + if (!tp) + return ENXIO; + return((*linesw[tp->t_line].l_read)(tp, uio, flag)); +} +int wlwrite (dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + int unit, channel; + struct tty *tp; + struct cl_info *cl; + struct wlsoftc *sc; + unit = CL_UNIT(dev); + if (unit >= wl_cd.cd_ndevs || + (sc = (struct wlsoftc *) wl_cd.cd_devs[unit]) == NULL) { + return (ENODEV); + } + channel = CL_CHANNEL(dev); + cl = &sc->sc_cl[channel]; + tp = cl->tty; + if (!tp) + return ENXIO; + return((*linesw[tp->t_line].l_write)(tp, uio, flag)); +} +int wlioctl (dev, cmd, data, flag, p) + dev_t dev; + int cmd; + caddr_t data; + int flag; + struct proc *p; +{ + int error; + int unit, channel; + struct tty *tp; + struct cl_info *cl; + struct wlsoftc *sc; + unit = CL_UNIT(dev); + if (unit >= wl_cd.cd_ndevs || + (sc = (struct wlsoftc *) wl_cd.cd_devs[unit]) == NULL) { + return (ENODEV); + } + channel = CL_CHANNEL(dev); + cl = &sc->sc_cl[channel]; + tp = cl->tty; + if (!tp) + return ENXIO; + + error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); + if (error >= 0) + return(error); + + error = ttioctl(tp, cmd, data, flag, p); + if (error >= 0) + return(error); + + switch (cmd) { + case TIOCSBRK: + /* */ + break; + + case TIOCCBRK: + /* */ + break; + + case TIOCSDTR: + (void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS); + break; + + case TIOCCDTR: + (void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC); + break; + + case TIOCMSET: + (void) clmctl(dev, *(int *) data, DMSET); + break; + + case TIOCMBIS: + (void) clmctl(dev, *(int *) data, DMBIS); + break; + + case TIOCMBIC: + (void) clmctl(dev, *(int *) data, DMBIC); + break; + + case TIOCMGET: + *(int *)data = clmctl(dev, 0, DMGET); + break; + case TIOCGFLAGS: + *(int *)data = cl->cl_swflags; + break; + case TIOCSFLAGS: + error = suser(p->p_ucred, &p->p_acflag); + if (error != 0) + return(EPERM); + + cl->cl_swflags = *(int *)data; + cl->cl_swflags &= /* only allow valid flags */ + (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS); + break; + default: + return(ENOTTY); + } + + return 0; +} +int +wlstop(tp, flag) + struct tty *tp; + int flag; +{ + int s; + + s = splcl(); + if (tp->t_state & TS_BUSY) { + if ((tp->t_state & TS_TTSTOP) == 0) + tp->t_state |= TS_FLUSH; + } + splx(s); + return 0; +} + +static u_char +clgetc(sc, channel) + struct wlsoftc *sc; + int *channel; +{ + struct clreg *cl_reg; + u_char val, reoir, licr, isrl, fifo_cnt, data; + cl_reg = sc->cl_reg; + + val = cl_reg->cl_rir; + /* if no receive interrupt pending wait */ + if (!(val & 0x80)) { + return 0; + } + /* XXX do we need to suck the entire FIFO contents? */ + licr = cl_reg->cl_licr; + *channel = (licr >> 2) & 0x3; + /* is the interrupt for us (port 0) */ + /* the character is for us yea. */ + isrl = cl_reg->cl_risrl; +#if 0 + if (isrl & 0x01) { + status = BREAK; + } + if (isrl & 0x02) { + status = FRAME; + } + if (isrl & 0x04) { + status = PARITY; + } + if (isrl & 0x08) { + status = OVERFLOW; + } + /* we do not have special characters ;-) */ +#endif + fifo_cnt = cl_reg->cl_rfoc; + if (fifo_cnt > 0) { + data = cl_reg->cl_rdr; + cl_reg->cl_teoir = 0x00; + } else { + data = 0; + cl_reg->cl_teoir = 0x08; + } + return data; +} + +int +clccparam(sc, par, channel) + struct wlsoftc *sc; + struct termios *par; + int channel; +{ + u_int divisor, clk, clen; + int s, imask, ints; + + s = splcl(); + sc->cl_reg->cl_car = channel; + if (par->c_ospeed == 0) { + /* disconnect, drop RTS DTR stop reciever */ + sc->cl_reg->cl_msvr_rts = 0x00; + sc->cl_reg->cl_msvr_dtr = 0x00; + sc->cl_reg->cl_ccr = 0x05; + splx(s); + return (0xff); + } + + sc->cl_reg->cl_msvr_rts = 0x03; + sc->cl_reg->cl_msvr_dtr = 0x03; + + divisor = cl_clkdiv(par->c_ospeed); + clk = cl_clknum(par->c_ospeed); + sc->cl_reg->cl_tbpr = divisor; + sc->cl_reg->cl_tcor = clk << 5; + divisor = cl_clkdiv(par->c_ispeed); + clk = cl_clknum(par->c_ispeed); + sc->cl_reg->cl_rbpr = divisor; + sc->cl_reg->cl_rcor = clk; + sc->cl_reg->cl_rtprl = cl_clkrxtimeout(par->c_ispeed); + sc->cl_reg->cl_rtprh = 0x00; + + switch (par->c_cflag & CSIZE) { + case CS5: + clen = 4; /* this is the mask for the chip. */ + imask = 0x1F; + break; + case CS6: + clen = 5; + imask = 0x3F; + break; + case CS7: + clen = 6; + imask = 0x7F; + break; + default: + clen = 7; + imask = 0xFF; + } + sc->cl_reg->cl_cor3 = par->c_cflag & PARENB ? 4 : 2; + + { + u_char cor1; + if (par->c_cflag & PARENB) { + if (par->c_cflag & PARODD) { + cor1 = 0xE0 | clen ; /* odd */ + } else { + cor1 = 0x40 | clen ; /* even */ + } + } else { + cor1 = 0x10 | clen; /* ignore parity */ + } + if (sc->cl_reg->cl_cor1 != cor1) { + sc->cl_reg->cl_cor1 = cor1; + sc->cl_reg->cl_ccr = 0x20; + while (sc->cl_reg->cl_ccr != 0) + ; + } + } + + if ((par->c_cflag & CREAD) == 0) { + sc->cl_reg->cl_ccr = 0x08; + } else { + sc->cl_reg->cl_ccr = 0x0a; + } + while (sc->cl_reg->cl_ccr != 0) + ; + + ints = 0; +#define SCC_DSR 0x80 +#define SCC_DCD 0x40 +#define SCC_CTS 0x20 + if ((par->c_cflag & CLOCAL) == 0) { + ints |= SCC_DCD; + } + if ((par->c_cflag & CCTS_OFLOW) != 0) { + ints |= SCC_CTS; + } + if ((par->c_cflag & CRTSCTS) != 0) { + ints |= SCC_CTS; + } +#ifdef DONT_LET_HARDWARE + if ((par->c_cflag & CCTS_IFLOW) != 0) { + ints |= SCC_DSR; + } +#endif + sc->cl_reg->cl_cor4 = ints | CL_FIFO_CNT; + sc->cl_reg->cl_cor5 = ints | CL_FIFO_CNT; + + return imask; +} +static int clknum = 0; +u_char +cl_clkdiv(speed) + int speed; +{ + int i = 0; + if (cl_clocks[clknum].speed == speed) { + return cl_clocks[clknum].divisor; + } + for (i = 0; cl_clocks[i].speed != 0; i++) { + if (cl_clocks[i].speed == speed) { + clknum = i; + return cl_clocks[clknum].divisor; + } + } + /* return some sane value if unknown speed */ + return cl_clocks[4].divisor; +} +u_char +cl_clknum(speed) + int speed; +{ + int found = 0; + int i = 0; + if (cl_clocks[clknum].speed == speed) { + return cl_clocks[clknum].clock; + } + for (i = 0; found != 0 && cl_clocks[i].speed != 0; i++) { + if (cl_clocks[clknum].speed == speed) { + clknum = i; + return cl_clocks[clknum].clock; + } + } + /* return some sane value if unknown speed */ + return cl_clocks[4].clock; +} +u_char +cl_clkrxtimeout(speed) + int speed; +{ + int i = 0; + if (cl_clocks[clknum].speed == speed) { + return cl_clocks[clknum].rx_timeout; + } + for (i = 0; cl_clocks[i].speed != 0; i++) { + if (cl_clocks[i].speed == speed) { + clknum = i; + return cl_clocks[clknum].rx_timeout; + } + } + /* return some sane value if unknown speed */ + return cl_clocks[4].rx_timeout; +} +void +cl_unblock(tp) + struct tty *tp; +{ + tp->t_state &= ~TS_FLUSH; + if (tp->t_outq.c_cc != 0) + clstart(tp); +} +void +clstart(tp) + struct tty *tp; +{ + dev_t dev; + u_char cbuf; + struct wlsoftc *sc; + int channel, unit, s, cnt; + + dev = tp->t_dev; + channel = CL_CHANNEL(dev); + unit = CL_UNIT(dev); + if (unit >= wl_cd.cd_ndevs || + (sc = (struct wlsoftc *) wl_cd.cd_devs[unit]) == NULL) { + return; + } + + printf("WS"); + printf("channel %d unit %d\n", channel, unit); + + if ((tp->t_state & TS_ISOPEN) == 0) + return; + + s = splcl(); + cl_dumpport(0); +#if 0 + if (sc->sc_cl[channel].transmitting == 1) { + /* i'm busy, go away, I will get to it later. */ + splx(s); + return; + } + cnt = q_to_b(&tp->t_outq, &cbuf, 1); + if ( cnt != 0 ) { + sc->sc_cl[channel].transmitting = 1; + sc->cl_reg->cl_car = channel; + sc->cl_reg->cl_tdr = cbuf; + } else { + sc->sc_cl[channel].transmitting = 0; + } +#else + if ((tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP | TS_FLUSH)) == 0) + { + tp->t_state |= TS_BUSY; + sc->cl_reg->cl_car = channel; + printf("ier %02x\n", sc->cl_reg->cl_ier); + sc->cl_reg->cl_ier = sc->cl_reg->cl_ier | 0x3; + printf("whac"); + } +#endif + splx(s); + printf("ked\n"); + cl_dumpport(0); + return; +} +int +cl_mintr(sc) + struct wlsoftc *sc; +{ + u_char mir, misr, msvr; + int channel; + struct tty *tp; + +zscnputc(0, 'W'); +zscnputc(0, 'M'); + + if(((mir = sc->cl_reg->cl_mir) & 0x40) == 0x0) { + /* only if intr is not shared? */ + log(LOG_WARNING, "cl_mintr extra intr\n"); + return 0; + } + sc->sc_mxintrcnt.ev_count++; + + channel = mir & 0x03; + misr = sc->cl_reg->cl_misr; + msvr = sc->cl_reg->cl_msvr_rts; + if (misr & 0x01) { + /* timers are not currently used?? */ + log(LOG_WARNING, "cl_mintr: channel %x timer 1 unexpected\n",channel); + } + if (misr & 0x02) { + /* timers are not currently used?? */ + log(LOG_WARNING, "cl_mintr: channel %x timer 2 unexpected\n",channel); + } + if (misr & 0x20) { + log(LOG_WARNING, "cl_mintr: channel %x cts %x\n",channel, + ((msvr & 0x20) != 0x0) + ); + } + if (misr & 0x40) { + struct tty *tp = sc->sc_cl[channel].tty; + log(LOG_WARNING, "cl_mintr: channel %x cd %x\n",channel, + ((msvr & 0x40) != 0x0) + ); + ttymodem(tp, ((msvr & 0x40) != 0x0) ); + } + if (misr & 0x80) { + log(LOG_WARNING, "cl_mintr: channel %x dsr %x\n",channel, + ((msvr & 0x80) != 0x0) + ); + } + sc->cl_reg->cl_meoir = 0x00; + return 1; +} + +int +cl_txintr(sc) + struct wlsoftc *sc; +{ + static empty = 0; + u_char tir, cmr, teoir; + u_char max; + int channel; + struct tty *tp; + int cnt; + u_char buffer[CL_FIFO_MAX +1]; + u_char *tptr; + +zscnputc(0, 'W'); +zscnputc(0, 'T'); + + if(((tir = sc->cl_reg->cl_tir) & 0x40) == 0x0) { + /* only if intr is not shared ??? */ + log(LOG_WARNING, "cl_txintr extra intr\n"); + return 0; + } + sc->sc_txintrcnt.ev_count++; + + channel = tir & 0x03; + cmr = sc->cl_reg->cl_cmr; + + sc->sc_cl[channel].txcnt ++; + + tp = sc->sc_cl[channel].tty; + if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0) { + sc->cl_reg->cl_ier = sc->cl_reg->cl_ier & ~0x3; + sc->cl_reg->cl_teoir = 0x08; + return 1; + } + switch (cmr & CL_TXMASK) { + case CL_TXDMAINT: + { + u_char dmabsts; + int nbuf, busy, resid; + void *pbuffer; + dmabsts = sc->cl_reg->cl_dmabsts; + log(LOG_WARNING, "cl_txintr: DMAMODE channel %x dmabsts %x\n", + channel, dmabsts); + nbuf = ((dmabsts & 0x8) >> 3) & 0x1; + busy = ((dmabsts & 0x4) >> 2) & 0x1; + + do { + pbuffer = sc->sc_cl[channel].tx[nbuf]; + resid = tp->t_outq.c_cc; + cnt = min (CL_BUFSIZE,resid); + log(LOG_WARNING, "cl_txintr: resid %x cnt %x pbuf %x\n", + resid, cnt, pbuffer); + if (cnt != 0) { + cnt = q_to_b(&tp->t_outq, pbuffer, cnt); + resid -= cnt; + if (nbuf == 0) { + sc->cl_reg->cl_atbadru = + ((u_long) sc->sc_cl[channel].txp[nbuf]) >> 16; + sc->cl_reg->cl_atbadrl = + ((u_long) sc->sc_cl[channel].txp[nbuf]) & 0xffff; + sc->cl_reg->cl_atbcnt = cnt; + sc->cl_reg->cl_atbsts = 0x43; + } else { + sc->cl_reg->cl_btbadru = + ((u_long) sc->sc_cl[channel].txp[nbuf]) >> 16; + sc->cl_reg->cl_btbadrl = + ((u_long) sc->sc_cl[channel].txp[nbuf]) & 0xffff; + sc->cl_reg->cl_btbcnt = cnt; + sc->cl_reg->cl_btbsts = 0x43; + } + teoir = 0x08; + } else { + teoir = 0x08; + if (tp->t_state & TS_BUSY) { + tp->t_state &= ~(TS_BUSY | TS_FLUSH); + if (tp->t_state & TS_ASLEEP) { + tp->t_state &= ~TS_ASLEEP; + wakeup((caddr_t) &tp->t_outq); + } + selwakeup(&tp->t_wsel); + } + sc->cl_reg->cl_ier = sc->cl_reg->cl_ier & ~0x3; + } + nbuf = ~nbuf & 0x1; + busy--; + } while (resid != 0 && busy != -1);/* if not busy do other buffer */ + log(LOG_WARNING, "cl_txintr: done\n"); + } + break; + case CL_TXINTR: + max = sc->cl_reg->cl_tftc; + cnt = min ((int)max,tp->t_outq.c_cc); + if (cnt != 0) { + cnt = q_to_b(&tp->t_outq, buffer, cnt); + empty = 0; + for (tptr = buffer; tptr < &buffer[cnt]; tptr++) { + sc->cl_reg->cl_tdr = *tptr; + } + teoir = 0x00; + } else { + if (empty > 5 && ((empty % 20000 )== 0)) { + log(LOG_WARNING, "cl_txintr to many empty intr %d channel %d\n", + empty, channel); + } + empty++; + teoir = 0x08; + if (tp->t_state & TS_BUSY) { + tp->t_state &= ~(TS_BUSY | TS_FLUSH); + if (tp->t_state & TS_ASLEEP) { + tp->t_state &= ~TS_ASLEEP; + wakeup((caddr_t) &tp->t_outq); + } + selwakeup(&tp->t_wsel); + } + sc->cl_reg->cl_ier = sc->cl_reg->cl_ier & ~0x3; + } + break; + default: + log(LOG_WARNING, "cl_txintr unknown mode %x\n", cmr); + /* we probably will go to hell quickly now */ + teoir = 0x08; + } + sc->cl_reg->cl_teoir = teoir; + return 1; +} + +int +cl_rxintr(sc) + struct wlsoftc *sc; +{ + u_char rir, channel, cmr, risrl; + u_char c; + u_char fifocnt; + struct tty *tp; + int i; + u_char reoir; + u_char buffer[CL_FIFO_MAX +1]; + +zscnputc(0, 'W'); +zscnputc(0, 'R'); + + rir = sc->cl_reg->cl_rir; + if((rir & 0x40) == 0x0) { + /* only if intr is not shared ??? */ + log(LOG_WARNING, "cl_rxintr extra intr\n"); + return 0; + } + sc->sc_rxintrcnt.ev_count++; + channel = rir & 0x3; + cmr = sc->cl_reg->cl_cmr; + reoir = 0x08; + + sc->sc_cl[channel].rxcnt ++; + risrl = sc->cl_reg->cl_risrl; + if (risrl & 0x80) { + /* timeout, no characters */ + reoir = 0x08; + } else + /* We don't need no sinkin special characters */ + if (risrl & 0x08) { + cl_overflow (sc, channel, &sc->sc_fotime, "fifo"); + reoir = 0x08; + } else + if (risrl & 0x04) { + cl_parity(sc, channel); + reoir = 0x08; + } else + if (risrl & 0x02) { + cl_frame(sc, channel); + reoir = 0x08; + } else + if (risrl & 0x01) { + cl_break(sc, channel); + reoir = 0x08; + } + + switch (cmr & CL_RXMASK) { + case CL_RXDMAINT: + { + int nbuf; + u_short cnt; + int bufcomplete; + u_char status, dmabsts; + u_char risrh = sc->cl_reg->cl_risrh; + dmabsts = sc->cl_reg->cl_dmabsts; +#ifdef DMA_DEBUG +log(LOG_WARNING, "cl_txintr: DMAMODE channel %x dmabsts %x risrl %x risrh %x\n", + channel, dmabsts, risrl, risrh); +#endif + nbuf = (risrh & 0x08) ? 1 : 0; + bufcomplete = (risrh & 0x20) ? 1 : 0; + if (nbuf == 0) { + cnt = sc->cl_reg->cl_arbcnt; + status = sc->cl_reg->cl_arbsts; + } else { + cnt = sc->cl_reg->cl_brbcnt; + status = sc->cl_reg->cl_brbsts; + } +#ifdef DMA_DEBUG +log(LOG_WARNING, "cl_rxintr: 1channel %x buf %x cnt %x status %x\n", +channel, nbuf, cnt, status); +#endif +#if USE_BUFFER + cl_appendbufn(sc, channel, sc->rx[nbuf], cnt); +#else + { + int i; + u_char *pbuf; + tp = sc->sc_cl[channel].tty; + pbuf = sc->sc_cl[channel].rx[nbuf]; + /* this should be done at off level */ +{ + u_short rcbadru, rcbadrl; + u_char arbsts, brbsts; + u_char *pbufs, *pbufe; + rcbadru = sc->cl_reg->cl_rcbadru; + rcbadrl = sc->cl_reg->cl_rcbadrl; + arbsts = sc->cl_reg->cl_arbsts; + brbsts = sc->cl_reg->cl_brbsts; + pbufs = sc->sc_cl[channel].rxp[nbuf]; + pbufe = (u_char *)(((u_long)rcbadru << 16) | (u_long)rcbadrl); + cnt = pbufe - pbufs; +#ifdef DMA_DEBUG + log(LOG_WARNING, "cl_rxintr: rcbadru %x rcbadrl %x arbsts %x brbsts %x cnt %x\n", + rcbadru, rcbadrl, arbsts, brbsts, cnt); +#endif +#ifdef DMA_DEBUG1 + log(LOG_WARNING, "cl_rxintr: buf %x cnt %x\n", + nbuf, cnt); +#endif +} + reoir = 0x0 | (bufcomplete) ? 0 : 0xd0; + sc->cl_reg->cl_reoir = reoir; +#ifdef DMA_DEBUG +log(LOG_WARNING, "cl_rxintr: reoir %x\n", reoir); +#endif + delay(10); /* give the chip a moment */ +#ifdef DMA_DEBUG +log(LOG_WARNING, "cl_rxintr: 2channel %x buf %x cnt %x status %x\n", +channel, nbuf, cnt, status); +#endif + for (i = 0; i < cnt; i++) { + u_char c; + c = pbuf[i]; + (*linesw[tp->t_line].l_rint)(c,tp); + } + /* this should be done at off level */ + if (nbuf == 0) { + sc->cl_reg->cl_arbcnt = CL_BUFSIZE; + sc->cl_reg->cl_arbsts = 0x01; + } else { + sc->cl_reg->cl_brbcnt = CL_BUFSIZE; + sc->cl_reg->cl_brbsts = 0x01; + } + } +#endif + } + sc->cl_reg->cl_reoir = reoir; + break; + case CL_RXINTR: + fifocnt = sc->cl_reg->cl_rfoc; + tp = sc->sc_cl[channel].tty; + for (i = 0; i < fifocnt; i++) { + buffer[i] = sc->cl_reg->cl_rdr; + } + if (NULL == tp) { + /* if the channel is not configured, + * dont send characters upstream. + * also fix problem with NULL dereference + */ + reoir = 0x00; + break; + } + + sc->cl_reg->cl_reoir = reoir; + for (i = 0; i < fifocnt; i++) { + u_char c; + c = buffer[i]; +#if USE_BUFFER + cl_appendbuf(sc, channel, c); +#else + /* does any restricitions exist on spl + * for this call + */ + (*linesw[tp->t_line].l_rint)(c,tp); + reoir = 0x00; +#endif + } + break; + default: + log(LOG_WARNING, "cl_rxintr unknown mode %x\n", cmr); + /* we probably will go to hell quickly now */ + reoir = 0x08; + sc->cl_reg->cl_reoir = reoir; + } + return 1; +} + +void +cl_overflow (sc, channel, ptime, msg) +struct wlsoftc *sc; +int channel; +long *ptime; +u_char *msg; +{ +/* + if (*ptime != time.tv_sec) { +*/ + { +/* + *ptime = time.tv_sec; +*/ + log(LOG_WARNING, "%s%d[%d]: %s overrun\n", wl_cd.cd_name, + 0 /* fix */, channel, msg); + } + return; +} +void +cl_parity (sc, channel) + struct wlsoftc *sc; + int channel; +{ + log(LOG_WARNING, "%s%d[%d]: parity error\n", wl_cd.cd_name, 0, channel); + return; +} +void +cl_frame (sc, channel) + struct wlsoftc *sc; + int channel; +{ + log(LOG_WARNING, "%s%d[%d]: frame error\n", wl_cd.cd_name, 0, channel); + return; +} +void +cl_break (sc, channel) + struct wlsoftc *sc; + int channel; +{ + log(LOG_WARNING, "%s%d[%d]: break detected\n", wl_cd.cd_name, 0, channel); + return; +} + +void +cl_dumpport0() +{ + cl_dumpport(0); + return; +} +void +cl_dumpport1() +{ + cl_dumpport(1); + return; +} +void +cl_dumpport2() +{ + cl_dumpport(2); + return; +} +void +cl_dumpport3() +{ + cl_dumpport(3); + return; +} + +void +cl_dumpport(channel) + int channel; +{ + u_char livr, cmr, cor1, cor2, cor3, cor4, cor5, cor6, cor7, + schr1, schr2, schr3, schr4, scrl, scrh, lnxt, + rbpr, rcor, tbpr, tcor, rpilr, rir, tpr, ier, ccr, + dmabsts, arbsts, brbsts, atbsts, btbsts, + csr, rts, dtr, rtprl, rtprh; + volatile void * parbadru, *parbadrl, *parbsts, *parbcnt; + u_short rcbadru, rcbadrl, arbadru, arbadrl, arbcnt, + brbadru, brbadrl, brbcnt; + u_short tcbadru, tcbadrl, atbadru, atbadrl, atbcnt, + btbadru, btbadrl, btbcnt; + struct wlsoftc *sc; + + struct clreg *cl_reg; + int s; + + sc = (struct wlsoftc *) wl_cd.cd_devs[0]; + cl_reg = sc->cl_reg; + + s = splcl(); + cl_reg->cl_car = (u_char) channel; + livr = cl_reg->cl_livr; + cmr = cl_reg->cl_cmr; + cor1 = cl_reg->cl_cor1; + cor2 = cl_reg->cl_cor2; + cor3 = cl_reg->cl_cor3; + cor4 = cl_reg->cl_cor4; + cor5 = cl_reg->cl_cor5; + cor6 = cl_reg->cl_cor6; + cor7 = cl_reg->cl_cor7; + schr1 = cl_reg->cl_schr1; + schr2 = cl_reg->cl_schr2; + schr3 = cl_reg->cl_schr3; + schr4 = cl_reg->cl_schr4; + scrl = cl_reg->cl_scrl; + scrh = cl_reg->cl_scrh; + lnxt = cl_reg->cl_lnxt; + rbpr = cl_reg->cl_rbpr; + rcor = cl_reg->cl_rcor; + tbpr = cl_reg->cl_tbpr; + rpilr = cl_reg->cl_rpilr; + ier = cl_reg->cl_ier; + ccr = cl_reg->cl_ccr; + tcor = cl_reg->cl_tcor; + csr = cl_reg->cl_csr; + tpr = cl_reg->cl_tpr; + rts = cl_reg->cl_msvr_rts; + dtr = cl_reg->cl_msvr_dtr; + rtprl = cl_reg->cl_rtprl; + rtprh = cl_reg->cl_rtprh; + dmabsts = cl_reg->cl_dmabsts; + tcbadru = cl_reg->cl_tcbadru; + tcbadrl = cl_reg->cl_tcbadrl; + rcbadru = cl_reg->cl_rcbadru; + rcbadrl = cl_reg->cl_rcbadrl; + + parbadru = &(cl_reg->cl_arbadru); + parbadrl = &(cl_reg->cl_arbadrl); + parbcnt = &(cl_reg->cl_arbcnt); + parbsts = &(cl_reg->cl_arbsts); + + arbadru = cl_reg->cl_arbadru; + arbadrl = cl_reg->cl_arbadrl; + arbcnt = cl_reg->cl_arbcnt; + arbsts = cl_reg->cl_arbsts; + + brbadru = cl_reg->cl_brbadru; + brbadrl = cl_reg->cl_brbadrl; + brbcnt = cl_reg->cl_brbcnt; + brbsts = cl_reg->cl_brbsts; + + atbadru = cl_reg->cl_atbadru; + atbadrl = cl_reg->cl_atbadrl; + atbcnt = cl_reg->cl_atbcnt; + atbsts = cl_reg->cl_atbsts; + + btbadru = cl_reg->cl_btbadru; + btbadrl = cl_reg->cl_btbadrl; + btbcnt = cl_reg->cl_btbcnt; + btbsts = cl_reg->cl_btbsts; + + splx(s); + + printf("{ port %x livr %x cmr %x\n", + channel,livr, cmr); + printf("cor1 %x cor2 %x cor3 %x cor4 %x cor5 %x cor6 %x cor7 %x\n", + cor1, cor2, cor3, cor4, cor5, cor6, cor7); + printf("schr1 %x schr2 %x schr3 %x schr4 %x\n", + schr1, schr2, schr3, schr4); + printf("scrl %x scrh %x lnxt %x\n", + scrl, scrh, lnxt); + printf("rbpr %x rcor %x tbpr %x tcor %x\n", + rbpr, rcor, tbpr, tcor); + printf("rpilr %x rir %x ier %x ccr %x\n", + rpilr, rir, ier, ccr); + printf("tpr %x csr %x rts %x dtr %x\n", + tpr, csr, rts, dtr); + printf("rtprl %x rtprh %x\n", + rtprl, rtprh); + printf("rxcnt %x txcnt %x\n", + sc->sc_cl[channel].rxcnt, sc->sc_cl[channel].txcnt); + printf("dmabsts %x, tcbadru %x, tcbadrl %x, rcbadru %x, rcbadrl %x,\n", + dmabsts, tcbadru, tcbadrl, rcbadru, rcbadrl ); + printf("parbadru %x, parbadrl %x, parbcnt %x, parbsts %x\n", + parbadru, parbadrl, parbcnt, parbsts); + printf("arbadru %x, arbadrl %x, arbcnt %x, arbsts %x\n", + arbadru, arbadrl, arbcnt, arbsts); + printf("brbadru %x, brbadrl %x, brbcnt %x, brbsts %x\n", + brbadru, brbadrl, brbcnt, brbsts); + printf("atbadru %x, atbadrl %x, atbcnt %x, atbsts %x\n", + atbadru, atbadrl, atbcnt, atbsts); + printf("btbadru %x, btbadrl %x, btbcnt %x, btbsts %x\n", + btbadru, btbadrl, btbcnt, btbsts); + printf("}\n"); + return; +} + +static void +clputc(sc, unit, c) + struct wlsoftc *sc; + int unit; + u_char c; +{ + int s; + u_char schar; + u_char oldchannel; + struct clreg *cl_reg; + cl_reg = sc->cl_reg; + +#ifdef NEW_CLCD_STRUCT + /* should we disable, flush and all that goo? */ + cl->car = unit; + schar = cl->schr3; + cl->schr3 = c; + cl->stcr = 0x08 | 0x03; /* send special char, char 3 */ + while (0 != cl->stcr) { + /* wait until cl notices the command + * otherwise it may not notice the character + * if we send characters too fast. + */ + } + cl->schr3 = schar; +#else +if (unit == 0) { + s = splhigh(); + oldchannel = cl_reg->cl_car; + cl_reg->cl_car = unit; + schar = cl_reg->cl_schr3; + cl_reg->cl_schr3 = c; + cl_reg->cl_stcr = 0x08 | 0x03; /* send special char, char 3 */ + while (0 != cl_reg->cl_stcr) { + /* wait until cl notices the command + * otherwise it may not notice the character + * if we send characters too fast. + */ + } + DELAY(5); + cl_reg->cl_schr3 = schar; + cl_reg->cl_car = oldchannel; + splx(s); +} else { + s = splhigh(); + oldchannel = cl_reg->cl_car; + cl_reg->cl_car = unit; + if (cl_reg->cl_tftc > 0) { + cl_reg->cl_tdr = c; + } + cl_reg->cl_car = oldchannel; + splx(s); +} +#endif + return; +} diff --git a/sys/arch/mvme68k/dev/wlreg.h b/sys/arch/mvme68k/dev/wlreg.h new file mode 100644 index 00000000000..7f14964235a --- /dev/null +++ b/sys/arch/mvme68k/dev/wlreg.h @@ -0,0 +1,163 @@ +/* $OpenBSD: wlreg.h,v 1.1 1996/12/24 20:31:25 deraadt Exp $ */ + +/* + * Copyright (c) 1995 Dale Rahn. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Dale Rahn. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +struct clreg { + volatile u_char anon1[0x7]; + volatile u_char cl_cor7; /* 0x07 */ + volatile u_char anon2[0x1]; + volatile u_char cl_livr; /* 0x09 */ + volatile u_char anon3[0x6]; + volatile u_char cl_cor1; /* 0x10 */ + volatile u_char cl_ier; /* 0x11 */ + volatile u_char cl_stcr; /* 0x12 */ + volatile u_char cl_ccr; /* 0x13 */ + volatile u_char cl_cor5; /* 0x14 */ + volatile u_char cl_cor4; /* 0x15 */ + volatile u_char cl_cor3; /* 0x16 */ + volatile u_char cl_cor2; /* 0x17 */ + volatile u_char cl_cor6; /* 0x18 */ + volatile u_char cl_dmabsts; /* 0x19 */ + volatile u_char cl_csr; /* 0x1a */ + volatile u_char cl_cmr; /* 0x1b */ + volatile u_char cl_schr4; /* 0x1c */ + volatile u_char cl_schr3; /* 0x1d */ + volatile u_char cl_schr2; /* 0x1e */ + volatile u_char cl_schr1; /* 0x1f */ + volatile u_char anon5[0x2]; + volatile u_char cl_scrh; /* 0x22 */ + volatile u_char cl_scrl; /* 0x23 */ +#define cl_rtpr rtpr.rtpr_rtpr +#define cl_rtprh rtpr.hl.rtpr_rtprh +#define cl_rtprl rtpr.hl.rtpr_rtprl + union { + volatile u_short rtpr_rtpr; /* 0x24 */ + struct { + volatile u_char rtpr_rtprh; /* 0x24 */ + volatile u_char rtpr_rtprl; /* 0x25 */ + } hl; + } rtpr; + volatile u_char cl_licr; /* 0x26 */ + volatile u_char anon6[0x7]; + volatile u_char cl_lnxt; /* 0x2e */ + volatile u_char anon7[0x1]; + volatile u_char cl_rfoc; /* 0x30 */ + volatile u_char anon8[0x7]; + volatile u_short cl_tcbadru; /* 0x38 */ + volatile u_short cl_tcbadrl; /* 0x3a */ + volatile u_short cl_rcbadru; /* 0x3c */ + volatile u_short cl_rcbadrl; /* 0x3e */ + volatile u_short cl_arbadru; /* 0x40 */ + volatile u_short cl_arbadrl; /* 0x42 */ + volatile u_short cl_brbadru; /* 0x44 */ + volatile u_short cl_brbadrl; /* 0x46 */ + volatile u_short cl_brbcnt; /* 0x48 */ + volatile u_short cl_arbcnt; /* 0x4a */ + volatile u_char anoni[0x2]; + volatile u_char cl_brbsts; /* 0x4e */ + volatile u_char cl_arbsts; /* 0x4f */ +#define cl_atbadr atbadr.atbadr +#define cl_atbadru atbadr.hl.atbadru +#define cl_atbadrl atbadr.hl.atbadrl + union { + struct { + volatile u_short atbadru; /* 0x50 */ + volatile u_short atbadrl; /* 0x52 */ + } hl; + volatile u_long atbadr; /* 0x50 */ + } atbadr; +#define cl_btbadr btbadr.btbadr +#define cl_btbadru btbadr.hl.btbadru +#define cl_btbadrl btbadr.hl.btbadrl + union { + struct { + volatile u_short btbadru; /* 0x54 */ + volatile u_short btbadrl; /* 0x56 */ + } hl; + volatile u_long btbadr; /* 0x54 */ + } btbadr; + volatile u_short cl_btbcnt; /* 0x58 */ + volatile u_short cl_atbcnt; /* 0x5a */ + volatile u_char anono[0x2]; + volatile u_char cl_btbsts; /* 0x5e */ + volatile u_char cl_atbsts; /* 0x5f */ + volatile u_char anonp[0x20]; + volatile u_char cl_tftc; /* 0x80 */ + volatile u_char cl_gfrcr; /* 0x81 */ + volatile u_char anonq[0x2]; + volatile u_char cl_reoir; /* 0x84 */ + volatile u_char cl_teoir; /* 0x85 */ + volatile u_char cl_meoir; /* 0x86 */ + volatile u_char anonr[0x1]; +#define cl_risr risr.risr_risr +#define cl_risrl risr.hl.risr_risrl +#define cl_risrh risr.hl.risr_risrh + union { + volatile u_short risr_risr; /* 0x88 */ + struct { + volatile u_char risr_risrh; /* 0x88 */ + volatile u_char risr_risrl; /* 0x89 */ + } hl; + } risr; + volatile u_char cl_tisr; /* 0x8a */ + volatile u_char cl_misr; /* 0x8b */ + volatile u_char anons[0x2]; + volatile u_char cl_bercnt; /* 0x8e */ + volatile u_char anont[0x31]; + volatile u_char cl_tcor; /* 0xc0 */ + volatile u_char anonu[0x2]; + volatile u_char cl_tbpr; /* 0xc3 */ + volatile u_char anonv[0x4]; + volatile u_char cl_rcor; /* 0xc8 */ + volatile u_char anonw[0x2]; + volatile u_char cl_rbpr; /* 0xcb */ + volatile u_char anonx[0xa]; + volatile u_char cl_cpsr; /* 0xd6 */ + volatile u_char anony[0x3]; + volatile u_char cl_tpr; /* 0xda */ + volatile u_char anonz[0x3]; + volatile u_char cl_msvr_rts; /* 0xde */ + volatile u_char cl_msvr_dtr; /* 0xdf */ + volatile u_char cl_tpilr; /* 0xe0 */ + volatile u_char cl_rpilr; /* 0xe1 */ + volatile u_char cl_stk; /* 0xe2 */ + volatile u_char cl_mpilr; /* 0xe3 */ + volatile u_char anonA[0x8]; + volatile u_char cl_tir; /* 0xec */ + volatile u_char cl_rir; /* 0xed */ + volatile u_char cl_car; /* 0xee */ + volatile u_char cl_mir; /* 0xef */ + volatile u_char anonB[0x6]; + volatile u_char cl_dmr; /* 0xf6 */ + volatile u_char anonC[0x1]; +#define cl_rdr cl_tdr + volatile u_char cl_tdr; /* 0xf8 */ + volatile u_char anonD[7]; +};