134506Skarels /* 234506Skarels * Copyright (c) 1988 Regents of the University of California. 334506Skarels * All rights reserved. 434506Skarels * 535055Skarels * This code is derived from software contributed to Berkeley by 635055Skarels * Computer Consoles Inc. 735055Skarels * 834506Skarels * Redistribution and use in source and binary forms are permitted 934866Sbostic * provided that the above copyright notice and this paragraph are 1034866Sbostic * duplicated in all such forms and that any documentation, 1134866Sbostic * advertising materials, and other materials related to such 1234866Sbostic * distribution and use acknowledge that the software was developed 1334866Sbostic * by the University of California, Berkeley. The name of the 1434866Sbostic * University may not be used to endorse or promote products derived 1534866Sbostic * from this software without specific prior written permission. 1634866Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1734866Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1834866Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1934506Skarels * 20*37607Smarc * @(#)mp.c 7.9 (Berkeley) 05/01/89 2134506Skarels */ 2232633Ssam 2332633Ssam #include "mp.h" 2432633Ssam #if NMP > 0 2532633Ssam /* 2632633Ssam * Multi Protocol Communications Controller (MPCC). 2732633Ssam * Asynchronous Terminal Protocol Support. 2832633Ssam */ 2932633Ssam #include "param.h" 3032633Ssam #include "ioctl.h" 3132633Ssam #include "tty.h" 3232633Ssam #include "dir.h" 3332633Ssam #include "user.h" 3432633Ssam #include "map.h" 3532633Ssam #include "buf.h" 3632633Ssam #include "conf.h" 3732633Ssam #include "file.h" 3832633Ssam #include "uio.h" 3932633Ssam #include "errno.h" 4032633Ssam #include "syslog.h" 4132633Ssam #include "vmmac.h" 4232633Ssam #include "kernel.h" 4332633Ssam #include "clist.h" 4432633Ssam 4537507Smckusick #include "machine/pte.h" 4637507Smckusick #include "machine/mtpr.h" 4734506Skarels 4832633Ssam #include "../tahoevba/vbavar.h" 4932633Ssam #include "../tahoevba/mpreg.h" 5032633Ssam 5132633Ssam #define MPCHUNK 16 5232633Ssam #define MPPORT(n) ((n) & 0xf) 5332633Ssam #define MPUNIT(n) ((n) >> 4) 5432633Ssam 5532633Ssam /* 5632633Ssam * Driver information for auto-configuration stuff. 5732633Ssam */ 5832633Ssam int mpprobe(), mpattach(), mpintr(); 5932633Ssam struct vba_device *mpinfo[NMP]; 6032633Ssam long mpstd[] = { 0 }; 6132633Ssam struct vba_driver mpdriver = 6232633Ssam { mpprobe, 0, mpattach, 0, mpstd, "mp", mpinfo }; 6332633Ssam 6432633Ssam int mpstart(); 65*37607Smarc int mpparam(); 66*37607Smarc struct mpevent *mpparam2(); 6732633Ssam struct mpevent *mp_getevent(); 6832633Ssam 6932633Ssam /* 7032633Ssam * The following structure is needed to deal with mpcc's convoluted 7132633Ssam * method for locating it's mblok structures (hold your stomach). 7232633Ssam * When an mpcc is reset at boot time it searches host memory 7332633Ssam * looking for a string that says ``ThIs Is MpCc''. The mpcc 7432633Ssam * then reads the structure to locate the pointer to it's mblok 7532633Ssam * structure (you can wretch now). 7632633Ssam */ 7732633Ssam struct mpbogus { 7832633Ssam char s[12]; /* `ThIs Is MpCc'' */ 7932633Ssam u_char status; 8032633Ssam u_char unused; 8132633Ssam u_short magic; 8232633Ssam struct mblok *mb; 8332633Ssam struct mblok *mbloks[NMP]; /* can support at most 16 mpcc's */ 8432633Ssam } mpbogus = { 'T','h','I','s',' ','I','s',' ','M','p','C','c' }; 8532633Ssam 8632633Ssam /* 8732633Ssam * Software state per unit. 8832633Ssam */ 8932633Ssam struct mpsoftc { 9032633Ssam u_int ms_ivec; /* interrupt vector */ 9132633Ssam u_int ms_softCAR; /* software carrier for async */ 9232633Ssam struct mblok *ms_mb; /* mpcc status area */ 9332633Ssam struct vb_buf ms_buf; /* vba resources for ms_mb */ 9432633Ssam struct hxmtl ms_hxl[MPMAXPORT];/* host transmit list */ 9532633Ssam struct asyncparam ms_async[MPMAXPORT][MPINSET];/* async structs */ 9632633Ssam char ms_cbuf[MPMAXPORT][MPOUTSET][CBSIZE];/* input character buffers */ 9732633Ssam } mp_softc[NMP]; 9832633Ssam 99*37607Smarc struct speedtab 100*37607Smarc mpspeedtab[] = { 101*37607Smarc 9600, M9600, /* baud rate = 9600 */ 102*37607Smarc 4800, M4800, /* baud rate = 4800 */ 103*37607Smarc 2400, M2400, /* baud rate = 2400 */ 104*37607Smarc 1800, M1800, /* baud rate = 1800 */ 105*37607Smarc 1200, M1200, /* baud rate = 1200 */ 106*37607Smarc 600, M600, /* baud rate = 600 */ 107*37607Smarc 300, M300, /* baud rate = 300 */ 108*37607Smarc 200, M200, /* baud rate = 200 */ 109*37607Smarc 150, M150, /* baud rate = 150 */ 110*37607Smarc 134, M134_5, /* baud rate = 134.5 */ 111*37607Smarc 110, M110, /* baud rate = 110 */ 112*37607Smarc 75, M75, /* baud rate = 75 */ 113*37607Smarc 50, M50, /* baud rate = 50 */ 114*37607Smarc 0, M0, /* baud rate = 0 */ 115*37607Smarc 2000, M2000, /* baud rate = 2000 */ 116*37607Smarc 3600, M3600, /* baud rate = 3600 */ 117*37607Smarc 7200, M7200, /* baud rate = 7200 */ 118*37607Smarc 19200, M19200, /* baud rate = 19,200 */ 119*37607Smarc 24000, M24000, /* baud rate = 24,000 */ 120*37607Smarc 28400, M28400, /* baud rate = 28,400 */ 121*37607Smarc 37800, M37800, /* baud rate = 37,800 */ 122*37607Smarc 40300, M40300, /* baud rate = 40,300 */ 123*37607Smarc 48000, M48000, /* baud rate = 48,000 */ 124*37607Smarc 52000, M52000, /* baud rate = 52,000 */ 125*37607Smarc 56800, M56800, /* baud rate = 56,800 */ 126*37607Smarc EXTA, MEXTA, /* baud rate = Ext A */ 127*37607Smarc EXTB, MEXTB, /* baud rate = Ext B */ 128*37607Smarc -1, -1, 129*37607Smarc }; 130*37607Smarc 13132633Ssam struct tty mp_tty[NMP*MPCHUNK]; 13232633Ssam #ifndef lint 13332633Ssam int nmp = NMP*MPCHUNK; 13432633Ssam #endif 13532633Ssam 13632633Ssam int ttrstrt(); 13732633Ssam 13832633Ssam mpprobe(reg, vi) 13932633Ssam caddr_t reg; 14032633Ssam struct vba_device *vi; 14132633Ssam { 14232633Ssam register int br, cvec; 14332633Ssam register struct mpsoftc *ms; 14432633Ssam 14532633Ssam #ifdef lint 14632633Ssam br = 0; cvec = br; br = cvec; 14732633Ssam mpintr(0); 14834506Skarels mpdlintr(0); 14932633Ssam #endif 15032633Ssam if (badaddr(reg, 2)) 15132633Ssam return (0); 15232633Ssam ms = &mp_softc[vi->ui_unit]; 15332633Ssam /* 15432633Ssam * Allocate page tables and mblok 15532633Ssam * structure (mblok in non-cached memory). 15632633Ssam */ 15732633Ssam if (vbainit(&ms->ms_buf, sizeof (struct mblok), VB_32BIT) == 0) { 15832633Ssam printf("mp%d: vbainit failed\n", vi->ui_unit); 15932633Ssam return (0); 16032633Ssam } 16132633Ssam ms->ms_mb = (struct mblok *)ms->ms_buf.vb_rawbuf; 16232633Ssam ms->ms_ivec = MPINTRBASE + 2*vi->ui_unit; /* XXX */ 16332633Ssam br = 0x14, cvec = ms->ms_ivec; /* XXX */ 16434287Skarels return (sizeof (*reg)); 16532633Ssam } 16632633Ssam 16732633Ssam mpattach(vi) 16832633Ssam register struct vba_device *vi; 16932633Ssam { 17032633Ssam register struct mpsoftc *ms = &mp_softc[vi->ui_unit]; 17132633Ssam 17232633Ssam ms->ms_softCAR = vi->ui_flags; 17332633Ssam /* 17432633Ssam * Setup pointer to mblok, initialize bogus 17532633Ssam * status block used by mpcc to locate the pointer 17632633Ssam * and then poke the mpcc to get it to search host 17732633Ssam * memory to find mblok pointer. 17832633Ssam */ 17932633Ssam mpbogus.mbloks[vi->ui_unit] = (struct mblok *)ms->ms_buf.vb_physbuf; 18032633Ssam *(short *)vi->ui_addr = 0x100; /* magic */ 18132633Ssam } 18232633Ssam 18332633Ssam /* 18432633Ssam * Open an mpcc port. 18532633Ssam */ 18634506Skarels /* ARGSUSED */ 18732633Ssam mpopen(dev, mode) 18832633Ssam dev_t dev; 18932633Ssam { 19032633Ssam register struct tty *tp; 19132633Ssam register struct mpsoftc *ms; 19232633Ssam int error, s, port, unit, mpu; 19332633Ssam struct vba_device *vi; 19432633Ssam struct mpport *mp; 19532633Ssam struct mpevent *ev; 19632633Ssam 19732633Ssam unit = minor(dev); 19832633Ssam mpu = MPUNIT(unit); 19932633Ssam if (mpu >= NMP || (vi = mpinfo[mpu]) == 0 || vi->ui_alive == 0) 20032633Ssam return (ENXIO); 20132633Ssam tp = &mp_tty[unit]; 20232633Ssam if (tp->t_state & TS_XCLUDE && u.u_uid != 0) 20332633Ssam return (EBUSY); 20432633Ssam ms = &mp_softc[mpu]; 20532633Ssam port = MPPORT(unit); 20632633Ssam if (ms->ms_mb->mb_proto[port] != MPPROTO_ASYNC || 20732633Ssam ms->ms_mb->mb_status != MP_OPOPEN) 20832633Ssam return (ENXIO); 20932633Ssam mp = &ms->ms_mb->mb_port[port]; /* host mpcc struct */ 21032633Ssam s = spl8(); 21135935Sbostic /* 21235935Sbostic * serialize open and close events 21335935Sbostic */ 214*37607Smarc while ((mp->mp_flags & MP_PROGRESS) || ((tp->t_state & TS_WOPEN) && 215*37607Smarc !(mode&O_NONBLOCK) && !(tp->t_cflag&CLOCAL))) 21632633Ssam sleep((caddr_t)&tp->t_canq, TTIPRI); 21735935Sbostic restart: 21832633Ssam tp->t_state |= TS_WOPEN; 21932633Ssam tp->t_addr = (caddr_t)ms; 22032633Ssam tp->t_oproc = mpstart; 221*37607Smarc tp->t_param = mpparam; 22232633Ssam tp->t_dev = dev; 22334978Sbostic if ((tp->t_state & TS_ISOPEN) == 0) { 22434978Sbostic ttychars(tp); 22534978Sbostic if (tp->t_ispeed == 0) { 226*37607Smarc tp->t_ispeed = TTYDEF_SPEED; 227*37607Smarc tp->t_ospeed = TTYDEF_SPEED; 228*37607Smarc tp->t_iflag = TTYDEF_IFLAG; 229*37607Smarc tp->t_oflag = TTYDEF_OFLAG; 230*37607Smarc tp->t_lflag = TTYDEF_LFLAG; 231*37607Smarc tp->t_cflag = TTYDEF_CFLAG; 23234978Sbostic } 23334978Sbostic /* 23434978Sbostic * Initialize port state: init MPCC interface 23534978Sbostic * structures for port and setup modem control. 23634978Sbostic */ 23734978Sbostic error = mpportinit(ms, mp, port); 23834978Sbostic if (error) 23934978Sbostic goto bad; 240*37607Smarc ev = mpparam2(tp, &tp->t_termios); 24134978Sbostic if (ev == 0) { 24234978Sbostic error = ENOBUFS; 24334978Sbostic goto bad; 24434978Sbostic } 24535935Sbostic mp->mp_flags |= MP_PROGRESS; 24634978Sbostic mpcmd(ev, EVCMD_OPEN, 0, ms->ms_mb, port); 24735935Sbostic /* 24835935Sbostic * wait for port to start 24935935Sbostic */ 25035935Sbostic while (mp->mp_proto != MPPROTO_ASYNC) 25135935Sbostic sleep((caddr_t)&tp->t_canq, TTIPRI); 252*37607Smarc ttsetwater(tp); 25335935Sbostic mp->mp_flags &= ~MP_PROGRESS; 25432633Ssam } 255*37607Smarc while (!(mode&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) && 256*37607Smarc (tp->t_state & TS_CARR_ON) == 0) { 25732633Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 25835935Sbostic /* 25935935Sbostic * a mpclose() might have disabled port. if so restart 26035935Sbostic */ 26135935Sbostic if (mp->mp_proto != MPPROTO_ASYNC) 26235935Sbostic goto restart; 26335935Sbostic tp->t_state |= TS_WOPEN; 26435935Sbostic } 26532633Ssam error = (*linesw[tp->t_line].l_open)(dev,tp); 26632633Ssam done: 26732633Ssam splx(s); 26835935Sbostic /* 26935935Sbostic * wakeup those processes waiting for the open to complete 27035935Sbostic */ 27132633Ssam wakeup((caddr_t)&tp->t_canq); 27232633Ssam return (error); 27332633Ssam bad: 27432633Ssam tp->t_state &= ~TS_WOPEN; 27532633Ssam goto done; 27632633Ssam } 27732633Ssam 27832633Ssam /* 27932633Ssam * Close an mpcc port. 28032633Ssam */ 28134506Skarels /* ARGSUSED */ 28234506Skarels mpclose(dev, flag) 28332633Ssam dev_t dev; 28432633Ssam { 28532633Ssam register struct tty *tp; 28632633Ssam register struct mpport *mp; 28732633Ssam register struct mpevent *ev; 28832633Ssam int s, port, unit, error; 28932633Ssam struct mblok *mb; 29032633Ssam 29132633Ssam unit = minor(dev); 29232633Ssam tp = &mp_tty[unit]; 29332633Ssam port = MPPORT(unit); 29432633Ssam mb = mp_softc[MPUNIT(unit)].ms_mb; 29532633Ssam mp = &mb->mb_port[port]; 29632633Ssam s = spl8(); 29735935Sbostic if (mp->mp_flags & MP_PROGRESS) { 29832633Ssam if (mp->mp_flags & MP_REMBSY) { 29932633Ssam mp->mp_flags &= ~MP_REMBSY; 30032633Ssam splx(s); 30132633Ssam return (0); 30232633Ssam } 30332633Ssam while (mp->mp_flags & MP_PROGRESS) 30435935Sbostic sleep((caddr_t)&tp->t_canq, TTIPRI); 30532633Ssam } 30632633Ssam error = 0; 30732633Ssam mp->mp_flags |= MP_PROGRESS; 30832633Ssam (*linesw[tp->t_line].l_close)(tp); 30935935Sbostic ev = mp_getevent(mp, unit, 1); 31032633Ssam if (ev == 0) { 31134977Sbostic error = ENOBUFS; 31234977Sbostic mp->mp_flags &= ~MP_PROGRESS; 31334977Sbostic goto out; 31432633Ssam } 31534977Sbostic if (tp->t_state & TS_HUPCLS || (tp->t_state & TS_ISOPEN) == 0) 31634977Sbostic mpmodem(unit, MMOD_OFF); 31734977Sbostic else 31834977Sbostic mpmodem(unit, MMOD_ON); 31932633Ssam mpcmd(ev, EVCMD_CLOSE, 0, mb, port); 32034977Sbostic ttyclose(tp); 32132633Ssam out: 32232633Ssam if (mp->mp_flags & MP_REMBSY) 32332633Ssam mpclean(mb, port); 32435935Sbostic else 32535935Sbostic while (mp->mp_flags & MP_PROGRESS) 32635935Sbostic sleep((caddr_t)&tp->t_canq,TTIPRI); 32732633Ssam splx(s); 32832633Ssam return (error); 32932633Ssam } 33032633Ssam 33132633Ssam /* 33232633Ssam * Read from an mpcc port. 33332633Ssam */ 334*37607Smarc mpread(dev, uio, flag) 33532633Ssam dev_t dev; 33632633Ssam struct uio *uio; 33732633Ssam { 33832633Ssam struct tty *tp; 33932633Ssam 34032633Ssam tp = &mp_tty[minor(dev)]; 341*37607Smarc return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 34232633Ssam } 34332633Ssam 34432633Ssam /* 34532633Ssam * Write to an mpcc port. 34632633Ssam */ 347*37607Smarc mpwrite(dev, uio, flag) 34832633Ssam dev_t dev; 34932633Ssam struct uio *uio; 35032633Ssam { 35132633Ssam struct tty *tp; 35232633Ssam 35332633Ssam tp = &mp_tty[minor(dev)]; 354*37607Smarc return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 35532633Ssam } 35632633Ssam 35732633Ssam /* 35832633Ssam * Ioctl for a mpcc port 35932633Ssam */ 36032633Ssam mpioctl(dev, cmd, data, flag) 36132633Ssam dev_t dev; 36232633Ssam caddr_t data; 36332633Ssam { 36432633Ssam register struct tty *tp; 36532633Ssam register struct mpsoftc *ms; 366*37607Smarc register struct mpport *mp; 36732633Ssam register struct mpevent *ev; 36832633Ssam int s, port, error, unit; 36932633Ssam struct mblok *mb; 37032633Ssam 37132633Ssam unit = minor(dev); 37232633Ssam tp = &mp_tty[unit]; 37332633Ssam ms = &mp_softc[MPUNIT(unit)]; 37432633Ssam mb = ms->ms_mb; 37535935Sbostic port = MPPORT(unit); 37635935Sbostic mp = &mb->mb_port[port]; 37735935Sbostic if (mp->mp_proto != MPPROTO_ASYNC) 37835935Sbostic return(ENXIO); 37932633Ssam error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 38032633Ssam if (error >= 0) 38132633Ssam return (error); 38232633Ssam error = ttioctl(tp, cmd, data, flag); 383*37607Smarc if (error >= 0) 38432633Ssam return (error); 38532633Ssam switch (cmd) { 38632633Ssam case TIOCSBRK: /* send break */ 38732633Ssam case TIOCCBRK: /* clear break */ 38832633Ssam s = spl8(); 38935935Sbostic while (mp->mp_flags & MP_IOCTL) { 39035935Sbostic sleep((caddr_t)&tp->t_canq, TTIPRI); 39135935Sbostic if (mp->mp_proto != MPPROTO_ASYNC) { 39235935Sbostic mp->mp_flags &= ~MP_IOCTL; 39335935Sbostic splx(s); 39435935Sbostic return(ENXIO); 39535935Sbostic } 39635935Sbostic } 39735935Sbostic ev = mp_getevent(mp, unit, 0); 39835935Sbostic if (ev) { 39935935Sbostic mp->mp_flags |= MP_IOCTL; 40032633Ssam mpcmd(ev, EVCMD_IOCTL, 40135935Sbostic (cmd == TIOCSBRK ? A_BRKON : A_BRKOFF), mb, port); 40235935Sbostic } else 40332633Ssam error = ENOBUFS; 40432633Ssam splx(s); 40532633Ssam break; 40632633Ssam case TIOCSDTR: /* set dtr control line */ 40732633Ssam break; 40832633Ssam case TIOCCDTR: /* clear dtr control line */ 40932633Ssam break; 41032633Ssam default: 41132633Ssam error = ENOTTY; 41232633Ssam break; 41332633Ssam } 41432633Ssam return (error); 41532633Ssam } 41632633Ssam 417*37607Smarc mpparam(tp, t) 418*37607Smarc struct tty *tp; 419*37607Smarc struct termios *t; 420*37607Smarc { 421*37607Smarc register struct mpevent *ev; 422*37607Smarc int unit = minor(tp->t_dev); 423*37607Smarc struct mpsoftc *ms = &mp_softc[MPUNIT(unit)]; 424*37607Smarc struct mblok *mb = ms->ms_mb; 425*37607Smarc 426*37607Smarc ev = mpparam2(tp, t); 427*37607Smarc if (ev == 0) 428*37607Smarc return (ENOBUFS); 429*37607Smarc mpcmd(ev, EVCMD_IOCTL, A_CHGALL, mb, MPPORT(unit)); 430*37607Smarc return (0); 431*37607Smarc } 432*37607Smarc 43332633Ssam struct mpevent * 434*37607Smarc mpparam2(tp, t) 435*37607Smarc register struct tty *tp; 436*37607Smarc struct termios *t; 43732633Ssam { 43832633Ssam register struct mpevent *ev; 43932633Ssam register struct mpport *mp; 440*37607Smarc int unit = minor(tp->t_dev); 44132633Ssam struct mblok *mb; 44232633Ssam struct mpsoftc *ms; 44332633Ssam register struct asyncparam *asp; 444*37607Smarc int port, speedcode; 44532633Ssam 44632633Ssam ms = &mp_softc[MPUNIT(unit)]; 44732633Ssam mb = ms->ms_mb; 44832633Ssam port = MPPORT(unit); 44932633Ssam mp = &mb->mb_port[port]; 45035935Sbostic ev = mp_getevent(mp, unit, 0); /* XXX */ 451*37607Smarc speedcode = ttspeedtab(t->c_ospeed, mpspeedtab); 452*37607Smarc if (ev == 0 || speedcode < 0) { 453*37607Smarc printf("mp mpunit %d port %d param2 failed ev: %x speed %d, wanted %d\n", 454*37607Smarc MPUNIT(unit), port, ev, speedcode, t->c_ospeed); 455*37607Smarc return (0); /* XXX */ 456*37607Smarc } 45732633Ssam /* YUCK */ 45832633Ssam asp = &ms->ms_async[port][mp->mp_on?mp->mp_on-1:MPINSET-1]; 459*37607Smarc asp->ap_xon = t->c_cc[VSTART]; 460*37607Smarc asp->ap_xoff = t->c_cc[VSTOP]; 461*37607Smarc if (!(t->c_iflag&IXON) || (asp->ap_xon == _POSIX_VDISABLE) || 462*37607Smarc (asp->ap_xoff == _POSIX_VDISABLE)) 46334796Sbostic asp->ap_xena = MPA_DIS; 46434796Sbostic else 46534796Sbostic asp->ap_xena = MPA_ENA; 466*37607Smarc asp->ap_xany = ((t->c_iflag & IXANY) ? MPA_ENA : MPA_DIS); 46732633Ssam #ifdef notnow 468*37607Smarc if (t->t_cflag&CSIZE) == CS8) { 46932633Ssam #endif 47032633Ssam asp->ap_data = MPCHAR_8; 47132633Ssam asp->ap_parity = MPPAR_NONE; 47232633Ssam #ifdef notnow 47332633Ssam } else { 47432633Ssam asp->ap_data = MPCHAR_7; 475*37607Smarc if ((t->c_flags & (EVENP|ODDP)) == ODDP) /* XXX */ 47632633Ssam asp->ap_parity = MPPAR_ODD; 47732633Ssam else 47832633Ssam asp->ap_parity = MPPAR_EVEN; 47932633Ssam } 48032633Ssam #endif 48135935Sbostic asp->ap_loop = MPA_DIS; /* disable loopback */ 48235935Sbostic asp->ap_rtimer = A_RCVTIM; /* default receive timer */ 483*37607Smarc if (t->c_ospeed == B110) 48432633Ssam asp->ap_stop = MPSTOP_2; 48532633Ssam else 48632633Ssam asp->ap_stop = MPSTOP_1; 487*37607Smarc if (t->c_ospeed == 0) { 48835935Sbostic tp->t_state |= TS_HUPCLS; 48935935Sbostic setm(&asp->ap_modem, 0, DROP); 49035935Sbostic seti(&asp->ap_intena, A_DCD); 49135935Sbostic return (ev); 49235935Sbostic } 493*37607Smarc if (t->c_ospeed == EXTA || t->c_ospeed == EXTB) 49432633Ssam asp->ap_baud = M19200; 49532633Ssam else 496*37607Smarc asp->ap_baud = speedcode; 497*37607Smarc if (1 || ms->ms_softCAR & (1<<port)) /* XXX HARDWIRE FOR NOW */ 49832633Ssam setm(&asp->ap_modem, A_DTR, ASSERT); 49932633Ssam else 50032633Ssam setm(&asp->ap_modem, A_DTR, AUTO); 50132633Ssam seti(&asp->ap_intena, A_DCD); 502*37607Smarc return(ev); 50332633Ssam } 50432633Ssam 50532633Ssam mpstart(tp) 50632633Ssam register struct tty *tp; 50732633Ssam { 50832633Ssam register struct mpevent *ev; 50932633Ssam register struct mpport *mp; 51032633Ssam struct mblok *mb; 51132633Ssam struct mpsoftc *ms; 51232633Ssam int port, unit, xcnt, n, s, i; 51332633Ssam struct hxmtl *hxp; 51432633Ssam struct clist outq; 51532633Ssam 51632633Ssam s = spl8(); 51732633Ssam unit = minor(tp->t_dev); 51832633Ssam ms = &mp_softc[MPUNIT(unit)]; 51932633Ssam mb = ms->ms_mb; 52032633Ssam port = MPPORT(unit); 52132633Ssam mp = &mb->mb_port[port]; 52232633Ssam hxp = &ms->ms_hxl[port]; 52332633Ssam xcnt = 0; 52432633Ssam outq = tp->t_outq; 52532633Ssam for (i = 0; i < MPXMIT; i++) { 52632633Ssam if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 52732633Ssam break; 528*37607Smarc if (outq.c_cc <= tp->t_lowat) { 52932633Ssam if (tp->t_state & TS_ASLEEP) { 53032633Ssam tp->t_state &= ~TS_ASLEEP; 53132633Ssam wakeup((caddr_t)&tp->t_outq); 53232633Ssam } 53332633Ssam if (tp->t_wsel) { 53432633Ssam selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 53532633Ssam tp->t_wsel = 0; 53632633Ssam tp->t_state &= ~TS_WCOLL; 53732633Ssam } 53832633Ssam } 53932633Ssam if (outq.c_cc == 0) 54032633Ssam break; 54132633Ssam /* 54232633Ssam * If we're not currently busy outputting, 54332633Ssam * and there is data to be output, set up 54432633Ssam * port transmit structure to send to mpcc. 54532633Ssam */ 546*37607Smarc if (1) /* || tp->t_flags & (RAW|LITOUT)) XXX FIX */ 54732633Ssam n = ndqb(&outq, 0); 54832633Ssam else { 54932633Ssam n = ndqb(&outq, 0200); 55032633Ssam if (n == 0) { 55135935Sbostic if (xcnt > 0) 55235935Sbostic break; 55332633Ssam n = getc(&outq); 55432633Ssam timeout(ttrstrt, (caddr_t)tp, (n&0177)+6); 55532633Ssam tp->t_state |= TS_TIMEOUT; 55632633Ssam break; 55732633Ssam } 55832633Ssam } 55934506Skarels hxp->dblock[i] = (caddr_t)kvtophys(outq.c_cf); 56032633Ssam hxp->size[i] = n; 56132633Ssam xcnt++; /* count of xmts to send */ 56232633Ssam ndadvance(&outq, n); 56332633Ssam } 56432633Ssam /* 56532633Ssam * If data to send, poke mpcc. 56632633Ssam */ 56732633Ssam if (xcnt) { 56835935Sbostic ev = mp_getevent(mp, unit, 0); 56932633Ssam if (ev == 0) { 57032633Ssam tp->t_state &= ~(TS_BUSY|TS_TIMEOUT); 57132633Ssam } else { 57232633Ssam tp->t_state |= TS_BUSY; 57332633Ssam ev->ev_count = xcnt; 57432633Ssam mpcmd(ev, EVCMD_WRITE, 0, mb, MPPORT(unit)); 57532633Ssam } 57632633Ssam } 57732633Ssam splx(s); 57832633Ssam } 57932633Ssam 58032633Ssam /* 58132633Ssam * Advance cc bytes from q but don't free memory. 58232633Ssam */ 58332633Ssam ndadvance(q, cc) 58432633Ssam register struct clist *q; 58532633Ssam register cc; 58632633Ssam { 58732633Ssam register struct cblock *bp; 58832633Ssam char *end; 58932633Ssam int rem, s; 59032633Ssam 59132633Ssam s = spltty(); 59232633Ssam if (q->c_cc <= 0) 59332633Ssam goto out; 59432633Ssam while (cc>0 && q->c_cc) { 59532633Ssam bp = (struct cblock *)((int)q->c_cf & ~CROUND); 59632633Ssam if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) { 59732633Ssam end = q->c_cl; 59832633Ssam } else { 59932633Ssam end = (char *)((int)bp + sizeof (struct cblock)); 60032633Ssam } 60132633Ssam rem = end - q->c_cf; 60232633Ssam if (cc >= rem) { 60332633Ssam cc -= rem; 60432633Ssam q->c_cc -= rem; 60532633Ssam q->c_cf = bp->c_next->c_info; 60632633Ssam } else { 60732633Ssam q->c_cc -= cc; 60832633Ssam q->c_cf += cc; 60932633Ssam break; 61032633Ssam } 61132633Ssam } 61232633Ssam if (q->c_cc <= 0) { 61332633Ssam q->c_cf = q->c_cl = NULL; 61432633Ssam q->c_cc = 0; 61532633Ssam } 61632633Ssam out: 61732633Ssam splx(s); 61832633Ssam } 61932633Ssam 62032633Ssam /* 62132633Ssam * Stop output on a line, e.g. for ^S/^Q or output flush. 62232633Ssam */ 62334506Skarels /* ARGSUSED */ 62432633Ssam mpstop(tp, rw) 62532633Ssam register struct tty *tp; 62632633Ssam int rw; 62732633Ssam { 62835935Sbostic register struct mpport *mp; 62935935Sbostic register struct mpevent *ev; 63035935Sbostic int unit = minor(tp->t_dev); 63135935Sbostic int port; 63235935Sbostic struct mblok *mb; 63334506Skarels int s; 63432633Ssam 63532633Ssam s = spl8(); 63632633Ssam if (tp->t_state & TS_BUSY) { 63735935Sbostic if ((tp->t_state & TS_TTSTOP) == 0) { 63832633Ssam tp->t_state |= TS_FLUSH; 63935935Sbostic port = MPPORT(unit); 64035935Sbostic mb = mp_softc[MPUNIT(unit)].ms_mb; 64135935Sbostic mp = &mb->mb_port[port]; 64235935Sbostic ev = mp_getevent(mp, unit, 0); 64335935Sbostic if (ev == 0) { 64435935Sbostic splx(s); 64535935Sbostic return; 64635935Sbostic } 64735935Sbostic mpcmd(ev, EVCMD_WRITE, A_FLUSH, mb, port); 64835935Sbostic } 64932633Ssam } 65032633Ssam splx(s); 65132633Ssam } 65232633Ssam 65332633Ssam /* 65432633Ssam * Initialize an async port's MPCC state. 65532633Ssam */ 65632633Ssam mpportinit(ms, mp, port) 65732633Ssam register struct mpsoftc *ms; 65832633Ssam register struct mpport *mp; 65932633Ssam int port; 66032633Ssam { 66132633Ssam register struct mpevent *ev; 66232633Ssam register int i; 66332633Ssam caddr_t ptr; 66432633Ssam 66532633Ssam mp->mp_on = mp->mp_off = 0; 66632633Ssam mp->mp_nextrcv = 0; 66732633Ssam mp->mp_flags = 0; 66832633Ssam ev = &mp->mp_recvq[0]; 66932633Ssam for (i = 0; ev < &mp->mp_recvq[MPINSET]; ev++, i++) { 67032633Ssam ev->ev_status = EVSTATUS_FREE; 67132633Ssam ev->ev_cmd = 0; 67232633Ssam ev->ev_opts = 0; 67332633Ssam ev->ev_error = 0; 67432633Ssam ev->ev_flags = 0; 67532633Ssam ev->ev_count = 0; 67634506Skarels ev->ev_un.hxl = (struct hxmtl *) kvtophys(&ms->ms_hxl[port]); 67734506Skarels ev->ev_params = (caddr_t) kvtophys(&ms->ms_async[port][i]); 67832633Ssam } 67932633Ssam ev = &mp->mp_sendq[0]; 68032633Ssam for (i = 0; ev < &mp->mp_sendq[MPOUTSET]; ev++, i++) { 68132633Ssam /* init so that L2 can't send any events */ 68232633Ssam /* to host until open has completed */ 68332633Ssam ev->ev_status = EVSTATUS_FREE; 68432633Ssam ev->ev_cmd = 0; 68535935Sbostic ev->ev_opts = 0; 68632633Ssam ev->ev_error = 0; 68732633Ssam ev->ev_flags = 0; 68832633Ssam ev->ev_count = 0; 68932633Ssam ptr = (caddr_t) &ms->ms_cbuf[port][i][0]; 69034506Skarels ev->ev_un.rcvblk = (u_char *)kvtophys(ptr); 69134506Skarels ev->ev_params = (caddr_t) kvtophys(ptr); 69232633Ssam } 69332633Ssam return (0); 69432633Ssam } 69532633Ssam 69632633Ssam /* 69732633Ssam * Send an event to an mpcc. 69832633Ssam */ 69932633Ssam mpcmd(ev, cmd, flags, mb, port) 70032633Ssam register struct mpevent *ev; 70132633Ssam struct mblok *mb; 70232633Ssam { 70332633Ssam int s; 70432633Ssam 70532633Ssam s = spl8(); 70632633Ssam /* move host values to inbound entry */ 70732633Ssam ev->ev_cmd = cmd; 70832633Ssam ev->ev_opts = flags; 70932633Ssam /* show event ready for mpcc */ 71032633Ssam ev->ev_status = EVSTATUS_GO; 71132633Ssam mpintmpcc(mb, port); 71232633Ssam splx(s); 71332633Ssam } 71432633Ssam 71532633Ssam /* 71632633Ssam * Return the next available event entry for the indicated port. 71732633Ssam */ 71832633Ssam struct mpevent * 71935935Sbostic mp_getevent(mp, unit, cls_req) 72032633Ssam register struct mpport *mp; 72132633Ssam int unit; 72235935Sbostic int cls_req; 72332633Ssam { 72432633Ssam register struct mpevent *ev; 72532633Ssam int i, s; 72632633Ssam 72732633Ssam s = spl8(); 72832633Ssam ev = &mp->mp_recvq[mp->mp_on]; 72932633Ssam if (ev->ev_status != EVSTATUS_FREE) 73032633Ssam goto bad; 73132633Ssam /* 73232633Ssam * If not a close request, verify one extra 73332633Ssam * event is available for closing the port. 73432633Ssam */ 73535935Sbostic if (!cls_req) { 73632633Ssam if ((i = mp->mp_on + 1) >= MPINSET) 73732633Ssam i = 0; 73832633Ssam if (mp->mp_recvq[i].ev_status != EVSTATUS_FREE) 73932633Ssam goto bad; 74032633Ssam } 74132633Ssam /* init inbound fields marking this entry as busy */ 74235935Sbostic ev->ev_cmd = 0; 74335935Sbostic ev->ev_opts = 0; 74432633Ssam ev->ev_error = 0; 74532633Ssam ev->ev_flags = 0; 74632633Ssam ev->ev_count = 0; 74732633Ssam ev->ev_status = EVSTATUS_BUSY; 74832633Ssam /* adjust pointer to next available inbound entry */ 74932633Ssam adjptr(mp->mp_on, MPINSET); 75032633Ssam splx(s); 75132633Ssam return (ev); 75232633Ssam bad: 75332633Ssam splx(s); 75435935Sbostic log(LOG_ERR, "mp%d: port%d, out of events\n", 75535935Sbostic MPUNIT(unit), MPPORT(unit)); 75632633Ssam return ((struct mpevent *)0); 75732633Ssam } 75832633Ssam 75932633Ssam mpmodem(unit, flag) 76032633Ssam int unit, flag; 76132633Ssam { 76232633Ssam struct mpsoftc *ms = &mp_softc[MPUNIT(unit)]; 76332633Ssam int port = MPPORT(unit); 76432633Ssam register struct mpport *mp; 76532633Ssam register struct asyncparam *asp; 76632633Ssam 76732633Ssam mp = &ms->ms_mb->mb_port[port]; 76832633Ssam asp = &ms->ms_async[port][mp->mp_on?mp->mp_on-1:MPINSET-1]; 76932633Ssam if (flag == MMOD_ON) { 770*37607Smarc if (1 || ms->ms_softCAR & (1 << port))/* XXX HARDWIRE FOR NOW */ 77132633Ssam setm(&asp->ap_modem, A_DTR, ASSERT); 77232633Ssam else 77332633Ssam setm(&asp->ap_modem, A_DTR, AUTO); 77432633Ssam seti(&asp->ap_intena, A_DCD); 77532633Ssam } else { 77632633Ssam setm(&asp->ap_modem, 0, DROP); 77732633Ssam seti(&asp->ap_intena, 0); 77832633Ssam } 77932633Ssam } 78032633Ssam 78132633Ssam /* 78232633Ssam * Set up the modem control structure according to mask. 78332633Ssam * Each set bit in the mask means assert the corresponding 78432633Ssam * modem control line, otherwise, it will be dropped. 78532633Ssam * RTS is special since it can either be asserted, dropped 78632633Ssam * or put in auto mode for auto modem control. 78732633Ssam */ 78832633Ssam static 78932633Ssam setm(mc, mask, rts) 79032633Ssam register struct mdmctl *mc; 79132633Ssam register int mask; 79232633Ssam { 79332633Ssam 79432633Ssam mc->mc_rngdsr = (mask & A_RNGDSR) ? ASSERT : DROP; 79532633Ssam mc->mc_rate = (mask & A_RATE) ? ASSERT : DROP; 79632633Ssam mc->mc_dcd = (mask & A_DCD) ? ASSERT : DROP; 79732633Ssam mc->mc_sectx = (mask & A_SECTX) ? ASSERT : DROP; 79832633Ssam mc->mc_cts = (mask & A_CTS) ? ASSERT : DROP; 79932633Ssam mc->mc_secrx = (mask & A_SECRX) ? ASSERT : DROP; 80032633Ssam mc->mc_dtr = (mask & A_DTR) ? ASSERT : DROP; 80132633Ssam mc->mc_rts = rts; 80232633Ssam } 80332633Ssam 80432633Ssam /* 80532633Ssam * Set up the status change enable field from mask. 80632633Ssam * When a signal is enabled in this structure and 80732633Ssam * and a change in state on a corresponding modem 80832633Ssam * control line occurs, a status change event will 80932633Ssam * be delivered to the host. 81032633Ssam */ 81132633Ssam static 81232633Ssam seti(mc, mask) 81332633Ssam register struct mdmctl *mc; 81432633Ssam register int mask; 81532633Ssam { 81632633Ssam 81732633Ssam mc->mc_rngdsr = (mask & A_RNGDSR) ? MDM_ON : MDM_OFF; 81832633Ssam mc->mc_rate = (mask & A_RATE) ? MDM_ON : MDM_OFF; 81932633Ssam mc->mc_dcd = (mask & A_DCD) ? MDM_ON : MDM_OFF; 82032633Ssam mc->mc_sectx = (mask & A_SECTX) ? MDM_ON : MDM_OFF; 82132633Ssam mc->mc_cts = (mask & A_CTS) ? MDM_ON : MDM_OFF; 82232633Ssam mc->mc_secrx = (mask & A_SECRX) ? MDM_ON : MDM_OFF; 82332633Ssam mc->mc_dtr = (mask & A_DTR) ? MDM_ON : MDM_OFF; 82432633Ssam mc->mc_rts = (mask & A_RTS) ? MDM_ON : MDM_OFF; 82532633Ssam } 82632633Ssam 82732633Ssam mpcleanport(mb, port) 82832633Ssam struct mblok *mb; 82932633Ssam int port; 83032633Ssam { 83132633Ssam register struct mpport *mp; 83232633Ssam register struct tty *tp; 83332633Ssam 83432633Ssam mp = &mb->mb_port[port]; 83532633Ssam if (mp->mp_proto == MPPROTO_ASYNC) { 83632633Ssam mp->mp_flags = MP_REMBSY; 83734506Skarels /* signal loss of carrier and close */ 83832633Ssam tp = &mp_tty[mb->mb_unit*MPCHUNK+port]; 83932633Ssam ttyflush(tp, FREAD|FWRITE); 84034506Skarels (void) (*linesw[tp->t_line].l_modem)(tp, 0); 84132633Ssam } 84232633Ssam } 84332633Ssam 84432633Ssam mpclean(mb, port) 84532633Ssam register struct mblok *mb; 84632633Ssam int port; 84732633Ssam { 84832633Ssam register struct mpport *mp; 84932633Ssam register struct mpevent *ev; 85032633Ssam register int i; 85134506Skarels u_char list[2]; 85232633Ssam int unit; 85332633Ssam 85432633Ssam mp = &mb->mb_port[port]; 85532633Ssam unit = mb->mb_unit; 85632633Ssam for (i = mp->mp_off; i != mp->mp_on; i = (i+1 % MPINSET)) { 85732633Ssam ev = &mp->mp_recvq[i]; 85832633Ssam ev->ev_error = ENXIO; 85932633Ssam ev->ev_status = EVSTATUS_DONE; 86032633Ssam } 86132633Ssam list[0] = port, list[1] = MPPORT_EOL; 86232633Ssam mpxintr(unit, list); 86332633Ssam mprintr(unit, list); 86432633Ssam /* Clear async for port */ 86532633Ssam mp->mp_proto = MPPROTO_UNUSED; 86632633Ssam mp->mp_flags = 0; 86732633Ssam mp->mp_on = 0; 86832633Ssam mp->mp_off = 0; 86932633Ssam mp->mp_nextrcv = 0; 87032633Ssam 87132633Ssam mp_tty[unit*MPCHUNK + port].t_state = 0; 87232633Ssam for (ev = &mp->mp_sendq[0]; ev < &mp->mp_sendq[MPOUTSET]; ev++) { 87332633Ssam ev->ev_status = EVSTATUS_FREE; 87432633Ssam ev->ev_cmd = 0; 87532633Ssam ev->ev_error = 0; 87632633Ssam ev->ev_un.rcvblk = 0; 87732633Ssam ev->ev_params = 0; 87832633Ssam } 87932633Ssam for (ev = &mp->mp_recvq[0]; ev < &mp->mp_recvq[MPINSET]; ev++) { 88032633Ssam ev->ev_status = EVSTATUS_FREE; 88132633Ssam ev->ev_cmd = 0; 88232633Ssam ev->ev_error = 0; 88332633Ssam ev->ev_params = 0; 88432633Ssam } 88532633Ssam } 88632633Ssam 88732633Ssam /* 88832633Ssam * MPCC interrupt handler. 88932633Ssam */ 89032633Ssam mpintr(mpcc) 89132633Ssam int mpcc; 89232633Ssam { 89332633Ssam register struct mblok *mb; 89432633Ssam register struct his *his; 89532633Ssam 89632633Ssam mb = mp_softc[mpcc].ms_mb; 89732633Ssam if (mb == 0) { 89832633Ssam printf("mp%d: stray interrupt\n", mpcc); 89932633Ssam return; 90032633Ssam } 90132633Ssam his = &mb->mb_hostint; 90232633Ssam his->semaphore &= ~MPSEMA_AVAILABLE; 90332633Ssam /* 90432633Ssam * Check for events to be processed. 90532633Ssam */ 90632633Ssam if (his->proto[MPPROTO_ASYNC].outbdone[0] != MPPORT_EOL) 90732633Ssam mprintr(mpcc, his->proto[MPPROTO_ASYNC].outbdone); 90832633Ssam if (his->proto[MPPROTO_ASYNC].inbdone[0] != MPPORT_EOL) 90932633Ssam mpxintr(mpcc, his->proto[MPPROTO_ASYNC].inbdone); 91032633Ssam if (mb->mb_harderr || mb->mb_softerr) 91132633Ssam mperror(mb, mpcc); 91232633Ssam his->semaphore |= MPSEMA_AVAILABLE; 91332633Ssam } 91432633Ssam 91532633Ssam /* 91632633Ssam * Handler for processing completion of transmitted events. 91732633Ssam */ 91832633Ssam mpxintr(unit, list) 91934506Skarels register u_char *list; 92032633Ssam { 92132633Ssam register struct mpport *mp; 92232633Ssam register struct mpevent *ev; 92332633Ssam register struct mblok *mb; 92432633Ssam register struct tty *tp; 92532633Ssam register struct asyncparam *ap; 92632633Ssam struct mpsoftc *ms; 92732633Ssam int port, i, j; 92835935Sbostic # define nextevent(mp) &mp->mp_recvq[mp->mp_off] 92932633Ssam 93032633Ssam ms = &mp_softc[unit]; 93132633Ssam mb = mp_softc[unit].ms_mb; 93232633Ssam for (j = 0; j < MPMAXPORT && ((port = *list++) != MPPORT_EOL); j++) { 93332633Ssam /* 93432633Ssam * Process each completed entry in the inbound queue. 93532633Ssam */ 93632633Ssam mp = &mb->mb_port[port]; 93732633Ssam tp = &mp_tty[unit*MPCHUNK + port]; 93832633Ssam ev = nextevent(mp); 93935935Sbostic for (; ev->ev_status & EVSTATUS_DONE; ev = nextevent(mp)) { 94032633Ssam /* YUCK */ 94132633Ssam ap = &ms->ms_async[port][mp->mp_off]; 94234506Skarels mppurge((caddr_t)ap, (int)sizeof (*ap)); 94332633Ssam switch (ev->ev_cmd) { 94432633Ssam case EVCMD_OPEN: 94532633Ssam /* 94632633Ssam * Open completion, start all reads and 94732633Ssam * assert modem status information. 94832633Ssam */ 94932633Ssam for (i = 0; i < MPOUTSET; i++) 95032633Ssam mp->mp_sendq[i].ev_status = EVSTATUS_GO; 95132633Ssam (*linesw[tp->t_line].l_modem) 95232633Ssam (tp, ap->ap_modem.mc_dcd == ASSERT); 95335935Sbostic mp_freein(ev); 95435935Sbostic adjptr(mp->mp_off, MPINSET); 95535935Sbostic mp->mp_proto = MPPROTO_ASYNC; /* XXX */ 95635935Sbostic wakeup((caddr_t)&tp->t_canq); 95732633Ssam break; 95832633Ssam case EVCMD_CLOSE: 95932633Ssam /* 96032633Ssam * Close completion, flush all pending 96132633Ssam * transmissions, free resources, and 96232633Ssam * cleanup mpcc port state. 96332633Ssam */ 96432633Ssam for (i = 0; i < MPOUTSET; i++) { 96532633Ssam mp->mp_sendq[i].ev_status = 96632633Ssam EVSTATUS_FREE; 96732633Ssam mp->mp_sendq[i].ev_un.rcvblk = 0; 96832633Ssam mp->mp_sendq[i].ev_params = 0; 96932633Ssam } 97035935Sbostic mp_freein(ev); 97135935Sbostic adjptr(mp->mp_off, MPINSET); 97235935Sbostic tp->t_state &= ~(TS_CARR_ON|TS_BUSY|TS_FLUSH); 97332633Ssam mp->mp_on = mp->mp_off = mp->mp_nextrcv = 0; 97432633Ssam mp->mp_flags &= ~MP_PROGRESS; 97532633Ssam mp->mp_proto = MPPROTO_UNUSED; 97635055Skarels wakeup((caddr_t)&tp->t_canq); 97735935Sbostic break; 97832633Ssam case EVCMD_IOCTL: 97935935Sbostic mp_freein(ev); 98035935Sbostic adjptr(mp->mp_off, MPINSET); 98135935Sbostic mp->mp_flags &= ~MP_IOCTL; 98235935Sbostic wakeup((caddr_t)&tp->t_canq); 98332633Ssam break; 98432633Ssam case EVCMD_WRITE: 98532633Ssam /* 98632633Ssam * Transmission completed, update tty 98732633Ssam * state and restart output. 98832633Ssam */ 98935935Sbostic if (ev->ev_opts != A_FLUSH) { 99035935Sbostic tp->t_state &= ~TS_BUSY; 99135935Sbostic if (tp->t_state & TS_FLUSH) 99235935Sbostic tp->t_state &= ~TS_FLUSH; 99335935Sbostic else { 99435935Sbostic register int cc = 0, n; 99535935Sbostic struct hxmtl *hxp; 99632633Ssam 99735935Sbostic hxp = &ms->ms_hxl[port]; 99835935Sbostic for (n=0;n < ev->ev_count; n++) 99935935Sbostic cc += hxp->size[n]; 100035935Sbostic ndflush(&tp->t_outq, cc); 100135935Sbostic } 100232633Ssam } 100332633Ssam switch (ev->ev_error) { 100432633Ssam case A_SIZERR: /*# error in xmt data size */ 100532633Ssam mplog(unit, port, A_XSIZE, 0); 100632633Ssam break; 100732633Ssam case A_NXBERR: /*# no more xmt evt buffers */ 100832633Ssam mplog(unit, port, A_NOXBUF, 0); 100932633Ssam break; 101032633Ssam } 101135935Sbostic mp_freein(ev); 101235935Sbostic adjptr(mp->mp_off, MPINSET); 101332633Ssam mpstart(tp); 101432633Ssam break; 101532633Ssam default: 101634506Skarels mplog(unit, port, A_INVCMD, (int)ev->ev_cmd); 101735935Sbostic mp_freein(ev); 101835935Sbostic adjptr(mp->mp_off, MPINSET); 101932633Ssam break; 102032633Ssam } 102132633Ssam } 102232633Ssam } 102335935Sbostic #undef nextevent 102432633Ssam } 102532633Ssam 102635935Sbostic mp_freein(ev) 102735935Sbostic register struct mpevent *ev; 102835935Sbostic { 102935935Sbostic /* re-init all values in this entry */ 103035935Sbostic ev->ev_cmd = 0; 103135935Sbostic ev->ev_opts = 0; 103235935Sbostic ev->ev_error = 0; 103335935Sbostic ev->ev_flags = 0; 103435935Sbostic ev->ev_count = 0; 103535935Sbostic /* show this entry is available for use */ 103635935Sbostic ev->ev_status = EVSTATUS_FREE; 103735935Sbostic } 103835935Sbostic 103932633Ssam /* 104032633Ssam * Handler for processing received events. 104132633Ssam */ 104232633Ssam mprintr(unit, list) 104334506Skarels u_char *list; 104432633Ssam { 104532633Ssam register struct tty *tp; 104632633Ssam register struct mpport *mp; 104732633Ssam register struct mpevent *ev; 104832633Ssam struct mblok *mb; 104932633Ssam register int cc; 105032633Ssam register char *cp; 105132633Ssam struct mpsoftc *ms; 105232633Ssam caddr_t ptr; 105332633Ssam char *rcverr; 105432633Ssam int port, i; 105532633Ssam 105632633Ssam ms = &mp_softc[unit]; 105732633Ssam mb = mp_softc[unit].ms_mb; 105832633Ssam for (i = 0; i < MPMAXPORT && (port = *list++) != MPPORT_EOL; i++) { 105932633Ssam tp = &mp_tty[unit*MPCHUNK + port]; 106032633Ssam mp = &mb->mb_port[port]; 106132633Ssam ev = &mp->mp_sendq[mp->mp_nextrcv]; 106232633Ssam while (ev->ev_status & EVSTATUS_DONE) { 106335935Sbostic switch(ev->ev_cmd) { 106435935Sbostic case EVCMD_STATUS: 106532633Ssam /* 106632633Ssam * Status change, look for carrier changes. 106732633Ssam */ 106835935Sbostic switch(ev->ev_opts) { 106935935Sbostic case DCDASRT: 107035935Sbostic (*linesw[tp->t_line].l_modem)(tp, 1); 107135935Sbostic wakeup((caddr_t)&tp->t_canq); 107235935Sbostic break; 107335935Sbostic case DCDDROP: 107435935Sbostic (*linesw[tp->t_line].l_modem)(tp, 0); 107535935Sbostic wakeup((caddr_t)&tp->t_canq); 107635935Sbostic break; 107735935Sbostic case NORBUF: 107835935Sbostic case NOEBUF: 107932633Ssam mplog(unit, port, 108035935Sbostic "out of receive events", 0); 108135935Sbostic break; 108235935Sbostic default: 108335935Sbostic mplog(unit, port, 108432633Ssam "unexpect status command", 108534506Skarels (int)ev->ev_opts); 108635935Sbostic break; 108735935Sbostic } 108835935Sbostic break; 108935935Sbostic case EVCMD_READ: 109032633Ssam /* 109135935Sbostic * Process received data. 109235935Sbostic */ 109335935Sbostic if ((tp->t_state & TS_ISOPEN) == 0) { 109435935Sbostic wakeup((caddr_t)&tp->t_rawq); 109535935Sbostic break; 109635935Sbostic } 109735935Sbostic if ((cc = ev->ev_count) == 0) 109835935Sbostic break; 109935935Sbostic cp = ms->ms_cbuf[port][mp->mp_nextrcv]; 110035935Sbostic mppurge(cp, CBSIZE); 110135935Sbostic while (cc-- > 0) { 110235935Sbostic /* 110335935Sbostic * A null character is inserted, 110435935Sbostic * potentially when a break or framing 110535935Sbostic * error occurs. If we're not in raw 110635935Sbostic * mode, substitute the interrupt 110735935Sbostic * character. 110835935Sbostic */ 1109*37607Smarc /*** XXX - FIXUP ***/ 111035935Sbostic if (*cp == 0 && 111135935Sbostic (ev->ev_error == BRKASRT || 111235935Sbostic ev->ev_error == FRAMERR)) 111335935Sbostic if ((tp->t_flags&RAW) == 0) 1114*37607Smarc ; 1115*37607Smarc /* XXX was break */ 111635935Sbostic (*linesw[tp->t_line].l_rint)(*cp++, tp); 111735935Sbostic } 111835935Sbostic /* setup for next read */ 111935935Sbostic ptr = (caddr_t)&mp_softc[unit].ms_cbuf[port][mp->mp_nextrcv][0]; 112035935Sbostic ev->ev_un.rcvblk = (u_char *)kvtophys(ptr); 112135935Sbostic ev->ev_params = (caddr_t) kvtophys(ptr); 112235935Sbostic switch(ev->ev_error) { 112335935Sbostic case RCVDTA: 112435935Sbostic /* Normal (good) rcv data do not 112535935Sbostic * report the following they are 112635935Sbostic * "normal" errors 112735935Sbostic */ 112835935Sbostic case FRAMERR: 112935935Sbostic /* frame error */ 113035935Sbostic case BRKASRT: 113135935Sbostic /* Break condition */ 113235935Sbostic case PARERR: 113335935Sbostic /* parity error */ 113435935Sbostic rcverr = (char *)0; 113535935Sbostic break; 113635935Sbostic case OVRNERR: 113735935Sbostic /* Overrun error */ 113835935Sbostic rcverr = "overrun error"; 113935935Sbostic break; 114035935Sbostic case OVFERR: 114135935Sbostic /* Overflow error */ 114235935Sbostic rcverr = "overflow error"; 114335935Sbostic break; 114435935Sbostic default: 114535935Sbostic rcverr = "undefined rcv error"; 114635935Sbostic break; 114735935Sbostic } 114835935Sbostic if (rcverr != (char *)0) 114935935Sbostic mplog(unit, port, rcverr, 115035935Sbostic (int)ev->ev_error); 115132633Ssam break; 115235935Sbostic default: 115335935Sbostic mplog(unit, port, "unexpected command", 115435935Sbostic (int)ev->ev_cmd); 115532633Ssam break; 115632633Ssam } 115732633Ssam ev->ev_cmd = 0; 115832633Ssam ev->ev_opts = 0; 115932633Ssam ev->ev_error = 0; 116032633Ssam ev->ev_flags = 0; 116135935Sbostic ev->ev_count = 0; 116232633Ssam ev->ev_status = EVSTATUS_GO; /* start next read */ 116332633Ssam adjptr(mp->mp_nextrcv, MPOUTSET); 116432633Ssam ev = &mp->mp_sendq[mp->mp_nextrcv]; 116532633Ssam } 116632633Ssam } 116732633Ssam } 116832633Ssam 116932633Ssam /* 117032633Ssam * Log an mpcc diagnostic. 117132633Ssam */ 117232633Ssam mplog(unit, port, cp, flags) 117332633Ssam char *cp; 117432633Ssam { 117532633Ssam 117632633Ssam if (flags) 117732633Ssam log(LOG_ERR, "mp%d: port%d, %s (%d)\n", 117832633Ssam unit, port, cp, flags); 117932633Ssam else 118032633Ssam log(LOG_ERR, "mp%d: port%d, %s\n", unit, port, cp); 118132633Ssam } 118232633Ssam 118332633Ssam int MPHOSTINT = 1; 118432633Ssam 118532633Ssam mptimeint(mb) 118632633Ssam register struct mblok *mb; 118732633Ssam { 118832633Ssam 118932633Ssam mb->mb_mpintcnt = 0; 119032633Ssam mb->mb_mpintclk = (caddr_t)0; 119132633Ssam *(u_short *)mpinfo[mb->mb_unit]->ui_addr = 2; 119232633Ssam } 119332633Ssam 119432633Ssam /* 119532633Ssam * Interupt mpcc 119632633Ssam */ 119732633Ssam mpintmpcc(mb, port) 119832633Ssam register struct mblok *mb; 119932633Ssam { 120032633Ssam 120132633Ssam mb->mb_intr[port] |= MPSEMA_WORK; 120232633Ssam if (++mb->mb_mpintcnt == MPHOSTINT) { 120332633Ssam mb->mb_mpintcnt = 0; 120432633Ssam *(u_short *)mpinfo[mb->mb_unit]->ui_addr = 2; 120532633Ssam if (mb->mb_mpintclk) { 120634506Skarels untimeout(mptimeint, (caddr_t)mb); 120732633Ssam mb->mb_mpintclk = 0; 120832633Ssam } 120932633Ssam } else { 121032633Ssam if (mb->mb_mpintclk == 0) { 121134506Skarels timeout(mptimeint, (caddr_t)mb, 4); 121232633Ssam mb->mb_mpintclk = (caddr_t)1; 121332633Ssam } 121432633Ssam } 121532633Ssam } 121632633Ssam 121732633Ssam static char *mpherrmsg[] = { 121832633Ssam "", 121932633Ssam "Bus error", /* MPBUSERR */ 122032633Ssam "Address error", /* ADDRERR */ 122132633Ssam "Undefined ecc interrupt", /* UNDECC */ 122232633Ssam "Undefined interrupt", /* UNDINT */ 122332633Ssam "Power failure occurred", /* PWRFL */ 122432633Ssam "Stray transmit done interrupt", /* NOXENTRY */ 122532633Ssam "Two fast timers on one port", /* TWOFTMRS */ 122632633Ssam "Interrupt queue full", /* INTQFULL */ 122732633Ssam "Interrupt queue ack error", /* INTQERR */ 122832633Ssam "Uncorrectable dma parity error", /* CBPERR */ 122932633Ssam "32 port ACAP failed power up", /* ACPDEAD */ 123032633Ssam }; 123132633Ssam #define NHERRS (sizeof (mpherrmsg) / sizeof (mpherrmsg[0])) 123232633Ssam 123332633Ssam mperror(mb, unit) 123432633Ssam register struct mblok *mb; 123532633Ssam int unit; 123632633Ssam { 123732633Ssam register char *cp; 123832633Ssam register int i; 123932633Ssam 124032633Ssam if (mb->mb_softerr) { 124132633Ssam switch (mb->mb_softerr) { 124232633Ssam case DMAPERR: /* dma parity error */ 124332633Ssam cp = "dma parity error"; 124432633Ssam break; 124532633Ssam case ECCERR: 124632633Ssam cp = "local memory ecc error"; 124732633Ssam break; 124832633Ssam default: 124932633Ssam cp = "unknown error"; 125032633Ssam break; 125132633Ssam } 125232633Ssam log(LOG_ERR, "mp%d: soft error, %s", unit, cp); 125332633Ssam mb->mb_softerr = 0; 125432633Ssam } 125532633Ssam if (mb->mb_harderr) { 125632633Ssam if (mb->mb_harderr < NHERRS) 125732633Ssam cp = mpherrmsg[mb->mb_harderr]; 125832633Ssam else 125932633Ssam cp = "unknown error"; 126032633Ssam log(LOG_ERR, "mp%d: hard error, %s", unit, cp); 126132633Ssam if (mb->mb_status == MP_OPOPEN) { 126232633Ssam for (i = 0; i < MPMAXPORT; i++) { 126332633Ssam mpcleanport(mb, i); 126432633Ssam mb->mb_proto[i] = MPPROTO_UNUSED; 126532633Ssam } 126632633Ssam } 126732633Ssam mb->mb_harderr = 0; 126832633Ssam mb->mb_status = 0; 126932633Ssam } 127032633Ssam } 127132633Ssam 127232633Ssam mppurge(addr, cc) 127332633Ssam register caddr_t addr; 127432633Ssam register int cc; 127532633Ssam { 127632633Ssam 127732633Ssam for (; cc >= 0; addr += NBPG, cc -= NBPG) 127832633Ssam mtpr(P1DC, addr); 127932633Ssam } 128032633Ssam 128132633Ssam /* 128232633Ssam * MPCC Download Pseudo-device. 128332633Ssam */ 128432633Ssam char mpdlbuf[MPDLBUFSIZE]; 128532633Ssam int mpdlbusy; /* interlock on download buffer */ 128632633Ssam int mpdlerr; 128732633Ssam 128832633Ssam mpdlopen(dev) 128932633Ssam dev_t dev; 129032633Ssam { 129132633Ssam int unit, mpu; 129232633Ssam struct vba_device *vi; 129332633Ssam 129432633Ssam unit = minor(dev); 129532633Ssam mpu = MPUNIT(unit); 129632633Ssam if (mpu >= NMP || (vi = mpinfo[mpu]) == 0 || vi->ui_alive == 0) 129732633Ssam return (ENODEV); 129832633Ssam return (0); 129932633Ssam } 130032633Ssam 130132633Ssam mpdlwrite(dev, uio) 130232633Ssam dev_t dev; 130332633Ssam struct uio *uio; 130432633Ssam { 130532633Ssam register struct mpsoftc *ms = &mp_softc[MPUNIT(minor(dev))]; 130632633Ssam register struct mpdl *dl; 130732633Ssam int error; 130832633Ssam 130932633Ssam if (ms->ms_mb == 0 || ms->ms_mb->mb_status != MP_DLOPEN) 131032633Ssam return (EFAULT); 131132633Ssam dl = &ms->ms_mb->mb_dl; 131232633Ssam dl->mpdl_count = uio->uio_iov->iov_len; 131334506Skarels dl->mpdl_data = (caddr_t) kvtophys(mpdlbuf); 131434506Skarels if (error = uiomove(mpdlbuf, (int)dl->mpdl_count, UIO_WRITE, uio)) 131532633Ssam return (error); 131632633Ssam uio->uio_resid -= dl->mpdl_count; /* set up return from write */ 131732633Ssam dl->mpdl_cmd = MPDLCMD_NORMAL; 131832633Ssam error = mpdlwait(dl); 131932633Ssam return (error); 132032633Ssam } 132132633Ssam 132232633Ssam mpdlclose(dev) 132332633Ssam dev_t dev; 132432633Ssam { 132532633Ssam register struct mblok *mb = mp_softc[MPUNIT(minor(dev))].ms_mb; 132632633Ssam 132732633Ssam if (mb == 0 || mb->mb_status != MP_DLDONE) { 132832633Ssam mpbogus.status = 0; 132932633Ssam if (mpbogus.mb == mpbogus.mbloks[MPUNIT(minor(dev))]) 133032633Ssam mpdlbusy--; 133132633Ssam return (EEXIST); 133232633Ssam } 133332633Ssam mb->mb_status = MP_OPOPEN; 133432633Ssam mpbogus.status = 0; 133532633Ssam /* set to dead, for board handshake */ 133632633Ssam mb->mb_hostint.imok = MPIMOK_DEAD; 133732633Ssam return (0); 133832633Ssam } 133932633Ssam 134032633Ssam int mpdltimeout(); 134132633Ssam 134234506Skarels /* ARGSUSED */ 134332633Ssam mpdlioctl(dev, cmd, data, flag) 134432633Ssam dev_t dev; 134532633Ssam caddr_t data; 134632633Ssam { 134732633Ssam register struct mblok *mb; 134832633Ssam register struct mpdl *dl; 134934506Skarels int unit, error, s, i; 135032633Ssam 135132633Ssam mb = mp_softc[unit=MPUNIT(minor(dev))].ms_mb; 135232633Ssam if (mb == 0) 135332633Ssam return (EEXIST); 135432633Ssam dl = &mb->mb_dl; 135532633Ssam error = 0; 135632633Ssam switch (cmd) { 135732633Ssam case MPIOPORTMAP: 135832633Ssam bcopy(data, (caddr_t)mb->mb_proto, sizeof (mb->mb_proto)); 135932633Ssam break; 136032633Ssam case MPIOHILO: 136132633Ssam bcopy(data, (caddr_t)&mb->mb_hiport, 2*(sizeof(mb->mb_hiport))); 136232633Ssam break; 136332633Ssam case MPIOENDDL: 136432633Ssam dl->mpdl_count = 0; 136532633Ssam dl->mpdl_data = 0; 136632633Ssam dl->mpdl_cmd = MPIOENDDL&IOCPARM_MASK; 136732633Ssam error = mpdlwait(dl); 136832633Ssam mpccinit(unit); 136932633Ssam mb->mb_status = MP_DLDONE; 137032633Ssam mpdlbusy--; 137132633Ssam break; 137232633Ssam case MPIOENDCODE: 137332633Ssam dl->mpdl_count = 0; 137432633Ssam dl->mpdl_data = 0; 137532633Ssam dl->mpdl_cmd = MPIOENDCODE&IOCPARM_MASK; 137632633Ssam error = mpdlwait(dl); 137732633Ssam break; 137832633Ssam case MPIOASYNCNF: 137932633Ssam bcopy(data, mpdlbuf, sizeof (struct abdcf)); 138034506Skarels dl->mpdl_data = (caddr_t) kvtophys(mpdlbuf); 138132633Ssam dl->mpdl_count = sizeof (struct abdcf); 138232633Ssam dl->mpdl_cmd = MPIOASYNCNF&IOCPARM_MASK; 138332633Ssam error = mpdlwait(dl); 138432633Ssam break; 138532633Ssam case MPIOSTARTDL: 138632633Ssam while (mpdlbusy) 138732633Ssam sleep((caddr_t)&mpdlbusy, PZERO+1); 138832633Ssam mpdlbusy++; 138932633Ssam /* initialize the downloading interface */ 139032633Ssam mpbogus.magic = MPMAGIC; 139132633Ssam mpbogus.mb = mpbogus.mbloks[unit]; 139232633Ssam mpbogus.status = 1; 139332633Ssam dl->mpdl_status = EVSTATUS_FREE; 139432633Ssam dl->mpdl_count = 0; 139532633Ssam dl->mpdl_cmd = 0; 139632633Ssam dl->mpdl_data = (char *) 0; 139732633Ssam mpdlerr = 0; 139832633Ssam mb->mb_magic = MPMAGIC; 139932633Ssam mb->mb_ivec = mp_softc[unit].ms_ivec+1; /* download vector */ 140032633Ssam mb->mb_status = MP_DLPEND; 140132633Ssam mb->mb_diagswitch[0] = 'A'; 140232633Ssam mb->mb_diagswitch[1] = 'P'; 140332633Ssam s = spl8(); 140432633Ssam *(u_short *)mpinfo[unit]->ui_addr = 2; 140534506Skarels timeout(mpdltimeout, (caddr_t)mb, 30*hz); 140632633Ssam sleep((caddr_t)&mb->mb_status, PZERO+1); 140732633Ssam splx(s); 140832633Ssam if (mb->mb_status == MP_DLOPEN) { 140934506Skarels untimeout(mpdltimeout, (caddr_t)mb); 141032633Ssam } else if (mb->mb_status == MP_DLTIME) { 141132633Ssam mpbogus.status = 0; 141232633Ssam error = ETIMEDOUT; 141332633Ssam } else { 141432633Ssam mpbogus.status = 0; 141532633Ssam error = ENXIO; 141632633Ssam log(LOG_ERR, "mp%d: start download: unknown status %x", 141732633Ssam unit, mb->mb_status); 141832633Ssam } 141934506Skarels bzero((caddr_t)mb->mb_port, sizeof (mb->mb_port)); 142032633Ssam break; 142132633Ssam case MPIORESETBOARD: 142232633Ssam s = spl8(); 142332633Ssam if (mb->mb_imokclk) 142432633Ssam mb->mb_imokclk = 0; 142532633Ssam *(u_short *)mpinfo[unit]->ui_addr = 0x100; 142632633Ssam if (mb->mb_status == MP_DLOPEN || mb->mb_status == MP_DLDONE) { 142732633Ssam mpdlerr = MP_DLERROR; 142832633Ssam dl->mpdl_status = EVSTATUS_FREE; 142932633Ssam wakeup((caddr_t)&dl->mpdl_status); 143032633Ssam mpbogus.status = 0; 143132633Ssam } 143232633Ssam for (i = 0; i < MPMAXPORT; i++) { 143332633Ssam if (mb->mb_harderr || mb->mb_softerr) 143432633Ssam mperror(mb, i); 143532633Ssam mpcleanport(mb, i); 143632633Ssam mb->mb_proto[i] = MPPROTO_UNUSED; 143732633Ssam } 143832633Ssam mb->mb_status = 0; 143932633Ssam splx(s); 144032633Ssam break; 144132633Ssam default: 144232633Ssam error = EINVAL; 144332633Ssam break; 144432633Ssam } 144532633Ssam return (error); 144632633Ssam } 144732633Ssam 144832633Ssam mpccinit(unit) 144932633Ssam int unit; 145032633Ssam { 145132633Ssam register struct mblok *mb = mp_softc[unit].ms_mb; 145232633Ssam register struct his *his; 145332633Ssam register int i, j; 145432633Ssam 145532633Ssam mb->mb_status = MP_DLDONE; 145632633Ssam mb->mb_ivec = mp_softc[unit].ms_ivec; 145732633Ssam mb->mb_magic = MPMAGIC; 145832633Ssam /* Init host interface structure */ 145932633Ssam his = &mb->mb_hostint; 146032633Ssam his->semaphore = MPSEMA_AVAILABLE; 146132633Ssam for (i = 0; i < NMPPROTO; i++) 146232633Ssam for (j = 0; j < MPMAXPORT; j++) { 146332633Ssam his->proto[i].inbdone[j] = MPPORT_EOL; 146432633Ssam his->proto[i].outbdone[j] = MPPORT_EOL; 146532633Ssam } 146632633Ssam mb->mb_unit = unit; 146732633Ssam } 146832633Ssam 146932633Ssam mpdlintr(mpcc) 147032633Ssam int mpcc; 147132633Ssam { 147232633Ssam register struct mblok *mb; 147332633Ssam register struct mpdl *dl; 147432633Ssam 147532633Ssam mb = mp_softc[mpcc].ms_mb; 147632633Ssam if (mb == 0) { 147732633Ssam printf("mp%d: stray download interrupt\n", mpcc); 147832633Ssam return; 147932633Ssam } 148032633Ssam dl = &mb->mb_dl; 148132633Ssam switch (mb->mb_status) { 148232633Ssam case MP_DLOPEN: 148332633Ssam if (dl->mpdl_status != EVSTATUS_DONE) 148432633Ssam mpdlerr = MP_DLERROR; 148532633Ssam dl->mpdl_status = EVSTATUS_FREE; 148632633Ssam wakeup((caddr_t)&dl->mpdl_status); 148732633Ssam return; 148832633Ssam case MP_DLPEND: 148932633Ssam mb->mb_status = MP_DLOPEN; 149034506Skarels wakeup((caddr_t)&mb->mb_status); 149132633Ssam /* fall thru... */ 149232633Ssam case MP_DLTIME: 149332633Ssam return; 149432633Ssam case MP_OPOPEN: 149532633Ssam if (mb->mb_imokclk) 149632633Ssam mb->mb_imokclk = 0; 149732633Ssam mb->mb_nointcnt = 0; /* reset no interrupt count */ 149832633Ssam mb->mb_hostint.imok = MPIMOK_DEAD; 149932633Ssam mb->mb_imokclk = (caddr_t)1; 150032633Ssam break; 150132633Ssam default: 150232633Ssam log(LOG_ERR, "mp%d: mpdlintr, status %x\n", 150332633Ssam mpcc, mb->mb_status); 150432633Ssam break; 150532633Ssam } 150632633Ssam } 150732633Ssam 150832633Ssam mpdltimeout(mp) 150932633Ssam struct mblok *mp; 151032633Ssam { 151132633Ssam 151232633Ssam mp->mb_status = MP_DLTIME; 151332633Ssam wakeup((caddr_t)&mp->mb_status); 151432633Ssam } 151532633Ssam 151632633Ssam /* 151732633Ssam * Wait for a transfer to complete or a timeout to occur. 151832633Ssam */ 151932633Ssam mpdlwait(dl) 152032633Ssam register struct mpdl *dl; 152132633Ssam { 152232633Ssam int s, error = 0; 152332633Ssam 152432633Ssam s = spl8(); 152532633Ssam dl->mpdl_status = EVSTATUS_GO; 152632633Ssam while (dl->mpdl_status != EVSTATUS_FREE) { 152732633Ssam sleep((caddr_t)&dl->mpdl_status, PZERO+1); 152832633Ssam if (mpdlerr == MP_DLERROR) 152932633Ssam error = EIO; 153032633Ssam } 153132633Ssam splx(s); 153232633Ssam return (error); 153332633Ssam } 153432633Ssam #endif 1535