Annotation of sys/arch/mvme88k/dev/vx.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: vx.c,v 1.38 2006/07/28 21:46:02 miod Exp $ */
! 2: /*
! 3: * Copyright (c) 1999 Steve Murphree, Jr.
! 4: * All rights reserved.
! 5: *
! 6: * Redistribution and use in source and binary forms, with or without
! 7: * modification, are permitted provided that the following conditions
! 8: * are met:
! 9: * 1. Redistributions of source code must retain the above copyright
! 10: * notice, this list of conditions and the following disclaimer.
! 11: * 2. Redistributions in binary form must reproduce the above copyright
! 12: * notice, this list of conditions and the following disclaimer in the
! 13: * documentation and/or other materials provided with the distribution.
! 14: * 3. The name of the author may not be used to endorse or promote products
! 15: * derived from this software without specific prior written permission.
! 16: *
! 17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 18: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 19: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 20: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 21: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 22: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 23: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 24: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 25: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 26: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 27: */
! 28:
! 29: /* This card lives in D16 space */
! 30: #define __BUS_SPACE_RESTRICT_D16__
! 31:
! 32: #include <sys/param.h>
! 33: #include <sys/ioctl.h>
! 34: #include <sys/proc.h>
! 35: #include <sys/tty.h>
! 36: #include <sys/uio.h>
! 37: #include <sys/systm.h>
! 38: #include <sys/time.h>
! 39: #include <sys/device.h>
! 40: #include <sys/syslog.h>
! 41:
! 42: #include <machine/autoconf.h>
! 43: #include <machine/conf.h>
! 44: #include <machine/cpu.h>
! 45: #include <machine/psl.h>
! 46:
! 47: #include <dev/cons.h>
! 48:
! 49: #include <mvme88k/dev/vme.h>
! 50: #include <mvme88k/dev/vxreg.h>
! 51:
! 52: #define splvx() spltty()
! 53:
! 54: struct vx_info {
! 55: struct tty *tty;
! 56: u_char vx_swflags;
! 57: int vx_linestatus;
! 58: int open;
! 59: int waiting;
! 60: u_char vx_speed;
! 61: u_char read_pending;
! 62: struct wring *wringp;
! 63: struct rring *rringp;
! 64: };
! 65:
! 66: struct vxsoftc {
! 67: struct device sc_dev;
! 68: struct vx_info sc_info[NVXPORTS];
! 69: struct vxreg *vx_reg;
! 70: vaddr_t board_vaddr;
! 71: struct channel *channel;
! 72: char channel_number;
! 73: struct packet sc_bppwait_pkt;
! 74: void *sc_bppwait_pktp;
! 75: struct intrhand sc_ih;
! 76: int sc_vec;
! 77: struct envelope *elist_head, *elist_tail;
! 78: struct packet *plist_head, *plist_tail;
! 79: };
! 80:
! 81: int vxmatch(struct device *, void *, void *);
! 82: void vxattach(struct device *, struct device *, void *);
! 83:
! 84: struct cfattach vx_ca = {
! 85: sizeof(struct vxsoftc), vxmatch, vxattach
! 86: };
! 87:
! 88: struct cfdriver vx_cd = {
! 89: NULL, "vx", DV_TTY
! 90: };
! 91:
! 92: int bpp_send(struct vxsoftc *, void *, int);
! 93: void ccode(struct vxsoftc *, int, char);
! 94: int create_channels(struct vxsoftc *);
! 95: void create_free_queue(struct vxsoftc *);
! 96: short dtr_ctl(struct vxsoftc *, int, int);
! 97: int env_isvalid(struct envelope *);
! 98: struct envelope *find_status_packet(struct vxsoftc *, struct packet *);
! 99: short flush_ctl(struct vxsoftc *, int, int);
! 100: struct envelope *get_cmd_tail(struct vxsoftc *);
! 101: void *get_free_envelope(struct vxsoftc *);
! 102: void *get_free_packet(struct vxsoftc *);
! 103: struct envelope *get_next_envelope(struct vxsoftc *, struct envelope *);
! 104: struct packet *get_packet(struct vxsoftc *, struct envelope *);
! 105: struct envelope *get_status_head(struct vxsoftc *);
! 106: void put_free_envelope(struct vxsoftc *, void *);
! 107: void put_free_packet(struct vxsoftc *, void *);
! 108: void read_chars(struct vxsoftc *, int);
! 109: void read_wakeup(struct vxsoftc *, int);
! 110: short rts_ctl(struct vxsoftc *, int, int);
! 111: void set_status_head(struct vxsoftc *, void *);
! 112: void vx_break(struct vxsoftc *, int);
! 113: int vx_ccparam(struct vxsoftc *, struct termios *, int);
! 114: int vx_event(struct vxsoftc *, struct packet *);
! 115: void vx_frame(struct vxsoftc *, int);
! 116: int vx_init(struct vxsoftc *);
! 117: int vx_intr(void *);
! 118: int vx_mctl(dev_t, int, int);
! 119: void vx_overflow(struct vxsoftc *, int, long *, u_char *);
! 120: int vx_param(struct tty *, struct termios *);
! 121: int vx_poll(struct vxsoftc *, struct packet *);
! 122: void vxputc(struct vxsoftc *, int, u_char);
! 123: int vx_sintr(struct vxsoftc *);
! 124: void vxstart(struct tty *tp);
! 125: u_short vxtspeed(int);
! 126: void vx_unblock(struct tty *);
! 127:
! 128: /* flags for bpp_send() */
! 129: #define NOWAIT 0
! 130: #define WAIT 1
! 131:
! 132: #define VX_UNIT(x) (minor(x) / NVXPORTS)
! 133: #define VX_PORT(x) (minor(x) % NVXPORTS)
! 134:
! 135: /*
! 136: * Convert dual-ported physical addresse to host virtual address, and the
! 137: * opposite.
! 138: */
! 139: #define VIRTUAL(addr) (((addr) & 0xffff) + sc->board_vaddr)
! 140: #define PHYSICAL(addr) \
! 141: (((addr - sc->board_vaddr) & 0xffff) | LOCAL_DPMEM_ADDRESS)
! 142:
! 143: #if 0
! 144: #define LO(x) (u_short)((unsigned long)x & 0x0000FFFF)
! 145: #define HI(x) (u_short)((unsigned long)x >> 16)
! 146: #else
! 147: #define LO(x) (u_short)(x)
! 148: #define HI(x) (LOCAL_DPMEM_ADDRESS >> 16)
! 149: #endif
! 150:
! 151: struct tty *
! 152: vxtty(dev_t dev)
! 153: {
! 154: int unit, port;
! 155: struct vxsoftc *sc;
! 156:
! 157: unit = VX_UNIT(dev);
! 158: if (unit >= vx_cd.cd_ndevs ||
! 159: (sc = (struct vxsoftc *)vx_cd.cd_devs[unit]) == NULL) {
! 160: return (NULL);
! 161: }
! 162: port = VX_PORT(dev);
! 163: return sc->sc_info[port].tty;
! 164: }
! 165:
! 166: int
! 167: vxmatch(struct device *parent, void *self, void *aux)
! 168: {
! 169: struct vxreg *vx_reg;
! 170: struct confargs *ca = aux;
! 171: bus_space_tag_t iot = ca->ca_iot;
! 172: bus_space_handle_t ioh;
! 173: int rc;
! 174:
! 175: if (bus_space_map(iot, ca->ca_paddr, 0x10000, 0, &ioh) != 0)
! 176: return 0;
! 177: vx_reg = (struct vxreg *)bus_space_vaddr(iot, ioh);
! 178: rc = badaddr((vaddr_t)&vx_reg->ipc_cr, 1);
! 179: bus_space_unmap(iot, ioh, 0x10000);
! 180:
! 181: return rc == 0;
! 182: }
! 183:
! 184: void
! 185: vxattach(struct device *parent, struct device *self, void *aux)
! 186: {
! 187: struct vxsoftc *sc = (struct vxsoftc *)self;
! 188: struct confargs *ca = aux;
! 189: bus_space_tag_t iot = ca->ca_iot;
! 190: bus_space_handle_t ioh;
! 191:
! 192: if (ca->ca_vec < 0) {
! 193: printf(": no more interrupts!\n");
! 194: return;
! 195: }
! 196: if (ca->ca_ipl < 0)
! 197: ca->ca_ipl = IPL_TTY;
! 198:
! 199: if (bus_space_map(iot, ca->ca_paddr, 0x10000, 0, &ioh) != 0) {
! 200: printf(": can't map registers!\n");
! 201: return;
! 202: }
! 203:
! 204: /* set up dual port memory and registers and init */
! 205: sc->board_vaddr = (vaddr_t)bus_space_vaddr(iot, ioh);
! 206: sc->vx_reg = (struct vxreg *)sc->board_vaddr;
! 207: sc->channel = (struct channel *)(sc->board_vaddr + 0x0100);
! 208: sc->sc_vec = ca->ca_vec;
! 209:
! 210: printf("\n");
! 211:
! 212: if (create_channels(sc) != 0) {
! 213: printf("%s: failed to create channel %d\n",
! 214: sc->sc_dev.dv_xname, sc->channel->channel_number);
! 215: return;
! 216: }
! 217: if (vx_init(sc) != 0) {
! 218: printf("%s: failed to initialize\n", sc->sc_dev.dv_xname);
! 219: return;
! 220: }
! 221:
! 222: /* enable interrupts */
! 223: sc->sc_ih.ih_fn = vx_intr;
! 224: sc->sc_ih.ih_arg = sc;
! 225: sc->sc_ih.ih_wantframe = 0;
! 226: sc->sc_ih.ih_ipl = IPL_TTY;
! 227:
! 228: vmeintr_establish(ca->ca_vec, &sc->sc_ih, self->dv_xname);
! 229: }
! 230:
! 231: short
! 232: dtr_ctl(struct vxsoftc *sc, int port, int on)
! 233: {
! 234: struct packet pkt;
! 235:
! 236: bzero(&pkt, sizeof(struct packet));
! 237: pkt.command = CMD_IOCTL;
! 238: pkt.ioctl_cmd_l = IOCTL_TCXONC;
! 239: pkt.command_pipe_number = sc->channel_number;
! 240: pkt.status_pipe_number = sc->channel_number;
! 241: pkt.device_number = port;
! 242: if (on) {
! 243: pkt.ioctl_arg_l = 6; /* assert DTR */
! 244: } else {
! 245: pkt.ioctl_arg_l = 7; /* negate DTR */
! 246: }
! 247:
! 248: return bpp_send(sc, &pkt, WAIT);
! 249: }
! 250:
! 251: short
! 252: rts_ctl(struct vxsoftc *sc, int port, int on)
! 253: {
! 254: struct packet pkt;
! 255:
! 256: bzero(&pkt, sizeof(struct packet));
! 257: pkt.command = CMD_IOCTL;
! 258: pkt.ioctl_cmd_l = IOCTL_TCXONC;
! 259: pkt.command_pipe_number = sc->channel_number;
! 260: pkt.status_pipe_number = sc->channel_number;
! 261: pkt.device_number = port;
! 262: if (on) {
! 263: pkt.ioctl_arg_l = 4; /* assert RTS */
! 264: } else {
! 265: pkt.ioctl_arg_l = 5; /* negate RTS */
! 266: }
! 267:
! 268: return bpp_send(sc, &pkt, WAIT);
! 269: }
! 270:
! 271: #if 0
! 272: short
! 273: flush_ctl(struct vxsoftc *sc, int port, int which)
! 274: {
! 275: struct packet pkt;
! 276:
! 277: bzero(&pkt, sizeof(struct packet));
! 278: pkt.command = CMD_IOCTL;
! 279: pkt.ioctl_cmd_l = IOCTL_TCFLSH;
! 280: pkt.command_pipe_number = sc->channel_number;
! 281: pkt.status_pipe_number = sc->channel_number;
! 282: pkt.device_number = port;
! 283: pkt.ioctl_arg_l = which; /* 0=input, 1=output, 2=both */
! 284:
! 285: return bpp_send(sc, &pkt, WAIT);
! 286: }
! 287: #endif
! 288:
! 289: int
! 290: vx_mctl(dev_t dev, int bits, int how)
! 291: {
! 292: int s, unit, port;
! 293: struct vxsoftc *sc;
! 294: struct vx_info *vxt;
! 295: u_char msvr;
! 296:
! 297: unit = VX_UNIT(dev);
! 298: port = VX_PORT(dev);
! 299: sc = (struct vxsoftc *)vx_cd.cd_devs[unit];
! 300: vxt = &sc->sc_info[port];
! 301:
! 302: s = splvx();
! 303: switch (how) {
! 304: case DMSET:
! 305: if (bits & TIOCM_RTS) {
! 306: rts_ctl(sc, port, 1);
! 307: vxt->vx_linestatus |= TIOCM_RTS;
! 308: } else {
! 309: rts_ctl(sc, port, 0);
! 310: vxt->vx_linestatus &= ~TIOCM_RTS;
! 311: }
! 312: if (bits & TIOCM_DTR) {
! 313: dtr_ctl(sc, port, 1);
! 314: vxt->vx_linestatus |= TIOCM_DTR;
! 315: } else {
! 316: dtr_ctl(sc, port, 0);
! 317: vxt->vx_linestatus &= ~TIOCM_DTR;
! 318: }
! 319: break;
! 320: case DMBIC:
! 321: if (bits & TIOCM_RTS) {
! 322: rts_ctl(sc, port, 0);
! 323: vxt->vx_linestatus &= ~TIOCM_RTS;
! 324: }
! 325: if (bits & TIOCM_DTR) {
! 326: dtr_ctl(sc, port, 0);
! 327: vxt->vx_linestatus &= ~TIOCM_DTR;
! 328: }
! 329: break;
! 330:
! 331: case DMBIS:
! 332: if (bits & TIOCM_RTS) {
! 333: rts_ctl(sc, port, 1);
! 334: vxt->vx_linestatus |= TIOCM_RTS;
! 335: }
! 336: if (bits & TIOCM_DTR) {
! 337: dtr_ctl(sc, port, 1);
! 338: vxt->vx_linestatus |= TIOCM_DTR;
! 339: }
! 340: break;
! 341:
! 342: case DMGET:
! 343: bits = 0;
! 344: msvr = vxt->vx_linestatus;
! 345: if (msvr & TIOCM_DSR) {
! 346: bits |= TIOCM_DSR;
! 347: }
! 348: if (msvr & TIOCM_CD) {
! 349: bits |= TIOCM_CD;
! 350: }
! 351: if (msvr & TIOCM_CTS) {
! 352: bits |= TIOCM_CTS;
! 353: }
! 354: if (msvr & TIOCM_DTR) {
! 355: bits |= TIOCM_DTR;
! 356: }
! 357: if (msvr & TIOCM_RTS) {
! 358: bits |= TIOCM_RTS;
! 359: }
! 360: break;
! 361: }
! 362:
! 363: splx(s);
! 364:
! 365: #if 0
! 366: bits = 0;
! 367: bits |= TIOCM_DTR;
! 368: bits |= TIOCM_RTS;
! 369: bits |= TIOCM_CTS;
! 370: bits |= TIOCM_CD;
! 371: bits |= TIOCM_DSR;
! 372: #endif
! 373: return (bits);
! 374: }
! 375:
! 376: int
! 377: vxopen(dev_t dev, int flag, int mode, struct proc *p)
! 378: {
! 379: int s, unit, port, error;
! 380: struct vx_info *vxt;
! 381: struct vxsoftc *sc;
! 382: struct tty *tp;
! 383: struct packet opkt;
! 384: u_short code;
! 385:
! 386: unit = VX_UNIT(dev);
! 387: port = VX_PORT(dev);
! 388: if (unit >= vx_cd.cd_ndevs ||
! 389: (sc = (struct vxsoftc *) vx_cd.cd_devs[unit]) == NULL) {
! 390: return (ENODEV);
! 391: }
! 392: vxt = &sc->sc_info[port];
! 393:
! 394: #if 0
! 395: flush_ctl(sc, port, 2);
! 396: #endif
! 397:
! 398: bzero(&opkt, sizeof(struct packet));
! 399: opkt.command_pipe_number = sc->channel_number;
! 400: opkt.status_pipe_number = sc->channel_number;
! 401: opkt.command = CMD_OPEN;
! 402: opkt.device_number = port;
! 403:
! 404: if ((error = bpp_send(sc, &opkt, WAIT)) != 0) {
! 405: #ifdef DEBUG_VXT
! 406: printf("unit %d, port %d, ", unit, port);
! 407: printf("error = %d\n", error);
! 408: #endif
! 409: return (ENXIO);
! 410: }
! 411:
! 412: code = opkt.event_code;
! 413:
! 414: s = splvx();
! 415: if (vxt->tty) {
! 416: tp = vxt->tty;
! 417: } else {
! 418: tp = vxt->tty = ttymalloc();
! 419: }
! 420:
! 421: /* set line status */
! 422: tp->t_state |= TS_CARR_ON;
! 423: if (code & E_DCD) {
! 424: tp->t_state |= TS_CARR_ON;
! 425: vxt->vx_linestatus |= TIOCM_CD;
! 426: }
! 427: if (code & E_DSR) {
! 428: vxt->vx_linestatus |= TIOCM_DSR;
! 429: }
! 430: if (code & E_CTS) {
! 431: vxt->vx_linestatus |= TIOCM_CTS;
! 432: }
! 433:
! 434: tp->t_oproc = vxstart;
! 435: tp->t_param = vx_param;
! 436: tp->t_dev = dev;
! 437:
! 438: if ((tp->t_state & TS_ISOPEN) == 0) {
! 439: tp->t_state |= TS_WOPEN;
! 440: ttychars(tp);
! 441: if (tp->t_ispeed == 0) {
! 442: /*
! 443: * only when cleared do we reset to defaults.
! 444: */
! 445: tp->t_iflag = TTYDEF_IFLAG;
! 446: tp->t_oflag = TTYDEF_OFLAG;
! 447: tp->t_lflag = TTYDEF_LFLAG;
! 448: tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
! 449: tp->t_cflag = TTYDEF_CFLAG;
! 450: }
! 451: /*
! 452: * do these all the time
! 453: */
! 454: if (vxt->vx_swflags & TIOCFLAG_CLOCAL)
! 455: tp->t_cflag |= CLOCAL;
! 456: if (vxt->vx_swflags & TIOCFLAG_CRTSCTS)
! 457: tp->t_cflag |= CRTSCTS;
! 458: if (vxt->vx_swflags & TIOCFLAG_MDMBUF)
! 459: tp->t_cflag |= MDMBUF;
! 460: vx_param(tp, &tp->t_termios);
! 461: ttsetwater(tp);
! 462:
! 463: (void)vx_mctl(dev, TIOCM_DTR | TIOCM_RTS, DMSET);
! 464:
! 465: tp->t_state |= TS_CARR_ON;
! 466: } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
! 467: splx(s);
! 468: return (EBUSY);
! 469: }
! 470:
! 471: /*
! 472: * Reset the tty pointer, as there could have been a dialout
! 473: * use of the tty with a dialin open waiting.
! 474: */
! 475: tp->t_dev = dev;
! 476: vxt->open = 1;
! 477: splx(s);
! 478: return (*linesw[tp->t_line].l_open)(dev, tp);
! 479: }
! 480:
! 481: int
! 482: vx_param(struct tty *tp, struct termios *t)
! 483: {
! 484: int unit, port;
! 485: struct vxsoftc *sc;
! 486: dev_t dev;
! 487:
! 488: dev = tp->t_dev;
! 489: unit = VX_UNIT(dev);
! 490: if (unit >= vx_cd.cd_ndevs ||
! 491: (sc = (struct vxsoftc *) vx_cd.cd_devs[unit]) == NULL) {
! 492: return (ENODEV);
! 493: }
! 494: port = VX_PORT(dev);
! 495: tp->t_ispeed = t->c_ispeed;
! 496: tp->t_ospeed = t->c_ospeed;
! 497: tp->t_cflag = t->c_cflag;
! 498: vx_ccparam(sc, t, port);
! 499: vx_unblock(tp);
! 500: return 0;
! 501: }
! 502:
! 503: int
! 504: vxclose(dev_t dev, int flag, int mode, struct proc *p)
! 505: {
! 506: int unit, port;
! 507: struct tty *tp;
! 508: struct vx_info *vxt;
! 509: struct vxsoftc *sc;
! 510: int s;
! 511: struct packet cpkt;
! 512:
! 513: unit = VX_UNIT(dev);
! 514: if (unit >= vx_cd.cd_ndevs ||
! 515: (sc = (struct vxsoftc *) vx_cd.cd_devs[unit]) == NULL) {
! 516: return (ENODEV);
! 517: }
! 518: port = VX_PORT(dev);
! 519: vxt = &sc->sc_info[port];
! 520: #if 0
! 521: flush_ctl(sc, port, 2); /* flush both input and output */
! 522: #endif
! 523:
! 524: tp = vxt->tty;
! 525: (*linesw[tp->t_line].l_close)(tp, flag);
! 526:
! 527: s = splvx();
! 528:
! 529: if ((tp->t_cflag & HUPCL) != 0) {
! 530: rts_ctl(sc, port, 0);
! 531: dtr_ctl(sc, port, 0);
! 532: }
! 533:
! 534: bzero(&cpkt, sizeof(struct packet));
! 535: cpkt.command_pipe_number = sc->channel_number;
! 536: cpkt.status_pipe_number = sc->channel_number;
! 537: cpkt.command = CMD_CLOSE;
! 538: cpkt.device_number = port;
! 539: bpp_send(sc, &cpkt, NOWAIT);
! 540:
! 541: vxt->open = 0;
! 542: splx(s);
! 543: ttyclose(tp);
! 544:
! 545: return (0);
! 546: }
! 547:
! 548: void
! 549: read_wakeup(struct vxsoftc *sc, int port)
! 550: {
! 551: struct packet rwp;
! 552: struct vx_info *volatile vxt;
! 553:
! 554: vxt = &sc->sc_info[port];
! 555: /*
! 556: * If we already have a read_wakeup paket
! 557: * for this port, do nothing.
! 558: */
! 559: if (vxt->read_pending != 0)
! 560: return;
! 561: else
! 562: vxt->read_pending = 1;
! 563:
! 564: bzero(&rwp, sizeof(struct packet));
! 565: rwp.command_pipe_number = sc->channel_number;
! 566: rwp.status_pipe_number = sc->channel_number;
! 567: rwp.command = CMD_READW;
! 568: rwp.device_number = port;
! 569:
! 570: /*
! 571: * Do not wait. Characters will be transferred
! 572: * to (*linesw[tp->t_line].l_rint)(c, tp); by
! 573: * vx_intr() (IPC will notify via interrupt)
! 574: */
! 575: bpp_send(sc, &rwp, NOWAIT);
! 576: }
! 577:
! 578: int
! 579: vxread(dev_t dev, struct uio *uio, int flag)
! 580: {
! 581: int unit, port;
! 582: struct tty *tp;
! 583: struct vx_info *volatile vxt;
! 584: struct vxsoftc *volatile sc;
! 585:
! 586: unit = VX_UNIT(dev);
! 587: if (unit >= vx_cd.cd_ndevs ||
! 588: (sc = (struct vxsoftc *) vx_cd.cd_devs[unit]) == NULL) {
! 589: return (ENODEV);
! 590: }
! 591: port = VX_PORT(dev);
! 592: vxt = &sc->sc_info[port];
! 593: tp = vxt->tty;
! 594: if (!tp)
! 595: return ENXIO;
! 596: return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
! 597: }
! 598:
! 599: int
! 600: vxwrite(dev_t dev, struct uio *uio, int flag)
! 601: {
! 602: int unit, port;
! 603: struct tty *tp;
! 604: struct vx_info *vxt;
! 605: struct vxsoftc *sc;
! 606: struct wring *wp;
! 607: struct packet wwp;
! 608: u_short get, put;
! 609:
! 610: unit = VX_UNIT(dev);
! 611: if (unit >= vx_cd.cd_ndevs ||
! 612: (sc = (struct vxsoftc *) vx_cd.cd_devs[unit]) == NULL) {
! 613: return (ENODEV);
! 614: }
! 615: port = VX_PORT(dev);
! 616: vxt = &sc->sc_info[port];
! 617: tp = vxt->tty;
! 618: if (!tp)
! 619: return ENXIO;
! 620:
! 621: wp = sc->sc_info[port].wringp;
! 622: get = wp->get;
! 623: put = wp->put;
! 624: if ((put + 1) == get) {
! 625: bzero(&wwp, sizeof(struct packet));
! 626: wwp.command_pipe_number = sc->channel_number;
! 627: wwp.status_pipe_number = sc->channel_number;
! 628: wwp.command = CMD_WRITEW;
! 629: wwp.device_number = port;
! 630: if (bpp_send(sc, &wwp, WAIT))
! 631: return (ENXIO);
! 632: }
! 633:
! 634: return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
! 635: }
! 636:
! 637: int
! 638: vxioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
! 639: {
! 640: int error;
! 641: int unit, port;
! 642: struct tty *tp;
! 643: struct vx_info *vxt;
! 644: struct vxsoftc *sc;
! 645:
! 646: unit = VX_UNIT(dev);
! 647: if (unit >= vx_cd.cd_ndevs ||
! 648: (sc = (struct vxsoftc *) vx_cd.cd_devs[unit]) == NULL) {
! 649: return (ENODEV);
! 650: }
! 651: port = VX_PORT(dev);
! 652: vxt = &sc->sc_info[port];
! 653: tp = vxt->tty;
! 654: if (!tp)
! 655: return ENXIO;
! 656:
! 657: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
! 658: if (error >= 0)
! 659: return (error);
! 660:
! 661: error = ttioctl(tp, cmd, data, flag, p);
! 662: if (error >= 0)
! 663: return (error);
! 664:
! 665: switch (cmd) {
! 666: case TIOCSBRK:
! 667: /* */
! 668: break;
! 669:
! 670: case TIOCCBRK:
! 671: /* */
! 672: break;
! 673:
! 674: case TIOCSDTR:
! 675: vx_mctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
! 676: break;
! 677:
! 678: case TIOCCDTR:
! 679: vx_mctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
! 680: break;
! 681:
! 682: case TIOCMSET:
! 683: vx_mctl(dev, *(int *)data, DMSET);
! 684: break;
! 685:
! 686: case TIOCMBIS:
! 687: vx_mctl(dev, *(int *)data, DMBIS);
! 688: break;
! 689:
! 690: case TIOCMBIC:
! 691: vx_mctl(dev, *(int *)data, DMBIC);
! 692: break;
! 693:
! 694: case TIOCMGET:
! 695: *(int *)data = vx_mctl(dev, 0, DMGET);
! 696: break;
! 697:
! 698: case TIOCGFLAGS:
! 699: *(int *)data = vxt->vx_swflags;
! 700: break;
! 701:
! 702: case TIOCSFLAGS:
! 703: error = suser(p, 0);
! 704: if (error != 0)
! 705: return (EPERM);
! 706:
! 707: vxt->vx_swflags = *(int *)data;
! 708: vxt->vx_swflags &= /* only allow valid flags */
! 709: (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
! 710: break;
! 711:
! 712: default:
! 713: return (ENOTTY);
! 714: }
! 715:
! 716: return 0;
! 717: }
! 718:
! 719: int
! 720: vxstop(struct tty *tp, int flag)
! 721: {
! 722: int s;
! 723:
! 724: s = splvx();
! 725: if (tp->t_state & TS_BUSY) {
! 726: if ((tp->t_state & TS_TTSTOP) == 0)
! 727: tp->t_state |= TS_FLUSH;
! 728: }
! 729: splx(s);
! 730: return 0;
! 731: }
! 732:
! 733: void
! 734: vxputc(struct vxsoftc *sc, int port, u_char c)
! 735: {
! 736: struct wring *wp;
! 737:
! 738: wp = sc->sc_info[port].wringp;
! 739: wp->data[wp->put++ & (WRING_BUF_SIZE - 1)] = c;
! 740: wp->put &= (WRING_BUF_SIZE - 1);
! 741: }
! 742:
! 743: u_short
! 744: vxtspeed(int speed)
! 745: {
! 746: switch (speed) {
! 747: case B0:
! 748: return VB0;
! 749: case B50:
! 750: return VB50;
! 751: case B75:
! 752: return VB75;
! 753: case B110:
! 754: return VB110;
! 755: case B134:
! 756: return VB134;
! 757: case B150:
! 758: return VB150;
! 759: case B200:
! 760: return VB200;
! 761: case B300:
! 762: return VB300;
! 763: case B600:
! 764: return VB600;
! 765: case B1200:
! 766: return VB1200;
! 767: case B1800:
! 768: return VB1800;
! 769: case B2400:
! 770: return VB2400;
! 771: case B4800:
! 772: return VB4800;
! 773: case B9600:
! 774: return VB9600;
! 775: case B19200:
! 776: return VB19200;
! 777: case B38400:
! 778: return VB38400;
! 779: default:
! 780: return VB9600;
! 781: }
! 782: }
! 783:
! 784: int
! 785: vx_ccparam(struct vxsoftc *sc, struct termios *par, int port)
! 786: {
! 787: int imask = 0, s;
! 788: int cflag;
! 789: struct packet pkt;
! 790:
! 791: if (par->c_ospeed == 0) {
! 792: s = splvx();
! 793: /* disconnect, drop RTS DTR stop receiver */
! 794: rts_ctl(sc, port, 0);
! 795: dtr_ctl(sc, port, 0);
! 796: splx(s);
! 797: return (0xff);
! 798: }
! 799:
! 800: bzero(&pkt, sizeof(struct packet));
! 801: pkt.command = CMD_IOCTL;
! 802: pkt.ioctl_cmd_l = IOCTL_TCGETA;
! 803: pkt.command_pipe_number = sc->channel_number;
! 804: pkt.status_pipe_number = sc->channel_number;
! 805: pkt.device_number = port;
! 806: if (bpp_send(sc, &pkt, WAIT))
! 807: return 0xff;
! 808:
! 809: cflag = pkt.pb.tio.c_cflag;
! 810: cflag |= vxtspeed(par->c_ospeed);
! 811:
! 812: switch (par->c_cflag & CSIZE) {
! 813: case CS5:
! 814: cflag |= VCS5;
! 815: imask = 0x1F;
! 816: break;
! 817: case CS6:
! 818: cflag |= VCS6;
! 819: imask = 0x3F;
! 820: break;
! 821: case CS7:
! 822: cflag |= VCS7;
! 823: imask = 0x7F;
! 824: break;
! 825: default:
! 826: cflag |= VCS8;
! 827: imask = 0xFF;
! 828: }
! 829:
! 830: if (par->c_cflag & PARENB) cflag |= VPARENB;
! 831: else cflag &= ~VPARENB;
! 832: if (par->c_cflag & PARODD) cflag |= VPARODD;
! 833: else cflag &= ~VPARODD;
! 834: if (par->c_cflag & CREAD) cflag |= VCREAD;
! 835: else cflag &= ~VCREAD;
! 836: if (par->c_cflag & CLOCAL) cflag |= VCLOCAL;
! 837: else cflag &= ~VCLOCAL;
! 838: if (par->c_cflag & HUPCL) cflag |= VHUPCL;
! 839: else cflag &= ~VHUPCL;
! 840:
! 841: pkt.command = CMD_IOCTL;
! 842: pkt.ioctl_cmd_l = IOCTL_TCSETA;
! 843: pkt.command_pipe_number = sc->channel_number;
! 844: pkt.status_pipe_number = sc->channel_number;
! 845: pkt.device_number = port;
! 846: pkt.pb.tio.c_cflag = cflag;
! 847: if (bpp_send(sc, &pkt, WAIT))
! 848: return 0xff;
! 849:
! 850: return imask;
! 851: }
! 852:
! 853: void
! 854: vx_unblock(struct tty *tp)
! 855: {
! 856: tp->t_state &= ~TS_FLUSH;
! 857: if (tp->t_outq.c_cc != 0)
! 858: vxstart(tp);
! 859: }
! 860:
! 861: void
! 862: vxstart(struct tty *tp)
! 863: {
! 864: dev_t dev;
! 865: struct vxsoftc *sc;
! 866: struct wring *wp;
! 867: int cc, port, unit, s, cnt, i;
! 868: u_short get, put;
! 869: char buffer[256];
! 870:
! 871: dev = tp->t_dev;
! 872: port = VX_PORT(dev);
! 873: unit = VX_UNIT(dev);
! 874: if (unit >= vx_cd.cd_ndevs ||
! 875: (sc = (struct vxsoftc *) vx_cd.cd_devs[unit]) == NULL) {
! 876: return;
! 877: }
! 878:
! 879: if ((tp->t_state & TS_ISOPEN) == 0)
! 880: return;
! 881:
! 882: s = splvx();
! 883: if ((tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP | TS_FLUSH)) == 0) {
! 884: tp->t_state |= TS_BUSY;
! 885: wp = sc->sc_info[port].wringp;
! 886: get = wp->get;
! 887: put = wp->put;
! 888: cc = tp->t_outq.c_cc;
! 889: while (cc > 0) {
! 890: cnt = min(sizeof buffer, cc);
! 891: cnt = q_to_b(&tp->t_outq, buffer, cnt);
! 892: buffer[cnt] = 0;
! 893: for (i = 0; i < cnt; i++) {
! 894: vxputc(sc, port, buffer[i]);
! 895: }
! 896: cc -= cnt;
! 897: }
! 898: tp->t_state &= ~TS_BUSY;
! 899: }
! 900: splx(s);
! 901: }
! 902:
! 903: void
! 904: read_chars(struct vxsoftc *sc, int port)
! 905: {
! 906: /*
! 907: * This routine is called by vx_intr() when there are
! 908: * characters in the read ring. It will process one
! 909: * cooked line, put the chars in the line disipline ring,
! 910: * and then return. The characters may then
! 911: * be read by vxread.
! 912: */
! 913: struct vx_info *vxt;
! 914: struct rring *rp;
! 915: struct tty *tp;
! 916: u_short get, put;
! 917: int frame_count, i, open;
! 918: char c;
! 919:
! 920: vxt = &sc->sc_info[port];
! 921: tp = vxt->tty;
! 922: rp = vxt->rringp;
! 923: open = vxt->open;
! 924: get = rp->get;
! 925: put = rp->put;
! 926: #ifdef DEBUG_VXT
! 927: printf("read_chars() get=%d, put=%d ", get, put);
! 928: printf("open = %d ring at 0x%x\n", open, rp);
! 929: #endif
! 930: while (get != put) {
! 931: frame_count = rp->data[rp->get++ & (RRING_BUF_SIZE - 1)];
! 932: rp->get &= (RRING_BUF_SIZE - 1);
! 933: for (i = 0; i < frame_count; i++) {
! 934: c = rp->data[rp->get++ & (RRING_BUF_SIZE - 1)];
! 935: rp->get &= (RRING_BUF_SIZE - 1);
! 936: if (open)
! 937: (*linesw[tp->t_line].l_rint)(c, tp);
! 938: }
! 939: c = rp->data[rp->get++ & (RRING_BUF_SIZE - 1)];
! 940: rp->get &= (RRING_BUF_SIZE - 1);
! 941: if (!(c & DELIMITER)) {
! 942: vx_frame(sc, port);
! 943: break;
! 944: } else {
! 945: break;
! 946: }
! 947: get = rp->get;
! 948: put = rp->put;
! 949: }
! 950: vxt->read_pending = 0;
! 951: read_wakeup(sc, port);
! 952: }
! 953:
! 954: void
! 955: ccode(struct vxsoftc *sc, int port, char c)
! 956: {
! 957: struct vx_info *vxt;
! 958: struct tty *tp;
! 959:
! 960: tp = vxt->tty;
! 961: (*linesw[tp->t_line].l_rint)(c, tp);
! 962: }
! 963:
! 964: int
! 965: vx_intr(void *arg)
! 966: {
! 967: struct vxsoftc *sc = arg;
! 968: struct envelope *envp, *next_envp;
! 969: struct packet *pktp, pkt;
! 970: int valid;
! 971: short cmd;
! 972: u_char port;
! 973:
! 974: while (env_isvalid(get_status_head(sc))) {
! 975: pktp = get_packet(sc, get_status_head(sc));
! 976: valid = env_isvalid(get_status_head(sc));
! 977: cmd = pktp->command;
! 978: port = pktp->device_number;
! 979: /*
! 980: * If we are waiting on this packet, store the info
! 981: * so bpp_send can process the packet
! 982: */
! 983: if (sc->sc_bppwait_pktp == pktp)
! 984: d16_bcopy(pktp, &sc->sc_bppwait_pkt, sizeof(struct packet));
! 985:
! 986: d16_bcopy(pktp, &pkt, sizeof(struct packet));
! 987: next_envp = get_next_envelope(sc, get_status_head(sc));
! 988: envp = get_status_head(sc);
! 989: /* return envelope and packet to the free queues */
! 990: put_free_envelope(sc, envp);
! 991: put_free_packet(sc, pktp);
! 992: /* mark new status pipe head pointer */
! 993: set_status_head(sc, next_envp);
! 994: /* if it was valid, process packet */
! 995: switch (cmd) {
! 996: case CMD_READW:
! 997: #ifdef DEBUG_VXT
! 998: printf("READW Packet\n");
! 999: #endif
! 1000: read_chars(sc, port);
! 1001: break;
! 1002: case CMD_WRITEW:
! 1003: #ifdef DEBUG_VXT
! 1004: printf("WRITEW Packet\n"); /* Still don't know XXXsmurph */
! 1005: #endif
! 1006: break;
! 1007: case CMD_EVENT:
! 1008: #ifdef DEBUG_VXT
! 1009: printf("EVENT Packet\n");
! 1010: #endif
! 1011: vx_event(sc, &pkt);
! 1012: break;
! 1013: case CMD_PROCESSED:
! 1014: #ifdef DEBUG_VXT
! 1015: printf("CMD_PROCESSED Packet\n");
! 1016: #endif
! 1017: break;
! 1018: default:
! 1019: #ifdef DEBUG_VXT
! 1020: printf("Other packet 0x%x\n", cmd);
! 1021: #endif
! 1022: break;
! 1023: }
! 1024: }
! 1025: return 1;
! 1026: }
! 1027:
! 1028: int
! 1029: vx_event(struct vxsoftc *sc, struct packet *evntp)
! 1030: {
! 1031: u_short code = evntp->event_code;
! 1032: struct packet evnt;
! 1033: struct vx_info *vxt;
! 1034:
! 1035: vxt = &sc->sc_info[evntp->device_number];
! 1036:
! 1037: if (code & E_INTR) {
! 1038: ccode(sc, evntp->device_number, CINTR);
! 1039: }
! 1040: if (code & E_QUIT) {
! 1041: ccode(sc, evntp->device_number, CQUIT);
! 1042: }
! 1043: if (code & E_HUP) {
! 1044: rts_ctl(sc, evntp->device_number, 0);
! 1045: dtr_ctl(sc, evntp->device_number, 0);
! 1046: }
! 1047: if (code & E_DCD) {
! 1048: vxt->vx_linestatus |= TIOCM_CD;
! 1049: }
! 1050: if (code & E_DSR) {
! 1051: vxt->vx_linestatus |= TIOCM_DSR;
! 1052: }
! 1053: if (code & E_CTS) {
! 1054: vxt->vx_linestatus |= TIOCM_CTS;
! 1055: }
! 1056: if (code & E_LOST_DCD) {
! 1057: vxt->vx_linestatus &= ~TIOCM_CD;
! 1058: }
! 1059: if (code & E_LOST_DSR) {
! 1060: vxt->vx_linestatus &= ~TIOCM_DSR;
! 1061: }
! 1062: if (code & E_LOST_CTS) {
! 1063: vxt->vx_linestatus &= ~TIOCM_CTS;
! 1064: }
! 1065: if (code & E_PR_FAULT) {
! 1066: /* do something... */
! 1067: }
! 1068: if (code & E_PR_POUT) {
! 1069: /* do something... */
! 1070: }
! 1071: if (code & E_PR_SELECT) {
! 1072: /* do something... */
! 1073: }
! 1074: if (code & E_SWITCH) {
! 1075: /* do something... */
! 1076: }
! 1077: if (code & E_BREAK) {
! 1078: vx_break(sc, evntp->device_number);
! 1079: }
! 1080:
! 1081: /* send an event packet back to the device */
! 1082: bzero(&evnt, sizeof(struct packet));
! 1083: evnt.command = CMD_EVENT;
! 1084: evnt.device_number = evntp->device_number;
! 1085: evnt.command_pipe_number = sc->channel_number;
! 1086: /* return status on same channel */
! 1087: evnt.status_pipe_number = sc->channel_number;
! 1088: /* send packet to the firmware */
! 1089: bpp_send(sc, &evnt, NOWAIT);
! 1090:
! 1091: return 1;
! 1092: }
! 1093:
! 1094: void
! 1095: vx_overflow(struct vxsoftc *sc, int port, long *ptime, u_char *msg)
! 1096: {
! 1097: log(LOG_WARNING, "%s port %d: overrun\n",
! 1098: sc->sc_dev.dv_xname, port);
! 1099: }
! 1100:
! 1101: void
! 1102: vx_frame(struct vxsoftc *sc, int port)
! 1103: {
! 1104: log(LOG_WARNING, "%s port %d: frame error\n",
! 1105: sc->sc_dev.dv_xname, port);
! 1106: }
! 1107:
! 1108: void
! 1109: vx_break(struct vxsoftc *sc, int port)
! 1110: {
! 1111: /*
! 1112: * No need to check for a ddb break, as the console can never be on
! 1113: * this hardware.
! 1114: */
! 1115: log(LOG_WARNING, "%s port %d: break detected\n",
! 1116: sc->sc_dev.dv_xname, port);
! 1117: }
! 1118:
! 1119: /*
! 1120: * Initialization and Buffered Pipe Protocol (BPP) code
! 1121: */
! 1122:
! 1123: void
! 1124: create_free_queue(struct vxsoftc *sc)
! 1125: {
! 1126: int i;
! 1127: struct envelope *envp, env;
! 1128: struct packet *pktp, pkt;
! 1129:
! 1130: envp = (struct envelope *)VIRTUAL(ENVELOPE_AREA);
! 1131: sc->elist_head = envp;
! 1132: for (i = 1; i <= NENVELOPES; i++) {
! 1133: bzero(&env, sizeof(struct envelope));
! 1134: if (i == NENVELOPES)
! 1135: env.link = NULL;
! 1136: else
! 1137: env.link = ENVELOPE_AREA + i * sizeof(struct envelope);
! 1138: env.packet_ptr = NULL;
! 1139: env.valid_flag = 0;
! 1140: d16_bcopy(&env, envp, sizeof(struct envelope));
! 1141: envp++;
! 1142: }
! 1143: sc->elist_tail = --envp;
! 1144:
! 1145: pktp = (struct packet *)VIRTUAL(PACKET_AREA);
! 1146: sc->plist_head = pktp;
! 1147: for (i = 1; i <= NPACKETS; i++) {
! 1148: bzero(&pkt, sizeof(struct packet));
! 1149: if (i == NPACKETS)
! 1150: pkt.link = NULL;
! 1151: else
! 1152: pkt.link = PACKET_AREA + i * sizeof(struct packet);
! 1153: d16_bcopy(&pkt, pktp, sizeof(struct packet));
! 1154: pktp++;
! 1155: }
! 1156: sc->plist_tail = --pktp;
! 1157: }
! 1158:
! 1159: void *
! 1160: get_free_envelope(struct vxsoftc *sc)
! 1161: {
! 1162: struct envelope *envp;
! 1163: paddr_t link;
! 1164:
! 1165: envp = sc->elist_head;
! 1166: /* pick envelope next pointer from the envelope itself */
! 1167: d16_bcopy((const void *)&envp->link, &link, sizeof link);
! 1168: sc->elist_head = (struct envelope *)VIRTUAL(link);
! 1169: d16_bzero(envp, sizeof(struct envelope));
! 1170:
! 1171: return envp;
! 1172: }
! 1173:
! 1174: void
! 1175: put_free_envelope(struct vxsoftc *sc, void *ep)
! 1176: {
! 1177: struct envelope *envp = (struct envelope *)ep;
! 1178: u_long link;
! 1179:
! 1180: #if 0
! 1181: d16_bzero(envp, sizeof(struct envelope));
! 1182: #endif
! 1183: /* put envelope next pointer in the envelope itself */
! 1184: link = PHYSICAL((vaddr_t)envp);
! 1185: d16_bzero((void *)&envp->link, sizeof envp->link);
! 1186: d16_bcopy(&link, (void *)&sc->elist_tail->link, sizeof link);
! 1187:
! 1188: sc->elist_tail = envp;
! 1189: }
! 1190:
! 1191: void *
! 1192: get_free_packet(struct vxsoftc *sc)
! 1193: {
! 1194: struct packet *pktp;
! 1195: paddr_t link;
! 1196:
! 1197: pktp = sc->plist_head;
! 1198: /* pick packet next pointer from the packet itself */
! 1199: d16_bcopy((const void *)&pktp->link, &link, sizeof link);
! 1200: sc->plist_head = (struct packet *)VIRTUAL(link);
! 1201: d16_bzero(pktp, sizeof(struct packet));
! 1202:
! 1203: return pktp;
! 1204: }
! 1205:
! 1206: void
! 1207: put_free_packet(struct vxsoftc *sc, void *pp)
! 1208: {
! 1209: struct packet *pktp = (struct packet *)pp;
! 1210: u_long link;
! 1211:
! 1212: #if 0
! 1213: d16_bzero(pktp, sizeof(struct packet));
! 1214: #endif
! 1215: pktp->command = CMD_PROCESSED;
! 1216: /* put packet next pointer in the packet itself */
! 1217: link = PHYSICAL((vaddr_t)pktp);
! 1218: d16_bzero((void *)&pktp->link, sizeof pktp->link);
! 1219: d16_bcopy(&link, (void *)&sc->plist_tail->link, sizeof link);
! 1220:
! 1221: sc->plist_tail = pktp;
! 1222: }
! 1223:
! 1224: /*
! 1225: * This is the nitty gritty. All the rest if this code
! 1226: * was hell to come by. Getting this right from the
! 1227: * Moto manual took *time*!
! 1228: */
! 1229: int
! 1230: create_channels(struct vxsoftc *sc)
! 1231: {
! 1232: u_long envp;
! 1233: u_short status;
! 1234: u_short tas;
! 1235: struct vxreg *ipc_csr = sc->vx_reg;
! 1236:
! 1237: /* wait for busy bit to clear */
! 1238: while ((ipc_csr->ipc_cr & IPC_CR_BUSY))
! 1239: ;
! 1240:
! 1241: create_free_queue(sc);
! 1242:
! 1243: /* set up channel header. we only want one */
! 1244: tas = ipc_csr->ipc_tas;
! 1245: while (!(tas & IPC_TAS_VALID_STATUS)) {
! 1246: envp = PHYSICAL((vaddr_t)get_free_envelope(sc));
! 1247: sc->channel->command_pipe_head_ptr_h = HI(envp);
! 1248: sc->channel->command_pipe_head_ptr_l = LO(envp);
! 1249: sc->channel->command_pipe_tail_ptr_h =
! 1250: sc->channel->command_pipe_head_ptr_h;
! 1251: sc->channel->command_pipe_tail_ptr_l =
! 1252: sc->channel->command_pipe_head_ptr_l;
! 1253: envp = PHYSICAL((vaddr_t)get_free_envelope(sc));
! 1254: sc->channel->status_pipe_head_ptr_h = HI(envp);
! 1255: sc->channel->status_pipe_head_ptr_l = LO(envp);
! 1256: sc->channel->status_pipe_tail_ptr_h =
! 1257: sc->channel->status_pipe_head_ptr_h;
! 1258: sc->channel->status_pipe_tail_ptr_l =
! 1259: sc->channel->status_pipe_head_ptr_l;
! 1260: sc->channel->interrupt_level = IPL_TTY;
! 1261: sc->channel->interrupt_vec = sc->sc_vec;
! 1262: sc->channel->channel_priority = 0;
! 1263: sc->channel->channel_number = 0;
! 1264: sc->channel->valid = 1;
! 1265: sc->channel->address_modifier = 0x8d; /* A32/D16 supervisor data access */
! 1266: sc->channel->datasize = 0; /* 32 bit data mode */
! 1267:
! 1268: /* loop until TAS bit is zero */
! 1269: while ((ipc_csr->ipc_tas & IPC_TAS_TAS))
! 1270: ;
! 1271: ipc_csr->ipc_tas |= IPC_TAS_TAS;
! 1272: /* load address of channel header */
! 1273: ipc_csr->ipc_addrh = HI(CHANNEL_H);
! 1274: ipc_csr->ipc_addrl = LO(CHANNEL_H);
! 1275: /* load address modifier reg (supervisor data access) */
! 1276: ipc_csr->ipc_amr = 0x8d;
! 1277: /* load tas with create channel command */
! 1278: ipc_csr->ipc_tas |= IPC_CSR_CREATE;
! 1279: /* set vaild command bit */
! 1280: ipc_csr->ipc_tas |= IPC_TAS_VALID_CMD;
! 1281: /* notify IPC of the CSR command */
! 1282: ipc_csr->ipc_cr |= IPC_CR_ATTEN;
! 1283:
! 1284: /* loop until IPC sets valid status bit */
! 1285: delay(5000);
! 1286: tas = ipc_csr->ipc_tas;
! 1287: }
! 1288:
! 1289: /* save the status */
! 1290: status = ipc_csr->ipc_sr;
! 1291: /* set COMMAND COMPLETE bit */
! 1292: ipc_csr->ipc_tas |= IPC_TAS_COMPLETE;
! 1293: /* notify IPC that we are through */
! 1294: ipc_csr->ipc_cr |= IPC_CR_ATTEN;
! 1295: /* check and see if the channel was created */
! 1296: if (status == 0 && sc->channel->valid) {
! 1297: sc->channel_number = sc->channel->channel_number;
! 1298: #ifdef DEBUG_VXT
! 1299: printf("%s: created channel %d\n", sc->sc_dev.dv_xname,
! 1300: sc->channel->channel_number);
! 1301: #endif
! 1302: return 0;
! 1303: } else {
! 1304: switch (status) {
! 1305: case 0x0000:
! 1306: printf("%s: channel not valid\n",
! 1307: sc->sc_dev.dv_xname);
! 1308: break;
! 1309: case 0xFFFF:
! 1310: printf("%s: invalid CSR command\n",
! 1311: sc->sc_dev.dv_xname);
! 1312: break;
! 1313: case 0xC000:
! 1314: printf("%s: could not read channel structure\n",
! 1315: sc->sc_dev.dv_xname);
! 1316: break;
! 1317: case 0x8000:
! 1318: printf("%s: could not write channel structure\n",
! 1319: sc->sc_dev.dv_xname);
! 1320: break;
! 1321: default:
! 1322: printf("%s: unknown IPC CSR command error 0x%x\n",
! 1323: sc->sc_dev.dv_xname, status);
! 1324: break;
! 1325: }
! 1326: return 1;
! 1327: }
! 1328: }
! 1329:
! 1330: struct envelope *
! 1331: get_next_envelope(struct vxsoftc *sc, struct envelope *thisenv)
! 1332: {
! 1333: paddr_t ptr;
! 1334:
! 1335: d16_bcopy((const void*)&thisenv->link, &ptr, sizeof ptr);
! 1336:
! 1337: return (struct envelope *)VIRTUAL(ptr);
! 1338: }
! 1339:
! 1340: int
! 1341: env_isvalid(struct envelope *thisenv)
! 1342: {
! 1343: return (int)thisenv->valid_flag;
! 1344: }
! 1345:
! 1346: struct envelope *
! 1347: get_cmd_tail(struct vxsoftc *sc)
! 1348: {
! 1349: paddr_t retaddr;
! 1350:
! 1351: retaddr = sc->channel->command_pipe_tail_ptr_h << 16;
! 1352: retaddr += sc->channel->command_pipe_tail_ptr_l;
! 1353: return (struct envelope *)VIRTUAL(retaddr);
! 1354: }
! 1355:
! 1356: struct envelope *
! 1357: get_status_head(struct vxsoftc *sc)
! 1358: {
! 1359: paddr_t retaddr;
! 1360:
! 1361: retaddr = sc->channel->status_pipe_head_ptr_h << 16;
! 1362: retaddr += sc->channel->status_pipe_head_ptr_l;
! 1363: return (struct envelope *)VIRTUAL(retaddr);
! 1364: }
! 1365:
! 1366: void
! 1367: set_status_head(struct vxsoftc *sc, void *envp)
! 1368: {
! 1369: paddr_t ptr;
! 1370:
! 1371: ptr = PHYSICAL((vaddr_t)envp);
! 1372: sc->channel->status_pipe_head_ptr_h = HI(ptr);
! 1373: sc->channel->status_pipe_head_ptr_l = LO(ptr);
! 1374: }
! 1375:
! 1376: struct packet *
! 1377: get_packet(struct vxsoftc *sc, struct envelope *thisenv)
! 1378: {
! 1379: paddr_t baseaddr;
! 1380:
! 1381: if (thisenv == NULL)
! 1382: return NULL;
! 1383:
! 1384: /*
! 1385: * packet ptr returned on status pipe is only last two bytes
! 1386: * so we must supply the full address based on the board address.
! 1387: * This also works for all envelopes because every address is an
! 1388: * offset to the board address.
! 1389: */
! 1390: d16_bcopy((const void *)&thisenv->packet_ptr, &baseaddr, sizeof baseaddr);
! 1391: return (struct packet *)VIRTUAL(baseaddr);
! 1392: }
! 1393:
! 1394: /*
! 1395: * Send a command via BPP
! 1396: */
! 1397: int
! 1398: bpp_send(struct vxsoftc *sc, void *pkt, int wait_flag)
! 1399: {
! 1400: struct envelope *envp;
! 1401: struct packet *pktp;
! 1402: paddr_t ptr;
! 1403: int tmo;
! 1404:
! 1405: /* load up packet in dual port mem */
! 1406: pktp = get_free_packet(sc);
! 1407: d16_bcopy(pkt, pktp, sizeof(struct packet));
! 1408:
! 1409: envp = get_cmd_tail(sc);
! 1410: ptr = PHYSICAL((vaddr_t)get_free_envelope(sc)); /* put a NULL env on the tail */
! 1411: sc->channel->command_pipe_tail_ptr_h = HI(ptr);
! 1412: sc->channel->command_pipe_tail_ptr_l = LO(ptr);
! 1413: d16_bcopy(&ptr, (void *)&envp->link, sizeof envp->link);
! 1414: ptr = PHYSICAL((vaddr_t)pktp);
! 1415: d16_bcopy(&ptr, (void *)&envp->packet_ptr, sizeof envp->packet_ptr);
! 1416: envp->valid_flag = 1;
! 1417:
! 1418: sc->vx_reg->ipc_cr |= IPC_CR_ATTEN;
! 1419:
! 1420: /* wait for a packet to return */
! 1421: if (wait_flag == NOWAIT)
! 1422: return 0;
! 1423:
! 1424: tmo = 0;
! 1425: while (pktp->command != CMD_PROCESSED) {
! 1426: #ifdef DEBUG_VXT
! 1427: printf("Polling for packet 0x%x in envelope 0x%x...\n", pktp, envp);
! 1428: #endif
! 1429: vx_intr(sc);
! 1430: if (++tmo > 20) {
! 1431: printf("%s: bpp_send pkt %x env %x timed out %d\n",
! 1432: sc->sc_dev.dv_xname, pktp, envp, pktp->command);
! 1433: return ETIMEDOUT;
! 1434: }
! 1435: delay(5000);
! 1436: }
! 1437: d16_bcopy(pktp, pkt, sizeof(struct packet));
! 1438: return pktp->error_l;
! 1439: }
! 1440:
! 1441: /*
! 1442: * BPP commands
! 1443: */
! 1444:
! 1445: int
! 1446: vx_init(struct vxsoftc *sc)
! 1447: {
! 1448: int i;
! 1449: int error;
! 1450: struct init_info *infp, inf;
! 1451: paddr_t wringp, rringp;
! 1452: struct packet init;
! 1453: struct packet evnt;
! 1454:
! 1455: /* init wait queue */
! 1456: d16_bzero(&sc->sc_bppwait_pkt, sizeof(struct packet));
! 1457: sc->sc_bppwait_pktp = NULL;
! 1458: /* set up init_info array */
! 1459: wringp = WRING_AREA;
! 1460: rringp = RRING_AREA;
! 1461: infp = (struct init_info *)VIRTUAL(INIT_INFO_AREA);
! 1462:
! 1463: for (i = 0; i < NVXPORTS; i++) {
! 1464: bzero(&inf, sizeof(struct init_info));
! 1465: inf.write_ring_ptr_h = HI(wringp);
! 1466: inf.write_ring_ptr_l = LO(wringp);
! 1467: sc->sc_info[i].wringp = (struct wring *)VIRTUAL(wringp);
! 1468: inf.read_ring_ptr_h = HI(rringp);
! 1469: inf.read_ring_ptr_l = LO(rringp);
! 1470: sc->sc_info[i].rringp = (struct rring *)VIRTUAL(rringp);
! 1471: #ifdef DEBUG_VXT
! 1472: printf("write at 0x%8x, read at 0x%8x\n", wringp, rringp);
! 1473: #endif
! 1474: inf.write_ring_size = WRING_DATA_SIZE;
! 1475: inf.read_ring_size = RRING_DATA_SIZE;
! 1476: inf.def_termio.c_iflag = VBRKINT;
! 1477: inf.def_termio.c_oflag = 0;
! 1478: inf.def_termio.c_cflag = (VB9600 | VCS8);
! 1479:
! 1480: inf.def_termio.c_lflag = VISIG; /* enable signal processing */
! 1481: inf.def_termio.c_line = 1; /* raw line discipline */
! 1482: inf.def_termio.c_cc[0] = CINTR;
! 1483: inf.def_termio.c_cc[1] = CQUIT;
! 1484: inf.def_termio.c_cc[2] = CERASE;
! 1485: inf.def_termio.c_cc[3] = CKILL;
! 1486: inf.def_termio.c_cc[4] = CEOF;
! 1487: inf.def_termio.c_cc[5] = CEOL;
! 1488: d16_bcopy(&inf, infp, sizeof(struct init_info));
! 1489: wringp += sizeof(struct wring);
! 1490: rringp += sizeof(struct rring);
! 1491: infp++;
! 1492: }
! 1493:
! 1494: /* set up init_packet */
! 1495: bzero(&init, sizeof(struct packet));
! 1496: init.command = CMD_INIT;
! 1497: init.command_pipe_number = sc->channel_number;
! 1498: /* return status on the same channel */
! 1499: init.status_pipe_number = sc->channel_number;
! 1500: init.interrupt_level = IPL_TTY;
! 1501: init.interrupt_vec = sc->sc_vec;
! 1502: init.init_info_ptr_h = HI(INIT_INFO_AREA);
! 1503: init.init_info_ptr_l = LO(INIT_INFO_AREA);
! 1504:
! 1505: /* send packet to the firmware and wait for completion */
! 1506: if ((error = bpp_send(sc, &init, WAIT)) != 0)
! 1507: return error;
! 1508:
! 1509: /* send one event packet to each device */
! 1510: for (i = 0; i < NVXPORTS; i++) {
! 1511: bzero(&evnt, sizeof(struct packet));
! 1512: evnt.command = CMD_EVENT;
! 1513: evnt.device_number = i;
! 1514: evnt.command_pipe_number = sc->channel_number;
! 1515: /* return status on same channel */
! 1516: evnt.status_pipe_number = sc->channel_number;
! 1517: /* send packet to the firmware */
! 1518: bpp_send(sc, &evnt, NOWAIT);
! 1519: }
! 1520:
! 1521: return 0;
! 1522: }
CVSweb