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

📄 dmb.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (lpr&DMB_DTR)  b |= TIOCM_DTR;	if (lstat&DMB_DCD)  b |= TIOCM_CD;	if (lstat&DMB_CTS)  b |= TIOCM_CTS;	if (lstat&DMB_RI)  b |= TIOCM_RI;	if (lstat&DMB_DSR)  b |= TIOCM_DSR;	return(b);}dmtodmb(bits)	register int bits;{	register long lpr = 0;	if (bits&TIOCM_RTS) lpr |= DMB_RTS;	if (bits&TIOCM_DTR) lpr |= DMB_DTR;	return(lpr);}/* * Set parameters from open or stty into the DMB hardware * registers. */dmbparam(unit)	register int unit;{	register struct tty *tp;	register struct dmb_device *addr;	register long lpar;	tp = &dmb_tty[unit];	if (tp->t_state & TS_BUSY) {	    tp->t_state |= TS_NEED_PARAM;	    return;	}	addr = (struct dmb_device *)tp->t_addr;	addr->dmb_acsr = (unit & LINEMASK) | DMB_IE;	/* line select */	/*  	 * Disconnect modem line if baudrate is zero.  POSIX checks the output	 * baud rate, while non-POSIX checks the input baud rate.	 */	if ((((tp->t_cflag&CBAUD)==B0) && (u.u_procp->p_progenv != A_POSIX)) || 	    (((tp->t_cflag_ext & CBAUD)==B0) && 		(u.u_procp->p_progenv == A_POSIX))) 		{		tp->t_cflag |= HUPCL;		addr->dmb_lpr &= ~(DMB_DTR | DMB_RTS); /* turn off DTR & RTS but leave enabled */		return;		}	/* else - set line parameters */	lpar = (dmb_speeds[tp->t_cflag_ext&CBAUD]<<28) | 	/* ospeed */		(dmb_speeds[tp->t_cflag&CBAUD]<<24);		/* ispeed */	/*	 * Berkeley-only dinosaurs	 */	if (tp->t_line != TERMIODISC) {		if ((tp->t_cflag & CBAUD) == B134){			lpar |= DMB_BITS6|DMB_PARITYENAB; 			tp->t_cflag |= CS6|PARENB;		}		else if ((tp->t_cflag_ext & CBAUD) == B110){			lpar |= DMB_TWOSTOPB;			tp->t_cflag |= CSTOPB;		}	} 	/* 	 * System V termio functionality.	 * Set device registers according to the specifications of the termio	 * structure. 	 */ 	if (tp->t_cflag & CREAD) 		lpar |= DMB_RXENA;	else 		lpar &= ~DMB_RXENA; 	if (tp->t_cflag & CSTOPB) 		lpar |= DMB_TWOSTOPB; 	else 		lpar &= ~DMB_TWOSTOPB; 	/* parity is enable */ 	if (tp->t_cflag & PARENB) { 		if ((tp->t_cflag & PARODD) == 0) 			/* set even */ 			lpar |= DMB_PARITYENAB|DMB_EVENPARITY; 		else 			/* else set odd */ 			lpar = (lpar | DMB_PARITYENAB)&~DMB_EVENPARITY; 	} 	/* 	 * character size. 	 * clear bits and check for 6,7,and 8, else its 5 bits. 	 */ 	lpar &= ~DMB_BITS8; 	switch(tp->t_cflag&CSIZE) { 		case CS6: 			lpar |= DMB_BITS6; 			break; 		case CS7: 			lpar |= DMB_BITS7; 			break; 		case CS8: 			lpar |= DMB_BITS8; 			break; 	}	/*	 * Outgoing Auto flow control.	 * No auto flow control allowed if startc != ^q and startc !=	 * ^s.  Most drivers do not allow this to be changed.	 */	if ((tp->t_cflag_ext & PAUTOFLOW) && (tp->t_cc[VSTOP] == CTRL('s')) && 		(tp->t_cc[VSTART] == CTRL('q'))) {		/*		 * OAUTO doesn't work on the DHB. 		 * Take this out if it ever does work.		 */		if (dmb_lines[unit >> LINEBITS] != DMB_16_LINES) 			lpar |= DMB_OAUTOFLOW;		else                        tp->t_cflag_ext &= ~PAUTOFLOW;	} 	#	ifdef DEBUG	if (dmbdebug)		mprintf("dmbparam: tp = %x, lpar = %x\n",tp, lpar);#	endif DEBUG	/*	 * Set "Report Modem" bit to get interrupts on modem status changes.	 * Enable receiver, and set Transmission interrupt delay so that	 *   xmit interrupt does not actually happen until all characters	 *   in current DMA have been transmitted.	 * Make all lines modem lines, in case a line is	 *   changed from local to remote (modem).	 */	lpar |= (DMB_REPORT | DMB_TXINTDELAY | DMB_DTR | DMB_RTS);        /*         * If outgoing auto flow control is enabled, the hardware will         * control the transmit enable bit.         */        if ((tp->t_cflag_ext & PAUTOFLOW) == 0)		addr->dmb_lstathigh |= DMB_TXENA;	addr->dmb_lpr = lpar;}/* * DMB32 transmitter interrupt. * Restart each line which used to be active but has * terminated transmission since the last interrupt. */dmbxint(dmb)	int dmb;{	int unit = dmb << LINEBITS;	struct tty *tp0 = &dmb_tty[unit];	register struct tty *tp;	register struct dmb_device *addr;	register struct uba_device *ui;	register long tbuf;	u_short cntr;	register temp_reg;	int totaldelay;	ui = dmbinfo[dmb];	addr = (struct dmb_device *)ui->ui_addr;	while ((tbuf = addr->dmb_tbuf) < 0)		{			/* xmitter action is set if "< 0" */		tbuf = tbuf & LINEMASK;		tp = tp0 + tbuf;		smp_lock(&tp->t_lk_tty,LK_RETRY);		DMB_LOCK(dmb);		/*		 * Make sure another processor hasn't serviced the interrupt.		 */		if ((tbuf = addr->dmb_tbuf) >= 0){			DMB_UNLOCK(dmb);			smp_unlock(&tp->t_lk_tty);			break;		}		if (tp != (tp0 + (tbuf & LINEMASK))) {			DMB_UNLOCK(dmb);			smp_unlock(&tp->t_lk_tty);			continue;		}		addr->dmb_tbuf = 0; /* must write to clear xmitter act bit */		smp_unlock(&lk_dmb[dmb]);		/*		 * Check Error byte and if any error bits set,		 * decode the error.		 */		switch (tbuf & DMB_ERMASK) {		case DMB_TXDMAERROR:			printf("dmb%d: DMA Error. tbuf = 0x%x\n", dmb, tbuf);			break;		case DMB_MSGERR:			printf("dmb%d: Message Error. tbuf = 0x%x\n", dmb, tbuf);			break;		case DMB_LASTCHERR:			printf("dmb%d: Last character Incomplete. tbuf = 0x%x\n", dmb, tbuf);			break;		case DMB_BUFERR:			printf("dmb%d: Buffer Error. tbuf = 0x%x\n", dmb, tbuf);			break;		case DMB_MODEMERR:			printf("dmb%d: Modem Error. tbuf = 0x%x\n", dmb, tbuf);			break;		case DMB_INTERNALERR:			printf("dmb%d: Internal Error. tbuf = 0x%x\n", dmb, tbuf);			break;		}#		ifdef DEBUG		printd10("dmbxint: unit=0x%x, line=%d, tp=0x%x, c_cc=%d\n",				unit, tbuf, tp, tp->t_outq.c_cc);#		endif		tbuf = tbuf & LINEMASK;		tp->t_state &= ~(TS_BUSY|TS_OABORT);		totaldelay = 0;		DMB_LOCK(dmb);		addr->dmb_acsr = DMB_IE | tbuf;		while ((addr->dmb_startdma&DMB_TXDMASTART)&&(totaldelay <= 100)){			totaldelay++;			DELAY(10000);		}		if (addr->dmb_startdma&DMB_TXDMASTART) {		    printf("dmbxint: Resetting DMA START bit on line %d\n",tbuf);		    addr->dmb_startdma &= ~DMB_TXDMASTART;		}		if (tp->t_state&TS_FLUSH)			tp->t_state &= ~TS_FLUSH;	/* was a non ^S stop */		else	{			/*			 * Determine number of characters transmitted so far			 * and flush these from the tty output queue.			 * (unit is the dmb unit number so add in the line #.)			 * unit is already left shifted by the number of lines			 */			/*	The original code below is replaced by functionally equivalent code.	We do this to work around a bug in the C optimizer which optimizes	the original code which was an ASHL instruction followed by BICL	to be an EXTZV instruction.  It is not permitted to have an EXTZV	instruction read from I/O space.  By using a register variable	as is done below, the optimization is avoided.	This could be reconsidered once the C optimizer is corrected.			 */#ifdef ORIGINAL_CODE			cntr = dmb_numchars[unit+tbuf] -				((addr->dmb_tbuffct >> DMB_TXCHARCT) & 0xffff);#else			temp_reg = (addr->dmb_tbuffct >> DMB_TXCHARCT);			temp_reg &= 0xffff;			cntr = dmb_numchars[unit+tbuf] - temp_reg;#endif			ndflush(&tp->t_outq, (int)cntr);			}		if (tp->t_state & TS_NEED_PARAM) {		    tp->t_state &= ~TS_NEED_PARAM;		    /*		     * (unit is the dmb unit number so add in the line #.)		     * unit is already left shifted by the number of lines		     */		    dmbparam(unit+tbuf);		}		DMB_UNLOCK(dmb);		if (tp->t_line)			(*linesw[tp->t_line].l_start)(tp);		else			dmbstart(tp);		smp_unlock(&tp->t_lk_tty);		}}/* * Start (restart) transmission on the given DMB32 line. */dmbstart(tp)	register struct tty *tp;{	register struct dmb_device *addr;	register int unit, nch;	register int totaldelay;	register int dmb;	int post_wakeup = 0;	TTY_ASSERT(tp);	unit = minor(tp->t_dev);	dmb = unit >> LINEBITS;	addr = (struct dmb_device *)tp->t_addr;	/*	 * If it's currently active, or delaying, no need to do anything.	 * Also do not transmit if not CTS.	 */	if ((tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) ||	   ((tp->t_state & TS_CARR_ON) && (dmbmodem[unit]&MODEM_CTS)==0))		return;	/*	 * If there are sleepers, and output has drained below low	 * water mark, wake up the sleepers.	 */	if (tp->t_outq.c_cc<=TTLOWAT(tp))		{		if (tp->t_state&TS_ASLEEP)			{			tp->t_state &= ~TS_ASLEEP;			post_wakeup = WAKEUP_OUTQ;			}		if (tp->t_wsel)			{		/* for select system call */			post_wakeup |= WAKEUP_SELECT;			tp->t_wsel = 0;			tp->t_state &= ~TS_WCOLL;			}		}	/*	 * Output had been aborted by a stop character.  Resume output by 	 * turning on transmit enable.	 */	if ((tp->t_state & TS_OABORT) && ((tp->t_cflag_ext & PAUTOFLOW) == 0)) {			DMB_LOCK(dmb);			addr->dmb_acsr = DMB_IE | (unit & LINEMASK);			addr->dmb_lstathigh |= DMB_TXENA;			DMB_UNLOCK(dmb);			tp->t_state |= TS_BUSY;			tp->t_state &= ~TS_OABORT;			goto dmbendstart;	}	/*	 * Now restart transmission unless the output queue is empty.	 */	if (tp->t_outq.c_cc == 0)		goto dmbendstart;	if ((tp->t_lflag_ext & PRAW) || (tp->t_oflag_ext & PLITOUT) || 	    ((tp->t_oflag & OPOST) == 0))		nch = ndqb(&tp->t_outq, 0);	/* # of consecutive chars */	else	{		nch = ndqb(&tp->t_outq, DELAY_FLAG);		/*		 * If first thing on queue is a delay process it.		 */		if (nch == 0)			{			nch = getc(&tp->t_outq);			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);			tp->t_state |= TS_TIMEOUT;			goto dmbendstart;			}		}	/*	 * If characters to transmit, restart transmission.	 */	if (nch)		{		DMB_LOCK(dmb);		addr->dmb_acsr = DMB_IE | (unit & LINEMASK);	/* line select */		/*		 * Wait for dma start to clear to a maximum of 1 second to		 * prevent a system hang on hardware failure.  After the bit		 * has stuck once, do not repeat this check.		 */		totaldelay = 0;		while ((addr->dmb_startdma&DMB_TXDMASTART)&&(totaldelay <= 100)){		  	if ((dmb_softc[unit/16].sc_flags[unit&LINEMASK]) == 0){	    			totaldelay++;	    			DELAY(10000);			}			else{				totaldelay = 90000;			}		}		if ((addr->dmb_startdma & DMB_TXDMASTART) && 		  ((dmb_softc[unit/16].sc_flags[unit&LINEMASK]) == 0)) {				printf("dmb%d,line%d DMB HARDWARE ERROR.  TX.DMA.START failed\n",unit/16,unit&LINEMASK); 				/*				 * Prevent further checks on this line by				 * setting state flag to be nonzero.				 */		  		dmb_softc[unit/16].sc_flags[unit&LINEMASK]++;				DMB_UNLOCK(dmb);				goto dmbendstart;		}		if (addr->dmb_abort & DMB_TXOUTABORT) {			addr->dmb_abort &= ~(DMB_TXOUTABORT);		}                /*                 * If outgoing auto flow control is enabled, the hardware will                 * control the transmit enable bit.                 */		if ((tp->t_cflag_ext & PAUTOFLOW) == 0)			addr->dmb_lstathigh |= DMB_TXENA;		/*		 * TODO: if (nch == 1) { use programmed (preempt) transfer }		 * 	 This will save on DMA setup overhead.		 */		/* hand the board the physical address of the buffer */		addr->dmb_tbuffadd = (long)svtophy(tp->t_outq.c_cf);		addr->dmb_tbuffct = (nch << DMB_TXCHARCT);		/*		 * Save the number of characters that we are DMA'ing,		 * for use in the transmit interrupt routine.		 * (unit is the whole minor device, unit # & line #.)		 */		dmb_numchars[unit] = nch;		addr->dmb_startdma |= (DMB_TXDMASTART | DMB_TXDMAPHYS);		tp->t_state |= TS_BUSY;		DMB_UNLOCK(dmb);		}		/*		 * Unfortunately these wakeups will be done while the tty lock		 * is still held.  The penalty is not so bad because most of		 * the callers of this routine will release locks very shortly		 * after calling this routine. 		 */dmbendstart:	if (post_wakeup & WAKEUP_OUTQ) 			wakeup((caddr_t)&tp->t_outq);		if (post_wakeup & WAKEUP_SELECT)			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);}/* * Stop output on a line, e.g. for ^S/^Q or output flush. *//*ARGSUSED*/dmbstop(tp, flag)	register struct tty *tp;{	register struct dmb_device *addr;	register int unit, s, dmb;	TTY_ASSERT(tp);	dmb = (minor(tp->t_dev)) >> LINEBITS;	addr = (struct dmb_device *)tp->t_addr;	/*	 * Block input/output interrupts while messing with state.	 * (tty lock must be taken out prior to calling this routine)	 */	if (tp->t_state & TS_BUSY)		{		/*		 * Device is transmitting; stop output.		 * We can continue later by examining the character count.		 */		unit = minor(tp->t_dev) & LINEMASK;		DMB_LOCK(dmb);		addr->dmb_acsr = unit | DMB_IE;		if ((tp->t_state&TS_TTSTOP)==0) {		    if (addr->dmb_startdma & DMB_TXDMASTART) {			addr->dmb_abort |= DMB_TXOUTABORT;  /* abort DMA transmission */			tp->t_state |= TS_FLUSH;	/* NOT a ctl-S */		    }		}		/*		 * Suspend output by turning off transmit enable.  Output will		 * resume when a start char is received.		 */		else if ((tp->t_cflag_ext & PAUTOFLOW) == 0) 			{			addr->dmb_lstathigh &= ~DMB_TXENA;			tp->t_state &= ~TS_BUSY;			tp->t_state |= TS_OABORT;			}		DMB_UNLOCK(dmb);		}}

⌨️ 快捷键说明

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