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*37751Smckusick * @(#)mp.c 7.10 (Berkeley) 05/09/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 "user.h" 3332633Ssam #include "map.h" 3432633Ssam #include "buf.h" 3532633Ssam #include "conf.h" 3632633Ssam #include "file.h" 3732633Ssam #include "errno.h" 3832633Ssam #include "syslog.h" 3932633Ssam #include "vmmac.h" 4032633Ssam #include "kernel.h" 4132633Ssam #include "clist.h" 4232633Ssam 4337507Smckusick #include "machine/pte.h" 4437507Smckusick #include "machine/mtpr.h" 4534506Skarels 4632633Ssam #include "../tahoevba/vbavar.h" 4732633Ssam #include "../tahoevba/mpreg.h" 4832633Ssam 4932633Ssam #define MPCHUNK 16 5032633Ssam #define MPPORT(n) ((n) & 0xf) 5132633Ssam #define MPUNIT(n) ((n) >> 4) 5232633Ssam 5332633Ssam /* 5432633Ssam * Driver information for auto-configuration stuff. 5532633Ssam */ 5632633Ssam int mpprobe(), mpattach(), mpintr(); 5732633Ssam struct vba_device *mpinfo[NMP]; 5832633Ssam long mpstd[] = { 0 }; 5932633Ssam struct vba_driver mpdriver = 6032633Ssam { mpprobe, 0, mpattach, 0, mpstd, "mp", mpinfo }; 6132633Ssam 6232633Ssam int mpstart(); 6337607Smarc int mpparam(); 6437607Smarc struct mpevent *mpparam2(); 6532633Ssam struct mpevent *mp_getevent(); 6632633Ssam 6732633Ssam /* 6832633Ssam * The following structure is needed to deal with mpcc's convoluted 6932633Ssam * method for locating it's mblok structures (hold your stomach). 7032633Ssam * When an mpcc is reset at boot time it searches host memory 7132633Ssam * looking for a string that says ``ThIs Is MpCc''. The mpcc 7232633Ssam * then reads the structure to locate the pointer to it's mblok 7332633Ssam * structure (you can wretch now). 7432633Ssam */ 7532633Ssam struct mpbogus { 7632633Ssam char s[12]; /* `ThIs Is MpCc'' */ 7732633Ssam u_char status; 7832633Ssam u_char unused; 7932633Ssam u_short magic; 8032633Ssam struct mblok *mb; 8132633Ssam struct mblok *mbloks[NMP]; /* can support at most 16 mpcc's */ 8232633Ssam } mpbogus = { 'T','h','I','s',' ','I','s',' ','M','p','C','c' }; 8332633Ssam 8432633Ssam /* 8532633Ssam * Software state per unit. 8632633Ssam */ 8732633Ssam struct mpsoftc { 8832633Ssam u_int ms_ivec; /* interrupt vector */ 8932633Ssam u_int ms_softCAR; /* software carrier for async */ 9032633Ssam struct mblok *ms_mb; /* mpcc status area */ 9132633Ssam struct vb_buf ms_buf; /* vba resources for ms_mb */ 9232633Ssam struct hxmtl ms_hxl[MPMAXPORT];/* host transmit list */ 9332633Ssam struct asyncparam ms_async[MPMAXPORT][MPINSET];/* async structs */ 9432633Ssam char ms_cbuf[MPMAXPORT][MPOUTSET][CBSIZE];/* input character buffers */ 9532633Ssam } mp_softc[NMP]; 9632633Ssam 9737607Smarc struct speedtab 9837607Smarc mpspeedtab[] = { 9937607Smarc 9600, M9600, /* baud rate = 9600 */ 10037607Smarc 4800, M4800, /* baud rate = 4800 */ 10137607Smarc 2400, M2400, /* baud rate = 2400 */ 10237607Smarc 1800, M1800, /* baud rate = 1800 */ 10337607Smarc 1200, M1200, /* baud rate = 1200 */ 10437607Smarc 600, M600, /* baud rate = 600 */ 10537607Smarc 300, M300, /* baud rate = 300 */ 10637607Smarc 200, M200, /* baud rate = 200 */ 10737607Smarc 150, M150, /* baud rate = 150 */ 10837607Smarc 134, M134_5, /* baud rate = 134.5 */ 10937607Smarc 110, M110, /* baud rate = 110 */ 11037607Smarc 75, M75, /* baud rate = 75 */ 11137607Smarc 50, M50, /* baud rate = 50 */ 11237607Smarc 0, M0, /* baud rate = 0 */ 11337607Smarc 2000, M2000, /* baud rate = 2000 */ 11437607Smarc 3600, M3600, /* baud rate = 3600 */ 11537607Smarc 7200, M7200, /* baud rate = 7200 */ 11637607Smarc 19200, M19200, /* baud rate = 19,200 */ 11737607Smarc 24000, M24000, /* baud rate = 24,000 */ 11837607Smarc 28400, M28400, /* baud rate = 28,400 */ 11937607Smarc 37800, M37800, /* baud rate = 37,800 */ 12037607Smarc 40300, M40300, /* baud rate = 40,300 */ 12137607Smarc 48000, M48000, /* baud rate = 48,000 */ 12237607Smarc 52000, M52000, /* baud rate = 52,000 */ 12337607Smarc 56800, M56800, /* baud rate = 56,800 */ 12437607Smarc EXTA, MEXTA, /* baud rate = Ext A */ 12537607Smarc EXTB, MEXTB, /* baud rate = Ext B */ 12637607Smarc -1, -1, 12737607Smarc }; 12837607Smarc 12932633Ssam struct tty mp_tty[NMP*MPCHUNK]; 13032633Ssam #ifndef lint 13132633Ssam int nmp = NMP*MPCHUNK; 13232633Ssam #endif 13332633Ssam 13432633Ssam int ttrstrt(); 13532633Ssam 13632633Ssam mpprobe(reg, vi) 13732633Ssam caddr_t reg; 13832633Ssam struct vba_device *vi; 13932633Ssam { 14032633Ssam register int br, cvec; 14132633Ssam register struct mpsoftc *ms; 14232633Ssam 14332633Ssam #ifdef lint 14432633Ssam br = 0; cvec = br; br = cvec; 14532633Ssam mpintr(0); 14634506Skarels mpdlintr(0); 14732633Ssam #endif 14832633Ssam if (badaddr(reg, 2)) 14932633Ssam return (0); 15032633Ssam ms = &mp_softc[vi->ui_unit]; 15132633Ssam /* 15232633Ssam * Allocate page tables and mblok 15332633Ssam * structure (mblok in non-cached memory). 15432633Ssam */ 15532633Ssam if (vbainit(&ms->ms_buf, sizeof (struct mblok), VB_32BIT) == 0) { 15632633Ssam printf("mp%d: vbainit failed\n", vi->ui_unit); 15732633Ssam return (0); 15832633Ssam } 15932633Ssam ms->ms_mb = (struct mblok *)ms->ms_buf.vb_rawbuf; 16032633Ssam ms->ms_ivec = MPINTRBASE + 2*vi->ui_unit; /* XXX */ 16132633Ssam br = 0x14, cvec = ms->ms_ivec; /* XXX */ 16234287Skarels return (sizeof (*reg)); 16332633Ssam } 16432633Ssam 16532633Ssam mpattach(vi) 16632633Ssam register struct vba_device *vi; 16732633Ssam { 16832633Ssam register struct mpsoftc *ms = &mp_softc[vi->ui_unit]; 16932633Ssam 17032633Ssam ms->ms_softCAR = vi->ui_flags; 17132633Ssam /* 17232633Ssam * Setup pointer to mblok, initialize bogus 17332633Ssam * status block used by mpcc to locate the pointer 17432633Ssam * and then poke the mpcc to get it to search host 17532633Ssam * memory to find mblok pointer. 17632633Ssam */ 17732633Ssam mpbogus.mbloks[vi->ui_unit] = (struct mblok *)ms->ms_buf.vb_physbuf; 17832633Ssam *(short *)vi->ui_addr = 0x100; /* magic */ 17932633Ssam } 18032633Ssam 18132633Ssam /* 18232633Ssam * Open an mpcc port. 18332633Ssam */ 18434506Skarels /* ARGSUSED */ 18532633Ssam mpopen(dev, mode) 18632633Ssam dev_t dev; 18732633Ssam { 18832633Ssam register struct tty *tp; 18932633Ssam register struct mpsoftc *ms; 19032633Ssam int error, s, port, unit, mpu; 19132633Ssam struct vba_device *vi; 19232633Ssam struct mpport *mp; 19332633Ssam struct mpevent *ev; 19432633Ssam 19532633Ssam unit = minor(dev); 19632633Ssam mpu = MPUNIT(unit); 19732633Ssam if (mpu >= NMP || (vi = mpinfo[mpu]) == 0 || vi->ui_alive == 0) 19832633Ssam return (ENXIO); 19932633Ssam tp = &mp_tty[unit]; 20032633Ssam if (tp->t_state & TS_XCLUDE && u.u_uid != 0) 20132633Ssam return (EBUSY); 20232633Ssam ms = &mp_softc[mpu]; 20332633Ssam port = MPPORT(unit); 20432633Ssam if (ms->ms_mb->mb_proto[port] != MPPROTO_ASYNC || 20532633Ssam ms->ms_mb->mb_status != MP_OPOPEN) 20632633Ssam return (ENXIO); 20732633Ssam mp = &ms->ms_mb->mb_port[port]; /* host mpcc struct */ 20832633Ssam s = spl8(); 20935935Sbostic /* 21035935Sbostic * serialize open and close events 21135935Sbostic */ 21237607Smarc while ((mp->mp_flags & MP_PROGRESS) || ((tp->t_state & TS_WOPEN) && 21337607Smarc !(mode&O_NONBLOCK) && !(tp->t_cflag&CLOCAL))) 21432633Ssam sleep((caddr_t)&tp->t_canq, TTIPRI); 21535935Sbostic restart: 21632633Ssam tp->t_state |= TS_WOPEN; 21732633Ssam tp->t_addr = (caddr_t)ms; 21832633Ssam tp->t_oproc = mpstart; 21937607Smarc tp->t_param = mpparam; 22032633Ssam tp->t_dev = dev; 22134978Sbostic if ((tp->t_state & TS_ISOPEN) == 0) { 22234978Sbostic ttychars(tp); 22334978Sbostic if (tp->t_ispeed == 0) { 22437607Smarc tp->t_ispeed = TTYDEF_SPEED; 22537607Smarc tp->t_ospeed = TTYDEF_SPEED; 22637607Smarc tp->t_iflag = TTYDEF_IFLAG; 22737607Smarc tp->t_oflag = TTYDEF_OFLAG; 22837607Smarc tp->t_lflag = TTYDEF_LFLAG; 22937607Smarc tp->t_cflag = TTYDEF_CFLAG; 23034978Sbostic } 23134978Sbostic /* 23234978Sbostic * Initialize port state: init MPCC interface 23334978Sbostic * structures for port and setup modem control. 23434978Sbostic */ 23534978Sbostic error = mpportinit(ms, mp, port); 23634978Sbostic if (error) 23734978Sbostic goto bad; 23837607Smarc ev = mpparam2(tp, &tp->t_termios); 23934978Sbostic if (ev == 0) { 24034978Sbostic error = ENOBUFS; 24134978Sbostic goto bad; 24234978Sbostic } 24335935Sbostic mp->mp_flags |= MP_PROGRESS; 24434978Sbostic mpcmd(ev, EVCMD_OPEN, 0, ms->ms_mb, port); 24535935Sbostic /* 24635935Sbostic * wait for port to start 24735935Sbostic */ 24835935Sbostic while (mp->mp_proto != MPPROTO_ASYNC) 24935935Sbostic sleep((caddr_t)&tp->t_canq, TTIPRI); 25037607Smarc ttsetwater(tp); 25135935Sbostic mp->mp_flags &= ~MP_PROGRESS; 25232633Ssam } 25337607Smarc while (!(mode&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) && 25437607Smarc (tp->t_state & TS_CARR_ON) == 0) { 25532633Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 25635935Sbostic /* 25735935Sbostic * a mpclose() might have disabled port. if so restart 25835935Sbostic */ 25935935Sbostic if (mp->mp_proto != MPPROTO_ASYNC) 26035935Sbostic goto restart; 26135935Sbostic tp->t_state |= TS_WOPEN; 26235935Sbostic } 26332633Ssam error = (*linesw[tp->t_line].l_open)(dev,tp); 26432633Ssam done: 26532633Ssam splx(s); 26635935Sbostic /* 26735935Sbostic * wakeup those processes waiting for the open to complete 26835935Sbostic */ 26932633Ssam wakeup((caddr_t)&tp->t_canq); 27032633Ssam return (error); 27132633Ssam bad: 27232633Ssam tp->t_state &= ~TS_WOPEN; 27332633Ssam goto done; 27432633Ssam } 27532633Ssam 27632633Ssam /* 27732633Ssam * Close an mpcc port. 27832633Ssam */ 27934506Skarels /* ARGSUSED */ 28034506Skarels mpclose(dev, flag) 28132633Ssam dev_t dev; 28232633Ssam { 28332633Ssam register struct tty *tp; 28432633Ssam register struct mpport *mp; 28532633Ssam register struct mpevent *ev; 28632633Ssam int s, port, unit, error; 28732633Ssam struct mblok *mb; 28832633Ssam 28932633Ssam unit = minor(dev); 29032633Ssam tp = &mp_tty[unit]; 29132633Ssam port = MPPORT(unit); 29232633Ssam mb = mp_softc[MPUNIT(unit)].ms_mb; 29332633Ssam mp = &mb->mb_port[port]; 29432633Ssam s = spl8(); 29535935Sbostic if (mp->mp_flags & MP_PROGRESS) { 29632633Ssam if (mp->mp_flags & MP_REMBSY) { 29732633Ssam mp->mp_flags &= ~MP_REMBSY; 29832633Ssam splx(s); 29932633Ssam return (0); 30032633Ssam } 30132633Ssam while (mp->mp_flags & MP_PROGRESS) 30235935Sbostic sleep((caddr_t)&tp->t_canq, TTIPRI); 30332633Ssam } 30432633Ssam error = 0; 30532633Ssam mp->mp_flags |= MP_PROGRESS; 30632633Ssam (*linesw[tp->t_line].l_close)(tp); 30735935Sbostic ev = mp_getevent(mp, unit, 1); 30832633Ssam if (ev == 0) { 30934977Sbostic error = ENOBUFS; 31034977Sbostic mp->mp_flags &= ~MP_PROGRESS; 31134977Sbostic goto out; 31232633Ssam } 31334977Sbostic if (tp->t_state & TS_HUPCLS || (tp->t_state & TS_ISOPEN) == 0) 31434977Sbostic mpmodem(unit, MMOD_OFF); 31534977Sbostic else 31634977Sbostic mpmodem(unit, MMOD_ON); 31732633Ssam mpcmd(ev, EVCMD_CLOSE, 0, mb, port); 31834977Sbostic ttyclose(tp); 31932633Ssam out: 32032633Ssam if (mp->mp_flags & MP_REMBSY) 32132633Ssam mpclean(mb, port); 32235935Sbostic else 32335935Sbostic while (mp->mp_flags & MP_PROGRESS) 32435935Sbostic sleep((caddr_t)&tp->t_canq,TTIPRI); 32532633Ssam splx(s); 32632633Ssam return (error); 32732633Ssam } 32832633Ssam 32932633Ssam /* 33032633Ssam * Read from an mpcc port. 33132633Ssam */ 33237607Smarc mpread(dev, uio, flag) 33332633Ssam dev_t dev; 33432633Ssam struct uio *uio; 33532633Ssam { 33632633Ssam struct tty *tp; 33732633Ssam 33832633Ssam tp = &mp_tty[minor(dev)]; 33937607Smarc return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 34032633Ssam } 34132633Ssam 34232633Ssam /* 34332633Ssam * Write to an mpcc port. 34432633Ssam */ 34537607Smarc mpwrite(dev, uio, flag) 34632633Ssam dev_t dev; 34732633Ssam struct uio *uio; 34832633Ssam { 34932633Ssam struct tty *tp; 35032633Ssam 35132633Ssam tp = &mp_tty[minor(dev)]; 35237607Smarc return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 35332633Ssam } 35432633Ssam 35532633Ssam /* 35632633Ssam * Ioctl for a mpcc port 35732633Ssam */ 35832633Ssam mpioctl(dev, cmd, data, flag) 35932633Ssam dev_t dev; 36032633Ssam caddr_t data; 36132633Ssam { 36232633Ssam register struct tty *tp; 36332633Ssam register struct mpsoftc *ms; 36437607Smarc register struct mpport *mp; 36532633Ssam register struct mpevent *ev; 36632633Ssam int s, port, error, unit; 36732633Ssam struct mblok *mb; 36832633Ssam 36932633Ssam unit = minor(dev); 37032633Ssam tp = &mp_tty[unit]; 37132633Ssam ms = &mp_softc[MPUNIT(unit)]; 37232633Ssam mb = ms->ms_mb; 37335935Sbostic port = MPPORT(unit); 37435935Sbostic mp = &mb->mb_port[port]; 37535935Sbostic if (mp->mp_proto != MPPROTO_ASYNC) 37635935Sbostic return(ENXIO); 37732633Ssam error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 37832633Ssam if (error >= 0) 37932633Ssam return (error); 38032633Ssam error = ttioctl(tp, cmd, data, flag); 38137607Smarc if (error >= 0) 38232633Ssam return (error); 38332633Ssam switch (cmd) { 38432633Ssam case TIOCSBRK: /* send break */ 38532633Ssam case TIOCCBRK: /* clear break */ 38632633Ssam s = spl8(); 38735935Sbostic while (mp->mp_flags & MP_IOCTL) { 38835935Sbostic sleep((caddr_t)&tp->t_canq, TTIPRI); 38935935Sbostic if (mp->mp_proto != MPPROTO_ASYNC) { 39035935Sbostic mp->mp_flags &= ~MP_IOCTL; 39135935Sbostic splx(s); 39235935Sbostic return(ENXIO); 39335935Sbostic } 39435935Sbostic } 39535935Sbostic ev = mp_getevent(mp, unit, 0); 39635935Sbostic if (ev) { 39735935Sbostic mp->mp_flags |= MP_IOCTL; 39832633Ssam mpcmd(ev, EVCMD_IOCTL, 39935935Sbostic (cmd == TIOCSBRK ? A_BRKON : A_BRKOFF), mb, port); 40035935Sbostic } else 40132633Ssam error = ENOBUFS; 40232633Ssam splx(s); 40332633Ssam break; 40432633Ssam case TIOCSDTR: /* set dtr control line */ 40532633Ssam break; 40632633Ssam case TIOCCDTR: /* clear dtr control line */ 40732633Ssam break; 40832633Ssam default: 40932633Ssam error = ENOTTY; 41032633Ssam break; 41132633Ssam } 41232633Ssam return (error); 41332633Ssam } 41432633Ssam 41537607Smarc mpparam(tp, t) 41637607Smarc struct tty *tp; 41737607Smarc struct termios *t; 41837607Smarc { 41937607Smarc register struct mpevent *ev; 42037607Smarc int unit = minor(tp->t_dev); 42137607Smarc struct mpsoftc *ms = &mp_softc[MPUNIT(unit)]; 42237607Smarc struct mblok *mb = ms->ms_mb; 42337607Smarc 42437607Smarc ev = mpparam2(tp, t); 42537607Smarc if (ev == 0) 42637607Smarc return (ENOBUFS); 42737607Smarc mpcmd(ev, EVCMD_IOCTL, A_CHGALL, mb, MPPORT(unit)); 42837607Smarc return (0); 42937607Smarc } 43037607Smarc 43132633Ssam struct mpevent * 43237607Smarc mpparam2(tp, t) 43337607Smarc register struct tty *tp; 43437607Smarc struct termios *t; 43532633Ssam { 43632633Ssam register struct mpevent *ev; 43732633Ssam register struct mpport *mp; 43837607Smarc int unit = minor(tp->t_dev); 43932633Ssam struct mblok *mb; 44032633Ssam struct mpsoftc *ms; 44132633Ssam register struct asyncparam *asp; 44237607Smarc int port, speedcode; 44332633Ssam 44432633Ssam ms = &mp_softc[MPUNIT(unit)]; 44532633Ssam mb = ms->ms_mb; 44632633Ssam port = MPPORT(unit); 44732633Ssam mp = &mb->mb_port[port]; 44835935Sbostic ev = mp_getevent(mp, unit, 0); /* XXX */ 44937607Smarc speedcode = ttspeedtab(t->c_ospeed, mpspeedtab); 45037607Smarc if (ev == 0 || speedcode < 0) { 45137607Smarc printf("mp mpunit %d port %d param2 failed ev: %x speed %d, wanted %d\n", 45237607Smarc MPUNIT(unit), port, ev, speedcode, t->c_ospeed); 45337607Smarc return (0); /* XXX */ 45437607Smarc } 45532633Ssam /* YUCK */ 45632633Ssam asp = &ms->ms_async[port][mp->mp_on?mp->mp_on-1:MPINSET-1]; 45737607Smarc asp->ap_xon = t->c_cc[VSTART]; 45837607Smarc asp->ap_xoff = t->c_cc[VSTOP]; 45937607Smarc if (!(t->c_iflag&IXON) || (asp->ap_xon == _POSIX_VDISABLE) || 46037607Smarc (asp->ap_xoff == _POSIX_VDISABLE)) 46134796Sbostic asp->ap_xena = MPA_DIS; 46234796Sbostic else 46334796Sbostic asp->ap_xena = MPA_ENA; 46437607Smarc asp->ap_xany = ((t->c_iflag & IXANY) ? MPA_ENA : MPA_DIS); 46532633Ssam #ifdef notnow 46637607Smarc if (t->t_cflag&CSIZE) == CS8) { 46732633Ssam #endif 46832633Ssam asp->ap_data = MPCHAR_8; 46932633Ssam asp->ap_parity = MPPAR_NONE; 47032633Ssam #ifdef notnow 47132633Ssam } else { 47232633Ssam asp->ap_data = MPCHAR_7; 47337607Smarc if ((t->c_flags & (EVENP|ODDP)) == ODDP) /* XXX */ 47432633Ssam asp->ap_parity = MPPAR_ODD; 47532633Ssam else 47632633Ssam asp->ap_parity = MPPAR_EVEN; 47732633Ssam } 47832633Ssam #endif 47935935Sbostic asp->ap_loop = MPA_DIS; /* disable loopback */ 48035935Sbostic asp->ap_rtimer = A_RCVTIM; /* default receive timer */ 48137607Smarc if (t->c_ospeed == B110) 48232633Ssam asp->ap_stop = MPSTOP_2; 48332633Ssam else 48432633Ssam asp->ap_stop = MPSTOP_1; 48537607Smarc if (t->c_ospeed == 0) { 48635935Sbostic tp->t_state |= TS_HUPCLS; 48735935Sbostic setm(&asp->ap_modem, 0, DROP); 48835935Sbostic seti(&asp->ap_intena, A_DCD); 48935935Sbostic return (ev); 49035935Sbostic } 49137607Smarc if (t->c_ospeed == EXTA || t->c_ospeed == EXTB) 49232633Ssam asp->ap_baud = M19200; 49332633Ssam else 49437607Smarc asp->ap_baud = speedcode; 49537607Smarc if (1 || ms->ms_softCAR & (1<<port)) /* XXX HARDWIRE FOR NOW */ 49632633Ssam setm(&asp->ap_modem, A_DTR, ASSERT); 49732633Ssam else 49832633Ssam setm(&asp->ap_modem, A_DTR, AUTO); 49932633Ssam seti(&asp->ap_intena, A_DCD); 50037607Smarc return(ev); 50132633Ssam } 50232633Ssam 50332633Ssam mpstart(tp) 50432633Ssam register struct tty *tp; 50532633Ssam { 50632633Ssam register struct mpevent *ev; 50732633Ssam register struct mpport *mp; 50832633Ssam struct mblok *mb; 50932633Ssam struct mpsoftc *ms; 51032633Ssam int port, unit, xcnt, n, s, i; 51132633Ssam struct hxmtl *hxp; 51232633Ssam struct clist outq; 51332633Ssam 51432633Ssam s = spl8(); 51532633Ssam unit = minor(tp->t_dev); 51632633Ssam ms = &mp_softc[MPUNIT(unit)]; 51732633Ssam mb = ms->ms_mb; 51832633Ssam port = MPPORT(unit); 51932633Ssam mp = &mb->mb_port[port]; 52032633Ssam hxp = &ms->ms_hxl[port]; 52132633Ssam xcnt = 0; 52232633Ssam outq = tp->t_outq; 52332633Ssam for (i = 0; i < MPXMIT; i++) { 52432633Ssam if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 52532633Ssam break; 52637607Smarc if (outq.c_cc <= tp->t_lowat) { 52732633Ssam if (tp->t_state & TS_ASLEEP) { 52832633Ssam tp->t_state &= ~TS_ASLEEP; 52932633Ssam wakeup((caddr_t)&tp->t_outq); 53032633Ssam } 53132633Ssam if (tp->t_wsel) { 53232633Ssam selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 53332633Ssam tp->t_wsel = 0; 53432633Ssam tp->t_state &= ~TS_WCOLL; 53532633Ssam } 53632633Ssam } 53732633Ssam if (outq.c_cc == 0) 53832633Ssam break; 53932633Ssam /* 54032633Ssam * If we're not currently busy outputting, 54132633Ssam * and there is data to be output, set up 54232633Ssam * port transmit structure to send to mpcc. 54332633Ssam */ 54437607Smarc if (1) /* || tp->t_flags & (RAW|LITOUT)) XXX FIX */ 54532633Ssam n = ndqb(&outq, 0); 54632633Ssam else { 54732633Ssam n = ndqb(&outq, 0200); 54832633Ssam if (n == 0) { 54935935Sbostic if (xcnt > 0) 55035935Sbostic break; 55132633Ssam n = getc(&outq); 55232633Ssam timeout(ttrstrt, (caddr_t)tp, (n&0177)+6); 55332633Ssam tp->t_state |= TS_TIMEOUT; 55432633Ssam break; 55532633Ssam } 55632633Ssam } 55734506Skarels hxp->dblock[i] = (caddr_t)kvtophys(outq.c_cf); 55832633Ssam hxp->size[i] = n; 55932633Ssam xcnt++; /* count of xmts to send */ 56032633Ssam ndadvance(&outq, n); 56132633Ssam } 56232633Ssam /* 56332633Ssam * If data to send, poke mpcc. 56432633Ssam */ 56532633Ssam if (xcnt) { 56635935Sbostic ev = mp_getevent(mp, unit, 0); 56732633Ssam if (ev == 0) { 56832633Ssam tp->t_state &= ~(TS_BUSY|TS_TIMEOUT); 56932633Ssam } else { 57032633Ssam tp->t_state |= TS_BUSY; 57132633Ssam ev->ev_count = xcnt; 57232633Ssam mpcmd(ev, EVCMD_WRITE, 0, mb, MPPORT(unit)); 57332633Ssam } 57432633Ssam } 57532633Ssam splx(s); 57632633Ssam } 57732633Ssam 57832633Ssam /* 57932633Ssam * Advance cc bytes from q but don't free memory. 58032633Ssam */ 58132633Ssam ndadvance(q, cc) 58232633Ssam register struct clist *q; 58332633Ssam register cc; 58432633Ssam { 58532633Ssam register struct cblock *bp; 58632633Ssam char *end; 58732633Ssam int rem, s; 58832633Ssam 58932633Ssam s = spltty(); 59032633Ssam if (q->c_cc <= 0) 59132633Ssam goto out; 59232633Ssam while (cc>0 && q->c_cc) { 59332633Ssam bp = (struct cblock *)((int)q->c_cf & ~CROUND); 59432633Ssam if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) { 59532633Ssam end = q->c_cl; 59632633Ssam } else { 59732633Ssam end = (char *)((int)bp + sizeof (struct cblock)); 59832633Ssam } 59932633Ssam rem = end - q->c_cf; 60032633Ssam if (cc >= rem) { 60132633Ssam cc -= rem; 60232633Ssam q->c_cc -= rem; 60332633Ssam q->c_cf = bp->c_next->c_info; 60432633Ssam } else { 60532633Ssam q->c_cc -= cc; 60632633Ssam q->c_cf += cc; 60732633Ssam break; 60832633Ssam } 60932633Ssam } 61032633Ssam if (q->c_cc <= 0) { 61132633Ssam q->c_cf = q->c_cl = NULL; 61232633Ssam q->c_cc = 0; 61332633Ssam } 61432633Ssam out: 61532633Ssam splx(s); 61632633Ssam } 61732633Ssam 61832633Ssam /* 61932633Ssam * Stop output on a line, e.g. for ^S/^Q or output flush. 62032633Ssam */ 62134506Skarels /* ARGSUSED */ 62232633Ssam mpstop(tp, rw) 62332633Ssam register struct tty *tp; 62432633Ssam int rw; 62532633Ssam { 62635935Sbostic register struct mpport *mp; 62735935Sbostic register struct mpevent *ev; 62835935Sbostic int unit = minor(tp->t_dev); 62935935Sbostic int port; 63035935Sbostic struct mblok *mb; 63134506Skarels int s; 63232633Ssam 63332633Ssam s = spl8(); 63432633Ssam if (tp->t_state & TS_BUSY) { 63535935Sbostic if ((tp->t_state & TS_TTSTOP) == 0) { 63632633Ssam tp->t_state |= TS_FLUSH; 63735935Sbostic port = MPPORT(unit); 63835935Sbostic mb = mp_softc[MPUNIT(unit)].ms_mb; 63935935Sbostic mp = &mb->mb_port[port]; 64035935Sbostic ev = mp_getevent(mp, unit, 0); 64135935Sbostic if (ev == 0) { 64235935Sbostic splx(s); 64335935Sbostic return; 64435935Sbostic } 64535935Sbostic mpcmd(ev, EVCMD_WRITE, A_FLUSH, mb, port); 64635935Sbostic } 64732633Ssam } 64832633Ssam splx(s); 64932633Ssam } 65032633Ssam 65132633Ssam /* 65232633Ssam * Initialize an async port's MPCC state. 65332633Ssam */ 65432633Ssam mpportinit(ms, mp, port) 65532633Ssam register struct mpsoftc *ms; 65632633Ssam register struct mpport *mp; 65732633Ssam int port; 65832633Ssam { 65932633Ssam register struct mpevent *ev; 66032633Ssam register int i; 66132633Ssam caddr_t ptr; 66232633Ssam 66332633Ssam mp->mp_on = mp->mp_off = 0; 66432633Ssam mp->mp_nextrcv = 0; 66532633Ssam mp->mp_flags = 0; 66632633Ssam ev = &mp->mp_recvq[0]; 66732633Ssam for (i = 0; ev < &mp->mp_recvq[MPINSET]; ev++, i++) { 66832633Ssam ev->ev_status = EVSTATUS_FREE; 66932633Ssam ev->ev_cmd = 0; 67032633Ssam ev->ev_opts = 0; 67132633Ssam ev->ev_error = 0; 67232633Ssam ev->ev_flags = 0; 67332633Ssam ev->ev_count = 0; 67434506Skarels ev->ev_un.hxl = (struct hxmtl *) kvtophys(&ms->ms_hxl[port]); 67534506Skarels ev->ev_params = (caddr_t) kvtophys(&ms->ms_async[port][i]); 67632633Ssam } 67732633Ssam ev = &mp->mp_sendq[0]; 67832633Ssam for (i = 0; ev < &mp->mp_sendq[MPOUTSET]; ev++, i++) { 67932633Ssam /* init so that L2 can't send any events */ 68032633Ssam /* to host until open has completed */ 68132633Ssam ev->ev_status = EVSTATUS_FREE; 68232633Ssam ev->ev_cmd = 0; 68335935Sbostic ev->ev_opts = 0; 68432633Ssam ev->ev_error = 0; 68532633Ssam ev->ev_flags = 0; 68632633Ssam ev->ev_count = 0; 68732633Ssam ptr = (caddr_t) &ms->ms_cbuf[port][i][0]; 68834506Skarels ev->ev_un.rcvblk = (u_char *)kvtophys(ptr); 68934506Skarels ev->ev_params = (caddr_t) kvtophys(ptr); 69032633Ssam } 69132633Ssam return (0); 69232633Ssam } 69332633Ssam 69432633Ssam /* 69532633Ssam * Send an event to an mpcc. 69632633Ssam */ 69732633Ssam mpcmd(ev, cmd, flags, mb, port) 69832633Ssam register struct mpevent *ev; 69932633Ssam struct mblok *mb; 70032633Ssam { 70132633Ssam int s; 70232633Ssam 70332633Ssam s = spl8(); 70432633Ssam /* move host values to inbound entry */ 70532633Ssam ev->ev_cmd = cmd; 70632633Ssam ev->ev_opts = flags; 70732633Ssam /* show event ready for mpcc */ 70832633Ssam ev->ev_status = EVSTATUS_GO; 70932633Ssam mpintmpcc(mb, port); 71032633Ssam splx(s); 71132633Ssam } 71232633Ssam 71332633Ssam /* 71432633Ssam * Return the next available event entry for the indicated port. 71532633Ssam */ 71632633Ssam struct mpevent * 71735935Sbostic mp_getevent(mp, unit, cls_req) 71832633Ssam register struct mpport *mp; 71932633Ssam int unit; 72035935Sbostic int cls_req; 72132633Ssam { 72232633Ssam register struct mpevent *ev; 72332633Ssam int i, s; 72432633Ssam 72532633Ssam s = spl8(); 72632633Ssam ev = &mp->mp_recvq[mp->mp_on]; 72732633Ssam if (ev->ev_status != EVSTATUS_FREE) 72832633Ssam goto bad; 72932633Ssam /* 73032633Ssam * If not a close request, verify one extra 73132633Ssam * event is available for closing the port. 73232633Ssam */ 73335935Sbostic if (!cls_req) { 73432633Ssam if ((i = mp->mp_on + 1) >= MPINSET) 73532633Ssam i = 0; 73632633Ssam if (mp->mp_recvq[i].ev_status != EVSTATUS_FREE) 73732633Ssam goto bad; 73832633Ssam } 73932633Ssam /* init inbound fields marking this entry as busy */ 74035935Sbostic ev->ev_cmd = 0; 74135935Sbostic ev->ev_opts = 0; 74232633Ssam ev->ev_error = 0; 74332633Ssam ev->ev_flags = 0; 74432633Ssam ev->ev_count = 0; 74532633Ssam ev->ev_status = EVSTATUS_BUSY; 74632633Ssam /* adjust pointer to next available inbound entry */ 74732633Ssam adjptr(mp->mp_on, MPINSET); 74832633Ssam splx(s); 74932633Ssam return (ev); 75032633Ssam bad: 75132633Ssam splx(s); 75235935Sbostic log(LOG_ERR, "mp%d: port%d, out of events\n", 75335935Sbostic MPUNIT(unit), MPPORT(unit)); 75432633Ssam return ((struct mpevent *)0); 75532633Ssam } 75632633Ssam 75732633Ssam mpmodem(unit, flag) 75832633Ssam int unit, flag; 75932633Ssam { 76032633Ssam struct mpsoftc *ms = &mp_softc[MPUNIT(unit)]; 76132633Ssam int port = MPPORT(unit); 76232633Ssam register struct mpport *mp; 76332633Ssam register struct asyncparam *asp; 76432633Ssam 76532633Ssam mp = &ms->ms_mb->mb_port[port]; 76632633Ssam asp = &ms->ms_async[port][mp->mp_on?mp->mp_on-1:MPINSET-1]; 76732633Ssam if (flag == MMOD_ON) { 76837607Smarc if (1 || ms->ms_softCAR & (1 << port))/* XXX HARDWIRE FOR NOW */ 76932633Ssam setm(&asp->ap_modem, A_DTR, ASSERT); 77032633Ssam else 77132633Ssam setm(&asp->ap_modem, A_DTR, AUTO); 77232633Ssam seti(&asp->ap_intena, A_DCD); 77332633Ssam } else { 77432633Ssam setm(&asp->ap_modem, 0, DROP); 77532633Ssam seti(&asp->ap_intena, 0); 77632633Ssam } 77732633Ssam } 77832633Ssam 77932633Ssam /* 78032633Ssam * Set up the modem control structure according to mask. 78132633Ssam * Each set bit in the mask means assert the corresponding 78232633Ssam * modem control line, otherwise, it will be dropped. 78332633Ssam * RTS is special since it can either be asserted, dropped 78432633Ssam * or put in auto mode for auto modem control. 78532633Ssam */ 78632633Ssam static 78732633Ssam setm(mc, mask, rts) 78832633Ssam register struct mdmctl *mc; 78932633Ssam register int mask; 79032633Ssam { 79132633Ssam 79232633Ssam mc->mc_rngdsr = (mask & A_RNGDSR) ? ASSERT : DROP; 79332633Ssam mc->mc_rate = (mask & A_RATE) ? ASSERT : DROP; 79432633Ssam mc->mc_dcd = (mask & A_DCD) ? ASSERT : DROP; 79532633Ssam mc->mc_sectx = (mask & A_SECTX) ? ASSERT : DROP; 79632633Ssam mc->mc_cts = (mask & A_CTS) ? ASSERT : DROP; 79732633Ssam mc->mc_secrx = (mask & A_SECRX) ? ASSERT : DROP; 79832633Ssam mc->mc_dtr = (mask & A_DTR) ? ASSERT : DROP; 79932633Ssam mc->mc_rts = rts; 80032633Ssam } 80132633Ssam 80232633Ssam /* 80332633Ssam * Set up the status change enable field from mask. 80432633Ssam * When a signal is enabled in this structure and 80532633Ssam * and a change in state on a corresponding modem 80632633Ssam * control line occurs, a status change event will 80732633Ssam * be delivered to the host. 80832633Ssam */ 80932633Ssam static 81032633Ssam seti(mc, mask) 81132633Ssam register struct mdmctl *mc; 81232633Ssam register int mask; 81332633Ssam { 81432633Ssam 81532633Ssam mc->mc_rngdsr = (mask & A_RNGDSR) ? MDM_ON : MDM_OFF; 81632633Ssam mc->mc_rate = (mask & A_RATE) ? MDM_ON : MDM_OFF; 81732633Ssam mc->mc_dcd = (mask & A_DCD) ? MDM_ON : MDM_OFF; 81832633Ssam mc->mc_sectx = (mask & A_SECTX) ? MDM_ON : MDM_OFF; 81932633Ssam mc->mc_cts = (mask & A_CTS) ? MDM_ON : MDM_OFF; 82032633Ssam mc->mc_secrx = (mask & A_SECRX) ? MDM_ON : MDM_OFF; 82132633Ssam mc->mc_dtr = (mask & A_DTR) ? MDM_ON : MDM_OFF; 82232633Ssam mc->mc_rts = (mask & A_RTS) ? MDM_ON : MDM_OFF; 82332633Ssam } 82432633Ssam 82532633Ssam mpcleanport(mb, port) 82632633Ssam struct mblok *mb; 82732633Ssam int port; 82832633Ssam { 82932633Ssam register struct mpport *mp; 83032633Ssam register struct tty *tp; 83132633Ssam 83232633Ssam mp = &mb->mb_port[port]; 83332633Ssam if (mp->mp_proto == MPPROTO_ASYNC) { 83432633Ssam mp->mp_flags = MP_REMBSY; 83534506Skarels /* signal loss of carrier and close */ 83632633Ssam tp = &mp_tty[mb->mb_unit*MPCHUNK+port]; 83732633Ssam ttyflush(tp, FREAD|FWRITE); 83834506Skarels (void) (*linesw[tp->t_line].l_modem)(tp, 0); 83932633Ssam } 84032633Ssam } 84132633Ssam 84232633Ssam mpclean(mb, port) 84332633Ssam register struct mblok *mb; 84432633Ssam int port; 84532633Ssam { 84632633Ssam register struct mpport *mp; 84732633Ssam register struct mpevent *ev; 84832633Ssam register int i; 84934506Skarels u_char list[2]; 85032633Ssam int unit; 85132633Ssam 85232633Ssam mp = &mb->mb_port[port]; 85332633Ssam unit = mb->mb_unit; 85432633Ssam for (i = mp->mp_off; i != mp->mp_on; i = (i+1 % MPINSET)) { 85532633Ssam ev = &mp->mp_recvq[i]; 85632633Ssam ev->ev_error = ENXIO; 85732633Ssam ev->ev_status = EVSTATUS_DONE; 85832633Ssam } 85932633Ssam list[0] = port, list[1] = MPPORT_EOL; 86032633Ssam mpxintr(unit, list); 86132633Ssam mprintr(unit, list); 86232633Ssam /* Clear async for port */ 86332633Ssam mp->mp_proto = MPPROTO_UNUSED; 86432633Ssam mp->mp_flags = 0; 86532633Ssam mp->mp_on = 0; 86632633Ssam mp->mp_off = 0; 86732633Ssam mp->mp_nextrcv = 0; 86832633Ssam 86932633Ssam mp_tty[unit*MPCHUNK + port].t_state = 0; 87032633Ssam for (ev = &mp->mp_sendq[0]; ev < &mp->mp_sendq[MPOUTSET]; ev++) { 87132633Ssam ev->ev_status = EVSTATUS_FREE; 87232633Ssam ev->ev_cmd = 0; 87332633Ssam ev->ev_error = 0; 87432633Ssam ev->ev_un.rcvblk = 0; 87532633Ssam ev->ev_params = 0; 87632633Ssam } 87732633Ssam for (ev = &mp->mp_recvq[0]; ev < &mp->mp_recvq[MPINSET]; ev++) { 87832633Ssam ev->ev_status = EVSTATUS_FREE; 87932633Ssam ev->ev_cmd = 0; 88032633Ssam ev->ev_error = 0; 88132633Ssam ev->ev_params = 0; 88232633Ssam } 88332633Ssam } 88432633Ssam 88532633Ssam /* 88632633Ssam * MPCC interrupt handler. 88732633Ssam */ 88832633Ssam mpintr(mpcc) 88932633Ssam int mpcc; 89032633Ssam { 89132633Ssam register struct mblok *mb; 89232633Ssam register struct his *his; 89332633Ssam 89432633Ssam mb = mp_softc[mpcc].ms_mb; 89532633Ssam if (mb == 0) { 89632633Ssam printf("mp%d: stray interrupt\n", mpcc); 89732633Ssam return; 89832633Ssam } 89932633Ssam his = &mb->mb_hostint; 90032633Ssam his->semaphore &= ~MPSEMA_AVAILABLE; 90132633Ssam /* 90232633Ssam * Check for events to be processed. 90332633Ssam */ 90432633Ssam if (his->proto[MPPROTO_ASYNC].outbdone[0] != MPPORT_EOL) 90532633Ssam mprintr(mpcc, his->proto[MPPROTO_ASYNC].outbdone); 90632633Ssam if (his->proto[MPPROTO_ASYNC].inbdone[0] != MPPORT_EOL) 90732633Ssam mpxintr(mpcc, his->proto[MPPROTO_ASYNC].inbdone); 90832633Ssam if (mb->mb_harderr || mb->mb_softerr) 90932633Ssam mperror(mb, mpcc); 91032633Ssam his->semaphore |= MPSEMA_AVAILABLE; 91132633Ssam } 91232633Ssam 91332633Ssam /* 91432633Ssam * Handler for processing completion of transmitted events. 91532633Ssam */ 91632633Ssam mpxintr(unit, list) 91734506Skarels register u_char *list; 91832633Ssam { 91932633Ssam register struct mpport *mp; 92032633Ssam register struct mpevent *ev; 92132633Ssam register struct mblok *mb; 92232633Ssam register struct tty *tp; 92332633Ssam register struct asyncparam *ap; 92432633Ssam struct mpsoftc *ms; 92532633Ssam int port, i, j; 92635935Sbostic # define nextevent(mp) &mp->mp_recvq[mp->mp_off] 92732633Ssam 92832633Ssam ms = &mp_softc[unit]; 92932633Ssam mb = mp_softc[unit].ms_mb; 93032633Ssam for (j = 0; j < MPMAXPORT && ((port = *list++) != MPPORT_EOL); j++) { 93132633Ssam /* 93232633Ssam * Process each completed entry in the inbound queue. 93332633Ssam */ 93432633Ssam mp = &mb->mb_port[port]; 93532633Ssam tp = &mp_tty[unit*MPCHUNK + port]; 93632633Ssam ev = nextevent(mp); 93735935Sbostic for (; ev->ev_status & EVSTATUS_DONE; ev = nextevent(mp)) { 93832633Ssam /* YUCK */ 93932633Ssam ap = &ms->ms_async[port][mp->mp_off]; 94034506Skarels mppurge((caddr_t)ap, (int)sizeof (*ap)); 94132633Ssam switch (ev->ev_cmd) { 94232633Ssam case EVCMD_OPEN: 94332633Ssam /* 94432633Ssam * Open completion, start all reads and 94532633Ssam * assert modem status information. 94632633Ssam */ 94732633Ssam for (i = 0; i < MPOUTSET; i++) 94832633Ssam mp->mp_sendq[i].ev_status = EVSTATUS_GO; 94932633Ssam (*linesw[tp->t_line].l_modem) 95032633Ssam (tp, ap->ap_modem.mc_dcd == ASSERT); 95135935Sbostic mp_freein(ev); 95235935Sbostic adjptr(mp->mp_off, MPINSET); 95335935Sbostic mp->mp_proto = MPPROTO_ASYNC; /* XXX */ 95435935Sbostic wakeup((caddr_t)&tp->t_canq); 95532633Ssam break; 95632633Ssam case EVCMD_CLOSE: 95732633Ssam /* 95832633Ssam * Close completion, flush all pending 95932633Ssam * transmissions, free resources, and 96032633Ssam * cleanup mpcc port state. 96132633Ssam */ 96232633Ssam for (i = 0; i < MPOUTSET; i++) { 96332633Ssam mp->mp_sendq[i].ev_status = 96432633Ssam EVSTATUS_FREE; 96532633Ssam mp->mp_sendq[i].ev_un.rcvblk = 0; 96632633Ssam mp->mp_sendq[i].ev_params = 0; 96732633Ssam } 96835935Sbostic mp_freein(ev); 96935935Sbostic adjptr(mp->mp_off, MPINSET); 97035935Sbostic tp->t_state &= ~(TS_CARR_ON|TS_BUSY|TS_FLUSH); 97132633Ssam mp->mp_on = mp->mp_off = mp->mp_nextrcv = 0; 97232633Ssam mp->mp_flags &= ~MP_PROGRESS; 97332633Ssam mp->mp_proto = MPPROTO_UNUSED; 97435055Skarels wakeup((caddr_t)&tp->t_canq); 97535935Sbostic break; 97632633Ssam case EVCMD_IOCTL: 97735935Sbostic mp_freein(ev); 97835935Sbostic adjptr(mp->mp_off, MPINSET); 97935935Sbostic mp->mp_flags &= ~MP_IOCTL; 98035935Sbostic wakeup((caddr_t)&tp->t_canq); 98132633Ssam break; 98232633Ssam case EVCMD_WRITE: 98332633Ssam /* 98432633Ssam * Transmission completed, update tty 98532633Ssam * state and restart output. 98632633Ssam */ 98735935Sbostic if (ev->ev_opts != A_FLUSH) { 98835935Sbostic tp->t_state &= ~TS_BUSY; 98935935Sbostic if (tp->t_state & TS_FLUSH) 99035935Sbostic tp->t_state &= ~TS_FLUSH; 99135935Sbostic else { 99235935Sbostic register int cc = 0, n; 99335935Sbostic struct hxmtl *hxp; 99432633Ssam 99535935Sbostic hxp = &ms->ms_hxl[port]; 99635935Sbostic for (n=0;n < ev->ev_count; n++) 99735935Sbostic cc += hxp->size[n]; 99835935Sbostic ndflush(&tp->t_outq, cc); 99935935Sbostic } 100032633Ssam } 100132633Ssam switch (ev->ev_error) { 100232633Ssam case A_SIZERR: /*# error in xmt data size */ 100332633Ssam mplog(unit, port, A_XSIZE, 0); 100432633Ssam break; 100532633Ssam case A_NXBERR: /*# no more xmt evt buffers */ 100632633Ssam mplog(unit, port, A_NOXBUF, 0); 100732633Ssam break; 100832633Ssam } 100935935Sbostic mp_freein(ev); 101035935Sbostic adjptr(mp->mp_off, MPINSET); 101132633Ssam mpstart(tp); 101232633Ssam break; 101332633Ssam default: 101434506Skarels mplog(unit, port, A_INVCMD, (int)ev->ev_cmd); 101535935Sbostic mp_freein(ev); 101635935Sbostic adjptr(mp->mp_off, MPINSET); 101732633Ssam break; 101832633Ssam } 101932633Ssam } 102032633Ssam } 102135935Sbostic #undef nextevent 102232633Ssam } 102332633Ssam 102435935Sbostic mp_freein(ev) 102535935Sbostic register struct mpevent *ev; 102635935Sbostic { 102735935Sbostic /* re-init all values in this entry */ 102835935Sbostic ev->ev_cmd = 0; 102935935Sbostic ev->ev_opts = 0; 103035935Sbostic ev->ev_error = 0; 103135935Sbostic ev->ev_flags = 0; 103235935Sbostic ev->ev_count = 0; 103335935Sbostic /* show this entry is available for use */ 103435935Sbostic ev->ev_status = EVSTATUS_FREE; 103535935Sbostic } 103635935Sbostic 103732633Ssam /* 103832633Ssam * Handler for processing received events. 103932633Ssam */ 104032633Ssam mprintr(unit, list) 104134506Skarels u_char *list; 104232633Ssam { 104332633Ssam register struct tty *tp; 104432633Ssam register struct mpport *mp; 104532633Ssam register struct mpevent *ev; 104632633Ssam struct mblok *mb; 104732633Ssam register int cc; 104832633Ssam register char *cp; 104932633Ssam struct mpsoftc *ms; 105032633Ssam caddr_t ptr; 105132633Ssam char *rcverr; 105232633Ssam int port, i; 105332633Ssam 105432633Ssam ms = &mp_softc[unit]; 105532633Ssam mb = mp_softc[unit].ms_mb; 105632633Ssam for (i = 0; i < MPMAXPORT && (port = *list++) != MPPORT_EOL; i++) { 105732633Ssam tp = &mp_tty[unit*MPCHUNK + port]; 105832633Ssam mp = &mb->mb_port[port]; 105932633Ssam ev = &mp->mp_sendq[mp->mp_nextrcv]; 106032633Ssam while (ev->ev_status & EVSTATUS_DONE) { 106135935Sbostic switch(ev->ev_cmd) { 106235935Sbostic case EVCMD_STATUS: 106332633Ssam /* 106432633Ssam * Status change, look for carrier changes. 106532633Ssam */ 106635935Sbostic switch(ev->ev_opts) { 106735935Sbostic case DCDASRT: 106835935Sbostic (*linesw[tp->t_line].l_modem)(tp, 1); 106935935Sbostic wakeup((caddr_t)&tp->t_canq); 107035935Sbostic break; 107135935Sbostic case DCDDROP: 107235935Sbostic (*linesw[tp->t_line].l_modem)(tp, 0); 107335935Sbostic wakeup((caddr_t)&tp->t_canq); 107435935Sbostic break; 107535935Sbostic case NORBUF: 107635935Sbostic case NOEBUF: 107732633Ssam mplog(unit, port, 107835935Sbostic "out of receive events", 0); 107935935Sbostic break; 108035935Sbostic default: 108135935Sbostic mplog(unit, port, 108232633Ssam "unexpect status command", 108334506Skarels (int)ev->ev_opts); 108435935Sbostic break; 108535935Sbostic } 108635935Sbostic break; 108735935Sbostic case EVCMD_READ: 108832633Ssam /* 108935935Sbostic * Process received data. 109035935Sbostic */ 109135935Sbostic if ((tp->t_state & TS_ISOPEN) == 0) { 109235935Sbostic wakeup((caddr_t)&tp->t_rawq); 109335935Sbostic break; 109435935Sbostic } 109535935Sbostic if ((cc = ev->ev_count) == 0) 109635935Sbostic break; 109735935Sbostic cp = ms->ms_cbuf[port][mp->mp_nextrcv]; 109835935Sbostic mppurge(cp, CBSIZE); 109935935Sbostic while (cc-- > 0) { 110035935Sbostic /* 110135935Sbostic * A null character is inserted, 110235935Sbostic * potentially when a break or framing 110335935Sbostic * error occurs. If we're not in raw 110435935Sbostic * mode, substitute the interrupt 110535935Sbostic * character. 110635935Sbostic */ 110737607Smarc /*** XXX - FIXUP ***/ 110835935Sbostic if (*cp == 0 && 110935935Sbostic (ev->ev_error == BRKASRT || 111035935Sbostic ev->ev_error == FRAMERR)) 111135935Sbostic if ((tp->t_flags&RAW) == 0) 111237607Smarc ; 111337607Smarc /* XXX was break */ 111435935Sbostic (*linesw[tp->t_line].l_rint)(*cp++, tp); 111535935Sbostic } 111635935Sbostic /* setup for next read */ 111735935Sbostic ptr = (caddr_t)&mp_softc[unit].ms_cbuf[port][mp->mp_nextrcv][0]; 111835935Sbostic ev->ev_un.rcvblk = (u_char *)kvtophys(ptr); 111935935Sbostic ev->ev_params = (caddr_t) kvtophys(ptr); 112035935Sbostic switch(ev->ev_error) { 112135935Sbostic case RCVDTA: 112235935Sbostic /* Normal (good) rcv data do not 112335935Sbostic * report the following they are 112435935Sbostic * "normal" errors 112535935Sbostic */ 112635935Sbostic case FRAMERR: 112735935Sbostic /* frame error */ 112835935Sbostic case BRKASRT: 112935935Sbostic /* Break condition */ 113035935Sbostic case PARERR: 113135935Sbostic /* parity error */ 113235935Sbostic rcverr = (char *)0; 113335935Sbostic break; 113435935Sbostic case OVRNERR: 113535935Sbostic /* Overrun error */ 113635935Sbostic rcverr = "overrun error"; 113735935Sbostic break; 113835935Sbostic case OVFERR: 113935935Sbostic /* Overflow error */ 114035935Sbostic rcverr = "overflow error"; 114135935Sbostic break; 114235935Sbostic default: 114335935Sbostic rcverr = "undefined rcv error"; 114435935Sbostic break; 114535935Sbostic } 114635935Sbostic if (rcverr != (char *)0) 114735935Sbostic mplog(unit, port, rcverr, 114835935Sbostic (int)ev->ev_error); 114932633Ssam break; 115035935Sbostic default: 115135935Sbostic mplog(unit, port, "unexpected command", 115235935Sbostic (int)ev->ev_cmd); 115332633Ssam break; 115432633Ssam } 115532633Ssam ev->ev_cmd = 0; 115632633Ssam ev->ev_opts = 0; 115732633Ssam ev->ev_error = 0; 115832633Ssam ev->ev_flags = 0; 115935935Sbostic ev->ev_count = 0; 116032633Ssam ev->ev_status = EVSTATUS_GO; /* start next read */ 116132633Ssam adjptr(mp->mp_nextrcv, MPOUTSET); 116232633Ssam ev = &mp->mp_sendq[mp->mp_nextrcv]; 116332633Ssam } 116432633Ssam } 116532633Ssam } 116632633Ssam 116732633Ssam /* 116832633Ssam * Log an mpcc diagnostic. 116932633Ssam */ 117032633Ssam mplog(unit, port, cp, flags) 117132633Ssam char *cp; 117232633Ssam { 117332633Ssam 117432633Ssam if (flags) 117532633Ssam log(LOG_ERR, "mp%d: port%d, %s (%d)\n", 117632633Ssam unit, port, cp, flags); 117732633Ssam else 117832633Ssam log(LOG_ERR, "mp%d: port%d, %s\n", unit, port, cp); 117932633Ssam } 118032633Ssam 118132633Ssam int MPHOSTINT = 1; 118232633Ssam 118332633Ssam mptimeint(mb) 118432633Ssam register struct mblok *mb; 118532633Ssam { 118632633Ssam 118732633Ssam mb->mb_mpintcnt = 0; 118832633Ssam mb->mb_mpintclk = (caddr_t)0; 118932633Ssam *(u_short *)mpinfo[mb->mb_unit]->ui_addr = 2; 119032633Ssam } 119132633Ssam 119232633Ssam /* 119332633Ssam * Interupt mpcc 119432633Ssam */ 119532633Ssam mpintmpcc(mb, port) 119632633Ssam register struct mblok *mb; 119732633Ssam { 119832633Ssam 119932633Ssam mb->mb_intr[port] |= MPSEMA_WORK; 120032633Ssam if (++mb->mb_mpintcnt == MPHOSTINT) { 120132633Ssam mb->mb_mpintcnt = 0; 120232633Ssam *(u_short *)mpinfo[mb->mb_unit]->ui_addr = 2; 120332633Ssam if (mb->mb_mpintclk) { 120434506Skarels untimeout(mptimeint, (caddr_t)mb); 120532633Ssam mb->mb_mpintclk = 0; 120632633Ssam } 120732633Ssam } else { 120832633Ssam if (mb->mb_mpintclk == 0) { 120934506Skarels timeout(mptimeint, (caddr_t)mb, 4); 121032633Ssam mb->mb_mpintclk = (caddr_t)1; 121132633Ssam } 121232633Ssam } 121332633Ssam } 121432633Ssam 121532633Ssam static char *mpherrmsg[] = { 121632633Ssam "", 121732633Ssam "Bus error", /* MPBUSERR */ 121832633Ssam "Address error", /* ADDRERR */ 121932633Ssam "Undefined ecc interrupt", /* UNDECC */ 122032633Ssam "Undefined interrupt", /* UNDINT */ 122132633Ssam "Power failure occurred", /* PWRFL */ 122232633Ssam "Stray transmit done interrupt", /* NOXENTRY */ 122332633Ssam "Two fast timers on one port", /* TWOFTMRS */ 122432633Ssam "Interrupt queue full", /* INTQFULL */ 122532633Ssam "Interrupt queue ack error", /* INTQERR */ 122632633Ssam "Uncorrectable dma parity error", /* CBPERR */ 122732633Ssam "32 port ACAP failed power up", /* ACPDEAD */ 122832633Ssam }; 122932633Ssam #define NHERRS (sizeof (mpherrmsg) / sizeof (mpherrmsg[0])) 123032633Ssam 123132633Ssam mperror(mb, unit) 123232633Ssam register struct mblok *mb; 123332633Ssam int unit; 123432633Ssam { 123532633Ssam register char *cp; 123632633Ssam register int i; 123732633Ssam 123832633Ssam if (mb->mb_softerr) { 123932633Ssam switch (mb->mb_softerr) { 124032633Ssam case DMAPERR: /* dma parity error */ 124132633Ssam cp = "dma parity error"; 124232633Ssam break; 124332633Ssam case ECCERR: 124432633Ssam cp = "local memory ecc error"; 124532633Ssam break; 124632633Ssam default: 124732633Ssam cp = "unknown error"; 124832633Ssam break; 124932633Ssam } 125032633Ssam log(LOG_ERR, "mp%d: soft error, %s", unit, cp); 125132633Ssam mb->mb_softerr = 0; 125232633Ssam } 125332633Ssam if (mb->mb_harderr) { 125432633Ssam if (mb->mb_harderr < NHERRS) 125532633Ssam cp = mpherrmsg[mb->mb_harderr]; 125632633Ssam else 125732633Ssam cp = "unknown error"; 125832633Ssam log(LOG_ERR, "mp%d: hard error, %s", unit, cp); 125932633Ssam if (mb->mb_status == MP_OPOPEN) { 126032633Ssam for (i = 0; i < MPMAXPORT; i++) { 126132633Ssam mpcleanport(mb, i); 126232633Ssam mb->mb_proto[i] = MPPROTO_UNUSED; 126332633Ssam } 126432633Ssam } 126532633Ssam mb->mb_harderr = 0; 126632633Ssam mb->mb_status = 0; 126732633Ssam } 126832633Ssam } 126932633Ssam 127032633Ssam mppurge(addr, cc) 127132633Ssam register caddr_t addr; 127232633Ssam register int cc; 127332633Ssam { 127432633Ssam 127532633Ssam for (; cc >= 0; addr += NBPG, cc -= NBPG) 127632633Ssam mtpr(P1DC, addr); 127732633Ssam } 127832633Ssam 127932633Ssam /* 128032633Ssam * MPCC Download Pseudo-device. 128132633Ssam */ 128232633Ssam char mpdlbuf[MPDLBUFSIZE]; 128332633Ssam int mpdlbusy; /* interlock on download buffer */ 128432633Ssam int mpdlerr; 128532633Ssam 128632633Ssam mpdlopen(dev) 128732633Ssam dev_t dev; 128832633Ssam { 128932633Ssam int unit, mpu; 129032633Ssam struct vba_device *vi; 129132633Ssam 129232633Ssam unit = minor(dev); 129332633Ssam mpu = MPUNIT(unit); 129432633Ssam if (mpu >= NMP || (vi = mpinfo[mpu]) == 0 || vi->ui_alive == 0) 129532633Ssam return (ENODEV); 129632633Ssam return (0); 129732633Ssam } 129832633Ssam 129932633Ssam mpdlwrite(dev, uio) 130032633Ssam dev_t dev; 130132633Ssam struct uio *uio; 130232633Ssam { 130332633Ssam register struct mpsoftc *ms = &mp_softc[MPUNIT(minor(dev))]; 130432633Ssam register struct mpdl *dl; 130532633Ssam int error; 130632633Ssam 130732633Ssam if (ms->ms_mb == 0 || ms->ms_mb->mb_status != MP_DLOPEN) 130832633Ssam return (EFAULT); 130932633Ssam dl = &ms->ms_mb->mb_dl; 131032633Ssam dl->mpdl_count = uio->uio_iov->iov_len; 131134506Skarels dl->mpdl_data = (caddr_t) kvtophys(mpdlbuf); 1312*37751Smckusick if (error = uiomove(mpdlbuf, (int)dl->mpdl_count, uio)) 131332633Ssam return (error); 131432633Ssam uio->uio_resid -= dl->mpdl_count; /* set up return from write */ 131532633Ssam dl->mpdl_cmd = MPDLCMD_NORMAL; 131632633Ssam error = mpdlwait(dl); 131732633Ssam return (error); 131832633Ssam } 131932633Ssam 132032633Ssam mpdlclose(dev) 132132633Ssam dev_t dev; 132232633Ssam { 132332633Ssam register struct mblok *mb = mp_softc[MPUNIT(minor(dev))].ms_mb; 132432633Ssam 132532633Ssam if (mb == 0 || mb->mb_status != MP_DLDONE) { 132632633Ssam mpbogus.status = 0; 132732633Ssam if (mpbogus.mb == mpbogus.mbloks[MPUNIT(minor(dev))]) 132832633Ssam mpdlbusy--; 132932633Ssam return (EEXIST); 133032633Ssam } 133132633Ssam mb->mb_status = MP_OPOPEN; 133232633Ssam mpbogus.status = 0; 133332633Ssam /* set to dead, for board handshake */ 133432633Ssam mb->mb_hostint.imok = MPIMOK_DEAD; 133532633Ssam return (0); 133632633Ssam } 133732633Ssam 133832633Ssam int mpdltimeout(); 133932633Ssam 134034506Skarels /* ARGSUSED */ 134132633Ssam mpdlioctl(dev, cmd, data, flag) 134232633Ssam dev_t dev; 134332633Ssam caddr_t data; 134432633Ssam { 134532633Ssam register struct mblok *mb; 134632633Ssam register struct mpdl *dl; 134734506Skarels int unit, error, s, i; 134832633Ssam 134932633Ssam mb = mp_softc[unit=MPUNIT(minor(dev))].ms_mb; 135032633Ssam if (mb == 0) 135132633Ssam return (EEXIST); 135232633Ssam dl = &mb->mb_dl; 135332633Ssam error = 0; 135432633Ssam switch (cmd) { 135532633Ssam case MPIOPORTMAP: 135632633Ssam bcopy(data, (caddr_t)mb->mb_proto, sizeof (mb->mb_proto)); 135732633Ssam break; 135832633Ssam case MPIOHILO: 135932633Ssam bcopy(data, (caddr_t)&mb->mb_hiport, 2*(sizeof(mb->mb_hiport))); 136032633Ssam break; 136132633Ssam case MPIOENDDL: 136232633Ssam dl->mpdl_count = 0; 136332633Ssam dl->mpdl_data = 0; 136432633Ssam dl->mpdl_cmd = MPIOENDDL&IOCPARM_MASK; 136532633Ssam error = mpdlwait(dl); 136632633Ssam mpccinit(unit); 136732633Ssam mb->mb_status = MP_DLDONE; 136832633Ssam mpdlbusy--; 136932633Ssam break; 137032633Ssam case MPIOENDCODE: 137132633Ssam dl->mpdl_count = 0; 137232633Ssam dl->mpdl_data = 0; 137332633Ssam dl->mpdl_cmd = MPIOENDCODE&IOCPARM_MASK; 137432633Ssam error = mpdlwait(dl); 137532633Ssam break; 137632633Ssam case MPIOASYNCNF: 137732633Ssam bcopy(data, mpdlbuf, sizeof (struct abdcf)); 137834506Skarels dl->mpdl_data = (caddr_t) kvtophys(mpdlbuf); 137932633Ssam dl->mpdl_count = sizeof (struct abdcf); 138032633Ssam dl->mpdl_cmd = MPIOASYNCNF&IOCPARM_MASK; 138132633Ssam error = mpdlwait(dl); 138232633Ssam break; 138332633Ssam case MPIOSTARTDL: 138432633Ssam while (mpdlbusy) 138532633Ssam sleep((caddr_t)&mpdlbusy, PZERO+1); 138632633Ssam mpdlbusy++; 138732633Ssam /* initialize the downloading interface */ 138832633Ssam mpbogus.magic = MPMAGIC; 138932633Ssam mpbogus.mb = mpbogus.mbloks[unit]; 139032633Ssam mpbogus.status = 1; 139132633Ssam dl->mpdl_status = EVSTATUS_FREE; 139232633Ssam dl->mpdl_count = 0; 139332633Ssam dl->mpdl_cmd = 0; 139432633Ssam dl->mpdl_data = (char *) 0; 139532633Ssam mpdlerr = 0; 139632633Ssam mb->mb_magic = MPMAGIC; 139732633Ssam mb->mb_ivec = mp_softc[unit].ms_ivec+1; /* download vector */ 139832633Ssam mb->mb_status = MP_DLPEND; 139932633Ssam mb->mb_diagswitch[0] = 'A'; 140032633Ssam mb->mb_diagswitch[1] = 'P'; 140132633Ssam s = spl8(); 140232633Ssam *(u_short *)mpinfo[unit]->ui_addr = 2; 140334506Skarels timeout(mpdltimeout, (caddr_t)mb, 30*hz); 140432633Ssam sleep((caddr_t)&mb->mb_status, PZERO+1); 140532633Ssam splx(s); 140632633Ssam if (mb->mb_status == MP_DLOPEN) { 140734506Skarels untimeout(mpdltimeout, (caddr_t)mb); 140832633Ssam } else if (mb->mb_status == MP_DLTIME) { 140932633Ssam mpbogus.status = 0; 141032633Ssam error = ETIMEDOUT; 141132633Ssam } else { 141232633Ssam mpbogus.status = 0; 141332633Ssam error = ENXIO; 141432633Ssam log(LOG_ERR, "mp%d: start download: unknown status %x", 141532633Ssam unit, mb->mb_status); 141632633Ssam } 141734506Skarels bzero((caddr_t)mb->mb_port, sizeof (mb->mb_port)); 141832633Ssam break; 141932633Ssam case MPIORESETBOARD: 142032633Ssam s = spl8(); 142132633Ssam if (mb->mb_imokclk) 142232633Ssam mb->mb_imokclk = 0; 142332633Ssam *(u_short *)mpinfo[unit]->ui_addr = 0x100; 142432633Ssam if (mb->mb_status == MP_DLOPEN || mb->mb_status == MP_DLDONE) { 142532633Ssam mpdlerr = MP_DLERROR; 142632633Ssam dl->mpdl_status = EVSTATUS_FREE; 142732633Ssam wakeup((caddr_t)&dl->mpdl_status); 142832633Ssam mpbogus.status = 0; 142932633Ssam } 143032633Ssam for (i = 0; i < MPMAXPORT; i++) { 143132633Ssam if (mb->mb_harderr || mb->mb_softerr) 143232633Ssam mperror(mb, i); 143332633Ssam mpcleanport(mb, i); 143432633Ssam mb->mb_proto[i] = MPPROTO_UNUSED; 143532633Ssam } 143632633Ssam mb->mb_status = 0; 143732633Ssam splx(s); 143832633Ssam break; 143932633Ssam default: 144032633Ssam error = EINVAL; 144132633Ssam break; 144232633Ssam } 144332633Ssam return (error); 144432633Ssam } 144532633Ssam 144632633Ssam mpccinit(unit) 144732633Ssam int unit; 144832633Ssam { 144932633Ssam register struct mblok *mb = mp_softc[unit].ms_mb; 145032633Ssam register struct his *his; 145132633Ssam register int i, j; 145232633Ssam 145332633Ssam mb->mb_status = MP_DLDONE; 145432633Ssam mb->mb_ivec = mp_softc[unit].ms_ivec; 145532633Ssam mb->mb_magic = MPMAGIC; 145632633Ssam /* Init host interface structure */ 145732633Ssam his = &mb->mb_hostint; 145832633Ssam his->semaphore = MPSEMA_AVAILABLE; 145932633Ssam for (i = 0; i < NMPPROTO; i++) 146032633Ssam for (j = 0; j < MPMAXPORT; j++) { 146132633Ssam his->proto[i].inbdone[j] = MPPORT_EOL; 146232633Ssam his->proto[i].outbdone[j] = MPPORT_EOL; 146332633Ssam } 146432633Ssam mb->mb_unit = unit; 146532633Ssam } 146632633Ssam 146732633Ssam mpdlintr(mpcc) 146832633Ssam int mpcc; 146932633Ssam { 147032633Ssam register struct mblok *mb; 147132633Ssam register struct mpdl *dl; 147232633Ssam 147332633Ssam mb = mp_softc[mpcc].ms_mb; 147432633Ssam if (mb == 0) { 147532633Ssam printf("mp%d: stray download interrupt\n", mpcc); 147632633Ssam return; 147732633Ssam } 147832633Ssam dl = &mb->mb_dl; 147932633Ssam switch (mb->mb_status) { 148032633Ssam case MP_DLOPEN: 148132633Ssam if (dl->mpdl_status != EVSTATUS_DONE) 148232633Ssam mpdlerr = MP_DLERROR; 148332633Ssam dl->mpdl_status = EVSTATUS_FREE; 148432633Ssam wakeup((caddr_t)&dl->mpdl_status); 148532633Ssam return; 148632633Ssam case MP_DLPEND: 148732633Ssam mb->mb_status = MP_DLOPEN; 148834506Skarels wakeup((caddr_t)&mb->mb_status); 148932633Ssam /* fall thru... */ 149032633Ssam case MP_DLTIME: 149132633Ssam return; 149232633Ssam case MP_OPOPEN: 149332633Ssam if (mb->mb_imokclk) 149432633Ssam mb->mb_imokclk = 0; 149532633Ssam mb->mb_nointcnt = 0; /* reset no interrupt count */ 149632633Ssam mb->mb_hostint.imok = MPIMOK_DEAD; 149732633Ssam mb->mb_imokclk = (caddr_t)1; 149832633Ssam break; 149932633Ssam default: 150032633Ssam log(LOG_ERR, "mp%d: mpdlintr, status %x\n", 150132633Ssam mpcc, mb->mb_status); 150232633Ssam break; 150332633Ssam } 150432633Ssam } 150532633Ssam 150632633Ssam mpdltimeout(mp) 150732633Ssam struct mblok *mp; 150832633Ssam { 150932633Ssam 151032633Ssam mp->mb_status = MP_DLTIME; 151132633Ssam wakeup((caddr_t)&mp->mb_status); 151232633Ssam } 151332633Ssam 151432633Ssam /* 151532633Ssam * Wait for a transfer to complete or a timeout to occur. 151632633Ssam */ 151732633Ssam mpdlwait(dl) 151832633Ssam register struct mpdl *dl; 151932633Ssam { 152032633Ssam int s, error = 0; 152132633Ssam 152232633Ssam s = spl8(); 152332633Ssam dl->mpdl_status = EVSTATUS_GO; 152432633Ssam while (dl->mpdl_status != EVSTATUS_FREE) { 152532633Ssam sleep((caddr_t)&dl->mpdl_status, PZERO+1); 152632633Ssam if (mpdlerr == MP_DLERROR) 152732633Ssam error = EIO; 152832633Ssam } 152932633Ssam splx(s); 153032633Ssam return (error); 153132633Ssam } 153232633Ssam #endif 1533