cy.c

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

C
2,536
字号
/*- * 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.83 1999/01/08 19:17:46 bde Exp $ */#include "opt_compat.h"#include "opt_devfs.h"#include "cy.h"/* * TODO: * Atomic COR change. * 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/tty.h>#include <sys/proc.h>#include <sys/conf.h>#include <sys/dkstat.h>#include <sys/fcntl.h>#include <sys/interrupt.h>#include <sys/kernel.h>#include <sys/malloc.h>#include <sys/syslog.h>#ifdef DEVFS#include <sys/devfsext.h>#endif#include <machine/clock.h>#include <machine/ipl.h>#ifndef SMP#include <machine/lock.h>#endif#include <i386/isa/isa_device.h>#include <i386/isa/cyreg.h>#include <i386/isa/ic/cd1400.h>#ifdef SMP#define disable_intr()	COM_DISABLE_INTR()#define enable_intr()	COM_ENABLE_INTR()#endif /* SMP *//* * 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	commctl		cymctl#define	comparam	cyparam#define	comspeed	cyspeed#define	comstart	cystart#define	comwakeup	cywakeup#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	siointr		cyintr#define	siointr1	cyintr1#define	sioioctl	cyioctl#define	sioopen		cyopen#define	siopoll		cypoll#define	sioprobe	cyprobe#define	sioread		cyread#define	siosettimeout	cysettimeout#define	siostop		cystop#define	siowrite	cywrite#define	sio_registered	cy_registered#define	sio_timeout	cy_timeout#define	sio_timeout_handle cy_timeout_handle#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	0x1F/* * ETC states.  com->etc may also contain a hardware ETC command value, * meaning that execution of that command is pending. */#define	ETC_NONE		0	/* we depend on bzero() setting this */#define	ETC_BREAK_STARTING	1#define	ETC_BREAK_STARTED	2#define	ETC_BREAK_ENDING	3#define	ETC_BREAK_ENDED		4#define	LOTS_OF_EVENTS	64	/* helps separate urgent events from input */#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) >> 16) * CY_MAX_PORTS \				 | (((mynor) & 0xff) & ~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 */#define	CSE_ODONE	1	/* output transmitted */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 */#endif	u_char	etc;		/* pending Embedded Transmit Command */	u_char	extra_state;	/* more flag bits, separate for order trick */#if 0	u_char	fifo_image;	/* copy of value written to FIFO */#endif	u_char	gfrcr_image;	/* copy of value read from GFRCR */#if 0	bool_t	hasfifo;	/* nonzero for 16550 UARTs */	bool_t	loses_outints;	/* nonzero if device loses output interrupts */#endif	u_char	mcr_dtr;	/* MCR bit that is wired to DTR */	u_char	mcr_image;	/* copy of value written to MCR */	u_char	mcr_rts;	/* MCR bit that is wired to RTS */#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 */	int	cy_align;	/* index for register alignment */	cy_addr	cy_iobase;	/* base address of this port's cyclom */	cy_addr	iobase;		/* base address of this port's cd1400 */	int	mcr_rts_reg;	/* cd1400 reg number of reg holding mcr_rts */	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;	bool_t	do_dcd_timestamp;	struct timeval	timestamp;	struct timeval	dcd_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	car;		/* CD1400 CAR shadow (if first unit in cd) */	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];#ifdef DEVFS	void	*devfs_token_ttyd;	void	*devfs_token_ttyl;	void	*devfs_token_ttyi;	void	*devfs_token_cuaa;	void	*devfs_token_cual;	void	*devfs_token_cuai;#endif};/* PCI driver entry point. */int	cyattach_common		__P((cy_addr cy_iobase, int cy_align));ointhand2_t	siointr;static	int	cy_units	__P((cy_addr cy_iobase, int cy_align));static	int	sioattach	__P((struct isa_device *dev));static	void	cd1400_channel_cmd __P((struct com_s *com, int cmd));static	void	cd1400_channel_cmd_wait __P((struct com_s *com));static	void	cd_etc		__P((struct com_s *com, int etc));static	int	cd_getreg	__P((struct com_s *com, int reg));static	void	cd_setreg	__P((struct com_s *com, int reg, int val));static	timeout_t siodtrwakeup;static	void	comhardclose	__P((struct com_s *com));#if 0static	void	siointr1	__P((struct com_s *com));#endifstatic	int	commctl		__P((struct com_s *com, int bits, int how));static	int	comparam	__P((struct tty *tp, struct termios *t));static	swihand_t siopoll;static	int	sioprobe	__P((struct isa_device *dev));static	void	siosettimeout	__P((void));static	int	comspeed	__P((speed_t speed, u_long cy_clock,				     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));#endifstatic char driver_name[] = "cy";/* 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])struct isa_driver	siodriver = {	sioprobe, sioattach, driver_name};static	d_open_t	sioopen;static	d_close_t	sioclose;static	d_read_t	sioread;static	d_write_t	siowrite;static	d_ioctl_t	sioioctl;static	d_stop_t	siostop;static	d_devtotty_t	siodevtotty;#define	CDEV_MAJOR	48static	struct cdevsw	sio_cdevsw = {	sioopen,	sioclose,	sioread,	siowrite,	sioioctl,	siostop,	noreset,	siodevtotty,	ttpoll,		nommap,		NULL,		driver_name,	NULL,		-1,		nodump,		nopsize,	D_TTY,};static	int	comconsole = -1;static	speed_t	comdefaultrate = TTYDEF_SPEED;static	u_int	com_events;	/* input chars + weighted output completions */static	bool_t	sio_registered;static	int	sio_timeout;static	int	sio_timeouts_until_log;static	struct	callout_handle sio_timeout_handle    = CALLOUT_HANDLE_INITIALIZER(&sio_timeout_handle);#if 0 /* XXX */static struct tty	*sio_tty[NSIO];#elsestatic struct tty	sio_tty[NSIO];#endifstatic	const int	nsio_tty = NSIO;#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_chip_offset[] = {	0x0000, 0x0400, 0x0800, 0x0c00, 0x0200, 0x0600, 0x0a00, 0x0e00,};static	int	cy_nr_cd1400s[NCY];static	int	cy_total_devices;#undef	RxFifoThresholdstatic	int	volatile RxFifoThreshold = (CD1400_RX_FIFO_SIZE / 2);static intsioprobe(dev)	struct isa_device	*dev;{	cy_addr	iobase;	iobase = (cy_addr)dev->id_maddr;	/* Cyclom-16Y hardware reset (Cyclom-8Ys don't care) */	cy_inb(iobase, CY16_RESET, 0);	/* 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, 0);	DELAY(500);	return (cy_units(iobase, 0) == 0 ? 0 : -1);}static intcy_units(cy_iobase, cy_align)	cy_addr	cy_iobase;	int	cy_align;{	int	cyu;	u_char	firmware_version;	int	i;	cy_addr	iobase;	for (cyu = 0; cyu < CY_MAX_CD1400s; ++cyu) {		iobase = cy_iobase + (cy_chip_offset[cyu] << cy_align);		/* wait for chip to become ready for new command */		for (i = 0; i < 10; i++) {			DELAY(50);			if (!cd_inb(iobase, CD1400_CCR, cy_align))				break;		}		/* clear the GFRCR register */		cd_outb(iobase, CD1400_GFRCR, cy_align, 0);		/* issue a reset command */		cd_outb(iobase, CD1400_CCR, cy_align,			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,						  cy_align);			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;	}

⌨️ 快捷键说明

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