cy.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 2,536 行 · 第 1/5 页

C
2,536
字号
	return (cyu);}static intsioattach(isdp)	struct isa_device	*isdp;{	int	adapter;	adapter = cyattach_common((cy_addr) isdp->id_maddr, 0);	if (adapter < 0)		return (0);	/*	 * XXX	 * This kludge is to allow ISA/PCI device specifications in the	 * kernel config file to be in any order.	 */	if (isdp->id_unit != adapter) {		printf("cy%d: attached as cy%d\n", isdp->id_unit, adapter);		isdp->id_unit = adapter;	/* XXX */	}	isdp->id_ointr = siointr;	isdp->id_ri_flags |= RI_FAST;	return (1);}intcyattach_common(cy_iobase, cy_align)	cy_addr	cy_iobase;	int	cy_align;{	int	adapter;	int	cyu;	dev_t	dev;	u_char	firmware_version;	cy_addr	iobase;	int	ncyu;	int	unit;	adapter = cy_total_devices;	if ((u_int)adapter >= NCY) {		printf(	"cy%d: can't attach adapter: insufficient cy devices configured\n",		       adapter);		return (-1);	}	ncyu = cy_units(cy_iobase, cy_align);	if (ncyu == 0)		return (-1);	cy_nr_cd1400s[adapter] = ncyu;	cy_total_devices++;	unit = adapter * CY_MAX_PORTS;	for (cyu = 0; cyu < ncyu; ++cyu) {		int	cdu;		iobase = (cy_addr) (cy_iobase				    + (cy_chip_offset[cyu] << cy_align));		firmware_version = cd_inb(iobase, CD1400_GFRCR, cy_align);		/* Set up a receive timeout period of than 1+ ms. */		cd_outb(iobase, CD1400_PPR, cy_align,			howmany(CY_CLOCK(firmware_version)				/ CD1400_PPR_PRESCALER, 1000));		for (cdu = 0; cdu < CD1400_NO_OF_CHANNELS; ++cdu, ++unit) {			struct com_s	*com;			int		s;	com = malloc(sizeof *com, M_DEVBUF, M_NOWAIT);	if (com == NULL)		break;	bzero(com, sizeof *com);	com->unit = unit;			com->gfrcr_image = firmware_version;			if (CY_RTS_DTR_SWAPPED(firmware_version)) {				com->mcr_dtr = MCR_RTS;				com->mcr_rts = MCR_DTR;				com->mcr_rts_reg = CD1400_MSVR2;			} else {				com->mcr_dtr = MCR_DTR;				com->mcr_rts = MCR_RTS;				com->mcr_rts_reg = CD1400_MSVR1;			}	com->dtr_wait = 3 * hz;	com->iptr = com->ibuf = com->ibuf1;	com->ibufend = com->ibuf1 + RS_IBUFSIZE;	com->ihighwater = com->ibuf1 + RS_IHIGHWATER;	com->obufs[0].l_head = com->obuf1;	com->obufs[1].l_head = com->obuf2;			com->cy_align = cy_align;			com->cy_iobase = cy_iobase;	com->iobase = iobase;			com->car = ~CD1400_CAR_CHAN;	/*	 * We don't use all the flags from <sys/ttydefaults.h> since they	 * are only relevant for logins.  It's important to have echo off	 * initially so that the line doesn't start blathering before the	 * echo flag can be turned off.	 */	com->it_in.c_iflag = 0;	com->it_in.c_oflag = 0;	com->it_in.c_cflag = TTYDEF_CFLAG;	com->it_in.c_lflag = 0;	if (unit == comconsole) {		com->it_in.c_iflag = TTYDEF_IFLAG;		com->it_in.c_oflag = TTYDEF_OFLAG;		com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL;		com->it_in.c_lflag = TTYDEF_LFLAG;		com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL;	}	termioschars(&com->it_in);	com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate;	com->it_out = com->it_in;	s = spltty();	com_addr(unit) = com;	splx(s);	if (!sio_registered) {		dev = makedev(CDEV_MAJOR, 0);		cdevsw_add(&dev, &sio_cdevsw, NULL);		register_swi(SWI_TTY, siopoll);		sio_registered = TRUE;	}#ifdef DEVFS	com->devfs_token_ttyd = devfs_add_devswf(&sio_cdevsw,		unit, DV_CHR,		UID_ROOT, GID_WHEEL, 0600, "ttyc%r%r", adapter,		unit % CY_MAX_PORTS);	com->devfs_token_ttyi = devfs_add_devswf(&sio_cdevsw,		unit | CONTROL_INIT_STATE, DV_CHR,		UID_ROOT, GID_WHEEL, 0600, "ttyic%r%r", adapter,		unit % CY_MAX_PORTS);	com->devfs_token_ttyl = devfs_add_devswf(&sio_cdevsw,		unit | CONTROL_LOCK_STATE, DV_CHR,		UID_ROOT, GID_WHEEL, 0600, "ttylc%r%r", adapter,		unit % CY_MAX_PORTS);	com->devfs_token_cuaa = devfs_add_devswf(&sio_cdevsw,		unit | CALLOUT_MASK, DV_CHR,		UID_UUCP, GID_DIALER, 0660, "cuac%r%r", adapter,		unit % CY_MAX_PORTS);	com->devfs_token_cuai = devfs_add_devswf(&sio_cdevsw,		unit | CALLOUT_MASK | CONTROL_INIT_STATE, DV_CHR,		UID_UUCP, GID_DIALER, 0660, "cuaic%r%r", adapter,		unit % CY_MAX_PORTS);	com->devfs_token_cual = devfs_add_devswf(&sio_cdevsw,		unit | CALLOUT_MASK | CONTROL_LOCK_STATE, DV_CHR,		UID_UUCP, GID_DIALER, 0660, "cualc%r%r", adapter,		unit % CY_MAX_PORTS);#endif		}	}	/* ensure an edge for the next interrupt */	cy_outb(cy_iobase, CY_CLEAR_INTR, cy_align, 0);	return (adapter);}static intsioopen(dev, flag, mode, p)	dev_t		dev;	int		flag;	int		mode;	struct proc	*p;{	struct com_s	*com;	int		error;	int		mynor;	int		s;	struct tty	*tp;	int		unit;	mynor = minor(dev);	unit = MINOR_TO_UNIT(mynor);	if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL)		return (ENXIO);	if (mynor & CONTROL_MASK)		return (0);#if 0 /* XXX */	tp = com->tp = sio_tty[unit] = ttymalloc(sio_tty[unit]);#else	tp = com->tp = &sio_tty[unit];#endif	s = spltty();	/*	 * We jump to this label after all non-interrupted sleeps to pick	 * up any changes of the device state.	 */open_top:	while (com->state & CS_DTR_OFF) {		error = tsleep(&com->dtr_wait, TTIPRI | PCATCH, "cydtr", 0);		if (error != 0)			goto out;	}	if (tp->t_state & TS_ISOPEN) {		/*		 * The device is open, so everything has been initialized.		 * Handle conflicts.		 */		if (mynor & CALLOUT_MASK) {			if (!com->active_out) {				error = EBUSY;				goto out;			}		} else {			if (com->active_out) {				if (flag & O_NONBLOCK) {					error = EBUSY;					goto out;				}				error =	tsleep(&com->active_out,					       TTIPRI | PCATCH, "cybi", 0);				if (error != 0)					goto out;				goto open_top;			}		}		if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {			error = EBUSY;			goto out;		}	} else {		/*		 * The device isn't open, so there are no conflicts.		 * Initialize it.  Initialization is done twice in many		 * cases: to preempt sleeping callin opens if we are		 * callout, and to complete a callin open after DCD rises.		 */		tp->t_oproc = comstart;		tp->t_param = comparam;		tp->t_dev = dev;		tp->t_termios = mynor & CALLOUT_MASK				? com->it_out : com->it_in;		tp->t_ififosize = 2 * RS_IBUFSIZE;		tp->t_ispeedwat = (speed_t)-1;		tp->t_ospeedwat = (speed_t)-1;		/* Encode per-board unit in LIVR for access in intr routines. */		cd_setreg(com, CD1400_LIVR,			  (unit & CD1400_xIVR_CHAN) << CD1400_xIVR_CHAN_SHIFT);		(void)commctl(com, TIOCM_DTR | TIOCM_RTS, DMSET);#if 0		com->poll = com->no_irq;		com->poll_output = com->loses_outints;#endif		++com->wopeners;		error = comparam(tp, &tp->t_termios);		--com->wopeners;		if (error != 0)			goto out;#if 0		if (com->hasfifo) {			/*			 * (Re)enable and flush fifos.			 *			 * Certain SMC chips cause problems if the fifos			 * are enabled while input is ready.  Turn off the			 * fifo if necessary to clear the input.  We test			 * the input ready bit after enabling the fifos			 * since we've already enabled them in comparam()			 * and to handle races between enabling and fresh			 * input.			 */			while (TRUE) {				outb(iobase + com_fifo,				     FIFO_RCV_RST | FIFO_XMT_RST				     | com->fifo_image);				DELAY(100);				if (!(inb(com->line_status_port) & LSR_RXRDY))					break;				outb(iobase + com_fifo, 0);				DELAY(100);				(void) inb(com->data_port);			}		}		disable_intr();		(void) inb(com->line_status_port);		(void) inb(com->data_port);		com->prev_modem_status = com->last_modem_status		    = inb(com->modem_status_port);		outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS				       | IER_EMSC);		enable_intr();#else /* !0 */		/*		 * Flush fifos.  This requires a full channel reset which		 * also disables the transmitter and receiver.  Recover		 * from this.		 */		cd1400_channel_cmd(com,				   CD1400_CCR_CMDRESET | CD1400_CCR_CHANRESET);		cd1400_channel_cmd(com, com->channel_control);		disable_intr();		com->prev_modem_status = com->last_modem_status		    = cd_getreg(com, CD1400_MSVR2);		cd_setreg(com, CD1400_SRER,			  com->intr_enable			  = CD1400_SRER_MDMCH | CD1400_SRER_RXDATA);		enable_intr();#endif /* 0 */		/*		 * Handle initial DCD.  Callout devices get a fake initial		 * DCD (trapdoor DCD).  If we are callout, then any sleeping		 * callin opens get woken up and resume sleeping on "cybi"		 * instead of "cydcd".		 */		/*		 * XXX `mynor & CALLOUT_MASK' should be		 * `tp->t_cflag & (SOFT_CARRIER | TRAPDOOR_CARRIER) where		 * TRAPDOOR_CARRIER is the default initial state for callout		 * devices and SOFT_CARRIER is like CLOCAL except it hides		 * the true carrier.		 */		if (com->prev_modem_status & MSR_DCD || mynor & CALLOUT_MASK)			(*linesw[tp->t_line].l_modem)(tp, 1);	}	/*	 * Wait for DCD if necessary.	 */	if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)	    && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {		++com->wopeners;		error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "cydcd", 0);		--com->wopeners;		if (error != 0)			goto out;		goto open_top;	}	error =	(*linesw[tp->t_line].l_open)(dev, tp);	disc_optim(tp, &tp->t_termios, com);	if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)		com->active_out = TRUE;	siosettimeout();out:	splx(s);	if (!(tp->t_state & TS_ISOPEN) && com->wopeners == 0)		comhardclose(com);	return (error);}static intsioclose(dev, flag, mode, p)	dev_t		dev;	int		flag;	int		mode;	struct proc	*p;{	struct com_s	*com;	int		mynor;	int		s;	struct tty	*tp;	mynor = minor(dev);	if (mynor & CONTROL_MASK)		return (0);	com = com_addr(MINOR_TO_UNIT(mynor));	tp = com->tp;	s = spltty();	cd_etc(com, CD1400_ETC_STOPBREAK);	(*linesw[tp->t_line].l_close)(tp, flag);	disc_optim(tp, &tp->t_termios, com);	siostop(tp, FREAD | FWRITE);	comhardclose(com);	ttyclose(tp);	siosettimeout();	splx(s);#ifdef broken /* session holds a ref to the tty; can't deallocate */	ttyfree(tp);	com->tp = sio_tty[unit] = NULL;#endif	return (0);}static voidcomhardclose(com)	struct com_s	*com;{	cy_addr		iobase;	int		s;	struct tty	*tp;	int		unit;	unit = com->unit;	iobase = com->iobase;	s = spltty();#if 0	com->poll = FALSE;	com->poll_output = FALSE;#endif	com->do_timestamp = 0;#if 0	outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);#else	/* XXX */	disable_intr();	com->etc = ETC_NONE;	cd_setreg(com, CD1400_COR2, com->cor[1] &= ~CD1400_COR2_ETC);	enable_intr();	cd1400_channel_cmd(com, CD1400_CCR_CMDRESET | CD1400_CCR_FTF);#endif	{#if 0		outb(iobase + com_ier, 0);#else		disable_intr();		cd_setreg(com, CD1400_SRER, com->intr_enable = 0);		enable_intr();#endif		tp = com->tp;		if (tp->t_cflag & HUPCL		    /*		     * XXX we will miss any carrier drop between here and the		     * next open.  Perhaps we should watch DCD even when the		     * port is closed; it is not sufficient to check it at		     * the next open because it might go up and down while		     * we're not watching.		     */		    || !com->active_out		       && !(com->prev_modem_status & MSR_DCD)		       && !(com->it_in.c_cflag & CLOCAL)		    || !(tp->t_state & TS_ISOPEN)) {			(void)commctl(com, TIOCM_DTR, DMBIC);			/* Disable receiver (leave transmitter enabled). */			com->channel_control = CD1400_CCR_CMDCHANCTL					       | CD1400_CCR_XMTEN					       | CD1400_CCR_RCVDIS;			cd1400_channel_cmd(com, com->channel_control);			if (com->dtr_wait != 0 && !(com->state & CS_DTR_OFF)) {				timeout(siodtrwakeup, com, com->dtr_wait);				com->state |= CS_DTR_OFF;			}		}	}#if 0	if (com->hasfifo) {		/*		 * Disable fifos so that they are off after controlled		 * reboots.  Some BIOSes fail to detect 16550s when the		 * fifos are enabled.		 */		outb(iobase + com_fifo, 0);	}#endif	com->active_out = FALSE;	wakeup(&com->active_out);	wakeup(TSA_CARR_ON(tp));	/* restart any wopeners */	splx(s);}static intsioread(dev, uio, flag)	dev_t		dev;	struct uio	*uio;	int		flag;{	int		mynor;	struct tty	*tp;	mynor = minor(dev);	if (mynor & CONTROL_MASK)		return (ENODEV);	tp = com_addr(MINOR_TO_UNIT(mynor))->tp;	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));}static intsiowrite(dev, uio, flag)	dev_t		dev;	struct uio	*uio;	int		flag;{	int		mynor;	struct tty	*tp;	int		unit;	mynor = minor(dev);	if (mynor & CONTROL_MASK)		return (ENODEV);	unit = MINOR_TO_UNIT(mynor);	tp = com_addr(unit)->tp;	/*	 * (XXX) We disallow virtual consoles if the physical console is	 * a serial port.  This is in case there is a display attached that	 * is not the console.  In that situation we don't need/want the X	 * server taking over the console.	 */	if (constty != NULL && unit == comconsole)		constty = NULL;#ifdef Smarts	/* XXX duplicate ttwrite(), but without so much output processing on	 * CR & LF chars.  Hardly worth the effort, given that high-throughput	 * sessions are raw anyhow.	 */#else	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));#endif

⌨️ 快捷键说明

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