📄 mp.c
字号:
return (ev); } if (t->c_ospeed == EXTA || t->c_ospeed == EXTB) asp->ap_baud = M19200; else asp->ap_baud = speedcode; if (1 || ms->ms_softCAR & (1<<port)) /* XXX HARDWIRE FOR NOW */ setm(&asp->ap_modem, A_DTR, ASSERT); else setm(&asp->ap_modem, A_DTR, AUTO); seti(&asp->ap_intena, A_DCD); return(ev);}mpstart(tp) register struct tty *tp;{ register struct mpevent *ev; register struct mpport *mp; struct mblok *mb; struct mpsoftc *ms; int port, unit, xcnt, n, s, i; struct hxmtl *hxp; struct clist outq; s = spl8(); unit = minor(tp->t_dev); ms = &mp_softc[MPUNIT(unit)]; mb = ms->ms_mb; port = MPPORT(unit); mp = &mb->mb_port[port]; hxp = &ms->ms_hxl[port]; xcnt = 0; outq = tp->t_outq; for (i = 0; i < MPXMIT; i++) { if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) break; if (outq.c_cc <= tp->t_lowat) { if (tp->t_state & TS_ASLEEP) { tp->t_state &= ~TS_ASLEEP; wakeup((caddr_t)&tp->t_outq); } if (tp->t_wsel) { selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); tp->t_wsel = 0; tp->t_state &= ~TS_WCOLL; } } if (outq.c_cc == 0) break; /* * If we're not currently busy outputting, * and there is data to be output, set up * port transmit structure to send to mpcc. */ if (1) /* || tp->t_flags & (RAW|LITOUT)) XXX FIX */ n = ndqb(&outq, 0); else { n = ndqb(&outq, 0200); if (n == 0) { if (xcnt > 0) break; n = getc(&outq); timeout(ttrstrt, (caddr_t)tp, (n&0177)+6); tp->t_state |= TS_TIMEOUT; break; } } hxp->dblock[i] = (caddr_t)kvtophys(outq.c_cf); hxp->size[i] = n; xcnt++; /* count of xmts to send */ ndadvance(&outq, n); } /* * If data to send, poke mpcc. */ if (xcnt) { ev = mp_getevent(mp, unit, 0); if (ev == 0) { tp->t_state &= ~(TS_BUSY|TS_TIMEOUT); } else { tp->t_state |= TS_BUSY; ev->ev_count = xcnt; mpcmd(ev, EVCMD_WRITE, 0, mb, MPPORT(unit)); } } splx(s);}/* * Advance cc bytes from q but don't free memory. */ndadvance(q, cc) register struct clist *q; register cc;{ register struct cblock *bp; char *end; int rem, s; s = spltty(); if (q->c_cc <= 0) goto out; while (cc>0 && q->c_cc) { bp = (struct cblock *)((int)q->c_cf & ~CROUND); if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) { end = q->c_cl; } else { end = (char *)((int)bp + sizeof (struct cblock)); } rem = end - q->c_cf; if (cc >= rem) { cc -= rem; q->c_cc -= rem; q->c_cf = bp->c_next->c_info; } else { q->c_cc -= cc; q->c_cf += cc; break; } } if (q->c_cc <= 0) { q->c_cf = q->c_cl = NULL; q->c_cc = 0; }out: splx(s);}/* * Stop output on a line, e.g. for ^S/^Q or output flush. *//* ARGSUSED */mpstop(tp, rw) register struct tty *tp; int rw;{ register struct mpport *mp; register struct mpevent *ev; int unit = minor(tp->t_dev); int port; struct mblok *mb; int s; s = spl8(); if (tp->t_state & TS_BUSY) { if ((tp->t_state & TS_TTSTOP) == 0) { tp->t_state |= TS_FLUSH; port = MPPORT(unit); mb = mp_softc[MPUNIT(unit)].ms_mb; mp = &mb->mb_port[port]; ev = mp_getevent(mp, unit, 0); if (ev == 0) { splx(s); return; } mpcmd(ev, EVCMD_WRITE, A_FLUSH, mb, port); } } splx(s);}/* * Initialize an async port's MPCC state. */mpportinit(ms, mp, port) register struct mpsoftc *ms; register struct mpport *mp; int port;{ register struct mpevent *ev; register int i; caddr_t ptr; mp->mp_on = mp->mp_off = 0; mp->mp_nextrcv = 0; mp->mp_flags = 0; ev = &mp->mp_recvq[0]; for (i = 0; ev < &mp->mp_recvq[MPINSET]; ev++, i++) { ev->ev_status = EVSTATUS_FREE; ev->ev_cmd = 0; ev->ev_opts = 0; ev->ev_error = 0; ev->ev_flags = 0; ev->ev_count = 0; ev->ev_un.hxl = (struct hxmtl *) kvtophys(&ms->ms_hxl[port]); ev->ev_params = (caddr_t) kvtophys(&ms->ms_async[port][i]); } ev = &mp->mp_sendq[0]; for (i = 0; ev < &mp->mp_sendq[MPOUTSET]; ev++, i++) { /* init so that L2 can't send any events */ /* to host until open has completed */ ev->ev_status = EVSTATUS_FREE; ev->ev_cmd = 0; ev->ev_opts = 0; ev->ev_error = 0; ev->ev_flags = 0; ev->ev_count = 0; ptr = (caddr_t) &ms->ms_cbuf[port][i][0]; ev->ev_un.rcvblk = (u_char *)kvtophys(ptr); ev->ev_params = (caddr_t) kvtophys(ptr); } return (0);}/* * Send an event to an mpcc. */mpcmd(ev, cmd, flags, mb, port) register struct mpevent *ev; struct mblok *mb;{ int s; s = spl8(); /* move host values to inbound entry */ ev->ev_cmd = cmd; ev->ev_opts = flags; /* show event ready for mpcc */ ev->ev_status = EVSTATUS_GO; mpintmpcc(mb, port); splx(s);}/* * Return the next available event entry for the indicated port. */struct mpevent *mp_getevent(mp, unit, cls_req) register struct mpport *mp; int unit; int cls_req;{ register struct mpevent *ev; int i, s; s = spl8(); ev = &mp->mp_recvq[mp->mp_on]; if (ev->ev_status != EVSTATUS_FREE) goto bad; /* * If not a close request, verify one extra * event is available for closing the port. */ if (!cls_req) { if ((i = mp->mp_on + 1) >= MPINSET) i = 0; if (mp->mp_recvq[i].ev_status != EVSTATUS_FREE) goto bad; } /* init inbound fields marking this entry as busy */ ev->ev_cmd = 0; ev->ev_opts = 0; ev->ev_error = 0; ev->ev_flags = 0; ev->ev_count = 0; ev->ev_status = EVSTATUS_BUSY; /* adjust pointer to next available inbound entry */ adjptr(mp->mp_on, MPINSET); splx(s); return (ev);bad: splx(s); log(LOG_ERR, "mp%d: port%d, out of events\n", MPUNIT(unit), MPPORT(unit)); return ((struct mpevent *)0);}mpmodem(unit, flag) int unit, flag;{ struct mpsoftc *ms = &mp_softc[MPUNIT(unit)]; int port = MPPORT(unit); register struct mpport *mp; register struct asyncparam *asp; mp = &ms->ms_mb->mb_port[port]; asp = &ms->ms_async[port][mp->mp_on?mp->mp_on-1:MPINSET-1]; if (flag == MMOD_ON) { if (1 || ms->ms_softCAR & (1 << port))/* XXX HARDWIRE FOR NOW */ setm(&asp->ap_modem, A_DTR, ASSERT); else setm(&asp->ap_modem, A_DTR, AUTO); seti(&asp->ap_intena, A_DCD); } else { setm(&asp->ap_modem, 0, DROP); seti(&asp->ap_intena, 0); }}/* * Set up the modem control structure according to mask. * Each set bit in the mask means assert the corresponding * modem control line, otherwise, it will be dropped. * RTS is special since it can either be asserted, dropped * or put in auto mode for auto modem control. */staticsetm(mc, mask, rts) register struct mdmctl *mc; register int mask;{ mc->mc_rngdsr = (mask & A_RNGDSR) ? ASSERT : DROP; mc->mc_rate = (mask & A_RATE) ? ASSERT : DROP; mc->mc_dcd = (mask & A_DCD) ? ASSERT : DROP; mc->mc_sectx = (mask & A_SECTX) ? ASSERT : DROP; mc->mc_cts = (mask & A_CTS) ? ASSERT : DROP; mc->mc_secrx = (mask & A_SECRX) ? ASSERT : DROP; mc->mc_dtr = (mask & A_DTR) ? ASSERT : DROP; mc->mc_rts = rts;}/* * Set up the status change enable field from mask. * When a signal is enabled in this structure and * and a change in state on a corresponding modem * control line occurs, a status change event will * be delivered to the host. */staticseti(mc, mask) register struct mdmctl *mc; register int mask;{ mc->mc_rngdsr = (mask & A_RNGDSR) ? MDM_ON : MDM_OFF; mc->mc_rate = (mask & A_RATE) ? MDM_ON : MDM_OFF; mc->mc_dcd = (mask & A_DCD) ? MDM_ON : MDM_OFF; mc->mc_sectx = (mask & A_SECTX) ? MDM_ON : MDM_OFF; mc->mc_cts = (mask & A_CTS) ? MDM_ON : MDM_OFF; mc->mc_secrx = (mask & A_SECRX) ? MDM_ON : MDM_OFF; mc->mc_dtr = (mask & A_DTR) ? MDM_ON : MDM_OFF; mc->mc_rts = (mask & A_RTS) ? MDM_ON : MDM_OFF;}mpcleanport(mb, port) struct mblok *mb; int port;{ register struct mpport *mp; register struct tty *tp; mp = &mb->mb_port[port]; if (mp->mp_proto == MPPROTO_ASYNC) { mp->mp_flags = MP_REMBSY; /* signal loss of carrier and close */ tp = &mp_tty[mb->mb_unit*MPCHUNK+port]; ttyflush(tp, FREAD|FWRITE); (void) (*linesw[tp->t_line].l_modem)(tp, 0); }}mpclean(mb, port) register struct mblok *mb; int port;{ register struct mpport *mp; register struct mpevent *ev; register int i; u_char list[2]; int unit; mp = &mb->mb_port[port]; unit = mb->mb_unit; for (i = mp->mp_off; i != mp->mp_on; i = (i+1 % MPINSET)) { ev = &mp->mp_recvq[i]; ev->ev_error = ENXIO; ev->ev_status = EVSTATUS_DONE; } list[0] = port, list[1] = MPPORT_EOL; mpxintr(unit, list); mprintr(unit, list); /* Clear async for port */ mp->mp_proto = MPPROTO_UNUSED; mp->mp_flags = 0; mp->mp_on = 0; mp->mp_off = 0; mp->mp_nextrcv = 0; mp_tty[unit*MPCHUNK + port].t_state = 0; for (ev = &mp->mp_sendq[0]; ev < &mp->mp_sendq[MPOUTSET]; ev++) { ev->ev_status = EVSTATUS_FREE; ev->ev_cmd = 0; ev->ev_error = 0; ev->ev_un.rcvblk = 0; ev->ev_params = 0; } for (ev = &mp->mp_recvq[0]; ev < &mp->mp_recvq[MPINSET]; ev++) { ev->ev_status = EVSTATUS_FREE; ev->ev_cmd = 0; ev->ev_error = 0; ev->ev_params = 0; }}/* * MPCC interrupt handler. */mpintr(mpcc) int mpcc;{ register struct mblok *mb; register struct his *his; mb = mp_softc[mpcc].ms_mb; if (mb == 0) { printf("mp%d: stray interrupt\n", mpcc); return; } his = &mb->mb_hostint; his->semaphore &= ~MPSEMA_AVAILABLE; /* * Check for events to be processed. */ if (his->proto[MPPROTO_ASYNC].outbdone[0] != MPPORT_EOL) mprintr(mpcc, his->proto[MPPROTO_ASYNC].outbdone); if (his->proto[MPPROTO_ASYNC].inbdone[0] != MPPORT_EOL) mpxintr(mpcc, his->proto[MPPROTO_ASYNC].inbdone); if (mb->mb_harderr || mb->mb_softerr) mperror(mb, mpcc); his->semaphore |= MPSEMA_AVAILABLE;}/* * Handler for processing completion of transmitted events. */mpxintr(unit, list) register u_char *list;{ register struct mpport *mp; register struct mpevent *ev; register struct mblok *mb; register struct tty *tp; register struct asyncparam *ap; struct mpsoftc *ms; int port, i, j;# define nextevent(mp) &mp->mp_recvq[mp->mp_off] ms = &mp_softc[unit]; mb = mp_softc[unit].ms_mb; for (j = 0; j < MPMAXPORT && ((port = *list++) != MPPORT_EOL); j++) { /* * Process each completed entry in the inbound queue. */ mp = &mb->mb_port[port]; tp = &mp_tty[unit*MPCHUNK + port]; ev = nextevent(mp); for (; ev->ev_status & EVSTATUS_DONE; ev = nextevent(mp)) { /* YUCK */ ap = &ms->ms_async[port][mp->mp_off]; mppurge((caddr_t)ap, (int)sizeof (*ap)); switch (ev->ev_cmd) { case EVCMD_OPEN: /* * Open completion, start all reads and * assert modem status information. */ for (i = 0; i < MPOUTSET; i++) mp->mp_sendq[i].ev_status = EVSTATUS_GO; (*linesw[tp->t_line].l_modem) (tp, ap->ap_modem.mc_dcd == ASSERT); mp_freein(ev); adjptr(mp->mp_off, MPINSET); mp->mp_proto = MPPROTO_ASYNC; /* XXX */ wakeup((caddr_t)&tp->t_canq); break; case EVCMD_CLOSE: /* * Close completion, flush all pending * transmissions, free resources, and * cleanup mpcc port state. */ for (i = 0; i < MPOUTSET; i++) { mp->mp_sendq[i].ev_status = EVSTATUS_FREE; mp->mp_sendq[i].ev_un.rcvblk = 0; mp->mp_sendq[i].ev_params = 0; } mp_freein(ev); adjptr(mp->mp_off, MPINSET); tp->t_state &= ~(TS_CARR_ON|TS_BUSY|TS_FLUSH); mp->mp_on = mp->mp_off = mp->mp_nextrcv = 0; mp->mp_flags &= ~MP_PROGRESS; mp->mp_proto = MPPROTO_UNUSED; wakeup((caddr_t)&tp->t_canq); break; case EVCMD_IOCTL: mp_freein(ev); adjptr(mp->mp_off, MPINSET); mp->mp_flags &= ~MP_IOCTL; wakeup((caddr_t)&tp->t_canq); break; case EVCMD_WRITE: /* * Transmission completed, update tty * state and restart output. */ if (ev->ev_opts != A_FLUSH) { tp->t_state &= ~TS_BUSY; if (tp->t_state & TS_FLUSH) tp->t_state &= ~TS_FLUSH; else { register int cc = 0, n; struct hxmtl *hxp; hxp = &ms->ms_hxl[port]; for (n=0;n < ev->ev_count; n++) cc += hxp->size[n]; ndflush(&tp->t_outq, cc); } } switch (ev->ev_error) { case A_SIZERR: /*# error in xmt data size */ mplog(unit, port, A_XSIZE, 0); break; case A_NXBERR: /*# no more xmt evt buffers */ mplog(unit, port, A_NOXBUF, 0); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -