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

📄 fas.c

📁 一个通讯程序源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* FAS Final Async Solution driver for 286/386 versions of system V UNIX *//* FAS was developed byUwe Doering             INET : gemini@geminix.in-berlin.deBillstedter Pfad 17 b   UUCP : ...!unido!fub!geminix.in-berlin.de!gemini1000 Berlin 20Germany*//*+:EDITS:*//*:09-10-1992-13:59-wht@n4hgf-ECU release 3.20 *//*:08-22-1992-15:38-wht@n4hgf-ECU release 3.20 BETA *//*:07-25-1991-12:57-wht@n4hgf-ECU release 3.10 *//*:06-04-1991-19:41-wht@n4hgf-add FASIC_SIP_CHANGE *//*:02-05-1991-12:13-wht@n4hgf-apply 2.08b2->2.08.0 diffs *//*:01-20-1991-05:01-wht@n4hgf-changed buffer sizes */#if defined(FASI)char *fasi_driver_ident = "FAS/i 2.08.01";#endif /* FASI */#if !defined (M_I286) && !defined(__STDC__)#ident	"@(#)fas.c	2.08"#endif/* Note: This source code was quite heavily optimized for speed. You         may wonder that register variables aren't used everywhere.         This is because there is an overhead in memory accesses         when using register variables. As you may know data accesses         usually need much more wait states on the memory bus than         code accesses (because of page or cache misses). Therefor,         saving some data accesses has higher priority than saving         code accesses.         You may also note some not very elegant constructions that         may be intentional because they are faster. If you want to         make style improvements you should check the assembler output         whether this wouldn't slow things down.         Decisions for speed optimization were based on assembler         listings produced by the standard UNIX V 3.X/386 C compiler.*/#include <sys/param.h>#include <sys/types.h>#include <sys/signal.h>#include <sys/buf.h>#include <sys/dir.h>#if defined (XENIX)#include <sys/page.h>#include <sys/seg.h>#endif#include <sys/user.h>#include <sys/errno.h>#include <sys/tty.h>#include <sys/conf.h>#include <sys/sysinfo.h>#include <sys/file.h>#if !defined (XENIX) && !defined(CBAUD)#include <sys/termio.h>#endif#include <sys/ioctl.h>#if !defined(FASI)#include <macros.h>#endif#if defined (HAVE_VPIX)#if !defined (XENIX)#include <sys/tss.h>#include <sys/immu.h>#include <sys/region.h>#endif#include <sys/proc.h>#include <sys/v86.h>#endif#if defined (XENIX)#include "fas.h"#else#include <local/fas.h>#if !defined (NO_ASM)#include <sys/inline.h>#endif#endif#if defined (SCO) || defined (XENIX)#define asyputchar sioputchar#define asygetchar siogetchar#endif#if defined (XENIX) || defined (NO_ASM)#define intr_disable()	old_level = SPLINT ()#define intr_restore()	(void) splx (old_level)#define REGVAR#else/* This is a terrible ugly kludge to speed up the `inb' and `outb'   functions. I.e., originally, the `outb' inline function had an   overhead of four data memory accesses for parameter passing. This   parameter passing actually consumed more clock cycles than the   assembler `outb' command itself. Although this solution can't   prevent unnessessary register moves it limits them at least to   register to register moves that are much faster. You need a   line like the following in the declaration part of every   function that uses `inb' or `outb' calls:	REGVAR;   This hack should work with every compiler that knows about the   UNIX V 3.X/386 standard compiler's inline assembler directives.*/asm	void loadal (val){%reg	val;	movl	val,%eax%mem	val;	movb	val,%al}asm	void loaddx (val){%reg	val;	movl	val,%edx%mem	val;	movw	val,%dx}asm	int outbyte (){	outb	(%dx)}asm	int inbyte (){	xorl	%eax,%eax	inb	(%dx)}/* The port parameter of the `outb' macro must be one of the predefined   port macros from `fas.h' or a simple uint variable (no indirection   is allowed). Additionally, `fip' must be a register variable in the   functions where `outb' is used. This prevents the destruction of the   `eax' CPU register while loading the `edx' register with the port   address. This is highly compiler implementation specific.*/#define outb(port,val) (regvar = (val), loadal (regvar), regvar = (port), loaddx (regvar), outbyte ())#define inb(port) (regvar = (port), loaddx (regvar), inbyte ())#define REGVAR register uint	regvar/* This function inserts the address optimization assembler pseudo-op   wherever called.*/asm	void optim (){	.optim}/* This dummy function has nothing to do but to call optim so that   the `.optim' assembler pseudo-op will be included in the assembler   file. This must be the first of all functions.*/#if defined (OPTIM)	/* Define for uPort, ISC doesn't know about */static void		/* `.optim', but has turned on optimization by */dummy ()		/* default, so we don't need it there anyway. */{	optim ();}#endif#endif	/* XENIX || NO_ASM *//* functions provided by this driver */int		fasinit ();int		fasopen ();int		fasclose ();int		fasread ();int		faswrite ();int		fasioctl ();int		fasintr ();#if defined (NEED_PUT_GETCHAR)int		asyputchar ();int		asygetchar ();#endif#if defined (NEED_INIT8250)int		init8250 ();#endifstatic int	fas_proc ();static void	fas_param ();static void	fas_fproc ();static void	fas_mproc ();static uint	fas_rproc ();static void	fas_xproc ();static void	fas_event ();#if defined (HAVE_VPIX)static int	fas_vpix_sr ();#endifstatic void	fas_rxfer ();static void	fas_xxfer ();static void	fas_ihlw_check ();static void	fas_hdx_check ();static void	fas_hangup ();static void	fas_timeout ();static void	fas_cmd ();static void	fas_open_device ();static void	fas_close_device ();static uint	fas_make_ctl_val ();static int	fas_test_device ();/* external functions used by this driver */extern int	ttinit ();extern int	ttiocom ();extern int	ttyflush ();extern int	SPLINT ();extern int	SPLWRK ();extern int	splx ();extern int	sleep ();extern int	wakeup ();extern void	longjmp ();extern int	signal ();extern int	timeout ();extern int	untimeout ();extern int	printf ();#if defined (SCO) || defined (XENIX)extern int	printcfg ();#endif#if defined (HAVE_VPIX)extern int	fubyte ();extern int	subyte ();extern int	v86setint ();#endif#if defined (XENIX)extern int	inb ();extern int	outb ();#endif/* external data objects used by this driver */extern int	tthiwat [];/* the following stuff is defined in space.c */extern uint	fas_physical_units;extern ulong	fas_port [];extern uint	fas_vec [];extern uint	fas_init_seq [];extern uint	fas_mcb [];extern ulong	fas_modem [];extern ulong	fas_flow [];extern uint	fas_ctl_port [];extern uint	fas_ctl_val [];extern uint	fas_int_ack_port [];extern uint	fas_int_ack [];extern struct fas_info	fas_info [];extern struct tty	fas_tty [];extern struct fas_info	*fas_info_ptr [];extern struct tty	*fas_tty_ptr [];/* end of space.c references */#if defined(FASI)int fasiintr_entries = 0;extern char *fasi_space_ident;#endif /* FASI *//* fas_is_initted   Flag to indicate that we have been thru init.   This is realy only necessary for systems that use asyputchar   and asygetchar but it doesn't hurt to have it anyway.*/static int	fas_is_initted = FALSE;/* event_scheduled   Flag to indicate that the event handler has been scheduled   via the timeout() function.*/static int	event_scheduled = FALSE;/* array of pointers to the first fas_info structure for each   interrupt vector*/static struct fas_info	*fas_first_int_user [NUM_INT_VECTORS];/* the values for the various baud rates */static uint	fas_speeds [CBAUD + 1] ={	1,			BAUD_BASE/50,	BAUD_BASE/75,		BAUD_BASE/110,	(2*BAUD_BASE+134)/269,	BAUD_BASE/150,	BAUD_BASE/200,		BAUD_BASE/300,	BAUD_BASE/600,		BAUD_BASE/1200,	BAUD_BASE/1800,		BAUD_BASE/2400,	BAUD_BASE/4800,		BAUD_BASE/9600,	BAUD_BASE/19200,	BAUD_BASE/38400};/* time for one character to completely leave the transmitter shift register */static uint	fas_ctimes [CBAUD + 1] ={	1,		HZ*15/50+2,	HZ*15/75+2,	HZ*15/110+2,	HZ*30/269+2,	HZ*15/150+2,	HZ*15/200+2,	HZ*15/300+2,	HZ*15/600+2,	HZ*15/1200+2,	HZ*15/1800+2,	HZ*15/2400+2,	HZ*15/4800+2,	HZ*15/9600+2,	HZ*15/19200+2,	HZ*15/38400+2};/* dynamically adapt xmit buffer size to baud rate to prevent long buffer   drains at low speeds   These values are checked against boundaries and will be modified if   necessary before use. Checking is done in fas_param (). Drain time   is about 5 seconds with continuous character flow.*/static uint	fas_xbuf_size [CBAUD + 1] ={	1,		50/2,	75/2,		110/2,	269/4,		150/2,	200/2,		300/2,	600/2,		1200/2,	1800/2,		2400/2,	4800/2,		9600/2,	19200/2,	38400/2};/* lookup table for minor device number -> open mode flags translation */static uint	fas_open_modes [16] ={	OS_OPEN_FOR_DIALOUT | OS_FAKE_CARR_ON | OS_CLOCAL,	OS_OPEN_FOR_DIALOUT | OS_FAKE_CARR_ON | OS_CLOCAL | OS_HWO_HANDSHAKE							| OS_HWI_HANDSHAKE,	OS_OPEN_FOR_DIALOUT | OS_FAKE_CARR_ON | OS_CLOCAL | OS_HWO_HANDSHAKE,	OS_OPEN_FOR_DIALOUT | OS_FAKE_CARR_ON | OS_CLOCAL | OS_HWO_HANDSHAKE							| OS_HDX_HANDSHAKE,	OS_OPEN_FOR_DIALOUT | OS_FAKE_CARR_ON,	OS_OPEN_FOR_DIALOUT | OS_FAKE_CARR_ON | OS_HWO_HANDSHAKE						| OS_HWI_HANDSHAKE,	OS_OPEN_FOR_DIALOUT | OS_FAKE_CARR_ON | OS_HWO_HANDSHAKE,	OS_OPEN_FOR_DIALOUT | OS_FAKE_CARR_ON | OS_HWO_HANDSHAKE						| OS_HDX_HANDSHAKE,	OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_NO_DIALOUT,	OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_NO_DIALOUT | OS_HWO_HANDSHAKE							| OS_HWI_HANDSHAKE,	OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_NO_DIALOUT | OS_HWO_HANDSHAKE,	OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_NO_DIALOUT | OS_HWO_HANDSHAKE							| OS_HDX_HANDSHAKE,	OS_OPEN_FOR_GETTY | OS_WAIT_OPEN,	OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_HWO_HANDSHAKE						| OS_HWI_HANDSHAKE,	OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_HWO_HANDSHAKE,	OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_HWO_HANDSHAKE						| OS_HDX_HANDSHAKE};/* The following defines are used to access multiplexed ports. */#define GET_PORT(port,num) \	((fip->device_flags.i & DF_CTL_EVERY)\			? (port)\			: (port) + (num))#define fas_first_ctl(fip,port) \	((void) (((fip)->device_flags.i & DF_CTL_FIRST)\			? outb (CTL_PORT, (port).p.ctl)\			: 0))#define fas_ctl(fip,port) \	((void) (((fip)->device_flags.i & (DF_CTL_FIRST | DF_CTL_EVERY))\			? outb (CTL_PORT, (port).p.ctl)\			: 0))#define fas_first_outb(fip,port,val) \	((void) (((fip)->device_flags.i & (DF_CTL_FIRST | DF_CTL_EVERY))\			? outb (CTL_PORT, (port).p.ctl)\			: 0),\		(void) outb ((port).addr, (val)))#define fas_outb(fip,port,val) \	((void) (((fip)->device_flags.i & DF_CTL_EVERY)\			? outb (CTL_PORT, (port).p.ctl)\			: 0),\		(void) outb ((port).addr, (val)))#define fas_first_inb(fip,port) \	((void) (((fip)->device_flags.i & (DF_CTL_FIRST | DF_CTL_EVERY))\			? outb (CTL_PORT, (port).p.ctl)\			: 0),\		inb ((port).addr))#define fas_inb(fip,port) \	((void) (((fip)->device_flags.i & DF_CTL_EVERY)\			? outb (CTL_PORT, (port).p.ctl)\			: 0),\		inb ((port).addr))/* The following defines are used to take apart the minor device numbers. */#define GET_UNIT(dev)		((dev) & 0x0f)#define GET_OPEN_MODE(dev)	(fas_open_modes [((dev) >> 4) & 0x0f])/* lock device against concurrent use */#define get_device_lock(fip,prio) \{\	/* sleep while device is used by an other process */\	while ((fip)->device_flags.i & DF_DEVICE_LOCKED)\		(void) sleep ((caddr_t) &(fip)->device_flags.i, (prio));\	(fip)->device_flags.s |= DF_DEVICE_LOCKED;\}/* release device */#define release_device_lock(fip) \{\	(fip)->device_flags.s &= ~DF_DEVICE_LOCKED;\	/* wakeup the process that may wait for this device */\	(void) wakeup ((caddr_t) &(fip)->device_flags.i);\}/* schedule event */#define event_sched(fip,event) \{\	(fip)->event_flags.s |= (event);\	if (!event_scheduled)\	{\		event_scheduled = TRUE;\		(void) timeout (fas_event, (void *) NULL,\				(EVENT_TIME) * (HZ) / 1000);\	}\}/* fasinit   This routine checks for the presense of the devices in the fas_port   array and if the device is present tests and initializes it.   During the initialization if the device is determined to be an   NS16550A chip the DF_DEVICE_IS_NS16550A flag is set and the FIFOs will   be used. If the device is an i82510 chip the DF_DEVICE_IS_I82510 flag   is set and the device will be handled accordingly.*/intfasinit (){	register struct fas_info	*fip;	register uint	unit;	uint	logical_units, port, *seq_ptr;	char	port_stat [MAX_UNITS + 1];	REGVAR;	if (fas_is_initted)		return (0);	fas_is_initted = TRUE;	/* execute the init sequence for the serial card */	for (seq_ptr = fas_init_seq; *seq_ptr; seq_ptr++)	{		port = *seq_ptr;		seq_ptr++;		if (*seq_ptr & READ_PORT)			(void) inb (port);		else			(void) outb (port, *seq_ptr);	}	/* setup the list of pointers to the tty structures */	for (unit = 0, logical_units = fas_physical_units * 2;		unit < logical_units; unit++)		fas_tty_ptr [unit] = &fas_tty [unit];	/* setup and initialize all serial ports */	for (unit = 0; unit < fas_physical_units; unit++)	{		fas_info_ptr [unit] = fip = &fas_info [unit];		port_stat [unit] = '-';		if (port = (uint) ((ushort) (fas_port [unit])))		{			/* check the int vector */			if (fas_vec [unit] >= NUM_INT_VECTORS)			{				port_stat [unit] = '>';				continue;			}			/* init all of its ports */			if (fas_ctl_port [unit])			{				fip->ctl_port = fas_ctl_port [unit];				if (fas_ctl_val [unit] & 0xff00)					fip->device_flags.s |= DF_CTL_EVERY;				else					fip->device_flags.s |= DF_CTL_FIRST;			}			fip->port_0.p.addr = GET_PORT (port, 0);			fip->port_1.p.addr = GET_PORT (port, 1);			fip->port_2.p.addr = GET_PORT (port, 2);			fip->port_3.p.addr = GET_PORT (port, 3);			fip->port_4.p.addr = GET_PORT (port, 4);			fip->port_5.p.addr = GET_PORT (port, 5);			fip->port_6.p.addr = GET_PORT (port, 6);			fip->port_0.p.ctl = fas_make_ctl_val (fip, unit, 0);			fip->port_1.p.ctl = fas_make_ctl_val (fip, unit, 1);			fip->port_2.p.ctl = fas_make_ctl_val (fip, unit, 2);			fip->port_3.p.ctl = fas_make_ctl_val (fip, unit, 3);			fip->port_4.p.ctl = fas_make_ctl_val (fip, unit, 4);			fip->port_5.p.ctl = fas_make_ctl_val (fip, unit, 5);			fip->port_6.p.ctl = fas_make_ctl_val (fip, unit, 6);			fip->vec = fas_vec [unit];			fip->modem.l = fas_modem [unit];			fip->flow.l = fas_flow [unit];			/* mask off invalid bits */			fip->modem.m.di &= MC_ANY_CONTROL;			fip->modem.m.eo &= MC_ANY_CONTROL;			fip->modem.m.ei &= MC_ANY_CONTROL;			fip->modem.m.ca &= MS_ANY_PRESENT;			fip->flow.m.ic &= MC_ANY_CONTROL;			fip->flow.m.oc &= MS_ANY_PRESENT;			fip->flow.m.oe &= MS_ANY_PRESENT;			fip->flow.m.hc &= MC_ANY_CONTROL;			fip->recv_ring_put_ptr = fip->recv_buffer;			fip->recv_ring_take_ptr = fip->recv_buffer;			fip->xmit_ring_put_ptr = fip->xmit_buffer;			fip->xmit_ring_take_ptr = fip->xmit_buffer;			fip->xmit_fifo_size = 1;			fip->ier = IE_NONE;	/* disable all ints */			fas_first_outb (fip, INT_ENABLE_PORT, fip->ier);			/* is there a serial chip ? */			if (fas_inb (fip, INT_ENABLE_PORT) != fip->ier)

⌨️ 快捷键说明

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