cy.c

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

C
2,542
字号
/*- * cyclades cyclom-y serial driver *	Andrew Herbert <andrew@werple.apana.org.au>, 17 August 1993 * * Copyright (c) 1993 Andrew Herbert. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. The name Andrew Herbert may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *	$\Id: cy.c,v 1.7.4.3 1996/01/29 04:44:13 bde Exp $ */#include "cy.h"#if NCY > 0/* * TODO: * Check that cy16's work. * Implement BREAK. * Fix overflows when closing line. * Atomic COR change. * Don't report individual ports in devconf; busy flag for board should be * union of the current individual busy flags. * Consoles. *//* * Temporary compile-time configuration options. */#define	RxFifoThreshold	(CD1400_RX_FIFO_SIZE / 2)			/* Number of chars in the receiver FIFO before an			 * an interrupt is generated.  Should depend on			 * line speed.  Needs to be about 6 on a 486DX33			 * for 4 active ports at 115200 bps.  Why doesn't			 * 10 work?			 */#define	PollMode	/* Use polling-based irq service routine, not the			 * hardware svcack lines.  Must be defined for			 * Cyclom-16Y boards.  Less efficient for Cyclom-8Ys,			 * and stops 4 * 115200 bps from working.			 */#undef	Smarts		/* Enable slightly more CD1400 intelligence.  Mainly			 * the output CR/LF processing, plus we can avoid a			 * few checks usually done in ttyinput().			 *			 * XXX not fully implemented, and not particularly			 * worthwhile.			 */#undef	CyDebug		/* Include debugging code (not very expensive). *//* These will go away. */#undef	SOFT_CTS_OFLOW#define	SOFT_HOTCHAR#include <sys/param.h>#include <sys/systm.h>#include <sys/reboot.h>#include <sys/ioctl.h>#include <sys/tty.h>#include <sys/proc.h>#include <sys/user.h>#include <sys/conf.h>#include <sys/dkstat.h>#include <sys/file.h>#include <sys/uio.h>#include <sys/kernel.h>#include <sys/malloc.h>#include <sys/syslog.h>#include <sys/devconf.h>#include <sys/interrupt.h>#include <machine/clock.h>#include <i386/isa/icu.h>	/* XXX just to get at `imen' */#include <i386/isa/isa.h>#include <i386/isa/isa_device.h>#include <i386/isa/cyreg.h>#include <i386/isa/ic/cd1400.h>/* * Dictionary so that I can name everything *sio* or *com* to compare with * sio.c.  There is also lots of ugly formatting and unnecessary ifdefs to * simplify the comparision.  These will go away. */#define	LSR_BI		CD1400_RDSR_BREAK#define	LSR_FE		CD1400_RDSR_FE#define	LSR_OE		CD1400_RDSR_OE#define	LSR_PE		CD1400_RDSR_PE#define	MCR_DTR		CD1400_MSVR2_DTR#define	MCR_RTS		CD1400_MSVR1_RTS#define	MSR_CTS		CD1400_MSVR2_CTS#define	MSR_DCD		CD1400_MSVR2_CD#define	MSR_DSR		CD1400_MSVR2_DSR#define	MSR_RI		CD1400_MSVR2_RI#define	NSIO		(NCY * CY_MAX_PORTS)#define	comconsole	cyconsole#define	comdefaultrate	cydefaultrate#define	com_events	cy_events#define	comhardclose	cyhardclose#define	commajor	cymajor#define	commctl		cymctl#define	comparam	cyparam#define	comspeed	cyspeed#define	comstart	cystart#define	comwakeup	cywakeup#define	kdc_sio		kdc_cy#define	nsio_tty	ncy_tty#define	p_com_addr	p_cy_addr#define	sioattach	cyattach#define	sioclose	cyclose#define	siodevtotty	cydevtotty#define	siodriver	cydriver#define	siodtrwakeup	cydtrwakeup#define	sioioctl	cyioctl#define	siointr		cyintr#define	siointr1	cyintr1#define	siointrts	cyintrts#define	sioopen		cyopen#define	siopoll		cypoll#define	sioprobe	cyprobe#define	sioread		cyread#define	sioregisterdev	cyregisterdev#define	siosettimeout	cysettimeout#define	siostop		cystop#define	siowrite	cywrite#define	sio_timeout	cy_timeout#define	sio_timeouts_until_log	cy_timeouts_until_log#define	sio_tty		cy_tty#define	CY_MAX_PORTS		(CD1400_NO_OF_CHANNELS * CY_MAX_CD1400s)/* We encode the cyclom unit number (cyu) in spare bits in the IVR's. */#define	CD1400_xIVR_CHAN_SHIFT	3#define	CD1400_xIVR_CHAN	0x0F	/* XXX reduce to pack Cyclom-8Ys */#define	LOTS_OF_EVENTS	64	/* helps separate urgent events from input */#define	RB_I_HIGH_WATER	(TTYHOG - 2 * RS_IBUFSIZE)#define	RS_IBUFSIZE	256#define	CALLOUT_MASK		0x80#define	CONTROL_MASK		0x60#define	CONTROL_INIT_STATE	0x20#define	CONTROL_LOCK_STATE	0x40#define	DEV_TO_UNIT(dev)	(MINOR_TO_UNIT(minor(dev)))#define	MINOR_MAGIC_MASK	(CALLOUT_MASK | CONTROL_MASK)#define	MINOR_TO_UNIT(mynor)	((mynor) & ~MINOR_MAGIC_MASK)/* * Input buffer watermarks. * The external device is asked to stop sending when the buffer exactly reaches * high water, or when the high level requests it. * The high level is notified immediately (rather than at a later clock tick) * when this watermark is reached. * The buffer size is chosen so the watermark should almost never be reached. * The low watermark is invisibly 0 since the buffer is always emptied all at * once. */#define	RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)/* * com state bits. * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher * than the other bits so that they can be tested as a group without masking * off the low bits. * * The following com and tty flags correspond closely: *	CS_BUSY		= TS_BUSY (maintained by comstart(), siopoll() and *				   siostop()) *	CS_TTGO		= ~TS_TTSTOP (maintained by comparam() and comstart()) *	CS_CTS_OFLOW	= CCTS_OFLOW (maintained by comparam()) *	CS_RTS_IFLOW	= CRTS_IFLOW (maintained by comparam()) * TS_FLUSH is not used. * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON. * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state). */#define	CS_BUSY		0x80	/* output in progress */#define	CS_TTGO		0x40	/* output not stopped by XOFF */#define	CS_ODEVREADY	0x20	/* external device h/w ready (CTS) */#define	CS_CHECKMSR	1	/* check of MSR scheduled */#define	CS_CTS_OFLOW	2	/* use CTS output flow control */#define	CS_DTR_OFF	0x10	/* DTR held off */#define	CS_ODONE	4	/* output completed */#define	CS_RTS_IFLOW	8	/* use RTS input flow control */static	char const * const	error_desc[] = {#define	CE_OVERRUN			0	"silo overflow",#define	CE_INTERRUPT_BUF_OVERFLOW	1	"interrupt-level buffer overflow",#define	CE_TTY_BUF_OVERFLOW		2	"tty-level buffer overflow",};#define	CE_NTYPES			3#define	CE_RECORD(com, errnum)		(++(com)->delta_error_counts[errnum])/* types.  XXX - should be elsewhere */typedef u_char	bool_t;		/* boolean */typedef u_char volatile *cy_addr;/* queue of linear buffers */struct lbq {	u_char	*l_head;	/* next char to process */	u_char	*l_tail;	/* one past the last char to process */	struct lbq *l_next;	/* next in queue */	bool_t	l_queued;	/* nonzero if queued */};/* com device structure */struct com_s {	u_char	state;		/* miscellaneous flag bits */	bool_t  active_out;	/* nonzero if the callout device is open */#if 0	u_char	cfcr_image;	/* copy of value written to CFCR */	u_char	ftl;		/* current rx fifo trigger level */	u_char	ftl_init;	/* ftl_max for next open() */	u_char	ftl_max;	/* maximum ftl for curent open() */	bool_t	hasfifo;	/* nonzero for 16550 UARTs */	bool_t	loses_outints;	/* nonzero if device loses output interrupts */#endif	u_char	mcr_image;	/* copy of value written to MCR */#if 0#ifdef COM_MULTIPORT	bool_t	multiport;	/* is this unit part of a multiport device? */#endif /* COM_MULTIPORT */	bool_t	no_irq;		/* nonzero if irq is not attached */	bool_t	poll;		/* nonzero if polling is required */	bool_t	poll_output;	/* nonzero if polling for output is required */#endif	int	unit;		/* unit	number */	int	dtr_wait;	/* time to hold DTR down on close (* 1/hz) */#if 0	u_int	tx_fifo_size;#endif	u_int	wopeners;	/* # processes waiting for DCD in open() */	/*	 * The high level of the driver never reads status registers directly	 * because there would be too many side effects to handle conveniently.	 * Instead, it reads copies of the registers stored here by the	 * interrupt handler.	 */	u_char	last_modem_status;	/* last MSR read by intr handler */	u_char	prev_modem_status;	/* last MSR handled by high level */	u_char	hotchar;	/* ldisc-specific char to be handled ASAP */	u_char	*ibuf;		/* start of input buffer */	u_char	*ibufend;	/* end of input buffer */	u_char	*ihighwater;	/* threshold in input buffer */	u_char	*iptr;		/* next free spot in input buffer */	struct lbq	obufq;	/* head of queue of output buffers */	struct lbq	obufs[2];	/* output buffers */	cy_addr	cy_iobase;	/* base address of this port's cyclom */	cy_addr	iobase;		/* base address of this port's cd1400 */	struct tty	*tp;	/* cross reference */	/* Initial state. */	struct termios	it_in;	/* should be in struct tty */	struct termios	it_out;	/* Lock state. */	struct termios	lt_in;	/* should be in struct tty */	struct termios	lt_out;	bool_t	do_timestamp;	struct timeval	timestamp;	u_long	bytes_in;	/* statistics */	u_long	bytes_out;	u_int	delta_error_counts[CE_NTYPES];	u_long	error_counts[CE_NTYPES];	u_int	recv_exception;	/* exception chars received */	u_int	mdm;		/* modem signal changes */#ifdef CyDebug	u_int	start_count;	/* no. of calls to comstart() */	u_int	start_real;	/* no. of calls that did something */#endif	u_char	channel_control;/* CD1400 CCR control command shadow */	u_char	cor[3];		/* CD1400 COR1-3 shadows */	u_char	intr_enable;	/* CD1400 SRER shadow */	/*	 * Ping-pong input buffers.  The extra factor of 2 in the sizes is	 * to allow for an error byte for each input byte.	 */#define	CE_INPUT_OFFSET		RS_IBUFSIZE	u_char	ibuf1[2 * RS_IBUFSIZE];	u_char	ibuf2[2 * RS_IBUFSIZE];	/*	 * Data area for output buffers.  Someday we should build the output	 * buffer queue without copying data.	 */	u_char	obuf1[256];	u_char	obuf2[256];	struct kern_devconf kdc;};/* * XXX public functions in drivers should be declared in headers produced * by `config', not here. *//* Interrupt handling entry points. */void	siointr		__P((int unit));void	siointrts	__P((int unit));void	siopoll		__P((void));/* Device switch entry points. */int	sioopen		__P((dev_t dev, int oflags, int devtype,			     struct proc *p));int	sioclose	__P((dev_t dev, int fflag, int devtype,			     struct proc *p));int	sioread		__P((dev_t dev, struct uio *uio, int ioflag));int	siowrite	__P((dev_t dev, struct uio *uio, int ioflag));int	sioioctl	__P((dev_t dev, int cmd, caddr_t data,			     int fflag, struct proc *p));void	siostop		__P((struct tty *tp, int rw));#define	sioreset	noresetstruct tty *siodevtotty	__P((dev_t dev));#define	siommap		nommap#define	siostrategy	nostrategystatic	int	sioattach	__P((struct isa_device *dev));static	void	cd1400_channel_cmd __P((cy_addr iobase, int cmd));static	timeout_t siodtrwakeup;static	void	comhardclose	__P((struct com_s *com));static	void	siointr1	__P((struct com_s *com));static	int	commctl		__P((struct com_s *com, int bits, int how));static	int	comparam	__P((struct tty *tp, struct termios *t));static	int	sioprobe	__P((struct isa_device *dev));static	void	sioregisterdev	__P((struct isa_device *id));static	void	siosettimeout	__P((void));static	int	comspeed	__P((speed_t speed, int *prescaler_io));static	void	comstart	__P((struct tty *tp));static	timeout_t comwakeup;static	void	disc_optim	__P((struct tty	*tp, struct termios *t,				     struct com_s *com));#ifdef CyDebugvoid	cystatus	__P((int unit));#endif/* table and macro for fast conversion from a unit number to its com struct */static	struct com_s	*p_com_addr[NSIO];#define	com_addr(unit)	(p_com_addr[unit])static  struct timeval	intr_timestamp;struct isa_driver	siodriver = {	sioprobe, sioattach, "cy"};#ifdef COMCONSOLE#undef COMCONSOLE#define	COMCONSOLE	1#else#define	COMCONSOLE	0#endif#ifndef CONUNIT#define	CONUNIT	(0)#endifstatic	int	comconsole = CONUNIT;static	speed_t	comdefaultrate = TTYDEF_SPEED;static	u_int	com_events;	/* input chars + weighted output completions */static	int	commajor;static	int	sio_timeout;static	int	sio_timeouts_until_log;#if 0 /* XXX */static struct tty	*sio_tty[NSIO];#elsestatic struct tty	sio_tty[NSIO];static	int	nsio_tty = NSIO;#endif#ifdef KGDB#include <machine/remote-sl.h>extern	int	kgdb_dev;extern	int	kgdb_rate;extern	int	kgdb_debug_init;#endif#ifdef CyDebugstatic	u_int	cd_inbs;static	u_int	cy_inbs;static	u_int	cd_outbs;static	u_int	cy_outbs;static	u_int	cy_svrr_probes;static	u_int	cy_timeouts;#endifstatic	int	cy_nr_cd1400s[NCY];#undef	RxFifoThresholdstatic	int	volatile RxFifoThreshold = (CD1400_RX_FIFO_SIZE / 2);static struct kern_devconf kdc_sio[NCY] = { {	0, 0, 0,		/* filled in by dev_attach */	"cyc", 0, { MDDT_ISA, 0, "tty" },	isa_generic_externalize, 0, 0, ISA_EXTERNALLEN,	&kdc_isa0,		/* parent */	0,			/* parentdata */	DC_UNCONFIGURED,	/* state */	"Cyclades multiport board",	DC_CLS_MISC		/* just an ordinary device */} };static voidsioregisterdev(id)	struct isa_device *id;{	int	unit;	unit = id->id_unit;	if (unit != 0)		kdc_sio[unit] = kdc_sio[0];	kdc_sio[unit].kdc_unit = unit;	kdc_sio[unit].kdc_isa = id;	dev_attach(&kdc_sio[unit]);}static intsioprobe(dev)	struct isa_device	*dev;{	int	cyu;	u_char	firmware_version;	cy_addr	iobase;	int	unit;	iobase = (cy_addr)dev->id_maddr;	unit = dev->id_unit;	if ((u_int)unit >= NCY)		return (0);	cy_nr_cd1400s[unit] = 0;	sioregisterdev(dev);	/* Cyclom-16Y hardware reset (Cyclom-8Ys don't care) */	cy_inb(iobase, CY16_RESET);	/* XXX? */	DELAY(500);	/* wait for the board to get its act together */	/* this is needed to get the board out of reset */	cy_outb(iobase, CY_CLEAR_INTR, 0);	DELAY(500);	for (cyu = 0; cyu < CY_MAX_CD1400s;	    ++cyu, iobase += CY_CD1400_MEMSIZE) {		int	i;		/* wait for chip to become ready for new command */		for (i = 0; i < 10; i++) {			DELAY(50);			if (!cd_inb(iobase, CD1400_CCR))				break;		}		/* clear the GFRCR register */		cd_outb(iobase, CD1400_GFRCR, 0);		/* issue a reset command */		cd_outb(iobase, CD1400_CCR,			CD1400_CCR_CMDRESET | CD1400_CCR_FULLRESET);		/* wait for the CD1400 to initialize itself */		for (i = 0; i < 200; i++) {			DELAY(50);			/* retrieve firmware version */			firmware_version = cd_inb(iobase, CD1400_GFRCR);			if ((firmware_version & 0xf0) == 0x40)				break;		}		/*		 * Anything in the 0x40-0x4F range is fine.		 * If one CD1400 is bad then we don't support higher		 * numbered good ones on this board.		 */		if ((firmware_version & 0xf0) != 0x40)			break;		++cy_nr_cd1400s[unit];	}	return (cy_nr_cd1400s[unit] == 0 ? 0 : -1);

⌨️ 快捷键说明

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