summaryrefslogtreecommitdiff
path: root/sys/arch/mvme88k/dev/vx.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/mvme88k/dev/vx.c')
-rw-r--r--sys/arch/mvme88k/dev/vx.c1691
1 files changed, 1691 insertions, 0 deletions
diff --git a/sys/arch/mvme88k/dev/vx.c b/sys/arch/mvme88k/dev/vx.c
new file mode 100644
index 00000000000..60aba6197ad
--- /dev/null
+++ b/sys/arch/mvme88k/dev/vx.c
@@ -0,0 +1,1691 @@
+/* $OpenBSD: vx.c,v 1.1 1999/05/29 04:41:45 smurph Exp $ */
+/*
+ * Copyright (c) 1999 Steve Murphree, Jr.
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/callout.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/device.h>
+#include <machine/cpu.h>
+#include <machine/autoconf.h>
+#include <dev/cons.h>
+#include <mvme88k/dev/vxreg.h>
+#include <sys/syslog.h>
+#include "pcctwo.h"
+#if NPCCTWO > 0
+ #include <mvme88k/dev/pcctworeg.h>
+ #include <mvme88k/dev/vme.h>
+#endif
+
+#include <machine/psl.h>
+#define splvx() spltty()
+
+#ifdef DEBUG
+ #undef DEBUG
+#endif
+#define DEBUG_KERN 1
+
+struct vx_info {
+ struct tty *tty;
+ u_char vx_swflags;
+ int vx_linestatus;
+ int open;
+ int waiting;
+ u_char vx_consio;
+ u_char vx_speed;
+ u_char read_pending;
+ struct wring *wringp;
+ struct rring *rringp;
+};
+
+struct vxsoftc {
+ struct device sc_dev;
+ struct evcnt sc_intrcnt;
+ struct evcnt sc_sintrcnt;
+ struct vx_info sc_info[9];
+ struct vxreg *vx_reg;
+ unsigned int board_addr;
+ struct channel *channel;
+ char channel_number;
+ struct packet sc_bppwait_pkt;
+ void *sc_bppwait_pktp;
+ struct intrhand sc_ih_c;
+ struct intrhand sc_ih_s;
+ struct vme2reg *sc_vme2;
+ int sc_ipl;
+ int sc_vec;
+ int sc_flags;
+ struct envelope *elist_head, *elist_tail;
+ struct packet *plist_head, *plist_tail;
+};
+
+extern int cold; /* var in autoconf.c that is set in machdep.c when booting */
+
+/* prototypes */
+
+void *get_next_envelope __P((struct envelope *thisenv));
+struct envelope *get_status_head __P((struct vxsoftc *sc));
+void set_status_head __P((struct vxsoftc *sc, void *envp));
+struct packet *get_packet __P((struct vxsoftc *sc, struct envelope *thisenv));
+struct envelope *find_status_packet __P((struct vxsoftc *sc, struct packet * pktp));
+
+void read_wakeup __P((struct vxsoftc *sc, int port));
+int bpp_send __P((struct vxsoftc *sc, void *pkt, int wait_flag));
+
+int create_channels __P((struct vxsoftc *sc));
+void *memcpy2 __P((void *dest, const void *src, size_t size));
+void *get_free_envelope __P((struct vxsoftc *sc));
+void put_free_envelope __P((struct vxsoftc *sc, void *envp));
+void *get_free_packet __P((struct vxsoftc *sc));
+void put_free_packet __P((struct vxsoftc *sc, void *pktp));
+
+int vx_init __P((struct vxsoftc *sc));
+int vx_event __P((struct vxsoftc *sc, struct packet *evntp));
+
+void vx_unblock __P((struct tty *tp));
+int vx_ccparam __P((struct vxsoftc *sc, struct termios *par, int port));
+
+int vx_param __P((struct tty *tp, struct termios *t));
+int vx_intr __P((struct vxsoftc *sc));
+int vx_sintr __P((struct vxsoftc *sc));
+int vx_poll __P((struct vxsoftc *sc, struct packet *wpktp));
+void vx_overflow __P((struct vxsoftc *sc, int port, long *ptime, u_char *msg));
+void vx_frame __P((struct vxsoftc *sc, int port));
+void vx_break __P(( struct vxsoftc *sc, int port));
+int vx_mctl __P((dev_t dev, int bits, int how));
+
+int vxmatch __P((struct device *parent, void *self, void *aux));
+void vxattach __P((struct device *parent, struct device *self, void *aux));
+
+int vxopen __P((dev_t dev, int flag, int mode, struct proc *p));
+int vxclose __P((dev_t dev, int flag, int mode, struct proc *p));
+int vxread __P((dev_t dev, struct uio *uio, int flag));
+int vxwrite __P((dev_t dev, struct uio *uio, int flag));
+int vxioctl __P((dev_t dev, int cmd, caddr_t data, int flag, struct proc *p));
+void vxstart __P((struct tty *tp));
+int vxstop __P((struct tty *tp, int flag));
+
+static void vxputc __P((struct vxsoftc *sc, int port, u_char c));
+static u_char vxgetc __P((struct vxsoftc *sc, int *port));
+
+struct cfattach vx_ca = {
+ sizeof(struct vxsoftc), vxmatch, vxattach
+};
+
+struct cfdriver vx_cd = {
+ NULL, "vx", DV_TTY, 0
+};
+
+#define VX_UNIT(x) (int)(minor(x) / 9)
+#define VX_PORT(x) (int)(minor(x) % 9)
+
+extern int cputyp;
+struct envelope *bpp_wait;
+unsigned int board_addr;
+
+struct tty * vxtty(dev)
+dev_t dev;
+{
+ int unit, port;
+ struct vxsoftc *sc;
+ unit = VX_UNIT(dev);
+ if (unit >= vx_cd.cd_ndevs ||
+ (sc = (struct vxsoftc *) vx_cd.cd_devs[unit]) == NULL) {
+ return (NULL);
+ }
+ port = VX_PORT(dev);
+ return sc->sc_info[port].tty;
+}
+
+int
+vxmatch(parent, self, aux)
+struct device *parent;
+void *self;
+void *aux;
+{
+ struct vxreg *vx_reg;
+ struct vxsoftc *sc = self;
+ struct confargs *ca = aux;
+ int ret;
+ if (cputyp != CPU_187)
+ return 0;
+#ifdef OLD_MAPPINGS
+ ca->ca_vaddr = ca->ca_paddr;
+#endif
+ ca->ca_len = 0x10000; /* we know this. */
+ ca->ca_ipl = 3; /* we need interrupts for this board to work */
+
+ vx_reg = (struct vxreg *)ca->ca_vaddr;
+ board_addr = (unsigned int)ca->ca_vaddr;
+ if (!badvaddr(&vx_reg->ipc_cr, 1)){
+ if (ca->ca_vec & 0x03) {
+ printf("xvt: bad vector 0x%x\n", ca->ca_vec);
+ return (0);
+ }
+ return (1);
+ } else {
+ return (0);
+ }
+}
+
+void
+vxattach(parent, self, aux)
+struct device *parent;
+struct device *self;
+void *aux;
+{
+ struct vxsoftc *sc = (struct vxsoftc *)self;
+ struct confargs *ca = aux;
+ int i;
+
+ /* set up dual port memory and registers and init*/
+ sc->vx_reg = (struct vxreg *)ca->ca_vaddr;
+ sc->channel = (struct channel *)(ca->ca_vaddr + 0x0100);
+ sc->sc_vme2 = ca->ca_master;
+ sc->sc_ipl = ca->ca_ipl;
+ sc->sc_vec = ca->ca_vec;
+ sc->board_addr = (unsigned int)ca->ca_vaddr;
+
+ printf("\n");
+
+ if (create_channels(sc)) {
+ printf("%s: failed to create channel %d\n", sc->sc_dev.dv_xname,
+ sc->channel->channel_number);
+ return;
+ }
+ if (vx_init(sc)){
+ printf("%s: failed to initialize\n", sc->sc_dev.dv_xname);
+ return;
+ }
+
+ /* enable interrupts */
+ sc->sc_ih_c.ih_fn = vx_intr;
+ sc->sc_ih_c.ih_arg = sc;
+ sc->sc_ih_c.ih_ipl = ca->ca_ipl;
+ sc->sc_ih_c.ih_wantframe = 0;
+
+ vmeintr_establish(ca->ca_vec, &sc->sc_ih_c);
+ evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt);
+}
+
+int vxtdefaultrate = TTYDEF_SPEED;
+
+dtr_ctl(sc, port, on)
+ struct vxsoftc *sc;
+ int port;
+ int on;
+{
+ struct packet pkt;
+ bzero(&pkt, sizeof(struct packet));
+ pkt.command = CMD_IOCTL;
+ pkt.ioctl_cmd_l = IOCTL_TCXONC;
+ pkt.command_pipe_number = sc->channel_number;
+ pkt.status_pipe_number = sc->channel_number;
+ pkt.device_number = port;
+ if (on) {
+ pkt.ioctl_arg_l = 6; /* assert DTR */
+ } else {
+ pkt.ioctl_arg_l = 7; /* negate DTR */
+ }
+ bpp_send(sc, &pkt, NOWAIT);
+ return (pkt.error_l);
+}
+
+rts_ctl(sc, port, on)
+ struct vxsoftc *sc;
+ int port;
+ int on;
+{
+ struct packet pkt;
+ bzero(&pkt, sizeof(struct packet));
+ pkt.command = CMD_IOCTL;
+ pkt.ioctl_cmd_l = IOCTL_TCXONC;
+ pkt.command_pipe_number = sc->channel_number;
+ pkt.status_pipe_number = sc->channel_number;
+ pkt.device_number = port;
+ if (on) {
+ pkt.ioctl_arg_l = 4; /* assert RTS */
+ } else {
+ pkt.ioctl_arg_l = 5; /* negate RTS */
+ }
+ bpp_send(sc, &pkt, NOWAIT);
+ return (pkt.error_l);
+}
+
+flush_ctl(sc, port, which)
+ struct vxsoftc *sc;
+ int port;
+ int which;
+{
+ struct packet pkt;
+ bzero(&pkt, sizeof(struct packet));
+ pkt.command = CMD_IOCTL;
+ pkt.ioctl_cmd_l = IOCTL_TCFLSH;
+ pkt.command_pipe_number = sc->channel_number;
+ pkt.status_pipe_number = sc->channel_number;
+ pkt.device_number = port;
+ pkt.ioctl_arg_l = which; /* 0=input, 1=output, 2=both */
+ bpp_send(sc, &pkt, NOWAIT);
+ return (pkt.error_l);
+}
+
+int vx_mctl (dev, bits, how)
+dev_t dev;
+int bits;
+int how;
+{
+ int s, unit, port;
+ int vxbits;
+ struct vxsoftc *sc;
+ struct vx_info *vxt;
+ u_char msvr;
+
+ unit = VX_UNIT(dev);
+ port = VX_PORT(dev);
+ sc = (struct vxsoftc *) vx_cd.cd_devs[unit];
+ vxt = &sc->sc_info[port];
+
+ s = splvx();
+ switch (how) {
+ case DMSET:
+ if( bits & TIOCM_RTS) {
+ rts_ctl(sc, port, 1);
+ vxt->vx_linestatus |= TIOCM_RTS;
+ } else {
+ rts_ctl(sc, port, 0);
+
+ vxt->vx_linestatus &= ~TIOCM_RTS;
+ }
+ if( bits & TIOCM_DTR) {
+ dtr_ctl(sc, port, 1);
+ vxt->vx_linestatus |= TIOCM_DTR;
+ } else {
+ dtr_ctl(sc, port, 0);
+ vxt->vx_linestatus &= ~TIOCM_DTR;
+ }
+ break;
+ case DMBIC:
+ if ( bits & TIOCM_RTS) {
+ rts_ctl(sc, port, 0);
+ vxt->vx_linestatus &= ~TIOCM_RTS;
+ }
+ if ( bits & TIOCM_DTR) {
+ dtr_ctl(sc, port, 0);
+ vxt->vx_linestatus &= ~TIOCM_DTR;
+ }
+ break;
+
+ case DMBIS:
+ if ( bits & TIOCM_RTS) {
+ rts_ctl(sc, port, 1);
+ vxt->vx_linestatus |= TIOCM_RTS;
+ }
+ if ( bits & TIOCM_DTR) {
+ dtr_ctl(sc, port, 1);
+ vxt->vx_linestatus |= TIOCM_DTR;
+ }
+ break;
+
+ case DMGET:
+ bits = 0;
+ msvr = vxt->vx_linestatus;
+ if( msvr & TIOCM_DSR) {
+ bits |= TIOCM_DSR;
+ }
+ if( msvr & TIOCM_CD) {
+ bits |= TIOCM_CD;
+ }
+ if( msvr & TIOCM_CTS) {
+ bits |= TIOCM_CTS;
+ }
+ if( msvr & TIOCM_DTR) {
+ bits |= TIOCM_DTR;
+ }
+ if( msvr & TIOCM_RTS) {
+ bits |= TIOCM_RTS;
+ }
+ break;
+ }
+
+ splx(s);
+ bits = 0;
+ bits |= TIOCM_DTR;
+ bits |= TIOCM_RTS;
+ bits |= TIOCM_CTS;
+ bits |= TIOCM_CD;
+ bits |= TIOCM_DSR;
+ return (bits);
+}
+
+int vxopen (dev, flag, mode, p)
+dev_t dev;
+int flag;
+int mode;
+struct proc *p;
+{
+ int s, unit, port;
+ struct vx_info *vxt;
+ struct vxsoftc *sc;
+ struct tty *tp;
+ struct open_packet opkt;
+ u_short code;
+
+ unit = VX_UNIT(dev);
+ port = VX_PORT(dev);
+
+ if (unit >= vx_cd.cd_ndevs ||
+ (sc = (struct vxsoftc *) vx_cd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+
+ /*flush_ctl(sc, port, 2);*/
+
+ bzero(&opkt, sizeof(struct packet));
+ opkt.eye_catcher[0] = 0x33;
+ opkt.eye_catcher[1] = 0x33;
+ opkt.eye_catcher[2] = 0x33;
+ opkt.eye_catcher[3] = 0x33;
+ opkt.command_pipe_number = sc->channel_number;
+ opkt.status_pipe_number = sc->channel_number;
+ opkt.command = CMD_OPEN;
+ opkt.device_number = port;
+
+ bpp_send(sc, &opkt, WAIT_POLL);
+
+ if (opkt.error_l) {
+#ifdef DEBUG_VXT
+ printf("unit %d, port %d, ", unit, port);
+ printf("error = %d\n", opkt.error_l);
+#endif
+ return (ENODEV);
+ }
+
+ code = opkt.event_code;
+ s = splvx();
+
+ vxt = &sc->sc_info[port];
+ if (vxt->tty) {
+ tp = vxt->tty;
+ } else {
+ tp = vxt->tty = ttymalloc();
+ }
+
+ /* set line status */
+ tp->t_state |= TS_CARR_ON;
+ if (code & E_DCD) {
+ tp->t_state |= TS_CARR_ON;
+ vxt->vx_linestatus |= TIOCM_CD;
+ }
+ if (code & E_DSR) {
+ vxt->vx_linestatus |= TIOCM_DSR;
+ }
+ if (code & E_CTS) {
+ vxt->vx_linestatus |= TIOCM_CTS;
+ }
+
+ tp->t_oproc = vxstart;
+ tp->t_param = vx_param;
+ 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 = vxtdefaultrate;
+ tp->t_cflag = TTYDEF_CFLAG;
+ }
+ /*
+ * do these all the time
+ */
+ if (vxt->vx_swflags & TIOCFLAG_CLOCAL)
+ tp->t_cflag |= CLOCAL;
+ if (vxt->vx_swflags & TIOCFLAG_CRTSCTS)
+ tp->t_cflag |= CRTSCTS;
+ if (vxt->vx_swflags & TIOCFLAG_MDMBUF)
+ tp->t_cflag |= MDMBUF;
+ vx_param(tp, &tp->t_termios);
+ ttsetwater(tp);
+
+ (void)vx_mctl(dev, TIOCM_DTR | TIOCM_RTS, DMSET);
+
+ tp->t_state |= TS_CARR_ON;
+ } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
+ splx(s);
+ return (EBUSY);
+ }
+
+ /*
+ * Reset the tty pointer, as there could have been a dialout
+ * use of the tty with a dialin open waiting.
+ */
+ tp->t_dev = dev;
+ sc->sc_info[port].open = 1;
+ read_wakeup(sc, port);
+ splx(s);
+ return ((*linesw[tp->t_line].l_open)(dev, tp));
+}
+
+int
+vx_param(tp, t)
+struct tty *tp;
+struct termios *t;
+{
+ int unit, port;
+ struct vxsoftc *sc;
+ int s;
+ dev_t dev;
+
+ dev = tp->t_dev;
+ unit = VX_UNIT(dev);
+ if (unit >= vx_cd.cd_ndevs ||
+ (sc = (struct vxsoftc *) vx_cd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ port = VX_PORT(dev);
+ tp->t_ispeed = t->c_ispeed;
+ tp->t_ospeed = t->c_ospeed;
+ tp->t_cflag = t->c_cflag;
+ vx_ccparam(sc, t, port);
+ vx_unblock(tp);
+ return 0;
+}
+
+int
+vxclose (dev, flag, mode, p)
+dev_t dev;
+int flag;
+int mode;
+struct proc *p;
+{
+ int unit, port;
+ struct tty *tp;
+ struct vx_info *vxt;
+ struct vxsoftc *sc;
+ int s;
+ struct close_packet cpkt;
+ unit = VX_UNIT(dev);
+ if (unit >= vx_cd.cd_ndevs ||
+ (sc = (struct vxsoftc *) vx_cd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ port = VX_PORT(dev);
+/* flush_ctl(sc, port, 2); flush both input and output */
+
+ vxt = &sc->sc_info[port];
+ tp = vxt->tty;
+ (*linesw[tp->t_line].l_close)(tp, flag);
+
+ if((tp->t_cflag & HUPCL) != 0) {
+ rts_ctl(sc, port, 0);
+ dtr_ctl(sc, port, 0);
+ }
+
+ s = splvx();
+
+ bzero(&cpkt, sizeof(struct packet));
+ cpkt.eye_catcher[0] = 0x55;
+ cpkt.eye_catcher[1] = 0x55;
+ cpkt.eye_catcher[2] = 0x55;
+ cpkt.eye_catcher[3] = 0x55;
+ cpkt.command_pipe_number = sc->channel_number;
+ cpkt.status_pipe_number = sc->channel_number;
+ cpkt.command = CMD_CLOSE;
+ cpkt.device_number = port;
+
+ bpp_send(sc, &cpkt, NOWAIT);
+ splx(s);
+ ttyclose(tp);
+ sc->sc_info[port].open = 0;
+ return (0);
+}
+
+void
+read_wakeup(sc, port)
+struct vxsoftc *sc;
+int port;
+{
+ struct rring *rp;
+ struct read_wakeup_packet rwp;
+ volatile struct vx_info *vxt;
+ vxt = &sc->sc_info[port];
+ /*
+ * If we already have a read_wakeup paket
+ * for this port, do nothing.
+ */
+ if (vxt->read_pending) {
+ return;
+ } else {
+ vxt->read_pending = 1;
+ }
+
+ bzero(&rwp, sizeof(struct packet));
+ rwp.eye_catcher[0] = 0x11;
+ rwp.eye_catcher[1] = 0x11;
+ rwp.eye_catcher[2] = 0x11;
+ rwp.eye_catcher[3] = 0x11;
+ rwp.command_pipe_number = sc->channel_number;
+ rwp.status_pipe_number = sc->channel_number;
+ rwp.command = CMD_READW;
+ rwp.device_number = port;
+
+ /*
+ * Do not wait. Characters will be transfered
+ * to (*linesw[tp->t_line].l_rint)(c,tp); by
+ * vx_intr() (IPC will notify via interrupt)
+ */
+ bpp_send(sc, &rwp, NOWAIT);
+}
+
+int
+vxread (dev, uio, flag)
+dev_t dev;
+struct uio *uio;
+int flag;
+{
+ int unit, port;
+ struct tty *tp;
+ volatile struct vx_info *vxt;
+ volatile struct vxsoftc *sc;
+
+ unit = VX_UNIT(dev);
+ if (unit >= vx_cd.cd_ndevs ||
+ (sc = (struct vxsoftc *) vx_cd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ port = VX_PORT(dev);
+ vxt = &sc->sc_info[port];
+ tp = vxt->tty;
+ if (!tp) return ENXIO;
+ return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+int
+vxwrite (dev, uio, flag)
+dev_t dev;
+struct uio *uio;
+int flag;
+{
+ int unit, port;
+ struct tty *tp;
+ struct vx_info *vxt;
+ struct vxsoftc *sc;
+ struct wring *wp;
+ struct write_wakeup_packet wwp;
+ u_short get, put;
+ int i, cnt, s;
+
+ unit = VX_UNIT(dev);
+ if (unit >= vx_cd.cd_ndevs ||
+ (sc = (struct vxsoftc *) vx_cd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+
+ port = VX_PORT(dev);
+ vxt = &sc->sc_info[port];
+ tp = vxt->tty;
+ if (!tp) return ENXIO;
+
+ wp = sc->sc_info[port].wringp;
+ get = wp->get;
+ put = wp->put;
+
+ if ((put + 1) == get) {
+ bzero(&wwp, sizeof(struct packet));
+ wwp.eye_catcher[0] = 0x22;
+ wwp.eye_catcher[1] = 0x22;
+ wwp.eye_catcher[2] = 0x22;
+ wwp.eye_catcher[3] = 0x22;
+ wwp.command_pipe_number = sc->channel_number;
+ wwp.status_pipe_number = sc->channel_number;
+ wwp.command = CMD_WRITEW;
+ wwp.device_number = port;
+
+ bpp_send(sc, &wwp, WAIT_POLL);
+
+ if (wwp.error_l) {
+ return (ENXIO);
+ }
+ }
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+int
+vxioctl (dev, cmd, data, flag, p)
+dev_t dev;
+int cmd;
+caddr_t data;
+int flag;
+struct proc *p;
+{
+ int error;
+ int unit, port;
+ struct tty *tp;
+ struct vx_info *vxt;
+ struct vxsoftc *sc;
+ unit = VX_UNIT(dev);
+ if (unit >= vx_cd.cd_ndevs ||
+ (sc = (struct vxsoftc *) vx_cd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ port = VX_PORT(dev);
+ vxt = &sc->sc_info[port];
+ tp = vxt->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) vx_mctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
+ break;
+
+ case TIOCCDTR:
+ (void) vx_mctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
+ break;
+
+ case TIOCMSET:
+ (void) vx_mctl(dev, *(int *) data, DMSET);
+ break;
+
+ case TIOCMBIS:
+ (void) vx_mctl(dev, *(int *) data, DMBIS);
+ break;
+
+ case TIOCMBIC:
+ (void) vx_mctl(dev, *(int *) data, DMBIC);
+ break;
+
+ case TIOCMGET:
+ *(int *)data = vx_mctl(dev, 0, DMGET);
+ break;
+
+ case TIOCGFLAGS:
+ *(int *)data = vxt->vx_swflags;
+ break;
+
+ case TIOCSFLAGS:
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0)
+ return(EPERM);
+
+ vxt->vx_swflags = *(int *)data;
+ vxt->vx_swflags &= /* only allow valid flags */
+ (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
+ break;
+
+ default:
+ return (ENOTTY);
+ }
+ return 0;
+}
+
+int
+vxstop(tp, flag)
+struct tty *tp;
+int flag;
+{
+ int s;
+
+ s = splvx();
+ 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
+vxgetc(sc, port)
+struct vxsoftc *sc;
+int *port;
+{
+ return 0;
+}
+
+static void
+vxputc(sc, port, c)
+struct vxsoftc *sc;
+int port;
+u_char c;
+{
+ struct wring *wp;
+
+ wp = sc->sc_info[port].wringp;
+ wp->data[wp->put++ & (WRING_BUF_SIZE-1)] = c;
+ wp->put &= (WRING_BUF_SIZE-1);
+ return;
+}
+
+u_short vxtspeed(speed)
+int speed;
+{
+ switch (speed) {
+ case B0:
+ return VB0;
+ break;
+ case B50:
+ return VB50;
+ break;
+ case B75:
+ return VB75;
+ break;
+ case B110:
+ return VB110;
+ break;
+ case B134:
+ return VB134;
+ break;
+ case B150:
+ return VB150;
+ break;
+ case B200:
+ return VB200;
+ break;
+ case B300:
+ return VB300;
+ break;
+ case B600:
+ return VB600;
+ break;
+ case B1200:
+ return VB1200;
+ break;
+ case B1800:
+ return VB1800;
+ break;
+ case B2400:
+ return VB2400;
+ break;
+ case B4800:
+ return VB4800;
+ break;
+ case B9600:
+ return VB9600;
+ break;
+ case B19200:
+ return VB19200;
+ break;
+ case B38400:
+ return VB38400;
+ break;
+ default:
+ return VB9600;
+ break;
+ }
+}
+
+int
+vx_ccparam(sc, par, port)
+struct vxsoftc *sc;
+struct termios *par;
+int port;
+{
+ struct termio tio;
+ int imask=0, ints, s;
+ int cflag, iflag, oflag, lflag;
+ struct ioctl_a_packet pkt;
+ bzero(&pkt, sizeof(struct packet));
+
+ if (par->c_ospeed == 0) {
+ s = splvx();
+ /* dont kill the console */
+ if(sc->sc_info[port].vx_consio == 0) {
+ /* disconnect, drop RTS DTR stop reciever */
+ rts_ctl(sc, port, 0);
+ dtr_ctl(sc, port, 0);
+ }
+ splx(s);
+ return (0xff);
+ }
+
+ pkt.command = CMD_IOCTL;
+ pkt.ioctl_cmd_l = IOCTL_TCGETA;
+ pkt.command_pipe_number = sc->channel_number;
+ pkt.status_pipe_number = sc->channel_number;
+ pkt.device_number = port;
+ bpp_send(sc, &pkt, WAIT_POLL);
+
+ cflag = pkt.c_cflag;
+ cflag |= vxtspeed(par->c_ospeed);
+
+ switch (par->c_cflag & CSIZE) {
+ case CS5:
+ cflag |= VCS5;
+ imask = 0x1F;
+ break;
+ case CS6:
+ cflag |= VCS6;
+ imask = 0x3F;
+ break;
+ case CS7:
+ cflag |= VCS7;
+ imask = 0x7F;
+ break;
+ default:
+ cflag |= VCS8;
+ imask = 0xFF;
+ }
+
+ if (par->c_cflag & PARENB) cflag |= VPARENB; else cflag &= ~VPARENB;
+ if (par->c_cflag & PARODD) cflag |= VPARODD; else cflag &= ~VPARODD;
+ if (par->c_cflag & CREAD) cflag |= VCREAD; else cflag &= ~VCREAD;
+ if (par->c_cflag & CLOCAL) cflag |= VCLOCAL; else cflag &= ~VCLOCAL;
+ if (par->c_cflag & HUPCL) cflag |= VHUPCL; else cflag &= ~VHUPCL;
+ /*
+ if (par->c_iflag & BRKINT) iflag |= VBRKINT; else iflag &= ~VBRKINT;
+ if (par->c_iflag & ISTRIP) iflag |= VISTRIP; else iflag &= ~VISTRIP;
+ if (par->c_iflag & ICRNL) iflag |= VICRNL; else iflag &= ~VICRNL;
+ if (par->c_iflag & IXON) iflag |= VIXON; else iflag &= ~VIXON;
+ if (par->c_iflag & IXANY) iflag |= VIXANY; else iflag &= ~VIXANY;
+ if (par->c_oflag & OPOST) oflag |= VOPOST; else oflag &= ~VOPOST;
+ if (par->c_oflag & ONLCR) oflag |= VONLCR; else oflag &= ~VONLCR;
+ if (par->c_oflag & OXTABS) oflag |= VOXTABS; else oflag &= ~VOXTABS;
+ if (par->c_lflag & ECHO) lflag |= VECHO; else lflag &= ~VECHO;
+ if (par->c_lflag & ECHOE) lflag |= VECHOE; else lflag &= ~VECHOE;
+ if (par->c_lflag & ICANON) lflag |= VICANON; else lflag &= ~VICANON;
+ if (par->c_lflag & ISIG) lflag |= VISIG; else lflag &= ~VISIG;
+ */
+ pkt.command = CMD_IOCTL;
+ pkt.ioctl_cmd_l = IOCTL_TCSETA;
+ pkt.command_pipe_number = sc->channel_number;
+ pkt.status_pipe_number = sc->channel_number;
+ pkt.device_number = port;
+ pkt.c_cflag = cflag;
+/*
+ pkt.c_iflag = iflag;
+ pkt.c_oflag = oflag;
+ pkt.c_lflag = lflag;
+ */
+
+ bpp_send(sc, &pkt, WAIT_POLL);
+ return imask;
+}
+
+void
+vx_unblock(tp)
+struct tty *tp;
+{
+ tp->t_state &= ~TS_FLUSH;
+ if (tp->t_outq.c_cc != 0)
+ vxstart(tp);
+}
+
+void
+vxstart(tp)
+struct tty *tp;
+{
+ dev_t dev;
+ u_char cbuf;
+ struct vxsoftc *sc;
+ struct wring *wp;
+ int cc, port, unit, s, cnt, i;
+ u_short get, put;
+ char buffer[WRING_BUF_SIZE];
+ char *wrdp;
+
+ dev = tp->t_dev;
+ port = VX_PORT(dev);
+ unit = VX_UNIT(dev);
+ if (unit >= vx_cd.cd_ndevs ||
+ (sc = (struct vxsoftc *) vx_cd.cd_devs[unit]) == NULL) {
+ return;
+ }
+
+ if ((tp->t_state & TS_ISOPEN) == 0)
+ return;
+
+ s = splvx();
+ if ((tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP | TS_FLUSH)) == 0) {
+ tp->t_state |= TS_BUSY;
+ wp = sc->sc_info[port].wringp;
+ get = wp->get;
+ put = wp->put;
+ cc = tp->t_outq.c_cc;
+ while (cc > 0) {
+ cnt = min(WRING_BUF_SIZE, cc);
+ cnt = q_to_b(&tp->t_outq, buffer, cnt);
+ buffer[cnt] = 0;
+ for (i=0; i<cnt; i++) {
+ vxputc(sc, port, buffer[i]);
+ }
+ cc -= cnt;
+ }
+ tp->t_state &= ~TS_BUSY;
+ }
+ splx(s);
+ return;
+}
+
+void
+read_chars(sc, port)
+struct vxsoftc *sc;
+int port;
+{
+ /*
+ * This routine is called by vx_intr() when there are
+ * characters in the read ring. It will process one
+ * cooked line, put the chars in the line disipline ring,
+ * and then return. The characters may then
+ * be read by vxread.
+ */
+ struct vx_info *vxt;
+ struct rring *rp;
+ struct read_wakeup_packet rwp;
+ struct tty *tp;
+ u_short get, put;
+ int frame_count, i, pc = 0, open;
+ char c;
+
+ vxt = &sc->sc_info[port];
+ tp = vxt->tty;
+ rp = vxt->rringp;
+ open = vxt->open;
+ get = rp->get;
+ put = rp->put;
+#ifdef DEBUG_VXT
+ printf("read_chars() get=%d, put=%d ", get, put);
+ printf("open = %d ring at 0x%x\n", open, rp);
+#endif
+ while (get != put) {
+ frame_count = rp->data[rp->get++ & (RRING_BUF_SIZE - 1)];
+ rp->get &= (RRING_BUF_SIZE - 1);
+ for (i=0; i<frame_count; i++) {
+ c = rp->data[rp->get++ & (RRING_BUF_SIZE - 1)];
+ rp->get &= (RRING_BUF_SIZE - 1);
+ if (open)
+ (*linesw[tp->t_line].l_rint)(c,tp);
+ }
+ c = rp->data[rp->get++ & (RRING_BUF_SIZE - 1)];
+ rp->get &= (RRING_BUF_SIZE - 1);
+ if (!(c & DELIMITER)) {
+ vx_frame (sc, port);
+ break;
+ } else {
+ break;
+ }
+ get = rp->get;
+ put = rp->put;
+ }
+ vxt->read_pending = 0;
+ read_wakeup(sc, port);
+ return;
+}
+
+ccode(sc, port, c)
+struct vxsoftc *sc;
+int port;
+char c;
+{
+ struct vx_info *vxt;
+ struct tty *tp;
+ tp = vxt->tty;
+ vxt = &sc->sc_info[port];
+ tp = vxt->tty;
+ (*linesw[tp->t_line].l_rint)(c,tp);
+}
+
+int
+vx_intr(sc)
+struct vxsoftc *sc;
+{
+ struct envelope *envp, *next_envp;
+ struct envelope env;
+ struct packet *pktp, pkt;
+ int valid, i;
+ short cmd;
+ u_char port;
+ struct vme2reg *vme2 = (struct vme2reg *)sc->sc_vme2;
+
+ if (vme2->vme2_vbr & VME2_SYSFAIL){
+ /* do something... print_dump(sc); */
+ }
+ if (!cold) sc->sc_intrcnt.ev_count++;
+
+ while (env_isvalid(get_status_head(sc))) {
+ pktp = get_packet(sc, get_status_head(sc));
+ valid = env_isvalid(get_status_head(sc));
+ cmd = pktp->command;
+ port = pktp->device_number;
+ /* if we are waiting on this packet, strore the info so bpp_send
+ can process the packet */
+ if (sc->sc_bppwait_pktp == pktp)
+ memcpy2(&sc->sc_bppwait_pkt, pktp, sizeof(struct packet));
+
+ memcpy2(&pkt, pktp, sizeof(struct packet));
+ next_envp = get_next_envelope(get_status_head(sc));
+ envp = get_status_head(sc);
+ /* return envelope and packet to the free queues */
+ put_free_envelope(sc, envp);
+ put_free_packet(sc, pktp);
+ /* mark new status pipe head pointer */
+ set_status_head(sc, next_envp);
+ /* if it was valid, process packet */
+ switch (cmd) {
+ case CMD_READW:
+#ifdef DEBUG_VXT
+ printf("READW Packet\n");
+#endif
+ read_chars(sc, port);
+ return 1;
+ break;
+ case CMD_WRITEW:
+#ifdef DEBUG_VXT
+ printf("WRITEW Packet\n"); /* Still don't know XXXsmurph */
+#endif
+ return 1;
+ break;
+ case CMD_EVENT:
+#ifdef DEBUG_VXT
+ printf("EVENT Packet\n");
+#endif
+ vx_event(sc, &pkt);
+ return 1;
+ break;
+ case CMD_PROCCESED:
+#ifdef DEBUG_VXT
+ printf("CMD_PROCCESED Packet\n");
+#endif
+ return 1;
+ break;
+ default:
+#ifdef DEBUG_VXT
+ printf("Other packet 0x%x\n", cmd);
+#endif
+ return 1;
+ break;
+ }
+ }
+ return 1;
+}
+
+int
+vx_event(sc, evntp)
+struct vxsoftc *sc;
+struct packet *evntp;
+{
+ u_short code = evntp->event_code;
+ struct event_packet evnt;
+ struct vx_info *vxt;
+
+ vxt = &sc->sc_info[evntp->device_number];
+
+ if (code & E_INTR) {
+ ccode(sc, evntp->device_number, CINTR);
+ }
+ if (code & E_QUIT) {
+ ccode(sc, evntp->device_number, CQUIT);
+ }
+ if (code & E_HUP) {
+ rts_ctl(sc, evntp->device_number, 0);
+ dtr_ctl(sc, evntp->device_number, 0);
+ }
+ if (code & E_DCD) {
+ vxt->vx_linestatus |= TIOCM_CD;
+ }
+ if (code & E_DSR) {
+ vxt->vx_linestatus |= TIOCM_DSR;
+ }
+ if (code & E_CTS) {
+ vxt->vx_linestatus |= TIOCM_CTS;
+ }
+ if (code & E_LOST_DCD) {
+ vxt->vx_linestatus &= ~TIOCM_CD;
+ }
+ if (code & E_LOST_DSR) {
+ vxt->vx_linestatus &= ~TIOCM_DSR;
+ }
+ if (code & E_LOST_CTS) {
+ vxt->vx_linestatus &= ~TIOCM_CTS;
+ }
+ if (code & E_PR_FAULT) {
+ /* do something... */
+ }
+ if (code & E_PR_POUT) {
+ /* do something... */
+ }
+ if (code & E_PR_SELECT) {
+ /* do something... */
+ }
+ if (code & E_SWITCH) {
+ /* do something... */
+ }
+ if (code & E_BREAK) {
+ vx_break (sc, evntp->device_number);
+ }
+
+ /* send and event packet backe to the device */
+ bzero(&evnt, sizeof(struct event_packet));
+ evnt.command = CMD_EVENT;
+ evnt.device_number = evntp->device_number;
+ evnt.command_pipe_number = sc->channel_number;
+ /* return status on same channel */
+ evnt.status_pipe_number = sc->channel_number;
+ /* send packet to the firmware */
+ bpp_send(sc, &evnt, NOWAIT);
+ return 1;
+}
+
+void
+vx_overflow (sc, port, ptime, msg)
+struct vxsoftc *sc;
+int port;
+long *ptime;
+u_char *msg;
+{
+ log(LOG_WARNING, "%s port %d: overrun\n", sc->sc_dev.dv_xname, port);
+ return;
+}
+
+void
+vx_frame (sc, port)
+struct vxsoftc *sc;
+int port;
+{
+ log(LOG_WARNING, "%s port %d: frame error\n", sc->sc_dev.dv_xname, port);
+ return;
+}
+
+void
+vx_break (sc, port)
+struct vxsoftc *sc;
+int port;
+{
+#ifdef DEBUG_KERN
+ Debugger();
+#else
+ log(LOG_WARNING, "%s port %d: break detected\n", sc->sc_dev.dv_xname, port);
+#endif
+ return;
+}
+
+/*
+ * Initialization and Buffered Pipe Protocol (BPP) code
+ */
+
+/* special function for 16 bit data transfer */
+/* Not needed now that I figured out VME bus */
+/* mappings and address modifiers, but I don't */
+/* want to change them :) */
+void *
+memcpy2(void *dest, const void *src, size_t size)
+{
+ int i;
+ short *d, *s;
+ d = (short*) dest;
+ s = (short*) src;
+ for (i=0; i<(size/2); i++) {
+ *d = *s;
+ d++;
+ s++;
+ }
+}
+
+void
+wzero(void *addr, size_t size)
+{
+ int i;
+ short *d;
+ d = (short*) addr;
+ for (i=0; i<(size/2); i++) {
+ *d = 0;
+ d++;
+ }
+}
+
+int
+create_free_queue(sc)
+struct vxsoftc *sc;
+{
+ int i;
+ struct envelope *envp;
+ struct envelope env;
+ struct packet *pktp;
+ struct packet pkt;
+
+ envp = (struct envelope *)ENVELOPE_AREA;
+ sc->elist_head = envp;
+ for (i=0; i < NENVELOPES; i++) {
+ bzero(envp, sizeof(struct envelope));
+ if (i==(NENVELOPES - 1)) {
+ envp->link = NULL;
+ } else {
+ envp->link = (u_long)envp + sizeof(struct envelope);
+ }
+ envp->packet_ptr = NULL;
+ envp->valid_flag = 0;
+ envp++;
+ }
+ sc->elist_tail = --envp;
+
+ pktp = (struct packet *)PACKET_AREA;
+ sc->plist_head = pktp;
+ for (i=0; i < NPACKETS; i++) {
+ bzero(pktp, sizeof(struct packet));
+ if (i==(NPACKETS - 1)) {
+ pktp->link = NULL;
+ } else {
+ pktp->link = (u_long)pktp + sizeof(struct packet);
+ }
+ pktp++;
+ }
+ sc->plist_tail = --pktp;
+ return 0; /* no error */
+}
+
+void *
+get_free_envelope(sc)
+struct vxsoftc *sc;
+{
+ void *envp;
+
+ envp = sc->elist_head;
+ sc->elist_head = (struct envelope *)sc->elist_head->link;
+ bzero(envp, sizeof(struct envelope));
+ return envp;
+}
+
+void
+put_free_envelope(sc, ep)
+struct vxsoftc *sc;
+void * ep;
+{
+ struct envelope *envp = (struct envelope *)ep;
+ bzero(envp, sizeof(struct envelope));
+ sc->elist_tail->link = (ulong)envp;
+ envp->link = NULL;
+ sc->elist_tail = envp;
+}
+
+void*
+get_free_packet(sc)
+struct vxsoftc *sc;
+{
+ struct packet *pktp;
+
+ pktp = sc->plist_head;
+ sc->plist_head = (struct packet *)sc->plist_head->link;
+ bzero(pktp, sizeof(struct packet));
+ return pktp;
+}
+
+void
+put_free_packet(sc, pp)
+struct vxsoftc *sc;
+void *pp;
+{
+ struct packet *pktp = (struct packet *)pp;
+ /*bzero(pktp, sizeof(struct packet));*/
+ pktp->command = CMD_PROCCESED;
+ sc->plist_tail->link = (u_long)pktp;
+ pktp->link = NULL;
+ sc->plist_tail = pktp;
+}
+
+/*
+ * This is the nitty gritty. All the rest if this code
+ * was hell to come by. Getting this right from the
+ * Moto manual took *time*!
+ */
+int
+create_channels(sc)
+struct vxsoftc *sc;
+{
+ struct envelope *envp;
+ struct envelope env;
+ struct packet *pktp;
+ u_char valid;
+ u_short status;
+ u_short tas, csr;
+ struct vxreg *ipc_csr;
+
+ ipc_csr = sc->vx_reg;
+ /* wait for busy bit to clear */
+ while ((ipc_csr->ipc_cr & IPC_CR_BUSY));
+ create_free_queue(sc);
+ /* set up channel header. we only want one */
+ tas = ipc_csr->ipc_tas;
+ while (!(tas & IPC_TAS_VALID_STATUS)) {
+ envp = get_free_envelope(sc);
+ sc->channel->command_pipe_head_ptr_h = HI(envp);
+ sc->channel->command_pipe_head_ptr_l = LO(envp);
+ sc->channel->command_pipe_tail_ptr_h = sc->channel->command_pipe_head_ptr_h;
+ sc->channel->command_pipe_tail_ptr_l = sc->channel->command_pipe_head_ptr_l;
+ envp = get_free_envelope(sc);
+ sc->channel->status_pipe_head_ptr_h = HI(envp);
+ sc->channel->status_pipe_head_ptr_l = LO(envp);
+ sc->channel->status_pipe_tail_ptr_h = sc->channel->status_pipe_head_ptr_h;
+ sc->channel->status_pipe_tail_ptr_l = sc->channel->status_pipe_head_ptr_l;
+ sc->channel->interrupt_level = sc->sc_ipl;
+ sc->channel->interrupt_vec = sc->sc_vec;
+ sc->channel->channel_priority = 0;
+ sc->channel->channel_number = 0;
+ sc->channel->valid = 1;
+ sc->channel->address_modifier = 0x8D; /* A32/D16 supervisor data access */
+ sc->channel->datasize = 0; /* 32 bit data mode */
+
+ /* loop until TAS bit is zero */
+ while ((ipc_csr->ipc_tas & IPC_TAS_TAS));
+ ipc_csr->ipc_tas |= IPC_TAS_TAS;
+ /* load address of channel header */
+ ipc_csr->ipc_addrh = HI(sc->channel);
+ ipc_csr->ipc_addrl = LO(sc->channel);
+ /* load address modifier reg (supervisor data access) */
+ ipc_csr->ipc_amr = 0x8D;
+ /* load tas with create channel command */
+ ipc_csr->ipc_tas |= IPC_CSR_CREATE;
+ /* set vaild command bit */
+ ipc_csr->ipc_tas |= IPC_TAS_VALID_CMD;
+ /* notify IPC of the CSR command */
+ ipc_csr->ipc_cr |= IPC_CR_ATTEN;
+ /* loop until IPC sets vaild status bit */
+ delay(5000);
+ tas = ipc_csr->ipc_tas;
+ }
+
+ /* save the status */
+ status = ipc_csr->ipc_sr;
+ /* set COMMAND COMPLETE bit */
+ ipc_csr->ipc_tas |= IPC_TAS_COMPLETE;
+ /* notify IPC that we are through */
+ ipc_csr->ipc_cr |= IPC_CR_ATTEN;
+ /* check and see if the channel was created */
+ if (!status && sc->channel->valid) {
+ sc->channel_number = sc->channel->channel_number;
+ printf("%s: created channel %d\n", sc->sc_dev.dv_xname,
+ sc->channel->channel_number);
+ return 0;
+ } else {
+ switch (status) {
+ case 0x0000:
+ printf("%s: channel not valid\n",
+ sc->sc_dev.dv_xname);
+ break;
+ case 0xFFFF:
+ printf("%s: invalid CSR command\n",
+ sc->sc_dev.dv_xname);
+ break;
+ case 0xC000:
+ printf("%s: could not read channel structure\n",
+ sc->sc_dev.dv_xname);
+ break;
+ case 0x8000:
+ printf("%s: could not write channel structure\n",
+ sc->sc_dev.dv_xname);
+ break;
+ default:
+ printf("%s: unknown IPC CSR command error 0x%x\n",
+ sc->sc_dev.dv_xname, status);
+ break;
+ }
+ return status; /* error */
+ }
+}
+
+void
+print_dump(sc)
+struct vxsoftc *sc;
+{
+ char *dump_area, *end_dump, *dumpp;
+ char dump[209];
+ char dump2[209];
+ bzero(&dump, 209);
+
+ dump_area = (char *)0xff780030;
+ memcpy2(&dump, dump_area, 208);
+
+ printf("%s", dump);
+}
+
+void *
+get_next_envelope(thisenv)
+struct envelope *thisenv;
+{
+ return ((void *)thisenv->link);
+}
+
+int
+env_isvalid(thisenv)
+struct envelope *thisenv;
+{
+ return thisenv->valid_flag;
+}
+
+struct envelope *
+get_cmd_tail(sc)
+struct vxsoftc *sc;
+{
+ unsigned long retaddr;
+ retaddr = (unsigned long)sc->vx_reg;
+ retaddr += sc->channel->command_pipe_tail_ptr_l;
+ return ((struct envelope *)retaddr);
+}
+
+struct envelope *
+get_status_head(sc)
+struct vxsoftc *sc;
+{
+ unsigned long retaddr;
+ retaddr = (unsigned long)sc->vx_reg;
+ retaddr += sc->channel->status_pipe_head_ptr_l;
+ return ((struct envelope *)retaddr);
+}
+
+void
+set_status_head(sc, envp)
+struct vxsoftc *sc;
+void *envp;
+{
+ sc->channel->status_pipe_head_ptr_h = HI(envp);
+ sc->channel->status_pipe_head_ptr_l = LO(envp);
+ return;
+}
+
+struct packet *
+get_packet(sc, thisenv)
+struct vxsoftc *sc;
+struct envelope *thisenv;
+{
+ struct envelope env;
+ unsigned long baseaddr;
+
+ if (thisenv == NULL) return NULL;
+ baseaddr = (unsigned long)sc->vx_reg;
+ /*
+ * packet ptr returned on status pipe is only last two bytes
+ * so we must supply the full address based on the board address.
+ * This also works for all envelopes because every address is an
+ * offset to the board address
+ */
+ baseaddr |= thisenv->packet_ptr;
+ return ((void*)baseaddr);
+}
+
+/*
+ * Send a command via BPP
+ */
+int
+bpp_send(struct vxsoftc *sc, void *pkt, int wait_flag)
+{
+ struct envelope *envp;
+ struct init_packet init, *initp;
+ struct packet *wpktp, *pktp, *testpktp;
+ struct vme2reg *vme2 = (struct vme2reg *)sc->sc_vme2;
+ unsigned long newenv;
+ int i, s;
+
+
+ /* load up packet in dual port mem */
+ pktp = get_free_packet(sc);
+ memcpy2(pktp, pkt, sizeof(struct packet));
+
+ envp = get_cmd_tail(sc);
+ newenv = (unsigned long)get_free_envelope(sc); /* put a NULL env on the tail */
+ envp->link = newenv;
+ sc->channel->command_pipe_tail_ptr_h = HI(newenv);
+ sc->channel->command_pipe_tail_ptr_l = LO(newenv);
+ envp->packet_ptr = (u_long)pktp; /* add the command packet */
+ envp->valid_flag = 1; /* set valid command flag */
+
+ sc->vx_reg->ipc_cr |= IPC_CR_ATTEN;
+ if (wait_flag) { /* wait for a packet to return */
+ while (pktp->command != CMD_PROCCESED) {
+#ifdef DEBUG_VXT
+ printf("Polling for packet 0x%x in envelope 0x%x...\n", pktp, envp);
+#endif
+ vx_intr(sc);
+ delay(5000);
+ }
+ memcpy2(pkt, pktp, sizeof(struct packet));
+ return 0;
+ }
+ return 0; /* no error */
+}
+
+/*
+ * BPP commands
+ */
+int
+vx_init(sc)
+struct vxsoftc *sc;
+{
+ int i;
+ struct init_info *infp, inf;
+ struct wring *wringp;
+ struct rring *rringp;
+ struct termio def_termio;
+ struct init_packet init;
+ struct event_packet evnt;
+
+ bzero(&def_termio, sizeof(struct termio));
+ /* init wait queue */
+ bzero(&sc->sc_bppwait_pkt, sizeof(struct packet));
+ sc->sc_bppwait_pktp = NULL;
+ /* set up init_info array */
+ wringp = (struct wring *)WRING_AREA;
+ rringp = (struct rring *)RRING_AREA;
+ infp = (struct init_info *)INIT_INFO_AREA;
+ for (i=0; i<9; i++) {
+ bzero(&inf, sizeof(struct init_info));
+ infp->write_ring_ptr_h = HI(wringp);
+ infp->write_ring_ptr_l = LO(wringp);
+ sc->sc_info[i].wringp = wringp;
+ infp->read_ring_ptr_h = HI(rringp);
+ infp->read_ring_ptr_l = LO(rringp);
+ sc->sc_info[i].rringp = rringp;
+#ifdef DEBUG_VXT
+ printf("write at 0x%8x, read at 0x%8x\n", wringp, rringp);
+#endif
+ infp->write_ring_size = WRING_DATA_SIZE;
+ infp->read_ring_size = RRING_DATA_SIZE;
+ infp->def_termio.c_iflag = VBRKINT;
+ infp->def_termio.c_oflag = 0;
+ infp->def_termio.c_cflag = (VB9600 | VCS8);
+
+ infp->def_termio.c_lflag = VISIG; /* enable signal processing */
+ infp->def_termio.c_line = 1; /* raw line disipline, we want to control it! */
+ infp->def_termio.c_cc[0] = CINTR;
+ infp->def_termio.c_cc[1] = CQUIT;
+ infp->def_termio.c_cc[2] = CERASE;
+ infp->def_termio.c_cc[3] = CKILL;
+ infp->def_termio.c_cc[4] = 20;
+ infp->def_termio.c_cc[5] = 2;
+ infp->reserved1 = 0; /* Must be Zero */
+ infp->reserved2 = 0;
+ infp->reserved3 = 0;
+ infp->reserved4 = 0;
+ wringp++; rringp++; infp++;
+ }
+ /* set up init_packet */
+ bzero(&init, sizeof(struct init_packet));
+ init.eye_catcher[0] = 0x12;
+ init.eye_catcher[1] = 0x34;
+ init.eye_catcher[2] = 0x56;
+ init.eye_catcher[3] = 0x78;
+ init.command = CMD_INIT;
+ init.command_pipe_number = sc->channel_number;
+ /* return status on the same channel */
+ init.status_pipe_number = sc->channel_number;
+ init.interrupt_level = sc->sc_ipl;
+ init.interrupt_vec = sc->sc_vec;
+ init.init_info_ptr_h = HI(INIT_INFO_AREA);
+ init.init_info_ptr_l = LO(INIT_INFO_AREA);
+
+ /* send packet to the firmware and wait for completion */
+ bpp_send(sc, &init, WAIT_POLL);
+
+ /* check for error */
+ if (init.error_l !=0) {
+ return init.error_l;
+ } else {
+ /* send one event packet to each device; */
+ for (i=0; i<9; i++) {
+ bzero(&evnt, sizeof(struct event_packet));
+ evnt.command = CMD_EVENT;
+ evnt.device_number = i;
+ evnt.command_pipe_number = sc->channel_number;
+ /* return status on same channel */
+ evnt.status_pipe_number = sc->channel_number;
+ /* send packet to the firmware */
+ bpp_send(sc, &evnt, NOWAIT);
+ }
+ return 0;
+ }
+}
+
+