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

📄 s2681cons.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
字号:
#ifndef lintstatic char *sccsid = "@(#)s2681cons.c	4.1	ULTRIX	7/2/90";#endif lint/* ------------------------------------------------------------------ *//* | Copyright Unpublished, MIPS Computer Systems, Inc.  All Rights | *//* | Reserved.  This software contains proprietary and confidential | *//* | information of MIPS and its suppliers.  Use, disclosure or     | *//* | reproduction is prohibited without the prior express written   | *//* | consent of MIPS.                                               | *//* ------------------------------------------------------------------ */#include "../h/param.h"#include "../h/conf.h"#include "../h/vm.h"#include "../h/dir.h"#include "../h/user.h"#include "../h/proc.h"#include "../h/ioctl.h"#include "../h/tty.h"#include "../h/uio.h"#include "../h/file.h"#include "../h/kernel.h"#include "../h/syslog.h"#include "../machine/s2681cons.h"#include "../machine/cpu.h"#define	ISPEED	B9600#define	IFLAGS	(EVENP|ODDP|ECHO|XTABS|CRMOD)#define	CN_REG_BASE	(*(struct cn_reg*)PHYS_TO_K1(0x1e007fff))#define	CN_REG_ADDR	(&CN_REG_BASE)#define CN_CHAN_A	(&(CN_REG_BASE.cn_chan_a))#define CN_CHAN_B	(&(CN_REG_BASE.cn_chan_b))#define CN_REG	register volatile struct cn_reg#define CN_CHAN	register volatile struct cn_chanchar	cn_soft_imr;	/* copy of write-only interrupt mask register. */int	cn_overrun;	/* reciever over-run counter */char	soft_cn_inport;struct uartstat {	u_char	us_mr1;	u_char	us_mr2;	u_char	us_baud;} uartstat[2];struct	tty cons[2];int	cnstart(), ttrstrt();int	cnscan();	/* watch modem control lines */extern char	partab[];/* * This routine is called directly from startup so that printing on the * console will be possible very early. The boot ROM has probably done  * enough initialization to be able to do polled operation, but we want * to be as independent of the boot ROM as possible. */cnattach(){	CN_REG *cnr = CN_REG_ADDR;	CN_CHAN *cnc;	/* 	 * Put channel B into a known state. It is assumed that channel A	 * has been programmed by the boot ROMS.	 */	cnc = CN_CHAN_B;	cnc->cnc_cmd = CNCMD_RXRESET; wbflush();	cnc->cnc_cmd = CNCMD_TXRESET; wbflush();	cnc->cnc_cmd = CNCMD_ERRESET; wbflush();	cnc->cnc_cmd = (CNCMD_BREAKRESET | CNCMD_RXENABLE | CNCMD_TXENABLE);	cnr->cn_outport_conf = 0x0;	/* quiet port b until open */	cnr->cn_auxreg = (CNAUX_SET1|	/* select baud rate table 1 */			CNAUX_ENIP2);	/* accept carrier change on b */	cnr->cn_imr = 0x0;	/* sync hardware/software intr mask */	cn_soft_imr = 0x0;	/* sync hardware/software intr mask */	cn_overrun = 0;		/* no overruns yet */}#define CNIDLE 0#define CNALERT 1static unsigned char cntimer_check[2];	/* start out idle */static unsigned char cntimer_started;static intcntimer(){	register i;	register s;	s = spltty();	for (i=0; i<2; i++) {		if (cons[i].t_state & TS_BUSY) {			if (cntimer_check[i] == CNALERT) {				cnxint(i);				log(LOG_WARNING,				   "cntimer: dropped tx_intr on unit %d\n", i);			} else {				cntimer_check[i] = CNALERT;			}		}	}	splx(s);	timeout(cntimer, (caddr_t)0, (7*hz)/2);	/* every 3.5 seconds */}cnopen (dev, flag)dev_t dev;{	register struct tty *tp;	register int unit;	register int s;	CN_REG *cnr = CN_REG_ADDR;	CN_CHAN *cnc;	int speed, prom_getenv();	unit = minor (dev);	if (unit >= 2)		return (ENXIO);	tp = &cons[unit];	tp->t_oproc = cnstart;	tp->t_state |= TS_WOPEN;	if ((tp->t_state & TS_ISOPEN) == 0) {		ttychars (tp);		if (unit==1) {			atob(prom_getenv("rbaud"), &speed);		} else {			atob(prom_getenv("lbaud"), &speed);		}		speed = map_speed(speed);		if (speed == -1)			speed = ISPEED;#ifdef ultrix		tp->t_cflag = speed & CBAUD;		tp->t_cflag_ext = speed & CBAUD;#else !ultrix		tp->t_ospeed = tp->t_ispeed = speed;#endif ultrix		tp->t_flags = IFLAGS;		/* tp->t_state |= TS_HUPCLS; */		cnparam (unit);		/*		 * Assert DTR and accept RX and CD interrupts.		 */		if (unit==1) {			cnr->cn_outport_set = CNOP_DTR_B|CNOP_RTS_B;			cn_soft_imr |= (CNIMR_RXRDY_B | CNIMR_CD_B);		} else {			/* no modem control on channel A */			cn_soft_imr |= CNIMR_RXRDY_A;		}		cnr->cn_imr = cn_soft_imr;	} else if (tp->t_state & TS_XCLUDE && u.u_uid != 0)		return (EBUSY);	/*	 * Wait for DSR, if applicable	 */#ifdef notdef	/*	 * I think this code was here to assist with multiplexing line 	 * between ACU and auto-answer functions.	 */	if (flag & O_NDELAY) {		tp->t_state |= TS_CARR_ON;		tp->t_flags |= NOHANG;	}#endif	s = spltty();	if (unit == 1) {		if (cnr->cn_inport & CNIP_CD_B) {			while ((tp->t_state & TS_CARR_ON) == 0) {				tp->t_state |= TS_WOPEN;				sleep ((caddr_t) & tp->t_rawq, TTIPRI);			}		} else {			tp->t_state |= TS_CARR_ON;		}	} else {		tp->t_state |= TS_CARR_ON;	}	splx(s);	if (cntimer_started == 0) {		cntimer();		/* start the watchdog */		cntimer_started = 1;	}	return ((*linesw[tp->t_line].l_open) (dev, tp));}cnclose(dev, flag)dev_t dev;{	register struct tty *tp;	register int unit;	CN_REG *cnr = CN_REG_ADDR;	unit = minor(dev);	if (unit >= 2)		/* For safety, not in dz.c */		return (ENXIO);	tp = &cons[unit];	(*linesw[tp->t_line].l_close)(tp);	if ((tp->t_state & (TS_HUPCLS|TS_WOPEN))	    || (tp->t_state & TS_ISOPEN) == 0) {		/*		 * Drop DTR|RTS, clear breaks, disable interrupts		 */		if (unit==1) {			cnr->cn_outport_clear = CNOP_DTR_B|CNOP_RTS_B;			cnr->cn_chan_b.cnc_cmd = CNCMD_BREAKSTOP;			cn_soft_imr &= ~(CNIMR_RXRDY_B | CNIMR_TXRDY_B);			cn_soft_imr &= ~CNIMR_CD_B;		} else {			cnr->cn_chan_a.cnc_cmd = CNCMD_BREAKSTOP;			cn_soft_imr &= ~(CNIMR_RXRDY_A | CNIMR_TXRDY_A);		}		cnr->cn_isr = cn_soft_imr;	}	ttyclose(tp);}cnread (dev, uio)dev_t dev;struct uio *uio;{	register struct tty *tp;	tp = &cons[minor (dev)];	return ((*linesw[tp->t_line].l_read) (tp, uio));}cnwrite (dev, uio)dev_t dev;struct uio *uio;{	register struct tty *tp;	tp = &cons[minor (dev)];	return ((*linesw[tp->t_line].l_write) (tp, uio));}cn_intr(){	register u_char isr;	CN_REG *cnr = CN_REG_ADDR;	CURRENT_CPUDATA->cpu_intr++;	while (isr = (cnr->cn_isr & cn_soft_imr)) {		if (isr & CNIMR_RXRDY_A)			cnrint(0);	/* read channel a receiver */		if (isr & CNIMR_RXRDY_B)			cnrint(1);	/* read channel b receiver */		if (isr & CNIMR_TXRDY_A)			cnxint(0);	/* feed channel a transmitter */		if (isr & CNIMR_TXRDY_B)			cnxint(1);	/* feed channel b transmitter */		if (isr & CNIMR_CD_B)			cncarrier();	/* service change in CD (chan B) */	}}cnrint(unit){	register struct tty *tp;	CN_CHAN *cnc;	register c;	register status;	int overrun = 0;	tp = &cons[unit];	if (unit==1)		cnc = CN_CHAN_B;	else		cnc = CN_CHAN_A;	if ((status = cnc->cnc_stat) & CNSTAT_RXRDY)		c = cnc->cnc_data;	if ((tp->t_state & (TS_ISOPEN))==0) {		return;	}	if (status & CNSTAT_PARITY) {		if ((tp->t_flags & (EVENP|ODDP)) == EVENP		    || (tp->t_flags & (EVENP|ODDP)) == ODDP) {			return;		}	}	if ((status & CNSTAT_OVERRUN) && overrun == 0) {		overrun = 1;		/*printf("cons[%d]: overrun error\n",unit);*/		overrun = 0;		cn_overrun++;		cnc->cnc_cmd = CNCMD_ERRESET;	}	if ((status & CNSTAT_FRAME) || (status & CNSTAT_RXBREAK)) {		if (tp->t_flags & RAW) {			c = 0;		} else {#ifdef ultrix			c = tp->t_cc[VINTR];#else !ultrix			c = tp->t_intrc;#endif ultrix		}	}	(*linesw[tp->t_line].l_rint)(c, tp);}cnxint(unit){	CN_REG *cnr = CN_REG_ADDR;	register struct tty *tp;	tp = &cons[unit];	cntimer_check[unit] = CNIDLE;		/* pacify the watchdog */	tp->t_state &= ~TS_BUSY;	if (unit==1) {		cn_soft_imr &= ~CNIMR_TXRDY_B;	} else {		cn_soft_imr &= ~CNIMR_TXRDY_A;	}	cnr->cn_imr = cn_soft_imr;	if (tp->t_state & TS_FLUSH)		tp->t_state &= ~TS_FLUSH;	if (tp->t_line)		(*linesw[tp->t_line].l_start)(tp);	else		cnstart(tp);}cnioctl (dev, cmd, data, flag)dev_t dev;caddr_t data;{	register struct	tty *tp;	register int unit;	CN_REG *cnr = CN_REG_ADDR;	CN_CHAN *cnc;	int error;	unit = minor (dev);	tp = &cons[unit];	if (unit==1)		cnc = CN_CHAN_B;	else		cnc = CN_CHAN_A;	error = (*linesw[tp->t_line].l_ioctl) (tp, cmd, data, flag);	if (error >= 0)		return (error);	error = ttioctl (tp, cmd, data, flag);	if (error >= 0) {		if (cmd == TIOCSETP || cmd == TIOCSETN)			cnparam (unit);		return (error);	}	switch (cmd) {	case TIOCSBRK:		cnc->cnc_cmd = CNCMD_BREAKSTART;		break;	case TIOCCBRK:		cnc->cnc_cmd = CNCMD_BREAKSTOP;		break;	case TIOCSDTR:		if (unit==1) {			cnr->cn_outport_set = CNOP_DTR_B;		} else			return(ENOTTY);		/* no modem control */		break;	case TIOCCDTR:		if (unit==1) {			cnr->cn_outport_clear = CNOP_DTR_B;		} else			return(ENOTTY);		/* no modem control */		break;	case TIOCMSET:	/* XXX */	case TIOCMBIS:	/* XXX */	case TIOCMBIC:	/* XXX */	case TIOCMGET:	/* XXX */	default: 		return (ENOTTY);	}	return (0);}/* *	cnparam - set parameter from tty struct into 2681 registers */cnparam(unit){	register struct tty *tp;	CN_REG *cnr = CN_REG_ADDR;	CN_CHAN *cnc;	int s,i;	int ibaud, obaud;	u_char mr1, mr2;	struct uartstat *us;	tp = &cons[unit];	if (unit==1) {		cnc = CN_CHAN_B;		us = &uartstat[1];	} else {		cnc = CN_CHAN_A;		us = &uartstat[0];	}	/* 	 * Block interrupts so parameters will be set	 * before the line interrupts.	 */	s = spltty();#ifdef ultrix	if ((tp->t_cflag&CBAUD)==0) {#else !ultrix	if ((tp->t_ispeed)==0) {#endif ultrix		tp->t_state |= TS_HUPCLS;		if (unit == 1)			cnr->cn_outport_clear = CNOP_DTR_B|CNOP_RTS_B;		splx(s);		return;	}	/*	 * Set baud rate. For now will only support ACR[7]=1 range of rates.	 * See the 2681 manual for details.	 */#ifdef ultrix	if (((ibaud = map_baud(tp->t_cflag&CBAUD)) != -1) &&	    ((obaud = map_baud(tp->t_cflag_ext&CBAUD)) != -1)) {#else !ultrix	if (((ibaud = map_baud(tp->t_ispeed)) != -1) &&	    ((obaud = map_baud(tp->t_ospeed)) != -1)) {#endif ultrix		obaud =  (ibaud << 4) | obaud;	}	/* build new mode word */#ifdef ultrix	if ((tp->t_cflag&CBAUD) == B134)#else !ultrix	if ((tp->t_ispeed) == B134)#endif ultrix		mr1 = CNMR1_BITS6 | CNMR1_PARITY;	else if (tp->t_flags & (RAW|LITOUT|PASS8))		mr1 = CNMR1_BITS8 | CNMR1_NOPARITY;	else		mr1 = CNMR1_BITS7 | CNMR1_PARITY;	if ((tp->t_flags&(EVENP|ODDP)) == ODDP)		mr1 |= CNMR1_ODDPARITY;	else		mr1 |= CNMR1_EVENPARITY;#ifdef ultrix	if ((tp->t_cflag&CBAUD) == B110) /* NO! not the silent 700, pleeeezz..*/#else !ultrix	if (tp->t_ispeed == B110)	/* NO! not the silent 700, pleeeezz..*/#endif ultrix		mr2 = CNMR2_STOP2;	else		mr2 = CNMR2_STOP1;	/* 	 * Avoid the busy wait on TXEMPTY if the parameters are not changing.	 */	if (us->us_mr1 == mr1 && us->us_mr2 == mr2 && us->us_baud == obaud) {		goto done;	}	us->us_mr1 = mr1;	us->us_mr2 = mr2;	us->us_baud = obaud;	i = 0;	while (!(cnc->cnc_stat & CNSTAT_TXEMPTY) && i < 20) {		DELAY(100);		i++;	}	if (i == 20)		printf("cnparam: timeout on TXEMPTY\n");	cnc->cnc_stat = obaud;	cnc->cnc_cmd = CNCMD_MRRESET; wbflush();	cnc->cnc_mode = mr1; wbflush();	cnc->cnc_mode = mr2; wbflush();done:	splx(s);}map_baud (symbol)char    symbol;{	int     speed;	switch (symbol) {		case B75: speed = 0; break;		case B110: speed = 1; break;		case B134: speed = 2; break;		case B150: speed = 3; break;		case B300: speed = 4; break;		case B600: speed = 5; break;		case B1200: speed = 6; break;		case B2400: speed = 8; break;		case B4800: speed = 9; break;		case B1800: speed = 10; break;		case B9600: speed = 11; break;		case EXTA: speed = 12; break;		default: speed = -1; break;	}	return (speed);}map_speed (speed) int    speed;{	switch (speed) {		case 75: speed = B75; break;		case 110: speed = B110; break;		case 134: speed = B134; break;		case 150: speed = B150; break;		case 300: speed = B300; break;		case 600: speed = B600; break;		case 1200: speed = B1200; break;		case 2400: speed = B2400; break;		case 4800: speed = B4800; break;		case 1800: speed = B1800; break;		case 9600: speed = B9600; break;		case 19200: speed = EXTA; break;		default: speed = -1; break;	}	return (speed);}cnstart(tp)register struct tty *tp;{	CN_REG *cnr = CN_REG_ADDR;	CN_CHAN *cnc;	register int unit, c, s;	s = spltty();	unit = minor(tp->t_dev);	/* If it's currently active, wait for the completion interrupt.	 * If it's delaying or stopped, just wait for the timeout to expire	 * or reception of start character.	 */	if (tp->t_state&(TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) {		goto out;	}	if (tp->t_outq.c_cc<=TTLOWAT(tp)) {		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 (unit==1) {		cnc = CN_CHAN_B;	} else {		cnc = CN_CHAN_A;	}again:	if (tp->t_outq.c_cc == 0)		goto out;	c = getc(&tp->t_outq);	if ((tp->t_flags & (RAW|LITOUT)) == 0) {		if (c <= 0177) {			c = (c | (partab[c]&0200))&0xff;		} else {			timeout(ttrstrt, (caddr_t)tp, (c&0177));			tp->t_state |= TS_TIMEOUT;			goto out;		}	}	tp->t_state |= TS_BUSY;	if (unit==1) {		cn_soft_imr |= CNIMR_TXRDY_B;	} else {		cn_soft_imr |= CNIMR_TXRDY_A;	}	cnr->cn_imr = cn_soft_imr;	cnc->cnc_data = c;	wbflush();	/* Try to use double buffering of transmitter */	if (cnc->cnc_stat & CNSTAT_TXRDY)		goto again;out:	splx(s);}#ifdef notdef/* * Stop output to the 2681; only needed if pdbma is used. XXX */cnstop(tp, flag)register struct tty *tp;int flag;{	return(0);}#endif/* * Check for state change of carrier on port B. */cncarrier(){	register struct tty *tp = &cons[1];	CN_REG *cnr = CN_REG_ADDR;	if (!(cnr->cn_inport_change & CNIP_CD_B)) {		/* carrier present */		if ((tp->t_state & TS_CARR_ON) == 0) {			wakeup ((caddr_t) & tp->t_rawq);			tp->t_state |= TS_CARR_ON;		}	} else {		if ((tp->t_state & TS_CARR_ON) &&		   (tp->t_flags & NOHANG) == 0) {			/* carrier lost */			if (tp->t_state & TS_ISOPEN) {				gsignal (tp->t_pgrp, SIGHUP);				gsignal (tp->t_pgrp, SIGCONT);				ttyflush (tp, FREAD | FWRITE);			}			tp->t_state &= ~TS_CARR_ON;		}	}}cnischar(){	CN_CHAN *cnc = CN_CHAN_A;	return (cnc->cnc_stat & CNSTAT_RXRDY);}cngetc(){	CN_CHAN *cnc = CN_CHAN_A;	register d;#ifdef ultrix	register  s = splcons();#else	register  s = splextreme();#endif ultrix	while (!(cnc->cnc_stat & CNSTAT_RXRDY))		wbflush();	d = cnc->cnc_data;	splx(s);	return(d);}cnputc(c){	CN_CHAN *cnc = CN_CHAN_A;#ifdef ultrix	register  s = splcons();#else	register  s = splextreme();#endif ultrix	while (!(cnc->cnc_stat & CNSTAT_TXRDY))		wbflush();	cnc->cnc_data = c;	while (!(cnc->cnc_stat & CNSTAT_TXEMPTY))		wbflush();	if (c == '\n')		cnputc('\r');	splx(s);}

⌨️ 快捷键说明

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