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

📄 dcm.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
	register char *bp;	register unsigned tail, next;	register int port, nch;	unsigned head;	char buf[16];	int s;#ifdef DCMSTATS	struct dcmstats *dsp = &dcmstats[BOARD(tp->t_dev)];	int tch = 0;#endif	s = spltty();#ifdef DCMSTATS	dsp->xints++;#endif#ifdef DEBUG	if (dcmdebug & DDB_OUTPUT)		printf("dcmstart(%d): state %x flags %x outcc %d\n",		       UNIT(tp->t_dev), tp->t_state, tp->t_flags,		       tp->t_outq.c_cc);#endif	if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))		goto out;	if (tp->t_outq.c_cc <= tp->t_lowat) {		if (tp->t_state&TS_ASLEEP) {			tp->t_state &= ~TS_ASLEEP;			wakeup((caddr_t)&tp->t_outq);		}		selwakeup(&tp->t_wsel);	}	if (tp->t_outq.c_cc == 0) {#ifdef DCMSTATS		dsp->xempty++;#endif		goto out;	}	dcm = dcm_addr[BOARD(tp->t_dev)];	port = PORT(tp->t_dev);	pp = dcm_preg(dcm, port);	tail = pp->t_tail & TX_MASK;	next = (tail + 1) & TX_MASK;	head = pp->t_head & TX_MASK;	if (head == next)		goto out;	fifo = &dcm->dcm_tfifos[3-port][tail];again:	nch = q_to_b(&tp->t_outq, buf, (head - next) & TX_MASK);#ifdef DCMSTATS	tch += nch;#endif#ifdef DEBUG	if (dcmdebug & DDB_OUTPUT)		printf("\thead %x tail %x nch %d\n", head, tail, nch);#endif	/*	 * Loop transmitting all the characters we can.	 */	for (bp = buf; --nch >= 0; bp++) {		fifo->data_char = *bp;		pp->t_tail = next;		/*		 * If this is the first character,		 * get the hardware moving right now.		 */		if (bp == buf) {			tp->t_state |= TS_BUSY;			SEM_LOCK(dcm);			dcm->dcm_cmdtab[port].dcm_data |= CT_TX;			dcm->dcm_cr |= (1 << port);			SEM_UNLOCK(dcm);		}		tail = next;		fifo = tail ? fifo+1 : &dcm->dcm_tfifos[3-port][0];		next = (next + 1) & TX_MASK;	}	/*	 * Head changed while we were loading the buffer,	 * go back and load some more if we can.	 */	if (tp->t_outq.c_cc && head != (pp->t_head & TX_MASK)) {#ifdef DCMSTATS		dsp->xrestarts++;#endif		head = pp->t_head & TX_MASK;		goto again;	}	/*	 * Kick it one last time in case it finished while we were	 * loading the last bunch.	 */	if (bp > &buf[1]) {		tp->t_state |= TS_BUSY;		SEM_LOCK(dcm);		dcm->dcm_cmdtab[port].dcm_data |= CT_TX;		dcm->dcm_cr |= (1 << port);		SEM_UNLOCK(dcm);	}#ifdef DEBUG	if (dcmdebug & DDB_INTR)		printf("dcmstart(%d): head %x tail %x outqcc %d\n",		       UNIT(tp->t_dev), head, tail, tp->t_outq.c_cc);#endifout:#ifdef DCMSTATS	dsp->xchars += tch;	if (tch <= DCMXBSIZE)		dsp->xsilo[tch]++;	else		dsp->xsilo[DCMXBSIZE+1]++;#endif	splx(s);} /* * Stop output on a line. */dcmstop(tp, flag)	register struct tty *tp;	int flag;{	int s;	s = spltty();	if (tp->t_state & TS_BUSY) {		/* XXX is there some way to safely stop transmission? */		if ((tp->t_state&TS_TTSTOP) == 0)			tp->t_state |= TS_FLUSH;	}	splx(s);} /* * Modem control */dcmmctl(dev, bits, how)	dev_t dev;	int bits, how;{	register struct dcmdevice *dcm;	int s, unit, brd, hit = 0;	unit = UNIT(dev);#ifdef DEBUG	if (dcmdebug & DDB_MODEM)		printf("dcmmctl(%d) unit %d  bits 0x%x how %x\n",		       BOARD(unit), unit, bits, how);#endif	brd = BOARD(unit);	dcm = dcm_addr[brd];	s = spltty();	switch (how) {	case DMSET:		dcm_modem[unit]->mdmout = bits;		hit++;		break;	case DMBIS:		dcm_modem[unit]->mdmout |= bits;		hit++;		break;	case DMBIC:		dcm_modem[unit]->mdmout &= ~bits;		hit++;		break;	case DMGET:		bits = dcm_modem[unit]->mdmin;		if (dcmsoftCAR[brd] & FLAG_STDDCE)			bits = hp2dce_in(bits);		break;	}	if (hit) {		SEM_LOCK(dcm);		dcm->dcm_modemchng |= 1<<(unit & 3);		dcm->dcm_cr |= CR_MODM;		SEM_UNLOCK(dcm);		DELAY(10); /* delay until done */		(void) splx(s);	}	return (bits);}/* * Set board to either interrupt per-character or at a fixed interval. */dcmsetischeme(brd, flags)	int brd, flags;{	register struct dcmdevice *dcm = dcm_addr[brd];	register struct dcmischeme *dis = &dcmischeme[brd];	register int i;	u_char mask;	int perchar = flags & DIS_PERCHAR;#ifdef DEBUG	if (dcmdebug & DDB_INTSCHM)		printf("dcmsetischeme(%d, %d): cur %d, ints %d, chars %d\n",		       brd, perchar, dis->dis_perchar,		       dis->dis_intr, dis->dis_char);	if ((flags & DIS_RESET) == 0 && perchar == dis->dis_perchar) {		printf("dcmsetischeme(%d):  redundent request %d\n",		       brd, perchar);		return;	}#endif	/*	 * If perchar is non-zero, we enable interrupts on all characters	 * otherwise we disable perchar interrupts and use periodic	 * polling interrupts.	 */	dis->dis_perchar = perchar;	mask = perchar ? 0xf : 0x0;	for (i = 0; i < 256; i++)		dcm->dcm_bmap[i].data_data = mask;	/*	 * Don't slow down tandem mode, interrupt on flow control	 * chars for any port on the board.	 */	if (!perchar) {		register struct tty *tp = &dcm_tty[MKUNIT(brd, 0)];		int c;		for (i = 0; i < 4; i++, tp++) {			if ((c = tp->t_cc[VSTART]) != _POSIX_VDISABLE)				dcm->dcm_bmap[c].data_data |= (1 << i);			if ((c = tp->t_cc[VSTOP]) != _POSIX_VDISABLE)				dcm->dcm_bmap[c].data_data |= (1 << i);		}	}	/*	 * Board starts with timer disabled so if first call is to	 * set perchar mode then we don't want to toggle the timer.	 */	if (flags == (DIS_RESET|DIS_PERCHAR))		return;	/*	 * Toggle card 16.7ms interrupts (we first make sure that card	 * has cleared the bit so it will see the toggle).	 */	while (dcm->dcm_cr & CR_TIMER)		;	SEM_LOCK(dcm);	dcm->dcm_cr |= CR_TIMER;	SEM_UNLOCK(dcm);}/* * Following are all routines needed for DCM to act as console */#include <hp/dev/cons.h>dcmcnprobe(cp)	struct consdev *cp;{	register struct hp_hw *hw;	int unit;	/* locate the major number */	for (dcmmajor = 0; dcmmajor < nchrdev; dcmmajor++)		if (cdevsw[dcmmajor].d_open == dcmopen)			break;	/*	 * Implicitly assigns the lowest select code DCM card found to be	 * logical unit 0 (actually CONUNIT).  If your config file does	 * anything different, you're screwed.	 */	for (hw = sc_table; hw->hw_type; hw++)		if (HW_ISDEV(hw, D_COMMDCM) && !badaddr((short *)hw->hw_kva))			break;	if (!HW_ISDEV(hw, D_COMMDCM)) {		cp->cn_pri = CN_DEAD;		return;	}	unit = CONUNIT;	dcm_addr[BOARD(CONUNIT)] = (struct dcmdevice *)hw->hw_kva;	/* initialize required fields */	cp->cn_dev = makedev(dcmmajor, unit);	cp->cn_tp = &dcm_tty[unit];	switch (dcm_addr[BOARD(unit)]->dcm_rsid) {	case DCMID:		cp->cn_pri = CN_NORMAL;		break;	case DCMID|DCMCON:		cp->cn_pri = CN_REMOTE;		break;	default:		cp->cn_pri = CN_DEAD;		return;	}	/*	 * If dcmconsole is initialized, raise our priority.	 */	if (dcmconsole == UNIT(unit))		cp->cn_pri = CN_REMOTE;#ifdef KGDB_CHEAT	/*	 * This doesn't currently work, at least not with ite consoles;	 * the console hasn't been initialized yet.	 */	if (major(kgdb_dev) == dcmmajor && BOARD(kgdb_dev) == BOARD(unit)) {		(void) dcminit(kgdb_dev, kgdb_rate);		if (kgdb_debug_init) {			/*			 * We assume that console is ready for us...			 * this assumes that a dca or ite console			 * has been selected already and will init			 * on the first putc.			 */			printf("dcm%d: ", UNIT(kgdb_dev));			kgdb_connect(1);		}	}#endif}dcmcninit(cp)	struct consdev *cp;{	dcminit(cp->cn_dev, dcmdefaultrate);	dcmconsinit = 1;	dcmconsole = UNIT(cp->cn_dev);}dcminit(dev, rate)	dev_t dev;	int rate;{	register struct dcmdevice *dcm = dcm_addr[BOARD(dev)];	int s, mode, port;	port = PORT(dev);	mode = LC_8BITS | LC_1STOP;	s = splhigh();	/*	 * Wait for transmitter buffer to empty.	 */	while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)		DELAY(DCM_USPERCH(rate));	/*	 * Make changes known to hardware.	 */	dcm->dcm_data[port].dcm_baud = ttspeedtab(rate, dcmspeedtab);	dcm->dcm_data[port].dcm_conf = mode;	SEM_LOCK(dcm);	dcm->dcm_cmdtab[port].dcm_data |= CT_CON;	dcm->dcm_cr |= (1 << port);	SEM_UNLOCK(dcm);	/*	 * Delay for config change to take place. Weighted by baud.	 * XXX why do we do this?	 */	DELAY(16 * DCM_USPERCH(rate));	splx(s);}dcmcngetc(dev)	dev_t dev;{	register struct dcmdevice *dcm = dcm_addr[BOARD(dev)];	register struct dcmrfifo *fifo;	register struct dcmpreg *pp;	register unsigned head;	int s, c, stat, port;	port = PORT(dev);	pp = dcm_preg(dcm, port);	s = splhigh();	head = pp->r_head & RX_MASK;	fifo = &dcm->dcm_rfifos[3-port][head>>1];	while (head == (pp->r_tail & RX_MASK))		;	/*	 * If board interrupts are enabled, just let our received char	 * interrupt through in case some other port on the board was	 * busy.  Otherwise we must clear the interrupt.	 */	SEM_LOCK(dcm);	if ((dcm->dcm_ic & IC_IE) == 0)		stat = dcm->dcm_iir;	SEM_UNLOCK(dcm);	c = fifo->data_char;	stat = fifo->data_stat;	pp->r_head = (head + 2) & RX_MASK;	splx(s);	return (c);}/* * Console kernel output character routine. */dcmcnputc(dev, c)	dev_t dev;	int c;{	register struct dcmdevice *dcm = dcm_addr[BOARD(dev)];	register struct dcmpreg *pp;	unsigned tail;	int s, port, stat;	port = PORT(dev);	pp = dcm_preg(dcm, port);	s = splhigh();#ifdef KGDB	if (dev != kgdb_dev)#endif	if (dcmconsinit == 0) {		(void) dcminit(dev, dcmdefaultrate);		dcmconsinit = 1;	}	tail = pp->t_tail & TX_MASK;	while (tail != (pp->t_head & TX_MASK))		;	dcm->dcm_tfifos[3-port][tail].data_char = c;	pp->t_tail = tail = (tail + 1) & TX_MASK;	SEM_LOCK(dcm);	dcm->dcm_cmdtab[port].dcm_data |= CT_TX;	dcm->dcm_cr |= (1 << port);	SEM_UNLOCK(dcm);	while (tail != (pp->t_head & TX_MASK))		;	/*	 * If board interrupts are enabled, just let our completion	 * interrupt through in case some other port on the board	 * was busy.  Otherwise we must clear the interrupt.	 */	if ((dcm->dcm_ic & IC_IE) == 0) {		SEM_LOCK(dcm);		stat = dcm->dcm_iir;		SEM_UNLOCK(dcm);	}	splx(s);}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -