⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mp.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
		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 + -